From 7f1711234e6a21c153e892758d9d82c333ab37ac Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 18 Oct 2007 19:56:47 -0300 Subject: V4L/DVB (6384): Replace TDA9887_SET_CONFIG by TUNER_SET_CONFIG Currently, the only tuner-specific device that allows special configurations is tda9887. However, tea5767 also may require some special configurations (for example, to specify a different Xtal freq). This patch replaces TDA9887_SET_CONFIG by a more generic internal ioctl (TUNER_SET_CONFIG). The newer one allows specifying what tuner is appliable to a configuration set, and allows an arbitrary configuration struct. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 3 +++ drivers/media/video/bt8xx/bttv-cards.c | 8 ++++++-- drivers/media/video/cx88/cx88-i2c.c | 10 ++++++++-- drivers/media/video/em28xx/em28xx-i2c.c | 8 +++++++- drivers/media/video/em28xx/em28xx-video.c | 5 ----- drivers/media/video/saa7134/saa7134-cards.c | 13 +++++++++++-- drivers/media/video/saa7134/saa7134-dvb.c | 19 +++++++++++++------ drivers/media/video/saa7134/saa7134-i2c.c | 13 ++++++++++--- drivers/media/video/saa7134/saa7134-video.c | 12 ++++++++++-- drivers/media/video/tuner-core.c | 23 +++++++++++++++++++---- drivers/media/video/tuner-simple.c | 15 +++++++++++++-- drivers/media/video/v4l2-common.c | 2 +- include/media/v4l2-common.h | 7 ++++++- 13 files changed, 107 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a5262e852c8..c49fa049717 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -84,6 +84,9 @@ struct dvb_tuner_ops { /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + /** This is to allow setting tuner-specific configs */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); + int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 585d1ef95af..4f91f98db37 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3574,8 +3574,12 @@ void __devinit bttv_init_card2(struct bttv *btv) } if (btv->tda9887_conf) { - bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG, - &btv->tda9887_conf); + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &btv->tda9887_conf; + + bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg); } btv->svhs = bttv_tvcards[btv->c.type].svhs; diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c8b1c50625f..937497c8624 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -127,8 +127,14 @@ static int attach_inform(struct i2c_client *client) } } - if (core->board.tda9887_conf) - client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); + } return 0; } diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index e3a4aa7a9df..e48191fb1dd 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -421,6 +421,8 @@ static int attach_inform(struct i2c_client *client) case 0x96: case 0x94: { + struct v4l2_priv_tun_config tda9887_cfg; + struct tuner_setup tun_setup; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; @@ -428,7 +430,11 @@ static int attach_inform(struct i2c_client *client) tun_setup.addr = client->addr; em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); break; } case 0x42: diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 0906bc5766c..bb0933f9d84 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -186,11 +186,6 @@ static void em28xx_config_i2c(struct em28xx *dev) f.frequency = 9076; /* FIXME:remove magic number */ dev->ctl_freq = f.frequency; em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); - - /* configure tda9887 */ - - -/* em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */ } /* diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 98c1b084a71..78d7d7059a9 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -4570,8 +4570,17 @@ int saa7134_board_init2(struct saa7134_dev *dev) printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE; - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf); + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + dev->tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); } tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index e1ab099ec4c..a9ca5730826 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1073,14 +1073,21 @@ static int dvb_init(struct saa7134_dev *dev) static int dvb_fini(struct saa7134_dev *dev) { - static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + /* FIXME: I suspect that this code is bogus, since the entry for + Pinnacle 300I DVB-T PAL already defines the proper init to allow + the detection of mt2032 (TDA9887_PORT2_INACTIVE) + */ + if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) { + struct v4l2_priv_tun_config tda9887_cfg; + static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &on; - switch (dev->board) { - case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: /* otherwise we don't detect the tuner on next insmod */ - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); - break; - }; + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg); + } + videobuf_dvb_unregister(&dev->dvb); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 6deaad1a548..800b397f8f1 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; - int conf = dev->tda9887_conf; struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", @@ -360,7 +359,6 @@ static int attach_inform(struct i2c_client *client) } if (tuner != UNSET) { - tun_setup.type = tuner; tun_setup.addr = saa7134_boards[dev->board].tuner_addr; tun_setup.config = saa7134_boards[dev->board].tuner_config; @@ -372,9 +370,18 @@ static int attach_inform(struct i2c_client *client) client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); } + + if (tuner == TUNER_TDA9887) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + client->driver->command(client, TUNER_SET_CONFIG, + &tda9887_cfg); + } } - client->driver->command(client, TDA9887_SET_CONFIG, &conf); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 6396d9b5c06..2c1d56ab2f2 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1236,16 +1236,24 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, restart_overlay = 1; break; case V4L2_CID_PRIVATE_AUTOMUTE: + { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + dev->ctl_automute = c->value; if (dev->tda9887_conf) { if (dev->ctl_automute) dev->tda9887_conf |= TDA9887_AUTOMUTE; else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, - &dev->tda9887_conf); + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); } break; + } default: return -EINVAL; } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9e99f3636d3..d1d6c664bb0 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -889,14 +889,29 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } #endif - case TDA9887_SET_CONFIG: - if (t->type == TUNER_TDA9887) { - int *i = arg; + case TUNER_SET_CONFIG: + { + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct v4l2_priv_tun_config *cfg = arg; + + if (t->type != cfg->tuner) + break; - t->tda9887_config = *i; + if (t->type == TUNER_TDA9887) { + t->tda9887_config = *(unsigned int *)cfg->priv; set_freq(client, t->tv_freq); + break; } + + if (NULL == fe_tuner_ops->set_config) { + tuner_warn("Tuner frontend module has no way to " + "set config\n"); + break; + } + fe_tuner_ops->set_config(&t->fe, cfg->priv); + break; + } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 7b93d3b1f4c..eec13cb6cd6 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } priv->last_div = div; if (t_params->has_tda9887) { + struct v4l2_priv_tun_config tda9887_cfg; int config = 0; int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + if (params->std == V4L2_STD_SECAM_LC) { if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; @@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); @@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, if (t_params->has_tda9887) { int config = 0; + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) @@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, config |= TDA9887_GAIN_NORMAL; if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 1141b4bf41c..a4d68d3ba5e 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", - [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", + [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 181a40c46a5..c019c1e9989 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -116,6 +116,11 @@ struct v4l2_decode_vbi_line { u32 type; /* VBI service type (V4L2_SLICED_*). 0 if no service found */ }; +struct v4l2_priv_tun_config { + int tuner; + void *priv; +}; + /* audio ioctls */ /* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */ @@ -131,7 +136,7 @@ struct v4l2_decode_vbi_line { #define TUNER_SET_STANDBY _IOW('d', 91, int) /* Sets tda9887 specific stuff, like port1, port2 and qss */ -#define TDA9887_SET_CONFIG _IOW('d', 92, int) +#define TUNER_SET_CONFIG _IOW('d', 92, struct v4l2_priv_tun_config) /* Switch the tuner to a specific tuner mode. Replacement of AUDC_SET_RADIO */ #define VIDIOC_INT_S_TUNER_MODE _IOW('d', 93, enum v4l2_tuner_type) -- cgit v1.2.3 From 0e1165e8d05ef4a530001ea4ac5ff0df78129dd2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 18 Oct 2007 20:10:07 -0300 Subject: V4L/DVB (6385): Adds the capability of configuring tea5767 support tea5767 has several possible configurations. Before the patch, the driver were assuming the more common configuration. However, some newer cards, like MSI @nyware Master requires other configurations, like de-activating a gpio port and changing chip Xtal. This patch adds the capability of altering device configuration at runtime. This may also be used later to activate some features like auto-mute when signal is weak. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 89 ++++++++++++++++++++++++++++++------------- drivers/media/video/tea5767.h | 19 +++++++++ 2 files changed, 81 insertions(+), 27 deletions(-) diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 71df419df7b..2d2acbdd24a 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -22,10 +22,12 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages"); #define PREFIX "tea5767 " -struct tea5767_priv { - struct tuner_i2c_props i2c_props; +/*****************************************************************************/ - u32 frequency; +struct tea5767_priv { + struct tuner_i2c_props i2c_props; + u32 frequency; + struct tea5767_ctrl ctrl; }; /*****************************************************************************/ @@ -127,17 +129,10 @@ struct tea5767_priv { /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff -enum tea5767_xtal_freq { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - - /*****************************************************************************/ -static void tea5767_status_dump(unsigned char *buffer) +static void tea5767_status_dump(struct tea5767_priv *priv, + unsigned char *buffer) { unsigned int div, frq; @@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer) div = ((buffer[0] & 0x3f) << 8) | buffer[1]; - switch (TEA5767_HIGH_LO_32768) { + switch (priv->ctrl.xtal_freq) { case TEA5767_HIGH_LO_13MHz: frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ break; @@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); - /* Rounds freq to next decimal value - for 62.5 KHz step */ - /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + buffer[2] = 0; - buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | - TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; - buffer[4] = 0; + if (priv->ctrl.port1) + buffer[2] |= TEA5767_PORT1_HIGH; if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); @@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("TEA5767 set to stereo\n"); } - /* Should be replaced */ - switch (TEA5767_HIGH_LO_32768) { + + buffer[3] = 0; + + if (priv->ctrl.port2) + buffer[3] |= TEA5767_PORT2_HIGH; + + if (priv->ctrl.high_cut) + buffer[3] |= TEA5767_HIGH_CUT_CTRL; + + if (priv->ctrl.st_noise) + buffer[3] |= TEA5767_ST_NOISE_CTL; + + if (priv->ctrl.soft_mute) + buffer[3] |= TEA5767_SOFT_MUTE; + + if (priv->ctrl.japan_band) + buffer[3] |= TEA5767_JAPAN_BAND; + + buffer[4] = 0; + + if (priv->ctrl.deemph_75) + buffer[4] |= TEA5767_DEEMPH_75; + + if (priv->ctrl.pllref) + buffer[4] |= TEA5767_PLLREF_ENABLE; + + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + switch (priv->ctrl.xtal_freq) { case TEA5767_HIGH_LO_13MHz: tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; - buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); - buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: @@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe, if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else - tea5767_status_dump(buffer); + tea5767_status_dump(priv, buffer); } priv->frequency = frq * 125 / 2; @@ -398,6 +417,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5767_priv *priv = fe->tuner_priv; *frequency = priv->frequency; + + return 0; +} + +static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); + return 0; } @@ -407,6 +436,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { }, .set_analog_params = set_radio_freq, + .set_config = tea5767_set_config, .sleep = tea5767_standby, .release = tea5767_release, .get_frequency = tea5767_get_frequency, @@ -425,8 +455,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return NULL; fe->tuner_priv = priv; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; + priv->ctrl.port1 = 1; + priv->ctrl.port2 = 1; + priv->ctrl.high_cut = 1; + priv->ctrl.st_noise = 1; + priv->ctrl.japan_band = 1; memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -436,7 +472,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return fe; } - EXPORT_SYMBOL_GPL(tea5767_attach); EXPORT_SYMBOL_GPL(tea5767_autodetection); diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h index 5d78281adcc..a44451f6114 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/video/tea5767.h @@ -20,6 +20,25 @@ #include #include "dvb_frontend.h" +enum tea5767_xtal { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + +struct tea5767_ctrl { + unsigned int port1:1; + unsigned int port2:1; + unsigned int high_cut:1; + unsigned int st_noise:1; + unsigned int soft_mute:1; + unsigned int japan_band:1; + unsigned int deemph_75:1; + unsigned int pllref:1; + enum tea5767_xtal xtal_freq; +}; + #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); -- cgit v1.2.3 From 55c88610fe974c95a62e495305a7386aaac3df39 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 19 Oct 2007 06:59:33 -0300 Subject: V4L/DVB (6386): Add support for radio on CX88_BOARD_MSI_TVANYWHERE_MASTER This board has some special tea5767 configuration. Basically, radio XTAL uses a different frequency than the other supported radios. It uses a 13 MHz XTAL. This patch adds the proper radio gpio and tea5767 configurations for the board. Also, with PAL/BG, the board requires some special init for tda9887: port1=0 port2=0 qss=1 Thanks to Serge Kolotylo and MIDImaster for their help on identifying the proper needs for this driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index a4eb6a87a76..f8a786ae475 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -26,6 +26,7 @@ #include #include "cx88.h" +#include "tea5767.h" static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = { }}, .radio = { .type = CX88_RADIO, + .vmux = 3, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff20, }, }, [CX88_BOARD_WINFAST_DV2000] = { @@ -1979,6 +1984,23 @@ static void cx88_card_setup(struct cx88_core *core) core->name, i); } break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + { + struct v4l2_priv_tun_config tea5767_cfg; + struct tea5767_ctrl ctl; + + memset(&ctl, 0, sizeof(ctl)); + + ctl.high_cut = 1; + ctl.st_noise = 1; + ctl.deemph_75 = 1; + ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; + + tea5767_cfg.tuner = TUNER_TEA5767; + tea5767_cfg.priv = &ctl; + + cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); + } } } -- cgit v1.2.3 From b02044d81fc028d4fef1c65f9b179a0aec091f0b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 24 Oct 2007 13:23:14 -0300 Subject: V4L/DVB (6399): saa7134/: make 2 functions static saa7134_buffer_requeue() and set_tvnorm() can become static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 4 ++-- drivers/media/video/saa7134/saa7134-video.c | 2 +- drivers/media/video/saa7134/saa7134.h | 4 ---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 4f0a9157ecb..fc71843b9dc 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data) /* resends a current buffer in queue after resume */ -int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) +static int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) { struct saa7134_buf *buf, *next; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 2c1d56ab2f2..86fe452842b 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -540,7 +540,7 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { dprintk("set tv norm = %s\n",norm->name); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 66a390c321a..16f4b5ce34d 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -596,9 +596,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); -int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q); - int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -631,7 +628,6 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); -- cgit v1.2.3 From 289d4d2f0746715ada41e0945116eb3d62d5f35c Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 24 Oct 2007 17:31:15 -0300 Subject: V4L/DVB (6400): usbvision: Convert the usbvision->lock semaphore to the mutex API Convert the usbvision->lock semaphore to the mutex API Signed-off-by: Matthias Kaehlcke Reviewed-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 8 +++- drivers/media/video/usbvision/usbvision-video.c | 54 ++++++++++++------------- drivers/media/video/usbvision/usbvision.h | 3 +- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index c7d5f9ed22d..2038d409f1d 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2242,14 +2242,18 @@ static void call_usbvision_power_off(struct work_struct *work) struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork); PDEBUG(DBG_FUNC, ""); - down_interruptible(&usbvision->lock); + if(mutex_lock_interruptible(&usbvision->lock)) { + return; + } + + if(usbvision->user == 0) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); } static void usbvision_powerOffTimer(unsigned long data) diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 36e689fa16c..e34f311124e 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) /* If so far no errors then we shall start the camera */ if (!errCode) { - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (usbvision->power == 0) { usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); @@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); } if (errCode) { @@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) (struct usb_usbvision *) video_get_drvdata(dev); PDEBUG(DBG_IO, "close"); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_audio_off(usbvision); usbvision_restart_isoc(usbvision); @@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input) if ((input >= usbvision->video_inputs) || (input < 0) ) return -EINVAL; - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_muxsel(usbvision, input); usbvision_set_input(usbvision); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) (struct usb_usbvision *) video_get_drvdata(dev); usbvision->tvnormId=*id; - down(&usbvision->lock); + mutex_lock(&usbvision->lock); call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnormId); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); /* propagate the change to the decoder */ usbvision_muxsel(usbvision, usbvision->ctl_input); @@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, usbvision->curFrame = NULL; /* by now we are committed to the new data... */ - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) PDEBUG(DBG_MMAP, "mmap"); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (!USBVISION_IS_OPERATIONAL(usbvision)) { - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EFAULT; } if (!(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(usbvision->max_frame_size)) { - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EINVAL; } @@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (i == usbvision->num_frames) { PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EINVAL; } @@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) size -= PAGE_SIZE; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) PDEBUG(DBG_IO, "%s:", __FUNCTION__); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (usbvision->user) { err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); @@ -1307,7 +1307,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return errCode; } @@ -1321,7 +1321,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) PDEBUG(DBG_IO, ""); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); /* Set packet size to 0 */ usbvision->ifaceAlt=0; @@ -1337,7 +1337,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -1641,7 +1641,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) usbvision->dev = dev; - init_MUTEX(&usbvision->lock); /* to 1 == available */ + mutex_init(&usbvision->lock); /* available */ // prepare control urb for control messages during interrupts usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); @@ -1676,13 +1676,13 @@ static void usbvision_release(struct usb_usbvision *usbvision) { PDEBUG(DBG_PROBE, ""); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_reset_powerOffTimer(usbvision); usbvision->initialized = 0; - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); usbvision_remove_sysfs(usbvision->vdev); usbvision_unregister_video(usbvision); @@ -1796,7 +1796,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, } PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); /* compute alternate max packet sizes */ uif = dev->actconfig->interface[0]; @@ -1840,7 +1840,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->streaming = Stream_Off; usbvision_register_video(usbvision); usbvision_configure_video(usbvision); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); usb_set_intfdata (intf, usbvision); @@ -1871,7 +1871,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) } usb_set_intfdata (intf, NULL); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); // At this time we ask to cancel outstanding URBs usbvision_stop_isoc(usbvision); @@ -1885,7 +1885,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->user) { printk(KERN_INFO "%s: In use, disconnect pending\n", diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index c5b6c501c86..c32f68566bf 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -396,7 +397,7 @@ struct usb_usbvision { unsigned char iface; /* Video interface number */ unsigned char ifaceAlt; /* Alt settings */ unsigned char Vin_Reg2_Preset; - struct semaphore lock; + struct mutex lock; struct timer_list powerOffTimer; struct work_struct powerOffWork; int power; /* is the device powered on? */ -- cgit v1.2.3 From e92adc2c39aaaa0129b7b97584784a8ba9da9ec4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 20 Sep 2007 01:44:27 -0300 Subject: V4L/DVB (6404): cx23885: i2c 16bit reg/val read/write fix Fix i2c reads and writes of 16bit register address / values Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 71da528932d..f7e8a481696 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -84,7 +84,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, u32 wdata, addr, ctrl; int retval, cnt; - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); + /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { cx_write(bus->reg_addr, msg->addr << 25); @@ -127,7 +128,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, wdata = msg->buf[cnt]; ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - if (cnt < msg->len-1 || !last) + if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; cx_write(bus->reg_addr, addr); @@ -162,7 +163,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, u32 ctrl, cnt; int retval; - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { @@ -178,11 +179,14 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, return 0; } + if (i2c_debug) + printk(" addr << 1) + 1); + for(cnt = 0; cnt < msg->len; cnt++) { ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; - if (cnt < msg->len-1 || !last) + if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; cx_write(bus->reg_addr, msg->addr << 25); @@ -195,9 +199,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, goto eio; msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; if (i2c_debug) { - if (!(ctrl & I2C_NOSTOP)) - printk(" addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); + printk(" %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) printk(" >\n"); } -- cgit v1.2.3 From 012cf21975e8ccc2d57859413b336087f7f98763 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 25 Aug 2006 16:52:54 -0300 Subject: V4L/DVB (6408): Cleanup: Removed obsoleted code from bttv-cards This is part of the old V4L1->V4L2 bttv patch, ported to current tree by Mauro Carvalho Chehab Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 4f91f98db37..6a2d3725882 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -4624,6 +4624,7 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) if (btv->radio_user) return; + if (set) { if (v->mode & VIDEO_SOUND_MONO) { val = 0x0000; -- cgit v1.2.3 From 302f61ad5db0e6a4c265e1f6454c102e2283a926 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 26 Oct 2007 10:53:21 -0300 Subject: V4L/DVB (6409): Cleanup: removed i2c_vidiocschan This is part of the old V4L1->V4L2 bttv patch, ported to current tree by Mauro Carvalho Chehab Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 581a3c95573..3e5c50ac913 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1254,16 +1254,6 @@ audio_input(struct bttv *btv, int input) return audio_mux(btv, input, btv->mute); } -static void -i2c_vidiocschan(struct bttv *btv) -{ - v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; - - bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); - if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200) - bttv_tda9880_setnorm(btv,btv->tvnorm); -} - static void bttv_crop_calc_limits(struct bttv_crop *c) { @@ -1298,6 +1288,7 @@ static int set_tvnorm(struct bttv *btv, unsigned int norm) { const struct bttv_tvnorm *tvnorm; + v4l2_std_id id; if (norm < 0 || norm >= BTTV_TVNORMS) return -EINVAL; @@ -1334,6 +1325,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm) bttv_tda9880_setnorm(btv,norm); break; } + id = tvnorm->v4l2_id; + bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id); + return 0; } @@ -1359,7 +1353,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ? TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN)); set_tvnorm(btv, norm); - i2c_vidiocschan(btv); } static void init_irqreg(struct bttv *btv) @@ -2095,7 +2088,6 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) mutex_lock(&btv->lock); set_tvnorm(btv,i); - i2c_vidiocschan(btv); mutex_unlock(&btv->lock); return 0; } @@ -3777,7 +3769,7 @@ static int bttv_open(struct inode *inode, struct file *file) V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), fh); - i2c_vidiocschan(btv); + set_tvnorm(btv,btv->tvnorm); btv->users++; -- cgit v1.2.3 From e84619b17440ccca4e4db7583d126c4189b987e5 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 26 Oct 2007 11:01:08 -0300 Subject: V4L/DVB (6410): Partial conversion from V4L1 to V4L2 This is part of the old V4L1->V4L2 bttv patch, ported to current tree by Mauro Carvalho Chehab Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/Kconfig | 2 +- drivers/media/video/bt8xx/bttv-driver.c | 663 +++++++------------------------- drivers/media/video/bt8xx/bttvp.h | 4 - 3 files changed, 131 insertions(+), 538 deletions(-) diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 2ca162b390a..ce93312cf84 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1 + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 3e5c50ac913..cb50fde2be8 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -9,6 +9,9 @@ some v4l2 code lines are taken from Justin's bttv2 driver which is (c) 2000 Justin Schoeman + V4L1 removal from: + (c) 2005-2006 Nickolay V. Shmyrev + Cropping and overscan support Copyright (C) 2005, 2006 Michael H. Schimek Sponsored by OPQ Systems AB @@ -1912,111 +1915,6 @@ static struct videobuf_queue_ops bttv_video_qops = { static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { switch (cmd) { - case BTTV_VERSION: - return BTTV_VERSION_CODE; - - /* *** v4l1 *** ************************************************ */ - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - *freq = btv->freq; - return 0; - } - case VIDIOCSFREQ: - { - struct v4l2_frequency freq; - - memset(&freq, 0, sizeof(freq)); - freq.frequency = *(unsigned long *)arg; - mutex_lock(&btv->lock); - freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - btv->freq = *(unsigned long *)arg; - bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv,*(unsigned long *)arg); - mutex_unlock(&btv->lock); - return 0; - } - - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; - strcpy(v->name, "Television"); - v->rangelow = 0; - v->rangehigh = 0x7FFFFFFF; - v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v->mode = btv->tvnorm; - v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - bttv_call_i2c_clients(btv,cmd,v); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; - if (v->mode >= BTTV_TVNORMS) - return -EINVAL; - - mutex_lock(&btv->lock); - set_tvnorm(btv,v->mode); - bttv_call_i2c_clients(btv,cmd,v); - mutex_unlock(&btv->lock); - return 0; - } - - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - unsigned int channel = v->channel; - - if (channel >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - v->tuners=0; - v->flags = VIDEO_VC_AUDIO; - v->type = VIDEO_TYPE_CAMERA; - v->norm = btv->tvnorm; - if (channel == bttv_tvcards[btv->c.type].tuner) { - strcpy(v->name,"Television"); - v->flags|=VIDEO_VC_TUNER; - v->type=VIDEO_TYPE_TV; - v->tuners=1; - } else if (channel == btv->svhs) { - strcpy(v->name,"S-Video"); - } else { - sprintf(v->name,"Composite%d",channel); - } - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - unsigned int channel = v->channel; - - if (channel >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - if (v->norm >= BTTV_TVNORMS) - return -EINVAL; - - mutex_lock(&btv->lock); - if (channel == btv->input && - v->norm == btv->tvnorm) { - /* nothing to do */ - mutex_unlock(&btv->lock); - return 0; - } - - set_input(btv, v->channel, v->norm); - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOCGAUDIO: { struct video_audio *v = arg; @@ -2152,45 +2050,6 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return 0; } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - memset(t,0,sizeof(*t)); - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_hook) { - /* Hmmm ... */ - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - btv->audio_hook(btv,&va,0); - t->audmode = V4L2_TUNER_MODE_MONO; - t->rxsubchans = V4L2_TUNER_SUB_MONO; - if(va.mode & VIDEO_SOUND_STEREO) { - t->audmode = V4L2_TUNER_MODE_STEREO; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - } - if(va.mode & VIDEO_SOUND_LANG2) { - t->audmode = V4L2_TUNER_MODE_LANG1; - t->rxsubchans = V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; - } - } - /* FIXME: fill capability+audmode */ - mutex_unlock(&btv->lock); - return 0; - } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; @@ -2251,6 +2110,10 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); return 0; } + case VIDIOC_G_CTRL: + return get_control(btv,arg); + case VIDIOC_S_CTRL: + return set_control(btv,arg); #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: @@ -2795,7 +2658,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, { struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; - unsigned long flags; int retval = 0; if (bttv_debug > 1) @@ -2805,9 +2667,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, bttv_reinit_bt848(btv); switch (cmd) { - case VIDIOCSFREQ: - case VIDIOCSTUNER: - case VIDIOCSCHAN: case VIDIOC_S_CTRL: case VIDIOC_S_STD: case VIDIOC_S_INPUT: @@ -2819,237 +2678,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, }; switch (cmd) { - - /* *** v4l1 *** ************************************************ */ - case VIDIOCGCAP: - { - struct video_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->video_dev->name); - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - /* vbi */ - cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; - } else { - /* others */ - cap->type = VID_TYPE_CAPTURE| - VID_TYPE_TUNER| - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - if (no_overlay <= 0) - cap->type |= VID_TYPE_OVERLAY; - - cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; - cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; - cap->minwidth = 48; - cap->minheight = 32; - } - cap->channels = bttv_tvcards[btv->c.type].video_inputs; - cap->audios = bttv_tvcards[btv->c.type].audio_inputs; - return 0; - } - - case VIDIOCGPICT: - { - struct video_picture *pic = arg; - - memset(pic,0,sizeof(*pic)); - pic->brightness = btv->bright; - pic->contrast = btv->contrast; - pic->hue = btv->hue; - pic->colour = btv->saturation; - if (fh->fmt) { - pic->depth = fh->fmt->depth; - pic->palette = fh->fmt->palette; - } - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *pic = arg; - const struct bttv_format *fmt; - - fmt = format_by_palette(pic->palette); - if (NULL == fmt) - return -EINVAL; - mutex_lock(&fh->cap.lock); - if (fmt->flags & FORMAT_FLAGS_RAW) { - /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL * - RAW_LINES * 2. F1 is stored at offset 0, F2 - at buffer size / 2. */ - fh->width = RAW_BPL; - fh->height = gbufsize / RAW_BPL; - btv->init.width = RAW_BPL; - btv->init.height = gbufsize / RAW_BPL; - } - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - if (bigendian) { - /* dirty hack time: swap bytes for overlay if the - display adaptor is big endian (insmod option) */ - if (fmt->palette == VIDEO_PALETTE_RGB555 || - fmt->palette == VIDEO_PALETTE_RGB565 || - fmt->palette == VIDEO_PALETTE_RGB32) { - fh->ovfmt = fmt+1; - } - } - bt848_bright(btv,pic->brightness); - bt848_contrast(btv,pic->contrast); - bt848_hue(btv,pic->hue); - bt848_sat(btv,pic->colour); - mutex_unlock(&fh->cap.lock); - return 0; - } - - case VIDIOCGWIN: - { - struct video_window *win = arg; - - memset(win,0,sizeof(*win)); - win->x = fh->ov.w.left; - win->y = fh->ov.w.top; - win->width = fh->ov.w.width; - win->height = fh->ov.w.height; - return 0; - } - case VIDIOCSWIN: - { - struct video_window *win = arg; - struct v4l2_window w2; - - if (no_overlay > 0) { - printk ("VIDIOCSWIN: no_overlay\n"); - return -EINVAL; - } - - w2.field = V4L2_FIELD_ANY; - w2.w.left = win->x; - w2.w.top = win->y; - w2.w.width = win->width; - w2.w.height = win->height; - w2.clipcount = win->clipcount; - w2.clips = (struct v4l2_clip __user *)win->clips; - retval = setup_window(fh, btv, &w2, 0); - if (0 == retval) { - /* on v4l1 this ioctl affects the read() size too */ - fh->width = fh->ov.w.width; - fh->height = fh->ov.w.height; - btv->init.width = fh->ov.w.width; - btv->init.height = fh->ov.w.height; - } - return retval; - } - - case VIDIOCGFBUF: - { - struct video_buffer *fbuf = arg; - - fbuf->base = btv->fbuf.base; - fbuf->width = btv->fbuf.fmt.width; - fbuf->height = btv->fbuf.fmt.height; - fbuf->bytesperline = btv->fbuf.fmt.bytesperline; - if (fh->ovfmt) - fbuf->depth = fh->ovfmt->depth; - else { - if (fbuf->width) - fbuf->depth = ((fbuf->bytesperline<<3) - + (fbuf->width-1) ) - /fbuf->width; - else - fbuf->depth = 0; - } - return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer *fbuf = arg; - const struct bttv_format *fmt; - unsigned long end; - - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - end = (unsigned long)fbuf->base + - fbuf->height * fbuf->bytesperline; - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - - switch (fbuf->depth) { - case 8: - fmt = format_by_palette(VIDEO_PALETTE_HI240); - break; - case 16: - fmt = format_by_palette(VIDEO_PALETTE_RGB565); - break; - case 24: - fmt = format_by_palette(VIDEO_PALETTE_RGB24); - break; - case 32: - fmt = format_by_palette(VIDEO_PALETTE_RGB32); - break; - case 15: - fbuf->depth = 16; - fmt = format_by_palette(VIDEO_PALETTE_RGB555); - break; - default: - fmt = NULL; - break; - } - if (NULL == fmt) - goto fh_unlock_and_return; - - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - btv->fbuf.base = fbuf->base; - btv->fbuf.fmt.width = fbuf->width; - btv->fbuf.fmt.height = fbuf->height; - if (fbuf->bytesperline) - btv->fbuf.fmt.bytesperline = fbuf->bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8; - mutex_unlock(&fh->cap.lock); - return 0; - } - - case VIDIOCCAPTURE: - case VIDIOC_OVERLAY: - { - struct bttv_buffer *new; - int *on = arg; - - if (*on) { - /* verify args */ - if (NULL == btv->fbuf.base) - return -EINVAL; - if (!fh->ov.setup_ok) { - dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); - return -EINVAL; - } - } - - if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) - return -EBUSY; - - mutex_lock(&fh->cap.lock); - if (*on) { - fh->ov.tvnorm = btv->tvnorm; - new = videobuf_pci_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; - } - - /* switch over */ - retval = bttv_switch_overlay(btv,fh,new); - mutex_unlock(&fh->cap.lock); - return retval; - } - +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; @@ -3068,98 +2697,19 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mbuf->offsets[i] = i * gbufsize; return 0; } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - struct bttv_buffer *buf; - enum v4l2_field field; - __s32 height2; - int res; - - if (vm->frame >= VIDEO_MAX_FRAME) - return -EINVAL; - - res = bttv_resource(fh); - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; - - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; - if (NULL == buf) - goto fh_unlock_and_return; - if (0 == buf->vb.baddr) - goto fh_unlock_and_return; - if (buf->vb.state == STATE_QUEUED || - buf->vb.state == STATE_ACTIVE) - goto fh_unlock_and_return; - - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (vm->height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - retval = bttv_prepare_buffer(&fh->cap,btv,buf, - format_by_palette(vm->format), - vm->width,vm->height,field); - if (0 != retval) - goto fh_unlock_and_return; - btv->init.width = vm->width; - btv->init.height = vm->height; - spin_lock_irqsave(&btv->s_lock,flags); - buffer_queue(&fh->cap,&buf->vb); - spin_unlock_irqrestore(&btv->s_lock,flags); - mutex_unlock(&fh->cap.lock); - return 0; - } - case VIDIOCSYNC: - { - int *frame = arg; - struct bttv_buffer *buf; - - if (*frame >= VIDEO_MAX_FRAME) - return -EINVAL; - - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; - if (NULL == buf) - goto fh_unlock_and_return; - retval = videobuf_waiton(&buf->vb,0,1); - if (0 != retval) - goto fh_unlock_and_return; - switch (buf->vb.state) { - case STATE_ERROR: - retval = -EIO; - /* fall through */ - case STATE_DONE: - { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - videobuf_dma_sync(&fh->cap,dma); - bttv_dma_free(&fh->cap,btv,buf); - break; - } - default: - retval = -EINVAL; - break; - } - mutex_unlock(&fh->cap.lock); - return retval; - } - +#endif case VIDIOCGVBIFMT: - if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) { - retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); - if (0 != retval) - return retval; - } - - /* fall through */ - case VIDIOCSVBIFMT: - return v4l_compat_translate_ioctl(inode, file, cmd, - arg, bttv_do_ioctl); - - case BTTV_VERSION: + case VIDIOCSYNC: + case VIDIOCMCAPTURE: + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCGWIN: + case VIDIOCSWIN: + case VIDIOCGCAP: + case VIDIOCGPICT: + case VIDIOCSPICT: case VIDIOCGFREQ: case VIDIOCSFREQ: case VIDIOCGTUNER: @@ -3168,7 +2718,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, case VIDIOCSCHAN: case VIDIOCGAUDIO: case VIDIOCSAUDIO: - return bttv_common_ioctls(btv,cmd,arg); + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + bttv_do_ioctl); /* *** v4l2 *** ************************************************ */ case VIDIOC_QUERYCAP: @@ -3196,7 +2747,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, cap->capabilities |= V4L2_CAP_TUNER; return 0; } - case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; @@ -3246,7 +2796,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, strlcpy(f->description,bttv_formats[i].name,sizeof(f->description)); return 0; } - case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; @@ -3273,6 +2822,38 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, fb->fmt.pixelformat = fh->ovfmt->fourcc; return 0; } + case VIDIOC_OVERLAY: + { + struct bttv_buffer *new; + int *on = arg; + + if (*on) { + /* verify args */ + if (NULL == btv->fbuf.base) + return -EINVAL; + if (!fh->ov.setup_ok) { + dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); + return -EINVAL; + } + } + + if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) + return -EBUSY; + + mutex_lock(&fh->cap.lock); + if (*on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_pci_alloc(sizeof(*new)); + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; + } + + /* switch over */ + retval = bttv_switch_overlay(btv,fh,new); + mutex_unlock(&fh->cap.lock); + return retval; + } case VIDIOC_S_FBUF: { struct v4l2_framebuffer *fb = arg; @@ -3340,13 +2921,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&fh->cap.lock); return retval; } - case VIDIOC_REQBUFS: return videobuf_reqbufs(bttv_queue(fh),arg); - case VIDIOC_QUERYBUF: return videobuf_querybuf(bttv_queue(fh),arg); - case VIDIOC_QBUF: { int res = bttv_resource(fh); @@ -3355,11 +2933,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return -EBUSY; return videobuf_qbuf(bttv_queue(fh),arg); } - case VIDIOC_DQBUF: return videobuf_dqbuf(bttv_queue(fh),arg, file->f_flags & O_NONBLOCK); - case VIDIOC_STREAMON: { int res = bttv_resource(fh); @@ -3422,10 +2998,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, } return 0; } - case VIDIOC_G_CTRL: - return get_control(btv,arg); - case VIDIOC_S_CTRL: - return set_control(btv,arg); case VIDIOC_G_PARM: { struct v4l2_streamparm *parm = arg; @@ -3438,6 +3010,45 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, parm->parm.capture.timeperframe = s.frameperiod; return 0; } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t,0,sizeof(*t)); + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_hook) { + /* Hmmm ... */ + struct video_audio va; + memset(&va, 0, sizeof(struct video_audio)); + btv->audio_hook(btv,&va,0); + t->audmode = V4L2_TUNER_MODE_MONO; + t->rxsubchans = V4L2_TUNER_SUB_MONO; + if(va.mode & VIDEO_SOUND_STEREO) { + t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + } + if(va.mode & VIDEO_SOUND_LANG2) { + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_LANG1 + | V4L2_TUNER_SUB_LANG2; + } + } + /* FIXME: fill capability+audmode */ + mutex_unlock(&btv->lock); + return 0; + } case VIDIOC_G_PRIORITY: { @@ -3575,15 +3186,15 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUMINPUT: case VIDIOC_G_INPUT: case VIDIOC_S_INPUT: - case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: case VIDIOC_LOG_STATUS: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); - default: return -ENOIOCTLCMD; } @@ -3601,33 +3212,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, static int bttv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct bttv_fh *fh = file->private_data; - - switch (cmd) { - case BTTV_VBISIZE: - { - const struct bttv_tvnorm *tvnorm; - - tvnorm = fh->vbi_fmt.tvnorm; - - if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] || - fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] || - fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) { - /* BTTV_VBISIZE cannot express these parameters, - however open() resets the paramters to defaults - and apps shouldn't call BTTV_VBISIZE after - VIDIOC_S_FMT. */ - return -EINVAL; - } - - bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); - return (fh->vbi_fmt.fmt.count[0] * 2 - * fh->vbi_fmt.fmt.samples_per_line); - } - - default: - return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); - } + return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); } static ssize_t bttv_read(struct file *file, char __user *data, @@ -3926,43 +3511,55 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, struct bttv *btv = file->private_data; switch (cmd) { - case VIDIOCGCAP: + case VIDIOC_QUERYCAP: { - struct video_capability *cap = arg; + struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->radio_dev->name); - cap->type = VID_TYPE_TUNER; - cap->channels = 1; - cap->audios = 1; + strcpy(cap->driver, "bttv"); + strlcpy(cap->card, btv->radio_dev->name,sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; return 0; } - - case VIDIOCGTUNER: + case VIDIOC_G_TUNER: { - struct video_tuner *v = arg; + struct v4l2_tuner *t = arg; - if(v->tuner) + if (UNSET == bttv_tvcards[btv->c.type].tuner) return -EINVAL; - memset(v,0,sizeof(*v)); - strcpy(v->name, "Radio"); - bttv_call_i2c_clients(btv,cmd,v); + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t,0,sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + + mutex_unlock(&btv->lock); + return 0; } - case VIDIOCSTUNER: - /* nothing to do */ - return 0; - - case BTTV_VERSION: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: + case VIDIOC_S_TUNER: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: case VIDIOC_LOG_STATUS: case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); - + case VIDIOCGCAP: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + radio_do_ioctl); default: return -ENOIOCTLCMD; } diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index d4ac4c4b49b..e60e54ad173 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -458,10 +458,6 @@ struct bttv { extern unsigned int bttv_num; extern struct bttv bttvs[BTTV_MAX]; -/* private ioctls */ -#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) -#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) - #endif #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) -- cgit v1.2.3 From c96dd0710685a0932c16ecc351621af3fe0cb2c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 26 Oct 2007 16:51:47 -0300 Subject: V4L/DVB (6411): remove V4L1 from being compiled when V4L2 only is selected Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 95 +++++++++------------------------ drivers/media/video/bt8xx/bttvp.h | 1 - 2 files changed, 24 insertions(+), 72 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index cb50fde2be8..061f52ba824 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -12,6 +12,9 @@ V4L1 removal from: (c) 2005-2006 Nickolay V. Shmyrev + Fixes to be fully V4L2 compliant by + (c) 2006 Mauro Carvalho Chehab + Cropping and overscan support Copyright (C) 2005, 2006 Michael H. Schimek Sponsored by OPQ Systems AB @@ -160,7 +163,7 @@ MODULE_LICENSE("GPL"); static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = to_video_device(cd); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } @@ -476,28 +479,24 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); static const struct bttv_format bttv_formats[] = { { .name = "8 bpp, gray", - .palette = VIDEO_PALETTE_GREY, .fourcc = V4L2_PIX_FMT_GREY, .btformat = BT848_COLOR_FMT_Y8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, },{ .name = "8 bpp, dithered color", - .palette = VIDEO_PALETTE_HI240, .fourcc = V4L2_PIX_FMT_HI240, .btformat = BT848_COLOR_FMT_RGB8, .depth = 8, .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, },{ .name = "15 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB555, .fourcc = V4L2_PIX_FMT_RGB555, .btformat = BT848_COLOR_FMT_RGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "15 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB555X, .btformat = BT848_COLOR_FMT_RGB15, .btswap = 0x03, /* byteswap */ @@ -505,14 +504,12 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB565, .fourcc = V4L2_PIX_FMT_RGB565, .btformat = BT848_COLOR_FMT_RGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB565X, .btformat = BT848_COLOR_FMT_RGB16, .btswap = 0x03, /* byteswap */ @@ -520,21 +517,18 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "24 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB24, .fourcc = V4L2_PIX_FMT_BGR24, .btformat = BT848_COLOR_FMT_RGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB32, .fourcc = V4L2_PIX_FMT_BGR32, .btformat = BT848_COLOR_FMT_RGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB32, .btformat = BT848_COLOR_FMT_RGB32, .btswap = 0x0f, /* byte+word swap */ @@ -542,21 +536,18 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", - .palette = VIDEO_PALETTE_YUV422, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", - .palette = VIDEO_PALETTE_YUYV, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, UYVY", - .palette = VIDEO_PALETTE_UYVY, .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, .btswap = 0x03, /* byteswap */ @@ -564,7 +555,6 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV422P, .fourcc = V4L2_PIX_FMT_YUV422P, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 16, @@ -573,7 +563,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 0, },{ .name = "4:2:0, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV420P, .fourcc = V4L2_PIX_FMT_YUV420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -582,7 +571,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 1, },{ .name = "4:2:0, planar, Y-Cr-Cb", - .palette = -1, .fourcc = V4L2_PIX_FMT_YVU420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -591,7 +579,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 1, },{ .name = "4:1:1, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV411P, .fourcc = V4L2_PIX_FMT_YUV411P, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 12, @@ -600,7 +587,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 0, },{ .name = "4:1:0, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV410P, .fourcc = V4L2_PIX_FMT_YUV410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -609,7 +595,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 2, },{ .name = "4:1:0, planar, Y-Cr-Cb", - .palette = -1, .fourcc = V4L2_PIX_FMT_YVU410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -618,7 +603,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 2, },{ .name = "raw scanlines", - .palette = VIDEO_PALETTE_RAW, .fourcc = -1, .btformat = BT848_COLOR_FMT_RAW, .depth = 8, @@ -1450,7 +1434,6 @@ static void bttv_reinit_bt848(struct bttv *btv) static int get_control(struct bttv *btv, struct v4l2_control *c) { - struct video_audio va; int i; for (i = 0; i < BTTV_CTLS; i++) @@ -1458,7 +1441,10 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) break; if (i == BTTV_CTLS) return -EINVAL; +#ifdef CONFIG_VIDEO_V4L1 if (btv->audio_hook && i >= 4 && i <= 8) { + struct video_audio va; + memset(&va,0,sizeof(va)); btv->audio_hook(btv,&va,0); switch (c->id) { @@ -1480,6 +1466,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) } return 0; } +#endif switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = btv->bright; @@ -1543,7 +1530,6 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) static int set_control(struct bttv *btv, struct v4l2_control *c) { - struct video_audio va; int i,val; for (i = 0; i < BTTV_CTLS; i++) @@ -1551,7 +1537,10 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) break; if (i == BTTV_CTLS) return -EINVAL; +#ifdef CONFIG_VIDEO_V4L1 if (btv->audio_hook && i >= 4 && i <= 8) { + struct video_audio va; + memset(&va,0,sizeof(va)); btv->audio_hook(btv,&va,0); switch (c->id) { @@ -1581,6 +1570,7 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) btv->audio_hook(btv,&va,1); return 0; } +#endif switch (c->id) { case V4L2_CID_BRIGHTNESS: bt848_bright(btv,c->value); @@ -1688,20 +1678,6 @@ static void bttv_field_count(struct bttv *btv) } } -static const struct bttv_format* -format_by_palette(int palette) -{ - unsigned int i; - - for (i = 0; i < BTTV_FORMATS; i++) { - if (-1 == bttv_formats[i].palette) - continue; - if (bttv_formats[i].palette == palette) - return bttv_formats+i; - } - return NULL; -} - static const struct bttv_format* format_by_fourcc(int fourcc) { @@ -1915,6 +1891,7 @@ static struct videobuf_queue_ops bttv_video_qops = { static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { switch (cmd) { +#ifdef CONFIG_VIDEO_V4L1 case VIDIOCGAUDIO: { struct video_audio *v = arg; @@ -1953,7 +1930,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) mutex_unlock(&btv->lock); return 0; } - +#endif /* *** v4l2 *** ************************************************ */ case VIDIOC_ENUMSTD: { @@ -2060,6 +2037,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&btv->lock); bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); +#ifdef CONFIG_VIDEO_V4L1 if (btv->audio_hook) { struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); @@ -2074,6 +2052,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) va.mode = VIDEO_SOUND_LANG2; btv->audio_hook(btv,&va,1); } +#endif mutex_unlock(&btv->lock); return 0; } @@ -2698,28 +2677,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return 0; } #endif - case VIDIOCGVBIFMT: - case VIDIOCSVBIFMT: - case VIDIOCSYNC: - case VIDIOCMCAPTURE: - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCGWIN: - case VIDIOCSWIN: - case VIDIOCGCAP: - case VIDIOCGPICT: - case VIDIOCSPICT: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGCHAN: - case VIDIOCSCHAN: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - bttv_do_ioctl); /* *** v4l2 *** ************************************************ */ case VIDIOC_QUERYCAP: @@ -2973,6 +2930,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return 0; } *c = bttv_ctls[i]; +#ifdef CONFIG_VIDEO_V4L1 if (btv->audio_hook && i >= 4 && i <= 8) { struct video_audio va; memset(&va,0,sizeof(va)); @@ -2996,6 +2954,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, break; } } +#endif return 0; } case VIDIOC_G_PARM: @@ -3027,7 +2986,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, t->type = V4L2_TUNER_ANALOG_TV; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; - +#ifdef CONFIG_VIDEO_V4L1 if (btv->audio_hook) { /* Hmmm ... */ struct video_audio va; @@ -3045,6 +3004,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, | V4L2_TUNER_SUB_LANG2; } } +#endif /* FIXME: fill capability+audmode */ mutex_unlock(&btv->lock); return 0; @@ -3196,7 +3156,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); default: - return -ENOIOCTLCMD; + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + bttv_do_ioctl); } return 0; @@ -3551,17 +3512,9 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_S_REGISTER: return bttv_common_ioctls(btv,cmd,arg); - case VIDIOCGCAP: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: + default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, radio_do_ioctl); - default: - return -ENOIOCTLCMD; } return 0; } @@ -4357,7 +4310,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->init.btv = btv; btv->init.ov.w.width = 320; btv->init.ov.w.height = 240; - btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24); + btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); btv->init.width = 320; btv->init.height = 240; btv->input = 0; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index e60e54ad173..37b96a54f90 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -112,7 +112,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[]; struct bttv_format { char *name; - int palette; /* video4linux 1 */ int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ int btswap; /* BT848_COLOR_CTL_* */ -- cgit v1.2.3 From c2806d03c090a1bf9c8c94bbecb92242b57469f3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 26 Oct 2007 16:54:54 -0300 Subject: V4L/DVB (6412): Audio hooks moved to another file Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/Makefile | 2 +- drivers/media/video/bt8xx/bttv-audio-hook.c | 390 +++++++++++++++++++++++++++ drivers/media/video/bt8xx/bttv-audio-hook.h | 23 ++ drivers/media/video/bt8xx/bttv-cards.c | 399 +--------------------------- drivers/media/video/bt8xx/bttv.h | 2 + drivers/media/video/bt8xx/bttvp.h | 3 +- 6 files changed, 420 insertions(+), 399 deletions(-) create mode 100644 drivers/media/video/bt8xx/bttv-audio-hook.c create mode 100644 drivers/media/video/bt8xx/bttv-audio-hook.h diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index a096a03418a..924d216d957 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -4,7 +4,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o + bttv-input.o bttv-audio-hook.o obj-$(CONFIG_VIDEO_BT848) += bttv.o diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c new file mode 100644 index 00000000000..1e7fcaa259e --- /dev/null +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -0,0 +1,390 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +/* ----------------------------------------------------------------------- */ +/* winview */ + +#include "bttvp.h" +#include + +static void winview_audio(struct bttv *btv, struct video_audio *v, int set) +{ + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + if (!set) { + /* Fixed by Leandro Lucarella flags |= VIDEO_AUDIO_VOLUME; + return; + } + + /* 32 levels logarithmic */ + vol = 32 - ((v->volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; + data = gpio_read(); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<mode & VIDEO_SOUND_LANG1) + con = 0x000; + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x300; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x200; +/* if (v->mode & VIDEO_SOUND_MONO) + * con = 0x100; */ + gpio_bits(0x300, con); + } else { + v->mode = VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +static void +gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val, con; + + if (btv->radio_user) + return; + + val = gpio_read(); + if (set) { + con = 0x000; + if (v->mode & VIDEO_SOUND_LANG2) { + if (v->mode & VIDEO_SOUND_LANG1) { + /* LANG1 + LANG2 */ + con = 0x100; + } + else { + /* LANG2 */ + con = 0x300; + } + } + if (con != (val & 0x300)) { + gpio_bits(0x300, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"gvbctv5pci"); + } + } else { + switch (val & 0x70) { + case 0x10: + v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + break; + case 0x30: + v->mode = VIDEO_SOUND_LANG2; + break; + case 0x50: + v->mode = VIDEO_SOUND_LANG1; + break; + case 0x60: + v->mode = VIDEO_SOUND_STEREO; + break; + case 0x70: + v->mode = VIDEO_SOUND_MONO; + break; + default: + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } + } +} + +/* + * Mario Medina Nussbaum + * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, + * 0xdde enables mono and 0xccd enables sap + * + * Petr Vandrovec + * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select + * input/output sound connection, so both must be set for output mode. + * + * Looks like it's needed only for the "tvphone", the "tvphone 98" + * handles this with a tda9840 + * + */ +static void +avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x02; + if (v->mode & VIDEO_SOUND_STEREO) + val = 0x01; + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1; + return; + } +} + +static void +avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x01; + if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + return; + } +} + +/* Lifetec 9415 handling */ +static void +lt9415_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (gpio_read() & 0x4000) { + v->mode = VIDEO_SOUND_MONO; + return; + } + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ + val = 0x0080; + if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ + val = 0x0880; + if ((v->mode & VIDEO_SOUND_LANG1) || + (v->mode & VIDEO_SOUND_MONO)) + val = 0; + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + return; + } +} + +/* TDA9821 on TerraTV+ Bt848, Bt878 */ +static void +terratv_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x180000,0x180000); + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x080000; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x180000; + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"terratv"); + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +static void +winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (v->mode & VIDEO_SOUND_MONO) /* Mono */ + val = 0x420000; + if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ + val = 0x420000; + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x410000; + if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM + * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. + */ +static void +pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val = 0; + + if (btv->radio_user) + return; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) { + val = 0x01; + } + if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) + || (v->mode & VIDEO_SOUND_STEREO)) { + val = 0x02; + } + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pvbt878p9b"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +static void +fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val = 0xffff; + + if (btv->radio_user) + return; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) { + val = 0x0000; + } + if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) + || (v->mode & VIDEO_SOUND_STEREO)) { + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + } + if (val != 0xffff) { + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +static void +windvr_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) + val = 0x040000; + if (v->mode & VIDEO_SOUND_LANG1) + val = 0; + if (v->mode & VIDEO_SOUND_LANG2) + val = 0x100000; + if (v->mode & VIDEO_SOUND_STEREO) + val = 0; + if (val) { + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa + */ +static void +adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int con = 0xffffff; + + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ + + if (set) { + /* btor(***, BT848_GPIO_OUT_EN); */ + if (v->mode & VIDEO_SOUND_LANG1) + con = 0x00000000; + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x00180000; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x00000000; + if (v->mode & VIDEO_SOUND_MONO) + con = 0x00060000; + if (con != 0xffffff) { + gpio_bits(0x1e0000,con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h new file mode 100644 index 00000000000..9770cacc17b --- /dev/null +++ b/drivers/media/video/bt8xx/bttv-audio-hook.h @@ -0,0 +1,23 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttvp.h" + +static void winview_audio(struct bttv *btv, struct video_audio *v, int set); +static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); +static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, + int set); +static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, + int set); +static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); +static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); +static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set); +static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); +static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); +static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); +static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); +static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 6a2d3725882..78e5e29748a 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -39,6 +39,7 @@ #include "bttvp.h" #include #include +#include "bttv-audio-hook.h" /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); @@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv); static void init_PXC200(struct bttv *btv); static void init_RTV24(struct bttv *btv); -static void winview_audio(struct bttv *btv, struct video_audio *v, int set); -static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); -static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, - int set); -static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, - int set); -static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); -static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); -static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); -static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); -static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); static void rv605_muxsel(struct bttv *btv, unsigned int input); static void eagle_muxsel(struct bttv *btv, unsigned int input); static void xguard_muxsel(struct bttv *btv, unsigned int input); @@ -3954,7 +3941,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) void bttv_tda9880_setnorm(struct bttv *btv, int norm) { /* fix up our card entry */ - if(norm==VIDEO_MODE_NTSC) { + if(norm==V4L2_STD_NTSC) { bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; @@ -4323,388 +4310,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ } - -/* ----------------------------------------------------------------------- */ -/* winview */ - -static void winview_audio(struct bttv *btv, struct video_audio *v, int set) -{ - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - if (!set) { - /* Fixed by Leandro Lucarella flags |= VIDEO_AUDIO_VOLUME; - return; - } - - /* 32 levels logarithmic */ - vol = 32 - ((v->volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = gpio_read(); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<mode & VIDEO_SOUND_LANG1) - con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x300; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x200; -/* if (v->mode & VIDEO_SOUND_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - v->mode = VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -static void -gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val, con; - - if (btv->radio_user) - return; - - val = gpio_read(); - if (set) { - con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) { - if (v->mode & VIDEO_SOUND_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } - } - if (con != (val & 0x300)) { - gpio_bits(0x300, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); - } - } else { - switch (val & 0x70) { - case 0x10: - v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - break; - case 0x30: - v->mode = VIDEO_SOUND_LANG2; - break; - case 0x50: - v->mode = VIDEO_SOUND_LANG1; - break; - case 0x60: - v->mode = VIDEO_SOUND_STEREO; - break; - case 0x70: - v->mode = VIDEO_SOUND_MONO; - break; - default: - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } - } -} - -/* - * Mario Medina Nussbaum - * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, - * 0xdde enables mono and 0xccd enables sap - * - * Petr Vandrovec - * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select - * input/output sound connection, so both must be set for output mode. - * - * Looks like it's needed only for the "tvphone", the "tvphone 98" - * handles this with a tda9840 - * - */ -static void -avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x02; - if (v->mode & VIDEO_SOUND_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1; - return; - } -} - -static void -avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x01; - if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - return; - } -} - -/* Lifetec 9415 handling */ -static void -lt9415_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (gpio_read() & 0x4000) { - v->mode = VIDEO_SOUND_MONO; - return; - } - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ - val = 0x0080; - if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ - val = 0x0880; - if ((v->mode & VIDEO_SOUND_LANG1) || - (v->mode & VIDEO_SOUND_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - return; - } -} - -/* TDA9821 on TerraTV+ Bt848, Bt878 */ -static void -terratv_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x180000,0x180000); - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x080000; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -static void -winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned long val = 0; - - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (v->mode & VIDEO_SOUND_MONO) /* Mono */ - val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ - val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x410000; - if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM - * revision 9B has on-board TDA9874A sound decoder). - * - * Note: There are card variants without tda9874a. Forcing the "stereo sound route" - * will mute this cards. - */ -static void -pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val = 0; - - if (btv->radio_user) - return; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) { - val = 0x01; - } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for FlyVideo 2000S (with tda9874 decoder) - * based on pvbt878p9b_audio() - this is not tested, please fix!!! - */ -static void -fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val = 0xffff; - - if (btv->radio_user) - return; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) { - val = 0x0000; - } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * sound control for Canopus WinDVR PCI - * Masaki Suzuki - */ -static void -windvr_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned long val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) - val = 0x040000; - if (v->mode & VIDEO_SOUND_LANG1) - val = 0; - if (v->mode & VIDEO_SOUND_LANG2) - val = 0x100000; - if (v->mode & VIDEO_SOUND_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * sound control for AD-TVK503 - * Hiroshi Takekawa - */ -static void -adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0xffffff; - - /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (v->mode & VIDEO_SOUND_LANG1) - con = 0x00000000; - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x00180000; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x00000000; - if (v->mode & VIDEO_SOUND_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] * * This is needed because rv605 don't use a normal multiplex, but a crosspoint diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 19e75d50a10..2edef15ba35 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -241,7 +241,9 @@ struct tvcard unsigned int radio_addr; unsigned int has_radio; +#ifdef CONFIG_VIDEO_V4L1 void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); +#endif void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 37b96a54f90..fdd78f8b1dc 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -336,8 +336,9 @@ struct bttv { /* old gpio interface */ wait_queue_head_t gpioq; int shutdown; +#ifdef CONFIG_VIDEO_V4L1 void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); - +#endif /* new gpio interface */ spinlock_t gpio_lock; -- cgit v1.2.3 From 5b261016f04eb5df1e1e652794f1f4d7dd072566 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 25 Aug 2006 16:53:02 -0300 Subject: V4L/DVB (6413): Forward VIDIOCGAUDIO and VIDIOCSAUDIO through v4l1-compat Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 41 --------------------------------- 1 file changed, 41 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 061f52ba824..2cdbac30209 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1891,47 +1891,6 @@ static struct videobuf_queue_ops bttv_video_qops = { static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { switch (cmd) { -#ifdef CONFIG_VIDEO_V4L1 - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - - memset(v,0,sizeof(*v)); - strcpy(v->name,"Television"); - v->flags |= VIDEO_AUDIO_MUTABLE; - v->mode = VIDEO_SOUND_MONO; - - mutex_lock(&btv->lock); - bttv_call_i2c_clients(btv,cmd,v); - - /* card specific hooks */ - if (btv->audio_hook) - btv->audio_hook(btv,v,0); - - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *v = arg; - unsigned int audio = v->audio; - - if (audio >= bttv_tvcards[btv->c.type].audio_inputs) - return -EINVAL; - - mutex_lock(&btv->lock); - audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0); - bttv_call_i2c_clients(btv,cmd,v); - - /* card specific hooks */ - if (btv->audio_hook) - btv->audio_hook(btv,v,1); - - mutex_unlock(&btv->lock); - return 0; - } -#endif - /* *** v4l2 *** ************************************************ */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; -- cgit v1.2.3 From de5bec6bb57e88db7efa49c6f7de0794ae67d06a Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 26 Oct 2007 17:15:19 -0300 Subject: V4L/DVB (6414): Remove bass, treble and balance from audio hook since they are unused Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 2cdbac30209..28b3a3efb84 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1454,15 +1454,6 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) case V4L2_CID_AUDIO_VOLUME: c->value = va.volume; break; - case V4L2_CID_AUDIO_BALANCE: - c->value = va.balance; - break; - case V4L2_CID_AUDIO_BASS: - c->value = va.bass; - break; - case V4L2_CID_AUDIO_TREBLE: - c->value = va.treble; - break; } return 0; } @@ -1557,15 +1548,6 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) case V4L2_CID_AUDIO_VOLUME: va.volume = c->value; break; - case V4L2_CID_AUDIO_BALANCE: - va.balance = c->value; - break; - case V4L2_CID_AUDIO_BASS: - va.bass = c->value; - break; - case V4L2_CID_AUDIO_TREBLE: - va.treble = c->value; - break; } btv->audio_hook(btv,&va,1); return 0; @@ -2899,18 +2881,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (!(va.flags & VIDEO_AUDIO_VOLUME)) *c = no_ctl; break; - case V4L2_CID_AUDIO_BALANCE: - if (!(va.flags & VIDEO_AUDIO_BALANCE)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_BASS: - if (!(va.flags & VIDEO_AUDIO_BASS)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_TREBLE: - if (!(va.flags & VIDEO_AUDIO_TREBLE)) - *c = no_ctl; - break; } } #endif -- cgit v1.2.3 From 40c6e683a238c561db00c4fdfead43cb3b19d75f Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 26 Oct 2007 17:21:30 -0300 Subject: V4L/DVB (6415): Restructurize volume hook and drop unused mute hook Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-audio-hook.c | 29 +++++++++++++-------------- drivers/media/video/bt8xx/bttv-driver.c | 31 +++-------------------------- 2 files changed, 17 insertions(+), 43 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c index 1e7fcaa259e..1f25cdbed7d 100644 --- a/drivers/media/video/bt8xx/bttv-audio-hook.c +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -5,13 +5,12 @@ * This code is placed under the terms of the GNU General Public License */ +#include "bttv-audio-hook.h" + /* ----------------------------------------------------------------------- */ /* winview */ -#include "bttvp.h" -#include - -static void winview_audio(struct bttv *btv, struct video_audio *v, int set) + void winview_audio(struct bttv *btv, struct video_audio *v, int set) { /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ int bits_out, loops, vol, data; @@ -57,7 +56,7 @@ static void winview_audio(struct bttv *btv, struct video_audio *v, int set) /* mono/stereo control for various cards (which don't use i2c chips but */ /* connect something to the GPIO pins */ -static void + void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int con = 0; @@ -79,7 +78,7 @@ gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set) } } -static void + void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val, con; @@ -142,7 +141,7 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) * handles this with a tda9840 * */ -static void + void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) { int val = 0; @@ -164,7 +163,7 @@ avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) } } -static void + void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) { int val = 0; @@ -185,7 +184,7 @@ avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) } /* Lifetec 9415 handling */ -static void + void lt9415_audio(struct bttv *btv, struct video_audio *v, int set) { int val = 0; @@ -215,7 +214,7 @@ lt9415_audio(struct bttv *btv, struct video_audio *v, int set) } /* TDA9821 on TerraTV+ Bt848, Bt878 */ -static void + void terratv_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int con = 0; @@ -235,7 +234,7 @@ terratv_audio(struct bttv *btv, struct video_audio *v, int set) } } -static void + void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned long val = 0; @@ -269,7 +268,7 @@ winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) * Note: There are card variants without tda9874a. Forcing the "stereo sound route" * will mute this cards. */ -static void + void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val = 0; @@ -301,7 +300,7 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) * sound control for FlyVideo 2000S (with tda9874 decoder) * based on pvbt878p9b_audio() - this is not tested, please fix!!! */ -static void + void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val = 0xffff; @@ -332,7 +331,7 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) * sound control for Canopus WinDVR PCI * Masaki Suzuki */ -static void + void windvr_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned long val = 0; @@ -361,7 +360,7 @@ windvr_audio(struct bttv *btv, struct video_audio *v, int set) * sound control for AD-TVK503 * Hiroshi Takekawa */ -static void + void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int con = 0xffffff; diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 28b3a3efb84..13221da6e40 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1434,23 +1434,13 @@ static void bttv_reinit_bt848(struct bttv *btv) static int get_control(struct bttv *btv, struct v4l2_control *c) { - int i; - - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) - return -EINVAL; #ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook && i >= 4 && i <= 8) { + if (btv->audio_hook && (c->id == V4L2_CID_AUDIO_VOLUME)) { struct video_audio va; memset(&va,0,sizeof(va)); btv->audio_hook(btv,&va,0); switch (c->id) { - case V4L2_CID_AUDIO_MUTE: - c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; - break; case V4L2_CID_AUDIO_VOLUME: c->value = va.volume; break; @@ -1521,30 +1511,15 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) static int set_control(struct bttv *btv, struct v4l2_control *c) { - int i,val; + int val; - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) - return -EINVAL; #ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook && i >= 4 && i <= 8) { + if (btv->audio_hook && (c->id == V4L2_CID_AUDIO_VOLUME)) { struct video_audio va; memset(&va,0,sizeof(va)); btv->audio_hook(btv,&va,0); switch (c->id) { - case V4L2_CID_AUDIO_MUTE: - if (c->value) { - va.flags |= VIDEO_AUDIO_MUTE; - audio_mute(btv, 1); - } else { - va.flags &= ~VIDEO_AUDIO_MUTE; - audio_mute(btv, 0); - } - break; - case V4L2_CID_AUDIO_VOLUME: va.volume = c->value; break; -- cgit v1.2.3 From 4b9b936f278163614543d66f8e8c93d5484dd148 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 25 Aug 2006 16:53:04 -0300 Subject: V4L/DVB (6416): Split hooks on volume and audio mode and rework their handling Also convert audio_mode_gpio functions from audio_hook Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-audio-hook.c | 173 +++++++++++++--------------- drivers/media/video/bt8xx/bttv-audio-hook.h | 28 ++--- drivers/media/video/bt8xx/bttv-cards.c | 38 +++--- drivers/media/video/bt8xx/bttv-driver.c | 97 ++++------------ drivers/media/video/bt8xx/bttv.h | 7 +- drivers/media/video/bt8xx/bttvp.h | 7 +- 6 files changed, 144 insertions(+), 206 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c index 1f25cdbed7d..a075198f830 100644 --- a/drivers/media/video/bt8xx/bttv-audio-hook.c +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -7,22 +7,18 @@ #include "bttv-audio-hook.h" +#include + /* ----------------------------------------------------------------------- */ /* winview */ - void winview_audio(struct bttv *btv, struct video_audio *v, int set) +void winview_volume(struct bttv *btv, __u16 volume) { /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ int bits_out, loops, vol, data; - if (!set) { - /* Fixed by Leandro Lucarella flags |= VIDEO_AUDIO_VOLUME; - return; - } - /* 32 levels logarithmic */ - vol = 32 - ((v->volume>>11)); + vol = 32 - ((volume>>11)); /* units */ bits_out = (PT2254_DBS_IN_2>>(vol%5)); /* tens */ @@ -56,30 +52,28 @@ /* mono/stereo control for various cards (which don't use i2c chips but */ /* connect something to the GPIO pins */ - void -gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set) +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int con = 0; if (set) { gpio_inout(0x300, 0x300); - if (v->mode & VIDEO_SOUND_LANG1) + if (t->audmode & V4L2_TUNER_MODE_LANG1) con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) + if (t->audmode & V4L2_TUNER_MODE_LANG2) con = 0x300; - if (v->mode & VIDEO_SOUND_STEREO) + if (t->audmode & V4L2_TUNER_MODE_STEREO) con = 0x200; -/* if (v->mode & VIDEO_SOUND_MONO) +/* if (t->audmode & V4L2_TUNER_MODE_MONO) * con = 0x100; */ gpio_bits(0x300, con); } else { - v->mode = VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } - void -gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int val, con; @@ -89,8 +83,8 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) val = gpio_read(); if (set) { con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) { - if (v->mode & VIDEO_SOUND_LANG1) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) { + if (t->audmode & V4L2_TUNER_MODE_LANG1) { /* LANG1 + LANG2 */ con = 0x100; } @@ -107,23 +101,23 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) } else { switch (val & 0x70) { case 0x10: - v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; break; case 0x30: - v->mode = VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG2; break; case 0x50: - v->mode = VIDEO_SOUND_LANG1; + t->audmode = V4L2_TUNER_MODE_LANG1; break; case 0x60: - v->mode = VIDEO_SOUND_STEREO; + t->audmode = V4L2_TUNER_MODE_STEREO; break; case 0x70: - v->mode = VIDEO_SOUND_MONO; + t->audmode = V4L2_TUNER_MODE_MONO; break; default: - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } } @@ -141,15 +135,15 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) * handles this with a tda9840 * */ - void -avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) + +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { int val = 0; if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ val = 0x02; - if (v->mode & VIDEO_SOUND_STEREO) + if (t->audmode & V4L2_TUNER_MODE_STEREO) val = 0x01; if (val) { gpio_bits(0x03,val); @@ -157,97 +151,96 @@ avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) bttv_gpio_tracking(btv,"avermedia"); } } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1; return; } } - void -avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) + +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { int val = 0; if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ val = 0x01; - if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ val = 0x02; btaor(val, ~0x03, BT848_GPIO_DATA); if (bttv_gpio) bttv_gpio_tracking(btv,"avermedia"); } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; return; } } /* Lifetec 9415 handling */ - void -lt9415_audio(struct bttv *btv, struct video_audio *v, int set) + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { int val = 0; if (gpio_read() & 0x4000) { - v->mode = VIDEO_SOUND_MONO; + t->audmode = V4L2_TUNER_MODE_MONO; return; } if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ val = 0x0080; - if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ val = 0x0880; - if ((v->mode & VIDEO_SOUND_LANG1) || - (v->mode & VIDEO_SOUND_MONO)) + if ((t->audmode & V4L2_TUNER_MODE_LANG1) || + (t->audmode & V4L2_TUNER_MODE_MONO)) val = 0; gpio_bits(0x0880, val); if (bttv_gpio) bttv_gpio_tracking(btv,"lt9415"); } else { /* autodetect doesn't work with this card :-( */ - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; return; } } /* TDA9821 on TerraTV+ Bt848, Bt878 */ - void -terratv_audio(struct bttv *btv, struct video_audio *v, int set) +void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int con = 0; if (set) { gpio_inout(0x180000,0x180000); - if (v->mode & VIDEO_SOUND_LANG2) + if (t->audmode & V4L2_TUNER_MODE_LANG2) con = 0x080000; - if (v->mode & VIDEO_SOUND_STEREO) + if (t->audmode & V4L2_TUNER_MODE_STEREO) con = 0x180000; gpio_bits(0x180000, con); if (bttv_gpio) bttv_gpio_tracking(btv,"terratv"); } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } - void -winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) + +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned long val = 0; if (set) { /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (v->mode & VIDEO_SOUND_MONO) /* Mono */ + if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ + if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ val = 0x410000; - if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ val = 0x020000; if (val) { gpio_bits(0x430000, val); @@ -255,8 +248,8 @@ winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) bttv_gpio_tracking(btv,"winfast2000"); } } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } @@ -268,8 +261,7 @@ winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) * Note: There are card variants without tda9874a. Forcing the "stereo sound route" * will mute this cards. */ - void -pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int val = 0; @@ -277,11 +269,11 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) return; if (set) { - if (v->mode & VIDEO_SOUND_MONO) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { val = 0x01; } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { val = 0x02; } if (val) { @@ -290,8 +282,8 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) bttv_gpio_tracking(btv,"pvbt878p9b"); } } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } @@ -300,8 +292,7 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) * sound control for FlyVideo 2000S (with tda9874 decoder) * based on pvbt878p9b_audio() - this is not tested, please fix!!! */ - void -fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int val = 0xffff; @@ -309,11 +300,11 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) return; if (set) { - if (v->mode & VIDEO_SOUND_MONO) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { val = 0x0000; } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ } if (val != 0xffff) { @@ -322,8 +313,8 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) bttv_gpio_tracking(btv,"fv2000s"); } } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } @@ -331,19 +322,18 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) * sound control for Canopus WinDVR PCI * Masaki Suzuki */ - void -windvr_audio(struct bttv *btv, struct video_audio *v, int set) +void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned long val = 0; if (set) { - if (v->mode & VIDEO_SOUND_MONO) + if (t->audmode & V4L2_TUNER_MODE_MONO) val = 0x040000; - if (v->mode & VIDEO_SOUND_LANG1) + if (t->audmode & V4L2_TUNER_MODE_LANG1) val = 0; - if (v->mode & VIDEO_SOUND_LANG2) + if (t->audmode & V4L2_TUNER_MODE_LANG2) val = 0x100000; - if (v->mode & VIDEO_SOUND_STEREO) + if (t->audmode & V4L2_TUNER_MODE_STEREO) val = 0; if (val) { gpio_bits(0x140000, val); @@ -351,8 +341,8 @@ windvr_audio(struct bttv *btv, struct video_audio *v, int set) bttv_gpio_tracking(btv,"windvr"); } } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } @@ -360,8 +350,7 @@ windvr_audio(struct bttv *btv, struct video_audio *v, int set) * sound control for AD-TVK503 * Hiroshi Takekawa */ - void -adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int con = 0xffffff; @@ -369,13 +358,13 @@ adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) if (set) { /* btor(***, BT848_GPIO_OUT_EN); */ - if (v->mode & VIDEO_SOUND_LANG1) + if (t->audmode & V4L2_TUNER_MODE_LANG1) con = 0x00000000; - if (v->mode & VIDEO_SOUND_LANG2) + if (t->audmode & V4L2_TUNER_MODE_LANG2) con = 0x00180000; - if (v->mode & VIDEO_SOUND_STEREO) + if (t->audmode & V4L2_TUNER_MODE_STEREO) con = 0x00000000; - if (v->mode & VIDEO_SOUND_MONO) + if (t->audmode & V4L2_TUNER_MODE_MONO) con = 0x00060000; if (con != 0xffffff) { gpio_bits(0x1e0000,con); @@ -383,7 +372,7 @@ adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) bttv_gpio_tracking(btv, "adtvk503"); } } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h index 9770cacc17b..159d07adeff 100644 --- a/drivers/media/video/bt8xx/bttv-audio-hook.h +++ b/drivers/media/video/bt8xx/bttv-audio-hook.h @@ -7,17 +7,17 @@ #include "bttvp.h" -static void winview_audio(struct bttv *btv, struct video_audio *v, int set); -static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); -static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, - int set); -static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, - int set); -static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); -static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); -static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); -static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); -static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); +void winview_volume (struct bttv *btv, __u16 volume); + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); + diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 78e5e29748a..63a47cd4c16 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -414,7 +414,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = avermedia_tvphone_audio, + .audio_mode_gpio= avermedia_tvphone_audio, .has_remote = 1, }, [BTTV_BOARD_MATRIX_VISION] = { @@ -526,7 +526,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = avermedia_tv_stereo_audio, + .audio_mode_gpio= avermedia_tv_stereo_audio, .no_gpioirq = 1, }, [BTTV_BOARD_VHX] = { @@ -591,7 +591,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = winview_audio, + .volume_gpio = winview_volume, .has_radio = 1, }, [BTTV_BOARD_AVEC_INTERCAP] = { @@ -715,7 +715,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = terratv_audio, + .audio_mode_gpio= terratv_audio, }, [BTTV_BOARD_HAUPPAUG_WCAM] = { .name = "Hauppauge WinCam newer (bt878)", @@ -763,7 +763,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = terratv_audio, + .audio_mode_gpio= terratv_audio, /* GPIO wiring: External 20 pin connector (for Active Radio Upgrade board) gpio00: i2c-sda @@ -902,7 +902,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = winfast2000_audio, + .audio_mode_gpio= winfast2000_audio, .has_remote = 1, }, [BTTV_BOARD_CHRONOS_VS2] = { @@ -1022,7 +1022,7 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, - .audio_hook = avermedia_tvphone_audio, + .audio_mode_gpio= avermedia_tvphone_audio, }, [BTTV_BOARD_PV951] = { .name = "ProVideo PV951", /* pic16c54 */ @@ -1154,7 +1154,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ALPS_TSHC6_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv3pci_audio, + .audio_mode_gpio= gvbctv3pci_audio, }, [BTTV_BOARD_PXELVWPLTVPAK] = { .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", @@ -1459,7 +1459,7 @@ struct tvcard bttv_tvcards[] = { /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, .gpiomute = 0x1800, - .audio_hook = fv2000s_audio, + .audio_mode_gpio= fv2000s_audio, .no_msp34xx = 1, .no_tda9875 = 1, .needs_tvaudio = 1, @@ -1500,7 +1500,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv3pci_audio, + .audio_mode_gpio= gvbctv3pci_audio, }, /* ---- card 0x44 ---------------------------------- */ @@ -1619,7 +1619,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ + .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ .has_radio = 1, /* Note: not all cards have radio */ .has_remote = 1, /* GPIO wiring: @@ -1697,7 +1697,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = windvr_audio, + .audio_mode_gpio= windvr_audio, }, [BTTV_BOARD_GRANDTEC_MULTI] = { .name = "GrandTec Multi Capture Card (Bt878)", @@ -1794,7 +1794,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC_M, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv5pci_audio, + .audio_mode_gpio= gvbctv5pci_audio, .has_radio = 1, }, [BTTV_BOARD_OSPREY1x0] = { @@ -2093,7 +2093,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = adtvk503_audio, + .audio_mode_gpio= adtvk503_audio, }, /* ---- card 0x64 ---------------------------------- */ @@ -3160,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv) /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio; - /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */ + if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio; + /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ } static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, @@ -3581,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->has_remote=1; if (!bttv_tvcards[btv->c.type].no_gpioirq) btv->gpioirq=1; - if (bttv_tvcards[btv->c.type].audio_hook) - btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; + if (bttv_tvcards[btv->c.type].volume_gpio) + btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio; + if (bttv_tvcards[btv->c.type].audio_mode_gpio) + btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio; if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) { /* detect Bt832 chip for quartzsight digital camera */ diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 13221da6e40..db0e4b78e7d 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1434,20 +1434,6 @@ static void bttv_reinit_bt848(struct bttv *btv) static int get_control(struct bttv *btv, struct v4l2_control *c) { -#ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook && (c->id == V4L2_CID_AUDIO_VOLUME)) { - struct video_audio va; - - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (c->id) { - case V4L2_CID_AUDIO_VOLUME: - c->value = va.volume; - break; - } - return 0; - } -#endif switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = btv->bright; @@ -1513,21 +1499,6 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) { int val; -#ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook && (c->id == V4L2_CID_AUDIO_VOLUME)) { - struct video_audio va; - - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (c->id) { - case V4L2_CID_AUDIO_VOLUME: - va.volume = c->value; - break; - } - btv->audio_hook(btv,&va,1); - return 0; - } -#endif switch (c->id) { case V4L2_CID_BRIGHTNESS: bt848_bright(btv,c->value); @@ -1545,6 +1516,11 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) audio_mute(btv, c->value); /* fall through */ case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) { + btv->volume_gpio (btv, c->value); + } + bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); + break; case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: @@ -1953,22 +1929,10 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&btv->lock); bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); -#ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook) { - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - if (t->audmode == V4L2_TUNER_MODE_MONO) - va.mode = VIDEO_SOUND_MONO; - else if (t->audmode == V4L2_TUNER_MODE_STEREO || - t->audmode == V4L2_TUNER_MODE_LANG1_LANG2) - va.mode = VIDEO_SOUND_STEREO; - else if (t->audmode == V4L2_TUNER_MODE_LANG1) - va.mode = VIDEO_SOUND_LANG1; - else if (t->audmode == V4L2_TUNER_MODE_LANG2) - va.mode = VIDEO_SOUND_LANG2; - btv->audio_hook(btv,&va,1); + + if (btv->audio_mode_gpio) { + btv->audio_mode_gpio (btv,t,1); } -#endif mutex_unlock(&btv->lock); return 0; } @@ -2846,19 +2810,11 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return 0; } *c = bttv_ctls[i]; -#ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook && i >= 4 && i <= 8) { - struct video_audio va; - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (bttv_ctls[i].id) { - case V4L2_CID_AUDIO_VOLUME: - if (!(va.flags & VIDEO_AUDIO_VOLUME)) - *c = no_ctl; - break; - } - } -#endif + + if (!btv->volume_gpio && + (bttv_ctls[i].id == V4L2_CID_AUDIO_VOLUME)) + *c = no_ctl; + return 0; } case VIDIOC_G_PARM: @@ -2890,26 +2846,11 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, t->type = V4L2_TUNER_ANALOG_TV; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; -#ifdef CONFIG_VIDEO_V4L1 - if (btv->audio_hook) { - /* Hmmm ... */ - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - btv->audio_hook(btv,&va,0); - t->audmode = V4L2_TUNER_MODE_MONO; - t->rxsubchans = V4L2_TUNER_SUB_MONO; - if(va.mode & VIDEO_SOUND_STEREO) { - t->audmode = V4L2_TUNER_MODE_STEREO; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - } - if(va.mode & VIDEO_SOUND_LANG2) { - t->audmode = V4L2_TUNER_MODE_LANG1; - t->rxsubchans = V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; - } + + if (btv->audio_mode_gpio) { + btv->audio_mode_gpio (btv,t,0); } -#endif - /* FIXME: fill capability+audmode */ + mutex_unlock(&btv->lock); return 0; } @@ -3403,6 +3344,10 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + if (btv->audio_mode_gpio) { + btv->audio_mode_gpio (btv,t,0); + } + mutex_unlock(&btv->lock); return 0; diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 2edef15ba35..bf4c339a520 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -241,9 +241,10 @@ struct tvcard unsigned int radio_addr; unsigned int has_radio; -#ifdef CONFIG_VIDEO_V4L1 - void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); -#endif + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index fdd78f8b1dc..4a02f0a8a46 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -336,9 +336,10 @@ struct bttv { /* old gpio interface */ wait_queue_head_t gpioq; int shutdown; -#ifdef CONFIG_VIDEO_V4L1 - void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); -#endif + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + /* new gpio interface */ spinlock_t gpio_lock; -- cgit v1.2.3 From 155c6ab9ed255745758b6aa0f266e4d40aa32a21 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Fri, 25 Aug 2006 16:53:07 -0300 Subject: V4L/DVB (6417): Report detected sound carrier into rxsubchans Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-audio-hook.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c index a075198f830..67b63423575 100644 --- a/drivers/media/video/bt8xx/bttv-audio-hook.c +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -101,24 +101,28 @@ void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) } else { switch (val & 0x70) { case 0x10: - t->audmode = V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; case 0x30: - t->audmode = V4L2_TUNER_MODE_LANG2; + t->rxsubchans = V4L2_TUNER_SUB_LANG2; break; case 0x50: - t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_LANG1; break; case 0x60: - t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans = V4L2_TUNER_SUB_STEREO; break; case 0x70: - t->audmode = V4L2_TUNER_MODE_MONO; + t->rxsubchans = V4L2_TUNER_SUB_MONO; break; default: - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; } + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } -- cgit v1.2.3 From dc3d75da05c3ff2dd6510c32a11deacced49d1a1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Aug 2006 16:53:08 -0300 Subject: V4L/DVB (6418): Converted tvaudio from V4L1 to V4L2 V4L1 ioctls were replaced to V4L2 were applicable. The older ones already implemented were removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvaudio.c | 306 ++++++++++++++++++++++++------------------ 1 file changed, 178 insertions(+), 128 deletions(-) diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index a19cdcc17ef..bb510dd5dda 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -307,14 +307,16 @@ static void generic_checkmode(struct CHIPSTATE *chip) v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; - if (mode & VIDEO_SOUND_STEREO) - desc->setmode(chip,VIDEO_SOUND_STEREO); - else if (mode & VIDEO_SOUND_LANG1) - desc->setmode(chip,VIDEO_SOUND_LANG1); - else if (mode & VIDEO_SOUND_LANG2) - desc->setmode(chip,VIDEO_SOUND_LANG2); + if (mode & V4L2_TUNER_MODE_STEREO) + desc->setmode(chip,V4L2_TUNER_MODE_STEREO); + if (mode & V4L2_TUNER_MODE_LANG1_LANG2) + desc->setmode(chip,V4L2_TUNER_MODE_STEREO); + else if (mode & V4L2_TUNER_MODE_LANG1) + desc->setmode(chip,V4L2_TUNER_MODE_LANG1); + else if (mode & V4L2_TUNER_MODE_LANG2) + desc->setmode(chip,V4L2_TUNER_MODE_LANG2); else - desc->setmode(chip,VIDEO_SOUND_MONO); + desc->setmode(chip,V4L2_TUNER_MODE_MONO); } /* ---------------------------------------------------------------------- */ @@ -345,11 +347,11 @@ static int tda9840_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TDA9840_DS_DUAL) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; if (val & TDA9840_ST_STEREO) - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", val, mode); @@ -362,16 +364,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode) int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: t |= TDA9840_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: t |= TDA9840_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: t |= TDA9840_DUALA; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: t |= TDA9840_DUALB; break; default: @@ -502,7 +504,7 @@ static int tda985x_getmode(struct CHIPSTATE *chip) chip_read(chip)) >> 4; /* Add mono mode regardless of SAP and stereo */ /* Allows forced mono */ - return mode | VIDEO_SOUND_MONO; + return mode | V4L2_TUNER_MODE_MONO; } static void tda985x_setmode(struct CHIPSTATE *chip, int mode) @@ -511,13 +513,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: c6 |= TDA985x_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: c6 |= TDA985x_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: c6 |= TDA985x_SAP; break; default: @@ -650,11 +652,11 @@ static int tda9873_getmode(struct CHIPSTATE *chip) int val,mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TDA9873_STEREO) - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if (val & TDA9873_DUAL) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; @@ -674,16 +676,16 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: sw_data |= TDA9873_TR_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: sw_data |= TDA9873_TR_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: sw_data |= TDA9873_TR_DUALA; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: sw_data |= TDA9873_TR_DUALB; break; default: @@ -841,7 +843,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) int dsr,nsr,mode; int necr; /* just for debugging */ - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) return mode; @@ -860,18 +862,18 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * that sound has (temporarily) switched from NICAM to * mono FM (or AM) on 1st sound carrier due to high NICAM bit * error count. So in fact there is no stereo in this case :-( - * But changing the mode to VIDEO_SOUND_MONO would switch + * But changing the mode to V4L2_TUNER_MODE_MONO would switch * external 4052 multiplexer in audio_hook(). */ if(nsr & 0x02) /* NSR.S/MB=1 */ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if(nsr & 0x01) /* NSR.D/SB=1 */ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } else { if(dsr & 0x02) /* DSR.IDSTE=1 */ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if(dsr & 0x04) /* DSR.IDDUA=1 */ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", @@ -902,14 +904,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) int mdacosr = (tda9874a_mode) ? 0x82:0x80; switch(mode) { - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_STEREO: break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: aosr = 0x80; /* auto-select, dual A/A */ mdacosr = (tda9874a_mode) ? 0x82:0x80; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: aosr = 0xa0; /* auto-select, dual B/B */ mdacosr = (tda9874a_mode) ? 0x83:0x81; break; @@ -927,11 +929,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) int fmmr,aosr; switch(mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: fmmr = 0x00; /* mono */ aosr = 0x10; /* A/A */ break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: if(tda9874a_mode) { fmmr = 0x00; aosr = 0x00; /* handled by NICAM auto-mute */ @@ -940,11 +942,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) aosr = 0x00; } break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: fmmr = 0x02; /* dual */ aosr = 0x10; /* dual A/A */ break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: fmmr = 0x02; /* dual */ aosr = 0x20; /* dual B/B */ break; @@ -1105,20 +1107,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) { int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1; - if (mode & VIDEO_SOUND_LANG1) { + if (mode & V4L2_TUNER_MODE_LANG1) { s1 |= TDA8425_S1_ML_SOUND_A; s1 |= TDA8425_S1_STEREO_PSEUDO; - } else if (mode & VIDEO_SOUND_LANG2) { + } else if (mode & V4L2_TUNER_MODE_LANG2) { s1 |= TDA8425_S1_ML_SOUND_B; s1 |= TDA8425_S1_STEREO_PSEUDO; } else { s1 |= TDA8425_S1_ML_STEREO; - if (mode & VIDEO_SOUND_MONO) + if (mode & V4L2_TUNER_MODE_MONO) s1 |= TDA8425_S1_STEREO_MONO; - if (mode & VIDEO_SOUND_STEREO) + if (mode & V4L2_TUNER_MODE_STEREO) s1 |= TDA8425_S1_STEREO_SPATIAL; } chip_write(chip,TDA8425_S1,s1); @@ -1177,11 +1179,11 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TA8874Z_B1){ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; }else if (!(val & TA8874Z_B0)){ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; } /* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; @@ -1199,16 +1201,16 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: t = &ta8874z_mono; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: t = &ta8874z_stereo; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: t = &ta8874z_main; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: t = &ta8874z_sub; break; default: @@ -1570,7 +1572,48 @@ static int chip_detach(struct i2c_client *client) return 0; } -static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) +static int tvaudio_get_ctrl(struct CHIPSTATE *chip, + struct v4l2_control *ctrl) +{ + struct CHIPDESC *desc = chiplist + chip->type; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=chip->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + if (!desc->flags & CHIP_HAS_VOLUME) + break; + ctrl->value = max(chip->left,chip->right); + return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume; + if (!desc->flags & CHIP_HAS_VOLUME) + break; + volume = max(chip->left,chip->right); + if (volume) + ctrl->value=(32768*min(chip->left,chip->right))/volume; + else + ctrl->value=32768; + return 0; + } + case V4L2_CID_AUDIO_BASS: + if (desc->flags & CHIP_HAS_BASSTREBLE) + break; + ctrl->value = chip->bass; + return 0; + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + ctrl->value = chip->treble; + return 0; + } + return -EINVAL; +} + +static int tvaudio_set_ctrl(struct CHIPSTATE *chip, + struct v4l2_control *ctrl) { struct CHIPDESC *desc = chiplist + chip->type; @@ -1584,11 +1627,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) else chip_write_masked(chip,desc->inputreg, desc->inputmap[chip->input],desc->inputmask); - break; - default: - return -EINVAL; + return 0; + case V4L2_CID_AUDIO_VOLUME: + { + int volume,balance; + + if (!desc->flags & CHIP_HAS_VOLUME) + break; + + volume = max(chip->left,chip->right); + if (volume) + balance=(32768*min(chip->left,chip->right))/volume; + else + balance=32768; + + volume=ctrl->value; + chip->left = (min(65536 - balance,32768) * volume) / 32768; + chip->right = (min(balance,volume *(__u16)32768)) / 32768; + + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + + return 0; } - return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume, balance; + if (!desc->flags & CHIP_HAS_VOLUME) + break; + + volume = max(chip->left,chip->right); + balance = ctrl->value; + + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + + return 0; + } + case V4L2_CID_AUDIO_BASS: + if (desc->flags & CHIP_HAS_BASSTREBLE) + break; + chip->bass = ctrl->value; + chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); + + return 0; + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + + chip->treble = ctrl->value; + chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); + + return 0; + } + return -EINVAL; } @@ -1609,67 +1701,36 @@ static int chip_command(struct i2c_client *client, chip->watch_stereo = 0; /* del_timer(&chip->wt); */ break; - /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - if (desc->flags & CHIP_HAS_VOLUME) { - va->flags |= VIDEO_AUDIO_VOLUME; - va->volume = max(chip->left,chip->right); - if (va->volume) - va->balance = (32768*min(chip->left,chip->right))/ - va->volume; - else - va->balance = 32768; - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; - va->bass = chip->bass; - va->treble = chip->treble; - } - if (!chip->radio) { - if (desc->getmode) - va->mode = desc->getmode(chip); - else - va->mode = VIDEO_SOUND_MONO; - } - break; - } - - case VIDIOCSAUDIO: + case VIDIOC_QUERYCTRL: { - struct video_audio *va = arg; - - if (desc->flags & CHIP_HAS_VOLUME) { - chip->left = (min(65536 - va->balance,32768) * - va->volume) / 32768; - chip->right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - chip->bass = va->bass; - chip->treble = va->treble; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); - } - if (desc->setmode && va->mode) { - chip->watch_stereo = 0; - /* del_timer(&chip->wt); */ - chip->mode = va->mode; - desc->setmode(chip,va->mode); + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + if (!desc->flags & CHIP_HAS_VOLUME) + return -EINVAL; + break; + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + break; + default: + return -EINVAL; } - break; + return v4l2_ctrl_query_fill_std(qc); } - case VIDIOC_S_CTRL: return tvaudio_set_ctrl(chip, arg); + case VIDIOC_G_CTRL: + return tvaudio_get_ctrl(chip, arg); case VIDIOC_INT_G_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1678,7 +1739,6 @@ static int chip_command(struct i2c_client *client, rt->output = 0; break; } - case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1693,7 +1753,6 @@ static int chip_command(struct i2c_client *client, desc->inputmap[chip->input], desc->inputmask); break; } - case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; @@ -1703,17 +1762,13 @@ static int chip_command(struct i2c_client *client, break; switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: - mode = VIDEO_SOUND_MONO; - break; case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - mode = VIDEO_SOUND_STEREO; - break; case V4L2_TUNER_MODE_LANG1: - mode = VIDEO_SOUND_LANG1; - break; case V4L2_TUNER_MODE_LANG2: - mode = VIDEO_SOUND_LANG2; + mode = vt->audmode; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + mode = V4L2_TUNER_MODE_STEREO; break; default: return -EINVAL; @@ -1728,11 +1783,10 @@ static int chip_command(struct i2c_client *client, } break; } - case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; - int mode = VIDEO_SOUND_MONO; + int mode = V4L2_TUNER_MODE_MONO; if (chip->radio) break; @@ -1744,30 +1798,26 @@ static int chip_command(struct i2c_client *client, if (desc->getmode) mode = desc->getmode(chip); - if (mode & VIDEO_SOUND_MONO) + if (mode & V4L2_TUNER_MODE_MONO) vt->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (mode & VIDEO_SOUND_STEREO) + if (mode & V4L2_TUNER_MODE_STEREO) vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; /* Note: for SAP it should be mono/lang2 or stereo/lang2. When this module is converted fully to v4l2, then this should change for those chips that can detect SAP. */ - if (mode & VIDEO_SOUND_LANG1) + if (mode & V4L2_TUNER_MODE_LANG1) vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; } - - case VIDIOCSCHAN: case VIDIOC_S_STD: chip->radio = 0; break; - - case VIDIOCSFREQ: case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ if (desc->checkmode) { - desc->setmode(chip,VIDEO_SOUND_MONO); - if (chip->prevmode != VIDEO_SOUND_MONO) + desc->setmode(chip,V4L2_TUNER_MODE_MONO); + if (chip->prevmode != V4L2_TUNER_MODE_MONO) chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); /* the thread will call checkmode() later */ -- cgit v1.2.3 From 7a00d45cf017172c74d15bad0f9f14720efd69dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Aug 2006 16:53:09 -0300 Subject: V4L/DVB (6419): V4L2 port of tda7432 from V4L1 api Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda7432.c | 232 ++++++++++++++++++++++-------------------- 1 file changed, 121 insertions(+), 111 deletions(-) diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 43225802a55..b4d10f7a4e5 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -8,6 +8,7 @@ * Muting and tone control by Jonathan Isom * * Copyright (c) 2000 Eric Sandeen + * Copyright (c) 2006 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client) t->volume = 0x3b ; /* -27dB Volume */ if (loudness) /* Turn loudness on? */ t->volume |= TDA7432_LD_ON; - t->muted = VIDEO_AUDIO_MUTE; + t->muted = 1; t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ @@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client) return 0; } -static int tda7432_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tda7432_get_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) { struct tda7432 *t = i2c_get_clientdata(client); - v4l_dbg(2, debug,client,"In tda7432_command\n"); - if (debug>1) - v4l_i2c_print_ioctl(client,cmd); - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - - /* Query card - scale from TDA7432 settings to V4L settings */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE | - VIDEO_AUDIO_MUTABLE; - if (t->muted) - va->flags |= VIDEO_AUDIO_MUTE; - va->mode |= VIDEO_SOUND_STEREO; - /* Master volume control - * V4L volume is min 0, max 65535 - * TDA7432 Volume: - * Min (-79dB) is 0x6f - * Max (+20dB) is 0x07 (630) - * Max (0dB) is 0x20 (829) - * (Mask out bit 7 of vol - it's for the loudness setting) - */ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=t->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: if (!maxvol){ /* max +20db */ - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; + ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; } else { /* max 0db */ - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829; + ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; } - - /* Balance depends on L,R attenuation - * V4L balance is 0 to 65535, middle is 32768 - * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f - * to scale up to V4L numbers, mult by 1057 - * attenuation exists for lf, lr, rf, rr - * we use only lf and rf (front channels) - */ - + return 0; + case V4L2_CID_AUDIO_BALANCE: + { if ( (t->lf) < (t->rf) ) /* right is attenuated, balance shifted left */ - va->balance = (32768 - 1057*(t->rf)); + ctrl->value = (32768 - 1057*(t->rf)); else /* left is attenuated, balance shifted right */ - va->balance = (32768 + 1057*(t->lf)); - + ctrl->value = (32768 + 1057*(t->lf)); + return 0; + } + case V4L2_CID_AUDIO_BASS: + { /* Bass/treble 4 bits each */ - va->bass=t->bass; - if(va->bass >= 0x8) - va->bass = ~(va->bass - 0x8) & 0xf; - va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass); - va->treble=t->treble; - if(va->treble >= 0x8) - va->treble = ~(va->treble - 0x8) & 0xf; - va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble); - - break; /* VIDIOCGAUDIO case */ + int bass=t->bass; + if(bass >= 0x8) + bass = ~(bass - 0x8) & 0xf; + ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); + return 0; } - - /* Set card - scale from V4L settings to TDA7432 settings */ - case VIDIOCSAUDIO: + case V4L2_CID_AUDIO_TREBLE: { - struct video_audio *va = arg; + int treble=t->treble; + if(treble >= 0x8) + treble = ~(treble - 0x8) & 0xf; + ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); + return 0; + } + } + return -EINVAL; +} - if(va->flags & VIDEO_AUDIO_VOLUME){ - if(!maxvol){ /* max +20db */ - t->volume = 0x6f - ((va->volume)/630); - } else { /* max 0db */ - t->volume = 0x6f - ((va->volume)/829); - } +static int tda7432_set_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) +{ + struct tda7432 *t = i2c_get_clientdata(client); + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + t->muted=ctrl->value; + break; + case V4L2_CID_AUDIO_VOLUME: + if(!maxvol){ /* max +20db */ + t->volume = 0x6f - ((ctrl->value)/630); + } else { /* max 0db */ + t->volume = 0x6f - ((ctrl->value)/829); + } if (loudness) /* Turn on the loudness bit */ t->volume |= TDA7432_LD_ON; - tda7432_write(client,TDA7432_VL, t->volume); - } - - if(va->flags & VIDEO_AUDIO_BASS) - { - t->bass = va->bass >> 12; - if(t->bass>= 0x8) - t->bass = (~t->bass & 0xf) + 0x8 ; - } - if(va->flags & VIDEO_AUDIO_TREBLE) - { - t->treble= va->treble >> 12; - if(t->treble>= 0x8) - t->treble = (~t->treble & 0xf) + 0x8 ; - } - if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS)) - tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); - - if(va->flags & VIDEO_AUDIO_BALANCE) { - if (va->balance < 32768) - { + tda7432_write(client,TDA7432_VL, t->volume); + return 0; + case V4L2_CID_AUDIO_BALANCE: + if (ctrl->value < 32768) { /* shifted to left, attenuate right */ - t->rr = (32768 - va->balance)/1057; + t->rr = (32768 - ctrl->value)/1057; t->rf = t->rr; t->lr = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; - } - else if(va->balance > 32769) - { + } else if(ctrl->value > 32769) { /* shifted to right, attenuate left */ - t->lf = (va->balance - 32768)/1057; + t->lf = (ctrl->value - 32768)/1057; t->lr = t->lf; t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; - } - else - { + } else { /* centered */ t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; t->lr = TDA7432_ATTEN_0DB; } - } + break; + case V4L2_CID_AUDIO_BASS: + t->bass = ctrl->value >> 12; + if(t->bass>= 0x8) + t->bass = (~t->bass & 0xf) + 0x8 ; + + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + return 0; + case V4L2_CID_AUDIO_TREBLE: + t->treble= ctrl->value >> 12; + if(t->treble>= 0x8) + t->treble = (~t->treble & 0xf) + 0x8 ; + + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + return 0; + default: + return -EINVAL; + } - t->muted=(va->flags & VIDEO_AUDIO_MUTE); - if (t->muted) - { - /* Mute & update balance*/ - tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); - tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); - tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); - tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); - } else { - tda7432_write(client,TDA7432_LF, t->lf); - tda7432_write(client,TDA7432_LR, t->lr); - tda7432_write(client,TDA7432_RF, t->rf); - tda7432_write(client,TDA7432_RR, t->rr); - } + /* Used for both mute and balance changes */ + if (t->muted) + { + /* Mute & update balance*/ + tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); + tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); + tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); + tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); + } else { + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); + } + return 0; +} - break; +static int tda7432_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + v4l_dbg(2, debug,client,"In tda7432_command\n"); + if (debug>1) + v4l_i2c_print_ioctl(client,cmd); + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + default: + return -EINVAL; + } + return v4l2_ctrl_query_fill_std(qc); + } + case VIDIOC_S_CTRL: + return tda7432_set_ctrl(client, arg); - } /* end of VIDEOCSAUDIO case */ + case VIDIOC_G_CTRL: + return tda7432_get_ctrl(client, arg); } /* end of (cmd) switch */ -- cgit v1.2.3 From 5eba35714e0dfa5618b438cfe46037f22133badc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Aug 2006 16:53:10 -0300 Subject: V4L/DVB (6420): V4L2 conversion for tda9875 from V4L1 API Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9875.c | 167 ++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 55 deletions(-) diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index d1104417087..3c0557130a7 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -7,6 +7,7 @@ * * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and * Eric Sandeen + * Copyright (c) 2006 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client) return 0; } -static int tda9875_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tda9875_get_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) { struct tda9875 *t = i2c_get_clientdata(client); - dprintk("In tda9875_command...\n"); + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + { + int left = (t->lvol+84)*606; + int right = (t->rvol+84)*606; - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: + ctrl->value=max(left,right); + return 0; + } + case V4L2_CID_AUDIO_BALANCE: { - struct video_audio *va = arg; - int left,right; + int left = (t->lvol+84)*606; + int right = (t->rvol+84)*606; + int volume = max(left,right); + int balance = (32768*min(left,right))/ + (volume ? volume : 1); + ctrl->value=(leftvalue = (t->bass+12)*2427; /* min -12 max +15 */ + return 0; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */ + return 0; + } + return -EINVAL; +} - dprintk("VIDIOCGAUDIO\n"); +static int tda9875_set_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) +{ + struct tda9875 *t = i2c_get_clientdata(client); + int chvol=0, volume, balance, left, right; - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + left = (t->lvol+84)*606; + right = (t->rvol+84)*606; + + volume = max(left,right); + balance = (32768*min(left,right))/ + (volume ? volume : 1); + balance =(leftvalue; - /* min is -84 max is 24 */ + chvol=1; + break; + case V4L2_CID_AUDIO_BALANCE: left = (t->lvol+84)*606; right = (t->rvol+84)*606; - va->volume=max(left,right); - va->balance=(32768*min(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(leftbalance) : va->balance; - va->bass = (t->bass+12)*2427; /* min -12 max +15 */ - va->treble = (t->treble+12)*2730;/* min -12 max +12 */ - va->mode |= VIDEO_SOUND_MONO; - - break; /* VIDIOCGAUDIO case */ + + volume=max(left,right); + + balance = ctrl->value; + + chvol=1; + break; + case V4L2_CID_AUDIO_BASS: + t->bass = ((ctrl->value/2400)-12) & 0xff; + if (t->bass > 15) + t->bass = 15; + if (t->bass < -12) + t->bass = -12 & 0xff; + break; + case V4L2_CID_AUDIO_TREBLE: + t->treble = ((ctrl->value/2700)-12) & 0xff; + if (t->treble > 12) + t->treble = 12; + if (t->treble < -12) + t->treble = -12 & 0xff; + break; + default: + return -EINVAL; } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - dprintk("VIDEOCSAUDIO...\n"); - left = (min(65536 - va->balance,32768) * - va->volume) / 32768; - right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; + if (chvol) { + left = (min(65536 - balance,32768) * + volume) / 32768; + right = (min(balance,32768) * + volume) / 32768; t->lvol = ((left/606)-84) & 0xff; if (t->lvol > 24) - t->lvol = 24; + t->lvol = 24; if (t->lvol < -84) - t->lvol = -84 & 0xff; + t->lvol = -84 & 0xff; t->rvol = ((right/606)-84) & 0xff; if (t->rvol > 24) - t->rvol = 24; + t->rvol = 24; if (t->rvol < -84) - t->rvol = -84 & 0xff; - - t->bass = ((va->bass/2400)-12) & 0xff; - if (t->bass > 15) - t->bass = 15; - if (t->bass < -12) - t->bass = -12 & 0xff; - - t->treble = ((va->treble/2700)-12) & 0xff; - if (t->treble > 12) - t->treble = 12; - if (t->treble < -12) - t->treble = -12 & 0xff; + t->rvol = -84 & 0xff; + } +//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + tda9875_set(client); -//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + return 0; +} - tda9875_set(client); +static int tda9875_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + dprintk("In tda9875_command...\n"); - break; + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + default: + return -EINVAL; + } + return v4l2_ctrl_query_fill_std(qc); + } + case VIDIOC_S_CTRL: + return tda9875_set_ctrl(client, arg); - } /* end of VIDEOCSAUDIO case */ + case VIDIOC_G_CTRL: + return tda9875_get_ctrl(client, arg); default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ -- cgit v1.2.3 From 07533b6a8097c6fdb17fb154725757b64238a8d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Aug 2006 16:53:11 -0300 Subject: V4L/DVB (6421): Make Kconfig reflect the changes at audio helper modules Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c9f14bfc854..ea5be3711a7 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -45,7 +45,7 @@ comment "Audio decoders" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, @@ -57,7 +57,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for tda7432 audio decoder chip found on some bt8xx boards. @@ -75,7 +75,7 @@ config VIDEO_TDA9840 config VIDEO_TDA9875 tristate "Philips TDA9875 audio processor" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for tda9875 audio decoder chip found on some bt8xx boards. -- cgit v1.2.3 From 12466577853b0d057f4416f4c7020e544f3a4209 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Oct 2007 11:08:20 -0300 Subject: V4L/DVB (6422): Add the pending entries for xc2028/3028 based boards Also replaces all occurrences of TUNER_XCEIVE_XC3028 to TUNER_XC2028. Some work is still may be required to make sure that non-tm6000 drivers will be capable of using tuner-xc2028. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 71 +++++++++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-cards.c | 6 +-- drivers/media/video/ivtv/ivtv-driver.c | 2 +- drivers/media/video/tuner-types.c | 6 +-- include/media/tuner.h | 2 +- 6 files changed, 80 insertions(+), 9 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index a88c02d2380..84c3ac7c33d 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -69,7 +69,7 @@ tuner=67 - Philips TD1316 Hybrid Tuner tuner=68 - Philips TUV1236D ATSC/NTSC dual in tuner=69 - Tena TNF 5335 and similar models tuner=70 - Samsung TCPN 2121P30A -tuner=71 - Xceive xc3028 +tuner=71 - Xceive xc2028/xc3028 tuner tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 418ea8b7f85..2d72de0e756 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -156,6 +156,74 @@ struct em28xx_board em28xx_boards[] = { MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), }}, }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { + .name = "Hauppauge WinTV HVR 900", + .vchannels = 3, + .norm = VIDEO_MODE_PAL, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .has_tuner = 1, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid XS", + .vchannels = 3, + .norm = VIDEO_MODE_PAL, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, + /* maybe there's a reason behind it why Terratec sells the Hybrid XS as Prodigy XS with a + * different PID, let's keep it separated for now maybe we'll need it lateron */ + [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { + .name = "Terratec Prodigy XS", + .vchannels = 3, + .norm = VIDEO_MODE_PAL, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, [EM2820_BOARD_MSI_VOX_USB_2] = { .name = "MSI VOX USB 2.0", .vchannels = 3, @@ -274,6 +342,9 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, }; diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index b6a8be622d3..aaa114b5c26 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -848,7 +848,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_pg600v2, }; @@ -879,7 +879,7 @@ static const struct ivtv_card ivtv_card_club3d = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_club3d, }; @@ -910,7 +910,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { }, .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_avertv_mce116, }; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 6d2dd8764f8..ec40453e46e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -829,7 +829,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) /* load modules */ #ifndef CONFIG_VIDEO_TUNER if (hw & IVTV_HW_TUNER) { - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { + if (itv->options.tuner == TUNER_XC2028) { IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); itv->tunerid = 1; } diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index c6a7934bd5a..ac363f01922 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1452,9 +1452,9 @@ struct tunertype tuners[] = { .params = tuner_samsung_tcpn_2121p30a_params, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), }, - [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */ - .name = "Xceive xc3028", - /* see xc3028.c for details */ + [TUNER_XC2028] = { /* Xceive 2028 */ + .name = "Xceive xc2028/xc3028 tuner", + /* see tuner-xc2028.c for details */ }, [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ .name = "Thomson FE6600", diff --git a/include/media/tuner.h b/include/media/tuner.h index c03dceb9260..d49392d90e5 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -117,7 +117,7 @@ extern int tuner_debug; #define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ #define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */ #define TUNER_SAMSUNG_TCPN_2121P30A 70 /* Hauppauge PVR-500MCE NTSC */ -#define TUNER_XCEIVE_XC3028 71 +#define TUNER_XC2028 71 #define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */ #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ -- cgit v1.2.3 From 6cb45879dca84c667996d65a12880db6705a2b0e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Oct 2007 11:57:03 -0300 Subject: V4L/DVB (6423): Add tuner-xc2028 driver Add support for Xceive XC2028/XC3028 tuner driver Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 12 ++ drivers/media/video/Makefile | 4 + drivers/media/video/tuner-core.c | 5 + drivers/media/video/tuner-driver.h | 2 + drivers/media/video/tuner-xc2028.c | 391 +++++++++++++++++++++++++++++++++++++ drivers/media/video/tuner-xc2028.h | 9 + 6 files changed, 423 insertions(+) create mode 100644 drivers/media/video/tuner-xc2028.c create mode 100644 drivers/media/video/tuner-xc2028.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ea5be3711a7..454846355e9 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -505,6 +505,18 @@ config TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. +config TUNER_XC2028 + tristate "Xceive xc2028 support for tm5600/tm6000 driver" + depends on I2C + select VIDEO_TUNER + help + Say Y here to include support for Xceive xc2028 tuner. This is + required on a few tm5600/tm6000 designs. You should notice + that this module currently works only with the special + firmware versions used on those Trident chips. + + If in doubt, say N. + config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b5a064163e0..1fd775e0a0b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -6,6 +6,10 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-types.o tda9887.o +ifneq ($(CONFIG_TUNER_XC2028),) + tuner-objs += tuner-xc2028.o +endif + msp3400-objs := msp3400-driver.o msp3400-kthreads.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index d1d6c664bb0..ce817a17ccf 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -193,6 +193,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) set_tv_freq(c, freq); t->tv_freq = freq; break; + default: + tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); } } @@ -320,6 +322,9 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c,buffer,4); attach_simple_tuner(t); break; + case TUNER_XC2028: + xc2028_tuner_init(c); + break; case TUNER_TDA9887: tda9887_tuner_init(t); break; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 28a10da76d1..5e733bc8362 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -70,6 +70,8 @@ struct tuner { struct tuner_operations ops; }; +extern int xc2028_tuner_init(struct i2c_client *c); + /* ------------------------------------------------------------------------ */ extern int tda9887_tuner_init(struct tuner *t); diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c new file mode 100644 index 00000000000..cfcc1fe68c5 --- /dev/null +++ b/drivers/media/video/tuner-xc2028.c @@ -0,0 +1,391 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include +#include +#include +#include +#include +#include "tuner-driver.h" +#include "tuner-xc2028.h" + +/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ +static const char *firmware_6M = "tm6000_xc3028_DTV_6M.fw"; +static const char *firmware_8M = "tm6000_xc3028_78M.fw"; +static const char *firmware_DK = "tm6000_xc3028_DK_PAL_MTS.fw"; +static const char *firmware_MN = "tm6000_xc3028_MN_BTSC.fw"; + +struct xc2028_data { + v4l2_std_id firm_type; /* video stds supported by current firmware */ + int bandwidth; /* Firmware bandwidth: 6M, 7M or 8M */ + int need_load_generic; /* The generic firmware were loaded? */ +}; + +#define i2c_send(rc,c,buf,size) \ +if (size != (rc = i2c_master_send(c, buf, size))) \ + tuner_warn("i2c output error: rc = %d (should be %d)\n", \ + rc, (int)size); + +#define i2c_rcv(rc,c,buf,size) \ +if (size != (rc = i2c_master_recv(c, buf, size))) \ + tuner_warn("i2c input error: rc = %d (should be %d)\n", \ + rc, (int)size); + +#define send_seq(c, data...) \ +{ int rc; \ + const static u8 _val[] = data; \ + if (sizeof(_val) != \ + (rc = i2c_master_send \ + (c, _val, sizeof(_val)))) { \ + printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \ + return; \ + } \ + msleep (10); \ +} + +static int xc2028_get_reg(struct i2c_client *c, u16 reg) +{ + int rc; + unsigned char buf[1]; + struct tuner *t = i2c_get_clientdata(c); + + buf[0]= reg; + + i2c_send(rc, c, buf, sizeof(buf)); + if (rc<0) + return rc; + + if (t->tuner_callback) { + rc = t->tuner_callback( c->adapter->algo_data, + XC2028_RESET_CLK, 0); + if (rc<0) + return rc; + } + + i2c_rcv(rc, c, buf, 2); + if (rc<0) + return rc; + + return (buf[1])|(buf[0]<<8); +} + +static int load_firmware (struct i2c_client *c, const char *name) +{ + const struct firmware *fw=NULL; + struct tuner *t = i2c_get_clientdata(c); + unsigned char *p, *endp; + int len=0, rc=0; + static const char firmware_ver[] = "tm6000/xcv v1"; + + tuner_info("Loading firmware %s\n", name); + rc = request_firmware(&fw, name, &c->dev); + if (rc < 0) { + tuner_info("Error %d while requesting firmware\n", rc); + return rc; + } + p=fw->data; + endp=p+fw->size; + + if(fw->size==0) { + tuner_info("Error: firmware size is zero!\n"); + rc=-EINVAL; + goto err; + } + if (fw->sizesize,(int)sizeof(firmware_ver)-1); + rc=-EINVAL; + goto err; + } + + if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) { + /* Firmware is incorrect */ + tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n"); + rc=-EINVAL; + goto err; + } + p+=sizeof(firmware_ver)-1; + + while(ptuner_callback(c->adapter->algo_data, + XC2028_TUNER_RESET, (*p)&0x7f); + if (rc<0) { + tuner_info("Error at RESET code %d\n", + (*p)&0x7f); + goto err; + } + p++; + continue; + } + len=*p; + p++; + if (p+len+1>endp) { + /* Firmware is incorrect */ + tuner_info("Error: firmware is truncated!\n"); + rc=-EINVAL; + goto err; + } + if (len<=0) { + tuner_info("Error: firmware file is corrupted!\n"); + rc=-EINVAL; + goto err; + } + + i2c_send(rc, c, p, len); + if (rc<0) + goto err; + p+=len; + + if (*p) + msleep(*p); + p++; + } + + +err: + release_firmware(fw); + + return rc; +} + +static int check_firmware(struct i2c_client *c) +{ + int rc, version; + struct tuner *t = i2c_get_clientdata(c); + struct xc2028_data *xc2028 = t->priv; + const char *name; + + if (!t->tuner_callback) { + printk(KERN_ERR "xc2028: need tuner_callback to load firmware\n"); + return -EINVAL; + } + + if (xc2028->need_load_generic) { + if (xc2028->bandwidth==6) + name = firmware_6M; + else + name = firmware_8M; + + /* Reset is needed before loading firmware */ + rc = t->tuner_callback(c->adapter->algo_data, + XC2028_TUNER_RESET, 0); + if (rc<0) + return rc; + + rc = load_firmware(c,name); + if (rc<0) + return rc; + + xc2028->need_load_generic=0; + xc2028->firm_type=0; + } + + if (xc2028->firm_type & t->std) + return 0; + + if (t->std & V4L2_STD_MN) + name=firmware_MN; + else + name=firmware_DK; + + rc = load_firmware(c,name); + if (rc<0) + return rc; + + version = xc2028_get_reg(c, 0x4); + tuner_info("Firmware version is %d.%d\n", + (version>>4)&0x0f,(version)&0x0f); + + xc2028->firm_type=t->std; + + return 0; +} + +static int xc2028_signal(struct i2c_client *c) +{ + int lock, signal; + + if (check_firmware(c)<0) + return 0; + + lock = xc2028_get_reg(c, 0x2); + if (lock<=0) + return lock; + + /* Frequency is locked. Return signal quality */ + + signal = xc2028_get_reg(c, 0x40); + + if(signal<=0) + return lock; + + return signal; +} + +#define DIV 15625 + +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + int rc; + unsigned char buf[5]; + struct tuner *t = i2c_get_clientdata(c); + unsigned long div = (freq*62500l+DIV/2)/DIV; + + if (check_firmware(c)<0) + return; + + /* Reset GPIO 1 */ + if (t->tuner_callback) { + rc = t->tuner_callback( c->adapter->algo_data, + XC2028_TUNER_RESET, 0); + if (rc<0) + return; + } + msleep(10); + + send_seq (c, {0x12, 0x39}); + send_seq (c, {0x0c, 0x80, 0xf0, 0xf7, 0x3e, 0x75, 0xc1, 0x8a, 0xe4}); + send_seq (c, {0x0c, 0x02, 0x00}); + send_seq (c, {0x05, 0x0f, 0xee, 0xaa, 0x5f, 0xea, 0x90}); + send_seq (c, {0x06, 0x00, 0x0a, 0x4d, 0x8c, 0xf2, 0xd8, 0xcf, 0x30}); + send_seq (c, {0x06, 0x79, 0x9f}); + send_seq (c, {0x0b, 0x0d, 0xa4, 0x6c}); + send_seq (c, {0x0a, 0x01, 0x67, 0x24, 0x40, 0x08, 0xc3, 0x20, 0x10}); + send_seq (c, {0x0a, 0x64, 0x3c, 0xfa, 0xf7, 0xe1, 0x0c, 0x2c}); + send_seq (c, {0x09, 0x0b}); + send_seq (c, {0x10, 0x13}); + send_seq (c, {0x16, 0x12}); + send_seq (c, {0x1f, 0x02}); + send_seq (c, {0x21, 0x02}); + send_seq (c, {0x01, 0x02}); + send_seq (c, {0x2b, 0x10}); + send_seq (c, {0x02, 0x02}); + send_seq (c, {0x02, 0x03}); + send_seq (c, {0x00, 0x8c}); + + send_seq (c, {0x00, 0x01, 0x00, 0x00}); + send_seq (c, {0x00, 0xcc, 0x20, 0x06}); + send_seq (c, {0x2b, 0x1a}); + send_seq (c, {0x2b, 0x1b}); + send_seq (c, {0x14, 0x01, 0x1b, 0x19, 0xb5, 0x29, 0xab, 0x09, 0x55}); + send_seq (c, {0x14, 0x44, 0x05, 0x65}); + send_seq (c, {0x13, 0x18, 0x08, 0x00, 0x00, 0x6c, 0x18, 0x16, 0x8c}); + send_seq (c, {0x13, 0x49, 0x2a, 0xab}); + send_seq (c, {0x0d, 0x01, 0x4b, 0x03, 0x97, 0x55, 0xc7, 0xd7, 0x00}); + send_seq (c, {0x0d, 0xa1, 0xeb, 0x8f, 0x5c}); + send_seq (c, {0x1a, 0x00, 0x00, 0x16, 0x8a, 0x40, 0x00, 0x00, 0x00, 0x20}); + send_seq (c, {0x2d, 0x01}); + send_seq (c, {0x18, 0x00}); + send_seq (c, {0x1b, 0x0d, 0x86, 0x51, 0xd2, 0x35, 0xa4, 0x92, 0xa5}); + send_seq (c, {0x1b, 0xb5, 0x25, 0x65}); + send_seq (c, {0x1d, 0x00}); + send_seq (c, {0x0f, 0x00, 0x29, 0x56, 0xb0, 0x00, 0xb6}); + send_seq (c, {0x20, 0x00}); + send_seq (c, {0x1e, 0x09, 0x02, 0x5b, 0x6c, 0x00, 0x4b, 0x81, 0x56}); + send_seq (c, {0x1e, 0x46, 0x69, 0x0b}); + send_seq (c, {0x22, 0x32}); + send_seq (c, {0x23, 0x0a}); + send_seq (c, {0x25, 0x00, 0x09, 0x90, 0x09, 0x06, 0x64, 0x02, 0x41}); + send_seq (c, {0x26, 0xcc}); + send_seq (c, {0x29, 0x40}); + send_seq (c, {0x21, 0x03}); + send_seq (c, {0x00, 0x8c}); + send_seq (c, {0x00, 0x00, 0x00, 0x00}); + + /* CMD= Set frequency */ + send_seq(c, {0x00, 0x02, 0x00, 0x00}); + if (t->tuner_callback) { + rc = t->tuner_callback( c->adapter->algo_data, + XC2028_RESET_CLK, 1); + if (rc<0) + return; + } + + msleep(10); +// send_seq(c, {0x00, 0x00, 0x10, 0xd0, 0x00}); +// msleep(100); + buf[0]= 0xff & (div>>24); + buf[1]= 0xff & (div>>16); + buf[2]= 0xff & (div>>8); + buf[3]= 0xff & (div); + buf[4]= 0; + + i2c_send(rc, c, buf, sizeof(buf)); + if (rc<0) + return; + msleep(100); + + printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", + buf[1],buf[2],buf[3],buf[4], + freq / 16, freq % 16 * 100 / 16); +// printk("signal=%d\n",xc2028_signal(c)); +} + + +static void xc2028_release(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + kfree(t->priv); + t->priv = NULL; +} + +static struct tuner_operations tea5767_tuner_ops = { + .set_tv_freq = set_tv_freq, + .has_signal = xc2028_signal, + .release = xc2028_release, +// .is_stereo = xc2028_stereo, +}; + + +static int init=0; + +int xc2028_tuner_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + int version = xc2028_get_reg(c, 0x4); + int prd_id = xc2028_get_reg(c, 0x8); + struct xc2028_data *xc2028; + + if (init) { + printk (KERN_ERR "Module already initialized!\n"); + return 0; + } + init++; + + xc2028 = kzalloc(sizeof(*xc2028), GFP_KERNEL); + if (!xc2028) + return -ENOMEM; + t->priv = xc2028; + +#ifdef HACK + xc2028->firm_type=1; + xc2028->bandwidth=6; +#endif + xc2028->bandwidth=6; + xc2028->need_load_generic=1; + + /* FIXME: Check where t->priv will be freed */ + + if (version<0) + version=0; + + if (prd_id<0) + prd_id=0; + + strlcpy(c->name, "xc2028", sizeof(c->name)); + tuner_info("type set to %d (%s, hw ver=%d.%d, fw ver=%d.%d, id=0x%04x)\n", + t->type, c->name, + (version>>12)&0x0f,(version>>8)&0x0f, + (version>>4)&0x0f,(version)&0x0f, prd_id); + + memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); + + return 0; +} diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h new file mode 100644 index 00000000000..7c540c3871b --- /dev/null +++ b/drivers/media/video/tuner-xc2028.h @@ -0,0 +1,9 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* xc2028 commands for callback */ +#define XC2028_TUNER_RESET 0 +#define XC2028_RESET_CLK 1 -- cgit v1.2.3 From c2622e5f8ec0c53794fa33488477f07250c3e452 Mon Sep 17 00:00:00 2001 From: Michel Ludwig Date: Wed, 18 Jul 2007 10:26:38 -0300 Subject: V4L/DVB (6424): Improve tuner-xc2028 script Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 69 +++++++++++--------------------------- 1 file changed, 20 insertions(+), 49 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index cfcc1fe68c5..4b33143788d 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -189,6 +189,26 @@ static int check_firmware(struct i2c_client *c) if (xc2028->firm_type & t->std) return 0; + send_seq (c, {0x12, 0x39}); + send_seq (c, {0x0c, 0x80, 0xf0, 0xf7, 0x3e, 0x75, 0xc1, 0x8a, 0xe4}); + send_seq (c, {0x0c, 0x02, 0x00}); + send_seq (c, {0x05, 0x0f, 0xee, 0xaa, 0x5f, 0xea, 0x90}); + send_seq (c, {0x06, 0x00, 0x0a, 0x4d, 0x8c, 0xf2, 0xd8, 0xcf, 0x30}); + send_seq (c, {0x06, 0x79, 0x9f}); + send_seq (c, {0x0b, 0x0d, 0xa4, 0x6c}); + send_seq (c, {0x0a, 0x01, 0x67, 0x24, 0x40, 0x08, 0xc3, 0x20, 0x10}); + send_seq (c, {0x0a, 0x64, 0x3c, 0xfa, 0xf7, 0xe1, 0x0c, 0x2c}); + send_seq (c, {0x09, 0x0b}); + send_seq (c, {0x10, 0x13}); + send_seq (c, {0x16, 0x12}); + send_seq (c, {0x1f, 0x02}); + send_seq (c, {0x21, 0x02}); + send_seq (c, {0x01, 0x02}); + send_seq (c, {0x2b, 0x10}); + send_seq (c, {0x02, 0x02}); + send_seq (c, {0x02, 0x03}); + send_seq (c, {0x00, 0x8c}); + if (t->std & V4L2_STD_MN) name=firmware_MN; else @@ -249,55 +269,6 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) } msleep(10); - send_seq (c, {0x12, 0x39}); - send_seq (c, {0x0c, 0x80, 0xf0, 0xf7, 0x3e, 0x75, 0xc1, 0x8a, 0xe4}); - send_seq (c, {0x0c, 0x02, 0x00}); - send_seq (c, {0x05, 0x0f, 0xee, 0xaa, 0x5f, 0xea, 0x90}); - send_seq (c, {0x06, 0x00, 0x0a, 0x4d, 0x8c, 0xf2, 0xd8, 0xcf, 0x30}); - send_seq (c, {0x06, 0x79, 0x9f}); - send_seq (c, {0x0b, 0x0d, 0xa4, 0x6c}); - send_seq (c, {0x0a, 0x01, 0x67, 0x24, 0x40, 0x08, 0xc3, 0x20, 0x10}); - send_seq (c, {0x0a, 0x64, 0x3c, 0xfa, 0xf7, 0xe1, 0x0c, 0x2c}); - send_seq (c, {0x09, 0x0b}); - send_seq (c, {0x10, 0x13}); - send_seq (c, {0x16, 0x12}); - send_seq (c, {0x1f, 0x02}); - send_seq (c, {0x21, 0x02}); - send_seq (c, {0x01, 0x02}); - send_seq (c, {0x2b, 0x10}); - send_seq (c, {0x02, 0x02}); - send_seq (c, {0x02, 0x03}); - send_seq (c, {0x00, 0x8c}); - - send_seq (c, {0x00, 0x01, 0x00, 0x00}); - send_seq (c, {0x00, 0xcc, 0x20, 0x06}); - send_seq (c, {0x2b, 0x1a}); - send_seq (c, {0x2b, 0x1b}); - send_seq (c, {0x14, 0x01, 0x1b, 0x19, 0xb5, 0x29, 0xab, 0x09, 0x55}); - send_seq (c, {0x14, 0x44, 0x05, 0x65}); - send_seq (c, {0x13, 0x18, 0x08, 0x00, 0x00, 0x6c, 0x18, 0x16, 0x8c}); - send_seq (c, {0x13, 0x49, 0x2a, 0xab}); - send_seq (c, {0x0d, 0x01, 0x4b, 0x03, 0x97, 0x55, 0xc7, 0xd7, 0x00}); - send_seq (c, {0x0d, 0xa1, 0xeb, 0x8f, 0x5c}); - send_seq (c, {0x1a, 0x00, 0x00, 0x16, 0x8a, 0x40, 0x00, 0x00, 0x00, 0x20}); - send_seq (c, {0x2d, 0x01}); - send_seq (c, {0x18, 0x00}); - send_seq (c, {0x1b, 0x0d, 0x86, 0x51, 0xd2, 0x35, 0xa4, 0x92, 0xa5}); - send_seq (c, {0x1b, 0xb5, 0x25, 0x65}); - send_seq (c, {0x1d, 0x00}); - send_seq (c, {0x0f, 0x00, 0x29, 0x56, 0xb0, 0x00, 0xb6}); - send_seq (c, {0x20, 0x00}); - send_seq (c, {0x1e, 0x09, 0x02, 0x5b, 0x6c, 0x00, 0x4b, 0x81, 0x56}); - send_seq (c, {0x1e, 0x46, 0x69, 0x0b}); - send_seq (c, {0x22, 0x32}); - send_seq (c, {0x23, 0x0a}); - send_seq (c, {0x25, 0x00, 0x09, 0x90, 0x09, 0x06, 0x64, 0x02, 0x41}); - send_seq (c, {0x26, 0xcc}); - send_seq (c, {0x29, 0x40}); - send_seq (c, {0x21, 0x03}); - send_seq (c, {0x00, 0x8c}); - send_seq (c, {0x00, 0x00, 0x00, 0x00}); - /* CMD= Set frequency */ send_seq(c, {0x00, 0x02, 0x00, 0x00}); if (t->tuner_callback) { -- cgit v1.2.3 From 701672eb7387390bff43f0c979026dd317836626 Mon Sep 17 00:00:00 2001 From: Michel Ludwig Date: Wed, 18 Jul 2007 10:29:10 -0300 Subject: V4L/DVB (6425): Add experimental DVB frontend tuner interface to xc2028/3028 Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 225 ++++++++++++++++++++++++++++++------- drivers/media/video/tuner-xc2028.h | 5 + 2 files changed, 191 insertions(+), 39 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 4b33143788d..2bb695490ab 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -1,6 +1,8 @@ /* tuner-xc2028 * * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) + * - frontend interface * This code is placed under the terms of the GNU General Public License v2 */ @@ -9,19 +11,38 @@ #include #include #include +#include #include "tuner-driver.h" #include "tuner-xc2028.h" +#include +#include "dvb_frontend.h" + +/* digital TV standards */ +#define V4L2_STD_DTV_6MHZ ((v4l2_std_id)0x04000000) +#define V4L2_STD_DTV_7MHZ ((v4l2_std_id)0x08000000) +#define V4L2_STD_DTV_8MHZ ((v4l2_std_id)0x10000000) + /* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ static const char *firmware_6M = "tm6000_xc3028_DTV_6M.fw"; -static const char *firmware_8M = "tm6000_xc3028_78M.fw"; +// static const char *firmware_78M = "tm6000_xc3028_78M.fw"; +static const char *firmware_7M = "tm6000_xc3028_7M.fw"; +static const char *firmware_8M = "tm6000_xc3028_8M.fw"; +static const char *firmware_B = "tm6000_xc3028_B_PAL.fw"; static const char *firmware_DK = "tm6000_xc3028_DK_PAL_MTS.fw"; static const char *firmware_MN = "tm6000_xc3028_MN_BTSC.fw"; +static const char *firmware_INIT0 = "tm6000_xc3028_INIT0.fw"; +static const char *firmware_8MHZ_INIT0 = "tm6000_xc3028_8MHZ_INIT0.fw"; struct xc2028_data { - v4l2_std_id firm_type; /* video stds supported by current firmware */ - int bandwidth; /* Firmware bandwidth: 6M, 7M or 8M */ - int need_load_generic; /* The generic firmware were loaded? */ + v4l2_std_id firm_type; /* video stds supported + by current firmware */ + fe_bandwidth_t bandwidth; /* Firmware bandwidth: + 6M, 7M or 8M */ + int need_load_generic; /* The generic firmware + were loaded? */ + enum tuner_mode mode; + struct i2c_client *i2c_client; }; #define i2c_send(rc,c,buf,size) \ @@ -80,7 +101,7 @@ static int load_firmware (struct i2c_client *c, const char *name) int len=0, rc=0; static const char firmware_ver[] = "tm6000/xcv v1"; - tuner_info("Loading firmware %s\n", name); + tuner_info("xc2028: Loading firmware %s\n", name); rc = request_firmware(&fw, name, &c->dev); if (rc < 0) { tuner_info("Error %d while requesting firmware\n", rc); @@ -154,24 +175,39 @@ err: return rc; } -static int check_firmware(struct i2c_client *c) +static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, + fe_bandwidth_t bandwidth) { int rc, version; struct tuner *t = i2c_get_clientdata(c); struct xc2028_data *xc2028 = t->priv; const char *name; + int change_digital_bandwidth; if (!t->tuner_callback) { printk(KERN_ERR "xc2028: need tuner_callback to load firmware\n"); return -EINVAL; } + printk(KERN_INFO "xc2028: I am in mode %u and I should switch to mode %i\n", + xc2028->mode, new_mode); + + /* first of all, determine whether we have switched the mode */ + if(new_mode != xc2028->mode) { + xc2028->mode = new_mode; + xc2028->need_load_generic = 1; + } + + change_digital_bandwidth = (xc2028->mode == T_DIGITAL_TV + && bandwidth != xc2028->bandwidth) ? 1 : 0; + tuner_info("xc2028: old bandwidth %u, new bandwidth %u\n", xc2028->bandwidth, + bandwidth); + if (xc2028->need_load_generic) { if (xc2028->bandwidth==6) - name = firmware_6M; + name = firmware_INIT0; else - name = firmware_8M; - + name = firmware_8MHZ_INIT0; /* Reset is needed before loading firmware */ rc = t->tuner_callback(c->adapter->algo_data, XC2028_TUNER_RESET, 0); @@ -184,37 +220,54 @@ static int check_firmware(struct i2c_client *c) xc2028->need_load_generic=0; xc2028->firm_type=0; + if(xc2028->mode == T_DIGITAL_TV) { + change_digital_bandwidth=1; + } + } + + tuner_info("xc2028: I should change bandwidth %u\n", + change_digital_bandwidth); + + if (change_digital_bandwidth) { + switch(bandwidth) { + case BANDWIDTH_8_MHZ: + t->std = V4L2_STD_DTV_8MHZ; + break; + + case BANDWIDTH_7_MHZ: + t->std = V4L2_STD_DTV_7MHZ; + break; + + case BANDWIDTH_6_MHZ: + t->std = V4L2_STD_DTV_6MHZ; + break; + + default: + tuner_info("error: bandwidth not supported.\n"); + }; + xc2028->bandwidth = bandwidth; } if (xc2028->firm_type & t->std) return 0; - send_seq (c, {0x12, 0x39}); - send_seq (c, {0x0c, 0x80, 0xf0, 0xf7, 0x3e, 0x75, 0xc1, 0x8a, 0xe4}); - send_seq (c, {0x0c, 0x02, 0x00}); - send_seq (c, {0x05, 0x0f, 0xee, 0xaa, 0x5f, 0xea, 0x90}); - send_seq (c, {0x06, 0x00, 0x0a, 0x4d, 0x8c, 0xf2, 0xd8, 0xcf, 0x30}); - send_seq (c, {0x06, 0x79, 0x9f}); - send_seq (c, {0x0b, 0x0d, 0xa4, 0x6c}); - send_seq (c, {0x0a, 0x01, 0x67, 0x24, 0x40, 0x08, 0xc3, 0x20, 0x10}); - send_seq (c, {0x0a, 0x64, 0x3c, 0xfa, 0xf7, 0xe1, 0x0c, 0x2c}); - send_seq (c, {0x09, 0x0b}); - send_seq (c, {0x10, 0x13}); - send_seq (c, {0x16, 0x12}); - send_seq (c, {0x1f, 0x02}); - send_seq (c, {0x21, 0x02}); - send_seq (c, {0x01, 0x02}); - send_seq (c, {0x2b, 0x10}); - send_seq (c, {0x02, 0x02}); - send_seq (c, {0x02, 0x03}); - send_seq (c, {0x00, 0x8c}); if (t->std & V4L2_STD_MN) name=firmware_MN; + else if (t->std & V4L2_STD_DTV_6MHZ) + name=firmware_6M; + else if (t->std & V4L2_STD_DTV_7MHZ) + name=firmware_7M; + else if (t->std & V4L2_STD_DTV_8MHZ) + name=firmware_8M; + else if (t->std & V4L2_STD_PAL_B) + name=firmware_B; else name=firmware_DK; - rc = load_firmware(c,name); + tuner_info("xc2028: loading firmware named %s.\n", name); + + rc = load_firmware(c, name); if (rc<0) return rc; @@ -231,8 +284,7 @@ static int xc2028_signal(struct i2c_client *c) { int lock, signal; - if (check_firmware(c)<0) - return 0; + printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); lock = xc2028_get_reg(c, 0x2); if (lock<=0) @@ -250,16 +302,37 @@ static int xc2028_signal(struct i2c_client *c) #define DIV 15625 -static void set_tv_freq(struct i2c_client *c, unsigned int freq) +static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, + enum tuner_mode new_mode, fe_bandwidth_t bandwidth) { int rc; unsigned char buf[5]; struct tuner *t = i2c_get_clientdata(c); - unsigned long div = (freq*62500l+DIV/2)/DIV; + u32 div, offset = 0; - if (check_firmware(c)<0) + printk("xc3028: should set frequency %d kHz)\n", freq / 1000); + + if (check_firmware(c, new_mode, bandwidth)<0) return; + if(new_mode == T_DIGITAL_TV) { + switch(bandwidth) { + case BANDWIDTH_8_MHZ: + offset = 2750000; + break; + + case BANDWIDTH_7_MHZ: + offset = 2750000; + break; + + case BANDWIDTH_6_MHZ: + default: + printk(KERN_ERR "xc2028: bandwidth not implemented!\n"); + } + } + + div = (freq - offset + DIV/2)/DIV; + /* Reset GPIO 1 */ if (t->tuner_callback) { rc = t->tuner_callback( c->adapter->algo_data, @@ -281,6 +354,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) msleep(10); // send_seq(c, {0x00, 0x00, 0x10, 0xd0, 0x00}); // msleep(100); + buf[0]= 0xff & (div>>24); buf[1]= 0xff & (div>>16); buf[2]= 0xff & (div>>8); @@ -299,6 +373,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) } +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + + generic_set_tv_freq(c, freq * 62500l, T_ANALOG_TV, + BANDWIDTH_8_MHZ /* unimportant */); +} + static void xc2028_release(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -324,6 +406,8 @@ int xc2028_tuner_init(struct i2c_client *c) int prd_id = xc2028_get_reg(c, 0x8); struct xc2028_data *xc2028; + tuner_info("Xcv2028/3028 init called!\n"); + if (init) { printk (KERN_ERR "Module already initialized!\n"); return 0; @@ -335,12 +419,9 @@ int xc2028_tuner_init(struct i2c_client *c) return -ENOMEM; t->priv = xc2028; -#ifdef HACK - xc2028->firm_type=1; - xc2028->bandwidth=6; -#endif - xc2028->bandwidth=6; + xc2028->bandwidth=BANDWIDTH_6_MHZ; xc2028->need_load_generic=1; + xc2028->mode = T_UNINITIALIZED; /* FIXME: Check where t->priv will be freed */ @@ -360,3 +441,69 @@ int xc2028_tuner_init(struct i2c_client *c) return 0; } + +static int xc3028_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct i2c_client *c = fe->tuner_priv; + + printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + + generic_set_tv_freq(c, p->frequency, T_DIGITAL_TV, + p->u.ofdm.bandwidth); + + return 0; +} + +static int xc3028_dvb_release(struct dvb_frontend *fe) +{ + printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + + fe->tuner_priv = NULL; + + return 0; +} + +static int xc3028_dvb_init(struct dvb_frontend *fe) +{ + printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + + return 0; +} + +static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = { + .info = { + .name = "Xceive XC3028", + .frequency_min = 42000000, + .frequency_max = 864000000, + .frequency_step = 50000, + }, + + .release = xc3028_dvb_release, + .init = xc3028_dvb_init, + +// int (*sleep)(struct dvb_frontend *fe); + + /** This is for simple PLLs - set all parameters in one go. */ + .set_params = xc3028_set_params, + + /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ +// int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + +// int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); +// int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + +// int (*get_status)(struct dvb_frontend *fe, u32 *status); +}; + +int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe) +{ + fe->tuner_priv = c; + + memcpy(&fe->ops.tuner_ops, &xc3028_dvb_tuner_ops, sizeof(fe->ops.tuner_ops)); + + return 0; +} + +EXPORT_SYMBOL(xc2028_attach); + diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 7c540c3871b..34ff4cba131 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -7,3 +7,8 @@ /* xc2028 commands for callback */ #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 + +struct dvb_frontend; +struct i2c_client; + +int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe); -- cgit v1.2.3 From 2e4160ca8046e3c35277bed62b2c180427d57dd7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 18 Jul 2007 13:33:23 -0300 Subject: V4L/DVB (6426): Some fixes on tuner-xc2028 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 58 +++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 2bb695490ab..838db8187a9 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -24,15 +24,19 @@ #define V4L2_STD_DTV_8MHZ ((v4l2_std_id)0x10000000) /* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ -static const char *firmware_6M = "tm6000_xc3028_DTV_6M.fw"; -// static const char *firmware_78M = "tm6000_xc3028_78M.fw"; -static const char *firmware_7M = "tm6000_xc3028_7M.fw"; -static const char *firmware_8M = "tm6000_xc3028_8M.fw"; -static const char *firmware_B = "tm6000_xc3028_B_PAL.fw"; -static const char *firmware_DK = "tm6000_xc3028_DK_PAL_MTS.fw"; -static const char *firmware_MN = "tm6000_xc3028_MN_BTSC.fw"; -static const char *firmware_INIT0 = "tm6000_xc3028_INIT0.fw"; -static const char *firmware_8MHZ_INIT0 = "tm6000_xc3028_8MHZ_INIT0.fw"; + +/* Generic firmwares */ +static const char *firmware_INIT0 = "tm_xc3028_MTS_init0.fw"; +static const char *firmware_8MHZ_INIT0 = "tm_xc3028_8M_MTS_init0.fw"; +static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw"; + +/* Standard-specific firmwares */ +static const char *firmware_6M = "tm_xc3028_DTV_6M.fw"; +static const char *firmware_7M = "tm_xc3028_7M.fw"; +static const char *firmware_8M = "tm_xc3028_8M.fw"; +static const char *firmware_B = "tm_xc3028_B_PAL.fw"; +static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw"; +static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; struct xc2028_data { v4l2_std_id firm_type; /* video stds supported @@ -79,13 +83,6 @@ static int xc2028_get_reg(struct i2c_client *c, u16 reg) if (rc<0) return rc; - if (t->tuner_callback) { - rc = t->tuner_callback( c->adapter->algo_data, - XC2028_RESET_CLK, 0); - if (rc<0) - return rc; - } - i2c_rcv(rc, c, buf, 2); if (rc<0) return rc; @@ -104,7 +101,11 @@ static int load_firmware (struct i2c_client *c, const char *name) tuner_info("xc2028: Loading firmware %s\n", name); rc = request_firmware(&fw, name, &c->dev); if (rc < 0) { - tuner_info("Error %d while requesting firmware\n", rc); + if (rc==-ENOENT) + tuner_info("Error: firmware %s not found.\n", name); + else + tuner_info("Error %d while requesting firmware %s \n", rc, name); + return rc; } p=fw->data; @@ -204,10 +205,11 @@ static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, bandwidth); if (xc2028->need_load_generic) { - if (xc2028->bandwidth==6) - name = firmware_INIT0; - else + if (xc2028->bandwidth==8) name = firmware_8MHZ_INIT0; + else + name = firmware_INIT0; + /* Reset is needed before loading firmware */ rc = t->tuner_callback(c->adapter->algo_data, XC2028_TUNER_RESET, 0); @@ -248,9 +250,12 @@ static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, xc2028->bandwidth = bandwidth; } - if (xc2028->firm_type & t->std) + if (xc2028->firm_type & t->std) { + tuner_info("xc3028: no need to load a std-specific firmware.\n"); return 0; + } + rc = load_firmware(c,firmware_INIT1); if (t->std & V4L2_STD_MN) name=firmware_MN; @@ -266,7 +271,6 @@ static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, name=firmware_DK; tuner_info("xc2028: loading firmware named %s.\n", name); - rc = load_firmware(c, name); if (rc<0) return rc; @@ -342,6 +346,16 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, } msleep(10); + char *name; + + rc = load_firmware(c,firmware_INIT1); + + if (t->std & V4L2_STD_MN) + name=firmware_MN; + else + name=firmware_DK; + + rc = load_firmware(c,name); /* CMD= Set frequency */ send_seq(c, {0x00, 0x02, 0x00, 0x00}); if (t->tuner_callback) { -- cgit v1.2.3 From d4e7668104f7f17fa093121bf13e9728b88da57d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 18 Jul 2007 23:14:25 -0300 Subject: V4L/DVB (6427): Some cleanups at tuner-xc2028 driver Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 41 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 838db8187a9..f514c5ce5c8 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -314,28 +314,11 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, struct tuner *t = i2c_get_clientdata(c); u32 div, offset = 0; - printk("xc3028: should set frequency %d kHz)\n", freq / 1000); - - if (check_firmware(c, new_mode, bandwidth)<0) - return; - - if(new_mode == T_DIGITAL_TV) { - switch(bandwidth) { - case BANDWIDTH_8_MHZ: - offset = 2750000; - break; - - case BANDWIDTH_7_MHZ: - offset = 2750000; - break; - - case BANDWIDTH_6_MHZ: - default: - printk(KERN_ERR "xc2028: bandwidth not implemented!\n"); - } - } + /* HACK: It seems that specific firmware need to be reloaded + when freq is changed */ + struct xc2028_data *xc2028 = t->priv; - div = (freq - offset + DIV/2)/DIV; + xc2028->firm_type=0; /* Reset GPIO 1 */ if (t->tuner_callback) { @@ -345,17 +328,16 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, return; } msleep(10); + printk("xc3028: should set frequency %d kHz)\n", freq / 1000); - char *name; + if (check_firmware(c, new_mode, bandwidth)<0) + return; - rc = load_firmware(c,firmware_INIT1); + if(new_mode == T_DIGITAL_TV) + offset = 2750000; - if (t->std & V4L2_STD_MN) - name=firmware_MN; - else - name=firmware_DK; + div = (freq - offset + DIV/2)/DIV; - rc = load_firmware(c,name); /* CMD= Set frequency */ send_seq(c, {0x00, 0x02, 0x00, 0x00}); if (t->tuner_callback) { @@ -366,8 +348,6 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, } msleep(10); -// send_seq(c, {0x00, 0x00, 0x10, 0xd0, 0x00}); -// msleep(100); buf[0]= 0xff & (div>>24); buf[1]= 0xff & (div>>16); @@ -383,7 +363,6 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", buf[1],buf[2],buf[3],buf[4], freq / 16, freq % 16 * 100 / 16); -// printk("signal=%d\n",xc2028_signal(c)); } -- cgit v1.2.3 From ff7326d4f09aee7fc0416d3b3d6f7106d0961f1f Mon Sep 17 00:00:00 2001 From: Michel Ludwig Date: Fri, 27 Jul 2007 08:24:39 -0300 Subject: V4L/DVB (6428): Make the naming of the DTV firmware files more consistent Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index f514c5ce5c8..78e83700a13 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -32,8 +32,8 @@ static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw"; /* Standard-specific firmwares */ static const char *firmware_6M = "tm_xc3028_DTV_6M.fw"; -static const char *firmware_7M = "tm_xc3028_7M.fw"; -static const char *firmware_8M = "tm_xc3028_8M.fw"; +static const char *firmware_7M = "tm_xc3028_DTV_7M.fw"; +static const char *firmware_8M = "tm_xc3028_DTV_8M.fw"; static const char *firmware_B = "tm_xc3028_B_PAL.fw"; static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw"; static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; -- cgit v1.2.3 From 3b20532c791399182bd04f0fcc70b60a95637fa5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Sep 2007 18:27:03 -0300 Subject: V4L/DVB (6429): Avoid having two tuner commands happening at the same time Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 40 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 78e83700a13..0e68002a4a0 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "tuner-driver.h" #include "tuner-xc2028.h" @@ -47,6 +48,8 @@ struct xc2028_data { were loaded? */ enum tuner_mode mode; struct i2c_client *i2c_client; + + struct mutex lock; }; #define i2c_send(rc,c,buf,size) \ @@ -286,20 +289,28 @@ static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, static int xc2028_signal(struct i2c_client *c) { - int lock, signal; + struct tuner *t = i2c_get_clientdata(c); + struct xc2028_data *xc2028 = t->priv; + int frq_lock, signal=0; + + mutex_lock(&xc2028->lock); printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); - lock = xc2028_get_reg(c, 0x2); - if (lock<=0) - return lock; + frq_lock = xc2028_get_reg(c, 0x2); + if (frq_lock<=0) + goto ret; /* Frequency is locked. Return signal quality */ signal = xc2028_get_reg(c, 0x40); - if(signal<=0) - return lock; + if(signal<=0) { + signal=frq_lock; + } + +ret: + mutex_unlock(&xc2028->lock); return signal; } @@ -318,6 +329,8 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, when freq is changed */ struct xc2028_data *xc2028 = t->priv; + mutex_lock(&xc2028->lock); + xc2028->firm_type=0; /* Reset GPIO 1 */ @@ -325,13 +338,13 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, rc = t->tuner_callback( c->adapter->algo_data, XC2028_TUNER_RESET, 0); if (rc<0) - return; + goto ret; } msleep(10); printk("xc3028: should set frequency %d kHz)\n", freq / 1000); if (check_firmware(c, new_mode, bandwidth)<0) - return; + goto ret; if(new_mode == T_DIGITAL_TV) offset = 2750000; @@ -344,7 +357,7 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, rc = t->tuner_callback( c->adapter->algo_data, XC2028_RESET_CLK, 1); if (rc<0) - return; + goto ret; } msleep(10); @@ -357,12 +370,15 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, i2c_send(rc, c, buf, sizeof(buf)); if (rc<0) - return; + goto ret; msleep(100); printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", buf[1],buf[2],buf[3],buf[4], freq / 16, freq % 16 * 100 / 16); + +ret: + mutex_unlock(&xc2028->lock); } @@ -416,6 +432,8 @@ int xc2028_tuner_init(struct i2c_client *c) xc2028->need_load_generic=1; xc2028->mode = T_UNINITIALIZED; + mutex_init(&xc2028->lock); + /* FIXME: Check where t->priv will be freed */ if (version<0) @@ -498,5 +516,7 @@ int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe) return 0; } + + EXPORT_SYMBOL(xc2028_attach); -- cgit v1.2.3 From 215b95baf969c6f895969f0a4ae0479954fba7cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Oct 2007 15:24:06 -0300 Subject: V4L/DVB (6430): Convert tuner-xc2028 driver to the newer hybrid approach This changeset converts tuner-xc2028 to the newer hybrid approach. It also prevents creating twice the xc3028 private struct by both DVB and V4L parts. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 8 + drivers/media/video/Kconfig | 12 -- drivers/media/video/Makefile | 5 +- drivers/media/video/tuner-core.c | 12 +- drivers/media/video/tuner-driver.h | 2 - drivers/media/video/tuner-xc2028.c | 398 +++++++++++++++++++------------------ drivers/media/video/tuner-xc2028.h | 24 ++- 7 files changed, 248 insertions(+), 213 deletions(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 1604f049040..dfb52592451 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -69,6 +69,7 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C + select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE @@ -89,6 +90,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE if VIDEO_TUNER_CUSTOMIZE +config TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the xc2028/xc3028 tuners. + config TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" depends on I2C diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 454846355e9..ea5be3711a7 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -505,18 +505,6 @@ config TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. If in doubt, say N. -config TUNER_XC2028 - tristate "Xceive xc2028 support for tm5600/tm6000 driver" - depends on I2C - select VIDEO_TUNER - help - Say Y here to include support for Xceive xc2028 tuner. This is - required on a few tm5600/tm6000 designs. You should notice - that this module currently works only with the special - firmware versions used on those Trident chips. - - If in doubt, say N. - config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 1fd775e0a0b..08ac197cc1d 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -6,10 +6,6 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-types.o tda9887.o -ifneq ($(CONFIG_TUNER_XC2028),) - tuner-objs += tuner-xc2028.o -endif - msp3400-objs := msp3400-driver.o msp3400-kthreads.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ @@ -85,6 +81,7 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o +obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o obj-$(CONFIG_TUNER_TDA8290) += tda8290.o diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index ce817a17ccf..13112732ed2 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -24,6 +24,7 @@ #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" +#include "tuner-xc2028.h" #include "tuner-simple.h" #define UNSET (-1U) @@ -323,8 +324,17 @@ static void set_type(struct i2c_client *c, unsigned int type, attach_simple_tuner(t); break; case TUNER_XC2028: - xc2028_tuner_init(c); + { + int rc=xc2028_attach(&t->fe, t->i2c.adapter, t->i2c.addr, + &c->dev, c->adapter->algo_data, + t->tuner_callback); + if (rc<0) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } break; + } case TUNER_TDA9887: tda9887_tuner_init(t); break; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 5e733bc8362..28a10da76d1 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -70,8 +70,6 @@ struct tuner { struct tuner_operations ops; }; -extern int xc2028_tuner_init(struct i2c_client *c); - /* ------------------------------------------------------------------------ */ extern int tda9887_tuner_init(struct tuner *t); diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 0e68002a4a0..e4c371896de 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -13,16 +13,15 @@ #include #include #include -#include "tuner-driver.h" +#include "tuner-i2c.h" #include "tuner-xc2028.h" #include #include "dvb_frontend.h" -/* digital TV standards */ -#define V4L2_STD_DTV_6MHZ ((v4l2_std_id)0x04000000) -#define V4L2_STD_DTV_7MHZ ((v4l2_std_id)0x08000000) -#define V4L2_STD_DTV_8MHZ ((v4l2_std_id)0x10000000) +#define PREFIX "xc2028 " + +static LIST_HEAD(xc2028_list); /* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ @@ -40,6 +39,15 @@ static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw"; static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; struct xc2028_data { + struct list_head xc2028_list; + struct tuner_i2c_props i2c_props; + int (*tuner_callback) (void *dev, + int command, int arg); + struct device *dev; + void *video_dev; + int count; + u32 frequency; + v4l2_std_id firm_type; /* video stds supported by current firmware */ fe_bandwidth_t bandwidth; /* Firmware bandwidth: @@ -48,61 +56,64 @@ struct xc2028_data { were loaded? */ enum tuner_mode mode; struct i2c_client *i2c_client; - - struct mutex lock; + + struct mutex lock; }; -#define i2c_send(rc,c,buf,size) \ -if (size != (rc = i2c_master_send(c, buf, size))) \ - tuner_warn("i2c output error: rc = %d (should be %d)\n", \ +#define i2c_send(rc, priv, buf, size) \ +if (size != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size))) \ + tuner_info("i2c output error: rc = %d (should be %d)\n", \ rc, (int)size); -#define i2c_rcv(rc,c,buf,size) \ -if (size != (rc = i2c_master_recv(c, buf, size))) \ - tuner_warn("i2c input error: rc = %d (should be %d)\n", \ +#define i2c_rcv(rc, priv, buf, size) \ +if (size != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size))) \ + tuner_info("i2c input error: rc = %d (should be %d)\n", \ rc, (int)size); -#define send_seq(c, data...) \ +#define send_seq(priv, data...) \ { int rc; \ - const static u8 _val[] = data; \ + static u8 _val[] = data; \ if (sizeof(_val) != \ - (rc = i2c_master_send \ - (c, _val, sizeof(_val)))) { \ - printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \ - return; \ + (rc = tuner_i2c_xfer_send (&priv->i2c_props, \ + _val, sizeof(_val)))) { \ + tuner_info("Error on line %d: %d\n",__LINE__,rc); \ + return -EINVAL; \ } \ msleep (10); \ } -static int xc2028_get_reg(struct i2c_client *c, u16 reg) +static int xc2028_get_reg(struct xc2028_data *priv, u16 reg) { int rc; unsigned char buf[1]; - struct tuner *t = i2c_get_clientdata(c); + + tuner_info("%s called\n", __FUNCTION__); buf[0]= reg; - i2c_send(rc, c, buf, sizeof(buf)); + i2c_send(rc, priv, buf, sizeof(buf)); if (rc<0) return rc; - i2c_rcv(rc, c, buf, 2); + i2c_rcv(rc, priv, buf, 2); if (rc<0) return rc; return (buf[1])|(buf[0]<<8); } -static int load_firmware (struct i2c_client *c, const char *name) +static int load_firmware (struct dvb_frontend *fe, const char *name) { + struct xc2028_data *priv = fe->tuner_priv; const struct firmware *fw=NULL; - struct tuner *t = i2c_get_clientdata(c); unsigned char *p, *endp; int len=0, rc=0; static const char firmware_ver[] = "tm6000/xcv v1"; - tuner_info("xc2028: Loading firmware %s\n", name); - rc = request_firmware(&fw, name, &c->dev); + tuner_info("%s called\n", __FUNCTION__); + + tuner_info("Loading firmware %s\n", name); + rc = request_firmware(&fw, name, priv->dev); if (rc < 0) { if (rc==-ENOENT) tuner_info("Error: firmware %s not found.\n", name); @@ -138,7 +149,7 @@ static int load_firmware (struct i2c_client *c, const char *name) while(ptuner_callback(c->adapter->algo_data, + rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, (*p)&0x7f); if (rc<0) { tuner_info("Error at RESET code %d\n", @@ -162,7 +173,7 @@ static int load_firmware (struct i2c_client *c, const char *name) goto err; } - i2c_send(rc, c, p, len); + i2c_send(rc, priv, p, len); if (rc<0) goto err; p+=len; @@ -179,171 +190,173 @@ err: return rc; } -static int check_firmware(struct i2c_client *c, enum tuner_mode new_mode, +static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, + v4l2_std_id std, fe_bandwidth_t bandwidth) { + struct xc2028_data *priv = fe->tuner_priv; int rc, version; - struct tuner *t = i2c_get_clientdata(c); - struct xc2028_data *xc2028 = t->priv; const char *name; int change_digital_bandwidth; - if (!t->tuner_callback) { - printk(KERN_ERR "xc2028: need tuner_callback to load firmware\n"); - return -EINVAL; - } + tuner_info("%s called\n", __FUNCTION__); - printk(KERN_INFO "xc2028: I am in mode %u and I should switch to mode %i\n", - xc2028->mode, new_mode); + tuner_info( "I am in mode %u and I should switch to mode %i\n", + priv->mode, new_mode); /* first of all, determine whether we have switched the mode */ - if(new_mode != xc2028->mode) { - xc2028->mode = new_mode; - xc2028->need_load_generic = 1; + if(new_mode != priv->mode) { + priv->mode = new_mode; + priv->need_load_generic = 1; } - change_digital_bandwidth = (xc2028->mode == T_DIGITAL_TV - && bandwidth != xc2028->bandwidth) ? 1 : 0; - tuner_info("xc2028: old bandwidth %u, new bandwidth %u\n", xc2028->bandwidth, + change_digital_bandwidth = (priv->mode == T_DIGITAL_TV + && bandwidth != priv->bandwidth) ? 1 : 0; + tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, bandwidth); - if (xc2028->need_load_generic) { - if (xc2028->bandwidth==8) + if (priv->need_load_generic) { + if (priv->bandwidth==8) name = firmware_8MHZ_INIT0; else name = firmware_INIT0; /* Reset is needed before loading firmware */ - rc = t->tuner_callback(c->adapter->algo_data, - XC2028_TUNER_RESET, 0); + rc = priv->tuner_callback(priv->video_dev, + XC2028_TUNER_RESET, 0); if (rc<0) return rc; - rc = load_firmware(c,name); + rc = load_firmware(fe,name); if (rc<0) return rc; - xc2028->need_load_generic=0; - xc2028->firm_type=0; - if(xc2028->mode == T_DIGITAL_TV) { + priv->need_load_generic=0; + priv->firm_type=0; + if(priv->mode == T_DIGITAL_TV) { change_digital_bandwidth=1; } } - tuner_info("xc2028: I should change bandwidth %u\n", + tuner_info("I should change bandwidth %u\n", change_digital_bandwidth); + /* FIXME: t->std makes no sense here */ if (change_digital_bandwidth) { switch(bandwidth) { case BANDWIDTH_8_MHZ: - t->std = V4L2_STD_DTV_8MHZ; + std = V4L2_STD_DTV_8MHZ; break; case BANDWIDTH_7_MHZ: - t->std = V4L2_STD_DTV_7MHZ; + std = V4L2_STD_DTV_7MHZ; break; case BANDWIDTH_6_MHZ: - t->std = V4L2_STD_DTV_6MHZ; + std = V4L2_STD_DTV_6MHZ; break; default: tuner_info("error: bandwidth not supported.\n"); }; - xc2028->bandwidth = bandwidth; + priv->bandwidth = bandwidth; } - if (xc2028->firm_type & t->std) { + if (priv->firm_type & std) { tuner_info("xc3028: no need to load a std-specific firmware.\n"); return 0; } - rc = load_firmware(c,firmware_INIT1); + rc = load_firmware(fe,firmware_INIT1); - if (t->std & V4L2_STD_MN) + if (std & V4L2_STD_MN) name=firmware_MN; - else if (t->std & V4L2_STD_DTV_6MHZ) + else if (std & V4L2_STD_DTV_6MHZ) name=firmware_6M; - else if (t->std & V4L2_STD_DTV_7MHZ) + else if (std & V4L2_STD_DTV_7MHZ) name=firmware_7M; - else if (t->std & V4L2_STD_DTV_8MHZ) + else if (std & V4L2_STD_DTV_8MHZ) name=firmware_8M; - else if (t->std & V4L2_STD_PAL_B) + else if (std & V4L2_STD_PAL_B) name=firmware_B; else name=firmware_DK; - tuner_info("xc2028: loading firmware named %s.\n", name); - rc = load_firmware(c, name); + tuner_info("loading firmware named %s.\n", name); + rc = load_firmware(fe, name); if (rc<0) return rc; - version = xc2028_get_reg(c, 0x4); + version = xc2028_get_reg(priv, 0x4); tuner_info("Firmware version is %d.%d\n", (version>>4)&0x0f,(version)&0x0f); - xc2028->firm_type=t->std; + priv->firm_type=std; return 0; } -static int xc2028_signal(struct i2c_client *c) +static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) { - struct tuner *t = i2c_get_clientdata(c); - struct xc2028_data *xc2028 = t->priv; + struct xc2028_data *priv = fe->tuner_priv; int frq_lock, signal=0; - mutex_lock(&xc2028->lock); + tuner_info("%s called\n", __FUNCTION__); - printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + mutex_lock(&priv->lock); - frq_lock = xc2028_get_reg(c, 0x2); + *strength = 0; + + frq_lock = xc2028_get_reg(priv, 0x2); if (frq_lock<=0) goto ret; /* Frequency is locked. Return signal quality */ - signal = xc2028_get_reg(c, 0x40); + signal = xc2028_get_reg(priv, 0x40); if(signal<=0) { signal=frq_lock; } ret: - mutex_unlock(&xc2028->lock); + mutex_unlock(&priv->lock); + + *strength = signal; - return signal; + return 0; } #define DIV 15625 -static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, - enum tuner_mode new_mode, fe_bandwidth_t bandwidth) +static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */, + enum tuner_mode new_mode, + v4l2_std_id std, + fe_bandwidth_t bandwidth) { - int rc; + struct xc2028_data *priv = fe->tuner_priv; + int rc=-EINVAL; unsigned char buf[5]; - struct tuner *t = i2c_get_clientdata(c); u32 div, offset = 0; + tuner_info("%s called\n", __FUNCTION__); + /* HACK: It seems that specific firmware need to be reloaded when freq is changed */ - struct xc2028_data *xc2028 = t->priv; - mutex_lock(&xc2028->lock); + mutex_lock(&priv->lock); - xc2028->firm_type=0; + priv->firm_type=0; /* Reset GPIO 1 */ - if (t->tuner_callback) { - rc = t->tuner_callback( c->adapter->algo_data, - XC2028_TUNER_RESET, 0); - if (rc<0) - goto ret; - } + rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); + if (rc<0) + goto ret; + msleep(10); - printk("xc3028: should set frequency %d kHz)\n", freq / 1000); + tuner_info("should set frequency %d kHz)\n", freq / 1000); - if (check_firmware(c, new_mode, bandwidth)<0) + if (check_firmware(fe, new_mode, std, bandwidth)<0) goto ret; if(new_mode == T_DIGITAL_TV) @@ -352,13 +365,10 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, div = (freq - offset + DIV/2)/DIV; /* CMD= Set frequency */ - send_seq(c, {0x00, 0x02, 0x00, 0x00}); - if (t->tuner_callback) { - rc = t->tuner_callback( c->adapter->algo_data, - XC2028_RESET_CLK, 1); - if (rc<0) - goto ret; - } + send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); + if (rc<0) + goto ret; msleep(10); @@ -368,121 +378,82 @@ static void generic_set_tv_freq(struct i2c_client *c, u32 freq /* in Hz */, buf[3]= 0xff & (div); buf[4]= 0; - i2c_send(rc, c, buf, sizeof(buf)); + i2c_send(rc, priv, buf, sizeof(buf)); if (rc<0) goto ret; msleep(100); + priv->frequency=freq; + printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", buf[1],buf[2],buf[3],buf[4], - freq / 16, freq % 16 * 100 / 16); + freq / 1000000, (freq%1000000)/10000); -ret: - mutex_unlock(&xc2028->lock); -} + rc=0; +ret: + mutex_unlock(&priv->lock); -static void set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); - - generic_set_tv_freq(c, freq * 62500l, T_ANALOG_TV, - BANDWIDTH_8_MHZ /* unimportant */); + return rc; } -static void xc2028_release(struct i2c_client *c) +static int xc2028_set_tv_freq(struct dvb_frontend *fe, + struct analog_parameters *p) { - struct tuner *t = i2c_get_clientdata(c); + struct xc2028_data *priv = fe->tuner_priv; - kfree(t->priv); - t->priv = NULL; -} - -static struct tuner_operations tea5767_tuner_ops = { - .set_tv_freq = set_tv_freq, - .has_signal = xc2028_signal, - .release = xc2028_release, -// .is_stereo = xc2028_stereo, -}; + tuner_info("%s called\n", __FUNCTION__); + return generic_set_tv_freq(fe, 62500l*p->frequency, T_ANALOG_TV, + p->std, + BANDWIDTH_8_MHZ /* NOT USED */); +} -static int init=0; - -int xc2028_tuner_init(struct i2c_client *c) +static int xc2028_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { - struct tuner *t = i2c_get_clientdata(c); - int version = xc2028_get_reg(c, 0x4); - int prd_id = xc2028_get_reg(c, 0x8); - struct xc2028_data *xc2028; + struct xc2028_data *priv = fe->tuner_priv; - tuner_info("Xcv2028/3028 init called!\n"); + tuner_info("%s called\n", __FUNCTION__); - if (init) { - printk (KERN_ERR "Module already initialized!\n"); - return 0; + /* FIXME: Only OFDM implemented */ + if (fe->ops.info.type != FE_OFDM) { + tuner_info ("DTV type not implemented.\n"); + return -EINVAL; } - init++; - - xc2028 = kzalloc(sizeof(*xc2028), GFP_KERNEL); - if (!xc2028) - return -ENOMEM; - t->priv = xc2028; - xc2028->bandwidth=BANDWIDTH_6_MHZ; - xc2028->need_load_generic=1; - xc2028->mode = T_UNINITIALIZED; + return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV, + 0, /* NOT USED */ + p->u.ofdm.bandwidth); - mutex_init(&xc2028->lock); - - /* FIXME: Check where t->priv will be freed */ - - if (version<0) - version=0; - - if (prd_id<0) - prd_id=0; - - strlcpy(c->name, "xc2028", sizeof(c->name)); - tuner_info("type set to %d (%s, hw ver=%d.%d, fw ver=%d.%d, id=0x%04x)\n", - t->type, c->name, - (version>>12)&0x0f,(version>>8)&0x0f, - (version>>4)&0x0f,(version)&0x0f, prd_id); - - memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); - - return 0; } -static int xc3028_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int xc2028_dvb_release(struct dvb_frontend *fe) { - struct i2c_client *c = fe->tuner_priv; + struct xc2028_data *priv = fe->tuner_priv; + + tuner_info("%s called\n", __FUNCTION__); - printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + priv->count--; - generic_set_tv_freq(c, p->frequency, T_DIGITAL_TV, - p->u.ofdm.bandwidth); + if (!priv->count) + kfree (priv); return 0; } -static int xc3028_dvb_release(struct dvb_frontend *fe) +static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) { - printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + struct xc2028_data *priv = fe->tuner_priv; - fe->tuner_priv = NULL; + tuner_info("%s called\n", __FUNCTION__); - return 0; -} - -static int xc3028_dvb_init(struct dvb_frontend *fe) -{ - printk(KERN_INFO "xc2028: %s called\n", __FUNCTION__); + *frequency = priv->frequency; return 0; } -static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = { +static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .info = { .name = "Xceive XC3028", .frequency_min = 42000000, @@ -490,33 +461,74 @@ static const struct dvb_tuner_ops xc3028_dvb_tuner_ops = { .frequency_step = 50000, }, - .release = xc3028_dvb_release, - .init = xc3028_dvb_init, + .set_analog_params = xc2028_set_tv_freq, + .release = xc2028_dvb_release, + .get_frequency = xc2028_get_frequency, + .get_rf_strength = xc2028_signal, + .set_params = xc2028_set_params, // int (*sleep)(struct dvb_frontend *fe); - - /** This is for simple PLLs - set all parameters in one go. */ - .set_params = xc3028_set_params, - - /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ -// int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); - -// int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); // int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); - // int (*get_status)(struct dvb_frontend *fe, u32 *status); }; -int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe) +int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, + u8 i2c_addr, struct device *dev, void *video_dev, + int (*tuner_callback) (void *dev, int command,int arg)) { - fe->tuner_priv = c; + struct xc2028_data *priv; - memcpy(&fe->ops.tuner_ops, &xc3028_dvb_tuner_ops, sizeof(fe->ops.tuner_ops)); + printk( KERN_INFO PREFIX "Xcv2028/3028 init called!\n"); - return 0; -} + if (NULL == dev) + return -ENODEV; + + if (NULL == video_dev) + return -ENODEV; + + if (!tuner_callback) { + printk( KERN_ERR PREFIX "No tuner callback!\n"); + return -EINVAL; + } + + list_for_each_entry(priv, &xc2028_list, xc2028_list) { + if (priv->dev == dev) { + dev = NULL; + priv->count++; + } + } + + if (dev) { + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + fe->tuner_priv = priv; + priv->bandwidth=BANDWIDTH_6_MHZ; + priv->need_load_generic=1; + priv->mode = T_UNINITIALIZED; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->dev = dev; + priv->video_dev = video_dev; + priv->tuner_callback = tuner_callback; + + mutex_init(&priv->lock); + + list_add_tail(&priv->xc2028_list,&xc2028_list); + } + + memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, + sizeof(xc2028_dvb_tuner_ops)); + + tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + + return 0; +} EXPORT_SYMBOL(xc2028_attach); +MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 34ff4cba131..d5a18a37d1c 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -4,6 +4,11 @@ * This code is placed under the terms of the GNU General Public License v2 */ +#ifndef __TUNER_XC2028_H__ +#define __TUNER_XC2028_H__ + +#include "dvb_frontend.h" + /* xc2028 commands for callback */ #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 @@ -11,4 +16,21 @@ struct dvb_frontend; struct i2c_client; -int xc2028_attach(struct i2c_client *c, struct dvb_frontend *fe); +#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) +int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, + u8 i2c_addr, struct device *dev, void *video_dev, + int (*tuner_callback) (void *dev, int command,int arg)); + +#else +static inline int xc2028_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, struct device *dev, void *video_dev, + int (*tuner_callback) (void *dev, int command,int arg)) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} +#endif + +#endif /* __TUNER_XC2028_H__ */ -- cgit v1.2.3 From de3fe21ba2fdc0733ad4e555b95121baeba7fcd5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Oct 2007 09:22:08 -0300 Subject: V4L/DVB (6431): Improve firmware format Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 99 +++++++ drivers/media/video/tuner-xc2028.c | 452 +++++++++++++++++++++++-------- drivers/media/video/tuner-xc2028.h | 15 +- 3 files changed, 455 insertions(+), 111 deletions(-) create mode 100644 drivers/media/video/tuner-xc2028-types.h diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h new file mode 100644 index 00000000000..80b19eb1b08 --- /dev/null +++ b/drivers/media/video/tuner-xc2028-types.h @@ -0,0 +1,99 @@ +/* tuner-xc2028_types + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* xc3028 firmware types */ + +/* BASE firmware should be loaded before any other firmware */ +#define BASE (1<<0) + +/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ +#define F8MHZ (1<<1) + +/* Multichannel Television Sound (MTS) + Those firmwares are capable of using xc2038 DSP to decode audio and + produce a baseband audio output on some pins of the chip. + There are MTS firmwares for the most used video standards. It should be + required to use MTS firmwares, depending on the way audio is routed into + the bridge chip + */ +#define MTS (1<<2) + +/* FIXME: I have no idea what's the difference between + D2620 and D2633 firmwares + */ +#define D2620 (1<<3) +#define D2633 (1<<4) + +/* DTV firmwares for 6, 7 and 8 MHz + DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS + DTV8 - 8MHz - DVB-C/DVB-T + */ +#define DTV6_ATSC (1<<5) +#define DTV6_QAM (1<<6) +#define DTV7 (1<<7) +#define DTV78 (1<<8) +#define DTV8 (1<<9) + +/* There's a FM | BASE firmware + FM specific firmware (std=0) */ +#define FM (1<<10) + +/* Applies only for FM firmware + Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) + */ +#define INPUT1 (1<<11) + + +/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + There are variants both with and without NOGD + */ +#define LCD (1<<12) + +/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + */ +#define NOGD (1<<13) + +/* Old firmwares were broken into init0 and init1 */ +#define INIT1 (1<<14) + +/* Newer types to be moved to videodev2.h */ + +#define V4L2_STD_SECAM_K3 (0x02000000) + +/* Audio types */ + +#define V4L2_STD_A2_A (1L<<32) +#define V4L2_STD_A2_B (1L<<33) +#define V4L2_STD_NICAM_A (1L<<34) +#define V4L2_STD_NICAM_B (1L<<35) +#define V4L2_STD_AM (1L<<36) +#define V4L2_STD_BTSC (1L<<37) +#define V4L2_STD__EIAJ (1L<<38) + +#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) +#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) + +/* To preserve backward compatibilty, + (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported + */ + +#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ + V4L2_STD_NICAM | \ + V4L2_STD_AM | \ + V4L2_STD_BTSC | \ + V4L2_STD_EIAJ) + +/* Used standards with audio restrictions */ + +#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) +#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) +#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) +#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) +#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) +#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index e4c371896de..7d53d58aafa 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -15,6 +15,7 @@ #include #include "tuner-i2c.h" #include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" #include #include "dvb_frontend.h" @@ -22,21 +23,13 @@ #define PREFIX "xc2028 " static LIST_HEAD(xc2028_list); - -/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ - -/* Generic firmwares */ -static const char *firmware_INIT0 = "tm_xc3028_MTS_init0.fw"; -static const char *firmware_8MHZ_INIT0 = "tm_xc3028_8M_MTS_init0.fw"; -static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw"; - -/* Standard-specific firmwares */ -static const char *firmware_6M = "tm_xc3028_DTV_6M.fw"; -static const char *firmware_7M = "tm_xc3028_DTV_7M.fw"; -static const char *firmware_8M = "tm_xc3028_DTV_8M.fw"; -static const char *firmware_B = "tm_xc3028_B_PAL.fw"; -static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw"; -static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + unsigned char *ptr; + unsigned int size; +}; struct xc2028_data { struct list_head xc2028_list; @@ -46,7 +39,14 @@ struct xc2028_data { struct device *dev; void *video_dev; int count; - u32 frequency; + __u32 frequency; + + struct firmware_description *firm; + int firm_size; + + __u16 version; + + struct xc2028_ctrl ctrl; v4l2_std_id firm_type; /* video stds supported by current firmware */ @@ -54,6 +54,9 @@ struct xc2028_data { 6M, 7M or 8M */ int need_load_generic; /* The generic firmware were loaded? */ + + int max_len; /* Max firmware chunk */ + enum tuner_mode mode; struct i2c_client *i2c_client; @@ -102,92 +105,263 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg) return (buf[1])|(buf[0]<<8); } -static int load_firmware (struct dvb_frontend *fe, const char *name) +static void free_firmware (struct xc2028_data *priv) { - struct xc2028_data *priv = fe->tuner_priv; + int i; + + if (!priv->firm) + return; + + for (i=0;ifirm_size;i++) { + if (priv->firm[i].ptr) + kfree(priv->firm[i].ptr); + } + kfree(priv->firm); + + priv->firm=NULL; + priv->need_load_generic = 1; +} + +static int load_all_firmwares (struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; const struct firmware *fw=NULL; unsigned char *p, *endp; - int len=0, rc=0; - static const char firmware_ver[] = "tm6000/xcv v1"; + int rc=0, n, n_array; + char name[33]; tuner_info("%s called\n", __FUNCTION__); - tuner_info("Loading firmware %s\n", name); - rc = request_firmware(&fw, name, priv->dev); + tuner_info("Loading firmware %s\n", priv->ctrl.fname); + rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); if (rc < 0) { if (rc==-ENOENT) - tuner_info("Error: firmware %s not found.\n", name); + tuner_info("Error: firmware %s not found.\n", + priv->ctrl.fname); else - tuner_info("Error %d while requesting firmware %s \n", rc, name); + tuner_info("Error %d while requesting firmware %s \n", + rc, priv->ctrl.fname); return rc; } p=fw->data; endp=p+fw->size; - if(fw->size==0) { + if(fw->sizesizesize,(int)sizeof(firmware_ver)-1); - rc=-EINVAL; - goto err; + + memcpy(name,p,sizeof(name)-1); + name[sizeof(name)-1]=0; + p+=sizeof(name)-1; + + priv->version = le16_to_cpu(*(__u16 *)p); + p += 2; + + tuner_info("firmware: %s, ver %d.%d\n", name, + priv->version>>8, priv->version&0xff); + + if (p+2>endp) + goto corrupt; + + n_array = le16_to_cpu(*(__u16 *)p); + p += 2; + + tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname); + + priv->firm=kzalloc(sizeof(*priv->firm)*n_array,GFP_KERNEL); + + if (!fw) { + tuner_info("Not enough memory for loading firmware.\n"); + rc=-ENOMEM; + goto done; } - if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) { - /* Firmware is incorrect */ - tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n"); - rc=-EINVAL; - goto err; + priv->firm_size = n_array; + n=-1; + while (p= n_array) { + tuner_info("Too much firmwares at the file\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (p+sizeof(type)+sizeof(id)+sizeof(size)>endp) { + tuner_info("Lost firmware!\n"); + goto corrupt; + } + + type = le32_to_cpu(*(__u32 *)p); + p += sizeof(type); + + id = le64_to_cpu(*(v4l2_std_id *)p); + p += sizeof(id); + + size = le32_to_cpu(*(v4l2_std_id *)p); + p += sizeof(size); + + if ((!size)||(size+p>endp)) { + tuner_info("Firmware type %x, id %lx corrupt\n", + type, (unsigned long) id); + goto corrupt; + } + + priv->firm[n].ptr=kzalloc(size,GFP_KERNEL); + if (!priv->firm[n].ptr) { + tuner_info("Not enough memory.\n"); + rc=-ENOMEM; + goto err; + } + tuner_info("Loading firmware type %x, id %lx, size=%d.\n", + type, (unsigned long) id, size); + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + + p += size; + } + + if (n+1 != priv->firm_size) { + tuner_info("Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +corrupt: + rc=-EINVAL; + tuner_info("Error: firmware file is corrupted!\n"); + +err: + tuner_info("Releasing loaded firmware file.\n"); + + free_firmware(priv); + +done: + release_firmware(fw); + tuner_info("Firmware files loaded.\n"); + + return rc; +} + +static int load_firmware (struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i, rc; + unsigned char *p, *endp, buf[priv->max_len]; + + tuner_info("%s called\n", __FUNCTION__); + + if (!priv->firm) { + printk (KERN_ERR PREFIX "Error! firmware not loaded\n"); + return -EINVAL; + } + + if ((type == 0) && (*id == 0)) + *id=V4L2_STD_PAL; + + /* Seek for exact match */ + for (i=0;ifirm_size;i++) { + if ( (type == priv->firm[i].type) && + (*id == priv->firm[i].id)) + goto found; + } + + /* Seek for generic video standard match */ + for (i=0;ifirm_size;i++) { + if ( (type == priv->firm[i].type) && (*id & priv->firm[i].id)) + goto found; + } + + /*FIXME: Would make sense to seek for type "hint" match ? */ + + tuner_info ("Can't find firmware for type=%x, id=%lx\n", type, + (long int)*id); + return -EINVAL; + +found: + *id = priv->firm[i].id; + tuner_info ("Found firmware for type=%x, id=%lx\n", type, + (long int)*id); + + p = priv->firm[i].ptr; + + if (!p) { + printk(KERN_ERR PREFIX "Firmware pointer were freed!"); + return -EINVAL; } - p+=sizeof(firmware_ver)-1; + endp = p+priv->firm[i].size; - while(pendp) { + tuner_info("missing bytes\n"); + return -EINVAL; + } + + + size = le16_to_cpu(*(__u16 *)p); + p += sizeof(size); + + if (size == 0xffff) + return 0; + + if (!size) { /* Special callback command received */ rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, (*p)&0x7f); + XC2028_TUNER_RESET, 0); if (rc<0) { tuner_info("Error at RESET code %d\n", (*p)&0x7f); - goto err; + return -EINVAL; } - p++; continue; } - len=*p; - p++; - if (p+len+1>endp) { - /* Firmware is incorrect */ - tuner_info("Error: firmware is truncated!\n"); - rc=-EINVAL; - goto err; - } - if (len<=0) { - tuner_info("Error: firmware file is corrupted!\n"); - rc=-EINVAL; - goto err; + + /* Checks for a sleep command */ + if (size & 0x8000) { + msleep (size & 0x7fff); + continue; } - i2c_send(rc, priv, p, len); - if (rc<0) - goto err; - p+=len; + if ((size + p > endp)) { + tuner_info("missing bytes: need %d, have %d\n", + size, (int)(endp-p)); + return -EINVAL; + } - if (*p) - msleep(*p); + buf[0] = *p; p++; - } + size--; + /* Sends message chunks */ + while (size>0) { + int len = (sizemax_len-1)?size:priv->max_len-1; -err: - release_firmware(fw); + memcpy(buf+1, p, len); - return rc; + i2c_send(rc, priv, buf, len+1); + if (rc<0) { + tuner_info("%d returned from send\n",rc); + return -EINVAL; + } + + p += len; + size -= len; + } + } + return -EINVAL; } static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, @@ -196,11 +370,21 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, { struct xc2028_data *priv = fe->tuner_priv; int rc, version; - const char *name; - int change_digital_bandwidth; + v4l2_std_id std0=0; + unsigned int type0=0,type=0; + int change_digital_bandwidth; tuner_info("%s called\n", __FUNCTION__); + if (!priv->firm) { + if (!priv->ctrl.fname) + return -EINVAL; + + rc=load_all_firmwares(fe); + if (rc<0) + return rc; + } + tuner_info( "I am in mode %u and I should switch to mode %i\n", priv->mode, new_mode); @@ -213,23 +397,31 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, change_digital_bandwidth = (priv->mode == T_DIGITAL_TV && bandwidth != priv->bandwidth) ? 1 : 0; tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, - bandwidth); + bandwidth); if (priv->need_load_generic) { - if (priv->bandwidth==8) - name = firmware_8MHZ_INIT0; - else - name = firmware_INIT0; - /* Reset is needed before loading firmware */ rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); if (rc<0) return rc; - rc = load_firmware(fe,name); - if (rc<0) + type0=BASE; + + if (priv->ctrl.type == XC2028_FIRM_MTS) + type0 |= MTS; + + if (priv->bandwidth==8) + type0 |= F8MHZ; + + /* FIXME: How to load FM and FM|INPUT1 firmwares? */ + + rc = load_firmware(fe, type0, &std0); + if (rc<0) { + tuner_info("Error %d while loading generic firmware\n", + rc); return rc; + } priv->need_load_generic=0; priv->firm_type=0; @@ -241,49 +433,53 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, tuner_info("I should change bandwidth %u\n", change_digital_bandwidth); - /* FIXME: t->std makes no sense here */ if (change_digital_bandwidth) { + + /*FIXME: Should allow selecting between D2620 and D2633 */ + type |= D2620; + + /* FIXME: When should select a DTV78 firmware? + */ switch(bandwidth) { - case BANDWIDTH_8_MHZ: - std = V4L2_STD_DTV_8MHZ; + case BANDWIDTH_8_MHZ: + type |= DTV8; break; - - case BANDWIDTH_7_MHZ: - std = V4L2_STD_DTV_7MHZ; + case BANDWIDTH_7_MHZ: + type |= DTV7; break; - - case BANDWIDTH_6_MHZ: - std = V4L2_STD_DTV_6MHZ; + case BANDWIDTH_6_MHZ: + /* FIXME: Should allow select also ATSC */ + type |= DTV6_QAM; break; - default: - tuner_info("error: bandwidth not supported.\n"); + default: + tuner_info("error: bandwidth not supported.\n"); }; priv->bandwidth = bandwidth; } + /* Load INIT1, if needed */ + tuner_info("Trying to load init1 firmware\n"); + type0 = BASE | INIT1 | priv->ctrl.type; + if (priv->ctrl.type == XC2028_FIRM_MTS) + type0 |= MTS; + + /* FIXME: Should handle errors - if INIT1 found */ + rc = load_firmware(fe, type0, &std0); + + /* FIXME: Should add support for FM radio + */ + + if (priv->ctrl.type == XC2028_FIRM_MTS) + type |= MTS; + + tuner_info("firmware standard to load: %08lx\n",(unsigned long) std); if (priv->firm_type & std) { - tuner_info("xc3028: no need to load a std-specific firmware.\n"); + tuner_info("no need to load a std-specific firmware.\n"); return 0; } - rc = load_firmware(fe,firmware_INIT1); - - if (std & V4L2_STD_MN) - name=firmware_MN; - else if (std & V4L2_STD_DTV_6MHZ) - name=firmware_6M; - else if (std & V4L2_STD_DTV_7MHZ) - name=firmware_7M; - else if (std & V4L2_STD_DTV_8MHZ) - name=firmware_8M; - else if (std & V4L2_STD_PAL_B) - name=firmware_B; - else - name=firmware_DK; - - tuner_info("loading firmware named %s.\n", name); - rc = load_firmware(fe, name); + rc = load_firmware(fe, type, &std); if (rc<0) return rc; @@ -341,11 +537,11 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */, tuner_info("%s called\n", __FUNCTION__); + mutex_lock(&priv->lock); + /* HACK: It seems that specific firmware need to be reloaded when freq is changed */ - mutex_lock(&priv->lock); - priv->firm_type=0; /* Reset GPIO 1 */ @@ -365,7 +561,13 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */, div = (freq - offset + DIV/2)/DIV; /* CMD= Set frequency */ - send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + + if (priv->version<0x0202) { + send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + } else { + send_seq(priv, {0x80, 0x02, 0x00, 0x00}); + } + rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); if (rc<0) goto ret; @@ -436,8 +638,13 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) priv->count--; - if (!priv->count) + if (!priv->count) { + if (priv->ctrl.fname) + kfree(priv->ctrl.fname); + + free_firmware(priv); kfree (priv); + } return 0; } @@ -453,6 +660,32 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } +static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct xc2028_ctrl *p = priv_cfg; + + tuner_info("%s called\n", __FUNCTION__); + + priv->ctrl.type = p->type; + + if (p->fname) { + if (priv->ctrl.fname) + kfree(priv->ctrl.fname); + + priv->ctrl.fname = kmalloc(strlen(p->fname)+1, GFP_KERNEL); + if (!priv->ctrl.fname) + return -ENOMEM; + + free_firmware(priv); + strcpy(priv->ctrl.fname, p->fname); + } + + tuner_info("%s OK\n", __FUNCTION__); + + return 0; +} + static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .info = { .name = "Xceive XC3028", @@ -461,6 +694,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .frequency_step = 50000, }, + .set_config = xc2028_set_config, .set_analog_params = xc2028_set_tv_freq, .release = xc2028_dvb_release, .get_frequency = xc2028_get_frequency, @@ -513,6 +747,8 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, priv->dev = dev; priv->video_dev = video_dev; priv->tuner_callback = tuner_callback; + priv->max_len = 13; + mutex_init(&priv->lock); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index d5a18a37d1c..f4856f07bd0 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -9,13 +9,22 @@ #include "dvb_frontend.h" +#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" + +enum xc2028_firm_type { + XC2028_FIRM_NORMAL, + XC2028_FIRM_MTS, +}; + +struct xc2028_ctrl { + enum xc2028_firm_type type; + char *fname; +}; + /* xc2028 commands for callback */ #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 -struct dvb_frontend; -struct i2c_client; - #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr, struct device *dev, void *video_dev, -- cgit v1.2.3 From 746d9732dbd5b95c3ba36230e2814fa2c391a311 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 25 Aug 2007 19:08:45 -0300 Subject: V4L/DVB (6433): Move all tda8275/8275a tuning code from tda8290 module into tda827x module Add analog tuning support to tda827x dvb_frontend tuner module. Convert tda8290 module back to native tuner interface. The tda8290 analog demodulator will be handled the same way as tda9887. The tuner.ko module (tuner-core) will pass commands to tda8290 via the tuner_operations interface. tda8290 will communicate with tda827x via the dvb_frontend interface, while passing a pointer to a private data structure. Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 1 + drivers/media/dvb/frontends/tda827x.c | 307 +++++++++++++++++- drivers/media/dvb/frontends/tda827x.h | 10 + drivers/media/video/tda8290.c | 566 +++++++--------------------------- drivers/media/video/tda8290.h | 30 +- drivers/media/video/tuner-core.c | 16 +- 6 files changed, 423 insertions(+), 507 deletions(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index dfb52592451..d363d0cae38 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -107,6 +107,7 @@ config TUNER_MT20XX config TUNER_TDA8290 tristate "TDA 8290+8275(a) tuner combo" depends on I2C + select DVB_TDA827X default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for Philips TDA8290+8275(a) tuner. diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 256fc4bf500..3c71f07a6d2 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -19,12 +19,16 @@ */ #include -#include #include +#include +#include #include "tda827x.h" static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "tda827x: " args); \ @@ -48,7 +52,7 @@ struct tda827x_data { u8 div1p5; }; -static const struct tda827x_data tda827x_dvbt[] = { +static const struct tda827x_data tda827x_table[] = { { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, @@ -106,21 +110,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe, tuner_freq = params->frequency + if_freq; i = 0; - while (tda827x_dvbt[i].lomax < tuner_freq) { - if(tda827x_dvbt[i + 1].lomax == 0) + while (tda827x_table[i].lomax < tuner_freq) { + if (tda827x_table[i + 1].lomax == 0) break; i++; } - N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); buf[0] = 0; buf[1] = (N>>8) | 0x40; buf[2] = N & 0xff; buf[3] = 0; buf[4] = 0x52; - buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + - (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; - buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + + tda827x_table[i].bp; + buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; buf[7] = 0xbf; buf[8] = 0x2a; buf[9] = 0x05; @@ -140,7 +145,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe, msleep(500); /* correct CP value */ buf[0] = 0x30; - buf[1] = 0x50 + tda827x_dvbt[i].cp; + buf[1] = 0x50 + tda827x_table[i].cp; msg.len = 2; if (fe->ops.i2c_gate_ctrl) @@ -173,6 +178,100 @@ static int tda827xo_sleep(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ +static int tda827xo_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[8]; + unsigned char reg2[2]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; + unsigned int freq = params->frequency; + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->cfg->sgIF; + + i = 0; + while (tda827x_table[i].lomax < N * 62500) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827x_table[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0x40; + tuner_reg[4] = 0x52 + (priv->cfg->tda827x_lpsel << 5); + tuner_reg[5] = (tda827x_table[i].spd << 6) + + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + tda827x_table[i].bp; + tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); + tuner_reg[7] = 0x8f; + + msg.buf = tuner_reg; + msg.len = 8; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msg.buf = reg2; + msg.len = 2; + reg2[0] = 0x80; + reg2[1] = 0; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0xbf; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 0x80; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 4; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4]; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(550); + reg2[0] = 0x30; + reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0x3f; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x80; + reg2[1] = 0x08; /* Vsync en */ + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = freq * 62500; + + return 0; +} + +static void tda827xo_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = { 0x80, 0x0c }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + + i2c_transfer(priv->i2c_adap, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + struct tda827xa_data { u32 lomax; u8 svco; @@ -212,6 +311,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} }; +static struct tda827xa_data tda827xa_analog[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + static int tda827xa_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -368,6 +496,156 @@ static int tda827xa_sleep(struct dvb_frontend *fe) return 0; } +/* ------------------------------------------------------------------ */ + +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char buf[] = {0x22, 0x01}; + int arg; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + if (priv->cfg->config) { + if (high) + dprintk("setting LNA to high gain\n"); + else + dprintk("setting LNA to low gain\n"); + } + switch (*priv->cfg->config) { + case 0: /* no LNA */ + break; + case 1: /* switch is GPIO 0 of tda8290 */ + case 2: + /* turn Vsync on */ + if (params->std & V4L2_STD_MN) + arg = 1; + else + arg = 0; + if (priv->cfg->tuner_callback) + priv->cfg->tuner_callback(priv->i2c_adap->algo_data, + 1, arg); + buf[1] = high ? 0 : 1; + if (*priv->cfg->config == 2) + buf[1] = high ? 1 : 0; + i2c_transfer(priv->i2c_adap, &msg, 1); + break; + case 3: /* switch with GPIO of saa713x */ + if (priv->cfg->tuner_callback) + priv->cfg->tuner_callback(priv->i2c_adap->algo_data, + 0, high); + break; + } +} + +static int tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[11]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = tuner_reg, .len = sizeof(tuner_reg) }; + unsigned int freq = params->frequency; + + tda827xa_lna_gain(fe, 1, params); + msleep(10); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->cfg->sgIF; + + i = 0; + while (tda827xa_analog[i].lomax < N * 62500) { + if (tda827xa_analog[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827xa_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0; + tuner_reg[4] = 0x16; + tuner_reg[5] = (tda827xa_analog[i].spd << 5) + + (tda827xa_analog[i].svco << 3) + + tda827xa_analog[i].sbs; + tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); + tuner_reg[7] = 0x1c; + tuner_reg[8] = 4; + tuner_reg[9] = 0x20; + tuner_reg[10] = 0x00; + msg.len = 11; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x90; + tuner_reg[1] = 0xff; + tuner_reg[2] = 0xe0; + tuner_reg[3] = 0; + tuner_reg[4] = 0x99 + (priv->cfg->tda827x_lpsel << 1); + msg.len = 5; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xa0; + tuner_reg[1] = 0xc0; + msg.len = 2; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x30; + tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msg.flags = I2C_M_RD; + i2c_transfer(priv->i2c_adap, &msg, 1); + msg.flags = 0; + tuner_reg[1] >>= 4; + dprintk("AGC2 gain is: %d\n", tuner_reg[1]); + if (tuner_reg[1] < 1) + tda827xa_lna_gain(fe, 0, params); + + msleep(100); + tuner_reg[0] = 0x60; + tuner_reg[1] = 0x3c; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(163); + tuner_reg[0] = 0x50; + tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x80; + tuner_reg[1] = 0x28; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xb0; + tuner_reg[1] = 0x01; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xc0; + tuner_reg[1] = 0x19 + (priv->cfg->tda827x_lpsel << 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = freq * 62500; + + return 0; +} + +static void tda827xa_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x2c}; + struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + i2c_transfer(priv->i2c_adap, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + static int tda827x_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -430,6 +708,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = { .init = tda827x_initial_init, .sleep = tda827x_initial_sleep, .set_params = tda827xo_set_params, + .set_analog_params = tda827xo_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -445,6 +724,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = { .init = tda827x_init, .sleep = tda827xa_sleep, .set_params = tda827xa_set_params, + .set_analog_params = tda827xa_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -465,9 +745,11 @@ static int tda827x_probe_version(struct dvb_frontend *fe) dprintk("tda827x tuner found\n"); fe->ops.tuner_ops.init = tda827x_init; fe->ops.tuner_ops.sleep = tda827xo_sleep; + priv->cfg->agcf = tda827xo_agcf; } else { dprintk("tda827xa tuner found\n"); memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + priv->cfg->agcf = tda827xa_agcf; } return 0; } @@ -487,17 +769,14 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, priv->i2c_adap = i2c; priv->cfg = cfg; memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; + dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); + return fe; } - EXPORT_SYMBOL(tda827x_attach); -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann "); MODULE_AUTHOR("Michael Krufky "); diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h index 69e8263d6d5..06626f7af61 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/dvb/frontends/tda827x.h @@ -29,9 +29,19 @@ struct tda827x_config { + /* saa7134 - provided callbacks */ void (*lna_gain) (struct dvb_frontend *fe, int high); int (*init) (struct dvb_frontend *fe); int (*sleep) (struct dvb_frontend *fe); + + /* interface to tda829x driver */ + unsigned char tda827x_lpsel; + unsigned int sgIF; + + unsigned int *config; + int (*tuner_callback) (void *dev, int command, int arg); + + void (*agcf)(struct dvb_frontend *fe); }; diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 0e5cf459d3e..5d30cbcd736 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -23,11 +23,11 @@ #include #include #include -#include "tuner-i2c.h" #include "tda8290.h" +#include "tda827x.h" -static int debug = 0; -module_param(debug, int, 0644); +static int tuner_debug = 0; +module_param_named(debug, tuner_debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); #define PREFIX "tda8290 " @@ -38,332 +38,18 @@ struct tda8290_priv { struct tuner_i2c_props i2c_props; unsigned char tda8290_easy_mode; - unsigned char tda827x_lpsel; + unsigned char tda827x_addr; unsigned char tda827x_ver; - unsigned int sgIF; - - u32 frequency; - - unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command,int arg); -}; - -/* ---------------------------------------------------------------------- */ - -struct tda827x_data { - u32 lomax; - u8 spd; - u8 bs; - u8 bp; - u8 cp; - u8 gc3; - u8 div1p5; -}; - /* Note lomax entry is lo / 62500 */ - -static struct tda827x_data tda827x_analog[] = { - { .lomax = 992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 62 MHz */ - { .lomax = 1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 66 MHz */ - { .lomax = 1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 76 MHz */ - { .lomax = 1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 84 MHz */ - { .lomax = 1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 93 MHz */ - { .lomax = 1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 98 MHz */ - { .lomax = 1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */ - { .lomax = 1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */ - { .lomax = 2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */ - { .lomax = 2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */ - { .lomax = 2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */ - { .lomax = 2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */ - { .lomax = 2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */ - { .lomax = 3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */ - { .lomax = 3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */ - { .lomax = 4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */ - { .lomax = 4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */ - { .lomax = 5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */ - { .lomax = 5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */ - { .lomax = 7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */ - { .lomax = 7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */ - { .lomax = 8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */ - { .lomax = 8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */ - { .lomax = 9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */ - { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */ - { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */ - { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */ - { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */ - { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ + struct tda827x_config cfg; }; -static void tda827x_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[8]; - unsigned char reg2[2]; - u32 N; - int i; - struct tda8290_priv *priv = fe->tuner_priv; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; - unsigned int freq = params->frequency; - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - i = 0; - while (tda827x_analog[i].lomax < N) { - if(tda827x_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827x_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5); - tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) + - (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp; - tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4); - tuner_reg[7] = 0x8f; - - msg.buf = tuner_reg; - msg.len = 8; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msg.buf= reg2; - msg.len = 2; - reg2[0] = 0x80; - reg2[1] = 0; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0xbf; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 4; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4]; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(550); - reg2[0] = 0x30; - reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0x3f; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x80; - reg2[1] = 0x08; // Vsync en - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -static void tda827x_agcf(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x0c}; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, - .flags = 0, .len = 2}; - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -/* ---------------------------------------------------------------------- */ - -struct tda827xa_data { - u32 lomax; - u8 svco; - u8 spd; - u8 scr; - u8 sbs; - u8 gc3; -}; - -static struct tda827xa_data tda827xa_analog[] = { - { .lomax = 910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, /* 56.875 MHz */ - { .lomax = 1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 67.25 MHz */ - { .lomax = 1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 81.25 MHz */ - { .lomax = 1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 97.5 MHz */ - { .lomax = 1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, /* 113.75 MHz */ - { .lomax = 2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 134.5 MHz */ - { .lomax = 2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 154 MHz */ - { .lomax = 2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 162.5 MHz */ - { .lomax = 2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 183 MHz */ - { .lomax = 3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, /* 195 MHz */ - { .lomax = 3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, /* 227.5 MHz */ - { .lomax = 4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, /* 269 MHz */ - { .lomax = 5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, /* 325 MHz */ - { .lomax = 6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 390 MHz */ - { .lomax = 7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 455 MHz */ - { .lomax = 8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 520 MHz */ - { .lomax = 8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, /* 538 MHz */ - { .lomax = 8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 554 MHz */ - { .lomax = 9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 620 MHz */ - { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 650 MHz */ - { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 700 MHz */ - { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 780 MHz */ - { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 820 MHz */ - { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 870 MHz */ - { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, /* 911 MHz */ - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ -}; - -static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char buf[] = {0x22, 0x01}; - int arg; - struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - - if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) - return; - - if (*priv->lna_cfg) { - if (high) - tuner_dbg("setting LNA to high gain\n"); - else - tuner_dbg("setting LNA to low gain\n"); - } - switch (*priv->lna_cfg) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - /* turn Vsync on */ - if (params->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - if (priv->tuner_callback) - priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); - buf[1] = high ? 0 : 1; - if (*priv->lna_cfg == 2) - buf[1] = high ? 1 : 0; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (priv->tuner_callback) - priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); - break; - } -} - -static void tda827xa_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[11]; - u32 N; - int i; - struct tda8290_priv *priv = fe->tuner_priv; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; - unsigned int freq = params->frequency; - - tda827xa_lna_gain(fe, 1, params); - msleep(10); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - i = 0; - while (tda827xa_analog[i].lomax < N) { - if(tda827xa_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827xa_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0; - tuner_reg[4] = 0x16; - tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + - tda827xa_analog[i].sbs; - tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; - tuner_reg[8] = 4; - tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); - msg.len = 5; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; - msg.len = 2; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msg.flags = I2C_M_RD; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain(fe, 0, params); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -static void tda827xa_agcf(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, - .flags = 0, .len = 2}; - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +static void tda8290_i2c_bridge(struct tuner *t, int close) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = t->priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; @@ -381,58 +67,56 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) /*---------------------------------------------------------------------*/ -static void set_audio(struct dvb_frontend *fe, - struct analog_parameters *params) +static void set_audio(struct tuner *t) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = t->priv; char* mode; - priv->tda827x_lpsel = 0; - if (params->std & V4L2_STD_MN) { - priv->sgIF = 92; + priv->cfg.tda827x_lpsel = 0; + if (t->std & V4L2_STD_MN) { + priv->cfg.sgIF = 92; priv->tda8290_easy_mode = 0x01; - priv->tda827x_lpsel = 1; + priv->cfg.tda827x_lpsel = 1; mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->sgIF = 108; + } else if (t->std & V4L2_STD_B) { + priv->cfg.sgIF = 108; priv->tda8290_easy_mode = 0x02; mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_GH) { + priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x04; mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_PAL_I) { + priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x08; mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_DK) { + priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; + } else if (t->std & V4L2_STD_SECAM_L) { + priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x20; mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; + } else if (t->std & V4L2_STD_SECAM_LC) { + priv->cfg.sgIF = 20; priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { - priv->sgIF = 124; + priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "xx"; } - if (params->mode == V4L2_TUNER_RADIO) - priv->sgIF = 88; /* if frequency is 5.5 MHz */ + if (t->mode == V4L2_TUNER_RADIO) + priv->cfg.sgIF = 88; /* if frequency is 5.5 MHz */ tuner_dbg("setting tda8290 to system %s\n", mode); } -static int tda8290_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static void tda8290_set_freq(struct tuner *t, unsigned int freq) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = t->priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -455,10 +139,16 @@ static int tda8290_set_params(struct dvb_frontend *fe, pll_stat; int i; - set_audio(fe, params); + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + set_audio(t); - if (priv->lna_cfg) - tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); + tuner_dbg("tda827xa config is 0x%02x\n", t->config); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -474,11 +164,11 @@ static int tda8290_set_params(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(fe, 1); - if (priv->tda827x_ver != 0) - tda827xa_set_analog_params(fe, params); - else - tda827x_set_analog_params(fe, params); + tda8290_i2c_bridge(t, 1); + + if (t->fe.ops.tuner_ops.set_analog_params) + t->fe.ops.tuner_ops.set_analog_params(&t->fe, ¶ms); + for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -507,10 +197,8 @@ static int tda8290_set_params(struct dvb_frontend *fe, if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); - if (priv->tda827x_ver != 0) - tda827xa_agcf(fe); - else - tda827x_agcf(fe); + if (priv->cfg.agcf) + priv->cfg.agcf(&t->fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -539,94 +227,61 @@ static int tda8290_set_params(struct dvb_frontend *fe, } } - tda8290_i2c_bridge(fe, 0); + tda8290_i2c_bridge(t, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); - - priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? - params->frequency * 125 / 2 : params->frequency * 62500; - - return 0; } /*---------------------------------------------------------------------*/ -static int tda8290_has_signal(struct dvb_frontend *fe) +static int tda8290_has_signal(struct tuner *t) { - struct tda8290_priv *priv = fe->tuner_priv; - int ret; + struct tda8290_priv *priv = t->priv; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; - /* for now, report based on afc status */ tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); - - ret = (afc & 0x80) ? 65535 : 0; - - tuner_dbg("AFC status: %d\n", ret); - - return ret; -} - -static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) -{ - *status = 0; - - if (tda8290_has_signal(fe)) - *status = TUNER_STATUS_LOCKED; - - return 0; -} - -static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - *strength = tda8290_has_signal(fe); - - return 0; + return (afc & 0x80)? 65535:0; } /*---------------------------------------------------------------------*/ -static int tda8290_standby(struct dvb_frontend *fe) +static void tda8290_standby(struct tuner *t) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = t->priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(fe, 1); + tda8290_i2c_bridge(t, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); + tda8290_i2c_bridge(t, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); - - return 0; } - -static void tda8290_init_if(struct dvb_frontend *fe) +static void tda8290_init_if(struct tuner *t) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = t->priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((priv->lna_cfg) && - ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) + if ((t->config == 1) || (t->config == 2)) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8290_init_tuner(struct dvb_frontend *fe) +static void tda8290_init_tuner(struct tuner *t) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = t->priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, @@ -636,41 +291,31 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(fe, 1); + tda8290_i2c_bridge(t, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); + tda8290_i2c_bridge(t, 0); } /*---------------------------------------------------------------------*/ -static int tda8290_release(struct dvb_frontend *fe) +static void tda8290_release(struct tuner *t) { - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} + if (t->fe.ops.tuner_ops.release) + t->fe.ops.tuner_ops.release(&t->fe); -static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda8290_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; + kfree(t->priv); + t->priv = NULL; } -static struct dvb_tuner_ops tda8290_tuner_ops = { - .sleep = tda8290_standby, - .set_analog_params = tda8290_set_params, - .release = tda8290_release, - .get_frequency = tda8290_get_frequency, - .get_status = tda8290_get_status, - .get_rf_strength = tda8290_get_rf_strength, +static struct tuner_operations tda8290_tuner_ops = { + .set_tv_freq = tda8290_set_freq, + .set_radio_freq = tda8290_set_freq, + .has_signal = tda8290_has_signal, + .standby = tda8290_standby, + .release = tda8290_release, }; -struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg) +int tda8290_attach(struct tuner *t) { struct tda8290_priv *priv = NULL; u8 data; @@ -680,17 +325,15 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) - return NULL; - fe->tuner_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - if (cfg) { - priv->lna_cfg = cfg->lna_cfg; - priv->tuner_callback = cfg->tuner_callback; - } + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + priv->cfg.config = &t->config; + priv->cfg.tuner_callback = t->tuner_callback; - tda8290_i2c_bridge(fe, 1); + tda8290_i2c_bridge(t, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; @@ -706,7 +349,7 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(fe, 0); + tda8290_i2c_bridge(t, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; @@ -727,42 +370,45 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(fe, 1); + tda8290_i2c_bridge(t, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) tuner_warn("TDA827x access failed!\n"); - memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, - sizeof(struct dvb_tuner_ops)); - if ((data & 0x3c) == 0) { - strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = 55000000; - fe->ops.tuner_ops.info.frequency_max = 860000000; - fe->ops.tuner_ops.info.frequency_step = 250000; + strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); priv->tda827x_ver = 0; } else { - strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = 44000000; - fe->ops.tuner_ops.info.frequency_max = 906000000; - fe->ops.tuner_ops.info.frequency_step = 62500; + strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); priv->tda827x_ver = 2; } + tda827x_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); + + /* FIXME: tda827x module doesn't probe the tuner until + * tda827x_initial_sleep is called + */ + if (t->fe.ops.tuner_ops.sleep) + t->fe.ops.tuner_ops.sleep(&t->fe); - priv->tda827x_lpsel = 0; + memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); - tda8290_init_tuner(fe); - tda8290_init_if(fe); - return fe; + tuner_info("type set to %s\n", t->i2c.name); + + priv->cfg.tda827x_lpsel = 0; + t->mode = V4L2_TUNER_ANALOG_TV; + + tda8290_init_tuner(t); + tda8290_init_if(t); + return 0; } -int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +int tda8290_probe(struct tuner *t) { struct tuner_i2c_props i2c_props = { - .adap = i2c_adap, - .addr = i2c_addr + .adap = t->i2c.adapter, + .addr = t->i2c.addr }; unsigned char soft_reset[] = { 0x00, 0x00 }; diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 107b24b05aa..9b63e62b3a0 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -18,36 +18,24 @@ #define __TDA8290_H__ #include -#include "dvb_frontend.h" - -struct tda8290_config -{ - unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command,int arg); -}; +#include "tuner-driver.h" #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern int tda8290_probe(struct tuner *t); -extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg); +extern int tda8290_attach(struct tuner *t); #else -static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +static inline int tda8290_probe(struct tuner *t) { - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return -EINVAL; } -static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg) +static inline int tda8290_attach(struct tuner *t) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; } #endif diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 13112732ed2..99558c708ae 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -220,15 +220,6 @@ static void tuner_i2c_address_check(struct tuner *t) tuner_warn("====================== WARNING! ======================\n"); } -static void attach_tda8290(struct tuner *t) -{ - struct tda8290_config cfg = { - .lna_cfg = &t->config, - .tuner_callback = t->tuner_callback - }; - tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); -} - static void attach_simple_tuner(struct tuner *t) { struct simple_tuner_config cfg = { @@ -284,7 +275,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_PHILIPS_TDA8290: { - attach_tda8290(t); + tda8290_attach(t); break; } case TUNER_TEA5767: @@ -343,7 +334,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } - if (fe_tuner_ops->set_analog_params) { + if ((fe_tuner_ops->set_analog_params) && + ((NULL == t->ops.set_tv_freq) && (NULL == t->ops.set_radio_freq))) { strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); t->ops.set_tv_freq = fe_set_freq; @@ -624,7 +616,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { + if (tda8290_probe(t) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ -- cgit v1.2.3 From ce1f8bdb0cbe9c5f57cf0256ef75fce06152547f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 00:28:50 -0300 Subject: V4L/DVB (6434): tda827x: fix GPL export on attach function EXPORT_SYMBOL should have been EXPORT_SYMBOL_GPL Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda827x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 3c71f07a6d2..6de1aea02d5 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -775,7 +775,7 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, return fe; } -EXPORT_SYMBOL(tda827x_attach); +EXPORT_SYMBOL_GPL(tda827x_attach); MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann "); -- cgit v1.2.3 From 5bea1cd3871351d70cc7624af138f8aa68b7be77 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 09:56:38 -0300 Subject: V4L/DVB (6435): tda8290: add support for NXP TDA18271 tuner and TDA8295 analog demod Add basic support for NXP TDA8295 analog demod and TDA18271 tuner silicon. TDA8295 + TDA8275a not yet tested. TDA8290 + TDA18271 not yet supported. Digital mode of TDA18271 not yet tested & needs more work. Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 1 + drivers/media/Kconfig | 3 +- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/tda18271.c | 1054 ++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/tda18271.h | 40 ++ drivers/media/video/tda8290.c | 319 ++++++++- drivers/media/video/tda8290.h | 8 + drivers/media/video/tuner-core.c | 5 + drivers/media/video/tuner-types.c | 3 + drivers/media/video/tveeprom.c | 2 +- include/media/tuner.h | 2 + 12 files changed, 1437 insertions(+), 8 deletions(-) create mode 100644 drivers/media/dvb/frontends/tda18271.c create mode 100644 drivers/media/dvb/frontends/tda18271.h diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 84c3ac7c33d..ac47b48715d 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -73,3 +73,4 @@ tuner=71 - Xceive xc2028/xc3028 tuner tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio +tuner=76 - tda8295+18271 diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index d363d0cae38..e5222938098 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -105,9 +105,10 @@ config TUNER_MT20XX Say Y here to include support for the MT2032 / MT2050 tuner. config TUNER_TDA8290 - tristate "TDA 8290+8275(a) tuner combo" + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" depends on I2C select DVB_TDA827X + select DVB_TDA18271 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for Philips TDA8290+8275(a) tuner. diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 59b9ed1f1ae..57178d6e1cf 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -316,6 +316,13 @@ config DVB_TDA827X help A DVB-T silicon tuner module. Say Y when you want to support this tuner. +config DVB_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + config DVB_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 4b8ad1f132a..457effcda5d 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o +obj-$(CONFIG_DVB_TDA18271) += tda18271.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c new file mode 100644 index 00000000000..3395f2bda49 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.c @@ -0,0 +1,1054 @@ +/* + tda18271.c - driver for the Philips / NXP TDA18271 silicon tuner + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "tda18271.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +#define tuner_dbg(fmt, arg...) do {\ + if (debug > 0) \ + printk(KERN_DEBUG fmt, ##arg); } while (0) + +#define tuner_extra_dbg(fmt, arg...) do {\ + if (debug > 1) \ + printk(KERN_DEBUG fmt, ##arg); } while (0) + +#define R_ID 0x00 /* ID byte */ +#define R_TM 0x01 /* Thermo byte */ +#define R_PL 0x02 /* Power level byte */ +#define R_EP1 0x03 /* Easy Prog byte 1 */ +#define R_EP2 0x04 /* Easy Prog byte 2 */ +#define R_EP3 0x05 /* Easy Prog byte 3 */ +#define R_EP4 0x06 /* Easy Prog byte 4 */ +#define R_EP5 0x07 /* Easy Prog byte 5 */ +#define R_CPD 0x08 /* Cal Post-Divider byte */ +#define R_CD1 0x09 /* Cal Divider byte 1 */ +#define R_CD2 0x0a /* Cal Divider byte 2 */ +#define R_CD3 0x0b /* Cal Divider byte 3 */ +#define R_MPD 0x0c /* Main Post-Divider byte */ +#define R_MD1 0x0d /* Main Divider byte 1 */ +#define R_MD2 0x0e /* Main Divider byte 2 */ +#define R_MD3 0x0f /* Main Divider byte 3 */ +#define R_EB1 0x10 /* Extended byte 1 */ +#define R_EB2 0x11 /* Extended byte 2 */ +#define R_EB3 0x12 /* Extended byte 3 */ +#define R_EB4 0x13 /* Extended byte 4 */ +#define R_EB5 0x14 /* Extended byte 5 */ +#define R_EB6 0x15 /* Extended byte 6 */ +#define R_EB7 0x16 /* Extended byte 7 */ +#define R_EB8 0x17 /* Extended byte 8 */ +#define R_EB9 0x18 /* Extended byte 9 */ +#define R_EB10 0x19 /* Extended byte 10 */ +#define R_EB11 0x1a /* Extended byte 11 */ +#define R_EB12 0x1b /* Extended byte 12 */ +#define R_EB13 0x1c /* Extended byte 13 */ +#define R_EB14 0x1d /* Extended byte 14 */ +#define R_EB15 0x1e /* Extended byte 15 */ +#define R_EB16 0x1f /* Extended byte 16 */ +#define R_EB17 0x20 /* Extended byte 17 */ +#define R_EB18 0x21 /* Extended byte 18 */ +#define R_EB19 0x22 /* Extended byte 19 */ +#define R_EB20 0x23 /* Extended byte 20 */ +#define R_EB21 0x24 /* Extended byte 21 */ +#define R_EB22 0x25 /* Extended byte 22 */ +#define R_EB23 0x26 /* Extended byte 23 */ + +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +static struct tda18271_pll_map tda18271_main_pll[] = { + { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, + { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, + { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, + { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, + { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, + { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, + { .lomax = 54000, .pd = 0x59, .d = 0x90 }, + { .lomax = 61000, .pd = 0x58, .d = 0x80 }, + { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, + { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, + { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, + { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, + { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, + { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, + { .lomax = 109000, .pd = 0x49, .d = 0x48 }, + { .lomax = 123000, .pd = 0x48, .d = 0x40 }, + { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, + { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, + { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, + { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, + { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, + { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, + { .lomax = 219000, .pd = 0x39, .d = 0x24 }, + { .lomax = 246000, .pd = 0x38, .d = 0x20 }, + { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, + { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, + { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, + { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, + { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, + { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, + { .lomax = 438000, .pd = 0x29, .d = 0x12 }, + { .lomax = 493000, .pd = 0x28, .d = 0x10 }, + { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, + { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, + { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, + { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, + { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, + { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, + { .lomax = 877000, .pd = 0x19, .d = 0x09 }, + { .lomax = 987000, .pd = 0x18, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271_cal_pll[] = { + { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, + { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, + { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, + { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, + { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, + { .lomax = 88000, .pd = 0xca, .d = 0x50 }, + { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, + { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, + { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, + { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, + { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, + { .lomax = 176000, .pd = 0xba, .d = 0x28 }, + { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, + { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, + { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, + { .lomax = 271000, .pd = 0xad, .d = 0x1a }, + { .lomax = 294000, .pd = 0xac, .d = 0x18 }, + { .lomax = 321000, .pd = 0xab, .d = 0x16 }, + { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, + { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, + { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, + { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, + { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 785000, .pd = 0x99, .d = 0x09 }, + { .lomax = 883000, .pd = 0x98, .d = 0x08 }, + { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +static struct tda18271_map tda18271_bp_filter[] = { + { .rfmax = 62000, .val = 0x00 }, + { .rfmax = 84000, .val = 0x01 }, + { .rfmax = 100000, .val = 0x02 }, + { .rfmax = 140000, .val = 0x03 }, + { .rfmax = 170000, .val = 0x04 }, + { .rfmax = 180000, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_km[] = { + { .rfmax = 61100, .val = 0x74 }, + { .rfmax = 350000, .val = 0x40 }, + { .rfmax = 720000, .val = 0x30 }, + { .rfmax = 865000, .val = 0x40 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_band[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 61100, .val = 0x01 }, +/* { .rfmax = 152600, .val = 0x02 }, */ + { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 164700, .val = 0x03 }, + { .rfmax = 203500, .val = 0x04 }, + { .rfmax = 457800, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_gain_taper[] = { + { .rfmax = 45400, .val = 0x1f }, + { .rfmax = 45800, .val = 0x1e }, + { .rfmax = 46200, .val = 0x1d }, + { .rfmax = 46700, .val = 0x1c }, + { .rfmax = 47100, .val = 0x1b }, + { .rfmax = 47500, .val = 0x1a }, + { .rfmax = 47900, .val = 0x19 }, + { .rfmax = 49600, .val = 0x17 }, + { .rfmax = 51200, .val = 0x16 }, + { .rfmax = 52900, .val = 0x15 }, + { .rfmax = 54500, .val = 0x14 }, + { .rfmax = 56200, .val = 0x13 }, + { .rfmax = 57800, .val = 0x12 }, + { .rfmax = 59500, .val = 0x11 }, + { .rfmax = 61100, .val = 0x10 }, + { .rfmax = 67600, .val = 0x0d }, + { .rfmax = 74200, .val = 0x0c }, + { .rfmax = 80700, .val = 0x0b }, + { .rfmax = 87200, .val = 0x0a }, + { .rfmax = 93800, .val = 0x09 }, + { .rfmax = 100300, .val = 0x08 }, + { .rfmax = 106900, .val = 0x07 }, + { .rfmax = 113400, .val = 0x06 }, + { .rfmax = 119900, .val = 0x05 }, + { .rfmax = 126500, .val = 0x04 }, + { .rfmax = 133000, .val = 0x03 }, + { .rfmax = 139500, .val = 0x02 }, + { .rfmax = 146100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x00 }, + { .rfmax = 154300, .val = 0x1f }, + { .rfmax = 156100, .val = 0x1e }, + { .rfmax = 157800, .val = 0x1d }, + { .rfmax = 159500, .val = 0x1c }, + { .rfmax = 161200, .val = 0x1b }, + { .rfmax = 163000, .val = 0x1a }, + { .rfmax = 164700, .val = 0x19 }, + { .rfmax = 170200, .val = 0x17 }, + { .rfmax = 175800, .val = 0x16 }, + { .rfmax = 181300, .val = 0x15 }, + { .rfmax = 186900, .val = 0x14 }, + { .rfmax = 192400, .val = 0x13 }, + { .rfmax = 198000, .val = 0x12 }, + { .rfmax = 203500, .val = 0x11 }, + { .rfmax = 216200, .val = 0x14 }, + { .rfmax = 228900, .val = 0x13 }, + { .rfmax = 241600, .val = 0x12 }, + { .rfmax = 254400, .val = 0x11 }, + { .rfmax = 267100, .val = 0x10 }, + { .rfmax = 279800, .val = 0x0f }, + { .rfmax = 292500, .val = 0x0e }, + { .rfmax = 305200, .val = 0x0d }, + { .rfmax = 317900, .val = 0x0c }, + { .rfmax = 330700, .val = 0x0b }, + { .rfmax = 343400, .val = 0x0a }, + { .rfmax = 356100, .val = 0x09 }, + { .rfmax = 368800, .val = 0x08 }, + { .rfmax = 381500, .val = 0x07 }, + { .rfmax = 394200, .val = 0x06 }, + { .rfmax = 406900, .val = 0x05 }, + { .rfmax = 419700, .val = 0x04 }, + { .rfmax = 432400, .val = 0x03 }, + { .rfmax = 445100, .val = 0x02 }, + { .rfmax = 457800, .val = 0x01 }, + { .rfmax = 476300, .val = 0x19 }, + { .rfmax = 494800, .val = 0x18 }, + { .rfmax = 513300, .val = 0x17 }, + { .rfmax = 531800, .val = 0x16 }, + { .rfmax = 550300, .val = 0x15 }, + { .rfmax = 568900, .val = 0x14 }, + { .rfmax = 587400, .val = 0x13 }, + { .rfmax = 605900, .val = 0x12 }, + { .rfmax = 624400, .val = 0x11 }, + { .rfmax = 642900, .val = 0x10 }, + { .rfmax = 661400, .val = 0x0f }, + { .rfmax = 679900, .val = 0x0e }, + { .rfmax = 698400, .val = 0x0d }, + { .rfmax = 716900, .val = 0x0c }, + { .rfmax = 735400, .val = 0x0b }, + { .rfmax = 753900, .val = 0x0a }, + { .rfmax = 772500, .val = 0x09 }, + { .rfmax = 791000, .val = 0x08 }, + { .rfmax = 809500, .val = 0x07 }, + { .rfmax = 828000, .val = 0x06 }, + { .rfmax = 846500, .val = 0x05 }, + { .rfmax = 865000, .val = 0x04 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_cal[] = { + { .rfmax = 41000, .val = 0x1e }, + { .rfmax = 43000, .val = 0x30 }, + { .rfmax = 45000, .val = 0x43 }, + { .rfmax = 46000, .val = 0x4d }, + { .rfmax = 47000, .val = 0x54 }, + { .rfmax = 47900, .val = 0x64 }, + { .rfmax = 49100, .val = 0x20 }, + { .rfmax = 50000, .val = 0x22 }, + { .rfmax = 51000, .val = 0x2a }, + { .rfmax = 53000, .val = 0x32 }, + { .rfmax = 55000, .val = 0x35 }, + { .rfmax = 56000, .val = 0x3c }, + { .rfmax = 57000, .val = 0x3f }, + { .rfmax = 58000, .val = 0x48 }, + { .rfmax = 59000, .val = 0x4d }, + { .rfmax = 60000, .val = 0x58 }, + { .rfmax = 61100, .val = 0x5f }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/*---------------------------------------------------------------------*/ + +#define TDA18271_NUM_REGS 39 + +#define TDA18271_ANALOG 0 +#define TDA18271_DIGITAL 1 + +struct tda18271_priv { + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + int mode; + + u32 frequency; + u32 bandwidth; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tuner_dbg("=== TDA18271 REG DUMP ===\n"); + tuner_dbg("ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); + tuner_dbg("THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); + tuner_dbg("POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); + tuner_dbg("EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); + tuner_dbg("EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); + tuner_dbg("EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); + tuner_dbg("EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); + tuner_dbg("EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); + tuner_dbg("CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); + tuner_dbg("CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); + tuner_dbg("CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); + tuner_dbg("CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); + tuner_dbg("MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); + tuner_dbg("MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); + tuner_dbg("MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); + tuner_dbg("MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); +} + +static void tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 2) + printk("ERROR: %s: i2c_transfer returned: %d\n", + __FUNCTION__, ret); + + if (debug > 1) + tda18271_dump_regs(fe); +} + +static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS+1]; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = len+1 }; + int i, ret; + + BUG_ON((len == 0) || (idx+len > sizeof(buf))); + + buf[0] = idx; + for (i = 1; i <= len; i++) { + buf[i] = regs[idx-1+i]; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* write registers */ + ret = i2c_transfer(priv->i2c_adap, &msg, 1); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 1) + printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", + __FUNCTION__, ret); +} + +/*---------------------------------------------------------------------*/ + +static void tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda18271_read_regs(fe); + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) != 0) + return; + + printk(KERN_INFO "tda18271: initializing registers\n"); + + /* initialize registers */ + regs[R_ID] = 0x83; + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + regs[R_EB1] = 0xff; + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + regs[R_EB12] = 0x0f; + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + regs[R_EB18] = 0x00; + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + regs[R_EB21] = 0x33; + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + /* setup AGC1 & AGC2 */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x87; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); +} + +static int tda18271_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 div, N = 0; + int i; + + + tuner_dbg("%s: freq = %d, ifc = %d\n", __FUNCTION__, freq, ifc); + + tda18271_init_regs(fe); + /* RF tracking filter calibration */ + + /* calculate BP_Filter */ + i = 0; + while ((tda18271_bp_filter[i].rfmax * 1000) < freq) { + if (tda18271_bp_filter[i + 1].rfmax == 0) + break; + i++; + } + tuner_extra_dbg("bp filter = 0x%x, i = %d\n", + tda18271_bp_filter[i].val, i); + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= tda18271_bp_filter[i].val; + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x60; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x60; + tda18271_write_regs(fe, R_EB7, 1); + + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + regs[R_EB20] = 0xcc; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EB4] |= 0x03; + + /* calculate CAL PLL */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 1250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2; + break; + } + + i = 0; + while ((tda18271_cal_pll[i].lomax * 1000) < N) { + if (tda18271_cal_pll[i + 1].lomax == 0) + break; + i++; + } + tuner_extra_dbg("cal pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); + + regs[R_CPD] = tda18271_cal_pll[i].pd; + + div = ((tda18271_cal_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_CD1] = 0xff & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; + + /* calculate MAIN PLL */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2 + 1000000; + break; + } + + i = 0; + while ((tda18271_main_pll[i].lomax * 1000) < N) { + if (tda18271_main_pll[i + 1].lomax == 0) + break; + i++; + } + tuner_extra_dbg("main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + + regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* RF tracking filter calibration initialization */ + + /* search for K,M,CO for RF Calibration */ + i = 0; + while ((tda18271_km[i].rfmax * 1000) < freq) { + if (tda18271_km[i + 1].rfmax == 0) + break; + i++; + } + tuner_extra_dbg("km = 0x%x, i = %d\n", tda18271_km[i].val, i); + + regs[R_EB13] &= 0x83; + regs[R_EB13] |= tda18271_km[i].val; + tda18271_write_regs(fe, R_EB13, 1); + + /* search for RF_BAND */ + i = 0; + while ((tda18271_rf_band[i].rfmax * 1000) < freq) { + if (tda18271_rf_band[i + 1].rfmax == 0) + break; + i++; + } + tuner_extra_dbg("rf band = 0x%x, i = %d\n", + tda18271_rf_band[i].val, i); + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (tda18271_rf_band[i].val << 5); + + /* search for Gain_Taper */ + i = 0; + while ((tda18271_gain_taper[i].rfmax * 1000) < freq) { + if (tda18271_gain_taper[i + 1].rfmax == 0) + break; + i++; + } + tuner_extra_dbg("gain taper = 0x%x, i = %d\n", + tda18271_gain_taper[i].val, i); + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= tda18271_gain_taper[i].val; + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x40; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x40; + tda18271_write_regs(fe, R_EB7, 1); + msleep(10); + + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + msleep(60); /* RF tracking filter calibration completion */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + tda18271_write_regs(fe, R_EP4, 1); + + tda18271_write_regs(fe, R_EP1, 1); + + /* RF tracking filer correction for VHF_Low band */ + i = 0; + while ((tda18271_rf_cal[i].rfmax * 1000) < freq) { + if (tda18271_rf_cal[i].rfmax == 0) + break; + i++; + } + tuner_extra_dbg("rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); + + /* VHF_Low band only */ + if (tda18271_rf_cal[i].rfmax != 0) { + regs[R_EB14] = tda18271_rf_cal[i].val; + tda18271_write_regs(fe, R_EB14, 1); + } + + /* Channel Configuration */ + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_EB22] = 0x2c; + break; + case TDA18271_DIGITAL: + regs[R_EB22] = 0x37; + break; + } + tda18271_write_regs(fe, R_EB22, 1); + + regs[R_EP1] |= 0x40; /* set dis power level on */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + + /* see table 22 */ + regs[R_EP3] |= std; + + /* TO DO: * + * ================ * + * FM radio, 0x18 * + * ATSC 6MHz, 0x1c * + * DVB-T 6MHz, 0x1c * + * DVB-T 7MHz, 0x1d * + * DVB-T 8MHz, 0x1e * + * QAM 6MHz, 0x1d * + * QAM 8MHz, 0x1f */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_EP4] |= 0x04; + regs[R_MPD] |= 0x80; + break; + } + + regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ + + /* FIXME: image rejection validity EP5[2:0] */ + + /* calculate MAIN PLL */ + N = freq + ifc; + + i = 0; + while ((tda18271_main_pll[i].lomax * 1000) < N) { + if (tda18271_main_pll[i + 1].lomax == 0) + break; + i++; + } + tuner_extra_dbg("main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + + regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + tda18271_write_regs(fe, R_TM, 15); + msleep(5); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + u8 std; + u32 bw, sgIF = 0; + + u32 freq = params->frequency; + + priv->mode = TDA18271_DIGITAL; + + /* see table 22 */ + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + std = 0x1b; /* device-specific (spec says 0x1c) */ + sgIF = 5380000; + break; + case QAM_64: + case QAM_256: + std = 0x18; /* device-specific (spec says 0x1d) */ + sgIF = 4000000; + break; + default: + printk(KERN_WARNING "%s: modulation not set!\n", + __FUNCTION__); + return -EINVAL; + } + freq += 1750000; /* Adjust to center (+1.75MHZ) */ + bw = 6000000; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + std = 0x1c; + bw = 6000000; + break; + case BANDWIDTH_7_MHZ: + std = 0x1d; + bw = 7000000; + break; + case BANDWIDTH_8_MHZ: + std = 0x1e; + bw = 8000000; + break; + default: + printk(KERN_WARNING "%s: bandwidth not set!\n", + __FUNCTION__); + return -EINVAL; + } + } else { + printk(KERN_WARNING "%s: modulation type not supported!\n", + __FUNCTION__); + return -EINVAL; + } + + return tda18271_tune(fe, sgIF, freq, bw, std); +} + +static int tda18271_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + u8 std; + unsigned int sgIF; + char *mode; + + priv->mode = TDA18271_ANALOG; + + /* see table 22 */ + if (params->std & V4L2_STD_MN) { + std = 0x0d; + sgIF = 92; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + std = 0x0e; + sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + std = 0x0f; + sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + std = 0x0f; + sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + std = 0x0f; + sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + std = 0x0f; + sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + std = 0x0f; + sgIF = 20; + mode = "LC"; + } else { + std = 0x0f; + sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + sgIF = 88; /* if frequency is 5.5 MHz */ + + tuner_dbg("setting tda18271 to system %s\n", mode); + + return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, + 0, std); +} + +static int tda18271_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static struct dvb_tuner_ops tda18271_tuner_ops = { + .info = { + .name = "NXP TDA18271HD", + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_step = 62500 + }, + .set_params = tda18271_set_params, + .set_analog_params = tda18271_set_analog_params, + .release = tda18271_release, + .get_frequency = tda18271_get_frequency, + .get_bandwidth = tda18271_get_bandwidth, +}; + +struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c) +{ + struct tda18271_priv *priv = NULL; + + tuner_dbg("%s:\n", __FUNCTION__); + priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL_GPL(tda18271_attach); +MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h new file mode 100644 index 00000000000..a8a19a7197f --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.h @@ -0,0 +1,40 @@ +/* + tda18271.h - header for the Philips / NXP TDA18271 silicon tuner + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_H__ +#define __TDA18271_H__ + +#include +#include "dvb_frontend.h" + +#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif + +#endif /* __TDA18271_H__ */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 5d30cbcd736..a38ed9db640 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -25,8 +25,9 @@ #include #include "tda8290.h" #include "tda827x.h" +#include "tda18271.h" -static int tuner_debug = 0; +static int tuner_debug; module_param_named(debug, tuner_debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); @@ -65,6 +66,34 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) } } +static void tda8295_i2c_bridge(struct tuner *t, int close) +{ + struct tda8290_priv *priv = t->priv; + + unsigned char enable[2] = { 0x45, 0xc1 }; + unsigned char disable[2] = { 0x46, 0x00 }; + unsigned char buf[3] = { 0x45, 0x01, 0x00 }; + unsigned char *msg; + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); + + buf[2] = msg[1]; + buf[2] &= ~0x04; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); + msleep(5); + + msg[1] |= 0x04; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + } +} + /*---------------------------------------------------------------------*/ static void set_audio(struct tuner *t) @@ -233,6 +262,153 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) /*---------------------------------------------------------------------*/ +static void tda8295_power(struct tuner *t, int enable) +{ + struct tda8290_priv *priv = t->priv; + unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ + + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + + if (enable) + buf[1] = 0x01; + else + buf[1] = 0x03; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_easy_mode(struct tuner *t, int enable) +{ + struct tda8290_priv *priv = t->priv; + unsigned char buf[] = { 0x01, 0x00 }; + + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + + if (enable) + buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ + else + buf[1] = 0x00; /* reset active bit */ + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_video_std(struct tuner *t) +{ + struct tda8290_priv *priv = t->priv; + unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); + + tda8295_set_easy_mode(t, 1); + msleep(20); + tda8295_set_easy_mode(t, 0); +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_agc1_out(struct tuner *t, int enable) +{ + struct tda8290_priv *priv = t->priv; + unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ + + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + + if (enable) + buf[1] &= ~0x40; + else + buf[1] |= 0x40; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_agc2_out(struct tuner *t, int enable) +{ + struct tda8290_priv *priv = t->priv; + unsigned char set_gpio_cf[] = { 0x44, 0x00 }; + unsigned char set_gpio_val[] = { 0x46, 0x00 }; + + tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); + tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); + + set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ + + if (enable) { + set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ + set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ + } + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); +} + +static int tda8295_has_signal(struct tuner *t) +{ + struct tda8290_priv *priv = t->priv; + + unsigned char hvpll_stat = 0x26; + unsigned char ret; + + tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); + return (ret & 0x01) ? 65535 : 0; +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_set_freq(struct tuner *t, unsigned int freq) +{ + struct tda8290_priv *priv = t->priv; + u16 ifc; + + unsigned char blanking_mode[] = { 0x1d, 0x00 }; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + set_audio(t); + + ifc = priv->cfg.sgIF; /* FIXME */ + + tuner_dbg("%s: ifc = %u, freq = %d\n", __FUNCTION__, ifc, freq); + + tda8295_power(t, 1); + tda8295_agc1_out(t, 1); + + tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); + + tda8295_set_video_std(t); + + blanking_mode[1] = 0x03; + tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); + msleep(20); + + tda8295_i2c_bridge(t, 1); + + if (t->fe.ops.tuner_ops.set_analog_params) + t->fe.ops.tuner_ops.set_analog_params(&t->fe, ¶ms); + + if (priv->cfg.agcf) + priv->cfg.agcf(&t->fe); + + if (tda8295_has_signal(t)) + tuner_dbg("tda8295 is locked\n"); + else + tuner_dbg("tda8295 not locked, no signal?\n"); + + tda8295_i2c_bridge(t, 0); +} + +/*---------------------------------------------------------------------*/ + static int tda8290_has_signal(struct tuner *t) { struct tda8290_priv *priv = t->priv; @@ -264,6 +440,13 @@ static void tda8290_standby(struct tuner *t) tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); } +static void tda8295_standby(struct tuner *t) +{ + tda8295_agc1_out(t, 0); /* Put AGC in tri-state */ + + tda8295_power(t, 0); +} + static void tda8290_init_if(struct tuner *t) { struct tda8290_priv *priv = t->priv; @@ -279,6 +462,35 @@ static void tda8290_init_if(struct tuner *t) tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } +static void tda8295_init_if(struct tuner *t) +{ + struct tda8290_priv *priv = t->priv; + + static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; + static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; + static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; + static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; + static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; + static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; + static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; + + tda8295_power(t, 1); + + tda8295_set_easy_mode(t, 0); + tda8295_set_video_std(t); + + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); + + tda8295_agc1_out(t, 0); + tda8295_agc2_out(t, 0); +} + static void tda8290_init_tuner(struct tuner *t) { struct tda8290_priv *priv = t->priv; @@ -298,7 +510,7 @@ static void tda8290_init_tuner(struct tuner *t) /*---------------------------------------------------------------------*/ -static void tda8290_release(struct tuner *t) +static void tda829x_release(struct tuner *t) { if (t->fe.ops.tuner_ops.release) t->fe.ops.tuner_ops.release(&t->fe); @@ -312,7 +524,15 @@ static struct tuner_operations tda8290_tuner_ops = { .set_radio_freq = tda8290_set_freq, .has_signal = tda8290_has_signal, .standby = tda8290_standby, - .release = tda8290_release, + .release = tda829x_release, +}; + +static struct tuner_operations tda8295_tuner_ops = { + .set_tv_freq = tda8295_set_freq, + .set_radio_freq = tda8295_set_freq, + .has_signal = tda8295_has_signal, + .standby = tda8295_standby, + .release = tda829x_release, }; int tda8290_attach(struct tuner *t) @@ -403,6 +623,95 @@ int tda8290_attach(struct tuner *t) tda8290_init_if(t); return 0; } +EXPORT_SYMBOL_GPL(tda8290_attach); + +int tda8295_attach(struct tuner *t) +{ + struct tda8290_priv *priv = NULL; + u8 data; + int i, ret, tuners_found; + u32 tuner_addrs; + struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; + + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + t->priv = priv; + + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; + + tda8295_i2c_bridge(t, 1); + /* probe for tuner chip */ + tuners_found = 0; + tuner_addrs = 0; + for (i = 0x60; i <= 0x63; i++) { + msg.addr = i; + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret == 1) { + tuners_found++; + tuner_addrs = (tuner_addrs << 8) + i; + } + } + /* if there is more than one tuner, we expect the right one is + behind the bridge and we choose the highest address that doesn't + give a response now + */ + tda8295_i2c_bridge(t, 0); + if (tuners_found > 1) + for (i = 0; i < tuners_found; i++) { + msg.addr = tuner_addrs & 0xff; + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + if (ret == 1) + tuner_addrs = tuner_addrs >> 8; + else + break; + } + if (tuner_addrs == 0) { + tuner_addrs = 0x60; + tuner_info("could not clearly identify tuner address, " + "defaulting to %x\n", tuner_addrs); + } else { + tuner_addrs = tuner_addrs & 0xff; + tuner_info("setting tuner address to %x\n", tuner_addrs); + } + priv->tda827x_addr = tuner_addrs; + msg.addr = tuner_addrs; + + tda8295_i2c_bridge(t, 1); + ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + tda8295_i2c_bridge(t, 0); + if (ret != 1) + tuner_warn("TDA827x access failed!\n"); + if ((data & 0x3c) == 0) { + strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); + tda18271_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap); + priv->tda827x_ver = 4; + } else { + strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); + tda827x_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); + + /* FIXME: tda827x module doesn't probe the tuner until + * tda827x_initial_sleep is called + */ + if (t->fe.ops.tuner_ops.sleep) + t->fe.ops.tuner_ops.sleep(&t->fe); + priv->tda827x_ver = 2; + } + priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */ + tuner_info("type set to %s\n", t->i2c.name); + + memcpy(&t->ops, &tda8295_tuner_ops, sizeof(struct tuner_operations)); + + priv->cfg.tda827x_lpsel = 0; + t->mode = V4L2_TUNER_ANALOG_TV; + + tda8295_init_if(t); + return 0; +} +EXPORT_SYMBOL_GPL(tda8295_attach); int tda8290_probe(struct tuner *t) { @@ -434,12 +743,10 @@ int tda8290_probe(struct tuner *t) tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); return -1; } - EXPORT_SYMBOL_GPL(tda8290_probe); -EXPORT_SYMBOL_GPL(tda8290_attach); MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); -MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); /* diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 9b63e62b3a0..dbbcb0f001e 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -24,6 +24,7 @@ extern int tda8290_probe(struct tuner *t); extern int tda8290_attach(struct tuner *t); +extern int tda8295_attach(struct tuner *t); #else static inline int tda8290_probe(struct tuner *t) { @@ -37,6 +38,13 @@ static inline int tda8290_attach(struct tuner *t) __FUNCTION__); return -EINVAL; } + +static inline int tda8295_attach(struct tuner *t) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return -EINVAL; +} #endif #endif /* __TDA8290_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 99558c708ae..6ae8cb205d8 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -278,6 +278,11 @@ static void set_type(struct i2c_client *c, unsigned int type, tda8290_attach(t); break; } + case TUNER_PHILIPS_TDA8295: + { + tda8295_attach(t); + break; + } case TUNER_TEA5767: if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index ac363f01922..4a674c436cf 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1475,6 +1475,9 @@ struct tunertype tuners[] = { .name = "Philips TEA5761 FM Radio", /* see tea5767.c for details */ }, + [TUNER_PHILIPS_TDA8295] = { /* Philips PAL|NTSC */ + .name = "tda8295+18271", + /* see tda8290.c for details */ }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4b2c4034f5b..27bfe6d3a33 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -257,7 +257,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "LG TAPQ_H702F"}, { TUNER_ABSENT, "TCL M09WPP_4N_E"}, { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_ABSENT, "Philips 18271_8295"}, + { TUNER_PHILIPS_TDA8295, "Philips 18271_8295"}, }; static struct HAUPPAUGE_AUDIOIC diff --git a/include/media/tuner.h b/include/media/tuner.h index d49392d90e5..faacd2d50b7 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -124,6 +124,8 @@ extern int tuner_debug; #define TUNER_TDA9887 74 /* This tuner should be used only internally */ #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ +#define TUNER_PHILIPS_TDA8295 76 + /* tv card specific */ #define TDA9887_PRESENT (1<<0) #define TDA9887_PORT1_INACTIVE (1<<1) -- cgit v1.2.3 From 1dde7a4fa2b197d298c3f1b97a7f78fd1c3a1bda Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 21 Oct 2007 13:40:56 -0300 Subject: V4L/DVB (6436): tuner: move analog_tuner_ops into dvb_frontend_ops Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 3 + drivers/media/video/tda8290.c | 8 +-- drivers/media/video/tda9887.c | 4 +- drivers/media/video/tuner-core.c | 91 ++++++++++++++++++------------- drivers/media/video/tuner-driver.h | 4 +- 5 files changed, 63 insertions(+), 47 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index c49fa049717..0dd0c672897 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -62,6 +62,8 @@ struct dvb_tuner_info { u32 bandwidth_step; }; +struct analog_tuner_ops; + struct analog_parameters { unsigned int frequency; unsigned int mode; @@ -146,6 +148,7 @@ struct dvb_frontend_ops { int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); struct dvb_tuner_ops tuner_ops; + struct analog_tuner_ops *analog_demod_ops; }; #define MAX_EVENT 8 diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a38ed9db640..da5e5a8169f 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -519,7 +519,7 @@ static void tda829x_release(struct tuner *t) t->priv = NULL; } -static struct tuner_operations tda8290_tuner_ops = { +static struct analog_tuner_ops tda8290_tuner_ops = { .set_tv_freq = tda8290_set_freq, .set_radio_freq = tda8290_set_freq, .has_signal = tda8290_has_signal, @@ -527,7 +527,7 @@ static struct tuner_operations tda8290_tuner_ops = { .release = tda829x_release, }; -static struct tuner_operations tda8295_tuner_ops = { +static struct analog_tuner_ops tda8295_tuner_ops = { .set_tv_freq = tda8295_set_freq, .set_radio_freq = tda8295_set_freq, .has_signal = tda8295_has_signal, @@ -612,7 +612,7 @@ int tda8290_attach(struct tuner *t) if (t->fe.ops.tuner_ops.sleep) t->fe.ops.tuner_ops.sleep(&t->fe); - memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations)); + t->fe.ops.analog_demod_ops = &tda8290_tuner_ops; tuner_info("type set to %s\n", t->i2c.name); @@ -703,7 +703,7 @@ int tda8295_attach(struct tuner *t) priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */ tuner_info("type set to %s\n", t->i2c.name); - memcpy(&t->ops, &tda8295_tuner_ops, sizeof(struct tuner_operations)); + t->fe.ops.analog_demod_ops = &tda8295_tuner_ops; priv->cfg.tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index be5387f11af..d9bfa812ffe 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -610,7 +610,7 @@ static void tda9887_release(struct tuner *t) t->priv = NULL; } -static struct tuner_operations tda9887_tuner_ops = { +static struct analog_tuner_ops tda9887_tuner_ops = { .set_tv_freq = tda9887_set_freq, .set_radio_freq = tda9887_set_freq, .standby = tda9887_standby, @@ -636,7 +636,7 @@ int tda9887_tuner_init(struct tuner *t) tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, t->i2c.driver->driver.name); - memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations)); + t->fe.ops.analog_demod_ops = &tda9887_tuner_ops; return 0; } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6ae8cb205d8..f31de98bbfa 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -122,16 +122,28 @@ static int fe_has_signal(struct tuner *t) return strength; } +static void tuner_status(struct tuner *t); + +static struct analog_tuner_ops tuner_core_ops = { + .set_tv_freq = fe_set_freq, + .set_radio_freq = fe_set_freq, + .standby = fe_standby, + .release = fe_release, + .has_signal = fe_has_signal, + .tuner_status = tuner_status +}; + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->ops.set_tv_freq) { + if ((NULL == ops) || (NULL == ops->set_tv_freq)) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -146,18 +158,19 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(t, freq); + ops->set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->ops.set_radio_freq) { + if ((NULL == ops) || (NULL == ops->set_radio_freq)) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -173,7 +186,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - t->ops.set_radio_freq(t, freq); + ops->set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -235,6 +248,7 @@ static void set_type(struct i2c_client *c, unsigned int type, { struct tuner *t = i2c_get_clientdata(c); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -262,8 +276,8 @@ static void set_type(struct i2c_client *c, unsigned int type, } /* discard private data, in case set_type() was previously called */ - if (t->ops.release) - t->ops.release(t); + if ((ops) && (ops->release)) + ops->release(t); else { kfree(t->priv); t->priv = NULL; @@ -339,15 +353,12 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } - if ((fe_tuner_ops->set_analog_params) && - ((NULL == t->ops.set_tv_freq) && (NULL == t->ops.set_radio_freq))) { + if (((NULL == ops) || + ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) && + (fe_tuner_ops->set_analog_params)) { strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); - t->ops.set_tv_freq = fe_set_freq; - t->ops.set_radio_freq = fe_set_freq; - t->ops.standby = fe_standby; - t->ops.release = fe_release; - t->ops.has_signal = fe_has_signal; + t->fe.ops.analog_demod_ops = &tuner_core_ops; } tuner_info("type set to %s\n", t->i2c.name); @@ -524,6 +535,7 @@ static void tuner_status(struct tuner *t) { unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; const char *p; switch (t->mode) { @@ -553,11 +565,11 @@ static void tuner_status(struct tuner *t) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); + if ((ops) && (ops->has_signal)) { + tuner_info("Signal strength: %d\n", ops->has_signal(t)); } - if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); + if ((ops) && (ops->is_stereo)) { + tuner_info("Stereo: %s\n", ops->is_stereo(t) ? "yes" : "no"); } } @@ -584,7 +596,6 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) t->type = UNSET; t->audmode = V4L2_TUNER_MODE_STEREO; t->mode_mask = T_UNINITIALIZED; - t->ops.tuner_status = tuner_status; if (show_i2c) { unsigned char buffer[16]; @@ -701,6 +712,7 @@ static int tuner_probe(struct i2c_adapter *adap) static int tuner_detach(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; int err; err = i2c_detach_client(&t->i2c); @@ -710,8 +722,8 @@ static int tuner_detach(struct i2c_client *client) return err; } - if (t->ops.release) - t->ops.release(t); + if ((ops) && (ops->release)) + ops->release(t); else { kfree(t->priv); } @@ -728,6 +740,8 @@ static int tuner_detach(struct i2c_client *client) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + if (mode == t->mode) return 0; @@ -735,8 +749,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (t->ops.standby) - t->ops.standby(t); + if ((ops) && (ops->standby)) + ops->standby(t); return EINVAL; } return 0; @@ -759,6 +773,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); @@ -785,8 +800,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if (t->ops.standby) - t->ops.standby(t); + if ((ops) && (ops->standby)) + ops->standby(t); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -854,8 +869,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { - if (t->ops.is_stereo) { - if (t->ops.is_stereo(t)) + if ((ops) && (ops->is_stereo)) { + if (ops->is_stereo(t)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -863,8 +878,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ~VIDEO_TUNER_STEREO_ON; } } - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); + if ((ops) && (ops->has_signal)) + vt->signal = ops->has_signal(t); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -894,8 +909,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - } else if (t->ops.is_stereo) - va->mode = t->ops.is_stereo(t) + } else if ((ops) && (ops->is_stereo)) + va->mode = ops->is_stereo(t) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } return 0; @@ -985,8 +1000,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(t); + if ((ops) && (ops->get_afc)) + tuner->afc = ops->get_afc(t); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -1005,13 +1020,13 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } else { - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(t) ? + if ((ops) && (ops->is_stereo)) { + tuner->rxsubchans = ops->is_stereo(t) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } } - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); + if ((ops) && (ops->has_signal)) + tuner->signal = ops->has_signal(t); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -1036,8 +1051,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if (t->ops.tuner_status) - t->ops.tuner_status(t); + if ((ops) && (ops->tuner_status)) + ops->tuner_status(t); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 28a10da76d1..f2a9c29f1f0 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -31,7 +31,7 @@ extern unsigned const int tuner_count; struct tuner; -struct tuner_operations { +struct analog_tuner_ops { void (*set_tv_freq)(struct tuner *t, unsigned int freq); void (*set_radio_freq)(struct tuner *t, unsigned int freq); int (*has_signal)(struct tuner *t); @@ -66,8 +66,6 @@ struct tuner { unsigned int config; int (*tuner_callback) (void *dev, int command,int arg); - - struct tuner_operations ops; }; /* ------------------------------------------------------------------------ */ -- cgit v1.2.3 From e2be32ac8017d1bcb293f8c11c046ff654991385 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 21 Oct 2007 14:35:21 -0300 Subject: V4L/DVB (6437): tuner: clear analog_demod_ops on release Clear analog_demod_ops on release. Fix test for analog_demod_ops after tuner attach. Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f31de98bbfa..9de66769b62 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -101,6 +101,8 @@ static void fe_release(struct tuner *t) if (fe_tuner_ops->release) fe_tuner_ops->release(&t->fe); + + t->fe.ops.analog_demod_ops = NULL; } static void fe_standby(struct tuner *t) @@ -353,6 +355,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } + ops = t->fe.ops.analog_demod_ops; + if (((NULL == ops) || ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) && (fe_tuner_ops->set_analog_params)) { -- cgit v1.2.3 From 16f291684c50497cc92e83f01d354fae187d1f18 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 21 Oct 2007 15:22:25 -0300 Subject: V4L/DVB (6438): tuner: move analog_demod_priv into struct dvb_frontend Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 1 + drivers/media/video/tda8290.c | 40 +++++++++++++++---------------- drivers/media/video/tda9887.c | 14 +++++------ drivers/media/video/tuner-core.c | 8 +------ drivers/media/video/tuner-driver.h | 1 - 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 0dd0c672897..f93c5db3666 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -169,6 +169,7 @@ struct dvb_frontend { void* tuner_priv; void* frontend_priv; void* sec_priv; + void* analog_demod_priv; }; extern int dvb_register_frontend(struct dvb_adapter* dvb, diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index da5e5a8169f..e001c397ccf 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -50,7 +50,7 @@ struct tda8290_priv { static void tda8290_i2c_bridge(struct tuner *t, int close) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; @@ -68,7 +68,7 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) static void tda8295_i2c_bridge(struct tuner *t, int close) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char enable[2] = { 0x45, 0xc1 }; unsigned char disable[2] = { 0x46, 0x00 }; @@ -98,7 +98,7 @@ static void tda8295_i2c_bridge(struct tuner *t, int close) static void set_audio(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; char* mode; priv->cfg.tda827x_lpsel = 0; @@ -145,7 +145,7 @@ static void set_audio(struct tuner *t) static void tda8290_set_freq(struct tuner *t, unsigned int freq) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -264,7 +264,7 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) static void tda8295_power(struct tuner *t, int enable) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); @@ -280,7 +280,7 @@ static void tda8295_power(struct tuner *t, int enable) static void tda8295_set_easy_mode(struct tuner *t, int enable) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char buf[] = { 0x01, 0x00 }; tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); @@ -296,7 +296,7 @@ static void tda8295_set_easy_mode(struct tuner *t, int enable) static void tda8295_set_video_std(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); @@ -310,7 +310,7 @@ static void tda8295_set_video_std(struct tuner *t) static void tda8295_agc1_out(struct tuner *t, int enable) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); @@ -326,7 +326,7 @@ static void tda8295_agc1_out(struct tuner *t, int enable) static void tda8295_agc2_out(struct tuner *t, int enable) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char set_gpio_cf[] = { 0x44, 0x00 }; unsigned char set_gpio_val[] = { 0x46, 0x00 }; @@ -347,7 +347,7 @@ static void tda8295_agc2_out(struct tuner *t, int enable) static int tda8295_has_signal(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char hvpll_stat = 0x26; unsigned char ret; @@ -361,7 +361,7 @@ static int tda8295_has_signal(struct tuner *t) static void tda8295_set_freq(struct tuner *t, unsigned int freq) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; u16 ifc; unsigned char blanking_mode[] = { 0x1d, 0x00 }; @@ -411,7 +411,7 @@ static void tda8295_set_freq(struct tuner *t, unsigned int freq) static int tda8290_has_signal(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; @@ -425,7 +425,7 @@ static int tda8290_has_signal(struct tuner *t) static void tda8290_standby(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; @@ -449,7 +449,7 @@ static void tda8295_standby(struct tuner *t) static void tda8290_init_if(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; @@ -464,7 +464,7 @@ static void tda8290_init_if(struct tuner *t) static void tda8295_init_if(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; @@ -493,7 +493,7 @@ static void tda8295_init_if(struct tuner *t) static void tda8290_init_tuner(struct tuner *t) { - struct tda8290_priv *priv = t->priv; + struct tda8290_priv *priv = t->fe.analog_demod_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, @@ -515,8 +515,8 @@ static void tda829x_release(struct tuner *t) if (t->fe.ops.tuner_ops.release) t->fe.ops.tuner_ops.release(&t->fe); - kfree(t->priv); - t->priv = NULL; + kfree(t->fe.analog_demod_priv); + t->fe.analog_demod_priv = NULL; } static struct analog_tuner_ops tda8290_tuner_ops = { @@ -546,7 +546,7 @@ int tda8290_attach(struct tuner *t) priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - t->priv = priv; + t->fe.analog_demod_priv = priv; priv->i2c_props.addr = t->i2c.addr; priv->i2c_props.adap = t->i2c.adapter; @@ -636,7 +636,7 @@ int tda8295_attach(struct tuner *t) priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - t->priv = priv; + t->fe.analog_demod_priv = priv; priv->i2c_props.addr = t->i2c.addr; priv->i2c_props.adap = t->i2c.adapter; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d9bfa812ffe..68b22da7e25 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -512,7 +512,7 @@ static int tda9887_set_config(struct tuner *t, char *buf) static int tda9887_status(struct tuner *t) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = t->fe.analog_demod_priv; unsigned char buf[1]; int rc; @@ -525,7 +525,7 @@ static int tda9887_status(struct tuner *t) static void tda9887_configure(struct tuner *t) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = t->fe.analog_demod_priv; int rc; memset(priv->data,0,sizeof(priv->data)); @@ -572,13 +572,13 @@ static void tda9887_configure(struct tuner *t) static void tda9887_tuner_status(struct tuner *t) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = t->fe.analog_demod_priv; tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } static int tda9887_get_afc(struct tuner *t) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = t->fe.analog_demod_priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -606,8 +606,8 @@ static void tda9887_set_freq(struct tuner *t, unsigned int freq) static void tda9887_release(struct tuner *t) { - kfree(t->priv); - t->priv = NULL; + kfree(t->fe.analog_demod_priv); + t->fe.analog_demod_priv = NULL; } static struct analog_tuner_ops tda9887_tuner_ops = { @@ -626,7 +626,7 @@ int tda9887_tuner_init(struct tuner *t) priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - t->priv = priv; + t->fe.analog_demod_priv = priv; priv->i2c_props.addr = t->i2c.addr; priv->i2c_props.adap = t->i2c.adapter; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9de66769b62..9903b3f2530 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -280,10 +280,6 @@ static void set_type(struct i2c_client *c, unsigned int type, /* discard private data, in case set_type() was previously called */ if ((ops) && (ops->release)) ops->release(t); - else { - kfree(t->priv); - t->priv = NULL; - } switch (t->type) { case TUNER_MT2032: @@ -728,9 +724,7 @@ static int tuner_detach(struct i2c_client *client) if ((ops) && (ops->release)) ops->release(t); - else { - kfree(t->priv); - } + kfree(t); return 0; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index f2a9c29f1f0..fffacb378fd 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -57,7 +57,6 @@ struct tuner { v4l2_std_id std; int using_v4l2; - void *priv; struct dvb_frontend fe; -- cgit v1.2.3 From 482b498d7a1eb0e445657fb55d2bc6d4871c0ef5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 00:12:16 -0300 Subject: V4L/DVB (6439): dvb_frontend: codingstyle cleanups thanks to checkpatch.pl Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f93c5db3666..50dc5568efa 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -165,19 +165,19 @@ struct dvb_fe_events { struct dvb_frontend { struct dvb_frontend_ops ops; struct dvb_adapter *dvb; - void* demodulator_priv; - void* tuner_priv; - void* frontend_priv; - void* sec_priv; - void* analog_demod_priv; + void *demodulator_priv; + void *tuner_priv; + void *frontend_priv; + void *sec_priv; + void *analog_demod_priv; }; -extern int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe); +extern int dvb_register_frontend(struct dvb_adapter *dvb, + struct dvb_frontend *fe); -extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern int dvb_unregister_frontend(struct dvb_frontend *fe); -extern void dvb_frontend_detach(struct dvb_frontend* fe); +extern void dvb_frontend_detach(struct dvb_frontend *fe); extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); -- cgit v1.2.3 From 4e9154b8a77d0f0f8f06857162823905612a50d7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 21 Oct 2007 19:39:50 -0300 Subject: V4L/DVB (6440): tuner: convert analog tuner demod sub-modules to dvb_frontend interface Convert tda9887 and tda8290/5 to dvb_frontend interface Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 164 ++++++++++++++++++++----------------- drivers/media/video/tda9887.c | 78 +++++++++++------- drivers/media/video/tuner-core.c | 79 ++++++++++-------- drivers/media/video/tuner-driver.h | 16 ++-- 4 files changed, 186 insertions(+), 151 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index e001c397ccf..288865c3c71 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -44,13 +44,15 @@ struct tda8290_priv { unsigned char tda827x_ver; struct tda827x_config cfg; + + struct tuner *t; }; /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct tuner *t, int close) +static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; @@ -66,9 +68,9 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) } } -static void tda8295_i2c_bridge(struct tuner *t, int close) +static void tda8295_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char enable[2] = { 0x45, 0xc1 }; unsigned char disable[2] = { 0x46, 0x00 }; @@ -96,9 +98,10 @@ static void tda8295_i2c_bridge(struct tuner *t, int close) /*---------------------------------------------------------------------*/ -static void set_audio(struct tuner *t) +static void set_audio(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; char* mode; priv->cfg.tda827x_lpsel = 0; @@ -143,9 +146,11 @@ static void set_audio(struct tuner *t) tuner_dbg("setting tda8290 to system %s\n", mode); } -static void tda8290_set_freq(struct tuner *t, unsigned int freq) +static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; + unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -175,7 +180,7 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) .std = t->std }; - set_audio(t); + set_audio(fe); tuner_dbg("tda827xa config is 0x%02x\n", t->config); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); @@ -193,10 +198,10 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); - if (t->fe.ops.tuner_ops.set_analog_params) - t->fe.ops.tuner_ops.set_analog_params(&t->fe, ¶ms); + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); @@ -227,7 +232,7 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); if (priv->cfg.agcf) - priv->cfg.agcf(&t->fe); + priv->cfg.agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -256,15 +261,15 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) } } - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); } /*---------------------------------------------------------------------*/ -static void tda8295_power(struct tuner *t, int enable) +static void tda8295_power(struct dvb_frontend *fe, int enable) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); @@ -278,9 +283,9 @@ static void tda8295_power(struct tuner *t, int enable) tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); } -static void tda8295_set_easy_mode(struct tuner *t, int enable) +static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x01, 0x00 }; tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); @@ -294,23 +299,23 @@ static void tda8295_set_easy_mode(struct tuner *t, int enable) tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); } -static void tda8295_set_video_std(struct tuner *t) +static void tda8295_set_video_std(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); - tda8295_set_easy_mode(t, 1); + tda8295_set_easy_mode(fe, 1); msleep(20); - tda8295_set_easy_mode(t, 0); + tda8295_set_easy_mode(fe, 0); } /*---------------------------------------------------------------------*/ -static void tda8295_agc1_out(struct tuner *t, int enable) +static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); @@ -324,9 +329,9 @@ static void tda8295_agc1_out(struct tuner *t, int enable) tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); } -static void tda8295_agc2_out(struct tuner *t, int enable) +static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char set_gpio_cf[] = { 0x44, 0x00 }; unsigned char set_gpio_val[] = { 0x46, 0x00 }; @@ -345,9 +350,9 @@ static void tda8295_agc2_out(struct tuner *t, int enable) tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); } -static int tda8295_has_signal(struct tuner *t) +static int tda8295_has_signal(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char hvpll_stat = 0x26; unsigned char ret; @@ -359,9 +364,10 @@ static int tda8295_has_signal(struct tuner *t) /*---------------------------------------------------------------------*/ -static void tda8295_set_freq(struct tuner *t, unsigned int freq) +static void tda8295_set_freq(struct dvb_frontend *fe, unsigned int freq) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; u16 ifc; unsigned char blanking_mode[] = { 0x1d, 0x00 }; @@ -373,45 +379,45 @@ static void tda8295_set_freq(struct tuner *t, unsigned int freq) .std = t->std }; - set_audio(t); + set_audio(fe); ifc = priv->cfg.sgIF; /* FIXME */ tuner_dbg("%s: ifc = %u, freq = %d\n", __FUNCTION__, ifc, freq); - tda8295_power(t, 1); - tda8295_agc1_out(t, 1); + tda8295_power(fe, 1); + tda8295_agc1_out(fe, 1); tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); - tda8295_set_video_std(t); + tda8295_set_video_std(fe); blanking_mode[1] = 0x03; tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); msleep(20); - tda8295_i2c_bridge(t, 1); + tda8295_i2c_bridge(fe, 1); - if (t->fe.ops.tuner_ops.set_analog_params) - t->fe.ops.tuner_ops.set_analog_params(&t->fe, ¶ms); + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); if (priv->cfg.agcf) - priv->cfg.agcf(&t->fe); + priv->cfg.agcf(fe); - if (tda8295_has_signal(t)) + if (tda8295_has_signal(fe)) tuner_dbg("tda8295 is locked\n"); else tuner_dbg("tda8295 not locked, no signal?\n"); - tda8295_i2c_bridge(t, 0); + tda8295_i2c_bridge(fe, 0); } /*---------------------------------------------------------------------*/ -static int tda8290_has_signal(struct tuner *t) +static int tda8290_has_signal(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char i2c_get_afc[1] = { 0x1B }; unsigned char afc = 0; @@ -423,33 +429,35 @@ static int tda8290_has_signal(struct tuner *t) /*---------------------------------------------------------------------*/ -static void tda8290_standby(struct tuner *t) +static void tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); } -static void tda8295_standby(struct tuner *t) +static void tda8295_standby(struct dvb_frontend *fe) { - tda8295_agc1_out(t, 0); /* Put AGC in tri-state */ + tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ - tda8295_power(t, 0); + tda8295_power(fe, 0); } -static void tda8290_init_if(struct tuner *t) +static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; @@ -462,9 +470,9 @@ static void tda8290_init_if(struct tuner *t) tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8295_init_if(struct tuner *t) +static void tda8295_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; @@ -474,10 +482,10 @@ static void tda8295_init_if(struct tuner *t) static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; - tda8295_power(t, 1); + tda8295_power(fe, 1); - tda8295_set_easy_mode(t, 0); - tda8295_set_video_std(t); + tda8295_set_easy_mode(fe, 0); + tda8295_set_video_std(fe); tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); @@ -487,13 +495,13 @@ static void tda8295_init_if(struct tuner *t) tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); - tda8295_agc1_out(t, 0); - tda8295_agc2_out(t, 0); + tda8295_agc1_out(fe, 0); + tda8295_agc2_out(fe, 0); } -static void tda8290_init_tuner(struct tuner *t) +static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = t->fe.analog_demod_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, @@ -503,20 +511,20 @@ static void tda8290_init_tuner(struct tuner *t) if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(fe, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(fe, 0); } /*---------------------------------------------------------------------*/ -static void tda829x_release(struct tuner *t) +static void tda829x_release(struct dvb_frontend *fe) { - if (t->fe.ops.tuner_ops.release) - t->fe.ops.tuner_ops.release(&t->fe); + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); - kfree(t->fe.analog_demod_priv); - t->fe.analog_demod_priv = NULL; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } static struct analog_tuner_ops tda8290_tuner_ops = { @@ -552,8 +560,9 @@ int tda8290_attach(struct tuner *t) priv->i2c_props.adap = t->i2c.adapter; priv->cfg.config = &t->config; priv->cfg.tuner_callback = t->tuner_callback; + priv->t = t; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(&t->fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; @@ -569,7 +578,7 @@ int tda8290_attach(struct tuner *t) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(t, 0); + tda8290_i2c_bridge(&t->fe, 0); if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; @@ -590,7 +599,7 @@ int tda8290_attach(struct tuner *t) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(t, 1); + tda8290_i2c_bridge(&t->fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if( ret != 1) @@ -619,8 +628,8 @@ int tda8290_attach(struct tuner *t) priv->cfg.tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; - tda8290_init_tuner(t); - tda8290_init_if(t); + tda8290_init_tuner(&t->fe); + tda8290_init_if(&t->fe); return 0; } EXPORT_SYMBOL_GPL(tda8290_attach); @@ -640,8 +649,9 @@ int tda8295_attach(struct tuner *t) priv->i2c_props.addr = t->i2c.addr; priv->i2c_props.adap = t->i2c.adapter; + priv->t = t; - tda8295_i2c_bridge(t, 1); + tda8295_i2c_bridge(&t->fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; @@ -657,7 +667,7 @@ int tda8295_attach(struct tuner *t) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8295_i2c_bridge(t, 0); + tda8295_i2c_bridge(&t->fe, 0); if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; @@ -678,9 +688,9 @@ int tda8295_attach(struct tuner *t) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8295_i2c_bridge(t, 1); + tda8295_i2c_bridge(&t->fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8295_i2c_bridge(t, 0); + tda8295_i2c_bridge(&t->fe, 0); if (ret != 1) tuner_warn("TDA827x access failed!\n"); if ((data & 0x3c) == 0) { @@ -708,7 +718,7 @@ int tda8295_attach(struct tuner *t) priv->cfg.tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; - tda8295_init_if(t); + tda8295_init_if(&t->fe); return 0; } EXPORT_SYMBOL_GPL(tda8295_attach); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 68b22da7e25..7663a557975 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -21,17 +21,19 @@ */ #define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \ + i2c_adapter_id(priv->t->i2c.adapter), priv->t->i2c.addr , ##arg); } while (0) #define tda9887_dbg(fmt, arg...) do {\ if (tuner_debug) \ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \ + i2c_adapter_id(priv->t->i2c.adapter), priv->t->i2c.addr , ##arg); } while (0) struct tda9887_priv { struct tuner_i2c_props i2c_props; unsigned char data[4]; + + struct tuner *t; }; /* ---------------------------------------------------------------------- */ @@ -262,8 +264,10 @@ static struct tvnorm radio_mono = { /* ---------------------------------------------------------------------- */ -static void dump_read_message(struct tuner *t, unsigned char *buf) +static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *afc[16] = { "- 12.5 kHz", "- 37.5 kHz", @@ -290,8 +294,10 @@ static void dump_read_message(struct tuner *t, unsigned char *buf) tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); } -static void dump_write_message(struct tuner *t, unsigned char *buf) +static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *sound[4] = { "AM/TV", "FM/radio", @@ -386,9 +392,12 @@ static void dump_write_message(struct tuner *t, unsigned char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_set_tvnorm(struct tuner *t, char *buf) +static int tda9887_set_tvnorm(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; struct tvnorm *norm = NULL; + char *buf = priv->data; int i; if (t->mode == V4L2_TUNER_RADIO) { @@ -426,8 +435,11 @@ module_param(port2, int, 0644); module_param(qss, int, 0644); module_param(adjust, int, 0644); -static int tda9887_set_insmod(struct tuner *t, char *buf) +static int tda9887_set_insmod(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + if (UNSET != port1) { if (port1) buf[1] |= cOutputPort1Inactive; @@ -455,8 +467,12 @@ static int tda9887_set_insmod(struct tuner *t, char *buf) return 0; } -static int tda9887_set_config(struct tuner *t, char *buf) +static int tda9887_set_config(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; + char *buf = priv->data; + if (t->tda9887_config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; if (t->tda9887_config & TDA9887_PORT1_INACTIVE) @@ -510,26 +526,27 @@ static int tda9887_set_config(struct tuner *t, char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_status(struct tuner *t) +static int tda9887_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->fe.analog_demod_priv; + struct tda9887_priv *priv = fe->analog_demod_priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); - dump_read_message(t, buf); + dump_read_message(fe, buf); return 0; } -static void tda9887_configure(struct tuner *t) +static void tda9887_configure(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->fe.analog_demod_priv; + struct tda9887_priv *priv = fe->analog_demod_priv; + struct tuner *t = priv->t; int rc; memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(t,priv->data); + tda9887_set_tvnorm(fe); /* A note on the port settings: These settings tend to depend on the specifics of the board. @@ -547,8 +564,8 @@ static void tda9887_configure(struct tuner *t) priv->data[1] |= cOutputPort1Inactive; priv->data[1] |= cOutputPort2Inactive; - tda9887_set_config(t,priv->data); - tda9887_set_insmod(t,priv->data); + tda9887_set_config(fe); + tda9887_set_insmod(fe); if (t->mode == T_STANDBY) { priv->data[1] |= cForcedMuteAudioON; @@ -557,28 +574,28 @@ static void tda9887_configure(struct tuner *t) tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1],priv->data[2],priv->data[3]); if (tuner_debug > 1) - dump_write_message(t, priv->data); + dump_write_message(fe, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); if (tuner_debug > 2) { msleep_interruptible(1000); - tda9887_status(t); + tda9887_status(fe); } } /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct tuner *t) +static void tda9887_tuner_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->fe.analog_demod_priv; + struct tda9887_priv *priv = fe->analog_demod_priv; tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct tuner *t) +static int tda9887_get_afc(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->fe.analog_demod_priv; + struct tda9887_priv *priv = fe->analog_demod_priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -594,20 +611,20 @@ static int tda9887_get_afc(struct tuner *t) return afc; } -static void tda9887_standby(struct tuner *t) +static void tda9887_standby(struct dvb_frontend *fe) { - tda9887_configure(t); + tda9887_configure(fe); } -static void tda9887_set_freq(struct tuner *t, unsigned int freq) +static void tda9887_set_freq(struct dvb_frontend *fe, unsigned int freq) { - tda9887_configure(t); + tda9887_configure(fe); } -static void tda9887_release(struct tuner *t) +static void tda9887_release(struct dvb_frontend *fe) { - kfree(t->fe.analog_demod_priv); - t->fe.analog_demod_priv = NULL; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } static struct analog_tuner_ops tda9887_tuner_ops = { @@ -630,6 +647,7 @@ int tda9887_tuner_init(struct tuner *t) priv->i2c_props.addr = t->i2c.addr; priv->i2c_props.adap = t->i2c.adapter; + priv->t = t; strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9903b3f2530..805a2bd29e7 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -77,9 +77,10 @@ static struct i2c_client client_template; /* ---------------------------------------------------------------------- */ -static void fe_set_freq(struct tuner *t, unsigned int freq) +static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct tuner *t = fe->analog_demod_priv; struct analog_parameters params = { .frequency = freq, @@ -92,39 +93,38 @@ static void fe_set_freq(struct tuner *t, unsigned int freq) tuner_warn("Tuner frontend module has no way to set freq\n"); return; } - fe_tuner_ops->set_analog_params(&t->fe, ¶ms); + fe_tuner_ops->set_analog_params(fe, ¶ms); } -static void fe_release(struct tuner *t) +static void fe_release(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - - if (fe_tuner_ops->release) - fe_tuner_ops->release(&t->fe); + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); - t->fe.ops.analog_demod_ops = NULL; + fe->ops.analog_demod_ops = NULL; + /* DO NOT kfree(t->fe.analog_demod_priv) */ + fe->analog_demod_priv = NULL; } -static void fe_standby(struct tuner *t) +static void fe_standby(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; if (fe_tuner_ops->sleep) - fe_tuner_ops->sleep(&t->fe); + fe_tuner_ops->sleep(fe); } -static int fe_has_signal(struct tuner *t) +static int fe_has_signal(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; u16 strength = 0; - if (fe_tuner_ops->get_rf_strength) - fe_tuner_ops->get_rf_strength(&t->fe, &strength); + if (fe->ops.tuner_ops.get_rf_strength) + fe->ops.tuner_ops.get_rf_strength(fe, &strength); return strength; } -static void tuner_status(struct tuner *t); +static void tuner_status(struct dvb_frontend *fe); static struct analog_tuner_ops tuner_core_ops = { .set_tv_freq = fe_set_freq, @@ -160,7 +160,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - ops->set_tv_freq(t, freq); + ops->set_tv_freq(&t->fe, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -188,7 +188,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } - ops->set_radio_freq(t, freq); + ops->set_radio_freq(&t->fe, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -279,7 +279,7 @@ static void set_type(struct i2c_client *c, unsigned int type, /* discard private data, in case set_type() was previously called */ if ((ops) && (ops->release)) - ops->release(t); + ops->release(&t->fe); switch (t->type) { case TUNER_MT2032: @@ -359,6 +359,7 @@ static void set_type(struct i2c_client *c, unsigned int type, strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); t->fe.ops.analog_demod_ops = &tuner_core_ops; + t->fe.analog_demod_priv = t; } tuner_info("type set to %s\n", t->i2c.name); @@ -531,8 +532,9 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct tuner *t) +static void tuner_status(struct dvb_frontend *fe) { + struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; @@ -566,10 +568,11 @@ static void tuner_status(struct tuner *t) tuner_info("Stereo: yes\n"); } if ((ops) && (ops->has_signal)) { - tuner_info("Signal strength: %d\n", ops->has_signal(t)); + tuner_info("Signal strength: %d\n", ops->has_signal(fe)); } if ((ops) && (ops->is_stereo)) { - tuner_info("Stereo: %s\n", ops->is_stereo(t) ? "yes" : "no"); + tuner_info("Stereo: %s\n", ops->is_stereo(fe) ? + "yes" : "no"); } } @@ -723,7 +726,7 @@ static int tuner_detach(struct i2c_client *client) } if ((ops) && (ops->release)) - ops->release(t); + ops->release(&t->fe); kfree(t); return 0; @@ -748,7 +751,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; if ((ops) && (ops->standby)) - ops->standby(t); + ops->standby(&t->fe); return EINVAL; } return 0; @@ -799,7 +802,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; t->mode = T_STANDBY; if ((ops) && (ops->standby)) - ops->standby(t); + ops->standby(&t->fe); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -868,7 +871,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { if ((ops) && (ops->is_stereo)) { - if (ops->is_stereo(t)) + if (ops->is_stereo(&t->fe)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -877,7 +880,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } } if ((ops) && (ops->has_signal)) - vt->signal = ops->has_signal(t); + vt->signal = ops->has_signal(&t->fe); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -908,7 +911,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } else if ((ops) && (ops->is_stereo)) - va->mode = ops->is_stereo(t) + va->mode = ops->is_stereo(&t->fe) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } return 0; @@ -999,7 +1002,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner->type = t->mode; if ((ops) && (ops->get_afc)) - tuner->afc = ops->get_afc(t); + tuner->afc = ops->get_afc(&t->fe); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -1015,16 +1018,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->rxsubchans = + (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; } else { if ((ops) && (ops->is_stereo)) { - tuner->rxsubchans = ops->is_stereo(t) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->rxsubchans = + ops->is_stereo(&t->fe) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; } } if ((ops) && (ops->has_signal)) - tuner->signal = ops->has_signal(t); + tuner->signal = ops->has_signal(&t->fe); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -1050,7 +1057,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: if ((ops) && (ops->tuner_status)) - ops->tuner_status(t); + ops->tuner_status(&t->fe); break; } diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index fffacb378fd..cc9c1c74117 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -32,14 +32,14 @@ extern unsigned const int tuner_count; struct tuner; struct analog_tuner_ops { - void (*set_tv_freq)(struct tuner *t, unsigned int freq); - void (*set_radio_freq)(struct tuner *t, unsigned int freq); - int (*has_signal)(struct tuner *t); - int (*is_stereo)(struct tuner *t); - int (*get_afc)(struct tuner *t); - void (*tuner_status)(struct tuner *t); - void (*standby)(struct tuner *t); - void (*release)(struct tuner *t); + void (*set_tv_freq)(struct dvb_frontend *fe, unsigned int freq); + void (*set_radio_freq)(struct dvb_frontend *fe, unsigned int freq); + int (*has_signal)(struct dvb_frontend *fe); + int (*is_stereo)(struct dvb_frontend *fe); + int (*get_afc)(struct dvb_frontend *fe); + void (*tuner_status)(struct dvb_frontend *fe); + void (*standby)(struct dvb_frontend *fe); + void (*release)(struct dvb_frontend *fe); }; struct tuner { -- cgit v1.2.3 From 1b29cedab9e69a6e4c9bba5f1981437b62be7bea Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 01:44:03 -0300 Subject: V4L/DVB (6441): tuner: clean up ops checking in tuner_status function Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 805a2bd29e7..3de03da28da 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -567,12 +567,13 @@ static void tuner_status(struct dvb_frontend *fe) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if ((ops) && (ops->has_signal)) { - tuner_info("Signal strength: %d\n", ops->has_signal(fe)); - } - if ((ops) && (ops->is_stereo)) { - tuner_info("Stereo: %s\n", ops->is_stereo(fe) ? - "yes" : "no"); + if (ops) { + if (ops->has_signal) + tuner_info("Signal strength: %d\n", + ops->has_signal(fe)); + if (ops->is_stereo) + tuner_info("Stereo: %s\n", + ops->is_stereo(fe) ? "yes" : "no"); } } -- cgit v1.2.3 From 5c82f4497b46e9c3877618bc36661a4abbf9c646 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 01:10:39 -0300 Subject: V4L/DVB (6442): move std if setting from tda8290 to tda827x Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda827x.c | 61 ++++++++++++++++++++++++++++++++--- drivers/media/dvb/frontends/tda827x.h | 3 -- drivers/media/video/tda8290.c | 20 +----------- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 6de1aea02d5..8329d33b517 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -38,10 +38,57 @@ struct tda827x_priv { int i2c_addr; struct i2c_adapter *i2c_adap; struct tda827x_config *cfg; + + unsigned int sgIF; + unsigned char lpsel; + u32 frequency; u32 bandwidth; }; +static void tda827x_set_std(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + char *mode; + + priv->lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + mode = "LC"; + } else { + priv->sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + dprintk("setting tda827x to system %s\n", mode); +} + + +/* ------------------------------------------------------------------ */ + struct tda827x_data { u32 lomax; u8 spd; @@ -189,10 +236,12 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe, struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; unsigned int freq = params->frequency; + tda827x_set_std(fe, params); + if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + priv->cfg->sgIF; + N = freq + priv->sgIF; i = 0; while (tda827x_table[i].lomax < N * 62500) { @@ -207,7 +256,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe, tuner_reg[1] = (unsigned char)(N>>8); tuner_reg[2] = (unsigned char) N; tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->cfg->tda827x_lpsel << 5); + tuner_reg[4] = 0x52 + (priv->lpsel << 5); tuner_reg[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + (tda827x_table[i].bs << 3) + tda827x_table[i].bp; @@ -550,13 +599,15 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe, .buf = tuner_reg, .len = sizeof(tuner_reg) }; unsigned int freq = params->frequency; + tda827x_set_std(fe, params); + tda827xa_lna_gain(fe, 1, params); msleep(10); if (params->mode == V4L2_TUNER_RADIO) freq = freq / 1000; - N = freq + priv->cfg->sgIF; + N = freq + priv->sgIF; i = 0; while (tda827xa_analog[i].lomax < N * 62500) { @@ -587,7 +638,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe, tuner_reg[1] = 0xff; tuner_reg[2] = 0xe0; tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->cfg->tda827x_lpsel << 1); + tuner_reg[4] = 0x99 + (priv->lpsel << 1); msg.len = 5; i2c_transfer(priv->i2c_adap, &msg, 1); @@ -627,7 +678,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe, i2c_transfer(priv->i2c_adap, &msg, 1); tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->cfg->tda827x_lpsel << 1); + tuner_reg[1] = 0x19 + (priv->lpsel << 1); i2c_transfer(priv->i2c_adap, &msg, 1); priv->frequency = freq * 62500; diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h index 06626f7af61..92eb65b4012 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/dvb/frontends/tda827x.h @@ -35,9 +35,6 @@ struct tda827x_config int (*sleep) (struct dvb_frontend *fe); /* interface to tda829x driver */ - unsigned char tda827x_lpsel; - unsigned int sgIF; - unsigned int *config; int (*tuner_callback) (void *dev, int command, int arg); diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 288865c3c71..1b19b93eabe 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -104,45 +104,32 @@ static void set_audio(struct dvb_frontend *fe) struct tuner *t = priv->t; char* mode; - priv->cfg.tda827x_lpsel = 0; if (t->std & V4L2_STD_MN) { - priv->cfg.sgIF = 92; priv->tda8290_easy_mode = 0x01; - priv->cfg.tda827x_lpsel = 1; mode = "MN"; } else if (t->std & V4L2_STD_B) { - priv->cfg.sgIF = 108; priv->tda8290_easy_mode = 0x02; mode = "B"; } else if (t->std & V4L2_STD_GH) { - priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x04; mode = "GH"; } else if (t->std & V4L2_STD_PAL_I) { - priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x08; mode = "I"; } else if (t->std & V4L2_STD_DK) { - priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "DK"; } else if (t->std & V4L2_STD_SECAM_L) { - priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x20; mode = "L"; } else if (t->std & V4L2_STD_SECAM_LC) { - priv->cfg.sgIF = 20; priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { - priv->cfg.sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "xx"; } - if (t->mode == V4L2_TUNER_RADIO) - priv->cfg.sgIF = 88; /* if frequency is 5.5 MHz */ - tuner_dbg("setting tda8290 to system %s\n", mode); } @@ -368,7 +355,6 @@ static void tda8295_set_freq(struct dvb_frontend *fe, unsigned int freq) { struct tda8290_priv *priv = fe->analog_demod_priv; struct tuner *t = priv->t; - u16 ifc; unsigned char blanking_mode[] = { 0x1d, 0x00 }; @@ -381,9 +367,7 @@ static void tda8295_set_freq(struct dvb_frontend *fe, unsigned int freq) set_audio(fe); - ifc = priv->cfg.sgIF; /* FIXME */ - - tuner_dbg("%s: ifc = %u, freq = %d\n", __FUNCTION__, ifc, freq); + tuner_dbg("%s: freq = %d\n", __FUNCTION__, freq); tda8295_power(fe, 1); tda8295_agc1_out(fe, 1); @@ -625,7 +609,6 @@ int tda8290_attach(struct tuner *t) tuner_info("type set to %s\n", t->i2c.name); - priv->cfg.tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; tda8290_init_tuner(&t->fe); @@ -715,7 +698,6 @@ int tda8295_attach(struct tuner *t) t->fe.ops.analog_demod_ops = &tda8295_tuner_ops; - priv->cfg.tda827x_lpsel = 0; t->mode = V4L2_TUNER_ANALOG_TV; tda8295_init_if(&t->fe); -- cgit v1.2.3 From 31c9584c0b071dfa7a75db6e21cc727f728f97b0 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 21 Oct 2007 20:48:48 -0300 Subject: V4L/DVB (6443): make tda9887 build selectable via Kconfig Signed-off-by: Michael Krufky Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 10 ++++++++++ drivers/media/video/Makefile | 3 ++- drivers/media/video/tda9887.c | 23 +++++++++++++++-------- drivers/media/video/tda9887.h | 33 +++++++++++++++++++++++++++++++++ drivers/media/video/tuner-core.c | 3 ++- drivers/media/video/tuner-driver.h | 4 ---- 6 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 drivers/media/video/tda9887.h diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index e5222938098..8f4a45346de 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -75,6 +75,7 @@ config VIDEO_TUNER select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE menuconfig VIDEO_TUNER_CUSTOMIZE bool "Customize analog tuner modules to build" @@ -130,10 +131,19 @@ config TUNER_TEA5767 config TUNER_SIMPLE tristate "Simple tuner support" depends on I2C + select TUNER_TDA9887 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for various simple tuners. +config TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + endif # VIDEO_TUNER_CUSTOMIZE config VIDEOBUF_GEN diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 08ac197cc1d..8a278182123 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -4,7 +4,7 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o tda9887.o +tuner-objs := tuner-core.o tuner-types.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o @@ -87,6 +87,7 @@ obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_TUNER_TDA9887) += tda9887.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 7663a557975..4f5d76ff0b4 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,7 +9,7 @@ #include #include #include -#include "tuner-driver.h" +#include "tda9887.h" /* Chips: @@ -20,13 +20,18 @@ Used as part of several tuners */ +static int tda9887_debug; +module_param_named(debug, tda9887_debug, int, 0644); + #define tda9887_info(fmt, arg...) do {\ printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \ - i2c_adapter_id(priv->t->i2c.adapter), priv->t->i2c.addr , ##arg); } while (0) + i2c_adapter_id(priv->t->i2c.adapter), \ + priv->t->i2c.addr, ##arg); } while (0) #define tda9887_dbg(fmt, arg...) do {\ - if (tuner_debug) \ + if (tda9887_debug) \ printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \ - i2c_adapter_id(priv->t->i2c.adapter), priv->t->i2c.addr , ##arg); } while (0) + i2c_adapter_id(priv->t->i2c.adapter), \ + priv->t->i2c.addr, ##arg); } while (0) struct tda9887_priv { struct tuner_i2c_props i2c_props; @@ -573,13 +578,13 @@ static void tda9887_configure(struct dvb_frontend *fe) tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1],priv->data[2],priv->data[3]); - if (tuner_debug > 1) + if (tda9887_debug > 1) dump_write_message(fe, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); - if (tuner_debug > 2) { + if (tda9887_debug > 2) { msleep_interruptible(1000); tda9887_status(fe); } @@ -590,7 +595,8 @@ static void tda9887_configure(struct dvb_frontend *fe) static void tda9887_tuner_status(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; - tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); + tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); } static int tda9887_get_afc(struct dvb_frontend *fe) @@ -636,7 +642,7 @@ static struct analog_tuner_ops tda9887_tuner_ops = { .release = tda9887_release, }; -int tda9887_tuner_init(struct tuner *t) +int tda9887_attach(struct tuner *t) { struct tda9887_priv *priv = NULL; @@ -658,6 +664,7 @@ int tda9887_tuner_init(struct tuner *t) return 0; } +EXPORT_SYMBOL_GPL(tda9887_attach); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h new file mode 100644 index 00000000000..b879f0ec285 --- /dev/null +++ b/drivers/media/video/tda9887.h @@ -0,0 +1,33 @@ +/* + 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 + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA9887_H__ +#define __TDA9887_H__ + +#include "tuner-driver.h" + +/* ------------------------------------------------------------------------ */ +#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) +extern int tda9887_attach(struct tuner *t); +#else +static inline int tda9887_attach(struct tuner *t) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return -EINVAL; +} +#endif + +#endif /* __TDA9887_H__ */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 3de03da28da..da16bf998fb 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -26,6 +26,7 @@ #include "tea5767.h" #include "tuner-xc2028.h" #include "tuner-simple.h" +#include "tda9887.h" #define UNSET (-1U) @@ -344,7 +345,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TDA9887: - tda9887_tuner_init(t); + tda9887_attach(t); break; default: attach_simple_tuner(t); diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index cc9c1c74117..c03d08cd832 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -69,10 +69,6 @@ struct tuner { /* ------------------------------------------------------------------------ */ -extern int tda9887_tuner_init(struct tuner *t); - -/* ------------------------------------------------------------------------ */ - #define tuner_warn(fmt, arg...) do {\ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -- cgit v1.2.3 From af3b0f3f01d299c46837a408e1b9510b8c304e43 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 18:03:29 -0300 Subject: V4L/DVB (6444): tuner-core: remove excessive parenthesis Convert all instances of "if ((ops) && (ops->foo))" to "if (ops && ops->foo)" Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index da16bf998fb..1e9c9755dec 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -279,7 +279,7 @@ static void set_type(struct i2c_client *c, unsigned int type, } /* discard private data, in case set_type() was previously called */ - if ((ops) && (ops->release)) + if (ops && ops->release) ops->release(&t->fe); switch (t->type) { @@ -727,7 +727,7 @@ static int tuner_detach(struct i2c_client *client) return err; } - if ((ops) && (ops->release)) + if (ops && ops->release) ops->release(&t->fe); kfree(t); @@ -752,7 +752,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if ((ops) && (ops->standby)) + if (ops && ops->standby) ops->standby(&t->fe); return EINVAL; } @@ -803,7 +803,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if ((ops) && (ops->standby)) + if (ops && ops->standby) ops->standby(&t->fe); break; #ifdef CONFIG_VIDEO_V4L1 @@ -872,7 +872,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { - if ((ops) && (ops->is_stereo)) { + if (ops && ops->is_stereo) { if (ops->is_stereo(&t->fe)) vt->flags |= VIDEO_TUNER_STEREO_ON; @@ -881,7 +881,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ~VIDEO_TUNER_STEREO_ON; } } - if ((ops) && (ops->has_signal)) + if (ops && ops->has_signal) vt->signal = ops->has_signal(&t->fe); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -912,7 +912,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - } else if ((ops) && (ops->is_stereo)) + } else if (ops && ops->is_stereo) va->mode = ops->is_stereo(&t->fe) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } @@ -1003,7 +1003,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if ((ops) && (ops->get_afc)) + if (ops && ops->get_afc) tuner->afc = ops->get_afc(&t->fe); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; @@ -1025,14 +1025,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } else { - if ((ops) && (ops->is_stereo)) { + if (ops && ops->is_stereo) { tuner->rxsubchans = ops->is_stereo(&t->fe) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } } - if ((ops) && (ops->has_signal)) + if (ops && ops->has_signal) tuner->signal = ops->has_signal(&t->fe); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; @@ -1058,7 +1058,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if ((ops) && (ops->tuner_status)) + if (ops && ops->tuner_status) ops->tuner_status(&t->fe); break; } -- cgit v1.2.3 From 4524c1aba5449d3519d1545f8106811eb73fc72c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 22 Oct 2007 18:15:39 -0300 Subject: V4L/DVB (6445): tuner-core: improve comments inside function fe_release() Explain who is responsible for freeing analog_demod_priv Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 1e9c9755dec..88db8b33c86 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -103,7 +103,15 @@ static void fe_release(struct dvb_frontend *fe) fe->ops.tuner_ops.release(fe); fe->ops.analog_demod_ops = NULL; - /* DO NOT kfree(t->fe.analog_demod_priv) */ + + /* DO NOT kfree(fe->analog_demod_priv) + * + * If we are in this function, analog_demod_priv contains a pointer + * to struct tuner *t. This will be kfree'd in tuner_detach(). + * + * Otherwise, fe->ops.analog_demod_ops->release will + * handle the cleanup for analog demodulator modules. + */ fe->analog_demod_priv = NULL; } -- cgit v1.2.3 From 6f998742f09a7116f1232cebc87a814e3aca639a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 24 Oct 2007 01:00:24 -0300 Subject: V4L/DVB (6446): tda18271: clean up debug macros Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271.c | 76 ++++++++++++++++------------------ 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c index 3395f2bda49..1b9c143888e 100644 --- a/drivers/media/dvb/frontends/tda18271.c +++ b/drivers/media/dvb/frontends/tda18271.c @@ -28,13 +28,9 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -#define tuner_dbg(fmt, arg...) do {\ - if (debug > 0) \ - printk(KERN_DEBUG fmt, ##arg); } while (0) - -#define tuner_extra_dbg(fmt, arg...) do {\ - if (debug > 1) \ - printk(KERN_DEBUG fmt, ##arg); } while (0) +#define dprintk(level, fmt, arg...) do {\ + if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) #define R_ID 0x00 /* ID byte */ #define R_TM 0x01 /* Thermo byte */ @@ -335,23 +331,23 @@ static void tda18271_dump_regs(struct dvb_frontend *fe) struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - tuner_dbg("=== TDA18271 REG DUMP ===\n"); - tuner_dbg("ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); - tuner_dbg("THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); - tuner_dbg("POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); - tuner_dbg("EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); - tuner_dbg("EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); - tuner_dbg("EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); - tuner_dbg("EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); - tuner_dbg("EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); - tuner_dbg("CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); - tuner_dbg("CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); - tuner_dbg("CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); - tuner_dbg("CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); - tuner_dbg("MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); - tuner_dbg("MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); - tuner_dbg("MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); - tuner_dbg("MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); + dprintk(1, "=== TDA18271 REG DUMP ===\n"); + dprintk(1, "ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); + dprintk(1, "THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); + dprintk(1, "POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); + dprintk(1, "EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); + dprintk(1, "EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); + dprintk(1, "EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); + dprintk(1, "EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); + dprintk(1, "EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); + dprintk(1, "CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); + dprintk(1, "CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); + dprintk(1, "CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); + dprintk(1, "CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); + dprintk(1, "MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); + dprintk(1, "MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); + dprintk(1, "MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); + dprintk(1, "MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); } static void tda18271_read_regs(struct dvb_frontend *fe) @@ -614,7 +610,7 @@ static int tda18271_tune(struct dvb_frontend *fe, int i; - tuner_dbg("%s: freq = %d, ifc = %d\n", __FUNCTION__, freq, ifc); + dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); tda18271_init_regs(fe); /* RF tracking filter calibration */ @@ -626,8 +622,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("bp filter = 0x%x, i = %d\n", - tda18271_bp_filter[i].val, i); + dprintk(2, "bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); regs[R_EP1] &= ~0x07; /* clear bp filter bits */ regs[R_EP1] |= tda18271_bp_filter[i].val; @@ -666,8 +661,8 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("cal pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); + dprintk(2, "cal pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); regs[R_CPD] = tda18271_cal_pll[i].pd; @@ -693,8 +688,8 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("main pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); @@ -722,7 +717,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("km = 0x%x, i = %d\n", tda18271_km[i].val, i); + dprintk(2, "km = 0x%x, i = %d\n", tda18271_km[i].val, i); regs[R_EB13] &= 0x83; regs[R_EB13] |= tda18271_km[i].val; @@ -735,8 +730,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("rf band = 0x%x, i = %d\n", - tda18271_rf_band[i].val, i); + dprintk(2, "rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); regs[R_EP2] &= ~0xe0; /* clear rf band bits */ regs[R_EP2] |= (tda18271_rf_band[i].val << 5); @@ -748,8 +742,8 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("gain taper = 0x%x, i = %d\n", - tda18271_gain_taper[i].val, i); + dprintk(2, "gain taper = 0x%x, i = %d\n", + tda18271_gain_taper[i].val, i); regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ regs[R_EP2] |= tda18271_gain_taper[i].val; @@ -783,7 +777,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); + dprintk(2, "rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); /* VHF_Low band only */ if (tda18271_rf_cal[i].rfmax != 0) { @@ -847,8 +841,8 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - tuner_extra_dbg("main pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); switch (priv->mode) { @@ -979,7 +973,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, if (params->mode == V4L2_TUNER_RADIO) sgIF = 88; /* if frequency is 5.5 MHz */ - tuner_dbg("setting tda18271 to system %s\n", mode); + dprintk(1, "setting tda18271 to system %s\n", mode); return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, 0, std); @@ -1025,7 +1019,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, { struct tda18271_priv *priv = NULL; - tuner_dbg("%s:\n", __FUNCTION__); + dprintk(1, "@ 0x%x\n", addr); priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); if (priv == NULL) return NULL; -- cgit v1.2.3 From 2be1b48fd27a3b6878db034288ed571b03df3a5c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 24 Oct 2007 09:23:17 -0300 Subject: V4L/DVB (6447): tuner: add i2c_gate_ctrl function to struct analog_tuner_ops In some designs, the tuner silicon may be on an i2c bus behind an i2c gate, controlled by the analog demodulator. We already have a method to control such i2c gates when they are controlled by the digital demodulator, but in some hybrid designs, there may be an i2c gate controlled by each demodulator. For example, when in analog tuning mode, one would access the tuner by opening the i2c gate controlled by the analog demodulator, while when in digital tuning mode, one would access the tuner by opening the i2c gate controlled by the digital demodulator. We must add this callback function to analog_tuner_ops in order to handle such configurations. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index c03d08cd832..728cacd2168 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -40,6 +40,7 @@ struct analog_tuner_ops { void (*tuner_status)(struct dvb_frontend *fe); void (*standby)(struct dvb_frontend *fe); void (*release)(struct dvb_frontend *fe); + int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); }; struct tuner { -- cgit v1.2.3 From a72dd305f99f6c6e4eff01478ae53fc80ce98fb1 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 24 Oct 2007 09:30:17 -0300 Subject: V4L/DVB (6448): tda8290: fill i2c_gate_ctrl callback Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 1b19b93eabe..5975c548b8a 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -50,14 +50,15 @@ struct tda8290_priv { /*---------------------------------------------------------------------*/ -static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char enable[2] = { 0x21, 0xC0 }; unsigned char disable[2] = { 0x21, 0x00 }; unsigned char *msg; - if(close) { + + if (close) { msg = enable; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ @@ -66,9 +67,11 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) msg = disable; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } + + return 0; } -static void tda8295_i2c_bridge(struct dvb_frontend *fe, int close) +static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) { struct tda8290_priv *priv = fe->analog_demod_priv; @@ -76,6 +79,7 @@ static void tda8295_i2c_bridge(struct dvb_frontend *fe, int close) unsigned char disable[2] = { 0x46, 0x00 }; unsigned char buf[3] = { 0x45, 0x01, 0x00 }; unsigned char *msg; + if (close) { msg = enable; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); @@ -94,6 +98,8 @@ static void tda8295_i2c_bridge(struct dvb_frontend *fe, int close) msg[1] |= 0x04; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } + + return 0; } /*---------------------------------------------------------------------*/ @@ -517,6 +523,7 @@ static struct analog_tuner_ops tda8290_tuner_ops = { .has_signal = tda8290_has_signal, .standby = tda8290_standby, .release = tda829x_release, + .i2c_gate_ctrl = tda8290_i2c_bridge, }; static struct analog_tuner_ops tda8295_tuner_ops = { @@ -525,6 +532,7 @@ static struct analog_tuner_ops tda8295_tuner_ops = { .has_signal = tda8295_has_signal, .standby = tda8295_standby, .release = tda829x_release, + .i2c_gate_ctrl = tda8295_i2c_bridge, }; int tda8290_attach(struct tuner *t) -- cgit v1.2.3 From 7d11c53c5d909d866dee0ce5db2d6ca1c422edca Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 24 Oct 2007 09:55:54 -0300 Subject: V4L/DVB (6449): tda18271: clean up i2c_gate handling Call analog_demod_ops->i2c_gate_ctrl when in analog tuning mode, and frontend_ops.i2c_gate_ctrl when in digital tuning mode. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/tda18271.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 457effcda5d..57e5fa80589 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -3,6 +3,7 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/video/ obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c index 1b9c143888e..aaaa2f88518 100644 --- a/drivers/media/dvb/frontends/tda18271.c +++ b/drivers/media/dvb/frontends/tda18271.c @@ -21,6 +21,7 @@ #include #include #include +#include "tuner-driver.h" #include "tda18271.h" @@ -324,6 +325,26 @@ struct tda18271_priv { u32 bandwidth; }; +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + int ret = 0; + + switch (priv->mode) { + case TDA18271_ANALOG: + if (ops && ops->i2c_gate_ctrl) + ret = ops->i2c_gate_ctrl(fe, enable); + break; + case TDA18271_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + } + + return ret; +}; + /*---------------------------------------------------------------------*/ static void tda18271_dump_regs(struct dvb_frontend *fe) @@ -363,14 +384,12 @@ static void tda18271_read_regs(struct dvb_frontend *fe) .buf = regs, .len = 16 } }; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); + tda18271_i2c_gate_ctrl(fe, 1); /* read all registers */ ret = i2c_transfer(priv->i2c_adap, msg, 2); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + tda18271_i2c_gate_ctrl(fe, 0); if (ret != 2) printk("ERROR: %s: i2c_transfer returned: %d\n", @@ -396,14 +415,12 @@ static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) buf[i] = regs[idx-1+i]; } - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); + tda18271_i2c_gate_ctrl(fe, 1); /* write registers */ ret = i2c_transfer(priv->i2c_adap, &msg, 1); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + tda18271_i2c_gate_ctrl(fe, 0); if (ret != 1) printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", -- cgit v1.2.3 From 5ef4730d1bfe5be71ce54d927c510ad5da968854 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 27 Oct 2007 02:17:19 -0300 Subject: V4L/DVB (6450): tda9887: add missing module license This module was always GPL, and will remain GPL Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 4f5d76ff0b4..080bd308073 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -666,6 +666,8 @@ int tda9887_attach(struct tuner *t) } EXPORT_SYMBOL_GPL(tda9887_attach); +MODULE_LICENSE("GPL"); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- -- cgit v1.2.3 From 8ffbc6559493c64d6194c92d856196fdaeb8a5fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Sep 2007 08:32:50 -0300 Subject: V4L/DVB (6451): v4l2: add support for bus-based I2C drivers Two new headers were added: one for I2C drivers that are only used by V4L2 drivers converted to the new bus-based I2C API, and one that can be used by both converted and unconverted drivers (at the expense of some additional overhead). To support the legacy I2C API a helper function was added to v4l2-common.c. These headers take care of all the 'boilerplate' code that all V4L2 I2C drivers have in common and will automatically support the bus-based I2C API introduced in kernel 2.6.22. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 31 +++++++++ include/media/v4l2-common.h | 11 +++ include/media/v4l2-i2c-drv-legacy.h | 132 ++++++++++++++++++++++++++++++++++++ include/media/v4l2-i2c-drv.h | 61 +++++++++++++++++ 4 files changed, 235 insertions(+) create mode 100644 include/media/v4l2-i2c-drv-legacy.h create mode 100644 include/media/v4l2-i2c-drv.h diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index a4d68d3ba5e..32607a612b1 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -1013,6 +1013,35 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip) /* ----------------------------------------------------------------- */ +/* Helper function for I2C legacy drivers */ + +int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, + const char *name, int (*probe)(struct i2c_client *)) +{ + struct i2c_client *client; + int err; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = driver; + snprintf(client->name, sizeof(client->name) - 1, name); + + err = probe(client); + if (err == 0) { + i2c_attach_client(client); + } + else { + kfree(client); + } + return err; +} + +/* ----------------------------------------------------------------- */ + EXPORT_SYMBOL(v4l2_norm_to_name); EXPORT_SYMBOL(v4l2_video_std_construct); @@ -1038,6 +1067,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client); EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); EXPORT_SYMBOL(v4l2_chip_match_host); +EXPORT_SYMBOL(v4l2_i2c_attach); + /* * Local variables: * c-basic-offset: 8 diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index c019c1e9989..475d0d8275e 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -104,6 +104,17 @@ int v4l2_chip_match_host(u32 id_type, u32 chip_id); /* ------------------------------------------------------------------------- */ +/* Helper function for I2C legacy drivers */ + +struct i2c_driver; +struct i2c_adapter; +struct i2c_client; + +int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, + const char *name, int (*probe)(struct i2c_client *)); + +/* ------------------------------------------------------------------------- */ + /* Internal ioctls */ /* VIDIOC_INT_DECODE_VBI_LINE */ diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h new file mode 100644 index 00000000000..c059b32844c --- /dev/null +++ b/include/media/v4l2-i2c-drv-legacy.h @@ -0,0 +1,132 @@ +/* + * v4l2-i2c-drv-legacy.h - contains I2C handling code that's identical + * for all V4L2 I2C drivers. Use this header if the + * I2C driver is used by both legacy drivers and + * drivers converted to the bus-based I2C API. + * + * Copyright (C) 2007 Hans Verkuil + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +struct v4l2_i2c_driver_data { + const char * const name; + int driverid; + int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); + int (*probe)(struct i2c_client *client); + int (*remove)(struct i2c_client *client); + int (*suspend)(struct i2c_client *client, pm_message_t state); + int (*resume)(struct i2c_client *client); + int legacy_class; +}; + +static struct v4l2_i2c_driver_data v4l2_i2c_data; +static struct i2c_client_address_data addr_data; +static struct i2c_driver v4l2_i2c_driver_legacy; +static char v4l2_i2c_drv_name_legacy[32]; + +static int v4l2_i2c_drv_attach_legacy(struct i2c_adapter *adapter, int address, int kind) +{ + return v4l2_i2c_attach(adapter, address, &v4l2_i2c_driver_legacy, + v4l2_i2c_drv_name_legacy, v4l2_i2c_data.probe); +} + +static int v4l2_i2c_drv_probe_legacy(struct i2c_adapter *adapter) +{ + if (adapter->class & v4l2_i2c_data.legacy_class) + return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); + return 0; +} + +static int v4l2_i2c_drv_detach_legacy(struct i2c_client *client) +{ + int err = i2c_detach_client(client); + + if (err) + return err; + if (v4l2_i2c_data.remove) + v4l2_i2c_data.remove(client); + kfree(client); + + return 0; +} + +static int v4l2_i2c_drv_suspend_helper(struct i2c_client *client, pm_message_t state) +{ + return v4l2_i2c_data.suspend ? v4l2_i2c_data.suspend(client, state) : 0; +} + +static int v4l2_i2c_drv_resume_helper(struct i2c_client *client) +{ + return v4l2_i2c_data.resume ? v4l2_i2c_data.resume(client) : 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver v4l2_i2c_driver_legacy = { + .driver = { + .owner = THIS_MODULE, + }, + .attach_adapter = v4l2_i2c_drv_probe_legacy, + .detach_client = v4l2_i2c_drv_detach_legacy, + .suspend = v4l2_i2c_drv_suspend_helper, + .resume = v4l2_i2c_drv_resume_helper, +}; + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver v4l2_i2c_driver = { + .suspend = v4l2_i2c_drv_suspend_helper, + .resume = v4l2_i2c_drv_resume_helper, +}; + +static int __init v4l2_i2c_drv_init(void) +{ + int err; + + strlcpy(v4l2_i2c_drv_name_legacy, v4l2_i2c_data.name, sizeof(v4l2_i2c_drv_name_legacy)); + strlcat(v4l2_i2c_drv_name_legacy, "'", sizeof(v4l2_i2c_drv_name_legacy)); + + if (v4l2_i2c_data.legacy_class == 0) + v4l2_i2c_data.legacy_class = I2C_CLASS_TV_ANALOG; + + v4l2_i2c_driver_legacy.driver.name = v4l2_i2c_drv_name_legacy; + v4l2_i2c_driver_legacy.id = v4l2_i2c_data.driverid; + v4l2_i2c_driver_legacy.command = v4l2_i2c_data.command; + err = i2c_add_driver(&v4l2_i2c_driver_legacy); + + if (err) + return err; + v4l2_i2c_driver.driver.name = v4l2_i2c_data.name; + v4l2_i2c_driver.id = v4l2_i2c_data.driverid; + v4l2_i2c_driver.command = v4l2_i2c_data.command; + v4l2_i2c_driver.probe = v4l2_i2c_data.probe; + v4l2_i2c_driver.remove = v4l2_i2c_data.remove; + err = i2c_add_driver(&v4l2_i2c_driver); + if (err) + i2c_del_driver(&v4l2_i2c_driver_legacy); + return err; +} + +static void __exit v4l2_i2c_drv_cleanup(void) +{ + i2c_del_driver(&v4l2_i2c_driver_legacy); + i2c_del_driver(&v4l2_i2c_driver); +} + +module_init(v4l2_i2c_drv_init); +module_exit(v4l2_i2c_drv_cleanup); diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h new file mode 100644 index 00000000000..547db60d364 --- /dev/null +++ b/include/media/v4l2-i2c-drv.h @@ -0,0 +1,61 @@ +/* + * v4l2-i2c-drv.h - contains I2C handling code that's identical for + * all V4L2 I2C drivers. Use this header if the + * I2C driver is only used by drivers converted + * to the bus-based I2C API. + * + * Copyright (C) 2007 Hans Verkuil + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +struct v4l2_i2c_driver_data { + const char * const name; + int driverid; + int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); + int (*probe)(struct i2c_client *client); + int (*remove)(struct i2c_client *client); + int (*suspend)(struct i2c_client *client, pm_message_t state); + int (*resume)(struct i2c_client *client); + int legacy_class; +}; + +static struct v4l2_i2c_driver_data v4l2_i2c_data; +static struct i2c_client_address_data addr_data; +static struct i2c_driver v4l2_i2c_driver; + + +/* Bus-based I2C implementation for kernels >= 2.6.22 */ + +static int __init v4l2_i2c_drv_init(void) +{ + v4l2_i2c_driver.driver.name = v4l2_i2c_data.name; + v4l2_i2c_driver.id = v4l2_i2c_data.driverid; + v4l2_i2c_driver.command = v4l2_i2c_data.command; + v4l2_i2c_driver.probe = v4l2_i2c_data.probe; + v4l2_i2c_driver.remove = v4l2_i2c_data.remove; + v4l2_i2c_driver.suspend = v4l2_i2c_data.suspend; + v4l2_i2c_driver.resume = v4l2_i2c_data.resume; + return i2c_add_driver(&v4l2_i2c_driver); +} + + +static void __exit v4l2_i2c_drv_cleanup(void) +{ + i2c_del_driver(&v4l2_i2c_driver); +} + +module_init(v4l2_i2c_drv_init); +module_exit(v4l2_i2c_drv_cleanup); -- cgit v1.2.3 From d9a53aa9024e507df01f257494956e906a92c864 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:08:25 -0300 Subject: V4L/DVB (6452): wm8775: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/wm8775.c | 78 +++++++++----------------------------------- 1 file changed, 15 insertions(+), 63 deletions(-) diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 9f7e894ef96..c31a0c34b08 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -34,6 +34,7 @@ #include #include #include +#include MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; + /* ----------------------------------------------------------------------- */ enum { @@ -76,8 +78,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) return -1; } -static int wm8775_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int wm8775_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct wm8775_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -159,31 +160,18 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) +static int wm8775_probe(struct i2c_client *client) { - struct i2c_client *client; struct wm8775_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "wm8775"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } state->input = 2; @@ -208,56 +196,20 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */ /* limit -1dB */ wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */ - i2c_attach_client(client); - return 0; } -static int wm8775_probe(struct i2c_adapter *adapter) +static int wm8775_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, wm8775_attach); - return 0; -} - -static int wm8775_detach(struct i2c_client *client) -{ - struct wm8775_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "wm8775", - }, - .id = I2C_DRIVERID_WM8775, - .attach_adapter = wm8775_probe, - .detach_client = wm8775_detach, - .command = wm8775_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "wm8775", + .driverid = I2C_DRIVERID_WM8775, + .command = wm8775_command, + .probe = wm8775_probe, + .remove = wm8775_remove, }; - -static int __init wm8775_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit wm8775_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(wm8775_init_module); -module_exit(wm8775_cleanup_module); -- cgit v1.2.3 From 49457cc2792a63512112434534ecfdd3d4c66e93 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:10:07 -0300 Subject: V4L/DVB (6453): wm8739: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/wm8739.c | 71 +++++++------------------------------------- 1 file changed, 10 insertions(+), 61 deletions(-) diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 1bf4cbec6a8..459228a5cf5 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -30,6 +30,7 @@ #include #include #include +#include MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); @@ -259,27 +260,11 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) +static int wm8739_probe(struct i2c_client *client) { - struct i2c_client *client; struct wm8739_state *state; - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "wm8739"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); if (state == NULL) { @@ -306,56 +291,20 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) /* normal, 256fs, 48KHz sampling rate */ wm8739_write(client, R9, 0x001); /* activate */ wm8739_set_audio(client); /* set volume/mute */ - - i2c_attach_client(client); - return 0; } -static int wm8739_probe(struct i2c_adapter *adapter) +static int wm8739_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, wm8739_attach); + kfree(i2c_get_clientdata(client)); return 0; } -static int wm8739_detach(struct i2c_client *client) -{ - struct wm8739_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(state); - kfree(client); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "wm8739", - }, - .id = I2C_DRIVERID_WM8739, - .attach_adapter = wm8739_probe, - .detach_client = wm8739_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "wm8739", + .driverid = I2C_DRIVERID_WM8739, .command = wm8739_command, + .probe = wm8739_probe, + .remove = wm8739_remove, }; - -static int __init wm8739_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit wm8739_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(wm8739_init_module); -module_exit(wm8739_cleanup_module); -- cgit v1.2.3 From 45eea27624d4dacd36c2167f75e2510ee5d4ab26 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:11:44 -0300 Subject: V4L/DVB (6454): vp27smpx: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 71 ++++++++---------------------------------- 1 file changed, 13 insertions(+), 58 deletions(-) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 63002e0ac76..24a94231504 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -30,6 +30,7 @@ #include #include #include +#include MODULE_DESCRIPTION("vp27smpx driver"); MODULE_AUTHOR("Hans Verkuil"); @@ -73,8 +74,7 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) } } -static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct vp27smpx_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; @@ -125,31 +125,20 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +static int vp27smpx_probe(struct i2c_client *client) { - struct i2c_client *client; struct vp27smpx_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } state->audmode = V4L2_TUNER_MODE_STEREO; @@ -157,56 +146,22 @@ static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) /* initialize vp27smpx */ vp27smpx_set_audmode(client, state->audmode); - i2c_attach_client(client); - - return 0; -} - -static int vp27smpx_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, vp27smpx_attach); return 0; } -static int vp27smpx_detach(struct i2c_client *client) +static int vp27smpx_remove(struct i2c_client *client) { - struct vp27smpx_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "vp27smpx", - }, - .id = I2C_DRIVERID_VP27SMPX, - .attach_adapter = vp27smpx_probe, - .detach_client = vp27smpx_detach, - .command = vp27smpx_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "vp27smpx", + .driverid = I2C_DRIVERID_VP27SMPX, + .command = vp27smpx_command, + .probe = vp27smpx_probe, + .remove = vp27smpx_remove, }; - -static int __init vp27smpx_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit vp27smpx_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(vp27smpx_init_module); -module_exit(vp27smpx_cleanup_module); -- cgit v1.2.3 From fbaa3d0db482ae55fc054b9446c1ecf699754054 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:19:39 -0300 Subject: V4L/DVB (6455): saa7115: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 76 +++++++++---------------------------------- 1 file changed, 16 insertions(+), 60 deletions(-) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 2d18f006982..ad60335544f 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, /* ============ SAA7115 AUDIO settings (end) ============= */ -static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa711x_state *state = i2c_get_clientdata(client); @@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa711x; - -static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) +static int saa7115_probe(struct i2c_client *client) { - struct i2c_client *client; struct saa711x_state *state; int i; char name[17]; u8 chip_id; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa711x; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); for (i = 0; i < 0x0f; i++) { @@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) /* Check whether this chip is part of the saa711x series */ if (memcmp(name, "1f711", 5)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", - address << 1, name); - kfree(client); + client->addr << 1, name); return 0; } snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); - v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name); + v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); i2c_set_clientdata(client, state); if (state == NULL) { - kfree(client); return -ENOMEM; } state->input = -1; @@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) saa711x_writeregs(client, saa7115_init_misc); saa711x_set_v4lstd(client, V4L2_STD_NTSC); - i2c_attach_client(client); - v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n", saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC)); - return 0; } -static int saa711x_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL) - return i2c_probe(adapter, &addr_data, &saa711x_attach); - return 0; -} +/* ----------------------------------------------------------------------- */ -static int saa711x_detach(struct i2c_client *client) +static int saa7115_remove(struct i2c_client *client) { - struct saa711x_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver_saa711x = { - .driver = { - .name = "saa7115", - }, - .id = I2C_DRIVERID_SAA711X, - .attach_adapter = saa711x_probe, - .detach_client = saa711x_detach, - .command = saa711x_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa7115", + .driverid = I2C_DRIVERID_SAA711X, + .command = saa7115_command, + .probe = saa7115_probe, + .remove = saa7115_remove, + .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, }; - -static int __init saa711x_init_module(void) -{ - return i2c_add_driver(&i2c_driver_saa711x); -} - -static void __exit saa711x_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver_saa711x); -} - -module_init(saa711x_init_module); -module_exit(saa711x_cleanup_module); -- cgit v1.2.3 From 77566dd724f118b332b5dbf62eedc869f1263f22 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:21:51 -0300 Subject: V4L/DVB (6456): saa7127: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7127.c | 83 +++++++------------------------------------ 1 file changed, 13 insertions(+), 70 deletions(-) diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index e35ef321ec7..958ecc7168c 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -55,6 +55,7 @@ #include #include #include +#include #include static int debug = 0; @@ -662,31 +663,19 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa7127; - -/* ----------------------------------------------------------------------- */ - -static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) +static int saa7127_probe(struct i2c_client *client) { - struct i2c_client *client; struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ int read_result = 0; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa7127; snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1); + v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", client->addr << 1); /* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0. @@ -696,13 +685,11 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) if ((saa7127_read(client, 0) & 0xe4) != 0 || (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { v4l_dbg(1, debug, client, "saa7127 not found\n"); - kfree(client); return 0; } state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return (-ENOMEM); } @@ -731,78 +718,34 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7129 found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); saa7127_write_inittab(client, saa7129_init_config_extra); state->ident = V4L2_IDENT_SAA7129; } else { - v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7127 found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state->ident = V4L2_IDENT_SAA7127; } - - i2c_attach_client(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, saa7127_attach); return 0; } /* ----------------------------------------------------------------------- */ -static int saa7127_detach(struct i2c_client *client) +static int saa7127_remove(struct i2c_client *client) { - struct saa7127_state *state = i2c_get_clientdata(client); - int err; - /* Turn off TV output */ saa7127_set_video_enable(client, 0); - - err = i2c_detach_client(client); - - if (err) { - return err; - } - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa7127 = { - .driver = { - .name = "saa7127", - }, - .id = I2C_DRIVERID_SAA7127, - .attach_adapter = saa7127_probe, - .detach_client = saa7127_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa7127", + .driverid = I2C_DRIVERID_SAA7127, .command = saa7127_command, + .probe = saa7127_probe, + .remove = saa7127_remove, }; - -/* ----------------------------------------------------------------------- */ - -static int __init saa7127_init_module(void) -{ - return i2c_add_driver(&i2c_driver_saa7127); -} - -/* ----------------------------------------------------------------------- */ - -static void __exit saa7127_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver_saa7127); -} - -/* ----------------------------------------------------------------------- */ - -module_init(saa7127_init_module); -module_exit(saa7127_cleanup_module); -- cgit v1.2.3 From 79518dafd59a812bb390f201c6f18a8f875fcffb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:28:59 -0300 Subject: V4L/DVB (6457): msp3400: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-driver.c | 69 ++++++------------------------------ 1 file changed, 11 insertions(+), 58 deletions(-) diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index c0c87e06259..f2946aca129 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -783,7 +784,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) static int msp_suspend(struct i2c_client *client, pm_message_t state) { - v4l_dbg(1, msp_debug, client, "suspend\n"); msp_reset(client); return 0; @@ -791,7 +791,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state) static int msp_resume(struct i2c_client *client) { - v4l_dbg(1, msp_debug, client, "resume\n"); msp_wake_thread(client); return 0; @@ -799,11 +798,8 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver; - -static int msp_attach(struct i2c_adapter *adapter, int address, int kind) +static int msp_probe(struct i2c_client *client) { - struct i2c_client *client; struct msp_state *state; int (*thread_func)(void *data) = NULL; int msp_hard; @@ -812,24 +808,15 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_product, msp_prod_hi, msp_prod_lo; int msp_rom; - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - kfree(client); return 0; } state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) { - kfree(client); return -ENOMEM; } @@ -857,7 +844,6 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); kfree(state); - kfree(client); return 0; } @@ -919,7 +905,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) printk("supports nicam and radio, "); @@ -954,24 +940,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } - - /* done */ - i2c_attach_client(client); - - return 0; -} - -static int msp_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, msp_attach); return 0; } -static int msp_detach(struct i2c_client *client) +static int msp_remove(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int err; /* shutdown control thread */ if (state->kthread) { @@ -980,43 +954,22 @@ static int msp_detach(struct i2c_client *client) } msp_reset(client); - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .id = I2C_DRIVERID_MSP3400, - .attach_adapter = msp_probe, - .detach_client = msp_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "msp3400", + .driverid = I2C_DRIVERID_MSP3400, + .command = msp_command, + .probe = msp_probe, + .remove = msp_remove, .suspend = msp_suspend, - .resume = msp_resume, - .command = msp_command, - .driver = { - .name = "msp3400", - }, + .resume = msp_resume, }; -static int __init msp3400_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit msp3400_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. -- cgit v1.2.3 From e8e6b99184aa8cf72c5a28bf2a64f6d81473b1ca Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:30:38 -0300 Subject: V4L/DVB (6458): cs53l23a: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs53l32a.c | 70 ++++++------------------------------------ 1 file changed, 9 insertions(+), 61 deletions(-) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index a73e285af73..e43febb9d16 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -29,6 +29,7 @@ #include #include #include +#include MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); @@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_routing *route = arg; struct v4l2_control *ctrl = arg; @@ -134,27 +134,17 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) +static int cs53l32a_probe(struct i2c_client *client) { - struct i2c_client *client; int i; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); @@ -179,55 +169,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v); } - - i2c_attach_client(client); - return 0; } -static int cs53l32a_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, cs53l32a_attach); - return 0; -} - -static int cs53l32a_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "cs53l32a", - }, - .id = I2C_DRIVERID_CS53L32A, - .attach_adapter = cs53l32a_probe, - .detach_client = cs53l32a_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cs53l32a", + .driverid = I2C_DRIVERID_CS53L32A, .command = cs53l32a_command, + .probe = cs53l32a_probe, }; - -static int __init cs53l32a_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit cs53l32a_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(cs53l32a_init_module); -module_exit(cs53l32a_cleanup_module); -- cgit v1.2.3 From 1a39275a3f2fc6fbdb876f5121d67d4b13310c5b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2007 11:44:47 -0300 Subject: V4L/DVB (6459): cx25840: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 466 +++++++++++++---------------- 1 file changed, 203 insertions(+), 263 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 15f191e170d..1556e2fad4c 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "cx25840-core.h" @@ -122,8 +123,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, enum cx25840_audio_input aud_input); -static void log_audio_status(struct i2c_client *client); -static void log_video_status(struct i2c_client *client); /* ----------------------------------------------------------------------- */ @@ -641,6 +640,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) /* ----------------------------------------------------------------------- */ +static void log_video_status(struct i2c_client *client) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx25840_state *state = i2c_get_clientdata(client); + u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; + u8 gen_stat1 = cx25840_read(client, 0x40d); + u8 gen_stat2 = cx25840_read(client, 0x40e); + int vid_input = state->vid_input; + + v4l_info(client, "Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + v4l_info(client, "Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + v4l_info(client, "Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8) { + v4l_info(client, "Specified video input: Composite %d\n", + vid_input - CX25840_COMPOSITE1 + 1); + } else { + v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct i2c_client *client) +{ + struct cx25840_state *state = i2c_get_clientdata(client); + u8 download_ctl = cx25840_read(client, 0x803); + u8 mod_det_stat0 = cx25840_read(client, 0x804); + u8 mod_det_stat1 = cx25840_read(client, 0x805); + u8 audio_config = cx25840_read(client, 0x808); + u8 pref_mode = cx25840_read(client, 0x809); + u8 afc0 = cx25840_read(client, 0x80b); + u8 mute_ctl = cx25840_read(client, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "not defined"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0x0e: p = "IF FM Radio"; break; + case 0x0f: p = "BTSC"; break; + case 0x10: p = "high-deviation FM"; break; + case 0x11: p = "very high-deviation FM"; break; + case 0xfd: p = "unknown audio standard"; break; + case 0xfe: p = "forced audio standard"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio standard: %s\n", p); + v4l_info(client, "Audio muted: %s\n", + (state->unmute_volume >= 0) ? "yes" : "no"); + v4l_info(client, "Audio microcontroller: %s\n", + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "undefined"; break; + case 0x01: p = "BTSC"; break; + case 0x02: p = "EIAJ"; break; + case 0x03: p = "A2-M"; break; + case 0x04: p = "A2-BG"; break; + case 0x05: p = "A2-DK1"; break; + case 0x06: p = "A2-DK2"; break; + case 0x07: p = "A2-DK3"; break; + case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x09: p = "AM-L"; break; + case 0x0a: p = "NICAM-BG"; break; + case 0x0b: p = "NICAM-DK"; break; + case 0x0c: p = "NICAM-I"; break; + case 0x0d: p = "NICAM-L"; break; + case 0x0e: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio system: %s\n", p); + } + + if (aud_input) { + v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + } else { + v4l_info(client, "Specified audio input: External\n"); + } + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + v4l_info(client, "Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 3) & 0x3) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + case 2: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x7) { + case 0: p = "chroma"; break; + case 1: p = "BTSC"; break; + case 2: p = "EIAJ"; break; + case 3: p = "A2-M"; break; + case 4: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 45 MHz format: %s\n", p); + } +} + +/* ----------------------------------------------------------------------- */ + static int cx25840_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -879,31 +1072,12 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_cx25840; - -static int cx25840_detect_client(struct i2c_adapter *adapter, int address, - int kind) +static int cx25840_probe(struct i2c_client *client) { - struct i2c_client *client; struct cx25840_state *state; u32 id; u16 device_id; - /* Check if the adapter supports the needed features - * Not until kernel version 2.6.11 did the bit-algo - * correctly report that it would do an I2C-level xfer */ - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_cx25840; - snprintf(client->name, sizeof(client->name) - 1, "cx25840"); - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; @@ -919,13 +1093,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - kfree(client); return 0; } state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } @@ -948,251 +1120,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->vbi_line_offset = 8; state->id = id; state->rev = device_id; - - i2c_attach_client(client); - return 0; } -static int cx25840_attach_adapter(struct i2c_adapter *adapter) +static int cx25840_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, &cx25840_detect_client); + kfree(i2c_get_clientdata(client)); return 0; } -static int cx25840_detach_client(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver i2c_driver_cx25840 = { - .driver = { - .name = "cx25840", - }, - .id = I2C_DRIVERID_CX25840, - .attach_adapter = cx25840_attach_adapter, - .detach_client = cx25840_detach_client, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cx25840", + .driverid = I2C_DRIVERID_CX25840, .command = cx25840_command, + .probe = cx25840_probe, + .remove = cx25840_remove, }; - - -static int __init m__init(void) -{ - return i2c_add_driver(&i2c_driver_cx25840); -} - -static void __exit m__exit(void) -{ - i2c_del_driver(&i2c_driver_cx25840); -} - -module_init(m__init); -module_exit(m__exit); - -/* ----------------------------------------------------------------------- */ - -static void log_video_status(struct i2c_client *client) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx25840_state *state = i2c_get_clientdata(client); - u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; - u8 gen_stat1 = cx25840_read(client, 0x40d); - u8 gen_stat2 = cx25840_read(client, 0x40e); - int vid_input = state->vid_input; - - v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); - - if (vid_input >= CX25840_COMPOSITE1 && - vid_input <= CX25840_COMPOSITE8) { - v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); - } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); - } - - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); -} - -/* ----------------------------------------------------------------------- */ - -static void log_audio_status(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - u8 download_ctl = cx25840_read(client, 0x803); - u8 mod_det_stat0 = cx25840_read(client, 0x804); - u8 mod_det_stat1 = cx25840_read(client, 0x805); - u8 audio_config = cx25840_read(client, 0x808); - u8 pref_mode = cx25840_read(client, 0x809); - u8 afc0 = cx25840_read(client, 0x80b); - u8 mute_ctl = cx25840_read(client, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio standard: %s\n", p); - v4l_info(client, "Audio muted: %s\n", - (state->unmute_volume >= 0) ? "yes" : "no"); - v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio system: %s\n", p); - } - - if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); - } else { - v4l_info(client, "Specified audio input: External\n"); - } - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; - } - v4l_info(client, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 45 MHz format: %s\n", p); - } -} -- cgit v1.2.3 From 88307eb3c69c80a705072e68463d8f72005fc027 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Sep 2007 04:49:16 -0300 Subject: V4L/DVB (6460): v4l2-i2c-drv: add legacy_probe function pointer Some devices do complicated tests whether the device can be probed or not. Add a legacy_probe function pointer to support that. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-i2c-drv-legacy.h | 6 ++++++ include/media/v4l2-i2c-drv.h | 1 + 2 files changed, 7 insertions(+) diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h index c059b32844c..433c984eefa 100644 --- a/include/media/v4l2-i2c-drv-legacy.h +++ b/include/media/v4l2-i2c-drv-legacy.h @@ -29,6 +29,7 @@ struct v4l2_i2c_driver_data { int (*remove)(struct i2c_client *client); int (*suspend)(struct i2c_client *client, pm_message_t state); int (*resume)(struct i2c_client *client); + int (*legacy_probe)(struct i2c_adapter *adapter); int legacy_class; }; @@ -45,6 +46,11 @@ static int v4l2_i2c_drv_attach_legacy(struct i2c_adapter *adapter, int address, static int v4l2_i2c_drv_probe_legacy(struct i2c_adapter *adapter) { + if (v4l2_i2c_data.legacy_probe) { + if (v4l2_i2c_data.legacy_probe(adapter)) + return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); + return 0; + } if (adapter->class & v4l2_i2c_data.legacy_class) return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); return 0; diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h index 547db60d364..bc61ab27779 100644 --- a/include/media/v4l2-i2c-drv.h +++ b/include/media/v4l2-i2c-drv.h @@ -29,6 +29,7 @@ struct v4l2_i2c_driver_data { int (*remove)(struct i2c_client *client); int (*suspend)(struct i2c_client *client, pm_message_t state); int (*resume)(struct i2c_client *client); + int (*legacy_probe)(struct i2c_adapter *adapter); int legacy_class; }; -- cgit v1.2.3 From 08e140544029192a123cc2cbf28edeb5d5462ad2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Sep 2007 04:50:44 -0300 Subject: V4L/DVB (6461): tvaudio: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvaudio.c | 198 ++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 114 deletions(-) diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index bb510dd5dda..a75560540e7 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[]; /* current state of the chip */ struct CHIPSTATE { - struct i2c_client c; + struct i2c_client *c; /* index into CHIPDESC array */ int type; @@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; -static struct i2c_driver driver; -static struct i2c_client client_template; - - /* ---------------------------------------------------------------------- */ /* i2c I/O functions */ @@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n", - chip->c.name, val); + v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n", + chip->c->name, val); chip->shadow.bytes[1] = val; buffer[0] = val; - if (1 != i2c_master_send(&chip->c,buffer,1)) { - v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n", - chip->c.name, val); + if (1 != i2c_master_send(chip->c,buffer,1)) { + v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n", + chip->c->name, val); return -1; } } else { - v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n", - chip->c.name, subaddr, val); + v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n", + chip->c->name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; - if (2 != i2c_master_send(&chip->c,buffer,2)) { - v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n", - chip->c.name, subaddr, val); + if (2 != i2c_master_send(chip->c,buffer,2)) { + v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n", + chip->c->name, subaddr, val); return -1; } } @@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip) { unsigned char buffer; - if (1 != i2c_master_recv(&chip->c,&buffer,1)) { - v4l_warn(&chip->c, "%s: I/O error (read)\n", - chip->c.name); + if (1 != i2c_master_recv(chip->c,&buffer,1)) { + v4l_warn(chip->c, "%s: I/O error (read)\n", + chip->c->name); return -1; } - v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer); + v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer); return buffer; } @@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) unsigned char write[1]; unsigned char read[1]; struct i2c_msg msgs[2] = { - { chip->c.addr, 0, 1, write }, - { chip->c.addr, I2C_M_RD, 1, read } + { chip->c->addr, 0, 1, write }, + { chip->c->addr, I2C_M_RD, 1, read } }; write[0] = subaddr; - if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { - v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name); + if (2 != i2c_transfer(chip->c->adapter,msgs,2)) { + v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name); return -1; } - v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n", - chip->c.name, subaddr,read[0]); + v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n", + chip->c->name, subaddr,read[0]); return read[0]; } @@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:", - chip->c.name, name,cmd->bytes[0]); + v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:", + chip->c->name, name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { if (debug) printk(" 0x%x",cmd->bytes[i]); @@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) printk("\n"); /* send data to the chip */ - if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name); + if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) { + v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name); return -1; } return 0; @@ -269,7 +266,7 @@ static int chip_thread(void *data) struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name); set_freezable(); for (;;) { set_current_state(TASK_INTERRUPTIBLE); @@ -279,7 +276,7 @@ static int chip_thread(void *data) try_to_freeze(); if (kthread_should_stop()) break; - v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name); /* don't do anything for radio or if mode != auto */ if (chip->radio || chip->mode != 0) @@ -292,7 +289,7 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); } - v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name); return 0; } @@ -304,7 +301,7 @@ static void generic_checkmode(struct CHIPSTATE *chip) if (mode == chip->prevmode) return; - v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name); chip->prevmode = mode; if (mode & V4L2_TUNER_MODE_STEREO) @@ -353,7 +350,7 @@ static int tda9840_getmode(struct CHIPSTATE *chip) if (val & TDA9840_ST_STEREO) mode |= V4L2_TUNER_MODE_STEREO; - v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -657,7 +654,7 @@ static int tda9873_getmode(struct CHIPSTATE *chip) mode |= V4L2_TUNER_MODE_STEREO; if (val & TDA9873_DUAL) mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -668,12 +665,12 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n"); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n"); return; } - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { case V4L2_TUNER_MODE_MONO: @@ -694,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -833,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip) chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -876,7 +873,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } - v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -922,7 +919,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ @@ -957,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -971,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1097,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip) int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1, /* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF}; - if (chip->c.adapter->id == I2C_HW_B_RIVA) { + if (chip->c->adapter->id == I2C_HW_B_RIVA) { memcpy (desc->inputmap, inputmap, sizeof (inputmap)); } return 0; @@ -1185,7 +1182,7 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) }else if (!(val & TA8874Z_B0)){ mode |= V4L2_TUNER_MODE_STEREO; } - /* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ + /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1198,7 +1195,7 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); + v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ case V4L2_TUNER_MODE_MONO: @@ -1464,51 +1461,55 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_attach(struct i2c_adapter *adap, int addr, int kind) +static int chip_probe(struct i2c_client *client) { struct CHIPSTATE *chip; struct CHIPDESC *desc; + if (debug) { + printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); + printk(KERN_INFO "tvaudio: known chips: "); + for (desc = chiplist; desc->name != NULL; desc++) + printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); + printk("\n"); + } + chip = kzalloc(sizeof(*chip),GFP_KERNEL); if (!chip) return -ENOMEM; - memcpy(&chip->c,&client_template,sizeof(struct i2c_client)); - chip->c.adapter = adap; - chip->c.addr = addr; - i2c_set_clientdata(&chip->c, chip); + chip->c = client; + i2c_set_clientdata(client, chip); /* find description for the chip */ - v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1); + v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; - if (addr < desc->addr_lo || - addr > desc->addr_hi) + if (client->addr < desc->addr_lo || + client->addr > desc->addr_hi) continue; if (desc->checkit && !desc->checkit(chip)) continue; break; } if (desc->name == NULL) { - v4l_dbg(1, debug, &chip->c, "no matching chip description found\n"); + v4l_dbg(1, debug, client, "no matching chip description found\n"); return -EIO; } - v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); if (desc->flags) { - v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n", + v4l_dbg(1, debug, client, "matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); } /* fill required data structures */ - strcpy(chip->c.name, desc->name); + strcpy(client->name, desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; chip->audmode = V4L2_TUNER_MODE_LANG1; - /* register */ - i2c_attach_client(&chip->c); /* initialization */ if (desc->initialize != NULL) @@ -1535,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) init_timer(&chip->wt); chip->wt.function = chip_thread_wake; chip->wt.data = (unsigned long)chip; - chip->thread = kthread_run(chip_thread, chip, chip->c.name); + chip->thread = kthread_run(chip_thread, chip, chip->c->name); if (IS_ERR(chip->thread)) { - v4l_warn(&chip->c, "%s: failed to create kthread\n", - chip->c.name); + v4l_warn(chip->c, "%s: failed to create kthread\n", + chip->c->name); chip->thread = NULL; } } return 0; } -static int chip_probe(struct i2c_adapter *adap) -{ - /* don't attach on saa7146 based cards, - because dedicated drivers are used */ - if ((adap->id == I2C_HW_SAA7146)) - return 0; - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, chip_attach); - return 0; -} - -static int chip_detach(struct i2c_client *client) +static int chip_remove(struct i2c_client *client) { struct CHIPSTATE *chip = i2c_get_clientdata(client); @@ -1567,7 +1557,6 @@ static int chip_detach(struct i2c_client *client) chip->thread = NULL; } - i2c_detach_client(&chip->c); kfree(chip); return 0; } @@ -1693,7 +1682,7 @@ static int chip_command(struct i2c_client *client, struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd); + v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd); switch (cmd) { case AUDC_SET_RADIO: @@ -1830,44 +1819,25 @@ static int chip_command(struct i2c_client *client, return 0; } -static struct i2c_driver driver = { - .driver = { - .name = "tvaudio", - }, - .id = I2C_DRIVERID_TVAUDIO, - .attach_adapter = chip_probe, - .detach_client = chip_detach, - .command = chip_command, -}; - -static struct i2c_client client_template = -{ - .name = "(unset)", - .driver = &driver, -}; - -static int __init audiochip_init_module(void) -{ - struct CHIPDESC *desc; - - if (debug) { - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); - printk("\n"); - } - - return i2c_add_driver(&driver); -} - -static void __exit audiochip_cleanup_module(void) +static int chip_legacy_probe(struct i2c_adapter *adap) { - i2c_del_driver(&driver); + /* don't attach on saa7146 based cards, + because dedicated drivers are used */ + if ((adap->id == I2C_HW_SAA7146)) + return 0; + if (adap->class & I2C_CLASS_TV_ANALOG) + return 1; + return 0; } -module_init(audiochip_init_module); -module_exit(audiochip_cleanup_module); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tvaudio", + .driverid = I2C_DRIVERID_TVAUDIO, + .command = chip_command, + .probe = chip_probe, + .remove = chip_remove, + .legacy_probe = chip_legacy_probe, +}; /* * Local variables: -- cgit v1.2.3 From 266669776c12b92bab6e0bba4b3124ae920df194 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Sep 2007 04:58:06 -0300 Subject: V4L/DVB (6462): upd64083: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/upd64083.c | 68 ++++++++---------------------------------- 1 file changed, 12 insertions(+), 56 deletions(-) diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 401bd21f46e..08d2d643c65 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -27,6 +27,7 @@ #include #include #include +#include #include MODULE_DESCRIPTION("uPD64083 driver"); @@ -171,32 +172,18 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) +static int upd64083_probe(struct i2c_client *client) { - struct i2c_client *client; struct upd64083_state *state; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { - return -ENOMEM; - } - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "uPD64083"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } i2c_set_clientdata(client, state); @@ -207,53 +194,22 @@ static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) for (i = 0; i < TOT_REGS; i++) { upd64083_write(client, i, state->regs[i]); } - i2c_attach_client(client); - return 0; } -static int upd64083_probe(struct i2c_adapter *adapter) +static int upd64083_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, upd64083_attach); - return 0; -} - -static int upd64083_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "upd64083", - }, - .id = I2C_DRIVERID_UPD64083, - .attach_adapter = upd64083_probe, - .detach_client = upd64083_detach, + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "upd64083", + .driverid = I2C_DRIVERID_UPD64083, .command = upd64083_command, + .probe = upd64083_probe, + .remove = upd64083_remove, }; - - -static int __init upd64083_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit upd64083_exit_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(upd64083_init_module); -module_exit(upd64083_exit_module); -- cgit v1.2.3 From 2b14e0314631bac6388c4501f3103ab5af22c0f0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Sep 2007 04:58:31 -0300 Subject: V4L/DVB (6463): upd64031a: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/upd64031a.c | 69 +++++++---------------------------------- 1 file changed, 12 insertions(+), 57 deletions(-) diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 0b2a961efd2..b060ce34071 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -28,6 +28,7 @@ #include #include #include +#include #include // --------------------- read registers functions define ----------------------- @@ -193,32 +194,18 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) +static int upd64031a_probe(struct i2c_client *client) { - struct i2c_client *client; struct upd64031a_state *state; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { - return -ENOMEM; - } - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "uPD64031A"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } i2c_set_clientdata(client, state); @@ -229,54 +216,22 @@ static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) for (i = 0; i < TOT_REGS; i++) { upd64031a_write(client, i, state->regs[i]); } - - i2c_attach_client(client); - return 0; } -static int upd64031a_probe(struct i2c_adapter *adapter) +static int upd64031a_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, upd64031a_attach); - return 0; -} - -static int upd64031a_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "upd64031a", - }, - .id = I2C_DRIVERID_UPD64031A, - .attach_adapter = upd64031a_probe, - .detach_client = upd64031a_detach, + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "upd64031a", + .driverid = I2C_DRIVERID_UPD64031A, .command = upd64031a_command, + .probe = upd64031a_probe, + .remove = upd64031a_remove, }; - - -static int __init upd64031a_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit upd64031a_exit_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(upd64031a_init_module); -module_exit(upd64031a_exit_module); -- cgit v1.2.3 From 6235168db8ed96c587e566be0dd72a77ca212693 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Sep 2007 05:03:17 -0300 Subject: V4L/DVB (6464): tlv320aic23b: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tlv320aic23b.c | 71 +++++++------------------------------- 1 file changed, 13 insertions(+), 58 deletions(-) diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 76b2e96429d..0282f385bbd 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -31,6 +31,7 @@ #include #include #include +#include MODULE_DESCRIPTION("tlv320aic23b driver"); MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); @@ -126,31 +127,18 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind) +static int tlv320aic23b_probe(struct i2c_client *client) { - struct i2c_client *client; struct tlv320aic23b_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } state->muted = 0; @@ -163,55 +151,22 @@ static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kin tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ - - i2c_attach_client(client); - return 0; } -static int tlv320aic23b_probe(struct i2c_adapter *adapter) +static int tlv320aic23b_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, tlv320aic23b_attach); - return 0; -} - -static int tlv320aic23b_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "tlv320aic23b", - }, - .id = I2C_DRIVERID_TLV320AIC23B, - .attach_adapter = tlv320aic23b_probe, - .detach_client = tlv320aic23b_detach, - .command = tlv320aic23b_command, -}; - -static int __init tlv320aic23b_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit tlv320aic23b_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(tlv320aic23b_init_module); -module_exit(tlv320aic23b_cleanup_module); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tlv320aic23b", + .driverid = I2C_DRIVERID_TLV320AIC23B, + .command = tlv320aic23b_command, + .probe = tlv320aic23b_probe, + .remove = tlv320aic23b_remove, +}; -- cgit v1.2.3 From 188f3457c21ac7869005021b56b4578293c644bb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 16 Sep 2007 10:47:15 -0300 Subject: V4L/DVB (6465): Use correct error codes when chip is not recognized If the chip isn't recognized, then the correct errors should be returned. The v4l2_i2c_attach() utility function will return 0 for all errors except -ENOMEM to provide proper compatibility support for the old I2C probing function. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs53l32a.c | 2 +- drivers/media/video/cx25840/cx25840-core.c | 6 +++++- drivers/media/video/msp3400-driver.c | 4 ++-- drivers/media/video/saa7115.c | 4 ++-- drivers/media/video/saa7127.c | 6 +++--- drivers/media/video/tlv320aic23b.c | 2 +- drivers/media/video/upd64031a.c | 2 +- drivers/media/video/upd64083.c | 2 +- drivers/media/video/v4l2-common.c | 2 +- drivers/media/video/vp27smpx.c | 2 +- drivers/media/video/wm8739.c | 4 ++++ 11 files changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index e43febb9d16..65bb6afd8df 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -140,7 +140,7 @@ static int cs53l32a_probe(struct i2c_client *client) /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 1556e2fad4c..6d2ca822a63 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1078,6 +1078,10 @@ static int cx25840_probe(struct i2c_client *client) u32 id; u16 device_id; + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; @@ -1093,7 +1097,7 @@ static int cx25840_probe(struct i2c_client *client) } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - return 0; + return -ENODEV; } state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index f2946aca129..f4c14604b0b 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -812,7 +812,7 @@ static int msp_probe(struct i2c_client *client) if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - return 0; + return -ENODEV; } state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -844,7 +844,7 @@ static int msp_probe(struct i2c_client *client) if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); kfree(state); - return 0; + return -ENODEV; } msp_set_audio(client); diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index ad60335544f..41e5e518a47 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1459,7 +1459,7 @@ static int saa7115_probe(struct i2c_client *client) /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); @@ -1478,7 +1478,7 @@ static int saa7115_probe(struct i2c_client *client) if (memcmp(name, "1f711", 5)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", client->addr << 1, name); - return 0; + return -ENODEV; } snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 958ecc7168c..0262acde088 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -671,7 +671,7 @@ static int saa7127_probe(struct i2c_client *client) /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; snprintf(client->name, sizeof(client->name) - 1, "saa7127"); @@ -685,12 +685,12 @@ static int saa7127_probe(struct i2c_client *client) if ((saa7127_read(client, 0) & 0xe4) != 0 || (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { v4l_dbg(1, debug, client, "saa7127 not found\n"); - return 0; + return -ENODEV; } state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); if (state == NULL) { - return (-ENOMEM); + return -ENOMEM; } i2c_set_clientdata(client, state); diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 0282f385bbd..e906528348a 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -133,7 +133,7 @@ static int tlv320aic23b_probe(struct i2c_client *client) /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index b060ce34071..0318432d85f 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -200,7 +200,7 @@ static int upd64031a_probe(struct i2c_client *client) int i; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 08d2d643c65..7e32c5b0c29 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -178,7 +178,7 @@ static int upd64083_probe(struct i2c_client *client) int i; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 32607a612b1..61ebdb0afa1 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -1037,7 +1037,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver else { kfree(client); } - return err; + return err != -ENOMEM ? 0 : err; } /* ----------------------------------------------------------------- */ diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 24a94231504..97e24769e65 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -131,7 +131,7 @@ static int vp27smpx_probe(struct i2c_client *client) /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + return -EIO; snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 459228a5cf5..3d9e709833c 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -264,6 +264,10 @@ static int wm8739_probe(struct i2c_client *client) { struct wm8739_state *state; + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); -- cgit v1.2.3 From a2e521e85c04af3511af3ea8971efb4ef8bde533 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Sep 2007 05:13:45 -0300 Subject: V4L/DVB (6466): v4l2-i2c-drv: first call remove, then detach client The remove driver function expects that the client is still attached to the driver, so do the detach after calling remove(). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-i2c-drv-legacy.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h index 433c984eefa..241854229d6 100644 --- a/include/media/v4l2-i2c-drv-legacy.h +++ b/include/media/v4l2-i2c-drv-legacy.h @@ -58,12 +58,14 @@ static int v4l2_i2c_drv_probe_legacy(struct i2c_adapter *adapter) static int v4l2_i2c_drv_detach_legacy(struct i2c_client *client) { - int err = i2c_detach_client(client); + int err; - if (err) - return err; if (v4l2_i2c_data.remove) v4l2_i2c_data.remove(client); + + err = i2c_detach_client(client); + if (err) + return err; kfree(client); return 0; -- cgit v1.2.3 From 393bf5573269979aa3fb55d1bdd0db4fcb288f99 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 18 Sep 2007 03:22:32 -0300 Subject: V4L/DVB (6467): v4l2-common: minor cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 61ebdb0afa1..c056ff6d810 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -1028,13 +1028,12 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver client->addr = address; client->adapter = adapter; client->driver = driver; - snprintf(client->name, sizeof(client->name) - 1, name); + strlcpy(client->name, name, sizeof(client->name)); err = probe(client); if (err == 0) { i2c_attach_client(client); - } - else { + } else { kfree(client); } return err != -ENOMEM ? 0 : err; -- cgit v1.2.3 From 8c125f2ceb3ec1ba01e96fffd8558ef163b40fe8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 27 Oct 2007 02:00:57 -0300 Subject: V4L/DVB (6468): tda8290: auto-detect tda8290 or tda8295 Consolidate tda8290_attach() and tda8295_attach() into a single function, tda829x_attach(), which will detect chip combinations tda8290 or tda8295 with tda8275, tda8275a or tda18271. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 257 +++++++++++++++++++-------------------- drivers/media/video/tda8290.h | 12 +- drivers/media/video/tuner-core.c | 6 +- 3 files changed, 127 insertions(+), 148 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 5975c548b8a..ed22be0f594 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -41,7 +41,13 @@ struct tda8290_priv { unsigned char tda8290_easy_mode; unsigned char tda827x_addr; - unsigned char tda827x_ver; + + unsigned char ver; +#define TDA8290 1 +#define TDA8295 2 +#define TDA8275 4 +#define TDA8275A 8 +#define TDA18271 16 struct tda827x_config cfg; @@ -136,7 +142,7 @@ static void set_audio(struct dvb_frontend *fe) mode = "xx"; } - tuner_dbg("setting tda8290 to system %s\n", mode); + tuner_dbg("setting tda829x to system %s\n", mode); } static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) @@ -429,7 +435,7 @@ static void tda8290_standby(struct dvb_frontend *fe) struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; tda8290_i2c_bridge(fe, 1); - if (priv->tda827x_ver != 0) + if (priv->ver & TDA8275A) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); tda8290_i2c_bridge(fe, 0); @@ -498,7 +504,7 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=tda8275_init, .len = 14}; - if (priv->tda827x_ver != 0) + if (priv->ver & TDA8275A) msg.buf = tda8275a_init; tda8290_i2c_bridge(fe, 1); @@ -517,48 +523,25 @@ static void tda829x_release(struct dvb_frontend *fe) fe->analog_demod_priv = NULL; } -static struct analog_tuner_ops tda8290_tuner_ops = { - .set_tv_freq = tda8290_set_freq, - .set_radio_freq = tda8290_set_freq, - .has_signal = tda8290_has_signal, - .standby = tda8290_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8290_i2c_bridge, -}; - -static struct analog_tuner_ops tda8295_tuner_ops = { - .set_tv_freq = tda8295_set_freq, - .set_radio_freq = tda8295_set_freq, - .has_signal = tda8295_has_signal, - .standby = tda8295_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8295_i2c_bridge, -}; - -int tda8290_attach(struct tuner *t) +static int tda829x_find_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = NULL; - u8 data; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + struct tuner *t = priv->t; int i, ret, tuners_found; u32 tuner_addrs; - struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1}; + u8 data; + struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - t->fe.analog_demod_priv = priv; + if (NULL == ops) + return -EINVAL; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; - priv->cfg.config = &t->config; - priv->cfg.tuner_callback = t->tuner_callback; - priv->t = t; + ops->i2c_gate_ctrl(fe, 1); - tda8290_i2c_bridge(&t->fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; - for (i=0x60; i<= 0x63; i++) { + for (i = 0x60; i <= 0x63; i++) { msg.addr = i; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { @@ -570,20 +553,23 @@ int tda8290_attach(struct tuner *t) behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(&t->fe, 0); - if(tuners_found > 1) + + ops->i2c_gate_ctrl(fe, 0); + + if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if(ret == 1) + if (ret == 1) tuner_addrs = tuner_addrs >> 8; else break; } + if (tuner_addrs == 0) { - tuner_addrs = 0x61; - tuner_info("could not clearly identify tuner address, defaulting to %x\n", - tuner_addrs); + tuner_addrs = 0x60; + tuner_info("could not clearly identify tuner address, " + "defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; tuner_info("setting tuner address to %x\n", tuner_addrs); @@ -591,127 +577,132 @@ int tda8290_attach(struct tuner *t) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(&t->fe, 1); - + ops->i2c_gate_ctrl(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if( ret != 1) - tuner_warn("TDA827x access failed!\n"); - if ((data & 0x3c) == 0) { - strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); - priv->tda827x_ver = 0; - } else { - strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); - priv->tda827x_ver = 2; + if (ret != 1) { + tuner_warn("tuner access failed!\n"); + return -EREMOTEIO; } - tda827x_attach(&t->fe, priv->tda827x_addr, - priv->i2c_props.adap, &priv->cfg); - /* FIXME: tda827x module doesn't probe the tuner until - * tda827x_initial_sleep is called - */ - if (t->fe.ops.tuner_ops.sleep) - t->fe.ops.tuner_ops.sleep(&t->fe); + if (data == 0x83) { + priv->ver |= TDA18271; + tda18271_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap); + } else { + if ((data & 0x3c) == 0) + priv->ver |= TDA8275; + else + priv->ver |= TDA8275A; - t->fe.ops.analog_demod_ops = &tda8290_tuner_ops; + tda827x_attach(&t->fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); - tuner_info("type set to %s\n", t->i2c.name); + /* FIXME: tda827x module doesn't probe the tuner until + * tda827x_initial_sleep is called + */ + if (t->fe.ops.tuner_ops.sleep) + t->fe.ops.tuner_ops.sleep(&t->fe); + } + ops->i2c_gate_ctrl(fe, 0); - t->mode = V4L2_TUNER_ANALOG_TV; + switch (priv->ver) { + case TDA8290 | TDA8275: + strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); + break; + case TDA8295 | TDA8275: + strlcpy(t->i2c.name, "tda8295+75", sizeof(t->i2c.name)); + break; + case TDA8290 | TDA8275A: + strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); + break; + case TDA8295 | TDA8275A: + strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); + break; + case TDA8290 | TDA18271: + strlcpy(t->i2c.name, "tda8290+18271", sizeof(t->i2c.name)); + break; + case TDA8295 | TDA18271: + strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); + break; + default: + return -EINVAL; + } - tda8290_init_tuner(&t->fe); - tda8290_init_if(&t->fe); return 0; } -EXPORT_SYMBOL_GPL(tda8290_attach); -int tda8295_attach(struct tuner *t) +static struct analog_tuner_ops tda8290_tuner_ops = { + .set_tv_freq = tda8290_set_freq, + .set_radio_freq = tda8290_set_freq, + .has_signal = tda8290_has_signal, + .standby = tda8290_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8290_i2c_bridge, +}; + +static struct analog_tuner_ops tda8295_tuner_ops = { + .set_tv_freq = tda8295_set_freq, + .set_radio_freq = tda8295_set_freq, + .has_signal = tda8295_has_signal, + .standby = tda8295_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8295_i2c_bridge, +}; + +int tda829x_attach(struct tuner *t) { + struct dvb_frontend *fe = &t->fe; struct tda8290_priv *priv = NULL; - u8 data; - int i, ret, tuners_found; - u32 tuner_addrs; - struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; + + unsigned char tda8290_id[] = { 0x1f, 0x00 }; +#define TDA8290_ID 0x89 + unsigned char tda8295_id[] = { 0x2f, 0x00 }; +#define TDA8295_ID 0x8a priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - t->fe.analog_demod_priv = priv; + fe->analog_demod_priv = priv; priv->i2c_props.addr = t->i2c.addr; priv->i2c_props.adap = t->i2c.adapter; + priv->cfg.config = &t->config; + priv->cfg.tuner_callback = t->tuner_callback; priv->t = t; - tda8295_i2c_bridge(&t->fe, 1); - /* probe for tuner chip */ - tuners_found = 0; - tuner_addrs = 0; - for (i = 0x60; i <= 0x63; i++) { - msg.addr = i; - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) { - tuners_found++; - tuner_addrs = (tuner_addrs << 8) + i; - } + /* detect tda8290 */ + tuner_i2c_xfer_send(&priv->i2c_props, &tda8290_id[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &tda8290_id[1], 1); + if (tda8290_id[1] == TDA8290_ID) { + priv->ver = TDA8290; + fe->ops.analog_demod_ops = &tda8290_tuner_ops; } - /* if there is more than one tuner, we expect the right one is - behind the bridge and we choose the highest address that doesn't - give a response now - */ - tda8295_i2c_bridge(&t->fe, 0); - if (tuners_found > 1) - for (i = 0; i < tuners_found; i++) { - msg.addr = tuner_addrs & 0xff; - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) - tuner_addrs = tuner_addrs >> 8; - else - break; - } - if (tuner_addrs == 0) { - tuner_addrs = 0x60; - tuner_info("could not clearly identify tuner address, " - "defaulting to %x\n", tuner_addrs); - } else { - tuner_addrs = tuner_addrs & 0xff; - tuner_info("setting tuner address to %x\n", tuner_addrs); + + /* detect tda8295 */ + tuner_i2c_xfer_send(&priv->i2c_props, &tda8295_id[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &tda8295_id[1], 1); + if (tda8295_id[1] == TDA8295_ID) { + priv->ver = TDA8295; + fe->ops.analog_demod_ops = &tda8295_tuner_ops; } - priv->tda827x_addr = tuner_addrs; - msg.addr = tuner_addrs; - tda8295_i2c_bridge(&t->fe, 1); - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8295_i2c_bridge(&t->fe, 0); - if (ret != 1) - tuner_warn("TDA827x access failed!\n"); - if ((data & 0x3c) == 0) { - strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); - tda18271_attach(&t->fe, priv->tda827x_addr, - priv->i2c_props.adap); - priv->tda827x_ver = 4; - } else { - strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); - tda827x_attach(&t->fe, priv->tda827x_addr, - priv->i2c_props.adap, &priv->cfg); + if (tda829x_find_tuner(fe) < 0) + return -EINVAL; - /* FIXME: tda827x module doesn't probe the tuner until - * tda827x_initial_sleep is called - */ - if (t->fe.ops.tuner_ops.sleep) - t->fe.ops.tuner_ops.sleep(&t->fe); - priv->tda827x_ver = 2; - } - priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */ - tuner_info("type set to %s\n", t->i2c.name); + if (priv->ver & TDA8290) { + tda8290_init_tuner(fe); + tda8290_init_if(fe); + } else if (priv->ver & TDA8295) + tda8295_init_if(fe); - t->fe.ops.analog_demod_ops = &tda8295_tuner_ops; + tuner_info("type set to %s\n", t->i2c.name); t->mode = V4L2_TUNER_ANALOG_TV; - tda8295_init_if(&t->fe); return 0; } -EXPORT_SYMBOL_GPL(tda8295_attach); +EXPORT_SYMBOL_GPL(tda829x_attach); int tda8290_probe(struct tuner *t) { @@ -745,7 +736,7 @@ int tda8290_probe(struct tuner *t) } EXPORT_SYMBOL_GPL(tda8290_probe); -MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); +MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index dbbcb0f001e..81517370b8d 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -23,8 +23,7 @@ #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda8290_probe(struct tuner *t); -extern int tda8290_attach(struct tuner *t); -extern int tda8295_attach(struct tuner *t); +extern int tda829x_attach(struct tuner *t); #else static inline int tda8290_probe(struct tuner *t) { @@ -32,14 +31,7 @@ static inline int tda8290_probe(struct tuner *t) return -EINVAL; } -static inline int tda8290_attach(struct tuner *t) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __FUNCTION__); - return -EINVAL; -} - -static inline int tda8295_attach(struct tuner *t) +static inline int tda829x_attach(struct tuner *t) { printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", __FUNCTION__); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 88db8b33c86..6ab57ec3f5a 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -295,13 +295,9 @@ static void set_type(struct i2c_client *c, unsigned int type, microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: - { - tda8290_attach(t); - break; - } case TUNER_PHILIPS_TDA8295: { - tda8295_attach(t); + tda829x_attach(t); break; } case TUNER_TEA5767: -- cgit v1.2.3 From 0b5f4a12e628893624b478523fb4e2708c605710 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 27 Oct 2007 13:09:16 -0300 Subject: V4L/DVB (6469): tuner: remove TUNER_PHILIPS_TDA8295 TUNER_PHILIPS_TDA8290 will autodetect a TDA8290 or a TDA8295, so we don't need this separate entry anymore. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 3 +-- drivers/media/video/tuner-core.c | 1 - drivers/media/video/tuner-types.c | 5 +---- drivers/media/video/tveeprom.c | 2 +- include/media/tuner.h | 2 -- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index ac47b48715d..2211c8eac64 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -52,7 +52,7 @@ tuner=50 - TCL 2002N tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3) tuner=52 - Thomson DTT 7610 (ATSC/NTSC) tuner=53 - Philips FQ1286 -tuner=54 - tda8290+75 +tuner=54 - Philips/NXP TDA 8290/8295 + 8275/8275A/18271 tuner=55 - TCL 2002MB tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4) tuner=57 - Philips FQ1236A MK4 @@ -73,4 +73,3 @@ tuner=71 - Xceive xc2028/xc3028 tuner tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio -tuner=76 - tda8295+18271 diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6ab57ec3f5a..600174239d0 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -295,7 +295,6 @@ static void set_type(struct i2c_client *c, unsigned int type, microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: - case TUNER_PHILIPS_TDA8295: { tda829x_attach(t); break; diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 4a674c436cf..e2cd05a0580 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1366,7 +1366,7 @@ struct tunertype tuners[] = { .count = ARRAY_SIZE(tuner_philips_fq1286_params), }, [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ - .name = "tda8290+75", + .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", /* see tda8290.c for details */ }, [TUNER_TCL_2002MB] = { /* TCL PAL */ .name = "TCL 2002MB", @@ -1475,9 +1475,6 @@ struct tunertype tuners[] = { .name = "Philips TEA5761 FM Radio", /* see tea5767.c for details */ }, - [TUNER_PHILIPS_TDA8295] = { /* Philips PAL|NTSC */ - .name = "tda8295+18271", - /* see tda8290.c for details */ }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 27bfe6d3a33..0faa1499235 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -257,7 +257,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "LG TAPQ_H702F"}, { TUNER_ABSENT, "TCL M09WPP_4N_E"}, { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_PHILIPS_TDA8295, "Philips 18271_8295"}, + { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, }; static struct HAUPPAUGE_AUDIOIC diff --git a/include/media/tuner.h b/include/media/tuner.h index faacd2d50b7..d49392d90e5 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -124,8 +124,6 @@ extern int tuner_debug; #define TUNER_TDA9887 74 /* This tuner should be used only internally */ #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ -#define TUNER_PHILIPS_TDA8295 76 - /* tv card specific */ #define TDA9887_PRESENT (1<<0) #define TDA9887_PORT1_INACTIVE (1<<1) -- cgit v1.2.3 From 1a156045ab06b2cce8cf46e7bf53da26ab33b084 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 11:33:18 -0300 Subject: V4L/DVB (6470): Avoid breaking compilation The next patchset series will change i2c structs inside tuner. This patch avoids breaking bissect, by commenting the still unused tuner xc2028. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 600174239d0..bff6e6a3e26 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -335,18 +335,6 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c,buffer,4); attach_simple_tuner(t); break; - case TUNER_XC2028: - { - int rc=xc2028_attach(&t->fe, t->i2c.adapter, t->i2c.addr, - &c->dev, c->adapter->algo_data, - t->tuner_callback); - if (rc<0) { - t->type = TUNER_ABSENT; - t->mode_mask = T_UNINITIALIZED; - return; - } - break; - } case TUNER_TDA9887: tda9887_attach(t); break; -- cgit v1.2.3 From 1cba97d71dca1a3c22b4d7f97893249817036215 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 14 Sep 2007 05:13:54 -0300 Subject: V4L/DVB (6471): tuner: i2c_client cannot be part of the tuner struct The bus-based I2C subsystem allocates the i2c_client struct. So if in order to be able to convert the tuner to the bus-based I2C API the embedded i2c_client struct must be removed from the tuner struct and replaced with a pointer. Signed-off-by: Hans Verkuil Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 22 ++++++++-------- drivers/media/video/tda9887.c | 22 ++++++++-------- drivers/media/video/tuner-core.c | 51 ++++++++++++++++++++++---------------- drivers/media/video/tuner-driver.h | 14 +++++------ 4 files changed, 59 insertions(+), 50 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index ed22be0f594..c7705cbab2f 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -608,22 +608,22 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) switch (priv->ver) { case TDA8290 | TDA8275: - strlcpy(t->i2c.name, "tda8290+75", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda8290+75", sizeof(t->i2c->name)); break; case TDA8295 | TDA8275: - strlcpy(t->i2c.name, "tda8295+75", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda8295+75", sizeof(t->i2c->name)); break; case TDA8290 | TDA8275A: - strlcpy(t->i2c.name, "tda8290+75a", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda8290+75a", sizeof(t->i2c->name)); break; case TDA8295 | TDA8275A: - strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda8295+75a", sizeof(t->i2c->name)); break; case TDA8290 | TDA18271: - strlcpy(t->i2c.name, "tda8290+18271", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda8290+18271", sizeof(t->i2c->name)); break; case TDA8295 | TDA18271: - strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda8295+18271", sizeof(t->i2c->name)); break; default: return -EINVAL; @@ -665,8 +665,8 @@ int tda829x_attach(struct tuner *t) return -ENOMEM; fe->analog_demod_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = t->i2c->addr; + priv->i2c_props.adap = t->i2c->adapter; priv->cfg.config = &t->config; priv->cfg.tuner_callback = t->tuner_callback; priv->t = t; @@ -696,7 +696,7 @@ int tda829x_attach(struct tuner *t) } else if (priv->ver & TDA8295) tda8295_init_if(fe); - tuner_info("type set to %s\n", t->i2c.name); + tuner_info("type set to %s\n", t->i2c->name); t->mode = V4L2_TUNER_ANALOG_TV; @@ -707,8 +707,8 @@ EXPORT_SYMBOL_GPL(tda829x_attach); int tda8290_probe(struct tuner *t) { struct tuner_i2c_props i2c_props = { - .adap = t->i2c.adapter, - .addr = t->i2c.addr + .adap = t->i2c->adapter, + .addr = t->i2c->addr }; unsigned char soft_reset[] = { 0x00, 0x00 }; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 080bd308073..dfa2964d7ef 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -24,14 +24,14 @@ static int tda9887_debug; module_param_named(debug, tda9887_debug, int, 0644); #define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \ - i2c_adapter_id(priv->t->i2c.adapter), \ - priv->t->i2c.addr, ##arg); } while (0) + printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \ + i2c_adapter_id(priv->t->i2c->adapter), \ + priv->t->i2c->addr, ##arg); } while (0) #define tda9887_dbg(fmt, arg...) do {\ if (tda9887_debug) \ - printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \ - i2c_adapter_id(priv->t->i2c.adapter), \ - priv->t->i2c.addr, ##arg); } while (0) + printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \ + i2c_adapter_id(priv->t->i2c->adapter), \ + priv->t->i2c->addr, ##arg); } while (0) struct tda9887_priv { struct tuner_i2c_props i2c_props; @@ -651,14 +651,14 @@ int tda9887_attach(struct tuner *t) return -ENOMEM; t->fe.analog_demod_priv = priv; - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + priv->i2c_props.addr = t->i2c->addr; + priv->i2c_props.adap = t->i2c->adapter; priv->t = t; - strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); + strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name)); - tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, - t->i2c.driver->driver.name); + tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr, + t->i2c->driver->driver.name); t->fe.ops.analog_demod_ops = &tda9887_tuner_ops; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index bff6e6a3e26..41ff4d2604a 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -226,20 +226,20 @@ static void set_freq(struct i2c_client *c, unsigned long freq) static void tuner_i2c_address_check(struct tuner *t) { if ((t->type == UNSET || t->type == TUNER_ABSENT) || - ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f))) return; tuner_warn("====================== WARNING! ======================\n"); tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); tuner_warn("will soon be dropped. This message indicates that your\n"); tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", - t->i2c.name, t->i2c.addr); + t->i2c->name, t->i2c->addr); tuner_warn("To ensure continued support for your device, please\n"); tuner_warn("send a copy of this message, along with full dmesg\n"); tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", - t->i2c.adapter->name, t->i2c.addr, t->type, + t->i2c->adapter->name, t->i2c->addr, t->type, tuners[t->type].name); tuner_warn("====================== WARNING! ======================\n"); } @@ -250,7 +250,7 @@ static void attach_simple_tuner(struct tuner *t) .type = t->type, .tun = &tuners[t->type] }; - simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); + simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } static void set_type(struct i2c_client *c, unsigned int type, @@ -292,7 +292,7 @@ static void set_type(struct i2c_client *c, unsigned int type, switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); + microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_PHILIPS_TDA8290: { @@ -300,7 +300,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { + if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -308,7 +308,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { + if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -348,13 +348,14 @@ static void set_type(struct i2c_client *c, unsigned int type, if (((NULL == ops) || ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) && (fe_tuner_ops->set_analog_params)) { - strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + strlcpy(t->i2c->name, fe_tuner_ops->info.name, + sizeof(t->i2c->name)); t->fe.ops.analog_demod_ops = &tuner_core_ops; t->fe.analog_demod_priv = t; } - tuner_info("type set to %s\n", t->i2c.name); + tuner_info("type set to %s\n", t->i2c->name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -579,16 +580,23 @@ static unsigned default_mode_mask; */ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { + struct i2c_client *client; struct tuner *t; - client_template.adapter = adap; - client_template.addr = addr; + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (NULL == client) + return -ENOMEM; t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) + if (NULL == t) { + kfree(client); return -ENOMEM; - memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); - i2c_set_clientdata(&t->i2c, t); + } + t->i2c = client; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(client, t); t->type = UNSET; t->audmode = V4L2_TUNER_MODE_STEREO; t->mode_mask = T_UNINITIALIZED; @@ -598,7 +606,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) int i,rc; memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer)); + rc = i2c_master_recv(client, buffer, sizeof(buffer)); tuner_info("I2C RECV = "); for (i=0;ii2c.adapter, t->i2c.addr) != EINVAL) { + if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -639,7 +647,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } break; case 0x60: - if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { + if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -664,8 +672,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) /* Should be just before return */ register_client: tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); - i2c_attach_client (&t->i2c); - set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); + i2c_attach_client (client); + set_type (client,t->type, t->mode_mask, t->config, t->tuner_callback); return 0; } @@ -711,7 +719,7 @@ static int tuner_detach(struct i2c_client *client) struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; int err; - err = i2c_detach_client(&t->i2c); + err = i2c_detach_client(t->i2c); if (err) { tuner_warn ("Client deregistration failed, client not detached.\n"); @@ -722,6 +730,7 @@ static int tuner_detach(struct i2c_client *client) ops->release(&t->fe); kfree(t); + kfree(client); return 0; } @@ -770,7 +779,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; if (tuner_debug>1) - v4l_i2c_print_ioctl(&(t->i2c),cmd); + v4l_i2c_print_ioctl(client,cmd); switch (cmd) { /* --- configuration --- */ diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 728cacd2168..0df136e58eb 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -45,7 +45,7 @@ struct analog_tuner_ops { struct tuner { /* device */ - struct i2c_client i2c; + struct i2c_client *i2c; unsigned int type; /* chip type */ @@ -71,16 +71,16 @@ struct tuner { /* ------------------------------------------------------------------------ */ #define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c->driver->driver.name, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c->driver->driver.name, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #define tuner_dbg(fmt, arg...) do {\ extern int tuner_debug; \ if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c->driver->driver.name, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #endif /* __TUNER_DRIVER_H__ */ -- cgit v1.2.3 From 690c544cf849e627d3f40a71633d0caf5c33eafe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 11:33:18 -0300 Subject: V4L/DVB (6472): Re-inserts xc2028 attach code, fixing its parameters I2C bus redesign changed i2c parameters. This patch re-adds tuner xc2028 attach function, replacing the parameters to the newer syntax. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 41ff4d2604a..11abd188b17 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -335,6 +335,18 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c,buffer,4); attach_simple_tuner(t); break; + case TUNER_XC2028: + { + int rc=xc2028_attach(&t->fe, t->i2c->adapter, t->i2c->addr, + &c->dev, c->adapter->algo_data, + t->tuner_callback); + if (rc<0) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + break; + } case TUNER_TDA9887: tda9887_attach(t); break; -- cgit v1.2.3 From 48aa336a842ad3bd4f031f14fb6d06b0274c38f9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 11:33:18 -0300 Subject: V4L/DVB (6473): Prevents double tuner registering Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 11abd188b17..cd5f0d8e693 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -279,8 +279,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->tuner_callback = tuner_callback; } - /* This code detects calls by card attach_inform */ - if (NULL == t->i2c.dev.driver) { + if (t->mode == T_UNINITIALIZED) { tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); return; @@ -684,6 +683,16 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) /* Should be just before return */ register_client: tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); + + /* Sets a default mode */ + if (t->mode_mask & T_ANALOG_TV) { + t->mode = T_ANALOG_TV; + } else if (t->mode_mask & T_RADIO) { + t->mode = T_RADIO; + } else { + t->mode = T_DIGITAL_TV; + } + i2c_attach_client (client); set_type (client,t->type, t->mode_mask, t->config, t->tuner_callback); return 0; -- cgit v1.2.3 From 882876bf9780fac570184b719a76140a1b1e4178 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 11:33:18 -0300 Subject: V4L/DVB (6474): Add support for tuner-xc2028 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 2d72de0e756..98dc1201907 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -35,6 +35,7 @@ #include #include "em28xx.h" +#include "tuner-xc2028.h" struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { @@ -362,6 +363,21 @@ void em28xx_pre_card_setup(struct em28xx *dev) } } +static void em28xx_config_tuner (struct em28xx *dev) +{ + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset (&ctl,0,sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); +} + void em28xx_card_setup(struct em28xx *dev) { /* request some modules */ @@ -394,6 +410,7 @@ void em28xx_card_setup(struct em28xx *dev) } } + em28xx_config_tuner (dev); } MODULE_DEVICE_TABLE (usb, em28xx_id_table); -- cgit v1.2.3 From 1808a698a87366f9d82945270355c2139df0a16d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 17:38:59 -0300 Subject: V4L/DVB (6475): Fix some troubles at list handling - priv->count were wrong. Should be incremented since the first usage; - forgot to use list_del() to remove the driver; - Release memory if an error occurs during _attach Thanks to Aidan Thornton for pointing this. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 7d53d58aafa..c5bdeff5428 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -639,6 +639,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) priv->count--; if (!priv->count) { + list_del(&priv->xc2028_list); + if (priv->ctrl.fname) kfree(priv->ctrl.fname); @@ -728,7 +730,6 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, list_for_each_entry(priv, &xc2028_list, xc2028_list) { if (priv->dev == dev) { dev = NULL; - priv->count++; } } @@ -754,6 +755,7 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, list_add_tail(&priv->xc2028_list,&xc2028_list); } + priv->count++; memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, sizeof(xc2028_dvb_tuner_ops)); -- cgit v1.2.3 From 6c362c8e58da972728a3666a0a00b9c2f1574e1f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 23:36:12 -0300 Subject: V4L/DVB (6476): Add support for analog tv on HVR-950 This patch adds USB ID for HVR-950. It also adds the callback for handling firmware loading. Thanks to Markus Reichberger for the reset commands. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 1 + drivers/media/video/em28xx/em28xx-i2c.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 98dc1201907..61b0c5a55df 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -344,6 +344,7 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index e48191fb1dd..a33878e0879 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -28,6 +28,7 @@ #include #include "em28xx.h" +#include "tuner-xc2028.h" #include #include @@ -391,6 +392,26 @@ static u32 functionality(struct i2c_adapter *adap) } +static int em28xx_tuner_callback(void *ptr, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + switch (command) { + case XC2028_TUNER_RESET: + /* FIXME: This is device-dependent */ + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); + + msleep(140); + break; + } + return rc; +} + static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) { struct em28xx *dev = client->adapter->algo_data; @@ -400,6 +421,8 @@ static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; tun_setup.type = dev->tuner_type; tun_setup.addr = dev->tuner_addr; + tun_setup.tuner_callback = em28xx_tuner_callback; + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); } -- cgit v1.2.3 From 983d214e08010c7b3c1997dc9cab7fa0984446f0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Oct 2007 23:44:18 -0300 Subject: V4L/DVB (6477): Properly fill MODULE_AUTHOR Most of the driver were written by Mauro Carvalho Chehab. DTV parts were added by Michel Ludwig. Reviewed-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index c5bdeff5428..813b54971e1 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -1,8 +1,10 @@ /* tuner-xc2028 * * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) * - frontend interface + * * This code is placed under the terms of the GNU General Public License v2 */ @@ -768,5 +770,6 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, EXPORT_SYMBOL(xc2028_attach); MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); +MODULE_AUTHOR("Michel Ludwig "); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 073ad9a00c653ac4a1668c324dd132c9996473f1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 29 Oct 2007 15:19:45 -0300 Subject: V4L/DVB (6480): bttv: uses input functions, should depend on INPUT Several media drivers use input_(*) functions so they need to depend on the INPUT config symbol. drivers/built-in.o: In function `bttv_input_fini': linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:346: undefined reference to `input_unregister_device' drivers/built-in.o: In function `bttv_input_init': linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:204: undefined reference to `input_allocate_device' linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:335: undefined reference to `input_free_device' linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:321: undefined reference to `input_register_device' linux-2.6.24-rc1-git4/drivers/media/video/bt8xx/bttv-input.c:335: undefined reference to `input_free_device' Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index ce93312cf84..cfc822bb502 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX -- cgit v1.2.3 From c7ac61c4693da113fd067ccfa4246df1e8a5c75e Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Sun, 28 Oct 2007 23:41:19 -0300 Subject: V4L/DVB (6481): radio-gemtek: make file_operations const make file_operations const Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 5e4b9ddb23c..d69412f587f 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; -static struct file_operations gemtek_fops = { +static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, -- cgit v1.2.3 From bdd36658fe7cce3b7dbb6ffb72ad0c9500d57e7a Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Mon, 29 Oct 2007 00:37:07 -0300 Subject: V4L/DVB (6482): zr364: make file_operations const zr364: make file_operations const Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zr364xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 6f1892585cb..1fdbb46de7f 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) } -static struct file_operations zr364xx_fops = { +static const struct file_operations zr364xx_fops = { .owner = THIS_MODULE, .open = zr364xx_open, .release = zr364xx_release, -- cgit v1.2.3 From 4be2f47054fb12a5868838770595e8d3a02e60f2 Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Mon, 29 Oct 2007 00:44:55 -0300 Subject: V4L/DVB (6483): ivtv-streams: make file_operations const Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-streams.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 74fb0e02197..a5bfbd98a49 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -43,7 +43,7 @@ #include "ivtv-cards.h" #include "ivtv-streams.h" -static struct file_operations ivtv_v4l2_enc_fops = { +static const struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = { .poll = ivtv_v4l2_enc_poll, }; -static struct file_operations ivtv_v4l2_dec_fops = { +static const struct file_operations ivtv_v4l2_dec_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, -- cgit v1.2.3 From 761dacd25d9e9be2358df21a0f086bbb4cf1c789 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Oct 2007 05:41:25 -0300 Subject: V4L/DVB (6486): m52790: add new Mitsubishi A/V switch i2c driver This driver is used by the ASUS Falcon2 cx23416-based cards. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 +++ drivers/media/video/Makefile | 1 + drivers/media/video/m52790.c | 172 ++++++++++++++++++++++++++++++++++++++++ include/media/m52790.h | 93 ++++++++++++++++++++++ include/media/v4l2-chip-ident.h | 3 + 5 files changed, 278 insertions(+) create mode 100644 drivers/media/video/m52790.c create mode 100644 include/media/m52790.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ea5be3711a7..320f9e06a93 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -119,6 +119,15 @@ config VIDEO_CS53L32A To compile this driver as a module, choose M here: the module will be called cs53l32a. +config VIDEO_M52790 + tristate "Mitsubishi M52790 A/V switch" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the Mitsubishi M52790 A/V switch. + + To compile this driver as a module, choose M here: the + module will be called m52790. + config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8a278182123..d8910d87aca 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c new file mode 100644 index 00000000000..51ecbfbc1ae --- /dev/null +++ b/drivers/media/video/m52790.c @@ -0,0 +1,172 @@ +/* + * m52790 i2c ivtv driver. + * Copyright (C) 2007 Hans Verkuil + * + * A/V source switching Mitsubishi M52790SP/FP + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned short normal_i2c[] = { 0x90 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +struct m52790_state { + u16 input; + u16 output; +}; + +/* ----------------------------------------------------------------------- */ + +static int m52790_write(struct i2c_client *client) +{ + struct m52790_state *state = i2c_get_clientdata(client); + u8 sw1 = (state->input | state->output) & 0xff; + u8 sw2 = (state->input | state->output) >> 8; + + return i2c_smbus_write_byte_data(client, sw1, sw2); +} + +static int m52790_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct m52790_state *state = i2c_get_clientdata(client); + struct v4l2_routing *route = arg; + + /* Note: audio and video are linked and cannot be switched separately. + So audio and video routing commands are identical for this chip. + In theory the video amplifier and audio modes could be handled + separately for the output, but that seems to be overkill right now. + The same holds for implementing an audio mute control, this is now + part of the audio output routing. The normal case is that another + chip takes care of the actual muting so making it part of the + output routing seems to be the right thing to do for now. */ + switch (cmd) { + case VIDIOC_INT_G_AUDIO_ROUTING: + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->input; + route->output = state->output; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_S_VIDEO_ROUTING: + state->input = route->input; + state->output = route->output; + m52790_write(client); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (reg->reg != 0) + return -EINVAL; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = state->input | state->output; + else { + state->input = reg->val & 0x0303; + state->output = reg->val & ~0x0303; + m52790_write(client); + } + break; + } +#endif + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_M52790, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Switch 1: %02x\n", + (state->input | state->output) & 0xff); + v4l_info(client, "Switch 2: %02x\n", + (state->input | state->output) >> 8); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +static int m52790_probe(struct i2c_client *client) +{ + struct m52790_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + snprintf(client->name, sizeof(client->name) - 1, "m52790"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->input = M52790_IN_TUNER; + state->output = M52790_OUT_STEREO; + i2c_set_clientdata(client, state); + m52790_write(client); + return 0; +} + +static int m52790_remove(struct i2c_client *client) +{ + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "m52790", + .driverid = I2C_DRIVERID_M52790, + .command = m52790_command, + .probe = m52790_probe, + .remove = m52790_remove, +}; + diff --git a/include/media/m52790.h b/include/media/m52790.h new file mode 100644 index 00000000000..7ddffae31a6 --- /dev/null +++ b/include/media/m52790.h @@ -0,0 +1,93 @@ +/* + m52790.h - definition for m52790 inputs and outputs + + Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) + + 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 + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _M52790_H_ +#define _M52790_H_ + +/* Input routing switch 1 */ + +#define M52790_SW1_IN_MASK 0x0003 +#define M52790_SW1_IN_TUNER 0x0000 +#define M52790_SW1_IN_V2 0x0001 +#define M52790_SW1_IN_V3 0x0002 +#define M52790_SW1_IN_V4 0x0003 + +/* Selects component input instead of composite */ +#define M52790_SW1_YCMIX 0x0004 + + +/* Input routing switch 2 */ + +#define M52790_SW2_IN_MASK 0x0300 +#define M52790_SW2_IN_TUNER 0x0000 +#define M52790_SW2_IN_V2 0x0100 +#define M52790_SW2_IN_V3 0x0200 +#define M52790_SW2_IN_V4 0x0300 + +/* Selects component input instead of composite */ +#define M52790_SW2_YCMIX 0x0400 + + +/* Output routing switch 1 */ + +/* Enable 6dB amplifier for composite out */ +#define M52790_SW1_V_AMP 0x0008 + +/* Enable 6dB amplifier for component out */ +#define M52790_SW1_YC_AMP 0x0010 + +/* Audio output mode */ +#define M52790_SW1_AUDIO_MASK 0x00c0 +#define M52790_SW1_AUDIO_MUTE 0x0000 +#define M52790_SW1_AUDIO_R 0x0040 +#define M52790_SW1_AUDIO_L 0x0080 +#define M52790_SW1_AUDIO_STEREO 0x00c0 + + +/* Output routing switch 2 */ + +/* Enable 6dB amplifier for composite out */ +#define M52790_SW2_V_AMP 0x0800 + +/* Enable 6dB amplifier for component out */ +#define M52790_SW2_YC_AMP 0x1000 + +/* Audio output mode */ +#define M52790_SW2_AUDIO_MASK 0xc000 +#define M52790_SW2_AUDIO_MUTE 0x0000 +#define M52790_SW2_AUDIO_R 0x4000 +#define M52790_SW2_AUDIO_L 0x8000 +#define M52790_SW2_AUDIO_STEREO 0xc000 + + +/* Common values */ +#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER) +#define M52790_IN_V2 (M52790_SW1_IN_V2 | M52790_SW2_IN_V2) +#define M52790_IN_V3 (M52790_SW1_IN_V3 | M52790_SW2_IN_V3) +#define M52790_IN_V4 (M52790_SW1_IN_V4 | M52790_SW2_IN_V4) + +#define M52790_OUT_STEREO (M52790_SW1_AUDIO_STEREO | \ + M52790_SW2_AUDIO_STEREO) +#define M52790_OUT_AMP_STEREO (M52790_SW1_AUDIO_STEREO | \ + M52790_SW1_V_AMP | \ + M52790_SW2_AUDIO_STEREO | \ + M52790_SW2_V_AMP) + +#endif diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 8ae42c41dd0..2442c281e4f 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -83,6 +83,9 @@ enum { /* module upd64083: just ident 64083 */ V4L2_IDENT_UPD64083 = 64083, + /* module m52790: just ident 52790 */ + V4L2_IDENT_M52790 = 52790, + /* module msp34xx: reserved range 34000-34999 */ V4L2_IDENT_MSP3400B = 34002, V4L2_IDENT_MSP3410B = 34102, -- cgit v1.2.3 From 05e997197e459a03df577ba49c34c1820957ee4a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Oct 2007 05:41:54 -0300 Subject: V4L/DVB (6487): i2c-id: add M52790 driver ID Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index e18017d4575..adbdc6da39c 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -125,6 +125,7 @@ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */ +#define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ -- cgit v1.2.3 From e2a1774d9c8b866db65853fd1a17e5f472dd5cf2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Oct 2007 05:50:03 -0300 Subject: V4L/DVB (6488): ivtv: add ASUS Falcon2 support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 1 + drivers/media/video/ivtv/ivtv-cards.c | 40 +++++++++++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-cards.h | 7 ++++-- drivers/media/video/ivtv/ivtv-driver.c | 5 +++++ drivers/media/video/ivtv/ivtv-i2c.c | 3 +++ drivers/media/video/ivtv/ivtv-routing.c | 25 ++++++++++----------- 6 files changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 854cc9c30ca..6e5eed5e243 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -12,6 +12,7 @@ config VIDEO_IVTV select VIDEO_SAA7127 select VIDEO_TVAUDIO select VIDEO_CS53L32A + select VIDEO_M52790 select VIDEO_WM8775 select VIDEO_WM8739 select VIDEO_VP27SMPX diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index aaa114b5c26..3211809fe0c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -23,6 +23,7 @@ #include "ivtv-i2c.h" #include +#include #include #include #include @@ -915,6 +916,44 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .pci_list = ivtv_pci_avertv_mce116, }; +/* ------------------------------------------------------------------------- */ + +/* ASUS Falcon2 */ + +static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_asus_falcon2 = { + .type = IVTV_CARD_ASUS_FALCON2, + .name = "ASUS Falcon2", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_M52790, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, + M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, + .tuners = { + { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .pci_list = ivtv_pci_asus_falcon2, +}; + static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, &ivtv_card_pvr350, @@ -937,6 +976,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pg600v2, &ivtv_card_club3d, &ivtv_card_avertv_mce116, + &ivtv_card_asus_falcon2, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index ff46e5ae865..81707bbb60d 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -45,7 +45,8 @@ #define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ #define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ #define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_LAST 20 +#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ +#define IVTV_CARD_LAST 21 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -69,6 +70,7 @@ #define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 #define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 #define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_ASUSTEK 0x1043 #define IVTV_PCI_ID_AVERMEDIA 0x1461 #define IVTV_PCI_ID_YUAN1 0x12ab #define IVTV_PCI_ID_YUAN2 0xff01 @@ -96,7 +98,8 @@ #define IVTV_HW_SAA717X (1 << 12) #define IVTV_HW_WM8739 (1 << 13) #define IVTV_HW_VP27SMPX (1 << 14) -#define IVTV_HW_GPIO (1 << 15) +#define IVTV_HW_M52790 (1 << 15) +#define IVTV_HW_GPIO (1 << 16) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index ec40453e46e..a8aca14f98a 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -185,6 +185,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" "\t\t\t20 = Club3D ZAP-TV1x01\n" "\t\t\t21 = AverTV MCE 116 Plus\n" + "\t\t\t22 = ASUS Falcon2\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -882,6 +883,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) if (hw & IVTV_HW_CS53L32A) ivtv_request_module(itv, "cs53l32a"); #endif +#ifndef CONFIG_VIDEO_M52790 + if (hw & IVTV_HW_M52790) + ivtv_request_module(itv, "m52790"); +#endif /* check which i2c devices are actually found */ for (i = 0; i < 32; i++) { diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 36e54f78aa2..7f513ecc078 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -80,6 +80,7 @@ #endif /* I2C_ADAP_CLASS_TV_ANALOG */ #define IVTV_CS53L32A_I2C_ADDR 0x11 +#define IVTV_M52790_I2C_ADDR 0x48 #define IVTV_CX25840_I2C_ADDR 0x44 #define IVTV_SAA7115_I2C_ADDR 0x21 #define IVTV_SAA7127_I2C_ADDR 0x44 @@ -110,6 +111,7 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, I2C_DRIVERID_VP27SMPX, + I2C_DRIVERID_M52790, 0 /* IVTV_HW_GPIO dummy driver ID */ }; @@ -130,6 +132,7 @@ static const char * const hw_drivernames[] = { "saa717x", "wm8739", "vp27smpx", + "m52790", "gpio", }; diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c index 398bd33033e..05564919b57 100644 --- a/drivers/media/video/ivtv/ivtv-routing.c +++ b/drivers/media/video/ivtv/ivtv-routing.c @@ -25,6 +25,7 @@ #include "ivtv-routing.h" #include +#include #include #include @@ -32,28 +33,26 @@ settings. */ void ivtv_audio_set_io(struct ivtv *itv) { + const struct ivtv_card_audio_input *in; struct v4l2_routing route; - u32 audio_input; - int mux_input; /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) + in = &itv->card->radio_input; + else + in = &itv->card->audio_inputs[itv->audio_input]; /* handle muxer chips */ - route.input = mux_input; + route.input = in->muxer_input; route.output = 0; + if (itv->card->hw_muxer & IVTV_HW_M52790) + route.output = M52790_OUT_STEREO; ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { + route.input = in->audio_input; + route.output = 0; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); } -- cgit v1.2.3 From fdef464a7fdcc0f5905d380b2065fec7715bc95d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Oct 2007 05:55:58 -0300 Subject: V4L/DVB (6489): ivtv: add support for AVerMedia PVR-150 Plus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 39 ++++++++++++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-cards.h | 3 ++- drivers/media/video/ivtv/ivtv-driver.c | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 3211809fe0c..4bb2fe8bce0 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -918,6 +918,44 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { /* ------------------------------------------------------------------------- */ +/* AVerMedia PVR-150 Plus (M113) card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_pvr150 = { + .type = IVTV_CARD_AVER_PVR150PLUS, + .name = "AVerMedia PVR-150 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_GPIO, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + .gpio_init = { .direction = 0x0800, .initial_value = 0 }, + .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, + .tuners = { + /* This card has a Partsnic PTI-5NF05 tuner */ + { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, + }, + .pci_list = ivtv_pci_aver_pvr150, +}; + +/* ------------------------------------------------------------------------- */ + /* ASUS Falcon2 */ static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { @@ -977,6 +1015,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_club3d, &ivtv_card_avertv_mce116, &ivtv_card_asus_falcon2, + &ivtv_card_aver_pvr150, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 81707bbb60d..881b0447316 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -46,7 +46,8 @@ #define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ #define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ #define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ -#define IVTV_CARD_LAST 21 +#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ +#define IVTV_CARD_LAST 22 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index a8aca14f98a..04179b7d1af 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -186,6 +186,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t20 = Club3D ZAP-TV1x01\n" "\t\t\t21 = AverTV MCE 116 Plus\n" "\t\t\t22 = ASUS Falcon2\n" + "\t\t\t23 = AverMedia PVR-150 Plus\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); -- cgit v1.2.3 From 7a06f3f2aab797a12f28cf0f4504ec4e346e97f9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Oct 2007 06:00:05 -0300 Subject: V4L/DVB (6490): Remove EXPERIMENTAL from several i2c drivers Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 320f9e06a93..6c7835629bc 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -111,7 +111,7 @@ config VIDEO_MSP3400 config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -139,7 +139,7 @@ config VIDEO_TLV320AIC23B config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -149,7 +149,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -253,7 +253,7 @@ config VIDEO_SAA7114 config VIDEO_SAA711X tristate "Philips SAA7113/4/5 video decoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Philips SAA7113/4/5 video decoders. @@ -309,7 +309,7 @@ comment "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Philips SAA7127/9 digital video encoders. @@ -347,7 +347,7 @@ comment "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the NEC Electronics uPD64031A Ghost Reduction video chip. It is most often found in NTSC TV cards made for @@ -359,7 +359,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the NEC Electronics uPD64083 3-Dimensional Y/C separation video chip. It is used to improve the quality of -- cgit v1.2.3 From 4942744f93884cb462400c66258c0013bea65dcf Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 30 Oct 2007 09:44:12 -0300 Subject: V4L/DVB (6491): tuner: prevent repeated "type set" message unless debug is enabled The tuner sub-module will usually log its type during its _attach() function, then tuner-core reports which type was attached when control is returned. In most cases, we expect to see the same message reported from both locations. We only need to see this second message if debug is enabled. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index cd5f0d8e693..b92efe0460f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -366,7 +366,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->fe.analog_demod_priv = t; } - tuner_info("type set to %s\n", t->i2c->name); + tuner_dbg("type set to %s\n", t->i2c->name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; -- cgit v1.2.3 From 241020d19ee9da29171d989ff876c657e4b938b5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 30 Oct 2007 09:46:10 -0300 Subject: V4L/DVB (6492): tuner: improve tuner_foo printk macros consistency Alter the tuner_foo printk macros to indicate which module is generating the message. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 2 ++ drivers/media/video/tuner-driver.h | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index b92efe0460f..17c873c869a 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -30,6 +30,8 @@ #define UNSET (-1U) +#define PREFIX "tuner " + /* standard i2c insmod options */ static unsigned short normal_i2c[] = { #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 0df136e58eb..1c60229dcd0 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -71,15 +71,15 @@ struct tuner { /* ------------------------------------------------------------------------ */ #define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c->driver->driver.name, \ + printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c->driver->driver.name, \ + printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #define tuner_dbg(fmt, arg...) do {\ extern int tuner_debug; \ if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c->driver->driver.name, \ + printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #endif /* __TUNER_DRIVER_H__ */ -- cgit v1.2.3 From c5d857d5d3a7cfe355d93916fc094035c85147f7 Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Wed, 31 Oct 2007 00:44:22 -0300 Subject: V4L/DVB (6496): saa7146_vv.h: remove wrong include remove wrong include Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- include/media/saa7146_vv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index e49f7e15606..89c442eb884 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -1,7 +1,6 @@ #ifndef __SAA7146_VV__ #define __SAA7146_VV__ -#include #include #include #include -- cgit v1.2.3 From 58a44040b4937c7d16b79a1b3048992eeac9853b Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Wed, 31 Oct 2007 01:20:42 -0300 Subject: V4L/DVB (6497): saa7146/budget*/dvb-ttpci: Remove V4L1 code Remove V4L1 code. Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/Kconfig | 10 +++++----- drivers/media/dvb/ttpci/av7110.c | 3 ++- drivers/media/dvb/ttpci/av7110.h | 7 ++++++- drivers/media/dvb/ttpci/av7110_av.c | 16 ++++++++++------ drivers/media/dvb/ttpci/av7110_av.h | 3 ++- drivers/media/dvb/ttpci/av7110_v4l.c | 4 ++-- 6 files changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 54b91f26ca6..f95961495ca 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -1,6 +1,6 @@ config DVB_AV7110 tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_CORE && PCI && I2C select FW_LOADER if !DVB_AV7110_FIRMWARE select VIDEO_SAA7146_VV select DVB_VES1820 if !DVB_FE_CUSTOMISE @@ -59,7 +59,7 @@ config DVB_AV7110_OSD config DVB_BUDGET tristate "Budget cards" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_CORE && PCI && I2C select VIDEO_SAA7146 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE @@ -84,7 +84,7 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT + depends on DVB_CORE && PCI && I2C && INPUT select VIDEO_SAA7146 select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -106,7 +106,7 @@ config DVB_BUDGET_CI config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_CORE && PCI && I2C select VIDEO_SAA7146_VV select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -127,7 +127,7 @@ config DVB_BUDGET_AV config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" - depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 + depends on DVB_CORE && DVB_BUDGET select DVB_AV7110 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 0d36c155695..0e5701bdff1 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->osd_mutex); /* TV standard */ - av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC + : AV7110_VIDEO_MODE_PAL; /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 0cb43952749..39fbf7d5cff 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -46,6 +46,11 @@ extern int av7110_debug; enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; +enum av7110_video_mode { + AV7110_VIDEO_MODE_PAL = 0, + AV7110_VIDEO_MODE_NTSC = 1 +}; + struct av7110_p2t { u8 pes[TS_SIZE]; u8 counter; @@ -170,7 +175,7 @@ struct av7110 { ca_slot_info_t ci_slot[2]; - int vidmode; + enum av7110_video_mode vidmode; struct dmxdev dmxdev; struct dvb_demux demux; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index d75e7e48add..aef6e36d7c5 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) return 0; } -int av7110_set_vidmode(struct av7110 *av7110, int mode) +int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) { int ret; dprintk(2, "av7110:%p, \n", av7110); @@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode) } -static int sw2mode[16] = { - VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, - VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, - VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, - VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, +static enum av7110_video_mode sw2mode[16] = { + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, }; static int get_video_format(struct av7110 *av7110, u8 *buf, int count) diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h index 45dc144b8b4..5f02ef85e47 100644 --- a/drivers/media/dvb/ttpci/av7110_av.h +++ b/drivers/media/dvb/ttpci/av7110_av.h @@ -3,7 +3,8 @@ struct av7110; -extern int av7110_set_vidmode(struct av7110 *av7110, int mode); +extern int av7110_set_vidmode(struct av7110 *av7110, + enum av7110_video_mode mode); extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 76cca003252..e2f066fb796 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) struct av7110 *av7110 = (struct av7110*) dev->ext_priv; if (std->id & V4L2_STD_PAL) { - av7110->vidmode = VIDEO_MODE_PAL; + av7110->vidmode = AV7110_VIDEO_MODE_PAL; av7110_set_vidmode(av7110, av7110->vidmode); } else if (std->id & V4L2_STD_NTSC) { - av7110->vidmode = VIDEO_MODE_NTSC; + av7110->vidmode = AV7110_VIDEO_MODE_NTSC; av7110_set_vidmode(av7110, av7110->vidmode); } else -- cgit v1.2.3 From 00405f8f11d3064c4af6fe826d8287863a453e7f Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 1 Nov 2007 01:16:04 -0300 Subject: V4L/DVB (6507): bttv: whitespace cleanup Someone wasn't using the v4l-dvb commit scripts and so didn't run the automatic whitespace cleaner on their code. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-audio-hook.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c index 67b63423575..2364d16586b 100644 --- a/drivers/media/video/bt8xx/bttv-audio-hook.c +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -117,9 +117,9 @@ void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) break; default: t->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; } t->audmode = V4L2_TUNER_MODE_STEREO | V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; -- cgit v1.2.3 From 8ae1fe2a0935afa878b8a506633fea45a8b00293 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 1 Nov 2007 01:16:05 -0300 Subject: V4L/DVB (6508): ttpci: Rework Kconfig menus and Makefile The ttpci Kconfig file has bugs that cause it to fail in certain Kconfig situations. The basic problem is that it selects certain drivers, but does not depend on the dependencies of those drivers. See http://article.gmane.org/gmane.comp.video.video4linux/35072 Using the Kconfig file also has some annoyances. For instance one can't turn off AV7110 support unless you go down several options and first turn off budget-patch support. Normally user selectable drivers are not forced on like this. The "AV7110 cards with Budget Patch" option is disabled if "Budget cards" isn't on. Normally a driver appears nested under a driver it depends on, but since drivers that don't depend on "Budget cards" are between the two options, the config programs can't display the tree correctly. The Makefile has an issue too. Some modules, ttpci-eeprom and budget-core, appear in the Makefile under several different config symbols. If more than one of these symbols is on, they will get added the to list of objects multiple times. The normal convention is to have a config symbol just the common object(s) and have the users of the that object either depend on or select that config symbol. This patch fixes all these issues. ttpci-eepom is under a new config symbol, and so is the budget-core module. The four different budget card types appear as sub-drivers under a main "SAA7146 DVB cards" option. Turning on budget-patch doesn't force AV7110. Drivers using SAA7146_VV have the necessary VIDEO_DEV dependency, so that it isn't possible to select SAA7146_VV without V4L being on. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/Kconfig | 2 +- drivers/media/dvb/ttpci/Kconfig | 35 +++++++++++++++++++++++++---------- drivers/media/dvb/ttpci/Makefile | 12 +++++++----- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index c5092ef1082..06ca75911b7 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -1,6 +1,6 @@ config VIDEO_SAA7146 tristate - depends on I2C + depends on I2C && PCI config VIDEO_SAA7146_VV tristate diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index f95961495ca..ae882432dd3 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -1,8 +1,14 @@ +config TTPCI_EEPROM + tristate + default n + config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select FW_LOADER if !DVB_AV7110_FIRMWARE + select TTPCI_EEPROM select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -57,10 +63,19 @@ config DVB_AV7110_OSD All other people say N. -config DVB_BUDGET - tristate "Budget cards" +config DVB_BUDGET_CORE + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" depends on DVB_CORE && PCI && I2C select VIDEO_SAA7146 + select TTPCI_EEPROM + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. + +config DVB_BUDGET + tristate "Budget cards" + depends on DVB_BUDGET_CORE && I2C select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_VES1820 if !DVB_FE_CUSTOMISE @@ -73,9 +88,9 @@ config DVB_BUDGET select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. + Support for simple SAA7146 based DVB cards (so called Budget- + or Nova-PCI cards) without onboard MPEG2 decoder, and without + analog inputs or an onboard Common Interface connector. Say Y if you own such a card and want to use it. @@ -84,8 +99,7 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_CORE && PCI && I2C && INPUT - select VIDEO_SAA7146 + depends on DVB_BUDGET_CORE && I2C select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -106,8 +120,9 @@ config DVB_BUDGET_CI config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_CORE && PCI && I2C + depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -127,8 +142,8 @@ config DVB_BUDGET_AV config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" - depends on DVB_CORE && DVB_BUDGET - select DVB_AV7110 + depends on DVB_BUDGET_CORE && I2C + depends on DVB_AV7110 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 2c1145236ee..d7483f1a9b3 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -5,11 +5,13 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o -obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o +obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o +obj-$(CONFIG_DVB_BUDGET) += budget.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -- cgit v1.2.3 From 352fae1dffe2d0d04949e579d03667377a176cff Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Nov 2007 16:56:26 -0300 Subject: V4L/DVB (6516): Allow faster loading by using 64 bytes block by em28xx i2c write Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 3 ++- drivers/media/video/tuner-xc2028.c | 3 +++ drivers/media/video/tuner-xc2028.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 61b0c5a55df..b56e0a70d8f 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -371,7 +371,8 @@ static void em28xx_config_tuner (struct em28xx *dev) memset (&ctl,0,sizeof(ctl)); - ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 813b54971e1..b9135b7c433 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -685,6 +685,9 @@ static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg) strcpy(priv->ctrl.fname, p->fname); } + if (p->max_len>0) + priv->max_len = p->max_len; + tuner_info("%s OK\n", __FUNCTION__); return 0; diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index f4856f07bd0..4e5e4d5d1b5 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -19,6 +19,7 @@ enum xc2028_firm_type { struct xc2028_ctrl { enum xc2028_firm_type type; char *fname; + int max_len; }; /* xc2028 commands for callback */ -- cgit v1.2.3 From ab0b9fc67c2370e813ccd5d83bca8db320e67eeb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Nov 2007 17:47:42 -0300 Subject: V4L/DVB (6517): CodingStyle fixup Used scripts/Lindent + manual check + scripts/checkpatch.pl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 347 ++++++++++++++++++------------------- drivers/media/video/tuner-xc2028.h | 12 +- 2 files changed, 175 insertions(+), 184 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index b9135b7c433..473fa73b181 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -65,27 +65,31 @@ struct xc2028_data { struct mutex lock; }; -#define i2c_send(rc, priv, buf, size) \ -if (size != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size))) \ - tuner_info("i2c output error: rc = %d (should be %d)\n", \ - rc, (int)size); - -#define i2c_rcv(rc, priv, buf, size) \ -if (size != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size))) \ - tuner_info("i2c input error: rc = %d (should be %d)\n", \ - rc, (int)size); - -#define send_seq(priv, data...) \ -{ int rc; \ +#define i2c_send(rc, priv, buf, size) do { \ + rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ + if (size != rc) \ + tuner_info("i2c output error: rc = %d (should be %d)\n",\ + rc, (int)size); \ +} while (0) + +#define i2c_rcv(rc, priv, buf, size) do { \ + rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ + if (size != rc) \ + tuner_info("i2c input error: rc = %d (should be %d)\n", \ + rc, (int)size); \ +} while (0) + +#define send_seq(priv, data...) do { \ + int rc; \ static u8 _val[] = data; \ if (sizeof(_val) != \ - (rc = tuner_i2c_xfer_send (&priv->i2c_props, \ + (rc = tuner_i2c_xfer_send(&priv->i2c_props, \ _val, sizeof(_val)))) { \ - tuner_info("Error on line %d: %d\n",__LINE__,rc); \ - return -EINVAL; \ + tuner_info("Error on line %d: %d\n", __LINE__, rc); \ + return -EINVAL; \ } \ - msleep (10); \ -} + msleep(10); \ +} while (0) static int xc2028_get_reg(struct xc2028_data *priv, u16 reg) { @@ -94,42 +98,42 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg) tuner_info("%s called\n", __FUNCTION__); - buf[0]= reg; + buf[0] = reg; i2c_send(rc, priv, buf, sizeof(buf)); - if (rc<0) + if (rc < 0) return rc; i2c_rcv(rc, priv, buf, 2); - if (rc<0) + if (rc < 0) return rc; - return (buf[1])|(buf[0]<<8); + return (buf[1]) | (buf[0] << 8); } -static void free_firmware (struct xc2028_data *priv) +static void free_firmware(struct xc2028_data *priv) { int i; if (!priv->firm) return; - for (i=0;ifirm_size;i++) { - if (priv->firm[i].ptr) - kfree(priv->firm[i].ptr); - } + for (i = 0; i < priv->firm_size; i++) + kfree(priv->firm[i].ptr); + kfree(priv->firm); - priv->firm=NULL; + priv->firm = NULL; priv->need_load_generic = 1; } -static int load_all_firmwares (struct dvb_frontend *fe) +static int load_all_firmwares(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; - const struct firmware *fw=NULL; + const struct firmware *fw = NULL; unsigned char *p, *endp; - int rc=0, n, n_array; + int rc = 0; + int n, n_array; char name[33]; tuner_info("%s called\n", __FUNCTION__); @@ -137,7 +141,7 @@ static int load_all_firmwares (struct dvb_frontend *fe) tuner_info("Loading firmware %s\n", priv->ctrl.fname); rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); if (rc < 0) { - if (rc==-ENOENT) + if (rc == -ENOENT) tuner_info("Error: firmware %s not found.\n", priv->ctrl.fname); else @@ -146,44 +150,44 @@ static int load_all_firmwares (struct dvb_frontend *fe) return rc; } - p=fw->data; - endp=p+fw->size; + p = fw->data; + endp = p + fw->size; - if(fw->sizesize < sizeof(name) - 1 + 2) { tuner_info("Error: firmware size is zero!\n"); - rc=-EINVAL; + rc = -EINVAL; goto done; } - memcpy(name,p,sizeof(name)-1); - name[sizeof(name)-1]=0; - p+=sizeof(name)-1; + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + p += sizeof(name) - 1; - priv->version = le16_to_cpu(*(__u16 *)p); + priv->version = le16_to_cpu(*(__u16 *) p); p += 2; tuner_info("firmware: %s, ver %d.%d\n", name, - priv->version>>8, priv->version&0xff); + priv->version >> 8, priv->version & 0xff); - if (p+2>endp) + if (p + 2 > endp) goto corrupt; - n_array = le16_to_cpu(*(__u16 *)p); + n_array = le16_to_cpu(*(__u16 *) p); p += 2; tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname); - priv->firm=kzalloc(sizeof(*priv->firm)*n_array,GFP_KERNEL); + priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); if (!fw) { tuner_info("Not enough memory for loading firmware.\n"); - rc=-ENOMEM; + rc = -ENOMEM; goto done; } priv->firm_size = n_array; - n=-1; - while (pendp) { + if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) { tuner_info("Lost firmware!\n"); goto corrupt; } - type = le32_to_cpu(*(__u32 *)p); + type = le32_to_cpu(*(__u32 *) p); p += sizeof(type); - id = le64_to_cpu(*(v4l2_std_id *)p); + id = le64_to_cpu(*(v4l2_std_id *) p); p += sizeof(id); - size = le32_to_cpu(*(v4l2_std_id *)p); + size = le32_to_cpu(*(v4l2_std_id *) p); p += sizeof(size); - if ((!size)||(size+p>endp)) { + if ((!size) || (size + p > endp)) { tuner_info("Firmware type %x, id %lx corrupt\n", - type, (unsigned long) id); + type, (unsigned long)id); goto corrupt; } - priv->firm[n].ptr=kzalloc(size,GFP_KERNEL); + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); if (!priv->firm[n].ptr) { tuner_info("Not enough memory.\n"); - rc=-ENOMEM; + rc = -ENOMEM; goto err; } tuner_info("Loading firmware type %x, id %lx, size=%d.\n", - type, (unsigned long) id, size); + type, (unsigned long)id, size); memcpy(priv->firm[n].ptr, p, size); priv->firm[n].type = type; @@ -231,7 +235,7 @@ static int load_all_firmwares (struct dvb_frontend *fe) p += size; } - if (n+1 != priv->firm_size) { + if (n + 1 != priv->firm_size) { tuner_info("Firmware file is incomplete!\n"); goto corrupt; } @@ -239,7 +243,7 @@ static int load_all_firmwares (struct dvb_frontend *fe) goto done; corrupt: - rc=-EINVAL; + rc = -EINVAL; tuner_info("Error: firmware file is corrupted!\n"); err: @@ -254,46 +258,44 @@ done: return rc; } -static int load_firmware (struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id * id) { struct xc2028_data *priv = fe->tuner_priv; - int i, rc; - unsigned char *p, *endp, buf[priv->max_len]; + int i, rc; + unsigned char *p, *endp, buf[priv->max_len]; tuner_info("%s called\n", __FUNCTION__); if (!priv->firm) { - printk (KERN_ERR PREFIX "Error! firmware not loaded\n"); + printk(KERN_ERR PREFIX "Error! firmware not loaded\n"); return -EINVAL; } if ((type == 0) && (*id == 0)) - *id=V4L2_STD_PAL; + *id = V4L2_STD_PAL; /* Seek for exact match */ - for (i=0;ifirm_size;i++) { - if ( (type == priv->firm[i].type) && - (*id == priv->firm[i].id)) + for (i = 0; i < priv->firm_size; i++) { + if ((type == priv->firm[i].type) && (*id == priv->firm[i].id)) goto found; } /* Seek for generic video standard match */ - for (i=0;ifirm_size;i++) { - if ( (type == priv->firm[i].type) && (*id & priv->firm[i].id)) + for (i = 0; i < priv->firm_size; i++) { + if ((type == priv->firm[i].type) && (*id & priv->firm[i].id)) goto found; } /*FIXME: Would make sense to seek for type "hint" match ? */ - tuner_info ("Can't find firmware for type=%x, id=%lx\n", type, - (long int)*id); + tuner_info("Can't find firmware for type=%x, id=%lx\n", type, + (long int)*id); return -EINVAL; found: *id = priv->firm[i].id; - tuner_info ("Found firmware for type=%x, id=%lx\n", type, - (long int)*id); + tuner_info("Found firmware for type=%x, id=%lx\n", type, (long int)*id); p = priv->firm[i].ptr; @@ -301,19 +303,18 @@ found: printk(KERN_ERR PREFIX "Firmware pointer were freed!"); return -EINVAL; } - endp = p+priv->firm[i].size; + endp = p + priv->firm[i].size; - while (pendp) { + if (p + sizeof(size) > endp) { tuner_info("missing bytes\n"); return -EINVAL; } - - size = le16_to_cpu(*(__u16 *)p); + size = le16_to_cpu(*(__u16 *) p); p += sizeof(size); if (size == 0xffff) @@ -322,10 +323,10 @@ found: if (!size) { /* Special callback command received */ rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, 0); - if (rc<0) { + XC2028_TUNER_RESET, 0); + if (rc < 0) { tuner_info("Error at RESET code %d\n", - (*p)&0x7f); + (*p) & 0x7f); return -EINVAL; } continue; @@ -333,13 +334,13 @@ found: /* Checks for a sleep command */ if (size & 0x8000) { - msleep (size & 0x7fff); + msleep(size & 0x7fff); continue; } if ((size + p > endp)) { tuner_info("missing bytes: need %d, have %d\n", - size, (int)(endp-p)); + size, (int)(endp - p)); return -EINVAL; } @@ -348,14 +349,15 @@ found: size--; /* Sends message chunks */ - while (size>0) { - int len = (sizemax_len-1)?size:priv->max_len-1; + while (size > 0) { + int len = (size < priv->max_len - 1) ? + size : priv->max_len - 1; - memcpy(buf+1, p, len); + memcpy(buf + 1, p, len); - i2c_send(rc, priv, buf, len+1); - if (rc<0) { - tuner_info("%d returned from send\n",rc); + i2c_send(rc, priv, buf, len + 1); + if (rc < 0) { + tuner_info("%d returned from send\n", rc); return -EINVAL; } @@ -367,13 +369,12 @@ found: } static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, - v4l2_std_id std, - fe_bandwidth_t bandwidth) + v4l2_std_id std, fe_bandwidth_t bandwidth) { struct xc2028_data *priv = fe->tuner_priv; int rc, version; - v4l2_std_id std0=0; - unsigned int type0=0,type=0; + v4l2_std_id std0 = 0; + unsigned int type0 = 0, type = 0; int change_digital_bandwidth; tuner_info("%s called\n", __FUNCTION__); @@ -382,58 +383,56 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (!priv->ctrl.fname) return -EINVAL; - rc=load_all_firmwares(fe); - if (rc<0) + rc = load_all_firmwares(fe); + if (rc < 0) return rc; } - tuner_info( "I am in mode %u and I should switch to mode %i\n", - priv->mode, new_mode); + tuner_info("I am in mode %u and I should switch to mode %i\n", + priv->mode, new_mode); /* first of all, determine whether we have switched the mode */ - if(new_mode != priv->mode) { + if (new_mode != priv->mode) { priv->mode = new_mode; priv->need_load_generic = 1; } change_digital_bandwidth = (priv->mode == T_DIGITAL_TV - && bandwidth != priv->bandwidth) ? 1 : 0; + && bandwidth != priv->bandwidth) ? 1 : 0; tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, - bandwidth); + bandwidth); if (priv->need_load_generic) { /* Reset is needed before loading firmware */ rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); - if (rc<0) + if (rc < 0) return rc; - type0=BASE; + type0 = BASE; if (priv->ctrl.type == XC2028_FIRM_MTS) type0 |= MTS; - if (priv->bandwidth==8) + if (priv->bandwidth == 8) type0 |= F8MHZ; /* FIXME: How to load FM and FM|INPUT1 firmwares? */ rc = load_firmware(fe, type0, &std0); - if (rc<0) { + if (rc < 0) { tuner_info("Error %d while loading generic firmware\n", rc); return rc; } - priv->need_load_generic=0; - priv->firm_type=0; - if(priv->mode == T_DIGITAL_TV) { - change_digital_bandwidth=1; - } + priv->need_load_generic = 0; + priv->firm_type = 0; + if (priv->mode == T_DIGITAL_TV) + change_digital_bandwidth = 1; } - tuner_info("I should change bandwidth %u\n", - change_digital_bandwidth); + tuner_info("I should change bandwidth %u\n", change_digital_bandwidth); if (change_digital_bandwidth) { @@ -442,7 +441,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, /* FIXME: When should select a DTV78 firmware? */ - switch(bandwidth) { + switch (bandwidth) { case BANDWIDTH_8_MHZ: type |= DTV8; break; @@ -475,21 +474,21 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (priv->ctrl.type == XC2028_FIRM_MTS) type |= MTS; - tuner_info("firmware standard to load: %08lx\n",(unsigned long) std); + tuner_info("firmware standard to load: %08lx\n", (unsigned long)std); if (priv->firm_type & std) { tuner_info("no need to load a std-specific firmware.\n"); return 0; } rc = load_firmware(fe, type, &std); - if (rc<0) + if (rc < 0) return rc; version = xc2028_get_reg(priv, 0x4); tuner_info("Firmware version is %d.%d\n", - (version>>4)&0x0f,(version)&0x0f); + (version >> 4) & 0x0f, (version) & 0x0f); - priv->firm_type=std; + priv->firm_type = std; return 0; } @@ -497,7 +496,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) { struct xc2028_data *priv = fe->tuner_priv; - int frq_lock, signal=0; + int frq_lock, signal = 0; tuner_info("%s called\n", __FUNCTION__); @@ -506,16 +505,15 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) *strength = 0; frq_lock = xc2028_get_reg(priv, 0x2); - if (frq_lock<=0) + if (frq_lock <= 0) goto ret; /* Frequency is locked. Return signal quality */ signal = xc2028_get_reg(priv, 0x40); - if(signal<=0) { - signal=frq_lock; - } + if (signal <= 0) + signal = frq_lock; ret: mutex_unlock(&priv->lock); @@ -527,15 +525,14 @@ ret: #define DIV 15625 -static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */, - enum tuner_mode new_mode, - v4l2_std_id std, - fe_bandwidth_t bandwidth) +static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , + enum tuner_mode new_mode, + v4l2_std_id std, fe_bandwidth_t bandwidth) { struct xc2028_data *priv = fe->tuner_priv; - int rc=-EINVAL; - unsigned char buf[5]; - u32 div, offset = 0; + int rc = -EINVAL; + unsigned char buf[5]; + u32 div, offset = 0; tuner_info("%s called\n", __FUNCTION__); @@ -544,56 +541,56 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */, /* HACK: It seems that specific firmware need to be reloaded when freq is changed */ - priv->firm_type=0; + priv->firm_type = 0; /* Reset GPIO 1 */ rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); - if (rc<0) + if (rc < 0) goto ret; msleep(10); tuner_info("should set frequency %d kHz)\n", freq / 1000); - if (check_firmware(fe, new_mode, std, bandwidth)<0) + if (check_firmware(fe, new_mode, std, bandwidth) < 0) goto ret; - if(new_mode == T_DIGITAL_TV) + if (new_mode == T_DIGITAL_TV) offset = 2750000; - div = (freq - offset + DIV/2)/DIV; + div = (freq - offset + DIV / 2) / DIV; /* CMD= Set frequency */ - if (priv->version<0x0202) { + if (priv->version < 0x0202) { send_seq(priv, {0x00, 0x02, 0x00, 0x00}); } else { send_seq(priv, {0x80, 0x02, 0x00, 0x00}); } rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); - if (rc<0) + if (rc < 0) goto ret; msleep(10); - buf[0]= 0xff & (div>>24); - buf[1]= 0xff & (div>>16); - buf[2]= 0xff & (div>>8); - buf[3]= 0xff & (div); - buf[4]= 0; + buf[0] = 0xff & (div >> 24); + buf[1] = 0xff & (div >> 16); + buf[2] = 0xff & (div >> 8); + buf[3] = 0xff & (div); + buf[4] = 0; i2c_send(rc, priv, buf, sizeof(buf)); - if (rc<0) + if (rc < 0) goto ret; msleep(100); - priv->frequency=freq; + priv->frequency = freq; printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", - buf[1],buf[2],buf[3],buf[4], - freq / 1000000, (freq%1000000)/10000); + buf[1], buf[2], buf[3], buf[4], + freq / 1000000, (freq % 1000000) / 10000); - rc=0; + rc = 0; ret: mutex_unlock(&priv->lock); @@ -602,15 +599,14 @@ ret: } static int xc2028_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *p) + struct analog_parameters *p) { struct xc2028_data *priv = fe->tuner_priv; tuner_info("%s called\n", __FUNCTION__); - return generic_set_tv_freq(fe, 62500l*p->frequency, T_ANALOG_TV, - p->std, - BANDWIDTH_8_MHZ /* NOT USED */); + return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV, + p->std, BANDWIDTH_8_MHZ /* NOT USED */); } static int xc2028_set_params(struct dvb_frontend *fe, @@ -622,13 +618,13 @@ static int xc2028_set_params(struct dvb_frontend *fe, /* FIXME: Only OFDM implemented */ if (fe->ops.info.type != FE_OFDM) { - tuner_info ("DTV type not implemented.\n"); + tuner_info("DTV type not implemented.\n"); return -EINVAL; } return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV, - 0, /* NOT USED */ - p->u.ofdm.bandwidth); + 0 /* NOT USED */, + p->u.ofdm.bandwidth); } @@ -643,11 +639,10 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) if (!priv->count) { list_del(&priv->xc2028_list); - if (priv->ctrl.fname) - kfree(priv->ctrl.fname); + kfree(priv->ctrl.fname); free_firmware(priv); - kfree (priv); + kfree(priv); } return 0; @@ -664,7 +659,7 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg) +static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) { struct xc2028_data *priv = fe->tuner_priv; struct xc2028_ctrl *p = priv_cfg; @@ -674,10 +669,9 @@ static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg) priv->ctrl.type = p->type; if (p->fname) { - if (priv->ctrl.fname) - kfree(priv->ctrl.fname); + kfree(priv->ctrl.fname); - priv->ctrl.fname = kmalloc(strlen(p->fname)+1, GFP_KERNEL); + priv->ctrl.fname = kmalloc(strlen(p->fname) + 1, GFP_KERNEL); if (!priv->ctrl.fname) return -ENOMEM; @@ -685,7 +679,7 @@ static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg) strcpy(priv->ctrl.fname, p->fname); } - if (p->max_len>0) + if (p->max_len > 0) priv->max_len = p->max_len; tuner_info("%s OK\n", __FUNCTION__); @@ -695,11 +689,11 @@ static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg) static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .info = { - .name = "Xceive XC3028", - .frequency_min = 42000000, - .frequency_max = 864000000, - .frequency_step = 50000, - }, + .name = "Xceive XC3028", + .frequency_min = 42000000, + .frequency_max = 864000000, + .frequency_step = 50000, + }, .set_config = xc2028_set_config, .set_analog_params = xc2028_set_tv_freq, @@ -708,18 +702,15 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .get_rf_strength = xc2028_signal, .set_params = xc2028_set_params, -// int (*sleep)(struct dvb_frontend *fe); -// int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); -// int (*get_status)(struct dvb_frontend *fe, u32 *status); }; -int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, +int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, struct device *dev, void *video_dev, - int (*tuner_callback) (void *dev, int command,int arg)) + int (*tuner_callback) (void *dev, int command, int arg)) { struct xc2028_data *priv; - printk( KERN_INFO PREFIX "Xcv2028/3028 init called!\n"); + printk(KERN_INFO PREFIX "Xcv2028/3028 init called!\n"); if (NULL == dev) return -ENODEV; @@ -728,14 +719,13 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, return -ENODEV; if (!tuner_callback) { - printk( KERN_ERR PREFIX "No tuner callback!\n"); + printk(KERN_ERR PREFIX "No tuner callback!\n"); return -EINVAL; } list_for_each_entry(priv, &xc2028_list, xc2028_list) { - if (priv->dev == dev) { + if (priv->dev == dev) dev = NULL; - } } if (dev) { @@ -745,8 +735,8 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, fe->tuner_priv = priv; - priv->bandwidth=BANDWIDTH_6_MHZ; - priv->need_load_generic=1; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->need_load_generic = 1; priv->mode = T_UNINITIALIZED; priv->i2c_props.addr = i2c_addr; priv->i2c_props.adap = i2c_adap; @@ -758,18 +748,17 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, mutex_init(&priv->lock); - list_add_tail(&priv->xc2028_list,&xc2028_list); + list_add_tail(&priv->xc2028_list, &xc2028_list); } priv->count++; memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, - sizeof(xc2028_dvb_tuner_ops)); + sizeof(xc2028_dvb_tuner_ops)); tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); return 0; } - EXPORT_SYMBOL(xc2028_attach); MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 4e5e4d5d1b5..e04611e653e 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -27,15 +27,17 @@ struct xc2028_ctrl { #define XC2028_RESET_CLK 1 #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) -int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, +int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, struct device *dev, void *video_dev, - int (*tuner_callback) (void *dev, int command,int arg)); + int (*tuner_callback) (void *dev, int command, int arg)); #else static inline int xc2028_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, struct device *dev, void *video_dev, - int (*tuner_callback) (void *dev, int command,int arg)) + struct i2c_adapter *i2c_adap, + u8 i2c_addr, struct device *dev, + void *video_dev, + int (*tuner_callback) (void *dev, int command, + int arg)) { printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", __FUNCTION__); -- cgit v1.2.3 From 7d070e26a868bd72f0d32189e0f3ceba47d2db82 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 1 Nov 2007 21:52:58 -0300 Subject: V4L/DVB (6519): Fix HVR900/HVR950 entry - Television is now default; - Add HVR950 name at the entry. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 37f0e3cedf4..abdcc68d47f 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -8,7 +8,7 @@ 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) 9 -> Pinnacle Dazzle DVC 90 (em2820/em2840) [2304:0207] - 10 -> Hauppauge WinTV HVR 900 (em2880) + 10 -> Hauppauge WinTV HVR 900/950 (em2880) 11 -> Terratec Hybrid XS (em2880) 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index b56e0a70d8f..9a6a4541e3c 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -158,7 +158,7 @@ struct em28xx_board em28xx_boards[] = { }}, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { - .name = "Hauppauge WinTV HVR 900", + .name = "Hauppauge WinTV HVR 900/950", .vchannels = 3, .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, @@ -166,13 +166,13 @@ struct em28xx_board em28xx_boards[] = { .has_tuner = 1, .decoder = EM28XX_TVP5150, .input = {{ - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - },{ .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, },{ .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, -- cgit v1.2.3 From 3dbd85ba36ff74af87550e76f5765a768b108409 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 08:07:07 -0300 Subject: V4L/DVB (6535): Fix: Adds the generic PCI IDs for em28xx Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 4 ++-- drivers/media/video/em28xx/em28xx-cards.c | 25 +++++++++---------------- drivers/media/video/em28xx/em28xx-video.c | 14 +++++--------- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index abdcc68d47f..f947dca5ac4 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -1,9 +1,9 @@ 0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800] - 1 -> Unknown EM2820/2840 video grabber (em2820/em2840) + 1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2750,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883] 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036] 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208] 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200] - 5 -> MSI VOX USB 2.0 (em2820/em2840) [eb1a:2820] + 5 -> MSI VOX USB 2.0 (em2820/em2840) 6 -> Terratec Cinergy 200 USB (em2800) 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 9a6a4541e3c..05264c655b5 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -57,22 +57,8 @@ struct em28xx_board em28xx_boards[] = { }}, }, [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2820/2840 video grabber", + .name = "Unknown EM2750/28xx video grabber", .is_em2800 = 0, - .vchannels = 2, - .norm = VIDEO_MODE_PAL, - .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, - .decoder = EM28XX_SAA7113, - .input = {{ - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - },{ - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - }}, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", @@ -337,8 +323,15 @@ const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table [] = { + { USB_DEVICE(0xeb1a, 0x2750), .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 }, + { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2821), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2860), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2861), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2870), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2881), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2883), .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index bb0933f9d84..fb0fa57dec9 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1782,15 +1782,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, model=card[nr]; if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) { - em28xx_errdev( "Your board has no eeprom inside it and thus can't\n" - "%s: be autodetected. Please pass card= insmod option to\n" - "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Generic type will be used." - "%s: Best regards,\n" - "%s: -- tux\n", - dev->name,dev->name,dev->name,dev->name,dev->name); - em28xx_errdev("%s: Here is a list of valid choices for the card= insmod option:\n", - dev->name); + em28xx_errdev("Your board has no unique USB ID and thus can't be autodetected.\n"); + em28xx_errdev("Please pass card= insmod option to workaround that.\n"); + em28xx_errdev("If there isn't any card number for you, please send an email to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); + em28xx_errdev("Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < em28xx_bcount; i++) { em28xx_errdev(" card=%d -> %s\n", i, em28xx_boards[i].name); -- cgit v1.2.3 From 03910cc39035d27f4c85c8ad2a236cc5c9456127 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 21:20:59 -0300 Subject: V4L/DVB (6536): Add a hint for boards without unique USB ID This patch adds a function to allow trying to detect boards that shares the generic IDs. The current detection method is based at eeprom checksum. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 198 ++++++++++++++++++++++++------ drivers/media/video/em28xx/em28xx-i2c.c | 74 +++++------ drivers/media/video/em28xx/em28xx-video.c | 120 ++++++------------ drivers/media/video/em28xx/em28xx.h | 2 + 4 files changed, 229 insertions(+), 165 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 05264c655b5..4cd49415eef 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -37,6 +37,16 @@ #include "em28xx.h" #include "tuner-xc2028.h" +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); + +struct em28xx_hash_table { + unsigned long hash; + unsigned int model; + unsigned int tuner; +}; + struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", @@ -342,70 +352,178 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, }; +MODULE_DEVICE_TABLE (usb, em28xx_id_table); + +static struct em28xx_hash_table em28xx_hash [] = { + { 0, 0, 0 }, +}; +/* Since em28xx_pre_card_setup() requires a proper dev->model, + * this won't work for boards with generic PCI IDs + */ void em28xx_pre_card_setup(struct em28xx *dev) { /* request some modules */ switch(dev->model){ - case EM2880_BOARD_TERRATEC_PRODIGY_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - { - em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? - break; - } + case EM2880_BOARD_TERRATEC_PRODIGY_XS: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + /* reset through GPIO? */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); + break; + } +} + +static int em28xx_tuner_callback(void *ptr, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + switch (command) { + case XC2028_TUNER_RESET: + /* FIXME: This is device-dependent */ + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); + + msleep(140); + break; } + return rc; } static void em28xx_config_tuner (struct em28xx *dev) { struct v4l2_priv_tun_config xc2028_cfg; struct xc2028_ctrl ctl; + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + if (!dev->has_tuner) + return; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.tuner_callback = em28xx_tuner_callback; + + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + + if (dev->tuner_type == TUNER_XC2028) { + memset (&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; - memset (&ctl,0,sizeof(ctl)); + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + dev->ctl_freq = f.frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); +} + +static int em28xx_hint_board(struct em28xx *dev) +{ + int i; - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; + for (i = 0; i < ARRAY_SIZE(em28xx_hash); i++) { + if (dev->hash == em28xx_hash[i].hash) { + dev->model = em28xx_hash[i].model; + dev->tuner_type = em28xx_hash[i].tuner; - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on eeprom hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + return 0; + } + } + em28xx_errdev("Your board has no unique USB ID and thus need a " + "hint to be detected.\n"); + em28xx_errdev("You may try to use card= insmod option to " + "workaround that.\n"); + em28xx_errdev("Please send an email with this log to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); + em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + + em28xx_errdev("Here is a list of valid choices for the card=" + " insmod option:\n"); + for (i = 0; i < em28xx_bcount; i++) { + em28xx_errdev(" card=%d -> %s\n", + i, em28xx_boards[i].name); + } + return -1; } void em28xx_card_setup(struct em28xx *dev) { /* request some modules */ - switch(dev->model){ - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - { - struct tveeprom tv; + switch (dev->model) { + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + { + struct tveeprom tv; #ifdef CONFIG_MODULES - request_module("tveeprom"); - request_module("ir-kbd-i2c"); - request_module("msp3400"); + request_module("tveeprom"); + request_module("ir-kbd-i2c"); #endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type= tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { - dev->i2s_speed=2048000; - dev->has_msp34xx=1; - } else - dev->has_msp34xx=0; - break; - } - case EM2820_BOARD_KWORLD_PVRTV2800RF: - { - em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF - break; - } + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + dev->tuner_type = tv.tuner_type; + if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed = 2048000; + dev->has_msp34xx = 1; + } + break; } + case EM2820_BOARD_KWORLD_PVRTV2800RF: + /* GPIO enables sound on KWORLD PVR TV 2800RF */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); + break; + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: + em28xx_hint_board(dev); + } + + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + dev->has_tuner = em28xx_boards[dev->model].has_tuner; + dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + dev->decoder = em28xx_boards[dev->model].decoder; + dev->video_inputs = em28xx_boards[dev->model].vchannels; + + if (tuner >= 0) + dev->tuner_type = tuner; + +#ifdef CONFIG_MODULES + /* request some modules */ + if (dev->has_msp34xx) + request_module("msp3400"); + if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) + request_module("saa7115"); + if (dev->decoder == EM28XX_TVP5150) + request_module("tvp5150"); + if (dev->has_tuner) + request_module("tuner"); +#endif + em28xx_config_tuner (dev); } - -MODULE_DEVICE_TABLE (usb, em28xx_id_table); diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index a33878e0879..e2003455f2b 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -292,6 +292,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return rc; } +/* based on linux/sunrpc/svcauth.h and linux/hash.h + * The original hash function returns a different value, if arch is x86_64 + * or i386. + */ +static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) +{ + unsigned long hash = 0; + unsigned long l = 0; + int len = 0; + unsigned char c; + do { + if (len == length) { + c = (char)len; + len = -1; + } else + c = *buf++; + l = (l << 8) | c; + len++; + if ((len & (32 / 8 - 1)) == 0) + hash = ((hash^l) * 0x9e370001UL); + } while (len); + + return (hash >> (32 - bits)) & 0xffffffffUL; +} + static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { unsigned char buf, *p = eedata; @@ -335,7 +360,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) printk("\n"); } - printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id); + if (em_eeprom->id == 0x9567eb1a) + dev->hash = em28xx_hash_mem(eedata, len, 32); + + printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n", + em_eeprom->id, dev->hash); printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, em_eeprom->product_ID); @@ -392,43 +421,6 @@ static u32 functionality(struct i2c_adapter *adap) } -static int em28xx_tuner_callback(void *ptr, int command, int arg) -{ - int rc = 0; - struct em28xx *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - switch (command) { - case XC2028_TUNER_RESET: - /* FIXME: This is device-dependent */ - dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); - dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); - - msleep(140); - break; - } - return rc; -} - -static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - struct tuner_setup tun_setup; - - if (dev->has_tuner) { - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - tun_setup.tuner_callback = em28xx_tuner_callback; - - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - } - - return (0); -} - /* * attach_inform() * gets called when a device attaches to the i2c bus @@ -487,9 +479,11 @@ static int attach_inform(struct i2c_client *client) break; default: + if (!dev->tuner_addr) + dev->tuner_addr = client->addr; + dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); - dev->tuner_addr = client->addr; - em28xx_set_tuner(-1, client); + } return 0; diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index fb0fa57dec9..18b8568c634 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -37,7 +37,6 @@ #include #include "em28xx.h" -#include #include #include @@ -71,10 +70,6 @@ MODULE_PARM_DESC(card,"card type"); MODULE_PARM_DESC(video_nr,"video device numbers"); MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); - static unsigned int video_debug = 0; module_param(video_debug,int,0644); MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); @@ -171,7 +166,6 @@ static int em28xx_config(struct em28xx *dev) */ static void em28xx_config_i2c(struct em28xx *dev) { - struct v4l2_frequency f; struct v4l2_routing route; route.input = INPUT(dev->ctl_input)->vmux; @@ -179,13 +173,6 @@ static void em28xx_config_i2c(struct em28xx *dev) em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* FIXME:remove magic number */ - dev->ctl_freq = f.frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); } /* @@ -1495,7 +1482,7 @@ static const struct file_operations em28xx_v4l_fops = { * allocates and inits the device structs, registers i2c bus and v4l device */ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - int minor, int model) + int minor) { struct em28xx *dev = *devhandle; int retval = -ENOMEM; @@ -1503,7 +1490,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, unsigned int maxh, maxw; dev->udev = udev; - dev->model = model; mutex_init(&dev->lock); init_waitqueue_head(&dev->open); @@ -1512,43 +1498,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; dev->em28xx_write_regs_req = em28xx_write_regs_req; dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->is_em2800 = em28xx_boards[model].is_em2800; - dev->has_tuner = em28xx_boards[model].has_tuner; - dev->has_msp34xx = em28xx_boards[model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[model].tda9887_conf; - dev->decoder = em28xx_boards[model].decoder; - - if (tuner >= 0) - dev->tuner_type = tuner; - else - dev->tuner_type = em28xx_boards[model].tuner_type; - - dev->video_inputs = em28xx_boards[model].vchannels; - - for (i = 0; i < TVNORMS; i++) - if (em28xx_boards[model].norm == tvnorms[i].mode) - break; - if (i == TVNORMS) - i = 0; - - dev->tvnorm = &tvnorms[i]; /* set default norm */ - - em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - /* set default image size */ - dev->width = maxw; - dev->height = maxh; - dev->interlaced = EM28XX_INTERLACED_DEFAULT; - dev->field_size = dev->width * dev->height; - dev->frame_size = - dev->interlaced ? dev->field_size << 1 : dev->field_size; - dev->bytesperline = dev->width * 2; - dev->hscale = 0; - dev->vscale = 0; - dev->ctl_input = 2; /* setup video picture settings for saa7113h */ memset(&dev->vpic, 0, sizeof(dev->vpic)); @@ -1561,24 +1510,17 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vpic.palette = VIDEO_PALETTE_YUV422; em28xx_pre_card_setup(dev); -#ifdef CONFIG_MODULES - /* request some modules */ - if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) - request_module("saa7115"); - if (dev->decoder == EM28XX_TVP5150) - request_module("tvp5150"); - if (dev->has_tuner) - request_module("tuner"); -#endif + errCode = em28xx_config(dev); if (errCode) { em28xx_errdev("error configuring device\n"); - em28xx_devused&=~(1<devno); + em28xx_devused &= ~(1<devno); kfree(dev); return -ENOMEM; } mutex_lock(&dev->lock); + /* register i2c bus */ em28xx_i2c_register(dev); @@ -1590,12 +1532,33 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, mutex_unlock(&dev->lock); + for (i = 0; i < TVNORMS; i++) + if (em28xx_boards[dev->model].norm == tvnorms[i].mode) + break; + if (i == TVNORMS) + i = 0; + + dev->tvnorm = &tvnorms[i]; /* set default norm */ + + em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); + + maxw = norm_maxw(dev); + maxh = norm_maxh(dev); + + /* set default image size */ + dev->width = maxw; + dev->height = maxh; + dev->interlaced = EM28XX_INTERLACED_DEFAULT; + dev->field_size = dev->width * dev->height; + dev->frame_size = + dev->interlaced ? dev->field_size << 1 : dev->field_size; + dev->bytesperline = dev->width * 2; + dev->hscale = 0; + dev->vscale = 0; + dev->ctl_input = 2; + errCode = em28xx_config(dev); -#ifdef CONFIG_MODULES - if (dev->has_msp34xx) - request_module("msp3400"); -#endif /* allocate and fill v4l2 device struct */ dev->vdev = video_device_alloc(); if (NULL == dev->vdev) { @@ -1695,7 +1658,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; - int model,i,nr,ifnum; + int i, nr, ifnum; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -1735,8 +1698,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, return -ENODEV; } - model=id->driver_info; - if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); em28xx_devused&=~(1<name, 29, "em28xx #%d", nr); - dev->devno=nr; + dev->devno = nr; + dev->model = id->driver_info; /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; @@ -1779,26 +1741,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if ((card[nr]>=0)&&(card[nr] insmod option to workaround that.\n"); - em28xx_errdev("If there isn't any card number for you, please send an email to:\n"); - em28xx_errdev("\tV4L Mailing List \n"); - em28xx_errdev("Here is a list of valid choices for the card= insmod option:\n"); - for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", i, - em28xx_boards[i].name); - } - } + dev->model = card[nr]; /* allocate device struct */ - retval = em28xx_init_dev(&dev, udev, nr, model); + retval = em28xx_init_dev(&dev, udev, nr); if (retval) return retval; - em28xx_info("Found %s\n", em28xx_boards[model].name); + em28xx_info("Found %s\n", em28xx_boards[dev->model].name); /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d8fcc9e17ac..e98dac7fc05 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -257,6 +257,8 @@ struct em28xx { int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; + unsigned long hash; /* eeprom hash - for boards with generic ID */ + /* states */ enum em28xx_dev_state state; enum em28xx_stream_state stream; -- cgit v1.2.3 From ea4fd5679b258d8ae85124a47b587a53ba6409de Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 21:21:57 -0300 Subject: V4L/DVB (6537): Add entry for Pixelview Prolink PlayTV USB 2.0 Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 1 + drivers/media/video/em28xx/em28xx-cards.c | 23 ++++++++++++++++++++++- drivers/media/video/em28xx/em28xx.h | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index f947dca5ac4..b3a8181343a 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -12,3 +12,4 @@ 11 -> Terratec Hybrid XS (em2880) 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) + 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4cd49415eef..e1e7510146e 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -328,6 +328,26 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, }}, }, + [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "Pixelview Prolink PlayTV USB 2.0", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + }}, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -355,7 +375,8 @@ struct usb_device_id em28xx_id_table [] = { MODULE_DEVICE_TABLE (usb, em28xx_id_table); static struct em28xx_hash_table em28xx_hash [] = { - { 0, 0, 0 }, + /* P/N: SA 60002070465 Tuner: TVF7533-MF */ + { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, }; /* Since em28xx_pre_card_setup() requires a proper dev->model, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index e98dac7fc05..209f6f9d558 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -46,6 +46,7 @@ #define EM2880_BOARD_TERRATEC_HYBRID_XS 11 #define EM2820_BOARD_KWORLD_PVRTV2800RF 12 #define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 +#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 #define UNSET -1 -- cgit v1.2.3 From 5a80415bcabf2b59e8c34db6e743c54582cfd3c2 Mon Sep 17 00:00:00 2001 From: Sascha Sommer Date: Sat, 3 Nov 2007 21:22:38 -0300 Subject: V4L/DVB (6538): em28xx: fix locking to allow accesses from 2 different threads at the same time The attached patch modifies the em28xx driver so that there can be ioctls from multiple different threads. This is necessary for capture apps like MPlayer that use different threads for capturing and channel tuning. Now the locking is only done for the ioctls that change properties of the device or access the i2c bus. It also removes some locks that look unnecessary: In em28xx_init_dev: the videodevice is not registered yet so nothing can access the hardware meanwhile, the device struct is not assigned to the interface yet so no race with disconnect is possible In em28xx_release_resources: it gets only called when dev->lock is already held Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 151 ++++++++++++++++-------------- drivers/media/video/em28xx/em28xx.h | 2 +- 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 18b8568c634..bc495a11dc2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -126,8 +126,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { static struct usb_driver em28xx_usb_driver; -static DEFINE_MUTEX(em28xx_sysfs_lock); -static DECLARE_RWSEM(em28xx_disconnect); /********************* v4l2 interface ******************************************/ @@ -253,22 +251,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_videodbg("open minor=%d type=%s users=%d\n", minor,v4l2_type_names[dev->type],dev->users); - if (!down_read_trylock(&em28xx_disconnect)) - return -ERESTARTSYS; + mutex_lock(&dev->lock); if (dev->users) { em28xx_warn("this driver can be opened only once\n"); - up_read(&em28xx_disconnect); + mutex_unlock(&dev->lock); return -EBUSY; } - mutex_init(&dev->fileop_lock); /* to 1 == available */ spin_lock_init(&dev->queue_lock); init_waitqueue_head(&dev->wait_frame); init_waitqueue_head(&dev->wait_stream); - mutex_lock(&dev->lock); - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { em28xx_set_alternate(dev); @@ -306,7 +300,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) err: mutex_unlock(&dev->lock); - up_read(&em28xx_disconnect); return errCode; } @@ -317,7 +310,6 @@ err: */ static void em28xx_release_resources(struct em28xx *dev) { - mutex_lock(&em28xx_sysfs_lock); /*FIXME: I2C IR should be disconnected */ @@ -329,7 +321,6 @@ static void em28xx_release_resources(struct em28xx *dev) video_unregister_device(dev->vbi_dev); em28xx_i2c_unregister(dev); usb_put_dev(dev->udev); - mutex_unlock(&em28xx_sysfs_lock); /* Mark device as unused */ @@ -389,6 +380,8 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, int ret = 0; struct em28xx *dev = filp->private_data; + mutex_lock(&dev->lock); + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); } @@ -396,47 +389,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EFAULT; } + mutex_unlock(&dev->lock); return (1); } if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EFAULT; } + mutex_unlock(&dev->lock); return (1); } - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; - if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("device not present\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_videodbg("device misconfigured; close and open it again\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EIO; } if (dev->io == IO_MMAP) { em28xx_videodbg ("IO method is set to mmap; close and open" " the device again to choose the read method\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EINVAL; } if (dev->io == IO_NONE) { if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { em28xx_errdev("read failed, not enough memory\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENOMEM; } dev->io = IO_READ; @@ -445,13 +437,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, } if (!count) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return 0; } if (list_empty(&dev->outqueue)) { if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EAGAIN; } ret = wait_event_interruptible @@ -459,11 +451,11 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, (!list_empty(&dev->outqueue)) || (dev->state & DEV_DISCONNECTED)); if (ret) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return ret; } if (dev->state & DEV_DISCONNECTED) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENODEV; } } @@ -482,12 +474,12 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, count = f->buf.length; if (copy_to_user(buf, f->bufmem, count)) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EFAULT; } *f_pos += count; - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return count; } @@ -501,8 +493,7 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) unsigned int mask = 0; struct em28xx *dev = filp->private_data; - if (mutex_lock_interruptible(&dev->fileop_lock)) - return POLLERR; + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("device not present\n"); @@ -527,13 +518,13 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) if (!list_empty(&dev->outqueue)) mask |= POLLIN | POLLRDNORM; - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return mask; } } - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return POLLERR; } @@ -575,25 +566,24 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) struct em28xx *dev = filp->private_data; - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("mmap: device not present\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_videodbg ("mmap: Device is misconfigured; close and " "open it again\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EIO; } if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(dev->frame[0].buf.length)) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EINVAL; } @@ -603,7 +593,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) } if (i == dev->num_frames) { em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EINVAL; } @@ -615,7 +605,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -627,7 +617,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = &dev->frame[i]; em28xx_vm_open(vma); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return 0; } @@ -1084,7 +1074,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, } } } + mutex_lock(&dev->lock); em28xx_i2c_call_clients(dev,cmd,qc); + mutex_unlock(&dev->lock); if (qc->type) return 0; else @@ -1098,7 +1090,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, if (!dev->has_msp34xx) retval=em28xx_get_ctrl(dev, ctrl); if (retval==-EINVAL) { + mutex_lock(&dev->lock); em28xx_i2c_call_clients(dev,cmd,arg); + mutex_unlock(&dev->lock); return 0; } else return retval; } @@ -1106,21 +1100,26 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, { struct v4l2_control *ctrl = arg; u8 i; + mutex_lock(&dev->lock); if (!dev->has_msp34xx){ for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { if (ctrl->id == em28xx_qctrl[i].id) { + int retval=-EINVAL; if (ctrl->value < em28xx_qctrl[i].minimum || ctrl->value > em28xx_qctrl[i].maximum) return -ERANGE; - return em28xx_set_ctrl(dev, ctrl); + retval = em28xx_set_ctrl(dev, ctrl); + mutex_unlock(&dev->lock); + return retval; } } } em28xx_i2c_call_clients(dev,cmd,arg); + mutex_unlock(&dev->lock); return 0; } /* --- tuner ioctls ------------------------------------------ */ @@ -1220,12 +1219,16 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, || dev->io != IO_MMAP) return -EINVAL; + mutex_lock(&dev->lock); if (dev->stream == STREAM_ON) { em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) + if ((ret = em28xx_stream_interrupt(dev))){ + mutex_unlock(&dev->lock); return ret; + } } em28xx_empty_framequeues(dev); + mutex_unlock(&dev->lock); return 0; } @@ -1291,11 +1294,23 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, return 0; } case VIDIOC_G_FMT: - return em28xx_get_fmt(dev, (struct v4l2_format *) arg); + { + int retval; + mutex_lock(&dev->lock); + retval = em28xx_get_fmt(dev, (struct v4l2_format *) arg); + mutex_unlock(&dev->lock); + return retval; + } case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: - return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); + { + int retval; + mutex_lock(&dev->lock); + retval = em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); + mutex_unlock(&dev->lock); + return retval; + } case VIDIOC_REQBUFS: { @@ -1320,10 +1335,13 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, return -EINVAL; } + mutex_lock(&dev->lock); if (dev->stream == STREAM_ON) { em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) + if ((ret = em28xx_stream_interrupt(dev))){ + mutex_unlock(&dev->lock); return ret; + } } em28xx_empty_framequeues(dev); @@ -1338,6 +1356,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", rb->count); dev->io = rb->count ? IO_MMAP : IO_NONE; + mutex_unlock(&dev->lock); return 0; } case VIDIOC_QUERYBUF: @@ -1439,26 +1458,19 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, int ret = 0; struct em28xx *dev = filp->private_data; - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; - if (dev->state & DEV_DISCONNECTED) { em28xx_errdev("v4l2 ioctl: device not present\n"); - mutex_unlock(&dev->fileop_lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_errdev ("v4l2 ioctl: device is misconfigured; close and open it again\n"); - mutex_unlock(&dev->fileop_lock); return -EIO; } ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); - mutex_unlock(&dev->fileop_lock); - return ret; } @@ -1519,8 +1531,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return -ENOMEM; } - mutex_lock(&dev->lock); - /* register i2c bus */ em28xx_i2c_register(dev); @@ -1530,8 +1540,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, /* configure the device */ em28xx_config_i2c(dev); - mutex_unlock(&dev->lock); - for (i = 0; i < TVNORMS; i++) if (em28xx_boards[dev->model].norm == tvnorms[i].mode) break; @@ -1599,8 +1607,18 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, list_add_tail(&dev->devlist,&em28xx_devlist); + + if (dev->has_msp34xx) { + /* Send a reset to other chips via gpio */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); + msleep(3); + em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); + msleep(3); + + } + video_mux(dev, 0); + /* register v4l2 device */ - mutex_lock(&dev->lock); if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]))) { em28xx_errdev("unable to register video device (error=%i).\n", @@ -1627,18 +1645,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, printk("registered VBI\n"); } - if (dev->has_msp34xx) { - /* Send a reset to other chips via gpio */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); - msleep(3); - em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); - msleep(3); - - } - video_mux(dev, 0); - - mutex_unlock(&dev->lock); - em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); @@ -1762,18 +1768,19 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ static void em28xx_usb_disconnect(struct usb_interface *interface) { - struct em28xx *dev = usb_get_intfdata(interface); + struct em28xx *dev; + + dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!dev) return; - down_write(&em28xx_disconnect); + em28xx_info("disconnecting %s\n", dev->vdev->name); + /* wait until all current v4l2 io is finished then deallocate resources */ mutex_lock(&dev->lock); - em28xx_info("disconnecting %s\n", dev->vdev->name); - wake_up_interruptible_all(&dev->open); if (dev->users) { @@ -1792,6 +1799,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_release_resources(dev); } + mutex_unlock(&dev->lock); if (!dev->users) { @@ -1799,7 +1807,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) kfree(dev); } - up_write(&em28xx_disconnect); } static struct usb_driver em28xx_usb_driver = { diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 209f6f9d558..65670ae2945 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -265,7 +265,7 @@ struct em28xx { enum em28xx_stream_state stream; enum em28xx_io_method io; /* locks */ - struct mutex lock, fileop_lock; + struct mutex lock; spinlock_t queue_lock; struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; -- cgit v1.2.3 From 4362559d826b369df41fc74df4c5db6061962dce Mon Sep 17 00:00:00 2001 From: Sascha Sommer Date: Sat, 3 Nov 2007 15:05:07 -0300 Subject: V4L/DVB (6539): em28xx: add support for vgear pockettv attached patch adds support for the vgear pockettv. It seems to require a write to another register for audio to work. I checked my old cinergydrv and we did the same register write there. I therefore enabled it for all em2800 based devices. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 23 +++++++++++++++++++++++ drivers/media/video/em28xx/em28xx.h | 12 ++++++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index e1e7510146e..ae6634156e7 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -328,6 +328,29 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, }}, }, + [EM2800_BOARD_VGEAR_POCKETTV] = { + .name = "V-Gear PocketTV", + .is_em2800 = 1, + .vchannels = 3, + .norm = VIDEO_MODE_PAL, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + }}, + }, [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { .name = "Pixelview Prolink PlayTV USB 2.0", .vchannels = 3, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 65670ae2945..70fddd45d1f 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -47,6 +47,7 @@ #define EM2820_BOARD_KWORLD_PVRTV2800RF 12 #define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 #define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 +#define EM2800_BOARD_VGEAR_POCKETTV 15 #define UNSET -1 @@ -335,6 +336,9 @@ extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; +/* em2800 registers */ +#define EM2800_AUDIOSRC_REG 0x08 + /* em28xx registers */ #define CHIPID_REG 0x0a #define USBSUSP_REG 0x0c /* */ @@ -390,6 +394,8 @@ extern const unsigned int em28xx_bcount; #define VIDEO_AC97 0x14 /* register settings */ +#define EM2800_AUDIO_SRC_TUNER 0x0d +#define EM2800_AUDIO_SRC_LINE 0x0c #define EM28XX_AUDIO_SRC_TUNER 0xc0 #define EM28XX_AUDIO_SRC_LINE 0x80 @@ -411,6 +417,12 @@ extern const unsigned int em28xx_bcount; inline static int em28xx_audio_source(struct em28xx *dev, int input) { + if(dev->is_em2800){ + u8 tmp = EM2800_AUDIO_SRC_TUNER; + if(input == EM28XX_AUDIO_SRC_LINE) + tmp = EM2800_AUDIO_SRC_LINE; + em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &tmp, 1); + } return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); } -- cgit v1.2.3 From 9b15c0251ba9d20dd88a69b2c607a2f2e5f0133a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 22:04:33 -0300 Subject: V4L/DVB (6541): Add V-Gear PocketTV to Cardlist.em28xx Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index b3a8181343a..f809834af12 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -13,3 +13,4 @@ 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) + 15 -> V-Gear PocketTV (em2800) -- cgit v1.2.3 From f1f32849d65ab1eacfedbabb624876ac06c1af9f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 3 Nov 2007 22:14:54 -0300 Subject: V4L/DVB (6543): tda8290: enable probing of tda8295 Prevent the tda8295 from falsely being detected as a tda9887 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 64 ++++++++++++++++++++++++++++++---------- drivers/media/video/tda8290.h | 4 +-- drivers/media/video/tuner-core.c | 4 +-- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index c7705cbab2f..dd239965465 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -632,6 +632,46 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) return 0; } +static int tda8290_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8290_ID 0x89 + unsigned char tda8290_id[] = { 0x1f, 0x00 }; + + /* detect tda8290 */ + tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1); + tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); + + if (tda8290_id[1] == TDA8290_ID) { + if (tuner_debug) + printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", + __FUNCTION__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + + return -1; +} + +static int tda8295_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8295_ID 0x8a + unsigned char tda8295_id[] = { 0x2f, 0x00 }; + + /* detect tda8295 */ + tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1); + tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); + + if (tda8295_id[1] == TDA8295_ID) { + if (tuner_debug) + printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n", + __FUNCTION__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + + return -1; +} + static struct analog_tuner_ops tda8290_tuner_ops = { .set_tv_freq = tda8290_set_freq, .set_radio_freq = tda8290_set_freq, @@ -655,11 +695,6 @@ int tda829x_attach(struct tuner *t) struct dvb_frontend *fe = &t->fe; struct tda8290_priv *priv = NULL; - unsigned char tda8290_id[] = { 0x1f, 0x00 }; -#define TDA8290_ID 0x89 - unsigned char tda8295_id[] = { 0x2f, 0x00 }; -#define TDA8295_ID 0x8a - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; @@ -671,18 +706,12 @@ int tda829x_attach(struct tuner *t) priv->cfg.tuner_callback = t->tuner_callback; priv->t = t; - /* detect tda8290 */ - tuner_i2c_xfer_send(&priv->i2c_props, &tda8290_id[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &tda8290_id[1], 1); - if (tda8290_id[1] == TDA8290_ID) { + if (tda8290_probe(&priv->i2c_props) == 0) { priv->ver = TDA8290; fe->ops.analog_demod_ops = &tda8290_tuner_ops; } - /* detect tda8295 */ - tuner_i2c_xfer_send(&priv->i2c_props, &tda8295_id[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &tda8295_id[1], 1); - if (tda8295_id[1] == TDA8295_ID) { + if (tda8295_probe(&priv->i2c_props) == 0) { priv->ver = TDA8295; fe->ops.analog_demod_ops = &tda8295_tuner_ops; } @@ -704,7 +733,7 @@ int tda829x_attach(struct tuner *t) } EXPORT_SYMBOL_GPL(tda829x_attach); -int tda8290_probe(struct tuner *t) +int tda829x_probe(struct tuner *t) { struct tuner_i2c_props i2c_props = { .adap = t->i2c->adapter, @@ -718,6 +747,11 @@ int tda8290_probe(struct tuner *t) unsigned char addr_dto_lsb = 0x07; unsigned char data; + if ((tda8290_probe(&i2c_props) == 0) || + (tda8295_probe(&i2c_props) == 0)) + return 0; + + /* fall back to old probing method */ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); @@ -734,7 +768,7 @@ int tda8290_probe(struct tuner *t) tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); return -1; } -EXPORT_SYMBOL_GPL(tda8290_probe); +EXPORT_SYMBOL_GPL(tda829x_probe); MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 81517370b8d..3a1f0452061 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -21,11 +21,11 @@ #include "tuner-driver.h" #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda8290_probe(struct tuner *t); +extern int tda829x_probe(struct tuner *t); extern int tda829x_attach(struct tuner *t); #else -static inline int tda8290_probe(struct tuner *t) +static inline int tda829x_probe(struct tuner *t) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return -EINVAL; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 17c873c869a..3ec50dbed74 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -649,8 +649,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda8290_probe(t) == 0) { - tuner_dbg("chip at addr %x is a tda8290\n", addr); + if (tda829x_probe(t) == 0) { + tuner_dbg("tda829x detected\n"); } else { /* Default is being tda9887 */ t->type = TUNER_TDA9887; -- cgit v1.2.3 From fad7b958e753e18ff443786360f7846da50a3085 Mon Sep 17 00:00:00 2001 From: Sascha Sommer Date: Sun, 4 Nov 2007 08:06:48 -0300 Subject: V4L/DVB (6545): em28xx: autodetect Cinergy 200 USB and VGear PocketTV Adds autodetection support for the Cinergy200 USB and the VGear PocketTV. Whenever a usb device with generic empia em2800 usb ids is detected the device gets scanned for connected i2c devices. If the device list matches an em2800 device in the device list the model id gets changed accordingly. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 30 ++++++++++++++++++++++++++++++ drivers/media/video/em28xx/em28xx-i2c.c | 19 +++++++++++++------ drivers/media/video/em28xx/em28xx-video.c | 1 + drivers/media/video/em28xx/em28xx.h | 2 ++ 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index ae6634156e7..fd7a8a5fba6 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -402,6 +402,11 @@ static struct em28xx_hash_table em28xx_hash [] = { { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, }; +static struct em28xx_hash_table em28xx_i2c_hash[] = { + { 0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC }, + { 0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC }, +}; + /* Since em28xx_pre_card_setup() requires a proper dev->model, * this won't work for boards with generic PCI IDs */ @@ -498,6 +503,30 @@ static int em28xx_hint_board(struct em28xx *dev) return 0; } } + + /* user did not request i2c scanning => do it now */ + if (!dev->i2c_hash) + em28xx_do_i2c_scan(dev); + + for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { + if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { + dev->model = em28xx_i2c_hash[i].model; + dev->tuner_type = em28xx_i2c_hash[i].tuner; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on i2c devicelist hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + em28xx_errdev("Your board has no unique USB ID and thus need a " "hint to be detected.\n"); em28xx_errdev("You may try to use card= insmod option to " @@ -505,6 +534,7 @@ static int em28xx_hint_board(struct em28xx *dev) em28xx_errdev("Please send an email with this log to:\n"); em28xx_errdev("\tV4L Mailing List \n"); em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); em28xx_errdev("Here is a list of valid choices for the card=" " insmod option:\n"); diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index e2003455f2b..acd853d217e 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -533,19 +533,26 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -static void do_i2c_scan(char *name, struct i2c_client *c) +void em28xx_do_i2c_scan(struct em28xx *dev) { + u8 i2c_devicelist[128]; unsigned char buf; int i, rc; + memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 0); + dev->i2c_client.addr = i; + rc = i2c_master_recv(&dev->i2c_client, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name, - i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + i2c_devicelist[i] = i; + printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", + dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } + + dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, + ARRAY_SIZE(i2c_devicelist), 32); } /* @@ -578,7 +585,7 @@ int em28xx_i2c_register(struct em28xx *dev) em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); if (i2c_scan) - do_i2c_scan(dev->name, &dev->i2c_client); + em28xx_do_i2c_scan(dev); return 0; } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index bc495a11dc2..b43edc3fa23 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1510,6 +1510,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; dev->em28xx_write_regs_req = em28xx_write_regs_req; dev->em28xx_read_reg_req = em28xx_read_reg_req; + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; /* setup video picture settings for saa7113h */ memset(&dev->vpic, 0, sizeof(dev->vpic)); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 70fddd45d1f..c2531da2e61 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -260,6 +260,7 @@ struct em28xx { int type; unsigned long hash; /* eeprom hash - for boards with generic ID */ + unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ /* states */ enum em28xx_dev_state state; @@ -296,6 +297,7 @@ struct em28xx { /* Provided by em28xx-i2c.c */ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg); +void em28xx_do_i2c_scan(struct em28xx *dev); int em28xx_i2c_register(struct em28xx *dev); int em28xx_i2c_unregister(struct em28xx *dev); -- cgit v1.2.3 From d2ba055d3b7ca7694af38a735f00850363ee9417 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 4 Nov 2007 08:32:42 -0300 Subject: V4L/DVB (6546): Add comments for the hint methods Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index fd7a8a5fba6..e88bf6700e6 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -397,11 +397,13 @@ struct usb_device_id em28xx_id_table [] = { }; MODULE_DEVICE_TABLE (usb, em28xx_id_table); -static struct em28xx_hash_table em28xx_hash [] = { +/* EEPROM hash table for devices with generic USB IDs */ +static struct em28xx_hash_table em28xx_eeprom_hash [] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, }; +/* I2C devicelist hash table for devices with generic USB IDs */ static struct em28xx_hash_table em28xx_i2c_hash[] = { { 0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC }, { 0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC }, @@ -484,10 +486,18 @@ static int em28xx_hint_board(struct em28xx *dev) { int i; - for (i = 0; i < ARRAY_SIZE(em28xx_hash); i++) { - if (dev->hash == em28xx_hash[i].hash) { - dev->model = em28xx_hash[i].model; - dev->tuner_type = em28xx_hash[i].tuner; + /* HINT method: EEPROM + * + * This method works only for boards with eeprom. + * Uses a hash of all eeprom bytes. The hash should be + * unique for a vendor/tuner pair. + * There are a high chance that tuners for different + * video standards produce different hashes. + */ + for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { + if (dev->hash == em28xx_eeprom_hash[i].hash) { + dev->model = em28xx_eeprom_hash[i].model; + dev->tuner_type = em28xx_eeprom_hash[i].tuner; em28xx_errdev("Your board has no unique USB ID.\n"); em28xx_errdev("A hint were successfully done, " @@ -504,6 +514,15 @@ static int em28xx_hint_board(struct em28xx *dev) } } + /* HINT method: I2C attached devices + * + * This method works for all boards. + * Uses a hash of i2c scanned devices. + * Devices with the same i2c attached chips will + * be considered equal. + * This method is less precise than the eeprom one. + */ + /* user did not request i2c scanning => do it now */ if (!dev->i2c_hash) em28xx_do_i2c_scan(dev); -- cgit v1.2.3 From e3e97fe61f25aa36b96afe2f16a915dd966c70b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Jan 2008 11:01:40 -0200 Subject: V4L/DVB(6548a) Fix compilation for TDA8290 From: Mauro Carvalho Chehab drivers/media/video/tda8290.c:27:21: error: tda827x.h: No such file or directory drivers/media/video/tda8290.c:28:22: error: tda18271.h: No such file or directory drivers/media/video/tda8290.c:52: error: field 'cfg' has incomplete type drivers/media/video/tda8290.c: In function 'tda829x_find_tuner': drivers/media/video/tda8290.c:590: error: implicit declaration of function 'tda18271_attach' drivers/media/video/tda8290.c:598: error: implicit declaration of function 'tda827x_attach' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index d8910d87aca..a837e1ea518 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -132,3 +132,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -- cgit v1.2.3 From 232fcefb55e67cf38176a1e5c188a04694445f11 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 25 Jan 2008 11:01:41 -0200 Subject: V4L/DVB(6548b) Fix compilation for em28xx From: Mauro Carvalho Chehab In file included from drivers/media/video/em28xx/em28xx-i2c.c:31: drivers/media/video/tuner-xc2028.h:10:26: error: dvb_frontend.h: No such file or directory In file included from drivers/media/video/em28xx/em28xx-i2c.c:31: drivers/media/video/tuner-xc2028.h:32: warning: 'struct dvb_frontend' declared inside parameter list drivers/media/video/tuner-xc2028.h:32: warning: its scope is only this definition or declaration, which is probably not what you want Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 826d0e34075..7e7a93d75c3 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -4,3 +4,6 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + -- cgit v1.2.3 From 1f3a4e328549cb85aa032c4ee5dfda7886754154 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 4 Nov 2007 10:51:28 -0300 Subject: V4L/DVB (6550): tda8290: return -ENODEV on probe failures Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index dd239965465..18e6a09642f 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -649,7 +649,7 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props) return 0; } - return -1; + return -ENODEV; } static int tda8295_probe(struct tuner_i2c_props *i2c_props) @@ -669,7 +669,7 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) return 0; } - return -1; + return -ENODEV; } static struct analog_tuner_ops tda8290_tuner_ops = { @@ -766,7 +766,7 @@ int tda829x_probe(struct tuner *t) } } tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); - return -1; + return -ENODEV; } EXPORT_SYMBOL_GPL(tda829x_probe); -- cgit v1.2.3 From a818e1c8f7fcb42866a8630c508caddaa8edb331 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 4 Nov 2007 11:03:22 -0300 Subject: V4L/DVB (6551): tda8290: rule out tda988x before detecting tda8290/tda8295 To ensure prevention of detecting a tda9885/6/7 as a tda8290 or tda8295, we will rule out the tda988x before testing the tda8290 / tda8295 id registers. We read 8 bytes from the chip. If they are all equal, then it is not a tda829x, or some other error has occurred. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 18e6a09642f..f0191babe40 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -746,6 +746,22 @@ int tda829x_probe(struct tuner *t) unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; unsigned char addr_dto_lsb = 0x07; unsigned char data; +#define PROBE_BUFFER_SIZE 8 + unsigned char buf[PROBE_BUFFER_SIZE]; + int i; + + /* rule out tda9887, which would return the same byte repeatedly */ + tuner_i2c_xfer_send(&i2c_props, soft_reset, 1); + tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE); + for (i = 1; i < PROBE_BUFFER_SIZE; i++) { + if (buf[i] == buf[0]) + continue; + break; + } + + /* all bytes are equal, not a tda829x - probably a tda9887 */ + if (i == PROBE_BUFFER_SIZE) + return -ENODEV; if ((tda8290_probe(&i2c_props) == 0) || (tda8295_probe(&i2c_props) == 0)) -- cgit v1.2.3 From 159ffe77cd9b1cd7c80c416b5635bdad7e3d7d55 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 4 Nov 2007 10:42:42 -0300 Subject: V4L/DVB (6553): tuner: replace default_mode_mask The default_mode_mask global is replaced by a list of tuner structs. The tuner driver now walks that list to see which radio and/or tv tuner devices are registered to a given i2c adapter. The default_mode_mask global had to go since this is no longer supported with the new bus-based I2C API. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 65 +++++++++++++++++++++++++++++++------- drivers/media/video/tuner-driver.h | 1 + 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 3ec50dbed74..4f2bd2dd15c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -585,8 +585,38 @@ static void tuner_status(struct dvb_frontend *fe) /* ---------------------------------------------------------------------- */ -/* static vars: used only in tuner_attach and tuner_probe */ -static unsigned default_mode_mask; +LIST_HEAD(tuner_list); + +/* Search for existing radio and/or TV tuners on the given I2C adapter. + Note that when this function is called from tuner_attach you can be + certain no other devices will be added/deleted at the same time, I2C + core protects against that. */ +static void tuner_lookup(struct i2c_adapter *adap, + struct tuner **radio, struct tuner **tv) +{ + struct tuner *pos; + + *radio = NULL; + *tv = NULL; + + list_for_each_entry(pos, &tuner_list, list) { + int mode_mask; + + if (pos->i2c->adapter != adap || + pos->i2c->driver->id != I2C_DRIVERID_TUNER) + continue; + + mode_mask = pos->mode_mask & ~T_STANDBY; + if (*radio == NULL && mode_mask == T_RADIO) + *radio = pos; + /* Note: currently TDA9887 is the only demod-only + device. If other devices appear then we need to + make this test more general. */ + else if (*tv == NULL && pos->type != TUNER_TDA9887 && + (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) + *tv = pos; + } +} /* During client attach, set_type is called by adapter's attach_inform callback. set_type must then be completed by tuner_attach. @@ -595,6 +625,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { struct i2c_client *client; struct tuner *t; + struct tuner *radio; + struct tuner *tv; client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (NULL == client) @@ -638,7 +670,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) t->mode_mask = T_RADIO; t->mode = T_STANDBY; t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask &= ~T_RADIO; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; goto register_client; } @@ -665,7 +699,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) t->mode_mask = T_RADIO; t->mode = T_STANDBY; t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask &= ~T_RADIO; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; goto register_client; } @@ -673,13 +709,21 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) } } - /* Initializes only the first adapter found */ - if (default_mode_mask != T_UNINITIALIZED) { - tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); - t->mode_mask = default_mode_mask; + /* Initializes only the first TV tuner on this adapter. Why only the + first? Because there are some devices (notably the ones with TI + tuners) that have more than one i2c address for the *same* device. + Experience shows that, except for just one case, the first + address is the right one. The exception is a Russian tuner + (ACORP_Y878F). So, the desired behavior is just to enable the + first found TV tuner. */ + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv == NULL) { + t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + if (radio == NULL) + t->mode_mask |= T_RADIO; + tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); t->tv_freq = 400 * 16; /* Sets freq to VHF High */ t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask = T_UNINITIALIZED; } /* Should be just before return */ @@ -729,8 +773,6 @@ static int tuner_probe(struct i2c_adapter *adap) "in i2c probe ignore list!\n"); } - default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tuner_attach); return 0; @@ -752,6 +794,7 @@ static int tuner_detach(struct i2c_client *client) if (ops && ops->release) ops->release(&t->fe); + list_del(&t->list); kfree(t); kfree(client); return 0; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 1c60229dcd0..3ff2943ecc1 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -46,6 +46,7 @@ struct analog_tuner_ops { struct tuner { /* device */ struct i2c_client *i2c; + struct list_head list; /* list of tuners */ unsigned int type; /* chip type */ -- cgit v1.2.3 From 92de1f16d15a30831d1685949aeb76c99032ef23 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 4 Nov 2007 10:53:09 -0300 Subject: V4L/DVB (6555): tuner: reorder functions to prepare for i2c conversion Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 438 ++++++++++++++++++++------------------- 1 file changed, 223 insertions(+), 215 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 4f2bd2dd15c..48b2d46048a 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -585,221 +585,6 @@ static void tuner_status(struct dvb_frontend *fe) /* ---------------------------------------------------------------------- */ -LIST_HEAD(tuner_list); - -/* Search for existing radio and/or TV tuners on the given I2C adapter. - Note that when this function is called from tuner_attach you can be - certain no other devices will be added/deleted at the same time, I2C - core protects against that. */ -static void tuner_lookup(struct i2c_adapter *adap, - struct tuner **radio, struct tuner **tv) -{ - struct tuner *pos; - - *radio = NULL; - *tv = NULL; - - list_for_each_entry(pos, &tuner_list, list) { - int mode_mask; - - if (pos->i2c->adapter != adap || - pos->i2c->driver->id != I2C_DRIVERID_TUNER) - continue; - - mode_mask = pos->mode_mask & ~T_STANDBY; - if (*radio == NULL && mode_mask == T_RADIO) - *radio = pos; - /* Note: currently TDA9887 is the only demod-only - device. If other devices appear then we need to - make this test more general. */ - else if (*tv == NULL && pos->type != TUNER_TDA9887 && - (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) - *tv = pos; - } -} - -/* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_attach. - */ -static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct i2c_client *client; - struct tuner *t; - struct tuner *radio; - struct tuner *tv; - - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (NULL == client) - return -ENOMEM; - - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) { - kfree(client); - return -ENOMEM; - } - t->i2c = client; - client_template.adapter = adap; - client_template.addr = addr; - memcpy(client, &client_template, sizeof(struct i2c_client)); - i2c_set_clientdata(client, t); - t->type = UNSET; - t->audmode = V4L2_TUNER_MODE_STEREO; - t->mode_mask = T_UNINITIALIZED; - - if (show_i2c) { - unsigned char buffer[16]; - int i,rc; - - memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(client, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i=0;iid == I2C_HW_SAA7146 && addr < 0x4a) - return -ENODEV; - - /* autodetection code based on the i2c addr */ - if (!no_autodetect) { - switch (addr) { - case 0x10: - if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) { - t->type = TUNER_TEA5761; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - case 0x42: - case 0x43: - case 0x4a: - case 0x4b: - /* If chip is not tda8290, don't register. - since it can be tda9887*/ - if (tda829x_probe(t) == 0) { - tuner_dbg("tda829x detected\n"); - } else { - /* Default is being tda9887 */ - t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - t->mode = T_STANDBY; - goto register_client; - } - break; - case 0x60: - if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) { - t->type = TUNER_TEA5767; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - } - } - - /* Initializes only the first TV tuner on this adapter. Why only the - first? Because there are some devices (notably the ones with TI - tuners) that have more than one i2c address for the *same* device. - Experience shows that, except for just one case, the first - address is the right one. The exception is a Russian tuner - (ACORP_Y878F). So, the desired behavior is just to enable the - first found TV tuner. */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv == NULL) { - t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - if (radio == NULL) - t->mode_mask |= T_RADIO; - tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); - t->tv_freq = 400 * 16; /* Sets freq to VHF High */ - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - } - - /* Should be just before return */ -register_client: - tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); - - /* Sets a default mode */ - if (t->mode_mask & T_ANALOG_TV) { - t->mode = T_ANALOG_TV; - } else if (t->mode_mask & T_RADIO) { - t->mode = T_RADIO; - } else { - t->mode = T_DIGITAL_TV; - } - - i2c_attach_client (client); - set_type (client,t->type, t->mode_mask, t->config, t->tuner_callback); - return 0; -} - -static int tuner_probe(struct i2c_adapter *adap) -{ - if (0 != addr) { - normal_i2c[0] = addr; - normal_i2c[1] = I2C_CLIENT_END; - } - - /* HACK: Ignore 0x6b and 0x6f on cx88 boards. - * FusionHDTV5 RT Gold has an ir receiver at 0x6b - * and an RTC at 0x6f which can get corrupted if probed. - */ - if ((adap->id == I2C_HW_B_CX2388x) || - (adap->id == I2C_HW_B_CX23885)) { - unsigned int i = 0; - - while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) - i += 2; - if (i + 4 < I2C_CLIENT_MAX_OPTS) { - ignore[i+0] = adap->nr; - ignore[i+1] = 0x6b; - ignore[i+2] = adap->nr; - ignore[i+3] = 0x6f; - ignore[i+4] = I2C_CLIENT_END; - } else - printk(KERN_WARNING "tuner: " - "too many options specified " - "in i2c probe ignore list!\n"); - } - - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; -} - -static int tuner_detach(struct i2c_client *client) -{ - struct tuner *t = i2c_get_clientdata(client); - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; - int err; - - err = i2c_detach_client(t->i2c); - if (err) { - tuner_warn - ("Client deregistration failed, client not detached.\n"); - return err; - } - - if (ops && ops->release) - ops->release(&t->fe); - - list_del(&t->list); - kfree(t); - kfree(client); - return 0; -} - /* * Switch tuner to other mode. If tuner support both tv and radio, * set another frequency to some value (This is needed for some pal @@ -1156,6 +941,229 @@ static int tuner_resume(struct i2c_client *c) return 0; } +/* ---------------------------------------------------------------------- */ + +LIST_HEAD(tuner_list); + +/* Search for existing radio and/or TV tuners on the given I2C adapter. + Note that when this function is called from tuner_attach you can be + certain no other devices will be added/deleted at the same time, I2C + core protects against that. */ +static void tuner_lookup(struct i2c_adapter *adap, + struct tuner **radio, struct tuner **tv) +{ + struct tuner *pos; + + *radio = NULL; + *tv = NULL; + + list_for_each_entry(pos, &tuner_list, list) { + int mode_mask; + + if (pos->i2c->adapter != adap || + pos->i2c->driver->id != I2C_DRIVERID_TUNER) + continue; + + mode_mask = pos->mode_mask & ~T_STANDBY; + if (*radio == NULL && mode_mask == T_RADIO) + *radio = pos; + /* Note: currently TDA9887 is the only demod-only + device. If other devices appear then we need to + make this test more general. */ + else if (*tv == NULL && pos->type != TUNER_TDA9887 && + (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) + *tv = pos; + } +} + +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_attach. + */ +static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct i2c_client *client; + struct tuner *t; + struct tuner *radio; + struct tuner *tv; + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (NULL == client) + return -ENOMEM; + + t = kzalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) { + kfree(client); + return -ENOMEM; + } + t->i2c = client; + client_template.adapter = adap; + client_template.addr = addr; + memcpy(client, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(client, t); + t->type = UNSET; + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + + if (show_i2c) { + unsigned char buffer[16]; + int i, rc; + + memset(buffer, 0, sizeof(buffer)); + rc = i2c_master_recv(client, buffer, sizeof(buffer)); + tuner_info("I2C RECV = "); + for (i = 0; i < rc; i++) + printk(KERN_CONT "%02x ", buffer[i]); + printk("\n"); + } + /* HACK: This test were added to avoid tuner to probe tda9840 and + tea6415c on the MXB card */ + if (adap->id == I2C_HW_SAA7146 && addr < 0x4a) + return -ENODEV; + + /* autodetection code based on the i2c addr */ + if (!no_autodetect) { + switch (addr) { + case 0x10: + if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) + != EINVAL) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + case 0x42: + case 0x43: + case 0x4a: + case 0x4b: + /* If chip is not tda8290, don't register. + since it can be tda9887*/ + if (tda829x_probe(t) == 0) { + tuner_dbg("tda829x detected\n"); + } else { + /* Default is being tda9887 */ + t->type = TUNER_TDA9887; + t->mode_mask = T_RADIO | T_ANALOG_TV | + T_DIGITAL_TV; + t->mode = T_STANDBY; + goto register_client; + } + break; + case 0x60: + if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) + != EINVAL) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + } + } + + /* Initializes only the first TV tuner on this adapter. Why only the + first? Because there are some devices (notably the ones with TI + tuners) that have more than one i2c address for the *same* device. + Experience shows that, except for just one case, the first + address is the right one. The exception is a Russian tuner + (ACORP_Y878F). So, the desired behavior is just to enable the + first found TV tuner. */ + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv == NULL) { + t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + if (radio == NULL) + t->mode_mask |= T_RADIO; + tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); + t->tv_freq = 400 * 16; /* Sets freq to VHF High */ + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + } + + /* Should be just before return */ +register_client: + tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); + + /* Sets a default mode */ + if (t->mode_mask & T_ANALOG_TV) { + t->mode = T_ANALOG_TV; + } else if (t->mode_mask & T_RADIO) { + t->mode = T_RADIO; + } else { + t->mode = T_DIGITAL_TV; + } + + i2c_attach_client(client); + set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); + return 0; +} + +static int tuner_probe(struct i2c_adapter *adap) +{ + if (0 != addr) { + normal_i2c[0] = addr; + normal_i2c[1] = I2C_CLIENT_END; + } + + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; +} + +static int tuner_detach(struct i2c_client *client) +{ + struct tuner *t = i2c_get_clientdata(client); + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + int err; + + err = i2c_detach_client(t->i2c); + if (err) { + tuner_warn + ("Client deregistration failed, client not detached.\n"); + return err; + } + + if (ops && ops->release) + ops->release(&t->fe); + + list_del(&t->list); + kfree(t); + kfree(client); + return 0; +} + /* ----------------------------------------------------------------------- */ static struct i2c_driver driver = { -- cgit v1.2.3 From 9dd659de9fbd1687c6175053c6453db5b932f152 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 4 Nov 2007 11:03:36 -0300 Subject: V4L/DVB (6556): tuner: convert to bus-based I2C API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt20xx.c | 2 +- drivers/media/video/tda8290.c | 2 +- drivers/media/video/tea5761.c | 2 +- drivers/media/video/tea5767.c | 2 +- drivers/media/video/tuner-core.c | 99 ++++++++++++-------------------------- drivers/media/video/tuner-driver.h | 6 +-- drivers/media/video/tuner-i2c.h | 6 +-- drivers/media/video/tuner-simple.c | 2 +- drivers/media/video/tuner-xc2028.c | 2 +- 9 files changed, 44 insertions(+), 79 deletions(-) diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index f49d1f4c40d..b630c26cfe8 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -14,7 +14,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "mt20xx " +#define PREFIX "mt20xx" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index f0191babe40..a849ded0000 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -31,7 +31,7 @@ static int tuner_debug; module_param_named(debug, tuner_debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tda8290 " +#define PREFIX "tda8290" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 2150222a386..5326eeceaac 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -18,7 +18,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5761 " +#define PREFIX "tea5761" struct tea5761_priv { struct tuner_i2c_props i2c_props; diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 2d2acbdd24a..2f5a99de185 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -20,7 +20,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5767 " +#define PREFIX "tea5767" /*****************************************************************************/ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 48b2d46048a..1b0d28a0ca7 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" @@ -30,7 +31,7 @@ #define UNSET (-1U) -#define PREFIX "tuner " +#define PREFIX t->i2c->driver->driver.name /* standard i2c insmod options */ static unsigned short normal_i2c[] = { @@ -75,9 +76,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 struct i2c_driver driver; -static struct i2c_client client_template; - /* ---------------------------------------------------------------------- */ static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq) @@ -919,18 +917,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) static int tuner_suspend(struct i2c_client *c, pm_message_t state) { - struct tuner *t = i2c_get_clientdata (c); + struct tuner *t = i2c_get_clientdata(c); - tuner_dbg ("suspend\n"); + tuner_dbg("suspend\n"); /* FIXME: power down ??? */ return 0; } static int tuner_resume(struct i2c_client *c) { - struct tuner *t = i2c_get_clientdata (c); + struct tuner *t = i2c_get_clientdata(c); - tuner_dbg ("resume\n"); + tuner_dbg("resume\n"); if (V4L2_TUNER_RADIO == t->mode) { if (t->radio_freq) set_freq(c, t->radio_freq); @@ -946,7 +944,7 @@ static int tuner_resume(struct i2c_client *c) LIST_HEAD(tuner_list); /* Search for existing radio and/or TV tuners on the given I2C adapter. - Note that when this function is called from tuner_attach you can be + Note that when this function is called from tuner_probe you can be certain no other devices will be added/deleted at the same time, I2C core protects against that. */ static void tuner_lookup(struct i2c_adapter *adap, @@ -977,28 +975,19 @@ static void tuner_lookup(struct i2c_adapter *adap, } /* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_attach. + set_type must then be completed by tuner_probe. */ -static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) +static int tuner_probe(struct i2c_client *client) { - struct i2c_client *client; struct tuner *t; struct tuner *radio; struct tuner *tv; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (NULL == client) - return -ENOMEM; - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) { - kfree(client); + if (NULL == t) return -ENOMEM; - } t->i2c = client; - client_template.adapter = adap; - client_template.addr = addr; - memcpy(client, &client_template, sizeof(struct i2c_client)); + strlcpy(client->name, "(tuner unset)", sizeof(client->name)); i2c_set_clientdata(client, t); t->type = UNSET; t->audmode = V4L2_TUNER_MODE_STEREO; @@ -1015,14 +1004,16 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) printk(KERN_CONT "%02x ", buffer[i]); printk("\n"); } - /* HACK: This test were added to avoid tuner to probe tda9840 and + /* HACK: This test was added to avoid tuner to probe tda9840 and tea6415c on the MXB card */ - if (adap->id == I2C_HW_SAA7146 && addr < 0x4a) + if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) { + kfree(t); return -ENODEV; + } /* autodetection code based on the i2c addr */ if (!no_autodetect) { - switch (addr) { + switch (client->addr) { case 0x10: if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) != EINVAL) { @@ -1092,7 +1083,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) /* Should be just before return */ register_client: - tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); + tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, + client->adapter->name); /* Sets a default mode */ if (t->mode_mask & T_ANALOG_TV) { @@ -1102,19 +1094,21 @@ register_client: } else { t->mode = T_DIGITAL_TV; } - - i2c_attach_client(client); set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); + list_add_tail(&t->list, &tuner_list); return 0; } -static int tuner_probe(struct i2c_adapter *adap) +static int tuner_legacy_probe(struct i2c_adapter *adap) { if (0 != addr) { normal_i2c[0] = addr; normal_i2c[1] = I2C_CLIENT_END; } + if ((adap->class & I2C_CLASS_TV_ANALOG) == 0) + return 0; + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. * FusionHDTV5 RT Gold has an ir receiver at 0x6b * and an RTC at 0x6f which can get corrupted if probed. @@ -1136,64 +1130,35 @@ static int tuner_probe(struct i2c_adapter *adap) "too many options specified " "in i2c probe ignore list!\n"); } - - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; + return 1; } -static int tuner_detach(struct i2c_client *client) +static int tuner_remove(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; - int err; - - err = i2c_detach_client(t->i2c); - if (err) { - tuner_warn - ("Client deregistration failed, client not detached.\n"); - return err; - } if (ops && ops->release) ops->release(&t->fe); list_del(&t->list); kfree(t); - kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -static struct i2c_driver driver = { - .id = I2C_DRIVERID_TUNER, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tuner", + .driverid = I2C_DRIVERID_TUNER, .command = tuner_command, + .probe = tuner_probe, + .remove = tuner_remove, .suspend = tuner_suspend, - .resume = tuner_resume, - .driver = { - .name = "tuner", - }, + .resume = tuner_resume, + .legacy_probe = tuner_legacy_probe, }; -static struct i2c_client client_template = { - .name = "(tuner unset)", - .driver = &driver, -}; - -static int __init tuner_init_module(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit tuner_cleanup_module(void) -{ - i2c_del_driver(&driver); -} -module_init(tuner_init_module); -module_exit(tuner_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 3ff2943ecc1..d6e5afdaa82 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -72,15 +72,15 @@ struct tuner { /* ------------------------------------------------------------------------ */ #define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #define tuner_dbg(fmt, arg...) do {\ extern int tuner_debug; \ if (tuner_debug) \ - printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) #endif /* __TUNER_DRIVER_H__ */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h index 159019ec337..cfba3d10906 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/video/tuner-i2c.h @@ -48,14 +48,14 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, #ifndef __TUNER_DRIVER_H__ #define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) #define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) #define tuner_dbg(fmt, arg...) do {\ if ((debug)) \ - printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) #endif /* __TUNER_DRIVER_H__ */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index eec13cb6cd6..c1db576696c 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -17,7 +17,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tuner-simple " +#define PREFIX "tuner-simple" static int offset = 0; module_param(offset, int, 0664); diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 473fa73b181..80d14020c78 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -22,7 +22,7 @@ #include #include "dvb_frontend.h" -#define PREFIX "xc2028 " +#define PREFIX "xc2028" static LIST_HEAD(xc2028_list); /* struct for storing firmware table */ -- cgit v1.2.3 From e7a2bc8a756e5c0adc6804dd7702442a06174b74 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Nov 2007 06:19:39 -0300 Subject: V4L/DVB (6557): tea5767: remove unnecessary warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 2f5a99de185..e1b48d87e7b 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -401,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return EINVAL; } - printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } -- cgit v1.2.3 From b873e1a3ccf9e04d2de85db0d510ec4b793fe569 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 5 Nov 2007 08:41:50 -0300 Subject: V4L/DVB (6559): Fix a buffer overflow at xc2028_get_reg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 80d14020c78..b4c88ed12a8 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -94,13 +94,13 @@ struct xc2028_data { static int xc2028_get_reg(struct xc2028_data *priv, u16 reg) { int rc; - unsigned char buf[1]; + unsigned char buf[2]; tuner_info("%s called\n", __FUNCTION__); buf[0] = reg; - i2c_send(rc, priv, buf, sizeof(buf)); + i2c_send(rc, priv, buf, 1); if (rc < 0) return rc; -- cgit v1.2.3 From f8b6030ccca06bf0d45d9b0908caac9b624a9beb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 5 Nov 2007 08:42:55 -0300 Subject: V4L/DVB (6560): Fix a bug when setting tuner type Tuner-type were correctly filled only by the hint function. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index e88bf6700e6..b1afc6c2d37 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -564,8 +564,26 @@ static int em28xx_hint_board(struct em28xx *dev) return -1; } + +static void em28xx_set_model(struct em28xx *dev) +{ + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + dev->has_tuner = em28xx_boards[dev->model].has_tuner; + dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + dev->decoder = em28xx_boards[dev->model].decoder; + dev->video_inputs = em28xx_boards[dev->model].vchannels; + + if (!em28xx_boards[dev->model].has_tuner) + dev->tuner_type = UNSET; +} + void em28xx_card_setup(struct em28xx *dev) { + em28xx_set_model(dev); + + dev->tuner_type = em28xx_boards[dev->model].tuner_type; + /* request some modules */ switch (dev->model) { case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: @@ -593,16 +611,11 @@ void em28xx_card_setup(struct em28xx *dev) break; case EM2820_BOARD_UNKNOWN: case EM2800_BOARD_UNKNOWN: - em28xx_hint_board(dev); + if (!em28xx_hint_board(dev)) + em28xx_set_model(dev); } - dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->has_tuner = em28xx_boards[dev->model].has_tuner; - dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; - dev->decoder = em28xx_boards[dev->model].decoder; - dev->video_inputs = em28xx_boards[dev->model].vchannels; - + /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; -- cgit v1.2.3 From 80b522085a2c870ba0c0bdf2415cc925d7c86ca5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 5 Nov 2007 09:07:13 -0300 Subject: V4L/DVB (6561): Fix xc2028 get register functions and calls The status registers require a dword for setting register. Fix it on all occurrences, and at xc3028_get_reg. Also, improves the hardware/firmware detection printk. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index b4c88ed12a8..ecfc39036f9 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -91,16 +91,17 @@ struct xc2028_data { msleep(10); \ } while (0) -static int xc2028_get_reg(struct xc2028_data *priv, u16 reg) +static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) { int rc; unsigned char buf[2]; tuner_info("%s called\n", __FUNCTION__); - buf[0] = reg; + buf[0] = reg>>8; + buf[1] = (unsigned char) reg; - i2c_send(rc, priv, buf, 1); + i2c_send(rc, priv, buf, 2); if (rc < 0) return rc; @@ -372,7 +373,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, v4l2_std_id std, fe_bandwidth_t bandwidth) { struct xc2028_data *priv = fe->tuner_priv; - int rc, version; + int rc, version, hwmodel; v4l2_std_id std0 = 0; unsigned int type0 = 0, type = 0; int change_digital_bandwidth; @@ -484,9 +485,13 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (rc < 0) return rc; - version = xc2028_get_reg(priv, 0x4); - tuner_info("Firmware version is %d.%d\n", - (version >> 4) & 0x0f, (version) & 0x0f); + version = xc2028_get_reg(priv, 0x0004); + hwmodel = xc2028_get_reg(priv, 0x0008); + + tuner_info("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); priv->firm_type = std; @@ -504,13 +509,15 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) *strength = 0; - frq_lock = xc2028_get_reg(priv, 0x2); + /* Sync Lock Indicator */ + frq_lock = xc2028_get_reg(priv, 0x0002); if (frq_lock <= 0) goto ret; /* Frequency is locked. Return signal quality */ - signal = xc2028_get_reg(priv, 0x40); + /* Get SNR of the video signal */ + signal = xc2028_get_reg(priv, 0x0040); if (signal <= 0) signal = frq_lock; -- cgit v1.2.3 From 98ae127cae56b99f2282d73399e0e1ca7dc13bc9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 5 Nov 2007 09:30:39 -0300 Subject: V4L/DVB (6562): Make HVR900 to use also tveeprom Hauppauge firmwares can be decoded using tveeprom. This patch adds HVR-900 as a tveeprom client. It also adds xc3028 tuner entry to tveeprom. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 8 +++++++- drivers/media/video/tveeprom.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index b1afc6c2d37..a2c0794821b 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -587,11 +587,11 @@ void em28xx_card_setup(struct em28xx *dev) /* request some modules */ switch (dev->model) { case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: { struct tveeprom tv; #ifdef CONFIG_MODULES request_module("tveeprom"); - request_module("ir-kbd-i2c"); #endif /* Call first TVeeprom */ @@ -603,6 +603,12 @@ void em28xx_card_setup(struct em28xx *dev) dev->i2s_speed = 2048000; dev->has_msp34xx = 1; } +#ifdef CONFIG_MODULES + if (tv.has_ir) + request_module("ir-kbd-i2c"); +#endif + /* FIXME: Should also retrieve decoder processor type */ + break; } case EM2820_BOARD_KWORLD_PVRTV2800RF: diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 0faa1499235..403fbd0afa3 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -226,7 +226,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "TCL M2523_3DI_E"}, { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ - { TUNER_ABSENT, "Xceive XC3028"}, + { TUNER_XC2028, "Xceive XC3028"}, { TUNER_ABSENT, "Philips FQ1216LME MK5"}, { TUNER_ABSENT, "Philips FQD1216LME"}, { TUNER_ABSENT, "Conexant CX24118A"}, -- cgit v1.2.3 From bbe1e0ba527a18e1ddda2eabb9da369e5bcf556e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 5 Nov 2007 09:54:42 -0300 Subject: V4L/DVB (6563): tda8290: optimize for loop in tda829x_probe function Thanks to Trent Piepho for pointing this out. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a849ded0000..c606f3c38cf 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -754,9 +754,8 @@ int tda829x_probe(struct tuner *t) tuner_i2c_xfer_send(&i2c_props, soft_reset, 1); tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE); for (i = 1; i < PROBE_BUFFER_SIZE; i++) { - if (buf[i] == buf[0]) - continue; - break; + if (buf[i] != buf[0]) + break; } /* all bytes are equal, not a tda829x - probably a tda9887 */ -- cgit v1.2.3 From c80296d755df29167deafa53e612644a95b40c6e Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Tue, 6 Nov 2007 10:25:16 -0300 Subject: V4L/DVB (6564): Move check before lock Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Andrew Morton CC: Antti Palosaari CC: Carl Lundqvist CC: Aapo Tahkola Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/au6610.c | 6 +++--- drivers/media/dvb/dvb-usb/gl861.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 18e0b16fb2a..f3ff8131469 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - if (num > 2) return -EINVAL; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index f01d99c1c43..6b99d9f4d5b 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - if (num > 2) return -EINVAL; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { -- cgit v1.2.3 From b00ef4b8d8c29bfb5f6f92ee60bc04b604f36ef2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:06:31 -0300 Subject: V4L/DVB (6569): bt8xx/dst.c: make code static This patch makes the following needlessly global code static: - dst_gpio_outb() - dst_gpio_inb() - rdc_8820_reset() - dst_pio_enable() - dst_command() - struct tuner_list[] Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dst.c | 19 ++++++++----------- drivers/media/dvb/bt8xx/dst_common.h | 5 ----- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index b7a17e69ca4..307ff35bdf1 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); } \ } while(0) +static int dst_command(struct dst_state *state, u8 *data, u8 len); static void dst_packsize(struct dst_state *state, int psize) { @@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) +static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, + u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int return 0; } -EXPORT_SYMBOL(dst_gpio_outb); -int dst_gpio_inb(struct dst_state *state, u8 *result) +static int dst_gpio_inb(struct dst_state *state, u8 *result) { union dst_gpio_packet rd_packet; int err; @@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result) return 0; } -EXPORT_SYMBOL(dst_gpio_inb); int rdc_reset_state(struct dst_state *state) { @@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state) } EXPORT_SYMBOL(rdc_reset_state); -int rdc_8820_reset(struct dst_state *state) +static int rdc_8820_reset(struct dst_state *state) { dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { @@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state) return 0; } -EXPORT_SYMBOL(rdc_8820_reset); -int dst_pio_enable(struct dst_state *state) +static int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); @@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state) return 0; } -EXPORT_SYMBOL(dst_pio_enable); int dst_pio_disable(struct dst_state *state) { @@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type) return 0; } -struct tuner_types tuner_list[] = { +static struct tuner_types tuner_list[] = { { .tuner_type = TUNER_TYPE_L64724, .tuner_name = "L 64724", @@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state) return 0; } -int dst_command(struct dst_state *state, u8 *data, u8 len) +static int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; @@ -1287,7 +1285,6 @@ error: return -EIO; } -EXPORT_SYMBOL(dst_command); static int dst_get_signal(struct dst_state *state) { diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 87623d203a8..d88cf2add82 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -165,10 +165,8 @@ struct dst_config }; int rdc_reset_state(struct dst_state *state); -int rdc_8820_reset(struct dst_state *state); int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); -int dst_pio_enable(struct dst_state *state); int dst_pio_disable(struct dst_state *state); int dst_error_recovery(struct dst_state* state); int dst_error_bailout(struct dst_state *state); @@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len); u8 dst_check_sum(u8 * buf, u32 len); struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); -int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay); - -int dst_command(struct dst_state* state, u8 * data, u8 len); #endif // DST_COMMON_H -- cgit v1.2.3 From 67b24c78839067729b660116ba394568cd136130 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:06:38 -0300 Subject: V4L/DVB (6570): core/dvb_ringbuffer.c: remove unused exports This patch removes the following unused EXPORT_SYMBOL's: - dvb_ringbuffer_flush - dvb_ringbuffer_pkt_write - dvb_ringbuffer_pkt_read - dvb_ringbuffer_pkt_dispose - dvb_ringbuffer_pkt_next Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ringbuffer.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 9878183ba3f..ac9d93cf83c 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_empty); EXPORT_SYMBOL(dvb_ringbuffer_free); EXPORT_SYMBOL(dvb_ringbuffer_avail); -EXPORT_SYMBOL(dvb_ringbuffer_flush); EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); -- cgit v1.2.3 From ad1ce84047a39aec735ef0d5efe29b845bea3262 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:06:41 -0300 Subject: V4L/DVB (6571): dvb-usb/gp8psk.c: #if 0 gp8psk_bcm4500_reload() This patch #if 0's the unused gp8psk_bcm4500_reload() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/gp8psk.c | 16 ---------------- drivers/media/dvb/dvb-usb/gp8psk.h | 1 - 2 files changed, 17 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 92147ee3e14..83e8535014c 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -int gp8psk_bcm4500_reload(struct dvb_usb_device *d) -{ - u8 buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn On 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - /* load BCM4500 firmware */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_load_bcm4500fw(d)) - return EINVAL; - return 0; -} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index e83a57506cf..e5cd8149c23 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif -- cgit v1.2.3 From 5e7361a143e94f85cd5f885782592fa835a3d001 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:06:47 -0300 Subject: V4L/DVB (6572): dvb-usb/vp702x.c: cleanups This patch contains the following cleanups: - make the needlessly global vp702x_usb_out_op() static - #if 0 the unused vp702x_power_ctrl() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/vp702x.c | 15 +-------------- drivers/media/dvb/dvb-usb/vp702x.h | 2 -- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 16533b31a82..e553c139ac4 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 return ret; } -int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { int ret; @@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } -int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - struct vp702x_device_state *st = d->priv; - - if (st->power_state == 0 && onoff) - vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); - else if (st->power_state == 1 && onoff == 0) - vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); - - st->power_state = onoff; - - return 0; -} static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h index 25a9dee4c82..c2f97f96c21 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.h +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff); #endif -- cgit v1.2.3 From 6fce7fcd6d062f7acb423c5d6a190f2977454640 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:06:52 -0300 Subject: V4L/DVB (6573): unexport flexcop_reset_block_300 This patch removes the unused EXPORT_SYMBOL(flexcop_reset_block_300). Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 29ec4183118..2ddafd071c9 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc) fc->write_ibi_reg(fc,ctrl_208,v208_save); } -EXPORT_SYMBOL(flexcop_reset_block_300); struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { -- cgit v1.2.3 From 9695a49839353bdaff79fe27399be2eb72585223 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:07:18 -0300 Subject: V4L/DVB (6574): common/ir-functions.c: make a function static ir_rc5_decode() can become static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-functions.c | 3 +-- include/media/ir-common.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index e7c3ab951a4..bb2a027b948 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high) * saa7134 */ /* decode raw bit pattern to RC5 code */ -u32 ir_rc5_decode(unsigned int code) +static u32 ir_rc5_decode(unsigned int code) { unsigned int org_code = code; unsigned int pair; @@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples); EXPORT_SYMBOL_GPL(ir_decode_biphase); EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); -EXPORT_SYMBOL_GPL(ir_rc5_decode); EXPORT_SYMBOL_GPL(ir_rc5_timer_end); EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup); diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 7a785fa7721..b904d325726 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -97,7 +97,6 @@ int ir_dump_samples(u32 *samples, int count); int ir_decode_biphase(u32 *samples, int count, int low, int high); int ir_decode_pulsedistance(u32 *samples, int count, int low, int high); -u32 ir_rc5_decode(unsigned int code); void ir_rc5_timer_end(unsigned long data); void ir_rc5_timer_keyup(unsigned long data); -- cgit v1.2.3 From 39e75cfedf5b40116136894241ca1182089f3637 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:07:20 -0300 Subject: V4L/DVB (6575): cx23885/: cleanups This patch contains the following cleanups: - make the following needlessly global code static: - cx23885-core.c: struct cx23885_sram_channels[] - cx23885-core.c: struct cx23887_sram_channels[] - cx23885-core.c: cx23885_wakeup() - cx23885-core.c: cx23885_sram_channel_setup() - cx23885-core.c: cx23885_sram_channel_dump() - cx23885-core.c: cx23885_risc_disasm() - cx23885-core.c: cx23885_shutdown() - cx23885-core.c: cx23885_reset() - cx23885-core.c: cx23885_dev_unregister() - cx23885-core.c: cx23885_risc_databuffer() - cx23885-core.c: cx23885_risc_stopper() - #if 0 the following unused functions: - cx23885-core.c: cx23885_risc_buffer() - cx23885-core.c: cx23885_cancel_buffers() - remove the following unused EXPORT_SYMBOL's: - cx23885-cards.c: cx23885_boards - cx23885-i2c.c: cx23885_call_i2c_clients Signed-off-by: Adrian Bunk Reviewed-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 2 - drivers/media/video/cx23885/cx23885-core.c | 95 +++++++---------------------- drivers/media/video/cx23885/cx23885-i2c.c | 2 - drivers/media/video/cx23885/cx23885.h | 4 -- 4 files changed, 23 insertions(+), 80 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index b9012acabb2..134b931b160 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -270,8 +270,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx23885_boards); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3cdd136477e..0c9c9af0efb 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -73,7 +73,7 @@ static LIST_HEAD(cx23885_devlist); * 0x00010ea0 0x00010xxx Free */ -struct sram_channel cx23885_sram_channels[] = { +static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH01] = { .name = "test ch1", .cmds_start = 0x10000, @@ -205,7 +205,7 @@ struct sram_channel cx23885_sram_channels[] = { * 0x00010ea0 0x00010xxx Free */ -struct sram_channel cx23887_sram_channels[] = { +static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { .name = "test ch1", .cmds_start = 0x0, @@ -356,8 +356,8 @@ static int cx23885_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) +static void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -391,12 +391,10 @@ void cx23885_wakeup(struct cx23885_tsport *port, printk("%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); } -void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); -int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) +static int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc) { unsigned int i, lines; u32 cdt; @@ -467,8 +465,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, return 0; } -void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) +static void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -529,8 +527,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) +static void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -548,7 +546,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port, } } -void cx23885_shutdown(struct cx23885_dev *dev) +static void cx23885_shutdown(struct cx23885_dev *dev) { /* disable RISC controller */ cx_write(DEV_CNTRL2, 0); @@ -578,7 +576,7 @@ void cx23885_shutdown(struct cx23885_dev *dev) } -void cx23885_reset(struct cx23885_dev *dev) +static void cx23885_reset(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); @@ -636,8 +634,8 @@ static int get_resources(struct cx23885_dev *dev) } static void cx23885_timeout(unsigned long data); -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); +static int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -837,7 +835,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) return 0; } -void cx23885_dev_unregister(struct cx23885_dev *dev) +static void cx23885_dev_unregister(struct cx23885_dev *dev) { release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); @@ -912,49 +910,12 @@ static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, return rp; } -int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int top_offset, - unsigned int bottom_offset, unsigned int bpl, - unsigned int padding, unsigned int lines) -{ - u32 instructions, fields; - u32 *rp; - int rc; - - fields = 0; - if (UNSET != top_offset) - fields++; - if (UNSET != bottom_offset) - fields++; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - /* write and jump need and extra dword */ - instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - if (UNSET != top_offset) - rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines); - if (UNSET != bottom_offset) - rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines); - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); - return 0; -} -int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) +static int cx23885_risc_databuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -981,8 +942,8 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, return 0; } -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) +static int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -1243,16 +1204,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_unlock_irqrestore(&port->slock, flags); } -void cx23885_cancel_buffers(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __FUNCTION__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} static void cx23885_timeout(unsigned long data) { diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index f7e8a481696..08e92df3316 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -368,8 +368,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus) /* ----------------------------------------------------------------------- */ -EXPORT_SYMBOL(cx23885_call_i2c_clients); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index dec4dc2fcbb..205640cc48f 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -254,10 +254,6 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) -extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc); - /* ----------------------------------------------------------- */ /* cx23885-cards.c */ -- cgit v1.2.3 From a2fbaa519befdb3db2485116518f3af55be604e6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:07:22 -0300 Subject: V4L/DVB (6576): cx88-mpeg.c: make 4 functions static This patch makes the following needlessly global functions static: - cx8802_init_common() - cx8802_fini_common() - cx8802_suspend_common() - cx8802_resume_common() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-mpeg.c | 14 ++++---------- drivers/media/video/cx88/cx88.h | 6 ------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 448c6738094..60ac4234d84 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -437,10 +437,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) return IRQ_RETVAL(handled); } -/* ----------------------------------------------------------- */ -/* exported stuff */ - -int cx8802_init_common(struct cx8802_dev *dev) +static int cx8802_init_common(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; int err; @@ -488,7 +485,7 @@ int cx8802_init_common(struct cx8802_dev *dev) return 0; } -void cx8802_fini_common(struct cx8802_dev *dev) +static void cx8802_fini_common(struct cx8802_dev *dev) { dprintk( 2, "cx8802_fini_common\n" ); cx8802_stop_dma(dev); @@ -504,7 +501,7 @@ void cx8802_fini_common(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) +static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -530,7 +527,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) return 0; } -int cx8802_resume_common(struct pci_dev *pci_dev) +static int cx8802_resume_common(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -874,9 +871,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare); EXPORT_SYMBOL(cx8802_buf_queue); EXPORT_SYMBOL(cx8802_cancel_buffers); -EXPORT_SYMBOL(cx8802_init_common); -EXPORT_SYMBOL(cx8802_fini_common); - EXPORT_SYMBOL(cx8802_register_driver); EXPORT_SYMBOL(cx8802_unregister_driver); EXPORT_SYMBOL(cx8802_get_driver); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index eb296bdecb1..bb1036a5c6c 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -633,12 +633,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev, void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); void cx8802_cancel_buffers(struct cx8802_dev *dev); -int cx8802_init_common(struct cx8802_dev *dev); -void cx8802_fini_common(struct cx8802_dev *dev); - -int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); -int cx8802_resume_common(struct pci_dev *pci_dev); - /* ----------------------------------------------------------- */ /* cx88-video.c*/ extern const u32 cx88_user_ctrls[]; -- cgit v1.2.3 From f760d618ab385e1c4060f1bfebc335971a5b79f4 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:07:26 -0300 Subject: V4L/DVB (6577): et61x251/: make 5 functions static This patch makes the following needlessly global functions in et61x251_core.c static: - et61x251_read_reg() - et61x251_i2c_try_read() - et61x251_i2c_try_write() - et61x251_i2c_read() - et61x251_i2c_write() Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/et61x251/et61x251_core.c | 20 ++++++++++---------- drivers/media/video/et61x251/et61x251_sensor.h | 8 -------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index d19d73b81ed..38d2ad0aade 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) } -int et61x251_read_reg(struct et61x251_device* cam, u16 index) +static int et61x251_read_reg(struct et61x251_device* cam, u16 index) { struct usb_device* udev = cam->usbdev; u8* buff = cam->control_buffer; @@ -268,9 +268,9 @@ et61x251_i2c_wait(struct et61x251_device* cam, } -int -et61x251_i2c_try_read(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, u8 address) +static int et61x251_i2c_try_read(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address) { struct usb_device* udev = cam->usbdev; u8* data = cam->control_buffer; @@ -301,10 +301,9 @@ et61x251_i2c_try_read(struct et61x251_device* cam, } -int -et61x251_i2c_try_write(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, u8 address, - u8 value) +static int et61x251_i2c_try_write(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address, u8 value) { struct usb_device* udev = cam->usbdev; u8* data = cam->control_buffer; @@ -387,13 +386,14 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, } -int et61x251_i2c_read(struct et61x251_device* cam, u8 address) +static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) { return et61x251_i2c_try_read(cam, &cam->sensor, address); } -int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) +static int et61x251_i2c_write(struct et61x251_device* cam, + u8 address, u8 value) { return et61x251_i2c_try_write(cam, &cam->sensor, address, value); } diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h index e1458633062..71a03148cb0 100644 --- a/drivers/media/video/et61x251/et61x251_sensor.h +++ b/drivers/media/video/et61x251/et61x251_sensor.h @@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam, /*****************************************************************************/ extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); -extern int et61x251_read_reg(struct et61x251_device*, u16 index); -extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); -extern int et61x251_i2c_read(struct et61x251_device*, u8 address); -extern int et61x251_i2c_try_write(struct et61x251_device*, - const struct et61x251_sensor*, u8 address, - u8 value); -extern int et61x251_i2c_try_read(struct et61x251_device*, - const struct et61x251_sensor*, u8 address); extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, u8 data2, u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, u8 data8, u8 address); -- cgit v1.2.3 From 53133afbeeb177487a907fdc2edf18f857497641 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Nov 2007 14:07:06 -0300 Subject: V4L/DVB (6578): dvb-usb: make some debug vars static This patch makes some needlessly global debug variables static. opera1.h became so small that I removed it. Signed-off-by: Adrian Bunk Reviewed-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 5 ++++- drivers/media/dvb/dvb-usb/cxusb.h | 5 ----- drivers/media/dvb/dvb-usb/digitv.c | 3 ++- drivers/media/dvb/dvb-usb/digitv.h | 3 --- drivers/media/dvb/dvb-usb/opera1.c | 6 ++++-- drivers/media/dvb/dvb-usb/opera1.h | 9 --------- drivers/media/dvb/dvb-usb/vp7045.c | 5 ++++- drivers/media/dvb/dvb-usb/vp7045.h | 5 ----- 8 files changed, 14 insertions(+), 27 deletions(-) delete mode 100644 drivers/media/dvb/dvb-usb/opera1.h diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 04e31cf7d53..5b6431ea38c 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -32,9 +32,12 @@ #include "zl10353.h" /* debug */ -int dvb_usb_cxusb_debug; +static int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) +#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ + dprintk(dvb_usb_cxusb_debug,0x01,args) static int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index c8ef77554b0..79ca7abb89a 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -4,11 +4,6 @@ #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" -extern int dvb_usb_cxusb_debug; -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) -#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ - dprintk(dvb_usb_cxusb_debug,0x01,args) - /* usb commands - some of it are guesses, don't have a reference yet */ #define CMD_I2C_WRITE 0x08 #define CMD_I2C_READ 0x09 diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index bca1e090573..3acbda4aa27 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -17,9 +17,10 @@ #include "nxt6000.h" /* debug */ -int dvb_usb_digitv_debug; +static int dvb_usb_digitv_debug; module_param_named(debug,dvb_usb_digitv_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) static int digitv_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h index 8b43e3db869..908c09f4966 100644 --- a/drivers/media/dvb/dvb-usb/digitv.h +++ b/drivers/media/dvb/dvb-usb/digitv.h @@ -8,9 +8,6 @@ struct digitv_state { int is_nxt6000; }; -extern int dvb_usb_digitv_debug; -#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) - /* protocol (from usblogging and the SDK: * * Always 7 bytes bulk message(s) for controlling diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index d7c04951cea..21935bf7059 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -10,7 +10,9 @@ * see Documentation/dvb/README.dvb-usb for more information */ -#include "opera1.h" +#define DVB_USB_LOG_PREFIX "opera" + +#include "dvb-usb.h" #include "stv0299.h" #define OPERA_READ_MSG 0 @@ -38,7 +40,7 @@ struct opera_rc_keys { u32 event; }; -int dvb_usb_opera1_debug; +static int dvb_usb_opera1_debug; module_param_named(debug, dvb_usb_opera1_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h deleted file mode 100644 index 53174427902..00000000000 --- a/drivers/media/dvb/dvb-usb/opera1.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _OPERA1_H_ -#define _OPERA1_H_ - -#define DVB_USB_LOG_PREFIX "opera" -#include "dvb-usb.h" - -extern int dvb_usb_opera1_debug; -#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args) -#endif diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 5bbd2d5192f..c172babf59b 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -15,9 +15,12 @@ #include "vp7045.h" /* debug */ -int dvb_usb_vp7045_debug; +static int dvb_usb_vp7045_debug; module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) { diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h index 9ce21a20fa8..969688f8526 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.h +++ b/drivers/media/dvb/dvb-usb/vp7045.h @@ -17,11 +17,6 @@ #define DVB_USB_LOG_PREFIX "vp7045" #include "dvb-usb.h" -extern int dvb_usb_vp7045_debug; -#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) - /* vp7045 commands */ /* Twinhan Vendor requests */ -- cgit v1.2.3 From 2c94a674e059e89252d58da655efa4e798be4d48 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 30 Oct 2007 05:52:52 -0300 Subject: V4L/DVB (6580): Set slave's master before master's attach call. V4L: Int if: Set slave's master before attach, remove master argument The master also now gets its own pointer from slave's structure. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-int-device.c | 6 +++--- include/media/v4l2-int-device.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 8b4ef530a3a..a545dcaf857 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void) if (!try_module_get(m->module)) continue; - if (m->u.master->attach(m, s)) { + s->u.slave->master = m; + if (m->u.master->attach(s)) { + s->u.slave->master = NULL; module_put(m->module); continue; } - - s->u.slave->master = m; } } } diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index 066ebfc4f98..c8b80e0f065 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -44,9 +44,8 @@ enum v4l2_int_type { struct v4l2_int_device; struct v4l2_int_master { - int (*attach)(struct v4l2_int_device *master, - struct v4l2_int_device *slave); - void (*detach)(struct v4l2_int_device *master); + int (*attach)(struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *slave); }; typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); -- cgit v1.2.3 From a3a048cea301baba5d451991074a85dc20a8f228 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 10 Nov 2007 22:21:01 -0300 Subject: V4L/DVB (6582): Fix em28xx to allow multiple open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows shared access support for em28xx. Just one userspace application is allowed to get stream. The other(s) application(s) can change V4L2 controls, set video standards, etc. This patch were splited from Markus Rechberger's tree and backported to 2.6.17 by Pádraig Brady. The original patch were ported to the latest em28xx version and had CodingStyle corrected to solve the issues pointed by scripts/checkpatch.pl. Thanks to Pádraig Brady for pointing this. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 124 ++++++++++++++++++------------ drivers/media/video/em28xx/em28xx.h | 6 ++ 2 files changed, 79 insertions(+), 51 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index b43edc3fa23..5b17ca9cad1 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -234,6 +234,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) int minor = iminor(inode); int errCode = 0; struct em28xx *h,*dev = NULL; + struct em28xx_fh *fh; list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { @@ -251,19 +252,17 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_videodbg("open minor=%d type=%s users=%d\n", minor,v4l2_type_names[dev->type],dev->users); - mutex_lock(&dev->lock); + fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); - if (dev->users) { - em28xx_warn("this driver can be opened only once\n"); - mutex_unlock(&dev->lock); - return -EBUSY; + if (!fh) { + em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + return -ENOMEM; } + mutex_lock(&dev->lock); + fh->dev = dev; + filp->private_data = fh; - spin_lock_init(&dev->queue_lock); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); - - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { em28xx_set_alternate(dev); dev->width = norm_maxw(dev); @@ -277,26 +276,16 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); - /* device needs to be initialized before isoc transfer */ - video_mux(dev, 0); /* start the transfer */ errCode = em28xx_init_isoc(dev); if (errCode) goto err; + em28xx_empty_framequeues(dev); } dev->users++; - filp->private_data = dev; - dev->io = IO_NONE; - dev->stream = STREAM_OFF; - dev->num_frames = 0; - - /* prepare queues */ - em28xx_empty_framequeues(dev); - - dev->state |= DEV_INITIALIZED; err: mutex_unlock(&dev->lock); @@ -333,34 +322,41 @@ static void em28xx_release_resources(struct em28xx *dev) */ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) { - int errCode; - struct em28xx *dev=filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int errCode; em28xx_videodbg("users=%d\n", dev->users); mutex_lock(&dev->lock); + if (fh->reader == 1) + fh->reader = 0; - em28xx_uninit_isoc(dev); + if (dev->users == 1) { + dev->reader = 0; - em28xx_release_buffers(dev); + em28xx_uninit_isoc(dev); + em28xx_release_buffers(dev); - /* the device is already disconnect, free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; - } + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); + return 0; + } - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n", - errCode); + /* set alternate 0 */ + dev->alt = 0; + em28xx_videodbg("setting alternate 0\n"); + errCode = usb_set_interface(dev->udev, 0, 0); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to " + "0 (error=%i)\n", errCode); + } } - + kfree(fh); dev->users--; wake_up_interruptible_nr(&dev->open, 1); mutex_unlock(&dev->lock); @@ -378,13 +374,19 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, struct em28xx_frame_t *f, *i; unsigned long lock_flags; int ret = 0; - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; mutex_lock(&dev->lock); - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + + if (dev->reader > 0 && fh->reader == 0) { + mutex_unlock(&dev->lock); + return -EBUSY; } + if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); @@ -423,6 +425,9 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, " the device again to choose the read method\n"); mutex_unlock(&dev->lock); return -EINVAL; + } else { + dev->reader = 1; + fh->reader = 1; } if (dev->io == IO_NONE) { @@ -491,7 +496,8 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) { unsigned int mask = 0; - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; mutex_lock(&dev->lock); @@ -559,15 +565,23 @@ static struct vm_operations_struct em28xx_vm_ops = { */ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) { - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long start = vma->vm_start; + void *pos; + u32 i; mutex_lock(&dev->lock); + if (dev->reader > 0 && fh->reader == 0) { + mutex_unlock(&dev->lock); + return -EBUSY; + } else { + dev->reader = 1; + fh->reader = 1; + } + if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("mmap: device not present\n"); mutex_unlock(&dev->lock); @@ -918,6 +932,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, struct em28xx *dev, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl) { + struct em28xx_fh *fh = filp->private_data; int ret; switch (cmd) { @@ -1227,6 +1242,8 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, return ret; } } + + fh->reader = 0; em28xx_empty_framequeues(dev); mutex_unlock(&dev->lock); @@ -1248,7 +1265,8 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, void *arg) { - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; if (!dev) return -ENODEV; @@ -1456,7 +1474,8 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int ret = 0; - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; if (dev->state & DEV_DISCONNECTED) { em28xx_errdev("v4l2 ioctl: device not present\n"); @@ -1503,7 +1522,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->udev = udev; mutex_init(&dev->lock); + spin_lock_init(&dev->queue_lock); init_waitqueue_head(&dev->open); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); dev->em28xx_write_regs = em28xx_write_regs; dev->em28xx_read_reg = em28xx_read_reg; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index c2531da2e61..f8ad0f4ae6d 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -258,6 +258,7 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; + unsigned int reader:1; unsigned long hash; /* eeprom hash - for boards with generic ID */ unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ @@ -294,6 +295,11 @@ struct em28xx { int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg); }; +struct em28xx_fh { + struct em28xx *dev; + unsigned int reader:1; +}; + /* Provided by em28xx-i2c.c */ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg); -- cgit v1.2.3 From a225452ef80a7bd894fd2dfd01a4973d444152f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Nov 2007 01:08:26 -0300 Subject: V4L/DVB (6583): Fix em28xx read stream locking On some situations, closing an streaming application and re-opening were returning -EBUSY. Uses the same locking schema also present on cx88. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 77 ++++++++++++++++++++++--------- drivers/media/video/em28xx/em28xx.h | 5 +- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 5b17ca9cad1..f0191779a8e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -225,6 +225,44 @@ static void video_mux(struct em28xx *dev, int index) } } +/* Usage lock check functions */ +static int res_get(struct em28xx_fh *fh) +{ + struct em28xx *dev = fh->dev; + int rc = 0; + + /* This instance already has stream_on */ + if (fh->stream_on) + return rc; + + mutex_lock(&dev->lock); + + if (dev->stream_on) + rc = -EINVAL; + else { + dev->stream_on = 1; + fh->stream_on = 1; + } + + mutex_unlock(&dev->lock); + return rc; +} + +static int res_check(struct em28xx_fh *fh) +{ + return (fh->stream_on); +} + +static void res_free(struct em28xx_fh *fh) +{ + struct em28xx *dev = fh->dev; + + mutex_lock(&dev->lock); + fh->stream_on = 0; + dev->stream_on = 0; + mutex_unlock(&dev->lock); +} + /* * em28xx_v4l2_open() * inits the device and starts isoc transfer @@ -328,15 +366,16 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) em28xx_videodbg("users=%d\n", dev->users); + + if (res_check(fh)) + res_free(fh); + mutex_lock(&dev->lock); - if (fh->reader == 1) - fh->reader = 0; if (dev->users == 1) { - dev->reader = 0; - em28xx_uninit_isoc(dev); em28xx_release_buffers(dev); + dev->io = IO_NONE; /* the device is already disconnect, free the remaining resources */ @@ -377,16 +416,15 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + mutex_lock(&dev->lock); if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); - if (dev->reader > 0 && fh->reader == 0) { - mutex_unlock(&dev->lock); - return -EBUSY; - } - if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); @@ -425,9 +463,6 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, " the device again to choose the read method\n"); mutex_unlock(&dev->lock); return -EINVAL; - } else { - dev->reader = 1; - fh->reader = 1; } if (dev->io == IO_NONE) { @@ -499,6 +534,9 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + if (unlikely(res_get(fh) < 0)) + return POLLERR; + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { @@ -572,15 +610,10 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) void *pos; u32 i; - mutex_lock(&dev->lock); - - if (dev->reader > 0 && fh->reader == 0) { - mutex_unlock(&dev->lock); + if (unlikely(res_get(fh) < 0)) return -EBUSY; - } else { - dev->reader = 1; - fh->reader = 1; - } + + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("mmap: device not present\n"); @@ -1219,6 +1252,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, if (list_empty(&dev->inqueue)) return -EINVAL; + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); @@ -1243,7 +1279,6 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, } } - fh->reader = 0; em28xx_empty_framequeues(dev); mutex_unlock(&dev->lock); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index f8ad0f4ae6d..3efc05d2df6 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -224,6 +224,8 @@ struct em28xx { unsigned int has_msp34xx:1; unsigned int has_tda9887:1; + unsigned int stream_on:1; /* Locks streams */ + u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; @@ -258,7 +260,6 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; - unsigned int reader:1; unsigned long hash; /* eeprom hash - for boards with generic ID */ unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ @@ -297,7 +298,7 @@ struct em28xx { struct em28xx_fh { struct em28xx *dev; - unsigned int reader:1; + unsigned int stream_on:1; /* Locks streams */ }; /* Provided by em28xx-i2c.c */ -- cgit v1.2.3 From 9e31ced888d1ca49ec5be51ef295e3ce994366c4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Nov 2007 01:13:49 -0300 Subject: V4L/DVB (6584): Fix read() method Backport read() fixes from Markus Rechberger. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 30 ++++++++++++++++++++++-------- drivers/media/video/em28xx/em28xx.h | 2 ++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index f0191779a8e..8a4d221a4fe 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -416,6 +416,9 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + /* FIXME: read() is not prepared to allow changing the video + resolution while streaming. Seems a bug at em28xx_set_fmt + */ if (unlikely(res_get(fh) < 0)) return -EBUSY; @@ -498,25 +501,36 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, mutex_unlock(&dev->lock); return -ENODEV; } + dev->video_bytesread = 0; } f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_for_each_entry(i, &dev->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&dev->outqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - em28xx_queue_unusedframes(dev); if (count > f->buf.length) count = f->buf.length; - if (copy_to_user(buf, f->bufmem, count)) { - mutex_unlock(&dev->lock); + if ((dev->video_bytesread + count) > dev->frame_size) + count = dev->frame_size - dev->video_bytesread; + + if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { + em28xx_err("Error while copying to user\n"); return -EFAULT; } + dev->video_bytesread += count; + + if (dev->video_bytesread == dev->frame_size) { + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_for_each_entry(i, &dev->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&dev->outqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + + em28xx_queue_unusedframes(dev); + dev->video_bytesread = 0; + } + *f_pos += count; mutex_unlock(&dev->lock); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 3efc05d2df6..672880383de 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -260,6 +260,7 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; + unsigned int video_bytesread; /* Number of bytes read */ unsigned long hash; /* eeprom hash - for boards with generic ID */ unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ @@ -268,6 +269,7 @@ struct em28xx { enum em28xx_dev_state state; enum em28xx_stream_state stream; enum em28xx_io_method io; + /* locks */ struct mutex lock; spinlock_t queue_lock; -- cgit v1.2.3 From 195a4ef627e110cd468a69fdb973548e6914577a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Nov 2007 13:17:17 -0300 Subject: V4L/DVB (6585): Convert em28xx to video_ioctl2 Uses the newer ioctl handler at videodev. This patch also cleans up some bad logic at the driver and do CodingStyle and other cleanups at the resulting driver. Also, since VIDIOCMBUF were not working, the V4L1 compat code were removed. The compat code will eventually be re-inserted, if we find a clean way for implementing compatibility with the old API. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 2177 +++++++++++++++-------------- 1 file changed, 1132 insertions(+), 1045 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 8a4d221a4fe..022afb7b98c 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -47,7 +47,7 @@ #define DRIVER_NAME "em28xx" #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0) #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -202,8 +202,6 @@ static void video_mux(struct em28xx *dev, int index) em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); - em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput); - if (dev->has_msp34xx) { if (dev->i2s_speed) em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); @@ -264,1297 +262,1391 @@ static void res_free(struct em28xx_fh *fh) } /* - * em28xx_v4l2_open() - * inits the device and starts isoc transfer + * em28xx_vm_open() */ -static int em28xx_v4l2_open(struct inode *inode, struct file *filp) +static void em28xx_vm_open(struct vm_area_struct *vma) { - int minor = iminor(inode); - int errCode = 0; - struct em28xx *h,*dev = NULL; - struct em28xx_fh *fh; + struct em28xx_frame_t *f = vma->vm_private_data; + f->vma_use_count++; +} - list_for_each_entry(h, &em28xx_devlist, devlist) { - if (h->vdev->minor == minor) { - dev = h; - dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev->minor == minor) { - dev = h; - dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - } - if (NULL == dev) - return -ENODEV; +/* + * em28xx_vm_close() + */ +static void em28xx_vm_close(struct vm_area_struct *vma) +{ + /* NOTE: buffers are not freed here */ + struct em28xx_frame_t *f = vma->vm_private_data; - em28xx_videodbg("open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[dev->type],dev->users); + if (f->vma_use_count) + f->vma_use_count--; +} - fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); +static struct vm_operations_struct em28xx_vm_ops = { + .open = em28xx_vm_open, + .close = em28xx_vm_close, +}; - if (!fh) { - em28xx_errdev("em28xx-video.c: Out of memory?!\n"); - return -ENOMEM; + +/* + * em28xx_get_ctrl() + * return the current saturation, brightness or contrast, mute state + */ +static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->mute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = dev->volume; + return 0; + default: + return -EINVAL; } - mutex_lock(&dev->lock); - fh->dev = dev; - filp->private_data = fh; +} - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - em28xx_set_alternate(dev); +/* + * em28xx_set_ctrl() + * mute or set new saturation, brightness or contrast + */ +static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value != dev->mute) { + dev->mute = ctrl->value; + em28xx_audio_usb_mute(dev, ctrl->value); + return em28xx_audio_analog_set(dev); + } + return 0; + case V4L2_CID_AUDIO_VOLUME: + dev->volume = ctrl->value; + return em28xx_audio_analog_set(dev); + default: + return -EINVAL; + } +} - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = 0; - dev->vscale = 0; +/* + * em28xx_stream_interrupt() + * stops streaming + */ +static int em28xx_stream_interrupt(struct em28xx *dev) +{ + int rc = 0; - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); + /* stop reading from the device */ + dev->stream = STREAM_INTERRUPT; + rc = wait_event_timeout(dev->wait_stream, + (dev->stream == STREAM_OFF) || + (dev->state & DEV_DISCONNECTED), + EM28XX_URB_TIMEOUT); - /* start the transfer */ - errCode = em28xx_init_isoc(dev); - if (errCode) - goto err; + if (rc) { + dev->state |= DEV_MISCONFIGURED; + em28xx_videodbg("device is misconfigured; close and " + "open /dev/video%d again\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); + return rc; + } - em28xx_empty_framequeues(dev); + return 0; +} + + +static int check_dev(struct em28xx *dev) +{ + if (dev->state & DEV_DISCONNECTED) { + em28xx_errdev("v4l2 ioctl: device not present\n"); + return -ENODEV; } - dev->users++; + if (dev->state & DEV_MISCONFIGURED) { + em28xx_errdev("v4l2 ioctl: device is misconfigured; " + "close and open it again\n"); + return -EIO; + } + return 0; +} -err: - mutex_unlock(&dev->lock); - return errCode; +static void get_scale(struct em28xx *dev, + unsigned int width, unsigned int height, + unsigned int *hscale, unsigned int *vscale) +{ + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + + *hscale = (((unsigned long)maxw) << 12) / width - 4096L; + if (*hscale >= 0x4000) + *hscale = 0x3fff; + + *vscale = (((unsigned long)maxh) << 12) / height - 4096L; + if (*vscale >= 0x4000) + *vscale = 0x3fff; } -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -static void em28xx_release_resources(struct em28xx *dev) +/* ------------------------------------------------------------------ + IOCTL vidioc handling + ------------------------------------------------------------------*/ + +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; - /*FIXME: I2C IR should be disconnected */ + mutex_lock(&dev->lock); - em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, - dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); - list_del(&dev->devlist); - video_unregister_device(dev->vdev); - video_unregister_device(dev->vbi_dev); - em28xx_i2c_unregister(dev); - usb_put_dev(dev->udev); + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + f->fmt.pix.bytesperline = dev->bytesperline; + f->fmt.pix.sizeimage = dev->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - /* Mark device as unused */ - em28xx_devused&=~(1<devno); + mutex_unlock(&dev->lock); + return 0; } -/* - * em28xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls - */ -static int em28xx_v4l2_close(struct inode *inode, struct file *filp) +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int errCode; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int width = f->fmt.pix.width; + int height = f->fmt.pix.height; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + unsigned int hscale, vscale; + + /* width must even because of the YUYV format + height must be even because of interlacing */ + height &= 0xfffe; + width &= 0xfffe; - em28xx_videodbg("users=%d\n", dev->users); + if (height < 32) + height = 32; + if (height > maxh) + height = maxh; + if (width < 48) + width = 48; + if (width > maxw) + width = maxw; + mutex_lock(&dev->lock); - if (res_check(fh)) - res_free(fh); + if (dev->is_em2800) { + /* the em2800 can only scale down to 50% */ + if (height % (maxh / 2)) + height = maxh; + if (width % (maxw / 2)) + width = maxw; + /* according to empiatech support */ + /* the MaxPacketSize is to small to support */ + /* framesizes larger than 640x480 @ 30 fps */ + /* or 640x576 @ 25 fps. As this would cut */ + /* of a part of the image we prefer */ + /* 360x576 or 360x480 for now */ + if (width == maxw && height == maxh) + width /= 2; + } - mutex_lock(&dev->lock); + get_scale(dev, width, height, &hscale, &vscale); - if (dev->users == 1) { - em28xx_uninit_isoc(dev); - em28xx_release_buffers(dev); - dev->io = IO_NONE; + width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; - } + f->fmt.pix.width = width; + f->fmt.pix.height = height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + f->fmt.pix.bytesperline = width * 2; + f->fmt.pix.sizeimage = width * 2 * height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to " - "0 (error=%i)\n", errCode); - } - } - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); mutex_unlock(&dev->lock); return 0; } -/* - * em28xx_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t -em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t * f_pos) +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { - struct em28xx_frame_t *f, *i; - unsigned long lock_flags; - int ret = 0; - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc, i; - /* FIXME: read() is not prepared to allow changing the video - resolution while streaming. Seems a bug at em28xx_set_fmt - */ + rc = check_dev(dev); + if (rc < 0) + return rc; - if (unlikely(res_get(fh) < 0)) - return -EBUSY; + vidioc_try_fmt_cap(file, priv, f); mutex_lock(&dev->lock); - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); - - if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->lock); - return -EFAULT; + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_S_FMT failed. " + "Unmap the buffers first.\n"); + rc = -EINVAL; + goto err; } - mutex_unlock(&dev->lock); - return (1); - } - if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } - mutex_unlock(&dev->lock); - return (1); + + /* stop io in case it is already in progress */ + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) + goto err; } - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - mutex_unlock(&dev->lock); - return -ENODEV; - } + em28xx_release_buffers(dev); + dev->io = IO_NONE; - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device misconfigured; close and open it again\n"); - mutex_unlock(&dev->lock); - return -EIO; - } + /* set new image size */ + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - if (dev->io == IO_MMAP) { - em28xx_videodbg ("IO method is set to mmap; close and open" - " the device again to choose the read method\n"); - mutex_unlock(&dev->lock); + /* FIXME: This is really weird! Why capture is starting with + this ioctl ??? + */ + em28xx_uninit_isoc(dev); + em28xx_set_alternate(dev); + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + em28xx_init_isoc(dev); + rc = 0; + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct v4l2_format f; + unsigned int i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + for (i = 0; i < TVNORMS; i++) + if (*norm == tvnorms[i].id) + break; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*norm & tvnorms[i].id) + break; + if (i == TVNORMS) return -EINVAL; - } - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_errdev("read failed, not enough memory\n"); - mutex_unlock(&dev->lock); - return -ENOMEM; - } - dev->io = IO_READ; - dev->stream = STREAM_ON; - em28xx_queue_unusedframes(dev); - } + *norm = tvnorms[i].id; - if (!count) { - mutex_unlock(&dev->lock); - return 0; - } + mutex_lock(&dev->lock); + dev->tvnorm = &tvnorms[i]; + mutex_unlock(&dev->lock); - if (list_empty(&dev->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&dev->lock); - return -EAGAIN; - } - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) { - mutex_unlock(&dev->lock); - return ret; - } - if (dev->state & DEV_DISCONNECTED) { - mutex_unlock(&dev->lock); - return -ENODEV; - } - dev->video_bytesread = 0; - } + /* Adjusts width/height, if needed */ + f.fmt.pix.width = dev->width; + f.fmt.pix.height = dev->height; + vidioc_try_fmt_cap(file, priv, &f); - f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); + mutex_lock(&dev->lock); - em28xx_queue_unusedframes(dev); + /* set new image size */ + dev->width = f.fmt.pix.width; + dev->height = f.fmt.pix.height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - if (count > f->buf.length) - count = f->buf.length; + em28xx_resolution_set(dev); + em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); - if ((dev->video_bytesread + count) > dev->frame_size) - count = dev->frame_size - dev->video_bytesread; + mutex_unlock(&dev->lock); + return 0; +} - if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { - em28xx_err("Error while copying to user\n"); - return -EFAULT; - } - dev->video_bytesread += count; +static const char *iname[] = { + [EM28XX_VMUX_COMPOSITE1] = "Composite1", + [EM28XX_VMUX_COMPOSITE2] = "Composite2", + [EM28XX_VMUX_COMPOSITE3] = "Composite3", + [EM28XX_VMUX_COMPOSITE4] = "Composite4", + [EM28XX_VMUX_SVIDEO] = "S-Video", + [EM28XX_VMUX_TELEVISION] = "Television", + [EM28XX_VMUX_CABLE] = "Cable TV", + [EM28XX_VMUX_DVB] = "DVB", + [EM28XX_VMUX_DEBUG] = "for debug only", +}; - if (dev->video_bytesread == dev->frame_size) { - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_for_each_entry(i, &dev->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&dev->outqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int n; - em28xx_queue_unusedframes(dev); - dev->video_bytesread = 0; - } + n = i->index; + if (n >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; - *f_pos += count; + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; - mutex_unlock(&dev->lock); + strcpy(i->name, iname[INPUT(n)->type]); - return count; + if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || + (EM28XX_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + + for (n = 0; n < ARRAY_SIZE(tvnorms); n++) + i->std |= tvnorms[n].id; + + return 0; } -/* - * em28xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - unsigned int mask = 0; - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; - if (unlikely(res_get(fh) < 0)) - return POLLERR; + *i = dev->ctl_input; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (i >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(i)->type) + return -EINVAL; mutex_lock(&dev->lock); - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - } else if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device is misconfigured; close and open it again\n"); - } else { - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers - (dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_warn - ("poll() failed, not enough memory\n"); - } else { - dev->io = IO_READ; - dev->stream = STREAM_ON; - } - } + video_mux(dev, i); - if (dev->io == IO_READ) { - em28xx_queue_unusedframes(dev); - poll_wait(filp, &dev->wait_frame, wait); + mutex_unlock(&dev->lock); + return 0; +} - if (!list_empty(&dev->outqueue)) - mask |= POLLIN | POLLRDNORM; +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int index = a->index; - mutex_unlock(&dev->lock); + if (a->index > 1) + return -EINVAL; - return mask; - } + index = dev->ctl_ainput; + + if (index == 0) { + strcpy(a->name, "Television"); + } else { + strcpy(a->name, "Line In"); } + a->capability = V4L2_AUDCAP_STEREO; + a->index = index; - mutex_unlock(&dev->lock); - return POLLERR; + return 0; } -/* - * em28xx_vm_open() - */ -static void em28xx_vm_open(struct vm_area_struct *vma) +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - struct em28xx_frame_t *f = vma->vm_private_data; - f->vma_use_count++; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (a->index != dev->ctl_ainput) + return -EINVAL; + + return 0; } -/* - * em28xx_vm_close() - */ -static void em28xx_vm_close(struct vm_area_struct *vma) +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) { - /* NOTE: buffers are not freed here */ - struct em28xx_frame_t *f = vma->vm_private_data; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int id = qc->id; + int i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; - if (f->vma_use_count) - f->vma_use_count--; + memset(qc, 0, sizeof(*qc)); + + qc->id = id; + + if (!dev->has_msp34xx) { + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); + return 0; + } + } + } + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc); + mutex_unlock(&dev->lock); + + if (qc->type) + return 0; + else + return -EINVAL; } -static struct vm_operations_struct em28xx_vm_ops = { - .open = em28xx_vm_open, - .close = em28xx_vm_close, -}; +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; -/* - * em28xx_v4l2_mmap() - */ -static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) + rc = check_dev(dev); + if (rc < 0) + return rc; + mutex_lock(&dev->lock); + + if (!dev->has_msp34xx) + rc = em28xx_get_ctrl(dev, ctrl); + else + rc = -EINVAL; + + if (rc == -EINVAL) { + em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl); + rc = 0; + } + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) { - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long start = vma->vm_start; - void *pos; - u32 i; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u8 i; + int rc; - if (unlikely(res_get(fh) < 0)) - return -EBUSY; + rc = check_dev(dev); + if (rc < 0) + return rc; mutex_lock(&dev->lock); - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("mmap: device not present\n"); - mutex_unlock(&dev->lock); - return -ENODEV; + if (dev->has_msp34xx) + em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); + else { + rc = 1; + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (ctrl->id == em28xx_qctrl[i].id) { + if (ctrl->value < em28xx_qctrl[i].minimum || + ctrl->value > em28xx_qctrl[i].maximum) { + rc = -ERANGE; + break; + } + + rc = em28xx_set_ctrl(dev, ctrl); + break; + } + } } - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg ("mmap: Device is misconfigured; close and " - "open it again\n"); - mutex_unlock(&dev->lock); - return -EIO; + /* Control not found - try to send it to the attached devices */ + if (rc == 1) { + em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); + rc = 0; } - if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(dev->frame[0].buf.length)) { - mutex_unlock(&dev->lock); + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) return -EINVAL; - } - for (i = 0; i < dev->num_frames; i++) { - if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == dev->num_frames) { - em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - mutex_unlock(&dev->lock); + strcpy(t->name, "Tuner"); + + mutex_lock(&dev->lock); + + em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) return -EINVAL; - } - /* VM_IO is eventually going to replace PageReserved altogether */ - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + mutex_lock(&dev->lock); - pos = dev->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); - vma->vm_ops = &em28xx_vm_ops; - vma->vm_private_data = &dev->frame[i]; + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != f->tuner) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + mutex_lock(&dev->lock); + + dev->ctl_freq = f->frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - em28xx_vm_open(vma); mutex_unlock(&dev->lock); return 0; } -/* - * em28xx_get_ctrl() - * return the current saturation, brightness or contrast, mute state - */ -static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) { - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->volume; - return 0; - default: + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - } + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ + cc->pixelaspect.denominator = 59; + + return 0; } -/* - * em28xx_set_ctrl() - * mute or set new saturation, brightness or contrast - */ -static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) { - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value != dev->mute) { - dev->mute = ctrl->value; - em28xx_audio_usb_mute(dev, ctrl->value); - return em28xx_audio_analog_set(dev); - } - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - return em28xx_audio_analog_set(dev); - default: + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&dev->inqueue)) return -EINVAL; + + mutex_lock(&dev->lock); + + if (unlikely(res_get(fh) < 0)) { + mutex_unlock(&dev->lock); + return -EBUSY; } + + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ + + mutex_unlock(&dev->lock); + return 0; } -/* - * em28xx_stream_interrupt() - * stops streaming - */ -static int em28xx_stream_interrupt(struct em28xx *dev) +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) { - int ret = 0; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; - /* stop reading from the device */ + rc = check_dev(dev); + if (rc < 0) + return rc; - dev->stream = STREAM_INTERRUPT; - ret = wait_event_timeout(dev->wait_stream, - (dev->stream == STREAM_OFF) || - (dev->state & DEV_DISCONNECTED), - EM28XX_URB_TIMEOUT); - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - else if (ret) { - dev->state |= DEV_MISCONFIGURED; - em28xx_videodbg("device is misconfigured; close and " - "open /dev/video%d again\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); - return ret; + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) { + mutex_unlock(&dev->lock); + return rc; + } } + em28xx_empty_framequeues(dev); + + mutex_unlock(&dev->lock); return 0; } -static int em28xx_set_norm(struct em28xx *dev, int width, int height) +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { - unsigned int hscale, vscale; - unsigned int maxh, maxw; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); - /* width must even because of the YUYV format */ - /* height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; + cap->version = EM28XX_VERSION_CODE; - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; + cap->capabilities = + V4L2_CAP_SLICED_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) - hscale = 0x3fff; - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + if (dev->has_tuner) + cap->capabilities |= V4L2_CAP_TUNER; - if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) - vscale = 0x3fff; - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + return 0; +} - /* set new image size */ - dev->width = width; - dev->height = height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmtd) +{ + if (fmtd->index != 0) + return -EINVAL; - em28xx_resolution_set(dev); + fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmtd->description, "Packed YUY2"); + fmtd->pixelformat = V4L2_PIX_FMT_YUYV; + memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); return 0; } -static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format) +/* Sliced VBI ioctls */ +static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv, + struct v4l2_format *f) { - em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", - (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : - (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ? - "V4L2_BUF_TYPE_VBI_CAPTURE" : - (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ? - "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " : - "not supported"); - - switch (format->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - format->fmt.pix.width = dev->width; - format->fmt.pix.height = dev->height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = dev->bytesperline; - format->fmt.pix.sizeimage = dev->frame_size; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - - em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, - dev->height); - break; - } + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - format->fmt.sliced.service_set=0; + rc = check_dev(dev); + if (rc < 0) + return rc; - em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); + mutex_lock(&dev->lock); - if (format->fmt.sliced.service_set==0) - return -EINVAL; + f->fmt.sliced.service_set = 0; - break; - } + em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); - default: + if (f->fmt.sliced.service_set == 0) + rc = -EINVAL; + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_try_set_vbi_capture(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); + mutex_unlock(&dev->lock); + + if (f->fmt.sliced.service_set == 0) return -EINVAL; - } - return (0); + + return 0; } -static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format) + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) { - u32 i; - int ret = 0; - int width = format->fmt.pix.width; - int height = format->fmt.pix.height; - unsigned int hscale, vscale; - unsigned int maxh, maxw; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u32 i; + int rc; - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); + rc = check_dev(dev); + if (rc < 0) + return rc; - em28xx_videodbg("%s: type=%s\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", - format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : - format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? - "V4L2_BUF_TYPE_VBI_CAPTURE " : - "not supported"); + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; - if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); + if (dev->io == IO_READ) { + em28xx_videodbg("method is set to read;" + " close and open the device again to" + " choose the mmap I/O method\n"); + return -EINVAL; + } - if (format->fmt.sliced.service_set==0) + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_REQBUFS failed; " + "previous buffers are still mapped\n"); return -EINVAL; + } - return 0; + mutex_lock(&dev->lock); + + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) { + mutex_unlock(&dev->lock); + return rc; + } } + em28xx_empty_framequeues(dev); + + em28xx_release_buffers(dev); + if (rb->count) + rb->count = em28xx_request_buffers(dev, rb->count); + + dev->frame_current = NULL; + dev->io = rb->count ? IO_MMAP : IO_NONE; + + mutex_unlock(&dev->lock); + return 0; +} - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) return -EINVAL; - em28xx_videodbg("%s: requested %dx%d\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", - format->fmt.pix.width, format->fmt.pix.height); + mutex_lock(&dev->lock); - /* FIXME: Move some code away from here */ - /* width must even because of the YUYV format */ - /* height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; + memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; + if (dev->frame[b->index].vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + if (dev->frame[b->index].state == F_DONE) + b->flags |= V4L2_BUF_FLAG_DONE; + else if (dev->frame[b->index].state != F_UNUSED) + b->flags |= V4L2_BUF_FLAG_QUEUED; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned long lock_flags; + int rc; - if(dev->is_em2800){ - /* the em2800 can only scale down to 50% */ - if(height % (maxh / 2)) - height=maxh; - if(width % (maxw / 2)) - width=maxw; - /* according to empiatech support */ - /* the MaxPacketSize is to small to support */ - /* framesizes larger than 640x480 @ 30 fps */ - /* or 640x576 @ 25 fps. As this would cut */ - /* of a part of the image we prefer */ - /* 360x576 or 360x480 for now */ - if(width == maxw && height == maxh) - width /= 2; - } + rc = check_dev(dev); + if (rc < 0) + return rc; - if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) - hscale = 0x3fff; + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP || + b->index >= dev->num_frames) + return -EINVAL; - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + if (dev->frame[b->index].state != F_UNUSED) + return -EAGAIN; - if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) - vscale = 0x3fff; + dev->frame[b->index].state = F_QUEUED; - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + /* add frame to fifo */ + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_add_tail(&dev->frame[b->index].frame, &dev->inqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - format->fmt.pix.width = width; - format->fmt.pix.height = height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = width * 2; - format->fmt.pix.sizeimage = width * 2 * height; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = V4L2_FIELD_INTERLACED; + return 0; +} - em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT", - format->fmt.pix.width, format->fmt.pix.height, hscale, vscale); +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + struct em28xx_frame_t *f; + unsigned long lock_flags; + + rc = check_dev(dev); + if (rc < 0) + return rc; - if (cmd == VIDIOC_TRY_FMT) - return 0; + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_S_FMT failed. " - "Unmap the buffers first.\n"); + if (list_empty(&dev->outqueue)) { + if (dev->stream == STREAM_OFF) return -EINVAL; - } - /* stop io in case it is already in progress */ - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + rc = wait_event_interruptible(dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (rc) + return rc; + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; } - em28xx_release_buffers(dev); - dev->io = IO_NONE; + spin_lock_irqsave(&dev->queue_lock, lock_flags); + f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame); + list_del(dev->outqueue.next); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - /* set new image size */ - dev->width = width; - dev->height = height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; - dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; - em28xx_uninit_isoc(dev); - em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); - em28xx_init_isoc(dev); + f->state = F_UNUSED; + memcpy(b, &f->buf, sizeof(*b)); + + if (f->vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; return 0; } /* - * em28xx_v4l2_do_ioctl() - * This function is _not_ called directly, but from - * em28xx_v4l2_ioctl. Userspace - * copying is done already, arg is a kernel pointer. + * em28xx_v4l2_open() + * inits the device and starts isoc transfer */ -static int em28xx_do_ioctl(struct inode *inode, struct file *filp, - struct em28xx *dev, unsigned int cmd, void *arg, - v4l2_kioctl driver_ioctl) +static int em28xx_v4l2_open(struct inode *inode, struct file *filp) { - struct em28xx_fh *fh = filp->private_data; - int ret; - - switch (cmd) { - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; + int minor = iminor(inode); + int errCode = 0; + struct em28xx *h,*dev = NULL; + struct em28xx_fh *fh; - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - ret = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (ret < 0) - return ret; - return 0; + list_for_each_entry(h, &em28xx_devlist, devlist) { + if (h->vdev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + if (h->vbi_dev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; + } } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + if (NULL == dev) + return -ENODEV; - *id = dev->tvnorm->id; - return 0; + em28xx_videodbg("open minor=%d type=%s users=%d\n", + minor,v4l2_type_names[dev->type],dev->users); + + fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); + + if (!fh) { + em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + return -ENOMEM; } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; + mutex_lock(&dev->lock); + fh->dev = dev; + filp->private_data = fh; - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + em28xx_set_alternate(dev); - mutex_lock(&dev->lock); - dev->tvnorm = &tvnorms[i]; + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ + dev->bytesperline = dev->width * 2; + dev->hscale = 0; + dev->vscale = 0; - em28xx_set_norm(dev, dev->width, dev->height); + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, - &dev->tvnorm->id); - mutex_unlock(&dev->lock); + /* start the transfer */ + errCode = em28xx_init_isoc(dev); + if (errCode) + goto err; - return 0; + em28xx_empty_framequeues(dev); } - /* ------ input switching ---------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; - static const char *iname[] = { - [EM28XX_VMUX_COMPOSITE1] = "Composite1", - [EM28XX_VMUX_COMPOSITE2] = "Composite2", - [EM28XX_VMUX_COMPOSITE3] = "Composite3", - [EM28XX_VMUX_COMPOSITE4] = "Composite4", - [EM28XX_VMUX_SVIDEO] = "S-Video", - [EM28XX_VMUX_TELEVISION] = "Television", - [EM28XX_VMUX_CABLE] = "Cable TV", - [EM28XX_VMUX_DVB] = "DVB", - [EM28XX_VMUX_DEBUG] = "for debug only", - }; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - memset(i, 0, sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || - (EM28XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - for (n = 0; n < ARRAY_SIZE(tvnorms); n++) - i->std |= tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = dev->ctl_input; + dev->users++; - return 0; - } - case VIDIOC_S_INPUT: - { - int *index = arg; +err: + mutex_unlock(&dev->lock); + return errCode; +} - if (*index >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(*index)->type) - return -EINVAL; +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +static void em28xx_release_resources(struct em28xx *dev) +{ - mutex_lock(&dev->lock); - video_mux(dev, *index); - mutex_unlock(&dev->lock); + /*FIXME: I2C IR should be disconnected */ - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int index = a->index; + em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, + dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); + list_del(&dev->devlist); + video_unregister_device(dev->vdev); + video_unregister_device(dev->vbi_dev); + em28xx_i2c_unregister(dev); + usb_put_dev(dev->udev); - if (a->index > 1) - return -EINVAL; - memset(a, 0, sizeof(*a)); - index = dev->ctl_ainput; - if (index == 0) { - strcpy(a->name, "Television"); - } else { - strcpy(a->name, "Line In"); + /* Mark device as unused */ + em28xx_devused&=~(1<devno); +} + +/* + * em28xx_v4l2_close() + * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls + */ +static int em28xx_v4l2_close(struct inode *inode, struct file *filp) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int errCode; + + em28xx_videodbg("users=%d\n", dev->users); + + + if (res_check(fh)) + res_free(fh); + + mutex_lock(&dev->lock); + + if (dev->users == 1) { + em28xx_uninit_isoc(dev); + em28xx_release_buffers(dev); + dev->io = IO_NONE; + + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); + return 0; + } + + /* set alternate 0 */ + dev->alt = 0; + em28xx_videodbg("setting alternate 0\n"); + errCode = usb_set_interface(dev->udev, 0, 0); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to " + "0 (error=%i)\n", errCode); } - a->capability = V4L2_AUDCAP_STEREO; - a->index = index; - return 0; } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; + kfree(fh); + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + mutex_unlock(&dev->lock); + return 0; +} - if (a->index != dev->ctl_ainput) - return -EINVAL; +/* + * em28xx_v4l2_read() + * will allocate buffers when called for the first time + */ +static ssize_t +em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, + loff_t * f_pos) +{ + struct em28xx_frame_t *f, *i; + unsigned long lock_flags; + int ret = 0; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; - return 0; - } + /* FIXME: read() is not prepared to allow changing the video + resolution while streaming. Seems a bug at em28xx_set_fmt + */ - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i, id=qc->id; - - memset(qc,0,sizeof(*qc)); - qc->id=id; - - if (!dev->has_msp34xx) { - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), - sizeof(*qc)); - return 0; - } - } + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + + mutex_lock(&dev->lock); + + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + + if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->lock); + return -EFAULT; } - mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev,cmd,qc); mutex_unlock(&dev->lock); - if (qc->type) - return 0; - else - return -EINVAL; + return (1); } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - int retval=-EINVAL; - - if (!dev->has_msp34xx) - retval=em28xx_get_ctrl(dev, ctrl); - if (retval==-EINVAL) { - mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev,cmd,arg); + if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { mutex_unlock(&dev->lock); - return 0; - } else return retval; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - u8 i; - mutex_lock(&dev->lock); - - if (!dev->has_msp34xx){ - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (ctrl->id == em28xx_qctrl[i].id) { - int retval=-EINVAL; - if (ctrl->value < - em28xx_qctrl[i].minimum - || ctrl->value > - em28xx_qctrl[i].maximum) - return -ERANGE; - retval = em28xx_set_ctrl(dev, ctrl); - mutex_unlock(&dev->lock); - return retval; - } - } + return -EFAULT; } - - em28xx_i2c_call_clients(dev,cmd,arg); mutex_unlock(&dev->lock); - return 0; + return (1); } - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - if (0 != t->index) - return -EINVAL; + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("device not present\n"); + mutex_unlock(&dev->lock); + return -ENODEV; + } - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Tuner"); - mutex_lock(&dev->lock); - /* let clients fill in the remainder of this struct */ - em28xx_i2c_call_clients(dev, cmd, t); + if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg("device misconfigured; close and open it again\n"); mutex_unlock(&dev->lock); - em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, - t->afc); - return 0; + return -EIO; } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; - if (0 != t->index) - return -EINVAL; - mutex_lock(&dev->lock); - /* let clients handle this */ - em28xx_i2c_call_clients(dev, cmd, t); + if (dev->io == IO_MMAP) { + em28xx_videodbg ("IO method is set to mmap; close and open" + " the device again to choose the read method\n"); mutex_unlock(&dev->lock); - return 0; + return -EINVAL; } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - return 0; + if (dev->io == IO_NONE) { + if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { + em28xx_errdev("read failed, not enough memory\n"); + mutex_unlock(&dev->lock); + return -ENOMEM; + } + dev->io = IO_READ; + dev->stream = STREAM_ON; + em28xx_queue_unusedframes(dev); } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - if (0 != f->tuner) - return -EINVAL; - - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + if (!count) { mutex_unlock(&dev->lock); return 0; } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cc = arg; - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - return 0; + if (list_empty(&dev->outqueue)) { + if (filp->f_flags & O_NONBLOCK) { + mutex_unlock(&dev->lock); + return -EAGAIN; + } + ret = wait_event_interruptible + (dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (ret) { + mutex_unlock(&dev->lock); + return ret; + } + if (dev->state & DEV_DISCONNECTED) { + mutex_unlock(&dev->lock); + return -ENODEV; + } + dev->video_bytesread = 0; } - case VIDIOC_STREAMON: - { - int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->inqueue)) - return -EINVAL; + f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); - if (unlikely(res_get(fh) < 0)) - return -EBUSY; + em28xx_queue_unusedframes(dev); - dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ + if (count > f->buf.length) + count = f->buf.length; - em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); + if ((dev->video_bytesread + count) > dev->frame_size) + count = dev->frame_size - dev->video_bytesread; - return 0; + if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { + em28xx_err("Error while copying to user\n"); + return -EFAULT; } - case VIDIOC_STREAMOFF: - { - int *type = arg; - int ret; + dev->video_bytesread += count; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; + if (dev->video_bytesread == dev->frame_size) { + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_for_each_entry(i, &dev->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&dev->outqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - mutex_lock(&dev->lock); - if (dev->stream == STREAM_ON) { - em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))){ - mutex_unlock(&dev->lock); - return ret; - } - } + em28xx_queue_unusedframes(dev); + dev->video_bytesread = 0; + } - em28xx_empty_framequeues(dev); - mutex_unlock(&dev->lock); + *f_pos += count; - return 0; - } - default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - driver_ioctl); - } - return 0; + mutex_unlock(&dev->lock); + + return count; } /* - * em28xx_v4l2_do_ioctl() - * This function is _not_ called directly, but from - * em28xx_v4l2_ioctl. Userspace - * copying is done already, arg is a kernel pointer. + * em28xx_v4l2_poll() + * will allocate buffers when called for the first time */ -static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) +static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) { + unsigned int mask = 0; struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; + struct em28xx *dev = fh->dev; - if (!dev) - return -ENODEV; + if (unlikely(res_get(fh) < 0)) + return POLLERR; - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); - - switch (cmd) { - - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof(*cap)); - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, - sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, - sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = - V4L2_CAP_SLICED_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (dev->has_tuner) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; - } - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *fmtd = arg; + mutex_lock(&dev->lock); - if (fmtd->index != 0) - return -EINVAL; - memset(fmtd, 0, sizeof(*fmtd)); - fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmtd->description, "Packed YUY2"); - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); - return 0; - } - case VIDIOC_G_FMT: - { - int retval; - mutex_lock(&dev->lock); - retval = em28xx_get_fmt(dev, (struct v4l2_format *) arg); - mutex_unlock(&dev->lock); - return retval; + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("device not present\n"); + } else if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg("device is misconfigured; close and open it again\n"); + } else { + if (dev->io == IO_NONE) { + if (!em28xx_request_buffers + (dev, EM28XX_NUM_READ_FRAMES)) { + em28xx_warn + ("poll() failed, not enough memory\n"); + } else { + dev->io = IO_READ; + dev->stream = STREAM_ON; + } + } - } - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - { - int retval; - mutex_lock(&dev->lock); - retval = em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); - mutex_unlock(&dev->lock); - return retval; - } + if (dev->io == IO_READ) { + em28xx_queue_unusedframes(dev); + poll_wait(filp, &dev->wait_frame, wait); - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - u32 i; - int ret; + if (!list_empty(&dev->outqueue)) + mask |= POLLIN | POLLRDNORM; - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; + mutex_unlock(&dev->lock); - if (dev->io == IO_READ) { - em28xx_videodbg ("method is set to read;" - " close and open the device again to" - " choose the mmap I/O method\n"); - return -EINVAL; + return mask; } + } - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); - return -EINVAL; - } - - mutex_lock(&dev->lock); - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))){ - mutex_unlock(&dev->lock); - return ret; - } - } + mutex_unlock(&dev->lock); + return POLLERR; +} - em28xx_empty_framequeues(dev); +/* + * em28xx_v4l2_mmap() + */ +static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long start = vma->vm_start; + void *pos; + u32 i; - em28xx_release_buffers(dev); - if (rb->count) - rb->count = - em28xx_request_buffers(dev, rb->count); + if (unlikely(res_get(fh) < 0)) + return -EBUSY; - dev->frame_current = NULL; + mutex_lock(&dev->lock); - em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", - rb->count); - dev->io = rb->count ? IO_MMAP : IO_NONE; + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("mmap: device not present\n"); mutex_unlock(&dev->lock); - return 0; + return -ENODEV; } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *b = arg; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) - return -EINVAL; - - memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); - if (dev->frame[b->index].vma_use_count) { - b->flags |= V4L2_BUF_FLAG_MAPPED; - } - if (dev->frame[b->index].state == F_DONE) - b->flags |= V4L2_BUF_FLAG_DONE; - else if (dev->frame[b->index].state != F_UNUSED) - b->flags |= V4L2_BUF_FLAG_QUEUED; - return 0; + if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg ("mmap: Device is misconfigured; close and " + "open it again\n"); + mutex_unlock(&dev->lock); + return -EIO; } - case VIDIOC_QBUF: - { - struct v4l2_buffer *b = arg; - unsigned long lock_flags; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) { - return -EINVAL; - } - - if (dev->frame[b->index].state != F_UNUSED) { - return -EAGAIN; - } - dev->frame[b->index].state = F_QUEUED; - /* add frame to fifo */ - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[b->index].frame, - &dev->inqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - return 0; + if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) { + mutex_unlock(&dev->lock); + return -EINVAL; } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *b = arg; - struct em28xx_frame_t *f; - unsigned long lock_flags; - int ret = 0; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->outqueue)) { - if (dev->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) - return ret; - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - } - - spin_lock_irqsave(&dev->queue_lock, lock_flags); - f = list_entry(dev->outqueue.next, - struct em28xx_frame_t, frame); - list_del(dev->outqueue.next); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - f->state = F_UNUSED; - memcpy(b, &f->buf, sizeof(*b)); + if (size > PAGE_ALIGN(dev->frame[0].buf.length)) + size = PAGE_ALIGN(dev->frame[0].buf.length); - if (f->vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - return 0; + for (i = 0; i < dev->num_frames; i++) { + if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) + break; } - default: - return em28xx_do_ioctl(inode, filp, dev, cmd, arg, - em28xx_video_do_ioctl); + if (i == dev->num_frames) { + em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); + mutex_unlock(&dev->lock); + return -EINVAL; } - return 0; -} - -/* - * em28xx_v4l2_ioctl() - * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl() - */ -static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - if (dev->state & DEV_DISCONNECTED) { - em28xx_errdev("v4l2 ioctl: device not present\n"); - return -ENODEV; - } + /* VM_IO is eventually going to replace PageReserved altogether */ + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - if (dev->state & DEV_MISCONFIGURED) { - em28xx_errdev - ("v4l2 ioctl: device is misconfigured; close and open it again\n"); - return -EIO; + pos = dev->frame[i].bufmem; + while (size > 0) { /* size is page-aligned */ + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + em28xx_videodbg("mmap: vm_insert_page failed\n"); + mutex_unlock(&dev->lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; } - ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); + vma->vm_ops = &em28xx_vm_ops; + vma->vm_private_data = &dev->frame[i]; - return ret; + em28xx_vm_open(vma); + mutex_unlock(&dev->lock); + return 0; } static const struct file_operations em28xx_v4l_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = em28xx_v4l2_ioctl, - .read = em28xx_v4l2_read, - .poll = em28xx_v4l2_poll, - .mmap = em28xx_v4l2_mmap, - .llseek = no_llseek, - .compat_ioctl = v4l_compat_ioctl32, + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .read = em28xx_v4l2_read, + .poll = em28xx_v4l2_poll, + .mmap = em28xx_v4l2_mmap, + .ioctl = video_ioctl2, + .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, +}; +static const struct video_device em28xx_video_template = { + .fops = &em28xx_v4l_fops, + .release = video_device_release, + + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + + .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture, + .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture, + .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + + .tvnorms = V4L2_STD_ALL, + .current_norm = V4L2_STD_NTSC_M, }; + /******************************** usb interface *****************************************/ /* @@ -1639,7 +1731,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, errCode = em28xx_config(dev); - /* allocate and fill v4l2 device struct */ + /* allocate and fill video video_device struct */ dev->vdev = video_device_alloc(); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); @@ -1647,7 +1739,17 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, kfree(dev); return -ENOMEM; } + memcpy(dev->vdev, &em28xx_video_template, + sizeof(em28xx_video_template)); + dev->vdev->type = VID_TYPE_CAPTURE; + if (dev->has_tuner) + dev->vdev->type |= VID_TYPE_TUNER; + dev->vdev->dev = &dev->udev->dev; + snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), + "%s#%d %s", "em28xx", dev->devno, "video"); + dev->vdev->current_norm = dev->tvnorm->id; + /* Allocate and fill vbi video_device struct */ dev->vbi_dev = video_device_alloc(); if (NULL == dev->vbi_dev) { em28xx_errdev("cannot allocate video_device.\n"); @@ -1656,41 +1758,27 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, kfree(dev); return -ENOMEM; } - - /* Fills VBI device info */ + memcpy(dev->vbi_dev, &em28xx_video_template, + sizeof(em28xx_video_template)); dev->vbi_dev->type = VFL_TYPE_VBI; - dev->vbi_dev->fops = &em28xx_v4l_fops; - dev->vbi_dev->minor = -1; dev->vbi_dev->dev = &dev->udev->dev; - dev->vbi_dev->release = video_device_release; - snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", - "em28xx",dev->devno,"vbi"); - - /* Fills CAPTURE device info */ - dev->vdev->type = VID_TYPE_CAPTURE; - if (dev->has_tuner) - dev->vdev->type |= VID_TYPE_TUNER; - dev->vdev->fops = &em28xx_v4l_fops; - dev->vdev->minor = -1; - dev->vdev->dev = &dev->udev->dev; - dev->vdev->release = video_device_release; - snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", - "em28xx",dev->devno,"video"); + snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), + "%s#%d %s", "em28xx", dev->devno, "vbi"); + dev->vbi_dev->current_norm = dev->tvnorm->id; list_add_tail(&dev->devlist,&em28xx_devlist); - if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); msleep(3); em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); msleep(3); - } + video_mux(dev, 0); - /* register v4l2 device */ + /* register v4l2 video video_device */ if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]))) { em28xx_errdev("unable to register video device (error=%i).\n", @@ -1703,6 +1791,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return -ENODEV; } + /* register v4l2 vbi video_device */ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { printk("unable to register vbi device\n"); @@ -1713,8 +1802,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_devused&=~(1<devno); kfree(dev); return -ENODEV; - } else { - printk("registered VBI\n"); } em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", -- cgit v1.2.3 From cb77d010221e66c63f4a71546fed73be9b12b9a3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Nov 2007 13:23:54 -0300 Subject: V4L/DVB (6586): Remove some dead code and make drive fully V4L2 compatible There were some vestiges of an old V4L1 I2C driver that were called by em28xx. This patch removes this dead code, and replaces videodev.h to videodev2.h Now, this driver doesn't require V4L1 anymore. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/Kconfig | 2 +- drivers/media/video/em28xx/em28xx-video.c | 10 ---------- drivers/media/video/em28xx/em28xx.h | 3 +-- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index c1127802ad9..813077b6ef7 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_EM28XX tristate "Empia EM2800/2820/2840 USB video capture support" - depends on VIDEO_V4L1 && I2C && INPUT + depends on VIDEO_DEV && I2C && INPUT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 022afb7b98c..c4db1aebdcd 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1675,16 +1675,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req = em28xx_read_reg_req; dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - /* setup video picture settings for saa7113h */ - memset(&dev->vpic, 0, sizeof(dev->vpic)); - dev->vpic.colour = 128 << 8; - dev->vpic.hue = 128 << 8; - dev->vpic.brightness = 128 << 8; - dev->vpic.contrast = 192 << 8; - dev->vpic.whiteness = 128 << 8; /* This one isn't used */ - dev->vpic.depth = 16; - dev->vpic.palette = VIDEO_PALETTE_YUV422; - em28xx_pre_card_setup(dev); errCode = em28xx_config(dev); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 672880383de..f355075d50d 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -25,7 +25,7 @@ #ifndef _EM28XX_H #define _EM28XX_H -#include +#include #include #include #include @@ -239,7 +239,6 @@ struct em28xx { /* video for linux */ int users; /* user count for exclusive use */ struct video_device *vdev; /* video for linux device struct */ - struct video_picture vpic; /* picture settings only used to init saa7113h */ struct em28xx_tvnorm *tvnorm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ -- cgit v1.2.3 From 7d497f8afa80128bb99a425a6d7a766a863128a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 11 Nov 2007 14:15:34 -0300 Subject: V4L/DVB (6587): Cleanup at tv norm selection With the conversion to the vidio_ioctl2, tvnorms array is not required anymore. Also, removed some code from V4L1 time (VIDEO_MODE_foo), specied at the non-used video_decoder.h. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 14 ------- drivers/media/video/em28xx/em28xx-i2c.c | 1 - drivers/media/video/em28xx/em28xx-video.c | 61 ++++--------------------------- drivers/media/video/em28xx/em28xx.h | 28 ++++++-------- 4 files changed, 18 insertions(+), 86 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index a2c0794821b..fd64058a04e 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -52,7 +52,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Unknown EM2800 video grabber", .is_em2800 = 1, .vchannels = 2, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, @@ -74,7 +73,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, .vchannels = 2, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, @@ -91,7 +89,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_TERRATEC_CINERGY_250] = { .name = "Terratec Cinergy 250 USB", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -113,7 +110,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_PINNACLE_USB_2] = { .name = "Pinnacle PCTV USB 2", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -135,7 +131,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { .name = "Hauppauge WinTV USB 2", .vchannels = 3, - .norm = VIDEO_MODE_NTSC, .tuner_type = TUNER_PHILIPS_FM1236_MK3, .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, .has_tuner = 1, @@ -156,7 +151,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900/950", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .has_tuner = 1, @@ -178,7 +172,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .tuner_type = TUNER_XC2028, @@ -202,7 +195,6 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .tuner_type = TUNER_XC2028, @@ -224,7 +216,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_MSI_VOX_USB_2] = { .name = "MSI VOX USB 2.0", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, .has_tuner = 1, @@ -247,7 +238,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy 200 USB", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -270,7 +260,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Leadtek Winfast USB II", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -293,7 +282,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Kworld USB2800", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_PHILIPS_ATSC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, @@ -315,7 +303,6 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .has_tuner = 0, .decoder = EM28XX_SAA7113, .input = {{ @@ -332,7 +319,6 @@ struct em28xx_board em28xx_boards[] = { .name = "V-Gear PocketTV", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index acd853d217e..cacd04d46e9 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "em28xx.h" #include "tuner-xc2028.h" diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index c4db1aebdcd..c2901f13eb2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "em28xx.h" @@ -77,29 +76,6 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ static unsigned long em28xx_devused; -/* supported tv norms */ -static struct em28xx_tvnorm tvnorms[] = { - { - .name = "PAL", - .id = V4L2_STD_PAL, - .mode = VIDEO_MODE_PAL, - }, { - .name = "NTSC", - .id = V4L2_STD_NTSC, - .mode = VIDEO_MODE_NTSC, - }, { - .name = "SECAM", - .id = V4L2_STD_SECAM, - .mode = VIDEO_MODE_SECAM, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - .mode = VIDEO_MODE_PAL, - } -}; - -#define TVNORMS ARRAY_SIZE(tvnorms) - /* supported controls */ /* Common to all boards */ static struct v4l2_queryctrl em28xx_qctrl[] = { @@ -536,27 +512,14 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; struct v4l2_format f; - unsigned int i; int rc; rc = check_dev(dev); if (rc < 0) return rc; - for (i = 0; i < TVNORMS; i++) - if (*norm == tvnorms[i].id) - break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*norm & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - - *norm = tvnorms[i].id; - mutex_lock(&dev->lock); - dev->tvnorm = &tvnorms[i]; + dev->norm = *norm; mutex_unlock(&dev->lock); /* Adjusts width/height, if needed */ @@ -575,7 +538,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); em28xx_resolution_set(dev); - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); + em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm); mutex_unlock(&dev->lock); return 0; @@ -615,8 +578,7 @@ static int vidioc_enum_input(struct file *file, void *priv, (EM28XX_VMUX_CABLE == INPUT(n)->type)) i->type = V4L2_INPUT_TYPE_TUNER; - for (n = 0; n < ARRAY_SIZE(tvnorms); n++) - i->std |= tvnorms[n].id; + i->std = dev->vdev->tvnorms; return 0; } @@ -1643,7 +1605,7 @@ static const struct video_device em28xx_video_template = { .vidioc_s_frequency = vidioc_s_frequency, .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_PAL, }; @@ -1658,7 +1620,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, { struct em28xx *dev = *devhandle; int retval = -ENOMEM; - int errCode, i; + int errCode; unsigned int maxh, maxw; dev->udev = udev; @@ -1694,15 +1656,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, /* configure the device */ em28xx_config_i2c(dev); - for (i = 0; i < TVNORMS; i++) - if (em28xx_boards[dev->model].norm == tvnorms[i].mode) - break; - if (i == TVNORMS) - i = 0; - - dev->tvnorm = &tvnorms[i]; /* set default norm */ - - em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); + /* set default norm */ + dev->norm = em28xx_video_template.current_norm; maxw = norm_maxw(dev); maxh = norm_maxh(dev); @@ -1737,7 +1692,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vdev->dev = &dev->udev->dev; snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", "em28xx", dev->devno, "video"); - dev->vdev->current_norm = dev->tvnorm->id; /* Allocate and fill vbi video_device struct */ dev->vbi_dev = video_device_alloc(); @@ -1754,7 +1708,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vbi_dev->dev = &dev->udev->dev; snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", "em28xx", dev->devno, "vbi"); - dev->vbi_dev->current_norm = dev->tvnorm->id; list_add_tail(&dev->devlist,&em28xx_devlist); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index f355075d50d..8d045867dac 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -167,7 +167,6 @@ enum em28xx_decoder { struct em28xx_board { char *name; int vchannels; - int norm; int tuner_type; /* i2c flags */ @@ -203,14 +202,6 @@ enum em28xx_dev_state { DEV_MISCONFIGURED = 0x04, }; -/* tvnorms */ -struct em28xx_tvnorm { - char *name; - v4l2_std_id id; - /* mode for saa7113h */ - int mode; -}; - /* main device struct */ struct em28xx { /* generic device properties */ @@ -239,7 +230,7 @@ struct em28xx { /* video for linux */ int users; /* user count for exclusive use */ struct video_device *vdev; /* video for linux device struct */ - struct em28xx_tvnorm *tvnorm; /* selected tv norm */ + v4l2_std_id norm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ unsigned int ctl_ainput; /* slected audio input */ @@ -522,18 +513,21 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val) /*FIXME: maxw should be dependent of alt mode */ inline static unsigned int norm_maxw(struct em28xx *dev) { - switch(dev->model){ - case (EM2820_BOARD_MSI_VOX_USB_2): return(640); - default: return(720); + switch (dev->model) { + case EM2820_BOARD_MSI_VOX_USB_2: + return 640; + default: + return 720; } } inline static unsigned int norm_maxh(struct em28xx *dev) { - switch(dev->model){ - case (EM2820_BOARD_MSI_VOX_USB_2): return(480); - default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480; + switch (dev->model) { + case EM2820_BOARD_MSI_VOX_USB_2: + return 480; + default: + return (dev->norm & V4L2_STD_625_50) ? 576 : 480; } } - #endif -- cgit v1.2.3 From 48e6a0173162690533951cd72b3edaa2e1605716 Mon Sep 17 00:00:00 2001 From: Jaroslav Barton Date: Sat, 10 Nov 2007 19:17:45 -0300 Subject: V4L/DVB (6588): Leadtek Winfast DTV Dongle remote control Add remote controller support for Leadtek Winfast DTV Dongle based on DiB7700P, MT2060 and using last drivers (6040:6a79c243aecc), firmware dvb-usb-dib0700-03-pre1.fw Signed-off-by: Jaroslav Barton Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 58452b52002..5af779e332b 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -415,6 +415,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x1e, 0x38, KEY_YELLOW }, { 0x1e, 0x3b, KEY_GOTO }, { 0x1e, 0x3d, KEY_POWER }, + + /* Key codes for the Leadtek Winfast DTV Dongle */ + { 0x00, 0x42, KEY_POWER }, + { 0x07, 0x7c, KEY_TUNER }, + { 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */ + { 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/ + { 0x0f, 0x71, KEY_DOT }, /* frequency */ + { 0x07, 0x43, KEY_0 }, + { 0x0c, 0x41, KEY_1 }, + { 0x04, 0x43, KEY_2 }, + { 0x0b, 0x7f, KEY_3 }, + { 0x0e, 0x41, KEY_4 }, + { 0x06, 0x43, KEY_5 }, + { 0x09, 0x7f, KEY_6 }, + { 0x0d, 0x7e, KEY_7 }, + { 0x05, 0x7c, KEY_8 }, + { 0x0a, 0x40, KEY_9 }, + { 0x0e, 0x4e, KEY_CLEAR }, + { 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */ + { 0x0f, 0x41, KEY_LAST }, /* recall */ + { 0x03, 0x42, KEY_MUTE }, + { 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/ + { 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */ + { 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x0b, 0x70, KEY_RECORD }, + { 0x03, 0x7d, KEY_VOLUMEUP }, + { 0x01, 0x7d, KEY_VOLUMEDOWN }, + { 0x02, 0x42, KEY_CHANNELUP }, + { 0x00, 0x7d, KEY_CHANNELDOWN }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ -- cgit v1.2.3 From 67053a409af94ac3d67e0ef0651c42c8c10f5394 Mon Sep 17 00:00:00 2001 From: dominik Date: Sat, 10 Nov 2007 19:23:31 -0300 Subject: V4L/DVB (6589): Gigabyte u7000 usb dvb-t support Signed-off-by: dominik Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 12 +++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 7 ++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 5af779e332b..1aa335d5aa9 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -850,6 +850,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, +/* 21 */{ USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -891,7 +892,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 7, + .num_device_descs = 8, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -920,6 +921,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "AVerMedia AVerTV DVB-T Express", { &dib0700_usb_id_table[20] }, { NULL }, + }, + /* dom : pour Gigabyte U7000 */ + { "Gigabyte U7000", + { &dib0700_usb_id_table[21], NULL }, + { NULL }, } }, @@ -990,7 +996,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, - }, + } }, .rc_interval = DEFAULT_RC_INTERVAL, @@ -1053,7 +1059,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Pinnacle PCTV Dual DVB-T Diversity Stick", { &dib0700_usb_id_table[18], NULL }, { NULL }, - }, + } } }, }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4fa3e895028..d6d96308cba 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -44,6 +44,9 @@ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 #define USB_VID_UNIWILL 0x1584 #define USB_VID_WIDEVIEW 0x14aa +/* dom : pour gigabyte u7000 */ +#define USB_VID_GIGABYTE 0x1044 + /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 @@ -69,6 +72,7 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7700_U7000 0x7001 #define USB_PID_DIBCOM_STK7070P 0x1ebc #define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 @@ -170,6 +174,7 @@ #define USB_PID_OPERA1_WARM 0x3829 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 - +/* dom pour gigabyte u7000 */ +#define USB_PID_GIGABYTE_U7000 0x7001 #endif -- cgit v1.2.3 From 542794be2caf46b5fe95cbb7cd878d884597647e Mon Sep 17 00:00:00 2001 From: Olivier DANET Date: Mon, 12 Nov 2007 10:48:51 -0300 Subject: V4L/DVB (6590): Adding support for VHF with MT2266-devices MT2266 : - support for VHF - Minor enhancements Signed-off-by: Olivier DANET Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt2266.c | 204 +++++++++++++++++++++++------------ 1 file changed, 134 insertions(+), 70 deletions(-) diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 03fe8265745..54b18f94b14 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -38,8 +38,12 @@ struct mt2266_priv { u32 frequency; u32 bandwidth; + u8 band; }; +#define MT2266_VHF 1 +#define MT2266_UHF 0 + /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ static int debug; @@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) } // Initialisation sequences -static u8 mt2266_init1[] = { - REG_TUNE, - 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; +static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, + 0x00, 0x52, 0x99, 0x3f }; static u8 mt2266_init2[] = { - 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, - 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, + 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, + 0xff, 0x00, 0x77, 0x0f, 0x2d +}; + +static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22 }; -static u8 mt2266_init_8mhz[] = { - REG_BANDWIDTH, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; +static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32 }; -static u8 mt2266_init_7mhz[] = { - REG_BANDWIDTH, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; +static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7 }; -static u8 mt2266_init_6mhz[] = { - REG_BANDWIDTH, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; +static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, + 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; + +static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, + 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; #define FREF 30000 // Quartz oscillator 30 MHz @@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame u8 lnaband; u8 b[10]; int i; + u8 band; priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); - freq = params->frequency / 1000; // Hz -> kHz + if (freq < 470000 && freq > 230000) + return -EINVAL; /* Gap between VHF and UHF bands */ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; priv->frequency = freq * 1000; - tune=2 * freq * (8192/16) / (FREF/16); - - if (freq <= 495000) lnaband = 0xEE; else - if (freq <= 525000) lnaband = 0xDD; else - if (freq <= 550000) lnaband = 0xCC; else - if (freq <= 580000) lnaband = 0xBB; else - if (freq <= 605000) lnaband = 0xAA; else - if (freq <= 630000) lnaband = 0x99; else - if (freq <= 655000) lnaband = 0x88; else - if (freq <= 685000) lnaband = 0x77; else - if (freq <= 710000) lnaband = 0x66; else - if (freq <= 735000) lnaband = 0x55; else - if (freq <= 765000) lnaband = 0x44; else - if (freq <= 802000) lnaband = 0x33; else - if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; - - msleep(100); - mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: - (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: - mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + tune = 2 * freq * (8192/16) / (FREF/16); + band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; + if (band == MT2266_VHF) + tune *= 2; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + mt2266_writeregs(priv, mt2266_init_6mhz, + sizeof(mt2266_init_6mhz)); + break; + case BANDWIDTH_7_MHZ: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; + case BANDWIDTH_8_MHZ: + default: + mt2266_writeregs(priv, mt2266_init_8mhz, + sizeof(mt2266_init_8mhz)); + break; + } + + if (band == MT2266_VHF && priv->band == MT2266_UHF) { + dprintk("Switch from UHF to VHF"); + mt2266_writereg(priv, 0x05, 0x04); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); + } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { + dprintk("Switch from VHF to UHF"); + mt2266_writereg(priv, 0x05, 0x52); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); + } + msleep(10); + + if (freq <= 495000) + lnaband = 0xEE; + else if (freq <= 525000) + lnaband = 0xDD; + else if (freq <= 550000) + lnaband = 0xCC; + else if (freq <= 580000) + lnaband = 0xBB; + else if (freq <= 605000) + lnaband = 0xAA; + else if (freq <= 630000) + lnaband = 0x99; + else if (freq <= 655000) + lnaband = 0x88; + else if (freq <= 685000) + lnaband = 0x77; + else if (freq <= 710000) + lnaband = 0x66; + else if (freq <= 735000) + lnaband = 0x55; + else if (freq <= 765000) + lnaband = 0x44; + else if (freq <= 802000) + lnaband = 0x33; + else if (freq <= 840000) + lnaband = 0x22; + else + lnaband = 0x11; b[0] = REG_TUNE; b[1] = (tune >> 8) & 0x1F; @@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); - dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); - - b[0] = 0x05; - b[1] = 0x62; - b[2] = lnaband; - mt2266_writeregs(priv,b,3); + dprintk("set_parms: tune=%d band=%d %s", + (int) tune, (int) lnaband, + (band == MT2266_UHF) ? "UHF" : "VHF"); + dprintk("set_parms: [1..3]: %2x %2x %2x", + (int) b[1], (int) b[2], (int)b[3]); + + if (band == MT2266_UHF) { + b[0] = 0x05; + b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; + b[2] = lnaband; + mt2266_writeregs(priv, b, 3); + } - //Waits for pll lock or timeout + /* Wait for pll lock or timeout */ i = 0; do { mt2266_readreg(priv,REG_LOCK,b); - if ((b[0] & 0x40)==0x40) + if (b[0] & 0x40) break; msleep(10); i++; } while (i<10); dprintk("Lock when i=%i",(int)i); + + if (band == MT2266_UHF && priv->band == MT2266_VHF) + mt2266_writereg(priv, 0x05, 0x62); + + priv->band = band; + return ret; } static void mt2266_calibrate(struct mt2266_priv *priv) { - mt2266_writereg(priv,0x11,0x03); - mt2266_writereg(priv,0x11,0x01); - - mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); - mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); - - mt2266_writereg(priv,0x33,0x5e); - mt2266_writereg(priv,0x10,0x10); - mt2266_writereg(priv,0x10,0x00); - - mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); - + mt2266_writereg(priv, 0x11, 0x03); + mt2266_writereg(priv, 0x11, 0x01); + mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); + mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); + mt2266_writereg(priv, 0x33, 0x5e); + mt2266_writereg(priv, 0x10, 0x10); + mt2266_writereg(priv, 0x10, 0x00); + mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); msleep(25); - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0x00); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); msleep(75); - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0xff); } static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) @@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static int mt2266_init(struct dvb_frontend *fe) { + int ret; struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); + ret = mt2266_writereg(priv, 0x17, 0x6d); + if (ret < 0) + return ret; + ret = mt2266_writereg(priv, 0x1c, 0xff); + if (ret < 0) + return ret; return 0; } static int mt2266_sleep(struct dvb_frontend *fe) { struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0x00); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); return 0; } @@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops mt2266_tuner_ops = { .info = { .name = "Microtune MT2266", - .frequency_min = 470000000, - .frequency_max = 860000000, + .frequency_min = 174000000, + .frequency_max = 862000000, .frequency_step = 50000, }, .release = mt2266_release, @@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter priv->cfg = cfg; priv->i2c = i2c; + priv->band = MT2266_UHF; - if (mt2266_readreg(priv,0,&id) != 0) { + if (mt2266_readreg(priv, 0, &id)) { kfree(priv); return NULL; } -- cgit v1.2.3 From ddef2dcc4ead7a9412533202a42c40648e620f43 Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Mon, 12 Nov 2007 11:42:54 -0300 Subject: V4L/DVB (6591): Adds support for MT9V111 on sn9c102 Adds a new image sensor to the sn9c102 driver. Signed-off-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/sn9c102.txt | 1 + drivers/media/video/sn9c102/Makefile | 1 + drivers/media/video/sn9c102/sn9c102_core.c | 4 +- drivers/media/video/sn9c102/sn9c102_devtable.h | 2 + drivers/media/video/sn9c102/sn9c102_mt9v111.c | 259 +++++++++++++++++++++++++ 5 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 drivers/media/video/sn9c102/sn9c102_mt9v111.c diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt index 1ffad19ce89..b26f5195af5 100644 --- a/Documentation/video4linux/sn9c102.txt +++ b/Documentation/video4linux/sn9c102.txt @@ -568,6 +568,7 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'. Many thanks to following persons for their contribute (listed in alphabetical order): +- David Anderson for the donation of a webcam; - Luca Capello for the donation of a webcam; - Philippe Coval for having helped testing the PAS202BCA image sensor; - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile index a56d16f69c7..7ecd5a90c7c 100644 --- a/drivers/media/video/sn9c102/Makefile +++ b/drivers/media/video/sn9c102/Makefile @@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \ sn9c102_hv7131r.o \ sn9c102_mi0343.o \ sn9c102_mi0360.o \ + sn9c102_mt9v111.o \ sn9c102_ov7630.o \ sn9c102_ov7660.o \ sn9c102_pas106b.o \ diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 511847912c4..c40ba3adab2 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -47,7 +47,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.47" +#define SN9C102_MODULE_VERSION "1:1.47pre49" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) /*****************************************************************************/ @@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); @@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + video_set_drvdata(cam->v4ldev, cam); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 916054faf9b..35223e0d7e4 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); +extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); @@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c new file mode 100644 index 00000000000..3b98ac3bbc3 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c @@ -0,0 +1,259 @@ +/*************************************************************************** + * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * + * Controllers * + * * + * Copyright (C) 2007 by Luca Risolia * + * * + * 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 * + * (at your option) any later version. * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static int mt9v111_init(struct sn9c102_device *cam) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + + err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, + {0x00, 0x03}, {0x1a, 0x04}, + {0x1f, 0x05}, {0x20, 0x06}, + {0x1f, 0x07}, {0x81, 0x08}, + {0x5c, 0x09}, {0x00, 0x0a}, + {0x00, 0x0b}, {0x00, 0x0c}, + {0x00, 0x0d}, {0x00, 0x0e}, + {0x00, 0x0f}, {0x03, 0x10}, + {0x00, 0x11}, {0x00, 0x12}, + {0x02, 0x13}, {0x14, 0x14}, + {0x28, 0x15}, {0x1e, 0x16}, + {0xe2, 0x17}, {0x06, 0x18}, + {0x00, 0x19}, {0x00, 0x1a}, + {0x00, 0x1b}, {0x08, 0x20}, + {0x39, 0x21}, {0x51, 0x22}, + {0x63, 0x23}, {0x73, 0x24}, + {0x82, 0x25}, {0x8f, 0x26}, + {0x9b, 0x27}, {0xa7, 0x28}, + {0xb1, 0x29}, {0xbc, 0x2a}, + {0xc6, 0x2b}, {0xcf, 0x2c}, + {0xd8, 0x2d}, {0xe1, 0x2e}, + {0xea, 0x2f}, {0xf2, 0x30}, + {0x13, 0x84}, {0x00, 0x85}, + {0x25, 0x86}, {0x00, 0x87}, + {0x07, 0x88}, {0x00, 0x89}, + {0xee, 0x8a}, {0x0f, 0x8b}, + {0xe5, 0x8c}, {0x0f, 0x8d}, + {0x2e, 0x8e}, {0x00, 0x8f}, + {0x30, 0x90}, {0x00, 0x91}, + {0xd4, 0x92}, {0x0f, 0x93}, + {0xfc, 0x94}, {0x0f, 0x95}, + {0x14, 0x96}, {0x00, 0x97}, + {0x00, 0x98}, {0x60, 0x99}, + {0x07, 0x9a}, {0x40, 0x9b}, + {0x20, 0x9c}, {0x00, 0x9d}, + {0x00, 0x9e}, {0x00, 0x9f}, + {0x2d, 0xc0}, {0x2d, 0xc1}, + {0x3a, 0xc2}, {0x05, 0xc3}, + {0x04, 0xc4}, {0x3f, 0xc5}, + {0x00, 0xc6}, {0x00, 0xc7}, + {0x50, 0xc8}, {0x3c, 0xc9}, + {0x28, 0xca}, {0xd8, 0xcb}, + {0x14, 0xcc}, {0xec, 0xcd}, + {0x32, 0xce}, {0xdd, 0xcf}, + {0x2d, 0xd0}, {0xdd, 0xd1}, + {0x6a, 0xd2}, {0x50, 0xd3}, + {0x60, 0xd4}, {0x00, 0xd5}, + {0x00, 0xd6}); + + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, + 0x04, 0x80, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x04, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, + 0x00, 0x08, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, + 0x00, 0x16, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, + 0x01, 0xe7, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, + 0x02, 0x87, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, + 0x00, 0x40, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, + 0x00, 0x09, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, + 0x30, 0x02, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, + 0x00, 0xb0, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, + 0x00, 0x7c, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x04, 0, 0); + + return err; +} + +static int mt9v111_get_ctrl(struct sn9c102_device *cam, + struct v4l2_control *ctrl) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + u8 data[2]; + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, + data) < 0) + return -EIO; + ctrl->value = data[1] & 0x80 ? 1 : 0; + return 0; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + +static int mt9v111_set_ctrl(struct sn9c102_device *cam, + const struct v4l2_control *ctrl) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x20, + ctrl->value ? 0x80 : 0x00, + ctrl->value ? 0x80 : 0x00, 0, + 0); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + +static int mt9v111_set_crop(struct sn9c102_device *cam, + const struct v4l2_rect *rect) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; + + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + +static int mt9v111_set_pix_format(struct sn9c102_device *cam, + const struct v4l2_pix_format *pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { + err += sn9c102_write_reg(cam, 0xb4, 0x17); + } else { + err += sn9c102_write_reg(cam, 0xe2, 0x17); + } + + return err; +} + + +static const struct sn9c102_sensor mt9v111 = { + .name = "MT9V111", + .maintainer = "Luca Risolia ", + .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x5c, + .init = &mt9v111_init, + .qctrl = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + }, + .get_ctrl = &mt9v111_get_ctrl, + .set_ctrl = &mt9v111_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &mt9v111_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &mt9v111_set_pix_format +}; + + +int sn9c102_probe_mt9v111(struct sn9c102_device *cam) +{ + u8 data[2]; + int err = 0; + + err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, + {0x29, 0x01}, {0x42, 0x17}, + {0x62, 0x17}, {0x08, 0x01}); + err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, + mt9v111.i2c_slave_id, 0x01, 0x00, + 0x04, 0, 0); + if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, + mt9v111.i2c_slave_id, 0x36, 2, + data) < 0) + return -EIO; + + if (data[0] != 0x82 || data[1] != 0x3a) + return -ENODEV; + + sn9c102_attach_sensor(cam, &mt9v111); + + return 0; +} -- cgit v1.2.3 From 43efe70253dd13b2d22ee51bb474ece25b3b41b1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 14 Nov 2007 19:30:28 -0300 Subject: V4L/DVB (6592): Add the capability to work with more complete firmwares Firmware version 2.7 has other firmware types. This patch adds the capability for the driver to work with those newer types. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 22 +++++++-- drivers/media/video/tuner-xc2028.c | 82 ++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index 80b19eb1b08..f6695d41356 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -31,8 +31,8 @@ DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS DTV8 - 8MHz - DVB-C/DVB-T */ -#define DTV6_ATSC (1<<5) -#define DTV6_QAM (1<<6) +#define DTV6 (1 << 5) +#define QAM (1 << 6) #define DTV7 (1<<7) #define DTV78 (1<<8) #define DTV8 (1<<9) @@ -60,9 +60,25 @@ /* Old firmwares were broken into init0 and init1 */ #define INIT1 (1<<14) +#define MONO (1 << 15) +#define ATSC (1 << 16) +#define IF (1 << 17) +#define LG60 (1 << 18) +#define ATI638 (1 << 19) +#define OREN538 (1 << 20) +#define OREN36 (1 << 21) +#define TOYOTA388 (1 << 22) +#define TOYOTA794 (1 << 23) +#define DIBCOM52 (1 << 24) +#define ZARLINK456 (1 << 25) +#define CHINA (1 << 26) +#define F6MHZ (1 << 27) +#define INPUT2 (1 << 28) +#define SCODE (1 << 29) + /* Newer types to be moved to videodev2.h */ -#define V4L2_STD_SECAM_K3 (0x02000000) +#define V4L2_STD_SECAM_K3 (0x04000000) /* Audio types */ diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index ecfc39036f9..ac0c9c3cde9 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -112,6 +112,68 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) return (buf[1]) | (buf[0] << 8); } +void dump_firm_type(unsigned int type) +{ + if (type & BASE) + printk("BASE "); + if (type & F8MHZ) + printk("F8MHZ "); + if (type & MTS) + printk("MTS "); + if (type & D2620) + printk("D2620 "); + if (type & D2633) + printk("D2633 "); + if (type & DTV6) + printk("DTV6 "); + if (type & QAM) + printk("QAM "); + if (type & DTV7) + printk("DTV7 "); + if (type & DTV78) + printk("DTV78 "); + if (type & DTV8) + printk("DTV8 "); + if (type & FM) + printk("FM "); + if (type & INPUT1) + printk("INPUT1 "); + if (type & LCD) + printk("LCD "); + if (type & NOGD) + printk("NOGD "); + if (type & MONO) + printk("MONO "); + if (type & ATSC) + printk("ATSC "); + if (type & IF) + printk("IF "); + if (type & LG60) + printk("LG60 "); + if (type & ATI638) + printk("ATI638 "); + if (type & OREN538) + printk("OREN538 "); + if (type & OREN36) + printk("OREN36 "); + if (type & TOYOTA388) + printk("TOYOTA388 "); + if (type & TOYOTA794) + printk("TOYOTA794 "); + if (type & DIBCOM52) + printk("DIBCOM52 "); + if (type & ZARLINK456) + printk("ZARLINK456 "); + if (type & CHINA) + printk("CHINA "); + if (type & F6MHZ) + printk("F6MHZ "); + if (type & INPUT2) + printk("INPUT2 "); + if (type & SCODE) + printk("SCODE "); +} + static void free_firmware(struct xc2028_data *priv) { int i; @@ -214,8 +276,10 @@ static int load_all_firmwares(struct dvb_frontend *fe) p += sizeof(size); if ((!size) || (size + p > endp)) { - tuner_info("Firmware type %x, id %lx corrupt\n", - type, (unsigned long)id); + tuner_info("Firmware type "); + dump_firm_type(type); + printk("(%x), id %lx corrupt (size=%ld, expected %d)\n", + type, (unsigned long)id, endp - p, size); goto corrupt; } @@ -225,7 +289,9 @@ static int load_all_firmwares(struct dvb_frontend *fe) rc = -ENOMEM; goto err; } - tuner_info("Loading firmware type %x, id %lx, size=%d.\n", + tuner_info("Loading firmware type "); + dump_firm_type(type); + printk("(%x), id %lx, size=%d.\n", type, (unsigned long)id, size); memcpy(priv->firm[n].ptr, p, size); @@ -366,7 +432,7 @@ found: size -= len; } } - return -EINVAL; + return 0; } static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, @@ -451,7 +517,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, break; case BANDWIDTH_6_MHZ: /* FIXME: Should allow select also ATSC */ - type |= DTV6_QAM; + type |= DTV6 | QAM; break; default: @@ -485,6 +551,12 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (rc < 0) return rc; + /* Load SCODE firmware, if needed */ + tuner_info("Trying to load scode firmware\n"); + type0 = SCODE | priv->ctrl.type; + if (priv->ctrl.type == XC2028_FIRM_MTS) + type0 |= MTS; + version = xc2028_get_reg(priv, 0x0004); hwmodel = xc2028_get_reg(priv, 0x0008); -- cgit v1.2.3 From f380e1d2c9a1ff82a89ec68850ce53094359000e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 15 Nov 2007 08:43:53 -0300 Subject: V4L/DVB (6593): Fix scode table loading Xceive 2028/3028 has a concept of scode/dcode. Scode is a table of 16 values (each with 12 bytes i2c sequence). Dcode is the entry of Scode table that should be used, given a certain frequency. The idea is that, depending on what frequency is selected, and according with a country-based (or standard-based?) table, the Xceive should be "hacked" to fine-tune that specific frequency. By default, Scode=0 is used, for undefined frequencies. Also, Scode=0 seems to be the most used value. This patch adds the capability of selecting a scode. However, extra work will be needed to allow auto-selecting the proper scode, for a given set of frequencies. I'm not sure what would be the proper way for implementing the dcode selection. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 98 ++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index ac0c9c3cde9..e046c21be0b 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -116,6 +116,8 @@ void dump_firm_type(unsigned int type) { if (type & BASE) printk("BASE "); + if (type & INIT1) + printk("INIT1 "); if (type & F8MHZ) printk("F8MHZ "); if (type & MTS) @@ -201,7 +203,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) tuner_info("%s called\n", __FUNCTION__); - tuner_info("Loading firmware %s\n", priv->ctrl.fname); + tuner_info("Reading firmware %s\n", priv->ctrl.fname); rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); if (rc < 0) { if (rc == -ENOENT) @@ -325,12 +327,11 @@ done: return rc; } -static int load_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id * id) +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) { struct xc2028_data *priv = fe->tuner_priv; - int i, rc; - unsigned char *p, *endp, buf[priv->max_len]; + int i; tuner_info("%s called\n", __FUNCTION__); @@ -339,7 +340,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, return -EINVAL; } - if ((type == 0) && (*id == 0)) + if (((type & ~SCODE) == 0) && (*id == 0)) *id = V4L2_STD_PAL; /* Seek for exact match */ @@ -356,21 +357,40 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, /*FIXME: Would make sense to seek for type "hint" match ? */ - tuner_info("Can't find firmware for type=%x, id=%lx\n", type, - (long int)*id); - return -EINVAL; + i = -EINVAL; + goto ret; found: *id = priv->firm[i].id; - tuner_info("Found firmware for type=%x, id=%lx\n", type, (long int)*id); - p = priv->firm[i].ptr; +ret: + tuner_info("%s firmware for type=", (i < 0)? "Can't find": "Found"); + dump_firm_type(type); + printk("(%x), id %08lx.\n", type, (unsigned long)*id); + + return i; +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p, *endp, buf[priv->max_len]; + + tuner_info("%s called\n", __FUNCTION__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + p = priv->firm[pos].ptr; if (!p) { printk(KERN_ERR PREFIX "Firmware pointer were freed!"); return -EINVAL; } - endp = p + priv->firm[i].size; + endp = p + priv->firm[pos].size; while (p < endp) { __u16 size; @@ -435,6 +455,42 @@ found: return 0; } +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, int scode) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + tuner_info("%s called\n", __FUNCTION__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + p = priv->firm[pos].ptr; + + if (!p) { + printk(KERN_ERR PREFIX "Firmware pointer were freed!"); + return -EINVAL; + } + + if ((priv->firm[pos].size != 12 * 16) || (scode >= 16)) + return -EINVAL; + + if (priv->version < 0x0202) { + send_seq(priv, {0x20, 0x00, 0x00, 0x00}); + } else { + send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); + } + + i2c_send(rc, priv, p + 12 * scode, 12); + + send_seq(priv, {0x00, 0x8c}); + + return 0; +} + static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, v4l2_std_id std, fe_bandwidth_t bandwidth) { @@ -527,8 +583,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, } /* Load INIT1, if needed */ - tuner_info("Trying to load init1 firmware\n"); - type0 = BASE | INIT1 | priv->ctrl.type; + tuner_info("Load init1 firmware, if exists\n"); + type0 = BASE | INIT1; if (priv->ctrl.type == XC2028_FIRM_MTS) type0 |= MTS; @@ -541,9 +597,9 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (priv->ctrl.type == XC2028_FIRM_MTS) type |= MTS; - tuner_info("firmware standard to load: %08lx\n", (unsigned long)std); + tuner_info("Firmware standard to load: %08lx\n", (unsigned long)std); if (priv->firm_type & std) { - tuner_info("no need to load a std-specific firmware.\n"); + tuner_info("Std-specific firmware already loaded.\n"); return 0; } @@ -551,11 +607,11 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (rc < 0) return rc; - /* Load SCODE firmware, if needed */ - tuner_info("Trying to load scode firmware\n"); - type0 = SCODE | priv->ctrl.type; - if (priv->ctrl.type == XC2028_FIRM_MTS) - type0 |= MTS; + /* Load SCODE firmware, if exists */ + tuner_info("Trying to load scode 0\n"); + type |= SCODE; + + rc = load_scode(fe, type, &std, 0); version = xc2028_get_reg(priv, 0x0004); hwmodel = xc2028_get_reg(priv, 0x0008); -- cgit v1.2.3 From 98883cdcb5884bd0f7a89ac36b7170404127b3ea Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 15 Nov 2007 09:35:44 -0300 Subject: V4L/DVB (6594): Add tuner_err macro Some tuners, like xc3028, need to print error messages. Instead of declaring local macros, create a tuner global macro for printing tuner errors. To preserve CodingStyle on all tuner_macros, a few CodingStyle violations were fixed at the other macros: - lines with more than 80 columns - two statements at the same line The patch also removes the CodingStyle violation of having emacs declarations inside de source code (CodingStyle chapter 18). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 40 +++++++++++++++++++----------------- drivers/media/video/tuner-i2c.h | 42 ++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index d6e5afdaa82..a4db32d97a1 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -71,24 +71,26 @@ struct tuner { /* ------------------------------------------------------------------------ */ -#define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) -#define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) -#define tuner_dbg(fmt, arg...) do {\ - extern int tuner_debug; \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); } while (0) +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + extern int tuner_debug; \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ + } while (0) #endif /* __TUNER_DRIVER_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h index cfba3d10906..b5ac189ba40 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/video/tuner-i2c.h @@ -47,24 +47,30 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, } #ifndef __TUNER_DRIVER_H__ -#define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#define tuner_dbg(fmt, arg...) do {\ - if ((debug)) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + if ((debug)) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) #endif /* __TUNER_DRIVER_H__ */ #endif /* __TUNER_I2C_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From 83fb340b3184875a63564ea174350b1d1b081874 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 15 Nov 2007 09:44:30 -0300 Subject: V4L/DVB (6595): Corrects printk lines Make the driver less verbose by default. It adds a debug parameter to make the driver more verbose. Also, error messages were using KERN_ERR level, instead of KERN_INFO. A few printk messages were reviewed to make them more clear. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 127 ++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index e046c21be0b..492181d8de8 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -24,6 +24,10 @@ #define PREFIX "xc2028" +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + static LIST_HEAD(xc2028_list); /* struct for storing firmware table */ struct firmware_description { @@ -68,14 +72,14 @@ struct xc2028_data { #define i2c_send(rc, priv, buf, size) do { \ rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ if (size != rc) \ - tuner_info("i2c output error: rc = %d (should be %d)\n",\ + tuner_err("i2c output error: rc = %d (should be %d)\n", \ rc, (int)size); \ } while (0) #define i2c_rcv(rc, priv, buf, size) do { \ rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ if (size != rc) \ - tuner_info("i2c input error: rc = %d (should be %d)\n", \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ rc, (int)size); \ } while (0) @@ -85,7 +89,7 @@ struct xc2028_data { if (sizeof(_val) != \ (rc = tuner_i2c_xfer_send(&priv->i2c_props, \ _val, sizeof(_val)))) { \ - tuner_info("Error on line %d: %d\n", __LINE__, rc); \ + tuner_err("Error on line %d: %d\n", __LINE__, rc); \ return -EINVAL; \ } \ msleep(10); \ @@ -96,7 +100,7 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) int rc; unsigned char buf[2]; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); buf[0] = reg>>8; buf[1] = (unsigned char) reg; @@ -201,16 +205,16 @@ static int load_all_firmwares(struct dvb_frontend *fe) int n, n_array; char name[33]; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); tuner_info("Reading firmware %s\n", priv->ctrl.fname); rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); if (rc < 0) { if (rc == -ENOENT) - tuner_info("Error: firmware %s not found.\n", + tuner_err("Error: firmware %s not found.\n", priv->ctrl.fname); else - tuner_info("Error %d while requesting firmware %s \n", + tuner_err("Error %d while requesting firmware %s \n", rc, priv->ctrl.fname); return rc; @@ -219,7 +223,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) endp = p + fw->size; if (fw->size < sizeof(name) - 1 + 2) { - tuner_info("Error: firmware size is zero!\n"); + tuner_err("Error: firmware size is zero!\n"); rc = -EINVAL; goto done; } @@ -231,7 +235,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) priv->version = le16_to_cpu(*(__u16 *) p); p += 2; - tuner_info("firmware: %s, ver %d.%d\n", name, + tuner_info("Firmware: %s, ver %d.%d\n", name, priv->version >> 8, priv->version & 0xff); if (p + 2 > endp) @@ -240,12 +244,13 @@ static int load_all_firmwares(struct dvb_frontend *fe) n_array = le16_to_cpu(*(__u16 *) p); p += 2; - tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname); + tuner_info("There are %d firmwares at %s\n", + n_array, priv->ctrl.fname); priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); if (!fw) { - tuner_info("Not enough memory for loading firmware.\n"); + tuner_err("Not enough memory for reading firmware.\n"); rc = -ENOMEM; goto done; } @@ -258,13 +263,13 @@ static int load_all_firmwares(struct dvb_frontend *fe) n++; if (n >= n_array) { - tuner_info("Too much firmwares at the file\n"); + tuner_err("Too much firmwares at the file\n"); goto corrupt; } /* Checks if there's enough bytes to read */ if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) { - tuner_info("Lost firmware!\n"); + tuner_err("Firmware header is incomplete!\n"); goto corrupt; } @@ -278,20 +283,21 @@ static int load_all_firmwares(struct dvb_frontend *fe) p += sizeof(size); if ((!size) || (size + p > endp)) { - tuner_info("Firmware type "); + tuner_err("Firmware type "); dump_firm_type(type); - printk("(%x), id %lx corrupt (size=%ld, expected %d)\n", - type, (unsigned long)id, endp - p, size); + printk("(%x), id %lx is corrupted " + "(size=%ld, expected %d)\n", + type, (unsigned long)id, endp - p, size); goto corrupt; } priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); if (!priv->firm[n].ptr) { - tuner_info("Not enough memory.\n"); + tuner_err("Not enough memory.\n"); rc = -ENOMEM; goto err; } - tuner_info("Loading firmware type "); + tuner_info("Reading firmware type "); dump_firm_type(type); printk("(%x), id %lx, size=%d.\n", type, (unsigned long)id, size); @@ -305,7 +311,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) } if (n + 1 != priv->firm_size) { - tuner_info("Firmware file is incomplete!\n"); + tuner_err("Firmware file is incomplete!\n"); goto corrupt; } @@ -313,7 +319,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) corrupt: rc = -EINVAL; - tuner_info("Error: firmware file is corrupted!\n"); + tuner_err("Error: firmware file is corrupted!\n"); err: tuner_info("Releasing loaded firmware file.\n"); @@ -322,7 +328,7 @@ err: done: release_firmware(fw); - tuner_info("Firmware files loaded.\n"); + tuner_dbg("Firmware files loaded.\n"); return rc; } @@ -333,10 +339,10 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, struct xc2028_data *priv = fe->tuner_priv; int i; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); if (!priv->firm) { - printk(KERN_ERR PREFIX "Error! firmware not loaded\n"); + tuner_err("Error! firmware not loaded\n"); return -EINVAL; } @@ -364,10 +370,11 @@ found: *id = priv->firm[i].id; ret: - tuner_info("%s firmware for type=", (i < 0)? "Can't find": "Found"); - dump_firm_type(type); - printk("(%x), id %08lx.\n", type, (unsigned long)*id); - + tuner_dbg("%s firmware for type=", (i < 0)? "Can't find": "Found"); + if (debug) { + dump_firm_type(type); + printk("(%x), id %08lx.\n", type, (unsigned long)*id); + } return i; } @@ -378,16 +385,20 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, int pos, rc; unsigned char *p, *endp, buf[priv->max_len]; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); pos = seek_firmware(fe, type, id); if (pos < 0) return pos; + tuner_info("Loading firmware for type="); + dump_firm_type(type); + printk("(%x), id %08lx.\n", type, (unsigned long)*id); + p = priv->firm[pos].ptr; if (!p) { - printk(KERN_ERR PREFIX "Firmware pointer were freed!"); + tuner_err("Firmware pointer were freed!"); return -EINVAL; } endp = p + priv->firm[pos].size; @@ -397,7 +408,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, /* Checks if there's enough bytes to read */ if (p + sizeof(size) > endp) { - tuner_info("missing bytes\n"); + tuner_err("Firmware chunk size is wrong\n"); return -EINVAL; } @@ -412,7 +423,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); if (rc < 0) { - tuner_info("Error at RESET code %d\n", + tuner_err("Error at RESET code %d\n", (*p) & 0x7f); return -EINVAL; } @@ -426,7 +437,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, } if ((size + p > endp)) { - tuner_info("missing bytes: need %d, have %d\n", + tuner_err("missing bytes: need %d, have %d\n", size, (int)(endp - p)); return -EINVAL; } @@ -444,7 +455,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, i2c_send(rc, priv, buf, len + 1); if (rc < 0) { - tuner_info("%d returned from send\n", rc); + tuner_err("%d returned from send\n", rc); return -EINVAL; } @@ -462,7 +473,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, int pos, rc; unsigned char *p; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); pos = seek_firmware(fe, type, id); if (pos < 0) @@ -471,7 +482,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, p = priv->firm[pos].ptr; if (!p) { - printk(KERN_ERR PREFIX "Firmware pointer were freed!"); + tuner_err("Firmware pointer were freed!"); return -EINVAL; } @@ -500,7 +511,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, unsigned int type0 = 0, type = 0; int change_digital_bandwidth; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); if (!priv->firm) { if (!priv->ctrl.fname) @@ -511,7 +522,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, return rc; } - tuner_info("I am in mode %u and I should switch to mode %i\n", + tuner_dbg("I am in mode %u and I should switch to mode %i\n", priv->mode, new_mode); /* first of all, determine whether we have switched the mode */ @@ -522,7 +533,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, change_digital_bandwidth = (priv->mode == T_DIGITAL_TV && bandwidth != priv->bandwidth) ? 1 : 0; - tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, + tuner_dbg("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, bandwidth); if (priv->need_load_generic) { @@ -544,8 +555,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, rc = load_firmware(fe, type0, &std0); if (rc < 0) { - tuner_info("Error %d while loading generic firmware\n", - rc); + tuner_err("Error %d while loading generic firmware\n", + rc); return rc; } @@ -555,7 +566,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, change_digital_bandwidth = 1; } - tuner_info("I should change bandwidth %u\n", change_digital_bandwidth); + tuner_dbg("I should change bandwidth %u\n", change_digital_bandwidth); if (change_digital_bandwidth) { @@ -577,13 +588,13 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, break; default: - tuner_info("error: bandwidth not supported.\n"); + tuner_err("error: bandwidth not supported.\n"); }; priv->bandwidth = bandwidth; } /* Load INIT1, if needed */ - tuner_info("Load init1 firmware, if exists\n"); + tuner_dbg("Load init1 firmware, if exists\n"); type0 = BASE | INIT1; if (priv->ctrl.type == XC2028_FIRM_MTS) type0 |= MTS; @@ -597,9 +608,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (priv->ctrl.type == XC2028_FIRM_MTS) type |= MTS; - tuner_info("Firmware standard to load: %08lx\n", (unsigned long)std); if (priv->firm_type & std) { - tuner_info("Std-specific firmware already loaded.\n"); + tuner_dbg("Std-specific firmware already loaded.\n"); return 0; } @@ -608,7 +618,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, return rc; /* Load SCODE firmware, if exists */ - tuner_info("Trying to load scode 0\n"); + tuner_dbg("Trying to load scode 0\n"); type |= SCODE; rc = load_scode(fe, type, &std, 0); @@ -631,7 +641,7 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) struct xc2028_data *priv = fe->tuner_priv; int frq_lock, signal = 0; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); mutex_lock(&priv->lock); @@ -669,7 +679,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , unsigned char buf[5]; u32 div, offset = 0; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); mutex_lock(&priv->lock); @@ -684,7 +694,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , goto ret; msleep(10); - tuner_info("should set frequency %d kHz)\n", freq / 1000); + tuner_dbg("should set frequency %d kHz)\n", freq / 1000); if (check_firmware(fe, new_mode, std, bandwidth) < 0) goto ret; @@ -721,7 +731,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , priv->frequency = freq; - printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", + tuner_dbg("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", buf[1], buf[2], buf[3], buf[4], freq / 1000000, (freq % 1000000) / 10000); @@ -738,7 +748,7 @@ static int xc2028_set_tv_freq(struct dvb_frontend *fe, { struct xc2028_data *priv = fe->tuner_priv; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV, p->std, BANDWIDTH_8_MHZ /* NOT USED */); @@ -749,11 +759,11 @@ static int xc2028_set_params(struct dvb_frontend *fe, { struct xc2028_data *priv = fe->tuner_priv; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); /* FIXME: Only OFDM implemented */ if (fe->ops.info.type != FE_OFDM) { - tuner_info("DTV type not implemented.\n"); + tuner_err("DTV type not implemented.\n"); return -EINVAL; } @@ -767,7 +777,7 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); priv->count--; @@ -787,7 +797,7 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct xc2028_data *priv = fe->tuner_priv; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); *frequency = priv->frequency; @@ -799,7 +809,7 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) struct xc2028_data *priv = fe->tuner_priv; struct xc2028_ctrl *p = priv_cfg; - tuner_info("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __FUNCTION__); priv->ctrl.type = p->type; @@ -817,8 +827,6 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) if (p->max_len > 0) priv->max_len = p->max_len; - tuner_info("%s OK\n", __FUNCTION__); - return 0; } @@ -845,7 +853,8 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, { struct xc2028_data *priv; - printk(KERN_INFO PREFIX "Xcv2028/3028 init called!\n"); + if (debug) + printk(KERN_DEBUG PREFIX "Xcv2028/3028 init called!\n"); if (NULL == dev) return -ENODEV; -- cgit v1.2.3 From 1414becf15da1701b0c45e9c82b1f120cb676a36 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 15 Nov 2007 10:45:19 -0300 Subject: V4L/DVB (6598): Fix standard name Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index f6695d41356..388884491f4 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -88,7 +88,7 @@ #define V4L2_STD_NICAM_B (1L<<35) #define V4L2_STD_AM (1L<<36) #define V4L2_STD_BTSC (1L<<37) -#define V4L2_STD__EIAJ (1L<<38) +#define V4L2_STD_EIAJ (1L<<38) #define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) #define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) -- cgit v1.2.3 From 0fc0686e64d21a6abded96af2b1a895dfa8b2530 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Tue, 6 Nov 2007 20:02:36 -0300 Subject: V4L/DVB (6600): V4L: videobuf: don't chew up namespace STATE_.*, convert to VIDEOBUF_ s/STATE_NEEDS_INIT/VIDEOBUF_NEEDS_INIT/g s/STATE_PREPARED/VIDEOBUF_PREPARED/g s/STATE_QUEUED/VIDEOBUF_QUEUED/g s/STATE_ACTIVE/VIDEOBUF_ACTIVE/g s/STATE_DONE/VIDEOBUF_DONE/g s/STATE_ERROR/VIDEOBUF_ERROR/g s/STATE_IDLE/VIDEOBUF_IDLE/g Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_fops.c | 8 ++--- drivers/media/common/saa7146_vbi.c | 10 +++--- drivers/media/common/saa7146_video.c | 8 ++--- drivers/media/video/bt8xx/bttv-driver.c | 26 +++++++-------- drivers/media/video/bt8xx/bttv-risc.c | 14 ++++---- drivers/media/video/bt8xx/bttv-vbi.c | 6 ++-- drivers/media/video/cx23885/cx23885-core.c | 18 +++++------ drivers/media/video/cx88/cx88-alsa.c | 2 +- drivers/media/video/cx88/cx88-core.c | 4 +-- drivers/media/video/cx88/cx88-mpeg.c | 14 ++++---- drivers/media/video/cx88/cx88-vbi.c | 10 +++--- drivers/media/video/cx88/cx88-video.c | 22 ++++++------- drivers/media/video/saa7134/saa7134-core.c | 8 ++--- drivers/media/video/saa7134/saa7134-ts.c | 8 ++--- drivers/media/video/saa7134/saa7134-vbi.c | 8 ++--- drivers/media/video/saa7134/saa7134-video.c | 12 +++---- drivers/media/video/videobuf-core.c | 50 ++++++++++++++--------------- drivers/media/video/videobuf-dvb.c | 2 +- drivers/media/video/vivi.c | 24 +++++++------- include/media/videobuf-core.h | 14 ++++---- 20 files changed, 134 insertions(+), 134 deletions(-) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 67d1b1b1b25..b40bf2306fb 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, buf->activate(dev,buf,NULL); } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); } return 0; @@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data) spin_lock_irqsave(&dev->slock,flags); if (q->curr) { DEB_D(("timeout on %p\n", q->curr)); - saa7146_buffer_finish(dev,q,STATE_ERROR); + saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); } /* we don't restart the transfer here like other drivers do. when @@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) } poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || buf->state == STATE_ERROR) { + if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { DEB_D(("poll succeeded!\n")); return POLLIN|POLLRDNORM; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 6103484e444..c32dda973e9 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev, struct saa7146_buf *next) { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); saa7146_set_vbi_capture(dev,buf,next); @@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (buf->vb.size != size) saa7146_dma_free(dev,q,buf); - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (0 != err) return err; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) saa7146_write(dev, MC1, MASK_20); if (vv->vbi_q.curr) { - saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } videobuf_queue_cancel(&fh->vbi_q); @@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) /* this must be += 2, one count for each field */ vv->vbi_fieldcount+=2; vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; - saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } else { DEB_VBI(("dev:%p\n",dev)); } diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index ae36d101006..c31ab480d8e 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev, { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; saa7146_set_capture(dev,buf,next); mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); @@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7146_dma_free(dev,q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct saa7146_format *sfmt; buf->vb.bytesperline = fh->video_fmt.bytesperline; @@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st) /* only finish the buffer if we have one... */ if( NULL != q->curr ) { - saa7146_buffer_finish(dev,q,STATE_DONE); + saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); } saa7146_buffer_next(dev,q,0); diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index db0e4b78e7d..eb2c12eb2fc 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1638,7 +1638,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, dprintk("switch_overlay: enter [new=%p]\n",new); if (new) - new->vb.state = STATE_DONE; + new->vb.state = VIDEOBUF_DONE; spin_lock_irqsave(&btv->s_lock,flags); old = btv->screen; btv->screen = new; @@ -1749,7 +1749,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, } /* alloc risc memory */ - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) goto fail; @@ -1759,7 +1759,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, if (0 != (rc = bttv_buffer_risc(btv,buf))) goto fail; - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -1798,7 +1798,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_fh *fh = q->priv_data; struct bttv *btv = fh->btv; - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue,&btv->capture); if (!btv->curr.frame_irq) { btv->loop_irq |= 1; @@ -3102,8 +3102,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -3699,20 +3699,20 @@ static void bttv_irq_timeout(unsigned long data) bttv_set_dma(btv, 0); /* wake up */ - bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR); - bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR); + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); + bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); /* cancel all outstanding capture / vbi requests */ while (!list_empty(&btv->capture)) { item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = STATE_ERROR; + item->vb.state = VIDEOBUF_ERROR; wake_up(&item->vb.done); } while (!list_empty(&btv->vcapture)) { item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = STATE_ERROR; + item->vb.state = VIDEOBUF_ERROR; wake_up(&item->vb.done); } @@ -3735,7 +3735,7 @@ bttv_irq_wakeup_top(struct bttv *btv) do_gettimeofday(&wakeup->vb.ts); wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = STATE_DONE; + wakeup->vb.state = VIDEOBUF_DONE; wake_up(&wakeup->vb.done); spin_unlock(&btv->s_lock); } @@ -3784,7 +3784,7 @@ bttv_irq_switch_video(struct bttv *btv) } /* wake up finished buffers */ - bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE); + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); spin_unlock(&btv->s_lock); } @@ -3817,7 +3817,7 @@ bttv_irq_switch_vbi(struct bttv *btv) bttv_buffer_activate_vbi(btv, new); bttv_set_dma(btv, 0); - bttv_irq_wakeup_vbi(btv, old, STATE_DONE); + bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); spin_unlock(&btv->s_lock); } diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 58986f1a5f1..e5979f77504 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } int @@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv, if (vbi) { unsigned int crop, vdelay; - vbi->vb.state = STATE_ACTIVE; + vbi->vb.state = VIDEOBUF_ACTIVE; list_del(&vbi->vb.queue); /* VDELAY is start of video, end of VBI capturing. */ @@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv, /* video capture */ if (NULL != set->top && NULL != set->bottom) { if (set->top == set->bottom) { - set->top->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); } else { - set->top->vb.state = STATE_ACTIVE; - set->bottom->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); if (set->bottom->vb.queue.next) @@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->top) { - set->top->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); bttv_apply_geo(btv, &set->top->geo,1); @@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->bottom) { - set->bottom->vb.state = STATE_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->bottom->vb.queue.next) list_del(&set->bottom->vb.queue); bttv_apply_geo(btv, &set->bottom->geo,1); diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 346ce019bdc..b924f05e3b7 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, redo_dma_risc = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; @@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, /* For bttv_buffer_activate_vbi(). */ buf->geo.vdelay = min_vdelay; - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->vb.field = field; dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", vb, &buf->top, &buf->bottom, @@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); dprintk("queue %p\n",vb); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue,&btv->vcapture); if (NULL == btv->cvbi) { fh->btv->loop_irq |= 4; diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 0c9c9af0efb..f205ad6354e 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -378,7 +378,7 @@ static void cx23885_wakeup(struct cx23885_tsport *port, do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } @@ -972,7 +972,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } static int cx23885_start_dma(struct cx23885_tsport *port, @@ -1075,7 +1075,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); cx23885_start_dma(port, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(5, "[%p/%d] restart_queue - first active\n", @@ -1086,7 +1086,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1123,7 +1123,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = port->ts_packet_size; buf->vb.height = port->ts_packet_count; buf->vb.size = size; @@ -1135,7 +1135,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, videobuf_to_dma(&buf->vb)->sglist, buf->vb.width, buf->vb.height); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -1158,7 +1158,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", @@ -1168,7 +1168,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1192,7 +1192,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 40ffd7a5579..8735227f7e4 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; chip->buf = buf; chip->dma_risc = dma; diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 62e8dd24c5f..01e2ac98970 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core, do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 60ac4234d84..339a88a64f5 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -195,7 +195,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); cx8802_start_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] restart_queue - first active\n", @@ -206,7 +206,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(1,"[%p/%d] restart_queue - move to active\n", @@ -242,7 +242,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = dev->ts_packet_size; buf->vb.height = dev->ts_packet_count; buf->vb.size = size; @@ -254,7 +254,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, dma->sglist, buf->vb.width, buf->vb.height, 0); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -276,7 +276,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue,&cx88q->active); cx8802_start_dma(dev, cx88q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] %s - first active\n", @@ -286,7 +286,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&cx88q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", @@ -306,7 +306,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index babb0855640..d96ecfcf393 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); @@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; @@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->vb.width, 0, buf->vb.height); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); cx8800_start_vbi_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] vbi_queue - first active\n", @@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index c84dafbdb99..6d5ea8ce983 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -486,7 +486,7 @@ static int restart_video_queue(struct cx8800_dev *dev, if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); start_video_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first active\n", @@ -496,7 +496,7 @@ static int restart_video_queue(struct cx8800_dev *dev, prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] restart_queue - move to active\n", @@ -553,7 +553,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, init_buffer = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { init_buffer = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; @@ -601,7 +601,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, fh->width, fh->height, fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -625,14 +625,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (!list_empty(&q->queued)) { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); start_video_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", @@ -644,7 +644,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", @@ -652,7 +652,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } @@ -822,8 +822,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -1496,7 +1496,7 @@ static void cx8800_vid_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index fc71843b9dc..76410f5bdcd 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, buf->activate(dev,buf,NULL); } else if (list_empty(&q->queue)) { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; } else { next = list_entry(q->queue.next,struct saa7134_buf, vb.queue); @@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, } } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; } return 0; } @@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data) try to start over with the next one. */ if (q->curr) { dprintk("timeout on %p\n",q->curr); - saa7134_buffer_finish(dev,q,STATE_ERROR); + saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR); } saa7134_buffer_next(dev,q); spin_unlock_irqrestore(&dev->slock,flags); diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 4b63ad3e846..f1b8fcaeb43 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev, { dprintk("buffer_activate [%p]",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; if (NULL == next) @@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa7134_dma_free(q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); saa_writel(SAA7134_RS_CONTROL(5),control); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if ((status & 0x100000) != 0x100000) goto done; } - saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->ts_q); diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 81a2aedeff5..f0d5ed9c2b0 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long control,base; dprintk("buffer_activate [%p]\n",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; task_init(dev,buf,TASK_A); @@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (buf->vb.size != size) saa7134_dma_free(q,buf); - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) goto done; dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; - saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->vbi_q); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 86fe452842b..9c160b2bca3 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -945,7 +945,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ dprintk("buffer_activate buf=%p\n",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; set_size(dev,TASK_A,buf->vb.width,buf->vb.height, @@ -1054,7 +1054,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = fh->width; @@ -1074,7 +1074,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -1421,8 +1421,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -2519,7 +2519,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) goto done; } dev->video_q.curr->vb.field_count = dev->video_fieldcount; - saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->video_q); diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index c8a5cb57963..26d1a500173 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -68,14 +68,14 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) MAGIC_CHECK(vb->magic,MAGIC_BUFFER); add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) { if (non_blocking) { retval = -EAGAIN; break; } set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + if (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) schedule(); set_current_state(TASK_RUNNING); if (intr && signal_pending(current)) { @@ -167,11 +167,11 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } - if (q->bufs[i]->state == STATE_QUEUED) { + if (q->bufs[i]->state == VIDEOBUF_QUEUED) { dprintk(1,"busy: buffer #%d queued\n",i); return 1; } - if (q->bufs[i]->state == STATE_ACTIVE) { + if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { dprintk(1,"busy: buffer #%d avtive\n",i); return 1; } @@ -191,9 +191,9 @@ void videobuf_queue_cancel(struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (q->bufs[i]->state == STATE_QUEUED) { + if (q->bufs[i]->state == VIDEOBUF_QUEUED) { list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; + q->bufs[i]->state = VIDEOBUF_ERROR; } } if (q->irqlock) @@ -259,17 +259,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: + case VIDEOBUF_PREPARED: + case VIDEOBUF_QUEUED: + case VIDEOBUF_ACTIVE: b->flags |= V4L2_BUF_FLAG_QUEUED; break; - case STATE_DONE: - case STATE_ERROR: + case VIDEOBUF_DONE: + case VIDEOBUF_ERROR: b->flags |= V4L2_BUF_FLAG_DONE; break; - case STATE_NEEDS_INIT: - case STATE_IDLE: + case VIDEOBUF_NEEDS_INIT: + case VIDEOBUF_IDLE: /* nothing */ break; } @@ -498,7 +498,7 @@ int videobuf_qbuf(struct videobuf_queue *q, dprintk(1,"qbuf: memory type is wrong.\n"); goto done; } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { dprintk(1,"qbuf: buffer is already queued or active.\n"); goto done; } @@ -525,7 +525,7 @@ int videobuf_qbuf(struct videobuf_queue *q, dprintk(1,"qbuf: buffer length is not enough\n"); goto done; } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + if (VIDEOBUF_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) q->ops->buf_release(q,buf); buf->baddr = b->m.userptr; break; @@ -595,16 +595,16 @@ int videobuf_dqbuf(struct videobuf_queue *q, goto done; } switch (buf->state) { - case STATE_ERROR: + case VIDEOBUF_ERROR: dprintk(1,"dqbuf: state is error\n"); retval = -EIO; CALL(q,sync,q, buf); - buf->state = STATE_IDLE; + buf->state = VIDEOBUF_IDLE; break; - case STATE_DONE: + case VIDEOBUF_DONE: dprintk(1,"dqbuf: state is done\n"); CALL(q,sync,q, buf); - buf->state = STATE_IDLE; + buf->state = VIDEOBUF_IDLE; break; default: dprintk(1,"dqbuf: state invalid\n"); @@ -637,7 +637,7 @@ int videobuf_streamon(struct videobuf_queue *q) if (q->irqlock) spin_lock_irqsave(q->irqlock,flags); list_for_each_entry(buf, &q->stream, stream) - if (buf->state == STATE_PREPARED) + if (buf->state == VIDEOBUF_PREPARED) q->ops->buf_queue(q,buf); if (q->irqlock) spin_unlock_irqrestore(q->irqlock,flags); @@ -704,7 +704,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, retval = videobuf_waiton(q->read_buf,0,0); if (0 == retval) { CALL(q,sync,q,q->read_buf); - if (STATE_ERROR == q->read_buf->state) + if (VIDEOBUF_ERROR == q->read_buf->state) retval = -EIO; else retval = q->read_buf->size; @@ -778,7 +778,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, CALL(q,sync,q,q->read_buf); - if (STATE_ERROR == q->read_buf->state) { + if (VIDEOBUF_ERROR == q->read_buf->state) { /* catch I/O errors */ q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); @@ -931,7 +931,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, break; } - if (q->read_buf->state == STATE_DONE) { + if (q->read_buf->state == VIDEOBUF_DONE) { rc = CALL (q,copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { @@ -999,8 +999,8 @@ unsigned int videobuf_poll_stream(struct file *file, if (0 == rc) { poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) rc = POLLIN|POLLRDNORM; } mutex_unlock(&q->lock); diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 880317e04a0..b73aba65d21 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data) /* feed buffer data to demux */ dma=videobuf_to_dma(buf); - if (buf->state == STATE_DONE) + if (buf->state == VIDEOBUF_DONE) dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 9b54ff9d2e3..fe9784a0cc2 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -370,7 +370,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) (unsigned long)tmpbuf,pos); /* Advice that buffer was filled */ - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; do_gettimeofday(&ts); buf->vb.ts = ts; @@ -522,7 +522,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) /* cancel all outstanding capture / vbi requests */ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); } mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); @@ -543,7 +543,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) vivi_stop_thread(dma_q); vivi_start_thread(dma_q); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first active\n", buf,buf->vb.i); @@ -553,7 +553,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&dma_q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; dprintk(2,"[%p/%d] restart_queue - move to active\n", buf,buf->vb.i); } else { @@ -572,7 +572,7 @@ static void vivi_vid_timeout(unsigned long data) while (!list_empty(&vidq->active)) { buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); } @@ -610,7 +610,7 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) videobuf_waiton(&buf->vb,0,0); videobuf_vmalloc_free(&buf->vb); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } #define norm_maxw() 1024 @@ -644,12 +644,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, init_buffer = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL))) goto fail; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; @@ -670,13 +670,13 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (!list_empty(&vidq->queued)) { dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue); list_add_tail(&buf->vb.queue,&vidq->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&vidq->active)) { list_add_tail(&buf->vb.queue,&vidq->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); @@ -688,13 +688,13 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue,&vidq->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; dprintk(2,"[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { list_add_tail(&buf->vb.queue,&vidq->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 4fd5d0eaa93..567dfe22c07 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -56,13 +56,13 @@ struct videobuf_mapping { }; enum videobuf_state { - STATE_NEEDS_INIT = 0, - STATE_PREPARED = 1, - STATE_QUEUED = 2, - STATE_ACTIVE = 3, - STATE_DONE = 4, - STATE_ERROR = 5, - STATE_IDLE = 6, + VIDEOBUF_NEEDS_INIT = 0, + VIDEOBUF_PREPARED = 1, + VIDEOBUF_QUEUED = 2, + VIDEOBUF_ACTIVE = 3, + VIDEOBUF_DONE = 4, + VIDEOBUF_ERROR = 5, + VIDEOBUF_IDLE = 6, }; struct videobuf_buffer { -- cgit v1.2.3 From d6964aa8d4a418d69da1652121940fabc6b5d591 Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Tue, 6 Nov 2007 20:23:08 -0300 Subject: V4L/DVB (6603): V4L: videobuf: convert streaming and reading to bitfields Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf-core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 567dfe22c07..7aa7a7b64c1 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -162,12 +162,12 @@ struct videobuf_queue { struct videobuf_queue_ops *ops; struct videobuf_qtype_ops *int_ops; + unsigned int streaming:1; + unsigned int reading:1; /* capture via mmap() + ioctl(QBUF/DQBUF) */ - unsigned int streaming; struct list_head stream; /* capture via read() */ - unsigned int reading; unsigned int read_off; struct videobuf_buffer *read_buf; -- cgit v1.2.3 From a82200fb59e7d12a1365199d9fe350bbf74255e4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 15 Nov 2007 11:58:00 -0300 Subject: V4L/DVB (6605): Add a modprobe option to manually select audio standard While there's no public API to define audio standard, adds a hack option for select them. This is needed only for NICAM and A2 firmwares, since AM, BTSC and EAIJ are already properly handled, on firmware version 2.7. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 492181d8de8..371e822fb4c 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -28,6 +28,20 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); +static char audio_std[8]; +module_param_string(audio_std, audio_std, sizeof(audio_std), 0); +MODULE_PARM_DESC(audio_std, + "Audio standard. XC3028 audio decoder explicitly " + "needs to know what audio\n" + "standard is needed for some video standards with audio A2 or NICAM.\n" + "The valid values are:\n" + "A2\n" + "A2/A\n" + "A2/B\n" + "NICAM\n" + "NICAM/A\n" + "NICAM/B\n"); + static LIST_HEAD(xc2028_list); /* struct for storing firmware table */ struct firmware_description { @@ -180,6 +194,24 @@ void dump_firm_type(unsigned int type) printk("SCODE "); } +static v4l2_std_id parse_audio_std_option(void) +{ + if (strcasecmp(audio_std, "A2")) + return V4L2_STD_A2; + if (strcasecmp(audio_std, "A2/A")) + return V4L2_STD_A2_A; + if (strcasecmp(audio_std, "A2/B")) + return V4L2_STD_A2_B; + if (strcasecmp(audio_std, "NICAM")) + return V4L2_STD_NICAM; + if (strcasecmp(audio_std, "NICAM/A")) + return V4L2_STD_NICAM_A; + if (strcasecmp(audio_std, "NICAM/B")) + return V4L2_STD_NICAM_B; + + return 0; +} + static void free_firmware(struct xc2028_data *priv) { int i; @@ -613,6 +645,9 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, return 0; } + /* Add audio hack to std mask */ + std |= parse_audio_std_option(); + rc = load_firmware(fe, type, &std); if (rc < 0) return rc; -- cgit v1.2.3 From ddf12227c3f8413d09c54f85e6642f79312f1430 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 15 Nov 2007 10:01:11 -0300 Subject: V4L/DVB (6606): saa7134: add autodetection support for alternate subids of Hauppauge HVR1110 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 30 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index a14545300e4..29ca16cdb71 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -102,7 +102,7 @@ 101 -> Pinnacle PCTV 310i [11bd:002f] 102 -> Avermedia AVerTV Studio 507 [1461:9715] 103 -> Compro Videomate DVB-T200A -104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6701] +104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6700,0070:6701,0070:6702,0070:6703,0070:6704,0070:6705] 105 -> Terratec Cinergy HT PCMCIA [153b:1172] 106 -> Encore ENLTV [1131:2342,1131:2341,3016:2344] 107 -> Encore ENLTV-FM [1131:230f] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 78d7d7059a9..138cec8bb02 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -4203,12 +4203,42 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1043, .subdevice = 0x4876, .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6700, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6701, .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6702, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6703, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6704, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6705, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, -- cgit v1.2.3 From 993efa7133985597eb48fb486c661010ab08b525 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 15 Nov 2007 10:34:33 -0300 Subject: V4L/DVB (6607): saa7134: add support for reading Hauppauge eeprom Increased size of dev->eedata from 128 to 256, since the Hauppauge data begins at byte 128. This has been tested on boards with smaller eeproms, and caused no problems. Added comments to distinguish between the various versions of the HVR1110. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 33 ++++++++++++++++++++++++++++- drivers/media/video/saa7134/saa7134.h | 2 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 138cec8bb02..533fb02394f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -26,6 +26,7 @@ #include "saa7134-reg.h" #include "saa7134.h" #include +#include /* commly used strings */ static char name_mute[] = "mute"; @@ -4381,6 +4382,34 @@ static void board_flyvideo(struct saa7134_dev *dev) /* ----------------------------------------------------------- */ +static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); + + /* Make sure we support the board model */ + switch (tv.model) { + case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ + case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ + case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ + case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */ + case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ + case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +/* ----------------------------------------------------------- */ + int saa7134_board_init1(struct saa7134_dev *dev) { /* Always print gpio, often manufacturers encode tuner type and other info. */ @@ -4661,13 +4690,15 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110: + hauppauge_eeprom(dev, dev->eedata+0x80); + /* break intentionally omitted */ case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_KWORLD_DVBT_210: case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: - case SAA7134_BOARD_HAUPPAUGE_HVR1110: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 16f4b5ce34d..a531e3c6c94 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -481,7 +481,7 @@ struct saa7134_dev { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; - unsigned char eedata[128]; + unsigned char eedata[256]; /* video overlay */ struct v4l2_framebuffer ovbuf; -- cgit v1.2.3 From 2fc580ffeb551066f769934e3a4717d721d0a559 Mon Sep 17 00:00:00 2001 From: Michel Ludwig Date: Fri, 16 Nov 2007 07:19:35 -0300 Subject: V4L/DVB (6610): Fix a wrong typecast Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 371e822fb4c..c64eae2c7ec 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -311,7 +311,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) id = le64_to_cpu(*(v4l2_std_id *) p); p += sizeof(id); - size = le32_to_cpu(*(v4l2_std_id *) p); + size = le32_to_cpu(*(__u32 *) p); p += sizeof(size); if ((!size) || (size + p > endp)) { -- cgit v1.2.3 From a37b4c9bc87a74ed5003c385eae264fc0acf6b35 Mon Sep 17 00:00:00 2001 From: Michel Ludwig Date: Fri, 16 Nov 2007 07:46:14 -0300 Subject: V4L/DVB (6611): Change xc2028_attach method to make easier for DVB Removes uneeded parameters and adds an structure for passing the parameters This patch is co-authored by Mauro Carvalho Chehab. Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 11 +++++--- drivers/media/video/tuner-xc2028.c | 53 +++++++++++++++++++------------------- drivers/media/video/tuner-xc2028.h | 20 +++++++------- 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 1b0d28a0ca7..e56a4194148 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -336,10 +336,13 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_XC2028: { - int rc=xc2028_attach(&t->fe, t->i2c->adapter, t->i2c->addr, - &c->dev, c->adapter->algo_data, - t->tuner_callback); - if (rc<0) { + struct xc2028_config cfg = { + .i2c_adap = t->i2c->adapter, + .i2c_addr = t->i2c->addr, + .video_dev = c->adapter->algo_data, + .callback = t->tuner_callback, + }; + if (!xc2028_attach(&t->fe, &cfg)) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index c64eae2c7ec..0a2ffe4f38d 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -56,7 +56,6 @@ struct xc2028_data { struct tuner_i2c_props i2c_props; int (*tuner_callback) (void *dev, int command, int arg); - struct device *dev; void *video_dev; int count; __u32 frequency; @@ -240,7 +239,8 @@ static int load_all_firmwares(struct dvb_frontend *fe) tuner_dbg("%s called\n", __FUNCTION__); tuner_info("Reading firmware %s\n", priv->ctrl.fname); - rc = request_firmware(&fw, priv->ctrl.fname, priv->dev); + rc = request_firmware(&fw, priv->ctrl.fname, + &priv->i2c_props.adap->dev); if (rc < 0) { if (rc == -ENOENT) tuner_err("Error: firmware %s not found.\n", @@ -546,8 +546,10 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, tuner_dbg("%s called\n", __FUNCTION__); if (!priv->firm) { - if (!priv->ctrl.fname) + if (!priv->ctrl.fname) { + tuner_info("xc2028/3028 firmware name not set!\n"); return -EINVAL; + } rc = load_all_firmwares(fe); if (rc < 0) @@ -882,53 +884,51 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { }; -int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, - u8 i2c_addr, struct device *dev, void *video_dev, - int (*tuner_callback) (void *dev, int command, int arg)) +void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) { struct xc2028_data *priv; + void *video_dev; if (debug) printk(KERN_DEBUG PREFIX "Xcv2028/3028 init called!\n"); - if (NULL == dev) - return -ENODEV; + if (NULL == cfg->video_dev) + return NULL; - if (NULL == video_dev) - return -ENODEV; - - if (!tuner_callback) { - printk(KERN_ERR PREFIX "No tuner callback!\n"); - return -EINVAL; + if (!fe) { + printk(KERN_ERR PREFIX "No frontend!\n"); + return NULL; } + video_dev = cfg->video_dev; + list_for_each_entry(priv, &xc2028_list, xc2028_list) { - if (priv->dev == dev) - dev = NULL; + if (priv->video_dev == cfg->video_dev) { + video_dev = NULL; + break; + } } - if (dev) { + if (video_dev) { priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - - fe->tuner_priv = priv; + return NULL; priv->bandwidth = BANDWIDTH_6_MHZ; priv->need_load_generic = 1; priv->mode = T_UNINITIALIZED; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->dev = dev; + priv->i2c_props.addr = cfg->i2c_addr; + priv->i2c_props.adap = cfg->i2c_adap; priv->video_dev = video_dev; - priv->tuner_callback = tuner_callback; + priv->tuner_callback = cfg->callback; priv->max_len = 13; - mutex_init(&priv->lock); list_add_tail(&priv->xc2028_list, &xc2028_list); } + + fe->tuner_priv = priv; priv->count++; memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, @@ -936,8 +936,9 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); - return 0; + return fe; } + EXPORT_SYMBOL(xc2028_attach); MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index e04611e653e..a20eeb4935d 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -22,22 +22,22 @@ struct xc2028_ctrl { int max_len; }; +struct xc2028_config { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + void *video_dev; + int (*callback) (void *dev, int command, int arg); +}; + /* xc2028 commands for callback */ #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) -int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, - u8 i2c_addr, struct device *dev, void *video_dev, - int (*tuner_callback) (void *dev, int command, int arg)); - +void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); #else -static inline int xc2028_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, struct device *dev, - void *video_dev, - int (*tuner_callback) (void *dev, int command, - int arg)) +void *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) { printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", __FUNCTION__); -- cgit v1.2.3 From 5403bbae9bfebe1f2df3a022c83e54f70906cefe Mon Sep 17 00:00:00 2001 From: Michel Ludwig Date: Fri, 16 Nov 2007 07:49:49 -0300 Subject: V4L/DVB (6612): Allow RESET_CLK callback and avoids unneeded loading TM5600/TM6000 needs clock reset during firmware load. This patch adds the capability of caling a callback method for this. Also, avoids uneeded firmware loads. Signed-off-by: Michel Ludwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 0a2ffe4f38d..89e6e64786e 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -461,6 +461,23 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, } continue; } + if (size >= 0xff00) { + switch (size) { + case 0xff00: + rc = priv->tuner_callback(priv->video_dev, + XC2028_RESET_CLK, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + default: + tuner_info("Invalid RESET code %d\n", + size & 0x7f); + return -EINVAL; + + } + } /* Checks for a sleep command */ if (size & 0x8000) { @@ -627,6 +644,9 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, priv->bandwidth = bandwidth; } + if (!change_digital_bandwidth && priv->mode == T_DIGITAL_TV) + return 0; + /* Load INIT1, if needed */ tuner_dbg("Load init1 firmware, if exists\n"); type0 = BASE | INIT1; -- cgit v1.2.3 From 2d4c0ac60dbcdee83da5bdebc661c2c145938d8a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 16 Nov 2007 09:43:19 -0300 Subject: V4L/DVB (6613): Fix: add a missing continue statement Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 89e6e64786e..748f9ad08b8 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -477,6 +477,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, return -EINVAL; } + continue; } /* Checks for a sleep command */ -- cgit v1.2.3 From ef8c1888b32132ae48553a8ce00d5858ec3e9b51 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 16 Nov 2007 16:28:21 -0300 Subject: V4L/DVB (6614): Fix driver for i386 architectures Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 14 +++++++------- drivers/media/video/tuner-xc2028.c | 10 ++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index 388884491f4..a9e2e0562d9 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -82,13 +82,13 @@ /* Audio types */ -#define V4L2_STD_A2_A (1L<<32) -#define V4L2_STD_A2_B (1L<<33) -#define V4L2_STD_NICAM_A (1L<<34) -#define V4L2_STD_NICAM_B (1L<<35) -#define V4L2_STD_AM (1L<<36) -#define V4L2_STD_BTSC (1L<<37) -#define V4L2_STD_EIAJ (1L<<38) +#define V4L2_STD_A2_A (1LL<<32) +#define V4L2_STD_A2_B (1LL<<33) +#define V4L2_STD_NICAM_A (1LL<<34) +#define V4L2_STD_NICAM_B (1LL<<35) +#define V4L2_STD_AM (1LL<<36) +#define V4L2_STD_BTSC (1LL<<37) +#define V4L2_STD_EIAJ (1LL<<38) #define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) #define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 748f9ad08b8..d23b33a1f69 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -22,6 +22,7 @@ #include #include "dvb_frontend.h" + #define PREFIX "xc2028" static int debug; @@ -193,7 +194,7 @@ void dump_firm_type(unsigned int type) printk("SCODE "); } -static v4l2_std_id parse_audio_std_option(void) +static v4l2_std_id parse_audio_std_option(void) { if (strcasecmp(audio_std, "A2")) return V4L2_STD_A2; @@ -317,9 +318,10 @@ static int load_all_firmwares(struct dvb_frontend *fe) if ((!size) || (size + p > endp)) { tuner_err("Firmware type "); dump_firm_type(type); - printk("(%x), id %lx is corrupted " - "(size=%ld, expected %d)\n", - type, (unsigned long)id, endp - p, size); + printk("(%x), id %llx is corrupted " + "(size=%d, expected %d)\n", + type, id, + (unsigned)(endp - p), size); goto corrupt; } -- cgit v1.2.3 From 13d97010ed0850fd7803563a2b9d92a56bb4aa35 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 19 Nov 2007 22:48:16 -0300 Subject: V4L/DVB (6616): drivers/media/radio: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index d69412f587f..246422b4926 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -58,10 +58,10 @@ static int initmute = 1; static int radio_nr = -1; module_param(io, int, 0444); -MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " "probing is disabled or fails. The most common I/O ports are: 0x20c " "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " - " work for the combined sound/radiocard)."); + "work for the combined sound/radiocard)."); module_param(probe, bool, 0444); MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " -- cgit v1.2.3 From ac9bb7f5167d53207893a783a2f722cd6e6ed78f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 20 Nov 2007 09:00:35 -0300 Subject: V4L/DVB (6617): drivers/media/video: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-vbi.c | 2 +- drivers/media/video/meye.c | 2 +- drivers/media/video/saa7134/saa7134-input.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index ced13febed8..6828f59b9d8 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client) fsc/1000000,fsc%1000000); v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i , vactive %i, vblank656 %i, src_dec %i," + "vblank %i, vactive %i, vblank656 %i, src_dec %i, " "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," " sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index c3116329043..3d51fa0a52b 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -2023,7 +2023,7 @@ static int __init meye_init(void) if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)" + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " "for capture\n", gbuffers, gbufsize / 1024, gbuffers * gbufsize / 1024); diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 3abaa1b8ac9..a485185357c 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -49,7 +49,7 @@ module_param(repeat_delay, int, 0644); MODULE_PARM_DESC(repeat_delay, "delay before key repeat started"); static int repeat_period = 33; module_param(repeat_period, int, 0644); -MODULE_PARM_DESC(repeat_period, "repeat period between" +MODULE_PARM_DESC(repeat_period, "repeat period between " "keypresses when key is down"); #define dprintk(fmt, arg...) if (ir_debug) \ -- cgit v1.2.3 From 11645cc370c1af0f6bc9ef7440d452def9580790 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 19 Nov 2007 22:48:15 -0300 Subject: V4L/DVB (6618): drivers/media/dvb: Add missing "space" Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ves1820.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 60433b5011f..8791701c8f2 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("ves1820: %s(): writereg error (reg == 0x%02x," + printk("ves1820: %s(): writereg error (reg == 0x%02x, " "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; @@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("ves1820: %s(): readreg error (reg == 0x%02x," + printk("ves1820: %s(): readreg error (reg == 0x%02x, " "ret == %i)\n", __FUNCTION__, reg, ret); return b1[0]; -- cgit v1.2.3 From 122d15888a8aa95fb6ca32eb1307c3e3337f1a38 Mon Sep 17 00:00:00 2001 From: Aidan Thornton Date: Tue, 20 Nov 2007 15:25:08 -0300 Subject: V4L/DVB (6619): Use MTS firmware for the HVR-900 The HVR-900 requires the MTS version of the xc3028 firmware in order to get any sound. The below patch selects this firmware variant on HVR-900 cards, as well as splitting the HVR-950 into its own entry (since I don't know if it uses the MTS variant and it will have to be split off eventually anyway). Signed-off-by: Aidan Thornton Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 3 ++- drivers/media/video/em28xx/em28xx-cards.c | 29 +++++++++++++++++++++++++++-- drivers/media/video/em28xx/em28xx.h | 2 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index f809834af12..94b53bd7130 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -8,9 +8,10 @@ 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) 9 -> Pinnacle Dazzle DVC 90 (em2820/em2840) [2304:0207] - 10 -> Hauppauge WinTV HVR 900/950 (em2880) + 10 -> Hauppauge WinTV HVR 900 (em2880) 11 -> Terratec Hybrid XS (em2880) 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) 15 -> V-Gear PocketTV (em2800) + 16 -> Hauppauge WinTV HVR 950 (em2880) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index fd64058a04e..c40b9d9b307 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -149,7 +149,29 @@ struct em28xx_board em28xx_boards[] = { }}, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { - .name = "Hauppauge WinTV HVR 900/950", + .name = "Hauppauge WinTV HVR 900", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .has_tuner = 1, + .xc2028_type = XC2028_FIRM_MTS, + .decoder = EM28XX_TVP5150, + .input = {{ + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + },{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + }}, + }, + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { + .name = "Hauppauge WinTV HVR 950", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, @@ -376,7 +398,7 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, - { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, @@ -404,6 +426,7 @@ void em28xx_pre_card_setup(struct em28xx *dev) switch(dev->model){ case EM2880_BOARD_TERRATEC_PRODIGY_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_TERRATEC_HYBRID_XS: /* reset through GPIO? */ em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); @@ -453,6 +476,7 @@ static void em28xx_config_tuner (struct em28xx *dev) ctl.fname = XC2028_DEFAULT_FIRMWARE; ctl.max_len = 64; + ctl.type = em28xx_boards[dev->model].xc2028_type; xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; @@ -574,6 +598,7 @@ void em28xx_card_setup(struct em28xx *dev) switch (dev->model) { case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: { struct tveeprom tv; #ifdef CONFIG_MODULES diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 8d045867dac..db82b51c85f 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -48,6 +48,7 @@ #define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 #define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 #define EM2800_BOARD_VGEAR_POCKETTV 15 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 #define UNSET -1 @@ -177,6 +178,7 @@ struct em28xx_board { unsigned int has_msp34xx:1; enum em28xx_decoder decoder; + int xc2028_type; struct em28xx_input input[MAX_EM28XX_INPUT]; }; -- cgit v1.2.3 From 5efab70958186d2bd63ab27b9465fce202352143 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Nov 2007 14:15:34 -0300 Subject: V4L/DVB (6620): kconfig: VIDEO_SAA7134 must select VIDEO_TVEEPROM The ability to read Hauppauge eeprom's was recently added to saa7134, so we must build the tveeprom module. Thanks to Matthias Schwarzott for pointing this out. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 3aa8cb2b860..8cb79a67216 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -4,6 +4,7 @@ config VIDEO_SAA7134 select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER + select VIDEO_TVEEPROM select CRC32 ---help--- This is a video4linux driver for Philips SAA713x based -- cgit v1.2.3 From 3b0c453aa78be253b4414cd337c9975f91e2c894 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 18 Nov 2007 14:15:42 -0300 Subject: V4L/DVB (6621): tda827x: fix NULL pointer dereference during tda827x_probe_version Fix the following oops: [ 750.807586] CPU: 1 [ 750.807587] EIP: 0060:[] Tainted: P VLI [ 750.807589] EFLAGS: 00010296 (2.6.22-14-generic #1) [ 750.807599] EIP is at tda827x_probe_version+0xc3/0x130 [tda827x] [ 750.807603] eax: 00000000 ebx: f5a45a00 ecx: 00000000 edx: 00000001 [ 750.807607] esi: f9de05ac edi: e9b897e0 ebp: ed8015ac esp: ed735f58 [ 750.807611] ds: 007b es: 007b fs: 00d8 gs: 0000 ss: 0068 [ 750.807615] Process kdvb-fe-1 (pid: 10662, ti=ed734000 task=d3b76530 task.ti=ed734000) [ 750.807618] Stack: f9e23972 00000038 ed735fd0 00010060 41ae0001 ed735f73 88b89608 e9b89608 [ 750.807629] e9b89608 ed801400 f9dde338 e9b89608 f9b2a46b 000000ae 00000a18 d3b76640 [ 750.807639] fffffffc f9b2bad6 00000003 f4433e68 e962b8c0 f4433e64 00000292 ed735fd0 [ 750.807649] Call Trace: [ 750.807653] [] tda10046_init+0x2d2/0x6c0 [tda1004x] [ 750.807700] [] tda827x_initial_init+0x8/0x20 [tda827x] [ 750.807713] [] dvb_frontend_init+0x2b/0x60 [dvb_core] [ 750.807745] [] dvb_frontend_thread+0x66/0x2f0 [dvb_core] [ 750.807780] [complete+64/96] complete+0x40/0x60 [ 750.807805] [] dvb_frontend_thread+0x0/0x2f0 [dvb_core] [ 750.807822] [kthread+66/112] kthread+0x42/0x70 [ 750.807828] [kthread+0/112] kthread+0x0/0x70 [ 750.807841] [kernel_thread_helper+7/16] kernel_thread_helper+0x7/0x10 [ 750.807869] ======================= [ 750.807872] Code: 8b 74 24 20 8b 7c 24 24 83 c4 28 c3 8b 0d 00 0c de f9 85 c9 75 42 be e0 04 de f9 81 c7 0c 01 00 00 b9 33 00 00 00 f3 a5 8b 43 08 40 14 50 e3 dd f9 8b 5c 24 1c 31 c0 8b 74 24 20 8b 7c 24 24 [ 750.807925] EIP: [] tda827x_probe_version+0xc3/0x130 [tda827x] SS:ESP 0068:ed735f58 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda827x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 8329d33b517..50adfb5395e 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -796,11 +796,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe) dprintk("tda827x tuner found\n"); fe->ops.tuner_ops.init = tda827x_init; fe->ops.tuner_ops.sleep = tda827xo_sleep; - priv->cfg->agcf = tda827xo_agcf; + if (priv->cfg) + priv->cfg->agcf = tda827xo_agcf; } else { dprintk("tda827xa tuner found\n"); memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); - priv->cfg->agcf = tda827xa_agcf; + if (priv->cfg) + priv->cfg->agcf = tda827xa_agcf; } return 0; } -- cgit v1.2.3 From 255c1887ccca6cde4a2eac231623b925bf621540 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Nov 2007 14:40:25 -0300 Subject: V4L/DVB (6622): tda827x: prevent possible NULL pointer dereference in tda827xa_lna_gain If tda827x_config hasn't been defined, exit the function. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda827x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 50adfb5395e..229b11987a5 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -556,6 +556,11 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, .buf = buf, .len = sizeof(buf) }; + if (NULL == priv->cfg) { + dprintk("tda827x_config not defined, cannot set LNA gain!\n"); + return; + } + if (priv->cfg->config) { if (high) dprintk("setting LNA to high gain\n"); -- cgit v1.2.3 From 166fb6b4721f9dd8eca3755517671154aa1eaaba Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 21 Nov 2007 19:55:52 -0300 Subject: V4L/DVB (6623): remove saa7134-oss The saa7134-oss is deprecated for quite some time, it's the only remaining OSS user outside of sound/oss/, and considering how few and what kind of soundcards are left supported by OSS I hardly see any use cases left. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/Kconfig | 12 - drivers/media/video/saa7134/Makefile | 1 - drivers/media/video/saa7134/saa7134-alsa.c | 16 +- drivers/media/video/saa7134/saa7134-oss.c | 1046 ---------------------------- 4 files changed, 3 insertions(+), 1072 deletions(-) delete mode 100644 drivers/media/video/saa7134/saa7134-oss.c diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 8cb79a67216..96bc3b1298a 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -24,18 +24,6 @@ config VIDEO_SAA7134_ALSA To compile this driver as a module, choose M here: the module will be called saa7134-alsa. -config VIDEO_SAA7134_OSS - tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)" - depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA - ---help--- - This is a video4linux driver for direct (DMA) audio in - Philips SAA713x based TV cards using OSS - - This is deprecated in favor of the ALSA module - - To compile this driver as a module, choose M here: the - module will be called saa7134-oss. - config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index c85c8a8ec36..9aff937ba7a 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ saa6752hs.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o -obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 4878f306778..ba2531034a9 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -1077,24 +1077,14 @@ static int saa7134_alsa_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; - if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { - saa7134_dmasound_init = alsa_device_init; - saa7134_dmasound_exit = alsa_device_exit; - } else { - printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n"); - return -EBUSY; - } + saa7134_dmasound_init = alsa_device_init; + saa7134_dmasound_exit = alsa_device_exit; printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); - if (dev->dmasound.priv_data == NULL) { - alsa_device_init(dev); - } else { - printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name); - return -EBUSY; - } + alsa_device_init(dev); } if (dev == NULL) diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c deleted file mode 100644 index aedf04653e0..00000000000 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * oss dsp interface - * - * (c) 2001,02 Gerd Knorr [SuSE Labs] - * 2005 conversion to standalone module: - * Ricardo Cerqueira - * - * 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 - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "saa7134-reg.h" -#include "saa7134.h" - -/* ------------------------------------------------------------------ */ - -static unsigned int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [oss]"); - -static unsigned int rate = 0; -module_param(rate, int, 0444); -MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)"); - -static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s)."); -module_param_array(dsp_nr, int, NULL, 0444); - -static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s)."); -module_param_array(mixer_nr, int, NULL, 0444); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) - - -/* ------------------------------------------------------------------ */ - -static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) -{ - if (blksize < 0x100) - blksize = 0x100; - if (blksize > 0x10000) - blksize = 0x10000; - - if (blocks < 2) - blocks = 2; - if ((blksize * blocks) > 1024*1024) - blocks = 1024*1024 / blksize; - - dev->dmasound.blocks = blocks; - dev->dmasound.blksize = blksize; - dev->dmasound.bufsize = blksize * blocks; - - dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", - blocks,blksize,blksize * blocks / 1024); - return 0; -} - -static int dsp_buffer_init(struct saa7134_dev *dev) -{ - int err; - - BUG_ON(!dev->dmasound.bufsize); - videobuf_dma_init(&dev->dmasound.dma); - err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, - (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); - if (0 != err) - return err; - return 0; -} - -static int dsp_buffer_free(struct saa7134_dev *dev) -{ - BUG_ON(!dev->dmasound.blksize); - videobuf_dma_free(&dev->dmasound.dma); - dev->dmasound.blocks = 0; - dev->dmasound.blksize = 0; - dev->dmasound.bufsize = 0; - return 0; -} - -static void dsp_dma_start(struct saa7134_dev *dev) -{ - dev->dmasound.dma_blk = 0; - dev->dmasound.dma_running = 1; - saa7134_set_dmabits(dev); -} - -static void dsp_dma_stop(struct saa7134_dev *dev) -{ - dev->dmasound.dma_blk = -1; - dev->dmasound.dma_running = 0; - saa7134_set_dmabits(dev); -} - -static int dsp_rec_start(struct saa7134_dev *dev) -{ - int err, bswap, sign; - u32 fmt, control; - unsigned long flags; - - /* prepare buffer */ - if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma))) - return err; - if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) - goto fail1; - if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, - dev->dmasound.dma.sglist, - dev->dmasound.dma.sglen, - 0))) - goto fail2; - - /* sample format */ - switch (dev->dmasound.afmt) { - case AFMT_U8: - case AFMT_S8: fmt = 0x00; break; - case AFMT_U16_LE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_S16_BE: fmt = 0x01; break; - default: - err = -EINVAL; - goto fail2; - } - - switch (dev->dmasound.afmt) { - case AFMT_S8: - case AFMT_S16_LE: - case AFMT_S16_BE: sign = 1; break; - default: sign = 0; break; - } - - switch (dev->dmasound.afmt) { - case AFMT_U16_BE: - case AFMT_S16_BE: bswap = 1; break; - default: bswap = 0; break; - } - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - if (1 == dev->dmasound.channels) - fmt |= (1 << 3); - if (2 == dev->dmasound.channels) - fmt |= (3 << 3); - if (sign) - fmt |= 0x04; - fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80; - - saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); - saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); - saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); - saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); - - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (1 == dev->dmasound.channels) - fmt |= (1 << 4); - if (2 == dev->dmasound.channels) - fmt |= (2 << 4); - if (!sign) - fmt |= 0x04; - saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4); - saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); - break; - } - dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", - dev->dmasound.afmt, dev->dmasound.channels, fmt, - bswap ? 'b' : '-'); - - /* dma: setup channel 6 (= AUDIO) */ - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (dev->dmasound.pt.dma >> 12); - if (bswap) - control |= SAA7134_RS_CONTROL_BSWAP; - saa_writel(SAA7134_RS_BA1(6),0); - saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); - saa_writel(SAA7134_RS_PITCH(6),0); - saa_writel(SAA7134_RS_CONTROL(6),control); - - /* start dma */ - dev->dmasound.recording_on = 1; - spin_lock_irqsave(&dev->slock,flags); - dsp_dma_start(dev); - spin_unlock_irqrestore(&dev->slock,flags); - return 0; - - fail2: - saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); - fail1: - videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma); - return err; -} - -static int dsp_rec_stop(struct saa7134_dev *dev) -{ - unsigned long flags; - - dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk); - - /* stop dma */ - dev->dmasound.recording_on = 0; - spin_lock_irqsave(&dev->slock,flags); - dsp_dma_stop(dev); - spin_unlock_irqrestore(&dev->slock,flags); - - /* unlock buffer */ - saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); - videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma); - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int dsp_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct saa7134_dev *dev; - int err; - - list_for_each_entry(dev, &saa7134_devlist, devlist) - if (dev->dmasound.minor_dsp == minor) - goto found; - return -ENODEV; - found: - - mutex_lock(&dev->dmasound.lock); - err = -EBUSY; - if (dev->dmasound.users_dsp) - goto fail1; - dev->dmasound.users_dsp++; - file->private_data = dev; - - dev->dmasound.afmt = AFMT_U8; - dev->dmasound.channels = 1; - dev->dmasound.read_count = 0; - dev->dmasound.read_offset = 0; - dsp_buffer_conf(dev,PAGE_SIZE,64); - err = dsp_buffer_init(dev); - if (0 != err) - goto fail2; - - mutex_unlock(&dev->dmasound.lock); - return 0; - - fail2: - dev->dmasound.users_dsp--; - fail1: - mutex_unlock(&dev->dmasound.lock); - return err; -} - -static int dsp_release(struct inode *inode, struct file *file) -{ - struct saa7134_dev *dev = file->private_data; - - mutex_lock(&dev->dmasound.lock); - if (dev->dmasound.recording_on) - dsp_rec_stop(dev); - dsp_buffer_free(dev); - dev->dmasound.users_dsp--; - file->private_data = NULL; - mutex_unlock(&dev->dmasound.lock); - return 0; -} - -static ssize_t dsp_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct saa7134_dev *dev = file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned int bytes; - unsigned long flags; - int err,ret = 0; - - add_wait_queue(&dev->dmasound.wq, &wait); - mutex_lock(&dev->dmasound.lock); - while (count > 0) { - /* wait for data if needed */ - if (0 == dev->dmasound.read_count) { - if (!dev->dmasound.recording_on) { - err = dsp_rec_start(dev); - if (err < 0) { - if (0 == ret) - ret = err; - break; - } - } - if (dev->dmasound.recording_on && - !dev->dmasound.dma_running) { - /* recover from overruns */ - spin_lock_irqsave(&dev->slock,flags); - dsp_dma_start(dev); - spin_unlock_irqrestore(&dev->slock,flags); - } - if (file->f_flags & O_NONBLOCK) { - if (0 == ret) - ret = -EAGAIN; - break; - } - mutex_unlock(&dev->dmasound.lock); - set_current_state(TASK_INTERRUPTIBLE); - if (0 == dev->dmasound.read_count) - schedule(); - set_current_state(TASK_RUNNING); - mutex_lock(&dev->dmasound.lock); - if (signal_pending(current)) { - if (0 == ret) - ret = -EINTR; - break; - } - } - - /* copy data to userspace */ - bytes = count; - if (bytes > dev->dmasound.read_count) - bytes = dev->dmasound.read_count; - if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset) - bytes = dev->dmasound.bufsize - dev->dmasound.read_offset; - if (copy_to_user(buffer + ret, - dev->dmasound.dma.vmalloc + dev->dmasound.read_offset, - bytes)) { - if (0 == ret) - ret = -EFAULT; - break; - } - - ret += bytes; - count -= bytes; - dev->dmasound.read_count -= bytes; - dev->dmasound.read_offset += bytes; - if (dev->dmasound.read_offset == dev->dmasound.bufsize) - dev->dmasound.read_offset = 0; - } - mutex_unlock(&dev->dmasound.lock); - remove_wait_queue(&dev->dmasound.wq, &wait); - return ret; -} - -static ssize_t dsp_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static const char *osspcm_ioctls[] = { - "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", - "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", - "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", - "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", - "SETDUPLEX", "GETODELAY" -}; -#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls) - -static void saa7134_oss_print_ioctl(char *name, unsigned int cmd) -{ - char *dir; - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "??"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'P': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? - osspcm_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'M': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - break; - default: - printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - } -} - -static int dsp_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct saa7134_dev *dev = file->private_data; - void __user *argp = (void __user *) arg; - int __user *p = argp; - int val = 0; - - if (debug > 1) - saa7134_oss_print_ioctl(dev->name,cmd); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - case SNDCTL_DSP_GETCAPS: - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - /* fall through */ - case SOUND_PCM_READ_RATE: - return put_user(dev->dmasound.rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - mutex_lock(&dev->dmasound.lock); - dev->dmasound.channels = val ? 2 : 1; - if (dev->dmasound.recording_on) { - dsp_rec_stop(dev); - dsp_rec_start(dev); - } - mutex_unlock(&dev->dmasound.lock); - return put_user(dev->dmasound.channels-1, p); - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2) - return -EINVAL; - mutex_lock(&dev->dmasound.lock); - dev->dmasound.channels = val; - if (dev->dmasound.recording_on) { - dsp_rec_stop(dev); - dsp_rec_start(dev); - } - mutex_unlock(&dev->dmasound.lock); - /* fall through */ - case SOUND_PCM_READ_CHANNELS: - return put_user(dev->dmasound.channels, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_U8 | AFMT_S8 | - AFMT_U16_LE | AFMT_U16_BE | - AFMT_S16_LE | AFMT_S16_BE, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ - if (get_user(val, p)) - return -EFAULT; - switch (val) { - case AFMT_QUERY: - /* nothing to do */ - break; - case AFMT_U8: - case AFMT_S8: - case AFMT_U16_LE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_S16_BE: - mutex_lock(&dev->dmasound.lock); - dev->dmasound.afmt = val; - if (dev->dmasound.recording_on) { - dsp_rec_stop(dev); - dsp_rec_start(dev); - } - mutex_unlock(&dev->dmasound.lock); - return put_user(dev->dmasound.afmt, p); - default: - return -EINVAL; - } - - case SOUND_PCM_READ_BITS: - switch (dev->dmasound.afmt) { - case AFMT_U8: - case AFMT_S8: - return put_user(8, p); - case AFMT_U16_LE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_S16_BE: - return put_user(16, p); - default: - return -EINVAL; - } - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_RESET: - mutex_lock(&dev->dmasound.lock); - if (dev->dmasound.recording_on) - dsp_rec_stop(dev); - mutex_unlock(&dev->dmasound.lock); - return 0; - case SNDCTL_DSP_GETBLKSIZE: - return put_user(dev->dmasound.blksize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (dev->dmasound.recording_on) - return -EBUSY; - dsp_buffer_free(dev); - /* used to be arg >> 16 instead of val >> 16; fixed */ - dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff); - dsp_buffer_init(dev); - return 0; - - case SNDCTL_DSP_SYNC: - /* NOP */ - return 0; - - case SNDCTL_DSP_GETISPACE: - { - audio_buf_info info; - info.fragsize = dev->dmasound.blksize; - info.fragstotal = dev->dmasound.blocks; - info.bytes = dev->dmasound.read_count; - info.fragments = info.bytes / info.fragsize; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - default: - return -EINVAL; - } -} - -static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) -{ - struct saa7134_dev *dev = file->private_data; - unsigned int mask = 0; - - poll_wait(file, &dev->dmasound.wq, wait); - - if (0 == dev->dmasound.read_count) { - mutex_lock(&dev->dmasound.lock); - if (!dev->dmasound.recording_on) - dsp_rec_start(dev); - mutex_unlock(&dev->dmasound.lock); - } else - mask |= (POLLIN | POLLRDNORM); - return mask; -} - -const struct file_operations saa7134_dsp_fops = { - .owner = THIS_MODULE, - .open = dsp_open, - .release = dsp_release, - .read = dsp_read, - .write = dsp_write, - .ioctl = dsp_ioctl, - .poll = dsp_poll, - .llseek = no_llseek, -}; - -/* ------------------------------------------------------------------ */ - -static int -mixer_recsrc_7134(struct saa7134_dev *dev) -{ - int analog_io,rate; - - switch (dev->dmasound.input) { - case TV: - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); - break; - case LINE1: - case LINE2: - case LINE2_LEFT: - analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08; - rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03; - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); - break; - } - return 0; -} - -static int -mixer_recsrc_7133(struct saa7134_dev *dev) -{ - u32 anabar, xbarin; - - xbarin = 0x03; // adc - anabar = 0; - switch (dev->dmasound.input) { - case TV: - xbarin = 0; // Demodulator - anabar = 2; // DACs - break; - case LINE1: - anabar = 0; // aux1, aux1 - break; - case LINE2: - case LINE2_LEFT: - anabar = 9; // aux2, aux2 - break; - } - /* output xbar always main channel */ - saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10); - saa_dsp_writel(dev, 0x464 >> 2, xbarin); - saa_writel(0x594 >> 2, anabar); - - return 0; -} - -static int -mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src) -{ - static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" }; - - dev->dmasound.count++; - dev->dmasound.input = src; - dprintk("mixer input = %s\n",iname[dev->dmasound.input]); - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - mixer_recsrc_7134(dev); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - mixer_recsrc_7133(dev); - break; - } - return 0; -} - -static int -mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) -{ - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - switch (src) { - case TV: - /* nothing */ - break; - case LINE1: - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, - (100 == level) ? 0x00 : 0x10); - break; - case LINE2: - case LINE2_LEFT: - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, - (100 == level) ? 0x00 : 0x20); - break; - } - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - /* nothing */ - break; - } - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int mixer_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct saa7134_dev *dev; - - list_for_each_entry(dev, &saa7134_devlist, devlist) - if (dev->dmasound.minor_mixer == minor) { - file->private_data = dev; - return 0; - } - return -ENODEV; -} - -static int mixer_release(struct inode *inode, struct file *file) -{ - file->private_data = NULL; - return 0; -} - -static int mixer_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct saa7134_dev *dev = file->private_data; - enum saa7134_audio_in input; - int val,ret; - void __user *argp = (void __user *) arg; - int __user *p = argp; - - if (debug > 1) - saa7134_oss_print_ioctl(dev->name,cmd); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - case SOUND_MIXER_INFO: - { - mixer_info info; - memset(&info,0,sizeof(info)); - strlcpy(info.id, "TV audio", sizeof(info.id)); - strlcpy(info.name, dev->name, sizeof(info.name)); - info.modify_counter = dev->dmasound.count; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - case SOUND_OLD_MIXER_INFO: - { - _old_mixer_info info; - memset(&info,0,sizeof(info)); - strlcpy(info.id, "TV audio", sizeof(info.id)); - strlcpy(info.name, dev->name, sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - case MIXER_READ(SOUND_MIXER_CAPS): - return put_user(SOUND_CAP_EXCL_INPUT, p); - case MIXER_READ(SOUND_MIXER_STEREODEVS): - return put_user(0, p); - case MIXER_READ(SOUND_MIXER_RECMASK): - case MIXER_READ(SOUND_MIXER_DEVMASK): - val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; - if (32000 == dev->dmasound.rate) - val |= SOUND_MASK_VIDEO; - return put_user(val, p); - - case MIXER_WRITE(SOUND_MIXER_RECSRC): - if (get_user(val, p)) - return -EFAULT; - input = dev->dmasound.input; - if (32000 == dev->dmasound.rate && - val & SOUND_MASK_VIDEO && dev->dmasound.input != TV) - input = TV; - if (val & SOUND_MASK_LINE1 && dev->dmasound.input != LINE1) - input = LINE1; - if (val & SOUND_MASK_LINE2 && dev->dmasound.input != LINE2) - input = LINE2; - if (input != dev->dmasound.input) - mixer_recsrc(dev,input); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_RECSRC): - switch (dev->dmasound.input) { - case TV: ret = SOUND_MASK_VIDEO; break; - case LINE1: ret = SOUND_MASK_LINE1; break; - case LINE2: ret = SOUND_MASK_LINE2; break; - default: ret = 0; - } - return put_user(ret, p); - - case MIXER_WRITE(SOUND_MIXER_VIDEO): - case MIXER_READ(SOUND_MIXER_VIDEO): - if (32000 != dev->dmasound.rate) - return -EINVAL; - return put_user(100 | 100 << 8, p); - - case MIXER_WRITE(SOUND_MIXER_LINE1): - if (get_user(val, p)) - return -EFAULT; - val &= 0xff; - val = (val <= 50) ? 50 : 100; - dev->dmasound.line1 = val; - mixer_level(dev,LINE1,dev->dmasound.line1); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_LINE1): - return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p); - - case MIXER_WRITE(SOUND_MIXER_LINE2): - if (get_user(val, p)) - return -EFAULT; - val &= 0xff; - val = (val <= 50) ? 50 : 100; - dev->dmasound.line2 = val; - mixer_level(dev,LINE2,dev->dmasound.line2); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_LINE2): - return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p); - - default: - return -EINVAL; - } -} - -const struct file_operations saa7134_mixer_fops = { - .owner = THIS_MODULE, - .open = mixer_open, - .release = mixer_release, - .ioctl = mixer_ioctl, - .llseek = no_llseek, -}; - -/* ------------------------------------------------------------------ */ - -static irqreturn_t saa7134_oss_irq(int irq, void *dev_id) -{ - struct saa7134_dmasound *dmasound = dev_id; - struct saa7134_dev *dev = dmasound->priv_data; - unsigned long report, status; - int loop, handled = 0; - - for (loop = 0; loop < 10; loop++) { - report = saa_readl(SAA7134_IRQ_REPORT); - status = saa_readl(SAA7134_IRQ_STATUS); - - if (report & SAA7134_IRQ_REPORT_DONE_RA3) { - handled = 1; - saa_writel(SAA7134_IRQ_REPORT,report); - saa7134_irq_oss_done(dev, status); - } else { - goto out; - } - } - - if (loop == 10) { - dprintk("error! looping IRQ!"); - } -out: - return IRQ_RETVAL(handled); -} - -int saa7134_oss_init1(struct saa7134_dev *dev) -{ - - if ((request_irq(dev->pci->irq, saa7134_oss_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, - (void*) &dev->dmasound)) < 0) - return -1; - - /* general */ - mutex_init(&dev->dmasound.lock); - init_waitqueue_head(&dev->dmasound.wq); - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa_writel(0x588 >> 2, 0x00000fff); - saa_writel(0x58c >> 2, 0x00543210); - saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb); - break; - } - - /* dsp */ - dev->dmasound.rate = 32000; - if (rate) - dev->dmasound.rate = rate; - dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000; - - /* mixer */ - dev->dmasound.line1 = 50; - dev->dmasound.line2 = 50; - mixer_level(dev,LINE1,dev->dmasound.line1); - mixer_level(dev,LINE2,dev->dmasound.line2); - mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2); - - return 0; -} - -int saa7134_oss_fini(struct saa7134_dev *dev) -{ - /* nothing */ - return 0; -} - -void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) -{ - int next_blk, reg = 0; - - spin_lock(&dev->slock); - if (UNSET == dev->dmasound.dma_blk) { - dprintk("irq: recording stopped\n"); - goto done; - } - if (0 != (status & 0x0f000000)) - dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); - if (0 == (status & 0x10000000)) { - /* odd */ - if (0 == (dev->dmasound.dma_blk & 0x01)) - reg = SAA7134_RS_BA1(6); - } else { - /* even */ - if (1 == (dev->dmasound.dma_blk & 0x01)) - reg = SAA7134_RS_BA2(6); - } - if (0 == reg) { - dprintk("irq: field oops [%s]\n", - (status & 0x10000000) ? "even" : "odd"); - goto done; - } - if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { - dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count, - dev->dmasound.bufsize); - dsp_dma_stop(dev); - goto done; - } - - /* next block addr */ - next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; - saa_writel(reg,next_blk * dev->dmasound.blksize); - if (debug > 2) - dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", - (status & 0x10000000) ? "even" : "odd ", next_blk, - next_blk * dev->dmasound.blksize); - - /* update status & wake waiting readers */ - dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; - dev->dmasound.read_count += dev->dmasound.blksize; - wake_up(&dev->dmasound.wq); - - done: - spin_unlock(&dev->slock); -} - -static int saa7134_dsp_create(struct saa7134_dev *dev) -{ - int err; - - err = dev->dmasound.minor_dsp = - register_sound_dsp(&saa7134_dsp_fops, - dsp_nr[dev->nr]); - if (err < 0) { - goto fail; - } - printk(KERN_INFO "%s: registered device dsp%d\n", - dev->name,dev->dmasound.minor_dsp >> 4); - - err = dev->dmasound.minor_mixer = - register_sound_mixer(&saa7134_mixer_fops, - mixer_nr[dev->nr]); - if (err < 0) - goto fail; - printk(KERN_INFO "%s: registered device mixer%d\n", - dev->name,dev->dmasound.minor_mixer >> 4); - - return 0; - -fail: - unregister_sound_dsp(dev->dmasound.minor_dsp); - return 0; - - -} - -static int oss_device_init(struct saa7134_dev *dev) -{ - dev->dmasound.priv_data = dev; - saa7134_oss_init1(dev); - saa7134_dsp_create(dev); - return 1; -} - -static int oss_device_exit(struct saa7134_dev *dev) -{ - - unregister_sound_mixer(dev->dmasound.minor_mixer); - unregister_sound_dsp(dev->dmasound.minor_dsp); - - saa7134_oss_fini(dev); - - if (dev->pci->irq > 0) { - synchronize_irq(dev->pci->irq); - free_irq(dev->pci->irq,&dev->dmasound); - } - - dev->dmasound.priv_data = NULL; - return 1; -} - -static int saa7134_oss_init(void) -{ - struct saa7134_dev *dev = NULL; - struct list_head *list; - - if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { - saa7134_dmasound_init = oss_device_init; - saa7134_dmasound_exit = oss_device_exit; - } else { - printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n"); - return -EBUSY; - } - - printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n"); - - - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); - if (dev->dmasound.priv_data == NULL) { - oss_device_init(dev); - } else { - printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name); - return -EBUSY; - } - } - - if (dev == NULL) - printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n"); - - return 0; - -} - -static void saa7134_oss_exit(void) -{ - struct saa7134_dev *dev; - - list_for_each_entry(dev, &saa7134_devlist, devlist) { - /* Device isn't registered by OSS, probably ALSA's */ - if (!dev->dmasound.minor_dsp) - continue; - - oss_device_exit(dev); - } - - saa7134_dmasound_init = NULL; - saa7134_dmasound_exit = NULL; - - printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); - - return; -} - -/* We initialize this late, to make sure the sound system is up and running */ -late_initcall(saa7134_oss_init); -module_exit(saa7134_oss_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From b17f109df1cd9fe1009501d59e466701106590d7 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 02:42:44 -0300 Subject: V4L/DVB (6624): CXUSB: return control message transfer result to caller Callers to cxusb_ctrl_msg currently do not receive any indication that their transfer failed. Return the true return code from dvb_usb_generic_{rw,write}. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 5b6431ea38c..b4a3f7baf1b 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -49,11 +49,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, sndbuf[0] = cmd; memcpy(&sndbuf[1], wbuf, wlen); if (wo) - dvb_usb_generic_write(d, sndbuf, 1+wlen); + return dvb_usb_generic_write(d, sndbuf, 1+wlen); else - dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); - - return 0; + return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); } /* GPIO */ -- cgit v1.2.3 From 13e001dfe3aeb9e7b05445af76e5b47235e81285 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 02:48:27 -0300 Subject: V4L/DVB (6625): CXUSB: i2c transfer failure notification The i2c master_xfer routine should return a negative result if not all transfers completed successfully. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index b4a3f7baf1b..86fbd6c73ea 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -132,7 +132,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } mutex_unlock(&d->i2c_mutex); - return i; + return i == num ? num : -EREMOTEIO; } static u32 cxusb_i2c_func(struct i2c_adapter *adapter) -- cgit v1.2.3 From 272479d7ab067344d118e7633b624bf98f8896f3 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 03:01:22 -0300 Subject: V4L/DVB (6626): CXUSB: support only-read i2c requests Any i2c read request that was not immediately preceded by a write request was incorrectly taking the write path. Add the capability to handle individual read requests. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 86fbd6c73ea..016a3780b71 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -98,8 +98,21 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], break; } - /* read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].flags & I2C_M_RD) { + /* read only */ + u8 obuf[3], ibuf[1+msg[i].len]; + obuf[0] = 0; + obuf[1] = msg[i].len; + obuf[2] = msg[i].addr; + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3, + ibuf, 1+msg[i].len) < 0) { + warn("i2c read failed"); + break; + } + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + /* write then read */ u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; @@ -117,7 +130,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); i++; - } else { /* write */ + } else { + /* write only */ u8 obuf[2+msg[i].len], ibuf; obuf[0] = msg[i].addr; obuf[1] = msg[i].len; -- cgit v1.2.3 From a644e4a3e95f8ca6eca019c92d8dfde101150687 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 03:05:09 -0300 Subject: V4L/DVB (6627): CXUSB: handle write then read from different address The path to perform a read immediately after a write was not checking that the address being read from was the same as the one that was written. Handling this case correctly should mean that we now can handle more than two i2c messages at a time. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 016a3780b71..74eeb168f24 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -83,9 +83,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - if (num > 2) - warn("more than two i2c messages at a time is not handled yet. TODO."); - for (i = 0; i < num; i++) { if (d->udev->descriptor.idVendor == USB_VID_MEDION) @@ -111,8 +108,9 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], break; } memcpy(msg[i].buf, &ibuf[1], msg[i].len); - } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - /* write then read */ + } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && + msg[i].addr == msg[i+1].addr) { + /* write to then read from same address */ u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; -- cgit v1.2.3 From 58d834ea89664b41e6e21ed2d8dc5680d0dd76b6 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 03:32:06 -0300 Subject: V4L/DVB (6628): zl10353: Improve support for boards without a tuner on secondary i2c Issue FSM_GO instead of TUNER_GO if there is no tuner attached to the secondary i2c bus. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/zl10353.c | 34 +++++++++++++----------------- drivers/media/dvb/frontends/zl10353_priv.h | 2 ++ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 0106df4c55e..9bfdc01fed2 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -183,35 +183,31 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - // if there is no attached secondary tuner, we call set_params to program - // a potential tuner attached somewhere else + /* + * If there is no tuner attached to the secondary I2C bus, we call + * set_params to program a potential tuner attached somewhere else. + * Otherwise, we update the PLL registers via calc_regs. + */ if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, param); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - } - - // if pllbuf is defined, retrieve the settings - if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5); + } else if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); pllbuf[1] <<= 1; - } else { - // fake pllbuf settings - pllbuf[1] = 0x61 << 1; - pllbuf[2] = 0; - pllbuf[3] = 0; - pllbuf[3] = 0; - pllbuf[4] = 0; + zl10353_write(fe, pllbuf, sizeof(pllbuf)); } - // there is no call to _just_ start decoding, so we send the pllbuf anyway - // even if there isn't a PLL attached to the secondary bus - zl10353_write(fe, pllbuf, sizeof(pllbuf)); - zl10353_single_write(fe, 0x5F, 0x13); - zl10353_single_write(fe, 0x70, 0x01); + + /* If no attached tuner or invalid PLL registers, just start the FSM. */ + if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL) + zl10353_single_write(fe, FSM_GO, 0x01); + else + zl10353_single_write(fe, TUNER_GO, 0x01); + udelay(250); zl10353_single_write(fe, 0xE4, 0x00); zl10353_single_write(fe, 0xE5, 0x2A); diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h index 4962434b35e..42855dfe31a 100644 --- a/drivers/media/dvb/frontends/zl10353_priv.h +++ b/drivers/media/dvb/frontends/zl10353_priv.h @@ -48,6 +48,8 @@ enum zl10353_reg_addr { RS_UBC_0 = 0x15, TRL_NOMINAL_RATE_1 = 0x65, TRL_NOMINAL_RATE_0 = 0x66, + TUNER_GO = 0x70, + FSM_GO = 0x71, CHIP_ID = 0x7F, }; -- cgit v1.2.3 From 794604c3efb511b74fb664af72c5dd7046e91075 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 03:55:45 -0300 Subject: V4L/DVB (6630): zl10353: calculate input frequency register instead of using hardcoded value Now we know the zl10353's correct ADC clock, we can calculate the input frequency registers correctly instead of just blindly setting them. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/zl10353.c | 42 ++++++++++++++++++++++++++---- drivers/media/dvb/frontends/zl10353.h | 3 ++- drivers/media/dvb/frontends/zl10353_priv.h | 6 +++-- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 9bfdc01fed2..1736c6ac39c 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006 Christopher Pascoe + * Copyright (C) 2006, 2007 Christopher Pascoe * * 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 @@ -16,7 +16,7 @@ * * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -25,6 +25,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "zl10353_priv.h" @@ -148,6 +149,35 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, __FUNCTION__, bw, adc_clock, *nominal_rate); } +static void zl10353_calc_input_freq(struct dvb_frontend *fe, + u16 *input_freq) +{ + struct zl10353_state *state = fe->demodulator_priv; + u32 adc_clock = 45056; /* 45.056 MHz */ + int if2 = 36167; /* 36.167 MHz */ + int ife; + u64 value; + + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + if (state->config.if2) + if2 = state->config.if2; + + if (adc_clock >= if2 * 2) + ife = if2; + else { + ife = adc_clock - (if2 % adc_clock); + if (ife > adc_clock / 2) + ife = adc_clock - ife; + } + value = 65536ULL * ife + adc_clock / 2; + do_div(value, adc_clock); + *input_freq = -value; + + dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", + __FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq); +} + static int zl10353_sleep(struct dvb_frontend *fe) { static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 }; @@ -160,7 +190,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { struct zl10353_state *state = fe->demodulator_priv; - u16 nominal_rate; + u16 nominal_rate, input_freq; u8 pllbuf[6] = { 0x67 }; /* These settings set "auto-everything" and start the FSM. */ @@ -178,8 +208,10 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); - zl10353_single_write(fe, 0x6C, 0xCD); - zl10353_single_write(fe, 0x6D, 0x7E); + zl10353_calc_input_freq(fe, &input_freq); + zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); + zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h index 1c3d494a6da..2660cec93f8 100644 --- a/drivers/media/dvb/frontends/zl10353.h +++ b/drivers/media/dvb/frontends/zl10353.h @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006 Christopher Pascoe + * Copyright (C) 2006, 2007 Christopher Pascoe * * 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 @@ -31,6 +31,7 @@ struct zl10353_config /* frequencies in kHz */ int adc_clock; /* default: 45056 */ + int if2; /* default: 36167 */ /* set if no pll is connected to the secondary i2c bus */ int no_tuner; diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h index 42855dfe31a..fcad9221945 100644 --- a/drivers/media/dvb/frontends/zl10353_priv.h +++ b/drivers/media/dvb/frontends/zl10353_priv.h @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006 Christopher Pascoe + * Copyright (C) 2006, 2007 Christopher Pascoe * * 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 @@ -16,7 +16,7 @@ * * 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., 675 Mass Ave, Cambridge, MA 02139, USA.= + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _ZL10353_PRIV_ @@ -48,6 +48,8 @@ enum zl10353_reg_addr { RS_UBC_0 = 0x15, TRL_NOMINAL_RATE_1 = 0x65, TRL_NOMINAL_RATE_0 = 0x66, + INPUT_FREQ_1 = 0x6C, + INPUT_FREQ_0 = 0x6D, TUNER_GO = 0x70, FSM_GO = 0x71, CHIP_ID = 0x7F, -- cgit v1.2.3 From 47cc5b78102b4e9993ea1c054b4f077cf7aac7db Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:14:23 -0300 Subject: V4L/DVB (6631): xc2028: eliminate i2c macro side-effects The I2C macros have side effects and send_seq could cause a return from a function with a mutex held. Change them to behave like real functions. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 82 +++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index d23b33a1f69..6e23fad0e56 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -83,31 +83,35 @@ struct xc2028_data { struct mutex lock; }; -#define i2c_send(rc, priv, buf, size) do { \ - rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ - if (size != rc) \ - tuner_err("i2c output error: rc = %d (should be %d)\n", \ - rc, (int)size); \ -} while (0) - -#define i2c_rcv(rc, priv, buf, size) do { \ - rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ - if (size != rc) \ +#define i2c_send(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_info("i2c output error: rc = %d (should be %d)\n",\ + _rc, (int)size); \ + _rc; \ +}) + +#define i2c_rcv(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ + if (size != _rc) \ tuner_err("i2c input error: rc = %d (should be %d)\n", \ - rc, (int)size); \ -} while (0) + _rc, (int)size); \ + _rc; \ +}) -#define send_seq(priv, data...) do { \ - int rc; \ +#define send_seq(priv, data...) ({ \ static u8 _val[] = data; \ + int _rc; \ if (sizeof(_val) != \ - (rc = tuner_i2c_xfer_send(&priv->i2c_props, \ + (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ _val, sizeof(_val)))) { \ - tuner_err("Error on line %d: %d\n", __LINE__, rc); \ - return -EINVAL; \ - } \ - msleep(10); \ -} while (0) + tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ + } else \ + msleep(10); \ + _rc; \ +}) static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) { @@ -119,11 +123,11 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) buf[0] = reg>>8; buf[1] = (unsigned char) reg; - i2c_send(rc, priv, buf, 2); + rc = i2c_send(priv, buf, 2); if (rc < 0) return rc; - i2c_rcv(rc, priv, buf, 2); + rc = i2c_rcv(priv, buf, 2); if (rc < 0) return rc; @@ -505,7 +509,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, memcpy(buf + 1, p, len); - i2c_send(rc, priv, buf, len + 1); + rc = i2c_send(priv, buf, len + 1); if (rc < 0) { tuner_err("%d returned from send\n", rc); return -EINVAL; @@ -541,15 +545,20 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, if ((priv->firm[pos].size != 12 * 16) || (scode >= 16)) return -EINVAL; - if (priv->version < 0x0202) { - send_seq(priv, {0x20, 0x00, 0x00, 0x00}); - } else { - send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); - } + if (priv->version < 0x0202) + rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); + else + rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); + if (rc < 0) + return -EIO; - i2c_send(rc, priv, p + 12 * scode, 12); + rc = i2c_send(priv, p + 12 * scode, 12); + if (rc < 0) + return -EIO; - send_seq(priv, {0x00, 0x8c}); + rc = send_seq(priv, {0x00, 0x8c}); + if (rc < 0) + return -EIO; return 0; } @@ -766,11 +775,12 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , /* CMD= Set frequency */ - if (priv->version < 0x0202) { - send_seq(priv, {0x00, 0x02, 0x00, 0x00}); - } else { - send_seq(priv, {0x80, 0x02, 0x00, 0x00}); - } + if (priv->version < 0x0202) + rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); + if (rc < 0) + goto ret; rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); if (rc < 0) @@ -784,7 +794,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , buf[3] = 0xff & (div); buf[4] = 0; - i2c_send(rc, priv, buf, sizeof(buf)); + rc = i2c_send(priv, buf, sizeof(buf)); if (rc < 0) goto ret; msleep(100); -- cgit v1.2.3 From e155d908f72cc429b538c101ee8ffcd10a44b69b Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:16:47 -0300 Subject: V4L/DVB (6632): xc2028: fix inverted logic in audio standard check strcasecmp returns 0 on match, not true. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 6e23fad0e56..166fede7d0e 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -200,17 +200,17 @@ void dump_firm_type(unsigned int type) static v4l2_std_id parse_audio_std_option(void) { - if (strcasecmp(audio_std, "A2")) + if (strcasecmp(audio_std, "A2") == 0) return V4L2_STD_A2; - if (strcasecmp(audio_std, "A2/A")) + if (strcasecmp(audio_std, "A2/A") == 0) return V4L2_STD_A2_A; - if (strcasecmp(audio_std, "A2/B")) + if (strcasecmp(audio_std, "A2/B") == 0) return V4L2_STD_A2_B; - if (strcasecmp(audio_std, "NICAM")) + if (strcasecmp(audio_std, "NICAM") == 0) return V4L2_STD_NICAM; - if (strcasecmp(audio_std, "NICAM/A")) + if (strcasecmp(audio_std, "NICAM/A") == 0) return V4L2_STD_NICAM_A; - if (strcasecmp(audio_std, "NICAM/B")) + if (strcasecmp(audio_std, "NICAM/B") == 0) return V4L2_STD_NICAM_B; return 0; -- cgit v1.2.3 From 7d58d1117ec02f5fe22ddd03ca08fe2a8c777ea2 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:31:58 -0300 Subject: V4L/DVB (6633): xc2028: make register reads atomic Issuing register reads as a separate address write and data read transactions means that other I2C activity could occur in between and state could get out of sync. Issue both the write and read in a single transaction so that the i2c layer can prevent other users accessing the bus until we are complete. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-i2c.h | 13 +++++++++ drivers/media/video/tuner-xc2028.c | 55 +++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h index b5ac189ba40..d7cf72c3fd7 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/video/tuner-i2c.h @@ -46,6 +46,19 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, return (ret == 1) ? len : ret; } +static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, + char *obuf, int olen, + char *ibuf, int ilen) +{ + struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, + .buf = obuf, .len = olen }, + { .addr = props->addr, .flags = I2C_M_RD, + .buf = ibuf, .len = ilen } }; + int ret = i2c_transfer(props->adap, msg, 2); + + return (ret == 2) ? ilen : ret; +} + #ifndef __TUNER_DRIVER_H__ #define tuner_warn(fmt, arg...) do { \ printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 166fede7d0e..a49a4e88689 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -101,6 +101,16 @@ struct xc2028_data { _rc; \ }) +#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ + ibuf, isize); \ + if (isize != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)isize); \ + _rc; \ +}) + #define send_seq(priv, data...) ({ \ static u8 _val[] = data; \ int _rc; \ @@ -113,25 +123,21 @@ struct xc2028_data { _rc; \ }) -static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) +static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) { - int rc; unsigned char buf[2]; + unsigned char ibuf[2]; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s %04x called\n", __FUNCTION__, reg); - buf[0] = reg>>8; + buf[0] = reg >> 8; buf[1] = (unsigned char) reg; - rc = i2c_send(priv, buf, 2); - if (rc < 0) - return rc; - - rc = i2c_rcv(priv, buf, 2); - if (rc < 0) - return rc; + if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) + return -EIO; - return (buf[1]) | (buf[0] << 8); + *val = (ibuf[1]) | (ibuf[0] << 8); + return 0; } void dump_firm_type(unsigned int type) @@ -567,7 +573,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, v4l2_std_id std, fe_bandwidth_t bandwidth) { struct xc2028_data *priv = fe->tuner_priv; - int rc, version, hwmodel; + int rc; + u16 version, hwmodel; v4l2_std_id std0 = 0; unsigned int type0 = 0, type = 0; int change_digital_bandwidth; @@ -692,8 +699,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, rc = load_scode(fe, type, &std, 0); - version = xc2028_get_reg(priv, 0x0004); - hwmodel = xc2028_get_reg(priv, 0x0008); + xc2028_get_reg(priv, 0x0004, &version); + xc2028_get_reg(priv, 0x0008, &hwmodel); tuner_info("Device is Xceive %d version %d.%d, " "firmware version %d.%d\n", @@ -708,33 +715,31 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) { struct xc2028_data *priv = fe->tuner_priv; - int frq_lock, signal = 0; + u16 frq_lock, signal = 0; + int rc; tuner_dbg("%s called\n", __FUNCTION__); mutex_lock(&priv->lock); - *strength = 0; - /* Sync Lock Indicator */ - frq_lock = xc2028_get_reg(priv, 0x0002); - if (frq_lock <= 0) + rc = xc2028_get_reg(priv, 0x0002, &frq_lock); + if (rc < 0 || frq_lock == 0) goto ret; /* Frequency is locked. Return signal quality */ /* Get SNR of the video signal */ - signal = xc2028_get_reg(priv, 0x0040); - - if (signal <= 0) - signal = frq_lock; + rc = xc2028_get_reg(priv, 0x0040, &signal); + if (rc < 0) + signal = -frq_lock; ret: mutex_unlock(&priv->lock); *strength = signal; - return 0; + return rc; } #define DIV 15625 -- cgit v1.2.3 From 3157ecef3bce47df74427d6656fa8592bfe8d2d7 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:34:29 -0300 Subject: V4L/DVB (6634): xc2028: error messages missing whitespace Fix some missing spaces in errors that may be emitted during attach failure. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index a49a4e88689..c208f1f5e72 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -928,13 +928,13 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) void *video_dev; if (debug) - printk(KERN_DEBUG PREFIX "Xcv2028/3028 init called!\n"); + printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n"); if (NULL == cfg->video_dev) return NULL; if (!fe) { - printk(KERN_ERR PREFIX "No frontend!\n"); + printk(KERN_ERR PREFIX ": No frontend!\n"); return NULL; } -- cgit v1.2.3 From 91240dd92474d4124f80b00e6200052b275a99a1 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:38:53 -0300 Subject: V4L/DVB (6635): xc2028: v4l2_std_id needs to be long long to display completely Cast v4l2_std_id variables to unsigned long long so they will printk properly. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index c208f1f5e72..a01231a0410 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -330,7 +330,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) dump_firm_type(type); printk("(%x), id %llx is corrupted " "(size=%d, expected %d)\n", - type, id, + type, (unsigned long long)id, (unsigned)(endp - p), size); goto corrupt; } @@ -343,8 +343,8 @@ static int load_all_firmwares(struct dvb_frontend *fe) } tuner_info("Reading firmware type "); dump_firm_type(type); - printk("(%x), id %lx, size=%d.\n", - type, (unsigned long)id, size); + printk("(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); memcpy(priv->firm[n].ptr, p, size); priv->firm[n].type = type; @@ -417,7 +417,7 @@ ret: tuner_dbg("%s firmware for type=", (i < 0)? "Can't find": "Found"); if (debug) { dump_firm_type(type); - printk("(%x), id %08lx.\n", type, (unsigned long)*id); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); } return i; } @@ -437,7 +437,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, tuner_info("Loading firmware for type="); dump_firm_type(type); - printk("(%x), id %08lx.\n", type, (unsigned long)*id); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); p = priv->firm[pos].ptr; -- cgit v1.2.3 From aa501be989f5df58c4732d5eb1989e5ca6479d90 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:45:38 -0300 Subject: V4L/DVB (6636): xc2028: protect device list Protect refcount changes and modifications to xc2028_list with a mutex. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index a01231a0410..ac7f3e1d32f 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -44,6 +44,8 @@ MODULE_PARM_DESC(audio_std, "NICAM/B\n"); static LIST_HEAD(xc2028_list); +static DEFINE_MUTEX(xc2028_list_mutex); + /* struct for storing firmware table */ struct firmware_description { unsigned int type; @@ -854,6 +856,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) tuner_dbg("%s called\n", __FUNCTION__); + mutex_lock(&xc2028_list_mutex); + priv->count--; if (!priv->count) { @@ -865,6 +869,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) kfree(priv); } + mutex_unlock(&xc2028_list_mutex); + return 0; } @@ -940,6 +946,8 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) video_dev = cfg->video_dev; + mutex_lock(&xc2028_list_mutex); + list_for_each_entry(priv, &xc2028_list, xc2028_list) { if (priv->video_dev == cfg->video_dev) { video_dev = NULL; @@ -949,8 +957,10 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) if (video_dev) { priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) + if (priv == NULL) { + mutex_unlock(&xc2028_list_mutex); return NULL; + } priv->bandwidth = BANDWIDTH_6_MHZ; priv->need_load_generic = 1; @@ -974,6 +984,8 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + mutex_unlock(&xc2028_list_mutex); + return fe; } -- cgit v1.2.3 From b32f9fb962d593e3c5a61092a79434714f405ef5 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 04:53:50 -0300 Subject: V4L/DVB (6637): xc2028: add missing break Add break to stop us from following the default failure path even upon success. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index ac7f3e1d32f..7e558decad8 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -485,6 +485,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, (*p) & 0x7f); return -EINVAL; } + break; default: tuner_info("Invalid RESET code %d\n", size & 0x7f); -- cgit v1.2.3 From 06fd82dc7bdc6045bf8d6c1438d2a33ffb1cf337 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 06:06:08 -0300 Subject: V4L/DVB (6638): xc2028: firmware loading cleanup Hold the private lock over set_config and set priv->firm_size to 0 after a failed firmware load to prevent firmware accidentally being freed on us. Clean up the firmware load/error messages somewhat and rename priv->version to priv->firm_version to make it clear which "version" it is. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 82 ++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 7e558decad8..7c86971a8d6 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -65,8 +65,7 @@ struct xc2028_data { struct firmware_description *firm; int firm_size; - - __u16 version; + __u16 firm_version; struct xc2028_ctrl ctrl; @@ -237,6 +236,7 @@ static void free_firmware(struct xc2028_data *priv) kfree(priv->firm); priv->firm = NULL; + priv->firm_size = 0; priv->need_load_generic = 1; } @@ -251,7 +251,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) tuner_dbg("%s called\n", __FUNCTION__); - tuner_info("Reading firmware %s\n", priv->ctrl.fname); + tuner_dbg("Reading firmware %s\n", priv->ctrl.fname); rc = request_firmware(&fw, priv->ctrl.fname, &priv->i2c_props.adap->dev); if (rc < 0) { @@ -267,40 +267,34 @@ static int load_all_firmwares(struct dvb_frontend *fe) p = fw->data; endp = p + fw->size; - if (fw->size < sizeof(name) - 1 + 2) { - tuner_err("Error: firmware size is zero!\n"); - rc = -EINVAL; - goto done; + if (fw->size < sizeof(name) - 1 + 2 + 2) { + tuner_err("Error: firmware file %s has invalid size!\n", + priv->ctrl.fname); + goto corrupt; } memcpy(name, p, sizeof(name) - 1); name[sizeof(name) - 1] = 0; p += sizeof(name) - 1; - priv->version = le16_to_cpu(*(__u16 *) p); + priv->firm_version = le16_to_cpu(*(__u16 *) p); p += 2; - tuner_info("Firmware: %s, ver %d.%d\n", name, - priv->version >> 8, priv->version & 0xff); - - if (p + 2 > endp) - goto corrupt; - n_array = le16_to_cpu(*(__u16 *) p); p += 2; - tuner_info("There are %d firmwares at %s\n", - n_array, priv->ctrl.fname); + tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, priv->ctrl.fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); - - if (!fw) { - tuner_err("Not enough memory for reading firmware.\n"); + if (priv->firm == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); rc = -ENOMEM; - goto done; + goto err; } - priv->firm_size = n_array; + n = -1; while (p < endp) { __u32 type, size; @@ -308,7 +302,8 @@ static int load_all_firmwares(struct dvb_frontend *fe) n++; if (n >= n_array) { - tuner_err("Too much firmwares at the file\n"); + tuner_err("More firmware images in file than " + "were expected!\n"); goto corrupt; } @@ -338,15 +333,17 @@ static int load_all_firmwares(struct dvb_frontend *fe) } priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); - if (!priv->firm[n].ptr) { - tuner_err("Not enough memory.\n"); + if (priv->firm[n].ptr == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); rc = -ENOMEM; goto err; } - tuner_info("Reading firmware type "); - dump_firm_type(type); - printk("(%x), id %llx, size=%d.\n", - type, (unsigned long long)id, size); + tuner_dbg("Reading firmware type "); + if (debug) { + dump_firm_type(type); + printk("(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } memcpy(priv->firm[n].ptr, p, size); priv->firm[n].type = type; @@ -368,13 +365,13 @@ corrupt: tuner_err("Error: firmware file is corrupted!\n"); err: - tuner_info("Releasing loaded firmware file.\n"); - + tuner_info("Releasing partially loaded firmware file.\n"); free_firmware(priv); done: release_firmware(fw); - tuner_dbg("Firmware files loaded.\n"); + if (rc == 0) + tuner_dbg("Firmware files loaded.\n"); return rc; } @@ -442,11 +439,6 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, printk("(%x), id %016llx.\n", type, (unsigned long long)*id); p = priv->firm[pos].ptr; - - if (!p) { - tuner_err("Firmware pointer were freed!"); - return -EINVAL; - } endp = p + priv->firm[pos].size; while (p < endp) { @@ -546,15 +538,10 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, p = priv->firm[pos].ptr; - if (!p) { - tuner_err("Firmware pointer were freed!"); - return -EINVAL; - } - if ((priv->firm[pos].size != 12 * 16) || (scode >= 16)) return -EINVAL; - if (priv->version < 0x0202) + if (priv->firm_version < 0x0202) rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); else rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); @@ -783,7 +770,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , /* CMD= Set frequency */ - if (priv->version < 0x0202) + if (priv->firm_version < 0x0202) rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); else rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); @@ -868,6 +855,7 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) free_firmware(priv); kfree(priv); + fe->tuner_priv = NULL; } mutex_unlock(&xc2028_list_mutex); @@ -893,14 +881,18 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) tuner_dbg("%s called\n", __FUNCTION__); + mutex_lock(&priv->lock); + priv->ctrl.type = p->type; if (p->fname) { kfree(priv->ctrl.fname); priv->ctrl.fname = kmalloc(strlen(p->fname) + 1, GFP_KERNEL); - if (!priv->ctrl.fname) + if (priv->ctrl.fname == NULL) { + mutex_unlock(&priv->lock); return -ENOMEM; + } free_firmware(priv); strcpy(priv->ctrl.fname, p->fname); @@ -909,6 +901,8 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) if (p->max_len > 0) priv->max_len = p->max_len; + mutex_unlock(&priv->lock); + return 0; } -- cgit v1.2.3 From 2ce4b3aa7c3c199466ae9f5ed32ea177912c8c3a Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 06:20:17 -0300 Subject: V4L/DVB (6639): xc2028: correct divisor length The frequency divisor should only be four bytes long. Also, display the frequency and divisor correctly in the debug output. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 7c86971a8d6..e85992f970f 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -740,7 +740,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , { struct xc2028_data *priv = fe->tuner_priv; int rc = -EINVAL; - unsigned char buf[5]; + unsigned char buf[4]; u32 div, offset = 0; tuner_dbg("%s called\n", __FUNCTION__); @@ -758,7 +758,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , goto ret; msleep(10); - tuner_dbg("should set frequency %d kHz)\n", freq / 1000); + tuner_dbg("should set frequency %d kHz\n", freq / 1000); if (check_firmware(fe, new_mode, std, bandwidth) < 0) goto ret; @@ -769,7 +769,6 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , div = (freq - offset + DIV / 2) / DIV; /* CMD= Set frequency */ - if (priv->firm_version < 0x0202) rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); else @@ -787,7 +786,6 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , buf[1] = 0xff & (div >> 16); buf[2] = 0xff & (div >> 8); buf[3] = 0xff & (div); - buf[4] = 0; rc = i2c_send(priv, buf, sizeof(buf)); if (rc < 0) @@ -796,9 +794,9 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , priv->frequency = freq; - tuner_dbg("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", - buf[1], buf[2], buf[3], buf[4], - freq / 1000000, (freq % 1000000) / 10000); + tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n", + buf[0], buf[1], buf[2], buf[3], + freq / 1000000, (freq % 1000000) / 1000); rc = 0; -- cgit v1.2.3 From ddf1c5f1d78c1ce30a7e6b2447670fc0e103bb62 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 06:33:16 -0300 Subject: V4L/DVB (6640): xc2028: correctly select 8MHz firmware We were using priv->bandwidth to select the base firmware to load, not the requested bandwidth value, oops. Also, 7MHz Digital TV needs 8MHz base firmware loaded. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index e85992f970f..adef80e627b 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -608,7 +608,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (priv->ctrl.type == XC2028_FIRM_MTS) type0 |= MTS; - if (priv->bandwidth == 8) + if (bandwidth == BANDWIDTH_7_MHZ || + bandwidth == BANDWIDTH_8_MHZ) type0 |= F8MHZ; /* FIXME: How to load FM and FM|INPUT1 firmwares? */ @@ -814,7 +815,8 @@ static int xc2028_set_tv_freq(struct dvb_frontend *fe, tuner_dbg("%s called\n", __FUNCTION__); return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV, - p->std, BANDWIDTH_8_MHZ /* NOT USED */); + p->std, BANDWIDTH_8_MHZ); + /* XXX Are some analog standards 6MHz? */ } static int xc2028_set_params(struct dvb_frontend *fe, -- cgit v1.2.3 From a44f1c43dfa98e2eb763968890157bfaf9001add Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 06:35:26 -0300 Subject: V4L/DVB (6641): xc2028: correct tuner offset for 7MHz DTV 7MHz bandwidth DVB-T needs an adjusted offset at the PLL to ensure the IF output is correctly centered. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index adef80e627b..c921d6009a8 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -764,8 +764,11 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , if (check_firmware(fe, new_mode, std, bandwidth) < 0) goto ret; - if (new_mode == T_DIGITAL_TV) + if (new_mode == T_DIGITAL_TV) { offset = 2750000; + if (priv->bandwidth == BANDWIDTH_7_MHZ) + offset -= 500000; + } div = (freq - offset + DIV / 2) / DIV; -- cgit v1.2.3 From 0a196b6fa9b42a2bb49733b37565aaaa97ffb07f Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 09:29:59 -0300 Subject: V4L/DVB (6642): xc2028: don't duplicate max_len in priv There is no need to duplicate the max_len field from the ctrl structure in the private data. If we use it directly from priv->ctrl, we can memcpy the structure (apart from strings) to reduce maintenance as it grows. Enforce a minimum max_len length of 8 data bytes (+ 1 address byte) as seems to be required by the tuner. Also, use kstrdup instead of open coding the string duplication. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index c921d6009a8..e19449603d7 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -75,9 +75,6 @@ struct xc2028_data { 6M, 7M or 8M */ int need_load_generic; /* The generic firmware were loaded? */ - - int max_len; /* Max firmware chunk */ - enum tuner_mode mode; struct i2c_client *i2c_client; @@ -426,7 +423,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, { struct xc2028_data *priv = fe->tuner_priv; int pos, rc; - unsigned char *p, *endp, buf[priv->max_len]; + unsigned char *p, *endp, buf[priv->ctrl.max_len]; tuner_dbg("%s called\n", __FUNCTION__); @@ -505,8 +502,8 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, /* Sends message chunks */ while (size > 0) { - int len = (size < priv->max_len - 1) ? - size : priv->max_len - 1; + int len = (size < priv->ctrl.max_len - 1) ? + size : priv->ctrl.max_len - 1; memcpy(buf + 1, p, len); @@ -881,32 +878,30 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) { struct xc2028_data *priv = fe->tuner_priv; struct xc2028_ctrl *p = priv_cfg; + int rc = 0; tuner_dbg("%s called\n", __FUNCTION__); mutex_lock(&priv->lock); - priv->ctrl.type = p->type; - - if (p->fname) { - kfree(priv->ctrl.fname); + kfree(priv->ctrl.fname); + free_firmware(priv); - priv->ctrl.fname = kmalloc(strlen(p->fname) + 1, GFP_KERNEL); - if (priv->ctrl.fname == NULL) { - mutex_unlock(&priv->lock); - return -ENOMEM; - } + memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + priv->ctrl.fname = NULL; - free_firmware(priv); - strcpy(priv->ctrl.fname, p->fname); + if (p->fname) { + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) + rc = -ENOMEM; } - if (p->max_len > 0) - priv->max_len = p->max_len; + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; mutex_unlock(&priv->lock); - return 0; + return rc; } static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { @@ -967,7 +962,7 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) priv->i2c_props.adap = cfg->i2c_adap; priv->video_dev = video_dev; priv->tuner_callback = cfg->callback; - priv->max_len = 13; + priv->ctrl.max_len = 13; mutex_init(&priv->lock); -- cgit v1.2.3 From b1535293dc816f01b0934718c370f9533c7d635e Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 10:04:06 -0300 Subject: V4L/DVB (6643): xc2028: use best match instead of first partial match during firmware selection Rather than picking the first video standard firmware that supports any of the standards that the user has requested, try to select one that supports as many of them as possible. This improves the likelihood that the firmware we select will support the user's desired TV standard. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 46 +++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index e19449603d7..3edf5be4719 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -377,9 +377,13 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id *id) { struct xc2028_data *priv = fe->tuner_priv; - int i; + int i, best_i = -1, best_nr_matches = 0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called, want type=", __FUNCTION__); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } if (!priv->firm) { tuner_err("Error! firmware not loaded\n"); @@ -397,20 +401,45 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, /* Seek for generic video standard match */ for (i = 0; i < priv->firm_size; i++) { - if ((type == priv->firm[i].type) && (*id & priv->firm[i].id)) - goto found; + v4l2_std_id match_mask; + int nr_matches; + + if (type != priv->firm[i].type) + continue; + + match_mask = *id & priv->firm[i].id; + if (!match_mask) + continue; + + if ((*id & match_mask) == *id) + goto found; /* Supports all the requested standards */ + + nr_matches = hweight64(match_mask); + if (nr_matches > best_nr_matches) { + best_nr_matches = nr_matches; + best_i = i; + } + } + + if (best_nr_matches > 0) { + tuner_dbg("Selecting best matching firmware (%d bits) for " + "type=", best_nr_matches); + dump_firm_type(type); + printk("(%x), id %016llx:\n", type, (unsigned long long)*id); + i = best_i; + goto found; } /*FIXME: Would make sense to seek for type "hint" match ? */ - i = -EINVAL; + i = -ENOENT; goto ret; found: *id = priv->firm[i].id; ret: - tuner_dbg("%s firmware for type=", (i < 0)? "Can't find": "Found"); + tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); if (debug) { dump_firm_type(type); printk("(%x), id %016llx.\n", type, (unsigned long long)*id); @@ -432,8 +461,9 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, return pos; tuner_info("Loading firmware for type="); - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + dump_firm_type(priv->firm[pos].type); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); p = priv->firm[pos].ptr; endp = p + priv->firm[pos].size; -- cgit v1.2.3 From d7b22c5cfef28d21051331622f9595993a083cc4 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 10:12:45 -0300 Subject: V4L/DVB (6644): xc2028: use correct offset into scode firmware When validating and loading SCODE firmware we need to take into account the two-byte size header before each entry. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 3edf5be4719..fbaab68fd05 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -565,9 +565,17 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, p = priv->firm[pos].ptr; - if ((priv->firm[pos].size != 12 * 16) || (scode >= 16)) + /* 16 SCODE entries per file; each SCODE entry is 12 bytes and + * has a 2-byte size header in the firmware format. */ + if (priv->firm[pos].size != 14 * 16 || scode >= 16 || + le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) return -EINVAL; + tuner_info("Loading SCODE for type="); + dump_firm_type(priv->firm[pos].type); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + if (priv->firm_version < 0x0202) rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); else @@ -575,7 +583,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, if (rc < 0) return -EIO; - rc = i2c_send(priv, p + 12 * scode, 12); + rc = i2c_send(priv, p + 14 * scode + 2, 12); if (rc < 0) return -EIO; -- cgit v1.2.3 From 59a636e50f339f91880b3a1e395829c43cc6541a Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 10:23:17 -0300 Subject: V4L/DVB (6645): xc2028: allow selection of D2633 firmware Add a bit to select D2633 DTV firmware to struct xc2028_ctrl, so that it can be enabled via .set_config. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 7 ++++--- drivers/media/video/tuner-xc2028.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index fbaab68fd05..a5efd5f6e57 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -665,9 +665,10 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, tuner_dbg("I should change bandwidth %u\n", change_digital_bandwidth); if (change_digital_bandwidth) { - - /*FIXME: Should allow selecting between D2620 and D2633 */ - type |= D2620; + if (priv->ctrl.d2633) + type |= D2633; + else + type |= D2620; /* FIXME: When should select a DTV78 firmware? */ diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index a20eeb4935d..4edc4b735c8 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -20,6 +20,7 @@ struct xc2028_ctrl { enum xc2028_firm_type type; char *fname; int max_len; + int d2633:1; }; struct xc2028_config { -- cgit v1.2.3 From e0f0b37a3e624440b1b0e8a5978b367895226e75 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 11:22:03 -0300 Subject: V4L/DVB (6646): xc2028: rework firmware (re)loading process Define a list of valid "firmware types" for each combination of BASE, DTV and SCODEs. By masking the appropriate firmware bits off we can just use one "type" for the firmware searching and also flag when we are looking for a BASE, DTV or SCODE type firmware. This makes it much easier to track if we need to change device modes or flash an individual firmware part. Add a structure to remember what firmware properties we have. This contains the currently loaded/wanted base firmware (type), video std (id), video std requested (std_req), scode file and number in use. Incorporate said structure into the tuner private data. When checking whether the current firmware needs to be reloaded, first figure out exactly what "type" of firmware we want (base, std and scode), and then proceed to load the appropriate matching base, std-specific and scode records iff there are any changes required. This removes guesswork from the process because we no longer need to individually code a check for every tuning parameter's interactions. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 8 ++ drivers/media/video/tuner-xc2028.c | 212 +++++++++++++++++-------------- drivers/media/video/tuner-xc2028.h | 1 + 3 files changed, 124 insertions(+), 97 deletions(-) diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index a9e2e0562d9..6cee48193c4 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -8,6 +8,7 @@ /* BASE firmware should be loaded before any other firmware */ #define BASE (1<<0) +#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) /* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ #define F8MHZ (1<<1) @@ -37,6 +38,8 @@ #define DTV78 (1<<8) #define DTV8 (1<<9) +#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) + /* There's a FM | BASE firmware + FM specific firmware (std=0) */ #define FM (1<<10) @@ -60,6 +63,7 @@ /* Old firmwares were broken into init0 and init1 */ #define INIT1 (1<<14) +/* SCODE firmware selects particular behaviours */ #define MONO (1 << 15) #define ATSC (1 << 16) #define IF (1 << 17) @@ -76,6 +80,10 @@ #define INPUT2 (1 << 28) #define SCODE (1 << 29) +#define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ + LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ + DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) + /* Newer types to be moved to videodev2.h */ #define V4L2_STD_SECAM_K3 (0x04000000) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index a5efd5f6e57..8140d8ad079 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -54,6 +54,14 @@ struct firmware_description { unsigned int size; }; +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + unsigned int scode_table; + int scode_nr; +}; + struct xc2028_data { struct list_head xc2028_list; struct tuner_i2c_props i2c_props; @@ -69,14 +77,7 @@ struct xc2028_data { struct xc2028_ctrl ctrl; - v4l2_std_id firm_type; /* video stds supported - by current firmware */ - fe_bandwidth_t bandwidth; /* Firmware bandwidth: - 6M, 7M or 8M */ - int need_load_generic; /* The generic firmware - were loaded? */ - enum tuner_mode mode; - struct i2c_client *i2c_client; + struct firmware_properties cur_fw; struct mutex lock; }; @@ -234,7 +235,8 @@ static void free_firmware(struct xc2028_data *priv) priv->firm = NULL; priv->firm_size = 0; - priv->need_load_generic = 1; + + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); } static int load_all_firmwares(struct dvb_frontend *fe) @@ -393,6 +395,13 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, if (((type & ~SCODE) == 0) && (*id == 0)) *id = V4L2_STD_PAL; + if (type & BASE) + type &= BASE_TYPES; + else if (type & SCODE) + type &= SCODE_TYPES; + else if (type & DTV_TYPES) + type = type & DTV_TYPES; + /* Seek for exact match */ for (i = 0; i < priv->firm_size; i++) { if ((type == priv->firm[i].type) && (*id == priv->firm[i].id)) @@ -598,11 +607,10 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, v4l2_std_id std, fe_bandwidth_t bandwidth) { struct xc2028_data *priv = fe->tuner_priv; - int rc; + int rc = 0; + unsigned int type = 0; + struct firmware_properties new_fw; u16 version, hwmodel; - v4l2_std_id std0 = 0; - unsigned int type0 = 0, type = 0; - int change_digital_bandwidth; tuner_dbg("%s called\n", __FUNCTION__); @@ -617,61 +625,19 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, return rc; } - tuner_dbg("I am in mode %u and I should switch to mode %i\n", - priv->mode, new_mode); - - /* first of all, determine whether we have switched the mode */ - if (new_mode != priv->mode) { - priv->mode = new_mode; - priv->need_load_generic = 1; - } - - change_digital_bandwidth = (priv->mode == T_DIGITAL_TV - && bandwidth != priv->bandwidth) ? 1 : 0; - tuner_dbg("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, - bandwidth); - - if (priv->need_load_generic) { - /* Reset is needed before loading firmware */ - rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, 0); - if (rc < 0) - return rc; - - type0 = BASE; - - if (priv->ctrl.type == XC2028_FIRM_MTS) - type0 |= MTS; - - if (bandwidth == BANDWIDTH_7_MHZ || - bandwidth == BANDWIDTH_8_MHZ) - type0 |= F8MHZ; - - /* FIXME: How to load FM and FM|INPUT1 firmwares? */ - - rc = load_firmware(fe, type0, &std0); - if (rc < 0) { - tuner_err("Error %d while loading generic firmware\n", - rc); - return rc; - } - - priv->need_load_generic = 0; - priv->firm_type = 0; - if (priv->mode == T_DIGITAL_TV) - change_digital_bandwidth = 1; - } + if (priv->ctrl.type == XC2028_FIRM_MTS) + type |= MTS; + if (bandwidth == BANDWIDTH_7_MHZ || bandwidth == BANDWIDTH_8_MHZ) + type |= F8MHZ; - tuner_dbg("I should change bandwidth %u\n", change_digital_bandwidth); + /* FIXME: How to load FM and FM|INPUT1 firmwares? */ - if (change_digital_bandwidth) { + if (new_mode == T_DIGITAL_TV) { if (priv->ctrl.d2633) type |= D2633; else type |= D2620; - /* FIXME: When should select a DTV78 firmware? - */ switch (bandwidth) { case BANDWIDTH_8_MHZ: type |= DTV8; @@ -683,49 +649,96 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, /* FIXME: Should allow select also ATSC */ type |= DTV6 | QAM; break; - default: tuner_err("error: bandwidth not supported.\n"); }; - priv->bandwidth = bandwidth; } - if (!change_digital_bandwidth && priv->mode == T_DIGITAL_TV) - return 0; + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE | priv->ctrl.scode_table; + new_fw.scode_nr = 0; + + tuner_dbg("checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk("(%x), id %016llx, scode_tbl ", new_fw.type, + (unsigned long long)new_fw.std_req); + dump_firm_type(priv->ctrl.scode_table); + printk("(%x), scode_nr %d\n", priv->ctrl.scode_table, + new_fw.scode_nr); + } + + /* No need to reload base firmware if it matches */ + if (((BASE | new_fw.type) & BASE_TYPES) == + (priv->cur_fw.type & BASE_TYPES)) { + tuner_dbg("BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = priv->tuner_callback(priv->video_dev, + XC2028_TUNER_RESET, 0); + if (rc < 0) + goto fail; + + rc = load_firmware(fe, BASE | new_fw.type, &new_fw.id); + if (rc < 0) { + tuner_err("Error %d while loading base firmware\n", + rc); + goto fail; + } /* Load INIT1, if needed */ tuner_dbg("Load init1 firmware, if exists\n"); - type0 = BASE | INIT1; - if (priv->ctrl.type == XC2028_FIRM_MTS) - type0 |= MTS; - /* FIXME: Should handle errors - if INIT1 found */ - rc = load_firmware(fe, type0, &std0); + rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &new_fw.id); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } - /* FIXME: Should add support for FM radio +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. */ - - if (priv->ctrl.type == XC2028_FIRM_MTS) - type |= MTS; - - if (priv->firm_type & std) { + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { tuner_dbg("Std-specific firmware already loaded.\n"); - return 0; + goto skip_std_specific; } + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + /* Add audio hack to std mask */ - std |= parse_audio_std_option(); + if (new_mode == T_ANALOG_TV) + new_fw.id |= parse_audio_std_option(); - rc = load_firmware(fe, type, &std); + rc = load_firmware(fe, new_fw.type, &new_fw.id); if (rc < 0) - return rc; + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + tuner_dbg("SCODE firmware already loaded.\n"); + goto check_device; + } /* Load SCODE firmware, if exists */ - tuner_dbg("Trying to load scode 0\n"); - type |= SCODE; + tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); - rc = load_scode(fe, type, &std, 0); + rc = load_scode(fe, new_fw.type | new_fw.scode_table, + &new_fw.id, new_fw.scode_nr); +check_device: xc2028_get_reg(priv, 0x0004, &version); xc2028_get_reg(priv, 0x0008, &hwmodel); @@ -734,9 +747,23 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, (version & 0xf0) >> 4, version & 0xf); - priv->firm_type = std; + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; return 0; + +fail: + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (rc == -ENOENT) + rc = -EINVAL; + return rc; } static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) @@ -785,16 +812,10 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , mutex_lock(&priv->lock); /* HACK: It seems that specific firmware need to be reloaded - when freq is changed */ - - priv->firm_type = 0; - - /* Reset GPIO 1 */ - rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0); - if (rc < 0) - goto ret; + when watching analog TV and freq is changed */ + if (new_mode != T_DIGITAL_TV) + priv->cur_fw.type = 0; - msleep(10); tuner_dbg("should set frequency %d kHz\n", freq / 1000); if (check_firmware(fe, new_mode, std, bandwidth) < 0) @@ -802,7 +823,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , if (new_mode == T_DIGITAL_TV) { offset = 2750000; - if (priv->bandwidth == BANDWIDTH_7_MHZ) + if (priv->cur_fw.type & DTV7) offset -= 500000; } @@ -994,9 +1015,6 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) return NULL; } - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->need_load_generic = 1; - priv->mode = T_UNINITIALIZED; priv->i2c_props.addr = cfg->i2c_addr; priv->i2c_props.adap = cfg->i2c_adap; priv->video_dev = video_dev; diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 4edc4b735c8..16259b14ce9 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -21,6 +21,7 @@ struct xc2028_ctrl { char *fname; int max_len; int d2633:1; + unsigned int scode_table; }; struct xc2028_config { -- cgit v1.2.3 From 8bf799a6217f6336fb95f37bf1b130003404bd7b Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 11:35:45 -0300 Subject: V4L/DVB (6647): xc2028: retry firmware load if tuner does not respond In practice, the tuner occasionally fails to respond correctly after a firmware load. Retry the firmware load if the firmware/hardware version we read back from the tuner after programming does not match what we expect. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 8140d8ad079..cc6fa2fa859 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -75,6 +75,9 @@ struct xc2028_data { int firm_size; __u16 firm_version; + __u16 hwmodel; + __u16 hwvers; + struct xc2028_ctrl ctrl; struct firmware_properties cur_fw; @@ -607,7 +610,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, v4l2_std_id std, fe_bandwidth_t bandwidth) { struct xc2028_data *priv = fe->tuner_priv; - int rc = 0; + int rc = 0, is_retry = 0; unsigned int type = 0; struct firmware_properties new_fw; u16 version, hwmodel; @@ -654,6 +657,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, }; } +retry: new_fw.type = type; new_fw.id = std; new_fw.std_req = std; @@ -739,14 +743,34 @@ skip_std_specific: &new_fw.id, new_fw.scode_nr); check_device: - xc2028_get_reg(priv, 0x0004, &version); - xc2028_get_reg(priv, 0x0008, &hwmodel); + if (xc2028_get_reg(priv, 0x0004, &version) < 0 || + xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { + tuner_err("Unable to read tuner registers.\n"); + goto fail; + } tuner_info("Device is Xceive %d version %d.%d, " "firmware version %d.%d\n", hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, (version & 0xf0) >> 4, version & 0xf); + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { + tuner_err("Incorrect readback of firmware version.\n"); + goto fail; + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { + priv->hwmodel = hwmodel; + priv->hwvers = version & 0xff00; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != (version & 0xff00)) { + tuner_err("Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); /* @@ -761,6 +785,13 @@ check_device: fail: memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (!is_retry) { + msleep(50); + is_retry = 1; + tuner_dbg("Retrying firmware load\n"); + goto retry; + } + if (rc == -ENOENT) rc = -EINVAL; return rc; -- cgit v1.2.3 From 45819c381fc4fb342dc091f30eef4b56193e34d5 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 11:41:20 -0300 Subject: V4L/DVB (6648): xc2028: add sleep hook Add sleep method to enable putting the tuner into standby mode. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index cc6fa2fa859..8f9ccaee9bb 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -929,6 +929,28 @@ static int xc2028_set_params(struct dvb_frontend *fe, } +static int xc2028_sleep(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); + + priv->cur_fw.type = 0; /* need firmware reload */ + + mutex_unlock(&priv->lock); + + return rc; +} + + static int xc2028_dvb_release(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; @@ -1009,6 +1031,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .get_frequency = xc2028_get_frequency, .get_rf_strength = xc2028_signal, .set_params = xc2028_set_params, + .sleep = xc2028_sleep, }; -- cgit v1.2.3 From aeb012bbf460171b75ba17dc064a543f7256521f Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 21:57:10 -0300 Subject: V4L/DVB (6649): Add support for the DViCO FusionHDTV Dual Digital 4 Add support for DViCO's Dual Digital 4 with xc3028 tuner, zl10353 DVB-T demodulator and a new-style I2C IR remote control receiver. This would not have been possible without the work of and advice from Mike Krufky, who originally got the Dual Digital 4 and second-gen DVB-T NANO devices working with the out-of-tree XC3028 driver. I converted it to use the in-tree XC3028 driver (after making it suitable for our use), and added the IR remote control support based on his advice. NB: a firmware package is required to use this device. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 200 +++++++++++++++++++++++++++++++- drivers/media/dvb/dvb-usb/cxusb.h | 2 + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 3 files changed, 201 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 74eeb168f24..ec8516ac810 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -15,7 +15,7 @@ * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) - * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) * * 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 @@ -30,6 +30,8 @@ #include "mt352.h" #include "mt352_priv.h" #include "zl10353.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -73,6 +75,29 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) st->gpio_write_state[GPIO_TUNER] = onoff; } +static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, + u8 newval) +{ + u8 o[2], gpio_state; + int rc; + + o[0] = 0xff & ~changemask; /* mask of bits to keep */ + o[1] = newval & changemask; /* new values for bits */ + + rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); + if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) + deb_info("bluebird_gpio_write failed.\n"); + + return rc < 0 ? rc : gpio_state; +} + +static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) +{ + cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); + msleep(5); + cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -210,6 +235,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) + return 0; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[1] && + keymap[i].data == ircode[2]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x02, KEY_TV }, { 0xfe, 0x0e, KEY_MP3 }, @@ -364,6 +417,13 @@ static struct mt352_config cxusb_mt352_config = { .demod_init = cxusb_mt352_demod_init, }; +static struct zl10353_config cxusb_zl10353_xc3028_config = { + .demod_address = 0x0f, + .if2 = 4560, + .no_tuner = 1, + .parallel_ts = 1, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -399,6 +459,52 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) +{ + struct dvb_usb_device *d = ptr; + + switch (command) { + case XC2028_TUNER_RESET: + deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); + cxusb_bluebird_gpio_pulse(d, 0x01, 1); + break; + case XC2028_RESET_CLK: + deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); + break; + default: + deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__, + command, arg); + return -EINVAL; + } + + return 0; +} + +static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &adap->dev->i2c_adap, + .i2c_addr = 0x61, + .video_dev = adap->dev, + .callback = dvico_bluebird_xc2028_callback, + }; + static struct xc2028_ctrl ctl = { + .type = XC2028_FIRM_NORMAL, + .fname = "xc3028-dvico-au-01.fw", + .max_len = 64, + .scode_table = ZARLINK456, + }; + + fe = dvb_attach(xc2028_attach, adap->fe, &cfg); + if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) + return -EIO; + + fe->ops.tuner_ops.set_config(fe, &ctl); + + return 0; +} + static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -460,6 +566,46 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } +static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap)) == NULL) + return -EIO; + + /* try to determine if there is no IR decoder on the I2C bus */ + for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) { + msleep(20); + if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) + goto no_IR; + if (ircode[0] == 0 && ircode[1] == 0) + continue; + if (ircode[2] + ircode[3] != 0xff) { +no_IR: + adap->dev->props.rc_key_map = NULL; + info("No IR receiver detected on this device."); + break; + } + } + + return 0; +} + /* * DViCO bluebird firmware needs the "warm" product ID to be patched into the * firmware file before download. @@ -492,6 +638,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -500,7 +647,8 @@ static int cxusb_probe(struct usb_interface *intf, dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) { + dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0) { return 0; } @@ -521,6 +669,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -779,6 +928,53 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { } }; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_mce_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), + .rc_query = cxusb_bluebird2_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4", + { NULL }, + { &cxusb_table[13], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index 79ca7abb89a..4768a2c3551 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -5,6 +5,8 @@ #include "dvb-usb.h" /* usb commands - some of it are guesses, don't have a reference yet */ +#define CMD_BLUEBIRD_GPIO_RW 0x05 + #define CMD_I2C_WRITE 0x08 #define CMD_I2C_READ 0x09 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index d6d96308cba..6f14c853ffe 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -147,6 +147,7 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 -- cgit v1.2.3 From 47bd5bc6486a5288aa3002533c24c8e9e564f9ac Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 23:11:37 -0300 Subject: V4L/DVB (6650): xc2028: base firmwares should have std0 When loading BASE firmware, we must use std = 0. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 8f9ccaee9bb..115738d75f3 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -614,6 +614,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, unsigned int type = 0; struct firmware_properties new_fw; u16 version, hwmodel; + v4l2_std_id std0; tuner_dbg("%s called\n", __FUNCTION__); @@ -690,7 +691,9 @@ retry: if (rc < 0) goto fail; - rc = load_firmware(fe, BASE | new_fw.type, &new_fw.id); + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE | new_fw.type, &std0); if (rc < 0) { tuner_err("Error %d while loading base firmware\n", rc); @@ -700,7 +703,7 @@ retry: /* Load INIT1, if needed */ tuner_dbg("Load init1 firmware, if exists\n"); - rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &new_fw.id); + rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); if (rc < 0 && rc != -ENOENT) { tuner_err("Error %d while loading init1 firmware\n", rc); -- cgit v1.2.3 From 11a9eff9b66b1cf860faa84084328d798d18834c Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 23:18:36 -0300 Subject: V4L/DVB (6651): xc2028: mask off type correctly when searching for standard-specific types When searching for standard-specific analog firmware, only certain type bits are valid, much like for DTV. Mask them off when finding the firmware to load. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 2 ++ drivers/media/video/tuner-xc2028.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index 6cee48193c4..c0dc6ec19f0 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -43,6 +43,8 @@ /* There's a FM | BASE firmware + FM specific firmware (std=0) */ #define FM (1<<10) +#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) + /* Applies only for FM firmware Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) */ diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 115738d75f3..5b646fed340 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -403,7 +403,9 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, else if (type & SCODE) type &= SCODE_TYPES; else if (type & DTV_TYPES) - type = type & DTV_TYPES; + type &= DTV_TYPES; + else if (type & STD_SPECIFIC_TYPES) + type &= STD_SPECIFIC_TYPES; /* Seek for exact match */ for (i = 0; i < priv->firm_size; i++) { -- cgit v1.2.3 From 1ad0b796a3fa3d1c1a7d16be7c70b626da2940a9 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 19 Nov 2007 23:43:13 -0300 Subject: V4L/DVB (6652): xc2028: try non-8MHZ init1 firmware When loading init1 firmware, there may not be an 8MHz specific version. Load the non-8MHz version if it exists. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 5b646fed340..429e81be697 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -706,6 +706,9 @@ retry: tuner_dbg("Load init1 firmware, if exists\n"); rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, + &std0); if (rc < 0 && rc != -ENOENT) { tuner_err("Error %d while loading init1 firmware\n", rc); -- cgit v1.2.3 From 5ccaf905015c83a9b28e8496b4504b9b8dc25a80 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Tue, 20 Nov 2007 01:53:31 -0300 Subject: V4L/DVB (6653): Add support for the DViCO FusionHDTV NANO2 w/ZL10353 and firmware Add support for the DViCO FusionHDTV DVB-T NANO with zl10353 demodulator and firmware in ROM on the device. Again, this is based on the great work of Mike Krufky with my modifications to use the in-tree XC2028 driver. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 88 ++++++++++++++++++++++++++++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index ec8516ac810..f6fa2c22b0b 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -98,6 +98,11 @@ static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); } +static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) +{ + cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -200,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } +static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int rc = 0; + + rc = cxusb_power_ctrl(d, onoff); + if (!onoff) + cxusb_nano2_led(d, 0); + + return rc; +} + static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -606,6 +622,26 @@ no_IR: return 0; } +static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + /* * DViCO bluebird firmware needs the "warm" product ID to be patched into the * firmware file before download. @@ -639,6 +675,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -648,7 +685,8 @@ static int cxusb_probe(struct usb_interface *intf, dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0) { + dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0) { return 0; } @@ -670,6 +708,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -975,6 +1014,53 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { } }; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_bluebird2_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2", + { NULL }, + { &cxusb_table[14], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 6f14c853ffe..53496985ddf 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -148,6 +148,7 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 +#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 -- cgit v1.2.3 From c6e62a3a398d62e8ae366ac1465911db0ac7fc0b Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Tue, 20 Nov 2007 02:49:41 -0300 Subject: V4L/DVB (6654): mt352: support oversampled IF input Rework the input frequency calculation so that it produces the right values when the ADC oversamples the IF input. This means MT352 devices can now process a near-zero IF (according to the, specs 4.57MHz is supported with the default crystal). Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt352.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 5dd9b731f6f..7cd190b6f01 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state, if (state->config.if2) if2 = state->config.if2; - ife = (2*adc_clock - if2); + if (adc_clock >= if2 * 2) + ife = if2; + else { + ife = adc_clock - (if2 % adc_clock); + if (ife > adc_clock / 2) + ife = adc_clock - ife; + } value = -16374 * ife / adc_clock; dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", __FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff); -- cgit v1.2.3 From 702a67624e4bc9c7056418b576af928940b7dbb9 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Tue, 20 Nov 2007 03:34:11 -0300 Subject: V4L/DVB (6655): Add support for MT352-based DViCO FusionHDTV DVB-T NANO devices There are at least three variants of the DViCO FusionHDTV DVB-T NANO that share the same USB device ID. The first (ZL10353 w/ firmware in ROM) is already supported; the latter two both require firmware and have either an MT352 or ZL10353 demodulator, and have a different IR receiver from the first. This introduces a new identify_state that can tell the difference between a "warm" device which is running the embedded firmware, and a "cold" device that needs us to upload firmware to it before it will work. We patch the uploaded device ID (like we do for other bluebird devices) to make it easy to identify the particular device variant when it reattaches. NB: These devices use a different firmware file from previous bluebird devices. You need a new firmware file to make this work. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 116 +++++++++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index f6fa2c22b0b..c44b9799efa 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -440,6 +440,13 @@ static struct zl10353_config cxusb_zl10353_xc3028_config = { .parallel_ts = 1, }; +static struct mt352_config cxusb_mt352_xc3028_config = { + .demod_address = 0x0f, + .if2 = 4560, + .no_tuner = 1, + .demod_init = cxusb_mt352_demod_init, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -639,30 +646,63 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) &adap->dev->i2c_adap)) != NULL) return 0; + if ((adap->fe = dvb_attach(mt352_attach, + &cxusb_mt352_xc3028_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + return -EIO; } +/* + * DViCO has shipped two devices with the same USB ID, but only one of them + * needs a firmware download. Check the device class details to see if they + * have non-default values to decide whether the device is actually cold or + * not, and forget a match if it turns out we selected the wrong device. + */ +static int bluebird_fx2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int wascold = *cold; + + *cold = udev->descriptor.bDeviceClass == 0xff && + udev->descriptor.bDeviceSubClass == 0xff && + udev->descriptor.bDeviceProtocol == 0xff; + + if (*cold && !wascold) + *desc = NULL; + + return 0; +} + /* * DViCO bluebird firmware needs the "warm" product ID to be patched into the * firmware file before download. */ -#define BLUEBIRD_01_ID_OFFSET 6638 +static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw) { - if (fw->size < BLUEBIRD_01_ID_OFFSET + 4) - return -EINVAL; + int pos; + + for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { + int idoff = dvico_firmware_id_offsets[pos]; - if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) && - fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { + if (fw->size < idoff + 4) + continue; - fw->data[BLUEBIRD_01_ID_OFFSET + 2] = - le16_to_cpu(udev->descriptor.idProduct) + 1; - fw->data[BLUEBIRD_01_ID_OFFSET + 3] = - le16_to_cpu(udev->descriptor.idProduct) >> 8; + if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && + fw->data[idoff + 1] == USB_VID_DVICO >> 8) { + fw->data[idoff + 2] = + le16_to_cpu(udev->descriptor.idProduct) + 1; + fw->data[idoff + 3] = + le16_to_cpu(udev->descriptor.idProduct) >> 8; - return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); + return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); + } } return -EINVAL; @@ -676,6 +716,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -686,7 +727,8 @@ static int cxusb_probe(struct usb_interface *intf, dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0) { + dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) { return 0; } @@ -709,6 +751,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1018,6 +1061,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, + .identify_state = bluebird_fx2_identify_state, .size_of_priv = sizeof(struct cxusb_state), @@ -1061,6 +1105,56 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { } }; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-02.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", + { &cxusb_table[14], NULL }, + { &cxusb_table[15], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 53496985ddf..c94d993a6ef 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -149,6 +149,7 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 +#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 -- cgit v1.2.3 From a1dcd9de648c8cf21abaeca7f77885665eed4117 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Tue, 20 Nov 2007 08:17:54 -0300 Subject: V4L/DVB (6656): zl10353: store frequencies in 0.1kHz to eliminate rounding errors Whilst reanalysing my formulas I realised it was no longer possible to get the right values for a 36.1667MHz IF due to rounding problems. Storing frequencies in units of 0.1kHz makes it possible to calculate these again correctly. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 2 +- drivers/media/dvb/frontends/zl10353.c | 15 +++++++++------ drivers/media/dvb/frontends/zl10353.h | 8 ++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index c44b9799efa..deeb3871a2a 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -435,7 +435,7 @@ static struct mt352_config cxusb_mt352_config = { static struct zl10353_config cxusb_zl10353_xc3028_config = { .demod_address = 0x0f, - .if2 = 4560, + .if2 = 45600, .no_tuner = 1, .parallel_ts = 1, }; diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 1736c6ac39c..091fbcced00 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -123,9 +123,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, enum fe_bandwidth bandwidth, u16 *nominal_rate) { - u32 adc_clock = 45056; /* 45.056 MHz */ - u8 bw; struct zl10353_state *state = fe->demodulator_priv; + u32 adc_clock = 450560; /* 45.056 MHz */ + u64 value; + u8 bw; if (state->config.adc_clock) adc_clock = state->config.adc_clock; @@ -143,7 +144,9 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, break; } - *nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock; + value = (bw * (u64)10 * (1 << 23) / 7 * 125 + adc_clock / 2); + do_div(value, adc_clock); + *nominal_rate = value; dprintk("%s: bw %d, adc_clock %d => 0x%x\n", __FUNCTION__, bw, adc_clock, *nominal_rate); @@ -153,8 +156,8 @@ static void zl10353_calc_input_freq(struct dvb_frontend *fe, u16 *input_freq) { struct zl10353_state *state = fe->demodulator_priv; - u32 adc_clock = 45056; /* 45.056 MHz */ - int if2 = 36167; /* 36.167 MHz */ + u32 adc_clock = 450560; /* 45.056 MHz */ + int if2 = 361667; /* 36.1667 MHz */ int ife; u64 value; @@ -170,7 +173,7 @@ static void zl10353_calc_input_freq(struct dvb_frontend *fe, if (ife > adc_clock / 2) ife = adc_clock - ife; } - value = 65536ULL * ife + adc_clock / 2; + value = (u64)65536 * ife + adc_clock / 2; do_div(value, adc_clock); *input_freq = -value; diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h index 2660cec93f8..fc734c22b5f 100644 --- a/drivers/media/dvb/frontends/zl10353.h +++ b/drivers/media/dvb/frontends/zl10353.h @@ -29,9 +29,9 @@ struct zl10353_config /* demodulator's I2C address */ u8 demod_address; - /* frequencies in kHz */ - int adc_clock; /* default: 45056 */ - int if2; /* default: 36167 */ + /* frequencies in units of 0.1kHz */ + int adc_clock; /* default: 450560 (45.056 MHz) */ + int if2; /* default: 361667 (36.1667 MHz) */ /* set if no pll is connected to the secondary i2c bus */ int no_tuner; @@ -50,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_ZL10353 +#endif /* CONFIG_DVB_ZL10353 */ #endif /* ZL10353_H */ -- cgit v1.2.3 From c71d4bc512dda42069c70219bd00315a91550367 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Nov 2007 11:47:18 -0300 Subject: V4L/DVB (6657): Fix standard selection for PAL/M, PAL/N, PAL/Nc and NTSC Those standards use 6 MHz firmware. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 429e81be697..911831442b5 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -910,12 +910,18 @@ static int xc2028_set_tv_freq(struct dvb_frontend *fe, struct analog_parameters *p) { struct xc2028_data *priv = fe->tuner_priv; + fe_bandwidth_t bw; + + /* FIXME: Maybe there are more 6 MHz video standards */ + if (p->std & V4L2_STD_MN) + bw = BANDWIDTH_6_MHZ; + else + bw = BANDWIDTH_8_MHZ; tuner_dbg("%s called\n", __FUNCTION__); return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV, - p->std, BANDWIDTH_8_MHZ); - /* XXX Are some analog standards 6MHz? */ + p->std, bw); } static int xc2028_set_params(struct dvb_frontend *fe, -- cgit v1.2.3 From a5e9fe149afb0fdf0de4729f1b0d203d4ac14906 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Nov 2007 11:36:18 -0300 Subject: V4L/DVB (6658): Sets a default std, if not specified Some drivers call set_frequency before selecting the video standard. Before this patch, an invalid standard ID could be assumed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 911831442b5..8fa3ab76fd5 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -912,7 +912,11 @@ static int xc2028_set_tv_freq(struct dvb_frontend *fe, struct xc2028_data *priv = fe->tuner_priv; fe_bandwidth_t bw; - /* FIXME: Maybe there are more 6 MHz video standards */ + /* if std is not defined, choose one */ + if (!p->std) + p->std = V4L2_STD_MN; + + /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ if (p->std & V4L2_STD_MN) bw = BANDWIDTH_6_MHZ; else -- cgit v1.2.3 From 5add9a6f3c90680f89b4694e81025d2aed9559af Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Nov 2007 12:08:53 -0300 Subject: V4L/DVB (6659): Convert MTS to bitfield Xc2028.3028 has two type of firmwares: audio-standard specific ones and baseband MTS firmwares. MTS firmwares provide stereo decoding for 6 MHz BTSC/EIAJ and for monoaural audio decoding on 8 MHz firmwares. It seems that the option to use MTS or a standard-specific audio decoding depends on the way xc2028/3028 is connected. Instead of wasting 32 (or 64 bits) to signalize if the driver needs to use MTS firmware, this patch converts it to a bitfield that can be shared with other proprieties of xc2028/3028. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 1 - drivers/media/video/em28xx/em28xx-cards.c | 4 ++-- drivers/media/video/em28xx/em28xx.h | 2 +- drivers/media/video/tuner-xc2028.c | 2 +- drivers/media/video/tuner-xc2028.h | 9 ++------- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index deeb3871a2a..c58365005ac 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -513,7 +513,6 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) .callback = dvico_bluebird_xc2028_callback, }; static struct xc2028_ctrl ctl = { - .type = XC2028_FIRM_NORMAL, .fname = "xc3028-dvico-au-01.fw", .max_len = 64, .scode_table = ZARLINK456, diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index c40b9d9b307..29e935f4109 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -154,7 +154,7 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .has_tuner = 1, - .xc2028_type = XC2028_FIRM_MTS, + .mts_firmware = 1, .decoder = EM28XX_TVP5150, .input = {{ .type = EM28XX_VMUX_TELEVISION, @@ -476,7 +476,7 @@ static void em28xx_config_tuner (struct em28xx *dev) ctl.fname = XC2028_DEFAULT_FIRMWARE; ctl.max_len = 64; - ctl.type = em28xx_boards[dev->model].xc2028_type; + ctl.mts = em28xx_boards[dev->model].mts_firmware; xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index db82b51c85f..93007cc72f4 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -176,9 +176,9 @@ struct em28xx_board { unsigned int has_tuner:1; unsigned int has_msp34xx:1; + unsigned int mts_firmware:1; enum em28xx_decoder decoder; - int xc2028_type; struct em28xx_input input[MAX_EM28XX_INPUT]; }; diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 8fa3ab76fd5..6a6642ea48c 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -631,7 +631,7 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, return rc; } - if (priv->ctrl.type == XC2028_FIRM_MTS) + if (priv->ctrl.mts) type |= MTS; if (bandwidth == BANDWIDTH_7_MHZ || bandwidth == BANDWIDTH_8_MHZ) type |= F8MHZ; diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 16259b14ce9..f24fb2a00f6 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -11,17 +11,12 @@ #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" -enum xc2028_firm_type { - XC2028_FIRM_NORMAL, - XC2028_FIRM_MTS, -}; - struct xc2028_ctrl { - enum xc2028_firm_type type; char *fname; int max_len; - int d2633:1; unsigned int scode_table; + unsigned int mts :1; + unsigned int d2633:1; }; struct xc2028_config { -- cgit v1.2.3 From 71a2ee37e8851f430d72daea0722908512d57f79 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Nov 2007 12:19:37 -0300 Subject: V4L/DVB (6660): Allow fully configuring xc3028 during xc2028_attach xc3028 can be used on some DTV only designs (for example, DVB-S boards). Before this patch, a DTV only board would need to call set_tuner_config callback. This patch allows to optionally pass a xc3028_ctrl parameter, via xc3028_config struct, fully initializing the driver for DTV. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 5 ++++- drivers/media/video/tuner-xc2028.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 6a6642ea48c..c231e7a74ff 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -1061,7 +1061,7 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) if (debug) printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n"); - if (NULL == cfg->video_dev) + if (NULL == cfg || NULL == cfg->video_dev) return NULL; if (!fe) { @@ -1106,6 +1106,9 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + if (cfg->ctrl) + xc2028_set_config(fe, cfg->ctrl); + mutex_unlock(&xc2028_list_mutex); return fe; diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index f24fb2a00f6..a59d00fb2a3 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -23,6 +23,7 @@ struct xc2028_config { struct i2c_adapter *i2c_adap; u8 i2c_addr; void *video_dev; + struct xc2028_ctrl *ctrl; int (*callback) (void *dev, int command, int arg); }; -- cgit v1.2.3 From 2800ae9cd669db0fc9993cbefae02f181343c295 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Nov 2007 12:48:04 -0300 Subject: V4L/DVB (6661): Remove firmware reload hack for analog On some cases, xc2028/xc3028 wents into "turn off" mode. It seems that this happens when very weak signals are tuned. To solve this, specific standard reaload were done previously. Christopher patches changed this behavior to a complete firmware reload. This patch removes the hack. A much cleaner solution for this trouble is just to sent a xc2028/3028 software reset. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index c231e7a74ff..a43a3398b7c 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -850,16 +850,21 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , mutex_lock(&priv->lock); - /* HACK: It seems that specific firmware need to be reloaded - when watching analog TV and freq is changed */ - if (new_mode != T_DIGITAL_TV) - priv->cur_fw.type = 0; - tuner_dbg("should set frequency %d kHz\n", freq / 1000); if (check_firmware(fe, new_mode, std, bandwidth) < 0) goto ret; + /* On some cases xc2028 can disable video output, if + * very weak signals are received. By sending a soft + * reset, this is re-enabled. So, it is better to always + * send a soft reset before changing channels, to be sure + * that xc2028 will be in a safe state. + * Maybe this might also be needed for DTV. + */ + if (new_mode != T_DIGITAL_TV) + rc = send_seq(priv, {0x00, 0x00}); + if (new_mode == T_DIGITAL_TV) { offset = 2750000; if (priv->cur_fw.type & DTV7) -- cgit v1.2.3 From cca83798119c92a3086af9e8a0419360c63aeadd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Nov 2007 11:47:18 -0300 Subject: V4L/DVB (6662): Fix standard selection for PAL Not all 8MHz firmware are marked with F8MHz. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index a43a3398b7c..1f14892a883 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -734,6 +734,9 @@ skip_base: new_fw.id |= parse_audio_std_option(); rc = load_firmware(fe, new_fw.type, &new_fw.id); + if (rc == -ENOENT) + rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); + if (rc < 0) goto fail; -- cgit v1.2.3 From 5a9dfc34fcee89ca399cf201a0904675e87c9576 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Nov 2007 14:20:24 -0300 Subject: V4L/DVB (6664): Add missing USB ID's at CARDLIST.em28xx Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 94b53bd7130..ceb277543f5 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -8,10 +8,10 @@ 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) 9 -> Pinnacle Dazzle DVC 90 (em2820/em2840) [2304:0207] - 10 -> Hauppauge WinTV HVR 900 (em2880) - 11 -> Terratec Hybrid XS (em2880) + 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] + 11 -> Terratec Hybrid XS (em2880) [0ccd:0042] 12 -> Kworld PVR TV 2800 RF (em2820/em2840) - 13 -> Terratec Prodigy XS (em2880) + 13 -> Terratec Prodigy XS (em2880) [0ccd:0047] 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) 15 -> V-Gear PocketTV (em2800) - 16 -> Hauppauge WinTV HVR 950 (em2880) + 16 -> Hauppauge WinTV HVR 950 (em2880) [2040:6513] -- cgit v1.2.3 From c23f5949c0eeec328c872f29c8f4c233e73c3c4d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Nov 2007 14:22:14 -0300 Subject: V4L/DVB (6665): Fix CodingStyle thanks to checkpatch.pl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 203 +++++++++++++++++------------- 1 file changed, 113 insertions(+), 90 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 29e935f4109..c4204c90fb0 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1,5 +1,6 @@ /* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices + em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB + video capture devices Copyright (C) 2005 Ludovico Cavedon Markus Rechberger @@ -55,15 +56,15 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_UNKNOWN] = { .name = "Unknown EM2750/28xx video grabber", @@ -76,15 +77,15 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_TERRATEC_CINERGY_250] = { .name = "Terratec Cinergy 250 USB", @@ -93,19 +94,19 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_PINNACLE_USB_2] = { .name = "Pinnacle PCTV USB 2", @@ -114,39 +115,41 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { .name = "Hauppauge WinTV USB 2", .vchannels = 3, .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE| + TDA9887_PORT2_ACTIVE, .has_tuner = 1, .decoder = EM28XX_TVP5150, .has_msp34xx = 1, /*FIXME: S-Video not tested */ - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = MSP_INPUT_DEFAULT, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), - }}, + } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900", @@ -156,19 +159,19 @@ struct em28xx_board em28xx_boards[] = { .has_tuner = 1, .mts_firmware = 1, .decoder = EM28XX_TVP5150, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = 1, - }}, + } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", @@ -177,19 +180,19 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_XC2028, .has_tuner = 1, .decoder = EM28XX_TVP5150, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = 1, - }}, + } }, }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", @@ -198,22 +201,23 @@ struct em28xx_board em28xx_boards[] = { .has_tuner = 1, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = 1, - }}, + } }, }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS as Prodigy XS with a - * different PID, let's keep it separated for now maybe we'll need it lateron */ + /* maybe there's a reason behind it why Terratec sells the Hybrid XS + as Prodigy XS with a different PID, let's keep it separated for now + maybe we'll need it lateron */ [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .vchannels = 3, @@ -221,40 +225,42 @@ struct em28xx_board em28xx_boards[] = { .has_tuner = 1, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = 1, - }}, + } }, }, [EM2820_BOARD_MSI_VOX_USB_2] = { .name = "MSI VOX USB 2.0", .vchannels = 3, .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, .has_tuner = 1, .decoder = EM28XX_SAA7114, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE4, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2800_BOARD_TERRATEC_CINERGY_200] = { .name = "Terratec Cinergy 200 USB", @@ -264,19 +270,19 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { .name = "Leadtek Winfast USB II", @@ -286,19 +292,19 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2800_BOARD_KWORLD_USB2800] = { .name = "Kworld USB2800", @@ -308,34 +314,34 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90", .vchannels = 3, .has_tuner = 0, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2800_BOARD_VGEAR_POCKETTV] = { .name = "V-Gear PocketTV", @@ -345,19 +351,19 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { .name = "Pixelview Prolink PlayTV USB 2.0", @@ -365,56 +371,73 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table [] = { - { USB_DEVICE(0xeb1a, 0x2750), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2821), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2860), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2861), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2870), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2881), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2883), .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, - { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, - { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0xeb1a, 0x2750), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2800), + .driver_info = EM2800_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2820), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2821), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2860), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2861), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2870), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2881), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2883), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0x0ccd, 0x0036), + .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, + { USB_DEVICE(0x2304, 0x0208), + .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x2040, 0x4200), + .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, + { USB_DEVICE(0x2304, 0x0207), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2040, 0x6500), + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6513), + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x0ccd, 0x0042), + .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0047), + .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, }; -MODULE_DEVICE_TABLE (usb, em28xx_id_table); +MODULE_DEVICE_TABLE(usb, em28xx_id_table); /* EEPROM hash table for devices with generic USB IDs */ static struct em28xx_hash_table em28xx_eeprom_hash [] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ - { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, + {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, }; /* I2C devicelist hash table for devices with generic USB IDs */ static struct em28xx_hash_table em28xx_i2c_hash[] = { - { 0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC }, - { 0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC }, + {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, + {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, }; /* Since em28xx_pre_card_setup() requires a proper dev->model, @@ -423,7 +446,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { void em28xx_pre_card_setup(struct em28xx *dev) { /* request some modules */ - switch(dev->model){ + switch (dev->model) { case EM2880_BOARD_TERRATEC_PRODIGY_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: @@ -454,7 +477,7 @@ static int em28xx_tuner_callback(void *ptr, int command, int arg) return rc; } -static void em28xx_config_tuner (struct em28xx *dev) +static void em28xx_config_tuner(struct em28xx *dev) { struct v4l2_priv_tun_config xc2028_cfg; struct xc2028_ctrl ctl; @@ -472,7 +495,7 @@ static void em28xx_config_tuner (struct em28xx *dev) em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); if (dev->tuner_type == TUNER_XC2028) { - memset (&ctl, 0, sizeof(ctl)); + memset(&ctl, 0, sizeof(ctl)); ctl.fname = XC2028_DEFAULT_FIRMWARE; ctl.max_len = 64; @@ -648,5 +671,5 @@ void em28xx_card_setup(struct em28xx *dev) request_module("tuner"); #endif - em28xx_config_tuner (dev); + em28xx_config_tuner(dev); } -- cgit v1.2.3 From 4c5efc1778387de98d5348666e7bc4396c9a5404 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 25 Nov 2007 19:04:47 -0300 Subject: V4L/DVB (6665a): finish the VID_HARDWARE_* removal This patch removes a few remainders of the VID_HARDWARE_* removal. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab 643d01fb38b6f376cced035549f4e193018776e7 --- Documentation/DocBook/videobook.tmpl | 9 --------- drivers/media/video/usbvision/usbvision.h | 4 ---- 2 files changed, 13 deletions(-) diff --git a/Documentation/DocBook/videobook.tmpl b/Documentation/DocBook/videobook.tmpl index b629da33951..b3d93ee2769 100644 --- a/Documentation/DocBook/videobook.tmpl +++ b/Documentation/DocBook/videobook.tmpl @@ -96,7 +96,6 @@ static struct video_device my_radio { "My radio", VID_TYPE_TUNER, - VID_HARDWARE_MYRADIO, radio_open. radio_close, NULL, /* no read */ @@ -118,13 +117,6 @@ static struct video_device my_radio indicates that the device can be tuned. Clearly our radio is going to have some way to change channel so it is tuneable. - - The VID_HARDWARE_ types are unique to each device. Numbers are assigned by - alan@redhat.com when device drivers are going to be released. Until then you - can pull a suitably large number out of your hat and use it. 10000 should be - safe for a very long time even allowing for the huge number of vendors - making new and different radio cards at the moment. - We declare an open and close routine, but we do not need read or write, which are used to read and write video data to or from the card itself. As @@ -844,7 +836,6 @@ static struct video_device my_camera "My Camera", VID_TYPE_OVERLAY|VID_TYPE_SCALES|\ VID_TYPE_CAPTURE|VID_TYPE_CHROMAKEY, - VID_HARDWARE_MYCAMERA, camera_open. camera_close, camera_read, /* no read */ diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index c32f68566bf..dd80a98780f 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -41,10 +41,6 @@ #define USBVISION_DEBUG /* Turn on debug messages */ -#ifndef VID_HARDWARE_USBVISION - #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ -#endif - #define USBVISION_PWR_REG 0x00 #define USBVISION_SSPND_EN (1 << 1) #define USBVISION_RES2 (1 << 2) -- cgit v1.2.3 From 91821ff3f958c16bf84d02258dd79da792c66ca8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 2 Dec 2007 09:35:33 -0300 Subject: V4L/DVB (6665b): add ivtv to MAINTAINERS Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2340cfb1e25..17524afa747 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2141,6 +2141,15 @@ L: isdn4linux@listserv.isdn4linux.de W: http://www.melware.de S: Maintained +IVTV VIDEO4LINUX DRIVER +P: Hans Verkuil +M: hverkuil@xs4all.nl +L: ivtv-devel@ivtvdriver.org +L: ivtv-users@ivtvdriver.org +L: video4linux-list@redhat.com +W: http://www.ivtvdriver.org +S: Maintained + JOURNALLING FLASH FILE SYSTEM V2 (JFFS2) P: David Woodhouse M: dwmw2@infradead.org -- cgit v1.2.3 From 0d65cd4f2bfe70872e4218d9d35d37a7000d6739 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 4 Nov 2007 17:59:28 -0300 Subject: V4L/DVB (6667): Fix access to configuration space while in D3 pci_save_state should be called before pci_set_power_state and pci_restore_state after pci_set_power_state Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 76410f5bdcd..40cdec26a7f 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1194,10 +1194,10 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) if (dev->remote) saa7134_ir_stop(dev); - pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); pci_save_state(pci_dev); + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); - return 0; + return 0; } static int saa7134_resume(struct pci_dev *pci_dev) @@ -1205,8 +1205,8 @@ static int saa7134_resume(struct pci_dev *pci_dev) struct saa7134_dev *dev = pci_get_drvdata(pci_dev); unsigned long flags; - pci_restore_state(pci_dev); pci_set_power_state(pci_dev, PCI_D0); + pci_restore_state(pci_dev); /* Do things that are done in saa7134_initdev , except of initializing memory structures.*/ -- cgit v1.2.3 From 3203cb86d22c63504f8368151029bf9dad014ddb Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 4 Nov 2007 19:34:23 -0300 Subject: V4L/DVB (6668): Fix theoretical races between IRQ handler and .suspend/resume *dev->insuspend = 1 should be set before synchronize_irq *ACK interrupts after synchronize_irq, to make sure there aren't pending interrupts. *Add barrier before we restart interrupts so the handler will 100% see the dev->insuspend Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 40cdec26a7f..85c165d1730 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1181,8 +1181,13 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) saa_writel(SAA7134_IRQ2, 0); saa_writel(SAA7134_MAIN_CTRL, 0); - synchronize_irq(pci_dev->irq); dev->insuspend = 1; + synchronize_irq(pci_dev->irq); + + /* ACK interrupts once more, just in case, + since the IRQ handler won't ack them anymore*/ + + saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT)); /* Disable timeout timers - if we have active buffers, we will fill them on resume*/ @@ -1246,6 +1251,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) /* start DMA now*/ dev->insuspend = 0; + smp_wmb(); saa7134_set_dmabits(dev); spin_unlock_irqrestore(&dev->slock, flags); -- cgit v1.2.3 From 5c01203fd289214ae3062dab4039fcbab4b2b84f Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 4 Nov 2007 18:21:25 -0300 Subject: V4L/DVB (6669): Add few missing bits of code to saa7134_resume First the saa7134_initdev waits between saa7134_hwinit1 and saa7134_hwinit2 , thus it is probably wise to do the same in saa7134_resume some hardware probably needs this. Call saa7134_irq_video_signalchange in .resume like in saa7134_resume to make saa7134_resume mirror perfectly the saa7134_initdev although this call isn't strictly necessary in the saa7134_initdev, but it won't harm anyway. Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 85c165d1730..f5e43d375d2 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1227,6 +1227,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_ir_start(dev, dev->remote); saa7134_hw_enable1(dev); + msleep(100); saa7134_board_init2(dev); @@ -1238,6 +1239,8 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_enable_i2s(dev); saa7134_hw_enable2(dev); + saa7134_irq_video_signalchange(dev); + /*resume unfinished buffer(s)*/ spin_lock_irqsave(&dev->slock, flags); saa7134_buffer_requeue(dev, &dev->video_q); -- cgit v1.2.3 From f36224d3992a7734349cdd6289ff73c3d007ce09 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Tue, 23 Oct 2007 00:58:59 -0300 Subject: V4L/DVB (6670): V4L: saa7134: tvaudio cleanups move some tv-audio initialization code out of tvaudio thread, and call it on resume too. Signed-off-by: Maxim Levitsky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 1 + drivers/media/video/saa7134/saa7134-tvaudio.c | 79 +++++++++++++-------------- drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index f5e43d375d2..cbddd35f161 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1235,6 +1235,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_set_tvnorm_hw(dev); saa7134_tvaudio_setmute(dev); saa7134_tvaudio_setvolume(dev, dev->ctl_volume); + saa7134_tvaudio_init(dev); saa7134_tvaudio_do_scan(dev); saa7134_enable_i2s(dev); saa7134_hw_enable2(dev); diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index f8e304c7623..4e9810469ae 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -163,32 +163,6 @@ static struct saa7134_tvaudio tvaudio[] = { /* ------------------------------------------------------------------ */ -static void tvaudio_init(struct saa7134_dev *dev) -{ - int clock = saa7134_boards[dev->board].audio_clock; - - if (UNSET != audio_clock_override) - clock = audio_clock_override; - - /* init all audio registers */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); - if (need_resched()) - schedule(); - else - udelay(10); - - saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); - /* frame locked audio is mandatory for NICAM */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); - - saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); - saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); - saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); - saa_writeb(SAA7134_FM_DEMATRIX, 0x80); -} - static u32 tvaudio_carr2reg(u32 carrier) { u64 a = carrier; @@ -517,9 +491,13 @@ static int tvaudio_thread(void *data) dev->thread.scan1 = dev->thread.scan2; dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); dev->tvaudio = NULL; - tvaudio_init(dev); + + saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); + saa_writeb(SAA7134_FM_DEMATRIX, 0x80); + if (dev->ctl_automute) dev->automute = 1; + mute_input_7134(dev); /* give the tuner some time */ @@ -784,27 +762,15 @@ static int mute_input_7133(struct saa7134_dev *dev) static int tvaudio_thread_ddep(void *data) { struct saa7134_dev *dev = data; - u32 value, norms, clock; + u32 value, norms; set_freezable(); - - clock = saa7134_boards[dev->board].audio_clock; - if (UNSET != audio_clock_override) - clock = audio_clock_override; - saa_writel(0x598 >> 2, clock); - - /* unmute */ - saa_dsp_writel(dev, 0x474 >> 2, 0x00); - saa_dsp_writel(dev, 0x450 >> 2, 0x00); - for (;;) { tvaudio_sleep(dev,-1); if (kthread_should_stop()) goto done; - restart: - try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; @@ -978,6 +944,38 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev) return retval; } +void saa7134_tvaudio_init(struct saa7134_dev *dev) +{ + int clock = saa7134_boards[dev->board].audio_clock; + + if (UNSET != audio_clock_override) + clock = audio_clock_override; + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + /* init all audio registers */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); + if (need_resched()) + schedule(); + else + udelay(10); + + saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); + /* frame locked audio is mandatory for NICAM */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); + saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); + saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + saa_writel(0x598 >> 2, clock); + saa_dsp_writel(dev, 0x474 >> 2, 0x00); + saa_dsp_writel(dev, 0x450 >> 2, 0x00); + } +} + int saa7134_tvaudio_init2(struct saa7134_dev *dev) { int (*my_thread)(void *data) = NULL; @@ -994,6 +992,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) dev->thread.thread = NULL; if (my_thread) { + saa7134_tvaudio_init(dev); /* start tvaudio thread */ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); if (IS_ERR(dev->thread.thread)) { diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index a531e3c6c94..5c5b0741307 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -678,6 +678,7 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev, void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level); int saa7134_tvaudio_getstereo(struct saa7134_dev *dev); +void saa7134_tvaudio_init(struct saa7134_dev *dev); int saa7134_tvaudio_init2(struct saa7134_dev *dev); int saa7134_tvaudio_fini(struct saa7134_dev *dev); int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); -- cgit v1.2.3 From 00deff1a076dc1cf6743813657623626720bf0f5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 24 Nov 2007 10:13:42 -0300 Subject: V4L/DVB (6671): Avoids checking digital/analog at check_firmware Since check_firmware is called via analog or digital set freq routines, move type selection to those routines. This avoids having several if's at the code, and simplifies the source code. A sideback effect is that implementing radio and other dvb types will become simpler. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 106 +++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 1f14892a883..94f367ab571 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -608,15 +608,14 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, return 0; } -static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, - v4l2_std_id std, fe_bandwidth_t bandwidth) +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std) { - struct xc2028_data *priv = fe->tuner_priv; - int rc = 0, is_retry = 0; - unsigned int type = 0; + struct xc2028_data *priv = fe->tuner_priv; struct firmware_properties new_fw; - u16 version, hwmodel; - v4l2_std_id std0; + int rc = 0, is_retry = 0; + u16 version, hwmodel; + v4l2_std_id std0; tuner_dbg("%s called\n", __FUNCTION__); @@ -633,32 +632,6 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, if (priv->ctrl.mts) type |= MTS; - if (bandwidth == BANDWIDTH_7_MHZ || bandwidth == BANDWIDTH_8_MHZ) - type |= F8MHZ; - - /* FIXME: How to load FM and FM|INPUT1 firmwares? */ - - if (new_mode == T_DIGITAL_TV) { - if (priv->ctrl.d2633) - type |= D2633; - else - type |= D2620; - - switch (bandwidth) { - case BANDWIDTH_8_MHZ: - type |= DTV8; - break; - case BANDWIDTH_7_MHZ: - type |= DTV7; - break; - case BANDWIDTH_6_MHZ: - /* FIXME: Should allow select also ATSC */ - type |= DTV6 | QAM; - break; - default: - tuner_err("error: bandwidth not supported.\n"); - }; - } retry: new_fw.type = type; @@ -729,10 +702,6 @@ skip_base: /* Reloading std-specific firmware forces a SCODE update */ priv->cur_fw.scode_table = 0; - /* Add audio hack to std mask */ - if (new_mode == T_ANALOG_TV) - new_fw.id |= parse_audio_std_option(); - rc = load_firmware(fe, new_fw.type, &new_fw.id); if (rc == -ENOENT) rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); @@ -840,9 +809,10 @@ ret: #define DIV 15625 -static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , +static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, enum tuner_mode new_mode, - v4l2_std_id std, fe_bandwidth_t bandwidth) + unsigned int type, + v4l2_std_id std) { struct xc2028_data *priv = fe->tuner_priv; int rc = -EINVAL; @@ -855,7 +825,7 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , tuner_dbg("should set frequency %d kHz\n", freq / 1000); - if (check_firmware(fe, new_mode, std, bandwidth) < 0) + if (check_firmware(fe, type, std) < 0) goto ret; /* On some cases xc2028 can disable video output, if @@ -865,10 +835,9 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ , * that xc2028 will be in a safe state. * Maybe this might also be needed for DTV. */ - if (new_mode != T_DIGITAL_TV) + if (new_mode == T_ANALOG_TV) { rc = send_seq(priv, {0x00, 0x00}); - - if (new_mode == T_DIGITAL_TV) { + } else { offset = 2750000; if (priv->cur_fw.type & DTV7) offset -= 500000; @@ -914,32 +883,35 @@ ret: return rc; } -static int xc2028_set_tv_freq(struct dvb_frontend *fe, +static int xc2028_set_analog_freq(struct dvb_frontend *fe, struct analog_parameters *p) { struct xc2028_data *priv = fe->tuner_priv; - fe_bandwidth_t bw; + unsigned int type=0; + + tuner_dbg("%s called\n", __FUNCTION__); /* if std is not defined, choose one */ if (!p->std) p->std = V4L2_STD_MN; /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ - if (p->std & V4L2_STD_MN) - bw = BANDWIDTH_6_MHZ; - else - bw = BANDWIDTH_8_MHZ; + if (!(p->std & V4L2_STD_MN)) + type |= F8MHZ; - tuner_dbg("%s called\n", __FUNCTION__); + /* Add audio hack to std mask */ + p->std |= parse_audio_std_option(); - return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV, - p->std, bw); + return generic_set_freq(fe, 62500l * p->frequency, + T_ANALOG_TV, type, p->std); } static int xc2028_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct xc2028_data *priv = fe->tuner_priv; + unsigned int type=0; + fe_bandwidth_t bw; tuner_dbg("%s called\n", __FUNCTION__); @@ -948,11 +920,33 @@ static int xc2028_set_params(struct dvb_frontend *fe, tuner_err("DTV type not implemented.\n"); return -EINVAL; } + bw = p->u.ofdm.bandwidth; - return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV, - 0 /* NOT USED */, - p->u.ofdm.bandwidth); + if (bw == BANDWIDTH_7_MHZ || bw == BANDWIDTH_8_MHZ) + type |= F8MHZ; + if (priv->ctrl.d2633) + type |= D2633; + else + type |= D2620; + + switch (bw) { + case BANDWIDTH_8_MHZ: + type |= DTV8; + break; + case BANDWIDTH_7_MHZ: + type |= DTV7; + break; + case BANDWIDTH_6_MHZ: + /* FIXME: Should allow select also ATSC */ + type |= DTV6 | QAM; + break; + default: + tuner_err("error: bandwidth not supported.\n"); + }; + + return generic_set_freq(fe, p->frequency, + T_DIGITAL_TV, type, 0); } static int xc2028_sleep(struct dvb_frontend *fe) @@ -1052,7 +1046,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { }, .set_config = xc2028_set_config, - .set_analog_params = xc2028_set_tv_freq, + .set_analog_params = xc2028_set_analog_freq, .release = xc2028_dvb_release, .get_frequency = xc2028_get_frequency, .get_rf_strength = xc2028_signal, -- cgit v1.2.3 From d74cb25e427e2ef979107cbed67d39eba53a6b0f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 24 Nov 2007 10:20:15 -0300 Subject: V4L/DVB (6672): Add support for radio Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 8 ++++++++ drivers/media/video/tuner-xc2028.h | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 94f367ab571..cef170cc2ad 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -891,6 +891,14 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, tuner_dbg("%s called\n", __FUNCTION__); + if (p->mode == V4L2_TUNER_RADIO) { + type |= FM; + if (priv->ctrl.input1) + type |= INPUT1; + return generic_set_freq(fe, (625l * p->frequency) / 10, + T_ANALOG_TV, type, 0); + } + /* if std is not defined, choose one */ if (!p->std) p->std = V4L2_STD_MN; diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index a59d00fb2a3..02e116b5459 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -15,8 +15,9 @@ struct xc2028_ctrl { char *fname; int max_len; unsigned int scode_table; - unsigned int mts :1; - unsigned int d2633:1; + unsigned int mts :1; + unsigned int d2633 :1; + unsigned int input1:1; }; struct xc2028_config { -- cgit v1.2.3 From d04aa54a27f7bc6f051e55c47abbc0a1db1718bc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 24 Nov 2007 10:47:03 -0300 Subject: V4L/DVB (6674): Add support for other DTV types Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 42 ++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index cef170cc2ad..42fb141fc38 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -919,35 +919,47 @@ static int xc2028_set_params(struct dvb_frontend *fe, { struct xc2028_data *priv = fe->tuner_priv; unsigned int type=0; - fe_bandwidth_t bw; + fe_bandwidth_t bw = BANDWIDTH_8_MHZ; tuner_dbg("%s called\n", __FUNCTION__); - /* FIXME: Only OFDM implemented */ - if (fe->ops.info.type != FE_OFDM) { - tuner_err("DTV type not implemented.\n"); - return -EINVAL; - } - bw = p->u.ofdm.bandwidth; - - if (bw == BANDWIDTH_7_MHZ || bw == BANDWIDTH_8_MHZ) - type |= F8MHZ; - if (priv->ctrl.d2633) type |= D2633; else type |= D2620; + switch(fe->ops.info.type) { + case FE_QPSK: + break; + case FE_OFDM: + bw = p->u.ofdm.bandwidth; + break; + case FE_QAM: + bw = BANDWIDTH_6_MHZ; + type |= QAM; + break; + case FE_ATSC: + bw = BANDWIDTH_6_MHZ; + type |= ATSC| D2633; + break; + } + + bw = p->u.ofdm.bandwidth; + + /* FIXME: + There are two Scodes that will never be selected: + DTV78 ZARLINK456, DTV78 DIBCOM52 + When it should opt for DTV78 instead of DTV7 or DTV8? + */ switch (bw) { case BANDWIDTH_8_MHZ: - type |= DTV8; + type |= DTV8 | F8MHZ; break; case BANDWIDTH_7_MHZ: - type |= DTV7; + type |= DTV7 | F8MHZ; break; case BANDWIDTH_6_MHZ: - /* FIXME: Should allow select also ATSC */ - type |= DTV6 | QAM; + type |= DTV6 ; break; default: tuner_err("error: bandwidth not supported.\n"); -- cgit v1.2.3 From b542dfdc9f6e6eaf3cc2ede27dbaf50425f8b4b5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 24 Nov 2007 11:07:12 -0300 Subject: V4L/DVB (6675): Allow selecting the proper SCode table for DTV Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 18 ++++++++++++++++++ drivers/media/video/tuner-xc2028.h | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 42fb141fc38..9743331c895 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -914,6 +914,19 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, T_ANALOG_TV, type, p->std); } +static unsigned int demod_type [] = { + [XC3028_FE_DEFAULT] = 0, + [XC3028_FE_LG60] = LG60, + [XC3028_FE_ATI638] = ATI638, + [XC3028_FE_OREN538] = OREN538, + [XC3028_FE_OREN36] = OREN36, + [XC3028_FE_TOYOTA388] = TOYOTA388, + [XC3028_FE_TOYOTA794] = TOYOTA794, + [XC3028_FE_DIBCOM52] = DIBCOM52, + [XC3028_FE_ZARLINK456] = ZARLINK456, + [XC3028_FE_CHINA] = CHINA, +}; + static int xc2028_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { @@ -965,6 +978,11 @@ static int xc2028_set_params(struct dvb_frontend *fe, tuner_err("error: bandwidth not supported.\n"); }; + if (priv->ctrl.demod < 0 || priv->ctrl.demod > ARRAY_SIZE(demod_type)) + tuner_err("error: demod type invalid. Assuming default.\n"); + else + type |= demod_type[priv->ctrl.demod]; + return generic_set_freq(fe, p->frequency, T_DIGITAL_TV, type, 0); } diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 02e116b5459..9b4224e2fe5 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -11,6 +11,20 @@ #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" +enum xc2028_demod_types +{ + XC3028_FE_DEFAULT = 0, + XC3028_FE_LG60, /* IF = 6.00 MHz */ + XC3028_FE_ATI638, /* IF = 6.38 MHz */ + XC3028_FE_OREN538, /* IF = 5.38 MHz */ + XC3028_FE_OREN36, /* IF = 3.60 MHz */ + XC3028_FE_TOYOTA388, /* IF = 3.88 MHz */ + XC3028_FE_TOYOTA794, /* IF = 7.94 MHz */ + XC3028_FE_DIBCOM52, /* IF = 5.20 MHz */ + XC3028_FE_ZARLINK456, /* IF = 4.56 MHz */ + XC3028_FE_CHINA, /* IF = 5.20 MHz */ +}; + struct xc2028_ctrl { char *fname; int max_len; @@ -18,6 +32,7 @@ struct xc2028_ctrl { unsigned int mts :1; unsigned int d2633 :1; unsigned int input1:1; + enum xc2028_demod_types demod; }; struct xc2028_config { -- cgit v1.2.3 From 66c2d53db28276fe49b49745230b7ac8d8fd5f47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 25 Nov 2007 19:26:36 -0300 Subject: V4L/DVB (6676): Improve s-code support s-code tables are related to IF frequency used for video demodulation. The s-codes for analog are automatically loaded, according with video standard. However, for digital, they will depend on the IF of the demoduler chip. IF of the demoduler. Before this patch, only a few IF's where possible to use. This patch allows selecting any IF defined at firmware file. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028-types.h | 3 ++ drivers/media/video/tuner-xc2028.c | 88 ++++++++++++++++++-------------- drivers/media/video/tuner-xc2028.h | 26 +++++----- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index c0dc6ec19f0..d0057fbf0ec 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -82,6 +82,9 @@ #define INPUT2 (1 << 28) #define SCODE (1 << 29) +/* This flag identifies that the scode table has a new format */ +#define HAS_IF (1 << 30) + #define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 9743331c895..cf72f22986a 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -50,6 +50,7 @@ static DEFINE_MUTEX(xc2028_list_mutex); struct firmware_description { unsigned int type; v4l2_std_id id; + __u16 int_freq; unsigned char *ptr; unsigned int size; }; @@ -58,6 +59,7 @@ struct firmware_properties { unsigned int type; v4l2_std_id id; v4l2_std_id std_req; + __u16 int_freq; unsigned int scode_table; int scode_nr; }; @@ -301,6 +303,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) while (p < endp) { __u32 type, size; v4l2_std_id id; + __u16 int_freq = 0; n++; if (n >= n_array) { @@ -321,6 +324,11 @@ static int load_all_firmwares(struct dvb_frontend *fe) id = le64_to_cpu(*(v4l2_std_id *) p); p += sizeof(id); + if (type & HAS_IF) { + int_freq = le16_to_cpu(*(__u16 *) p); + p += sizeof(int_freq); + } + size = le32_to_cpu(*(__u32 *) p); p += sizeof(size); @@ -351,6 +359,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) priv->firm[n].type = type; priv->firm[n].id = id; priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; p += size; } @@ -565,7 +574,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, } static int load_scode(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id, int scode) + v4l2_std_id *id, __u16 int_freq, int scode) { struct xc2028_data *priv = fe->tuner_priv; int pos, rc; @@ -573,17 +582,34 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, tuner_dbg("%s called\n", __FUNCTION__); - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } p = priv->firm[pos].ptr; - /* 16 SCODE entries per file; each SCODE entry is 12 bytes and - * has a 2-byte size header in the firmware format. */ - if (priv->firm[pos].size != 14 * 16 || scode >= 16 || - le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) - return -EINVAL; + if (type & HAS_IF) { + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + } else { + /* 16 SCODE entries per file; each SCODE entry is 12 bytes and + * has a 2-byte size header in the firmware format. */ + if (priv->firm[pos].size != 14 * 16 || scode >= 16 || + le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) + return -EINVAL; + p += 14 * scode + 2; + } tuner_info("Loading SCODE for type="); dump_firm_type(priv->firm[pos].type); @@ -597,7 +623,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, if (rc < 0) return -EIO; - rc = i2c_send(priv, p + 14 * scode + 2, 12); + rc = i2c_send(priv, p, 12); if (rc < 0) return -EIO; @@ -609,7 +635,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, } static int check_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id std) + v4l2_std_id std, __u16 int_freq) { struct xc2028_data *priv = fe->tuner_priv; struct firmware_properties new_fw; @@ -639,6 +665,7 @@ retry: new_fw.std_req = std; new_fw.scode_table = SCODE | priv->ctrl.scode_table; new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; tuner_dbg("checking firmware, user requested type="); if (debug) { @@ -719,8 +746,8 @@ skip_std_specific: /* Load SCODE firmware, if exists */ tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); - rc = load_scode(fe, new_fw.type | new_fw.scode_table, - &new_fw.id, new_fw.scode_nr); + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); check_device: if (xc2028_get_reg(priv, 0x0004, &version) < 0 || @@ -810,9 +837,10 @@ ret: #define DIV 15625 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, - enum tuner_mode new_mode, - unsigned int type, - v4l2_std_id std) + enum tuner_mode new_mode, + unsigned int type, + v4l2_std_id std, + u16 int_freq) { struct xc2028_data *priv = fe->tuner_priv; int rc = -EINVAL; @@ -825,7 +853,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, tuner_dbg("should set frequency %d kHz\n", freq / 1000); - if (check_firmware(fe, type, std) < 0) + if (check_firmware(fe, type, std, int_freq) < 0) goto ret; /* On some cases xc2028 can disable video output, if @@ -896,7 +924,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, if (priv->ctrl.input1) type |= INPUT1; return generic_set_freq(fe, (625l * p->frequency) / 10, - T_ANALOG_TV, type, 0); + T_ANALOG_TV, type, 0, 0); } /* if std is not defined, choose one */ @@ -911,22 +939,9 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, p->std |= parse_audio_std_option(); return generic_set_freq(fe, 62500l * p->frequency, - T_ANALOG_TV, type, p->std); + T_ANALOG_TV, type, p->std, 0); } -static unsigned int demod_type [] = { - [XC3028_FE_DEFAULT] = 0, - [XC3028_FE_LG60] = LG60, - [XC3028_FE_ATI638] = ATI638, - [XC3028_FE_OREN538] = OREN538, - [XC3028_FE_OREN36] = OREN36, - [XC3028_FE_TOYOTA388] = TOYOTA388, - [XC3028_FE_TOYOTA794] = TOYOTA794, - [XC3028_FE_DIBCOM52] = DIBCOM52, - [XC3028_FE_ZARLINK456] = ZARLINK456, - [XC3028_FE_CHINA] = CHINA, -}; - static int xc2028_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { @@ -978,13 +993,12 @@ static int xc2028_set_params(struct dvb_frontend *fe, tuner_err("error: bandwidth not supported.\n"); }; - if (priv->ctrl.demod < 0 || priv->ctrl.demod > ARRAY_SIZE(demod_type)) - tuner_err("error: demod type invalid. Assuming default.\n"); - else - type |= demod_type[priv->ctrl.demod]; + /* All S-code tables need a 200kHz shift */ + if (priv->ctrl.demod) + priv->ctrl.demod += 200; return generic_set_freq(fe, p->frequency, - T_DIGITAL_TV, type, 0); + T_DIGITAL_TV, type, 0, priv->ctrl.demod); } static int xc2028_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 9b4224e2fe5..1fe8b195960 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -11,19 +11,17 @@ #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" -enum xc2028_demod_types -{ - XC3028_FE_DEFAULT = 0, - XC3028_FE_LG60, /* IF = 6.00 MHz */ - XC3028_FE_ATI638, /* IF = 6.38 MHz */ - XC3028_FE_OREN538, /* IF = 5.38 MHz */ - XC3028_FE_OREN36, /* IF = 3.60 MHz */ - XC3028_FE_TOYOTA388, /* IF = 3.88 MHz */ - XC3028_FE_TOYOTA794, /* IF = 7.94 MHz */ - XC3028_FE_DIBCOM52, /* IF = 5.20 MHz */ - XC3028_FE_ZARLINK456, /* IF = 4.56 MHz */ - XC3028_FE_CHINA, /* IF = 5.20 MHz */ -}; +/* Dmoduler IF (kHz) */ +#define XC3028_FE_DEFAULT 0 +#define XC3028_FE_LG60 6000 +#define XC3028_FE_ATI638 6380 +#define XC3028_FE_OREN538 5380 +#define XC3028_FE_OREN36 3600 +#define XC3028_FE_TOYOTA388 3880 +#define XC3028_FE_TOYOTA794 7940 +#define XC3028_FE_DIBCOM52 5200 +#define XC3028_FE_ZARLINK456 4560 +#define XC3028_FE_CHINA 5200 struct xc2028_ctrl { char *fname; @@ -32,7 +30,7 @@ struct xc2028_ctrl { unsigned int mts :1; unsigned int d2633 :1; unsigned int input1:1; - enum xc2028_demod_types demod; + unsigned int demod; }; struct xc2028_config { -- cgit v1.2.3 From 63806eeb61dcdf30fdbf488babff98aea2ca3f08 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 25 Nov 2007 19:29:22 -0300 Subject: V4L/DVB (6677): Fix xc2028 driver for non OFDM A previous patch implemented support for non-OFDM digital TV. However, the previous bandwidth ofdm parameter were left at the code by mistake. Thanks to Michael Krufky and Patrick Boettcher for noticing this mistake. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index cf72f22986a..e1796ebb7c7 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -972,8 +972,6 @@ static int xc2028_set_params(struct dvb_frontend *fe, break; } - bw = p->u.ofdm.bandwidth; - /* FIXME: There are two Scodes that will never be selected: DTV78 ZARLINK456, DTV78 DIBCOM52 -- cgit v1.2.3 From 22ee1250bd41534552c61be13994fd12d1ee1318 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 22 Nov 2007 17:13:00 -0300 Subject: V4L/DVB (6678): tda18271: define init callback Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c index aaaa2f88518..ad72ff69ce9 100644 --- a/drivers/media/dvb/frontends/tda18271.c +++ b/drivers/media/dvb/frontends/tda18271.c @@ -429,17 +429,11 @@ static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) /*---------------------------------------------------------------------*/ -static void tda18271_init_regs(struct dvb_frontend *fe) +static int tda18271_init_regs(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - tda18271_read_regs(fe); - - /* test IR_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x08) != 0) - return; - printk(KERN_INFO "tda18271: initializing registers\n"); /* initialize registers */ @@ -616,6 +610,8 @@ static void tda18271_init_regs(struct dvb_frontend *fe) regs[R_EP1] = 0xc6; tda18271_write_regs(fe, R_EP1, 1); + + return 0; } static int tda18271_tune(struct dvb_frontend *fe, @@ -626,10 +622,15 @@ static int tda18271_tune(struct dvb_frontend *fe, u32 div, N = 0; int i; + tda18271_read_regs(fe); + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) == 0) + tda18271_init_regs(fe); + dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); - tda18271_init_regs(fe); /* RF tracking filter calibration */ /* calculate BP_Filter */ @@ -1024,6 +1025,7 @@ static struct dvb_tuner_ops tda18271_tuner_ops = { .frequency_max = 864000000, .frequency_step = 62500 }, + .init = tda18271_init_regs, .set_params = tda18271_set_params, .set_analog_params = tda18271_set_analog_params, .release = tda18271_release, -- cgit v1.2.3 From 63c254805e38bad4c64b5f5b0e135a2a357fa0bf Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 23 Nov 2007 15:08:11 -0300 Subject: V4L/DVB (6679): tda8290: force tuner init after attach Force tuner init after attach, then sleep until use. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index c606f3c38cf..09efb6a60db 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -597,13 +597,13 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) tda827x_attach(&t->fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); - - /* FIXME: tda827x module doesn't probe the tuner until - * tda827x_initial_sleep is called - */ - if (t->fe.ops.tuner_ops.sleep) - t->fe.ops.tuner_ops.sleep(&t->fe); } + if (t->fe.ops.tuner_ops.init) + t->fe.ops.tuner_ops.init(&t->fe); + + if (t->fe.ops.tuner_ops.sleep) + t->fe.ops.tuner_ops.sleep(&t->fe); + ops->i2c_gate_ctrl(fe, 0); switch (priv->ver) { -- cgit v1.2.3 From 6ca04de36b05aaf2f8122d0e566940969c6df801 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 23 Nov 2007 16:52:15 -0300 Subject: V4L/DVB (6680): tda18271: move tda18271_map tables to a separate source file Move tda18271_map tables to a separate source file, to improve code readability and ease maintenance. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Makefile | 2 + drivers/media/dvb/frontends/tda18271-fe.c | 784 ++++++++++++++++++ drivers/media/dvb/frontends/tda18271-priv.h | 96 +++ drivers/media/dvb/frontends/tda18271-tables.c | 253 ++++++ drivers/media/dvb/frontends/tda18271.c | 1067 ------------------------- 5 files changed, 1135 insertions(+), 1067 deletions(-) create mode 100644 drivers/media/dvb/frontends/tda18271-fe.c create mode 100644 drivers/media/dvb/frontends/tda18271-priv.h create mode 100644 drivers/media/dvb/frontends/tda18271-tables.c delete mode 100644 drivers/media/dvb/frontends/tda18271.c diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 57e5fa80589..784565208fb 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -5,6 +5,8 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/video/ +tda18271-objs := tda18271-tables.o tda18271-fe.o + obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o obj-$(CONFIG_DVB_SP8870) += sp8870.o diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c new file mode 100644 index 00000000000..ba980cf5811 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -0,0 +1,784 @@ +/* + tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include "tuner-driver.h" + +#include "tda18271.h" +#include "tda18271-priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +#define dprintk(level, fmt, arg...) do {\ + if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) + +/*---------------------------------------------------------------------*/ + +#define TDA18271_ANALOG 0 +#define TDA18271_DIGITAL 1 + +struct tda18271_priv { + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + int mode; + + u32 frequency; + u32 bandwidth; +}; + +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + int ret = 0; + + switch (priv->mode) { + case TDA18271_ANALOG: + if (ops && ops->i2c_gate_ctrl) + ret = ops->i2c_gate_ctrl(fe, enable); + break; + case TDA18271_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + } + + return ret; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + dprintk(1, "=== TDA18271 REG DUMP ===\n"); + dprintk(1, "ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); + dprintk(1, "THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); + dprintk(1, "POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); + dprintk(1, "EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); + dprintk(1, "EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); + dprintk(1, "EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); + dprintk(1, "EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); + dprintk(1, "EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); + dprintk(1, "CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); + dprintk(1, "CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); + dprintk(1, "CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); + dprintk(1, "CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); + dprintk(1, "MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); + dprintk(1, "MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); + dprintk(1, "MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); + dprintk(1, "MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); +} + +static void tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + printk("ERROR: %s: i2c_transfer returned: %d\n", + __FUNCTION__, ret); + + if (debug > 2) + tda18271_dump_regs(fe); +} + +static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS+1]; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = len+1 }; + int i, ret; + + BUG_ON((len == 0) || (idx+len > sizeof(buf))); + + buf[0] = idx; + for (i = 1; i <= len; i++) { + buf[i] = regs[idx-1+i]; + } + + tda18271_i2c_gate_ctrl(fe, 1); + + /* write registers */ + ret = i2c_transfer(priv->i2c_adap, &msg, 1); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 1) + printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", + __FUNCTION__, ret); +} + +/*---------------------------------------------------------------------*/ + +static int tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + printk(KERN_INFO "tda18271: initializing registers\n"); + + /* initialize registers */ + regs[R_ID] = 0x83; + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + regs[R_EB1] = 0xff; + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + regs[R_EB12] = 0x0f; + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + regs[R_EB18] = 0x00; + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + regs[R_EB21] = 0x33; + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + /* setup AGC1 & AGC2 */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + regs[R_MD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x87; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + regs[R_CD3] = 0x00; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + regs[R_EP2] = 0xdf; + + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + regs[R_EP1] = 0xc6; + tda18271_write_regs(fe, R_EP1, 1); + + return 0; +} + +static int tda18271_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 div, N = 0; + int i; + + tda18271_read_regs(fe); + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) == 0) + tda18271_init_regs(fe); + + + dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); + + /* RF tracking filter calibration */ + + /* calculate BP_Filter */ + i = 0; + while ((tda18271_bp_filter[i].rfmax * 1000) < freq) { + if (tda18271_bp_filter[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= tda18271_bp_filter[i].val; + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x60; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x60; + tda18271_write_regs(fe, R_EB7, 1); + + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + regs[R_EB20] = 0xcc; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EB4] |= 0x03; + + /* calculate CAL PLL */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 1250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2; + break; + } + + i = 0; + while ((tda18271_cal_pll[i].lomax * 1000) < N) { + if (tda18271_cal_pll[i + 1].lomax == 0) + break; + i++; + } + dprintk(2, "cal pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); + + regs[R_CPD] = tda18271_cal_pll[i].pd; + + div = ((tda18271_cal_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_CD1] = 0xff & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; + + /* calculate MAIN PLL */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2 + 1000000; + break; + } + + i = 0; + while ((tda18271_main_pll[i].lomax * 1000) < N) { + if (tda18271_main_pll[i + 1].lomax == 0) + break; + i++; + } + dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + + regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* RF tracking filter calibration initialization */ + + /* search for K,M,CO for RF Calibration */ + i = 0; + while ((tda18271_km[i].rfmax * 1000) < freq) { + if (tda18271_km[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "km = 0x%x, i = %d\n", tda18271_km[i].val, i); + + regs[R_EB13] &= 0x83; + regs[R_EB13] |= tda18271_km[i].val; + tda18271_write_regs(fe, R_EB13, 1); + + /* search for RF_BAND */ + i = 0; + while ((tda18271_rf_band[i].rfmax * 1000) < freq) { + if (tda18271_rf_band[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (tda18271_rf_band[i].val << 5); + + /* search for Gain_Taper */ + i = 0; + while ((tda18271_gain_taper[i].rfmax * 1000) < freq) { + if (tda18271_gain_taper[i + 1].rfmax == 0) + break; + i++; + } + dprintk(2, "gain taper = 0x%x, i = %d\n", + tda18271_gain_taper[i].val, i); + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= tda18271_gain_taper[i].val; + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x40; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x40; + tda18271_write_regs(fe, R_EB7, 1); + msleep(10); + + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + msleep(60); /* RF tracking filter calibration completion */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + tda18271_write_regs(fe, R_EP4, 1); + + tda18271_write_regs(fe, R_EP1, 1); + + /* RF tracking filer correction for VHF_Low band */ + i = 0; + while ((tda18271_rf_cal[i].rfmax * 1000) < freq) { + if (tda18271_rf_cal[i].rfmax == 0) + break; + i++; + } + dprintk(2, "rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); + + /* VHF_Low band only */ + if (tda18271_rf_cal[i].rfmax != 0) { + regs[R_EB14] = tda18271_rf_cal[i].val; + tda18271_write_regs(fe, R_EB14, 1); + } + + /* Channel Configuration */ + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_EB22] = 0x2c; + break; + case TDA18271_DIGITAL: + regs[R_EB22] = 0x37; + break; + } + tda18271_write_regs(fe, R_EB22, 1); + + regs[R_EP1] |= 0x40; /* set dis power level on */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + + /* see table 22 */ + regs[R_EP3] |= std; + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_EP4] |= 0x04; + regs[R_MPD] |= 0x80; + break; + } + + regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ + + /* FIXME: image rejection validity EP5[2:0] */ + + /* calculate MAIN PLL */ + N = freq + ifc; + + i = 0; + while ((tda18271_main_pll[i].lomax * 1000) < N) { + if (tda18271_main_pll[i + 1].lomax == 0) + break; + i++; + } + dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + + regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + tda18271_write_regs(fe, R_TM, 15); + msleep(5); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + u8 std; + u32 bw, sgIF = 0; + + u32 freq = params->frequency; + + priv->mode = TDA18271_DIGITAL; + + /* see table 22 */ + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + std = 0x1b; /* device-specific (spec says 0x1c) */ + sgIF = 5380000; + break; + case QAM_64: + case QAM_256: + std = 0x18; /* device-specific (spec says 0x1d) */ + sgIF = 4000000; + break; + default: + printk(KERN_WARNING "%s: modulation not set!\n", + __FUNCTION__); + return -EINVAL; + } + freq += 1750000; /* Adjust to center (+1.75MHZ) */ + bw = 6000000; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + std = 0x1b; /* device-specific (spec says 0x1c) */ + bw = 6000000; + sgIF = 3300000; + break; + case BANDWIDTH_7_MHZ: + std = 0x19; /* device-specific (spec says 0x1d) */ + bw = 7000000; + sgIF = 3800000; + break; + case BANDWIDTH_8_MHZ: + std = 0x1a; /* device-specific (spec says 0x1e) */ + bw = 8000000; + sgIF = 4300000; + break; + default: + printk(KERN_WARNING "%s: bandwidth not set!\n", + __FUNCTION__); + return -EINVAL; + } + } else { + printk(KERN_WARNING "%s: modulation type not supported!\n", + __FUNCTION__); + return -EINVAL; + } + + return tda18271_tune(fe, sgIF, freq, bw, std); +} + +static int tda18271_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + u8 std; + unsigned int sgIF; + char *mode; + + priv->mode = TDA18271_ANALOG; + + /* see table 22 */ + if (params->std & V4L2_STD_MN) { + std = 0x0d; + sgIF = 92; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + std = 0x0e; + sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + std = 0x0f; + sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + std = 0x0f; + sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + std = 0x0f; + sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + std = 0x0f; + sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + std = 0x0f; + sgIF = 20; + mode = "LC"; + } else { + std = 0x0f; + sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + sgIF = 88; /* if frequency is 5.5 MHz */ + + dprintk(1, "setting tda18271 to system %s\n", mode); + + return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, + 0, std); +} + +static int tda18271_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static struct dvb_tuner_ops tda18271_tuner_ops = { + .info = { + .name = "NXP TDA18271HD", + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_step = 62500 + }, + .init = tda18271_init_regs, + .set_params = tda18271_set_params, + .set_analog_params = tda18271_set_analog_params, + .release = tda18271_release, + .get_frequency = tda18271_get_frequency, + .get_bandwidth = tda18271_get_bandwidth, +}; + +struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c) +{ + struct tda18271_priv *priv = NULL; + + dprintk(1, "@ %d-%04x\n", i2c_adapter_id(i2c), addr); + priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL_GPL(tda18271_attach); +MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); +MODULE_AUTHOR("Michael Krufky "); +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h new file mode 100644 index 00000000000..71b4d796369 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -0,0 +1,96 @@ +/* + tda18271-priv.h - private header for the NXP TDA18271 silicon tuner + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_PRIV_H__ +#define __TDA18271_PRIV_H__ + +#include + +#define R_ID 0x00 /* ID byte */ +#define R_TM 0x01 /* Thermo byte */ +#define R_PL 0x02 /* Power level byte */ +#define R_EP1 0x03 /* Easy Prog byte 1 */ +#define R_EP2 0x04 /* Easy Prog byte 2 */ +#define R_EP3 0x05 /* Easy Prog byte 3 */ +#define R_EP4 0x06 /* Easy Prog byte 4 */ +#define R_EP5 0x07 /* Easy Prog byte 5 */ +#define R_CPD 0x08 /* Cal Post-Divider byte */ +#define R_CD1 0x09 /* Cal Divider byte 1 */ +#define R_CD2 0x0a /* Cal Divider byte 2 */ +#define R_CD3 0x0b /* Cal Divider byte 3 */ +#define R_MPD 0x0c /* Main Post-Divider byte */ +#define R_MD1 0x0d /* Main Divider byte 1 */ +#define R_MD2 0x0e /* Main Divider byte 2 */ +#define R_MD3 0x0f /* Main Divider byte 3 */ +#define R_EB1 0x10 /* Extended byte 1 */ +#define R_EB2 0x11 /* Extended byte 2 */ +#define R_EB3 0x12 /* Extended byte 3 */ +#define R_EB4 0x13 /* Extended byte 4 */ +#define R_EB5 0x14 /* Extended byte 5 */ +#define R_EB6 0x15 /* Extended byte 6 */ +#define R_EB7 0x16 /* Extended byte 7 */ +#define R_EB8 0x17 /* Extended byte 8 */ +#define R_EB9 0x18 /* Extended byte 9 */ +#define R_EB10 0x19 /* Extended byte 10 */ +#define R_EB11 0x1a /* Extended byte 11 */ +#define R_EB12 0x1b /* Extended byte 12 */ +#define R_EB13 0x1c /* Extended byte 13 */ +#define R_EB14 0x1d /* Extended byte 14 */ +#define R_EB15 0x1e /* Extended byte 15 */ +#define R_EB16 0x1f /* Extended byte 16 */ +#define R_EB17 0x20 /* Extended byte 17 */ +#define R_EB18 0x21 /* Extended byte 18 */ +#define R_EB19 0x22 /* Extended byte 19 */ +#define R_EB20 0x23 /* Extended byte 20 */ +#define R_EB21 0x24 /* Extended byte 21 */ +#define R_EB22 0x25 /* Extended byte 22 */ +#define R_EB23 0x26 /* Extended byte 23 */ + +#define TDA18271_NUM_REGS 39 + +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +extern struct tda18271_pll_map tda18271_main_pll[]; +extern struct tda18271_pll_map tda18271_cal_pll[]; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +extern struct tda18271_map tda18271_bp_filter[]; +extern struct tda18271_map tda18271_km[]; +extern struct tda18271_map tda18271_rf_band[]; +extern struct tda18271_map tda18271_gain_taper[]; +extern struct tda18271_map tda18271_rf_cal[]; + +#endif /* __TDA18271_PRIV_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c new file mode 100644 index 00000000000..a018b514087 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -0,0 +1,253 @@ +/* + tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner + + 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, or + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tda18271-priv.h" + +struct tda18271_pll_map tda18271_main_pll[] = { + { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, + { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, + { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, + { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, + { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, + { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, + { .lomax = 54000, .pd = 0x59, .d = 0x90 }, + { .lomax = 61000, .pd = 0x58, .d = 0x80 }, + { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, + { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, + { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, + { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, + { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, + { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, + { .lomax = 109000, .pd = 0x49, .d = 0x48 }, + { .lomax = 123000, .pd = 0x48, .d = 0x40 }, + { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, + { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, + { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, + { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, + { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, + { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, + { .lomax = 219000, .pd = 0x39, .d = 0x24 }, + { .lomax = 246000, .pd = 0x38, .d = 0x20 }, + { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, + { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, + { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, + { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, + { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, + { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, + { .lomax = 438000, .pd = 0x29, .d = 0x12 }, + { .lomax = 493000, .pd = 0x28, .d = 0x10 }, + { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, + { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, + { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, + { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, + { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, + { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, + { .lomax = 877000, .pd = 0x19, .d = 0x09 }, + { .lomax = 987000, .pd = 0x18, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +struct tda18271_pll_map tda18271_cal_pll[] = { + { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, + { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, + { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, + { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, + { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, + { .lomax = 88000, .pd = 0xca, .d = 0x50 }, + { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, + { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, + { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, + { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, + { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, + { .lomax = 176000, .pd = 0xba, .d = 0x28 }, + { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, + { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, + { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, + { .lomax = 271000, .pd = 0xad, .d = 0x1a }, + { .lomax = 294000, .pd = 0xac, .d = 0x18 }, + { .lomax = 321000, .pd = 0xab, .d = 0x16 }, + { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, + { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, + { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, + { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, + { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 785000, .pd = 0x99, .d = 0x09 }, + { .lomax = 883000, .pd = 0x98, .d = 0x08 }, + { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +struct tda18271_map tda18271_bp_filter[] = { + { .rfmax = 62000, .val = 0x00 }, + { .rfmax = 84000, .val = 0x01 }, + { .rfmax = 100000, .val = 0x02 }, + { .rfmax = 140000, .val = 0x03 }, + { .rfmax = 170000, .val = 0x04 }, + { .rfmax = 180000, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +struct tda18271_map tda18271_km[] = { + { .rfmax = 61100, .val = 0x74 }, + { .rfmax = 350000, .val = 0x40 }, + { .rfmax = 720000, .val = 0x30 }, + { .rfmax = 865000, .val = 0x40 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +struct tda18271_map tda18271_rf_band[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 61100, .val = 0x01 }, +/* { .rfmax = 152600, .val = 0x02 }, */ + { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 164700, .val = 0x03 }, + { .rfmax = 203500, .val = 0x04 }, + { .rfmax = 457800, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +struct tda18271_map tda18271_gain_taper[] = { + { .rfmax = 45400, .val = 0x1f }, + { .rfmax = 45800, .val = 0x1e }, + { .rfmax = 46200, .val = 0x1d }, + { .rfmax = 46700, .val = 0x1c }, + { .rfmax = 47100, .val = 0x1b }, + { .rfmax = 47500, .val = 0x1a }, + { .rfmax = 47900, .val = 0x19 }, + { .rfmax = 49600, .val = 0x17 }, + { .rfmax = 51200, .val = 0x16 }, + { .rfmax = 52900, .val = 0x15 }, + { .rfmax = 54500, .val = 0x14 }, + { .rfmax = 56200, .val = 0x13 }, + { .rfmax = 57800, .val = 0x12 }, + { .rfmax = 59500, .val = 0x11 }, + { .rfmax = 61100, .val = 0x10 }, + { .rfmax = 67600, .val = 0x0d }, + { .rfmax = 74200, .val = 0x0c }, + { .rfmax = 80700, .val = 0x0b }, + { .rfmax = 87200, .val = 0x0a }, + { .rfmax = 93800, .val = 0x09 }, + { .rfmax = 100300, .val = 0x08 }, + { .rfmax = 106900, .val = 0x07 }, + { .rfmax = 113400, .val = 0x06 }, + { .rfmax = 119900, .val = 0x05 }, + { .rfmax = 126500, .val = 0x04 }, + { .rfmax = 133000, .val = 0x03 }, + { .rfmax = 139500, .val = 0x02 }, + { .rfmax = 146100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x00 }, + { .rfmax = 154300, .val = 0x1f }, + { .rfmax = 156100, .val = 0x1e }, + { .rfmax = 157800, .val = 0x1d }, + { .rfmax = 159500, .val = 0x1c }, + { .rfmax = 161200, .val = 0x1b }, + { .rfmax = 163000, .val = 0x1a }, + { .rfmax = 164700, .val = 0x19 }, + { .rfmax = 170200, .val = 0x17 }, + { .rfmax = 175800, .val = 0x16 }, + { .rfmax = 181300, .val = 0x15 }, + { .rfmax = 186900, .val = 0x14 }, + { .rfmax = 192400, .val = 0x13 }, + { .rfmax = 198000, .val = 0x12 }, + { .rfmax = 203500, .val = 0x11 }, + { .rfmax = 216200, .val = 0x14 }, + { .rfmax = 228900, .val = 0x13 }, + { .rfmax = 241600, .val = 0x12 }, + { .rfmax = 254400, .val = 0x11 }, + { .rfmax = 267100, .val = 0x10 }, + { .rfmax = 279800, .val = 0x0f }, + { .rfmax = 292500, .val = 0x0e }, + { .rfmax = 305200, .val = 0x0d }, + { .rfmax = 317900, .val = 0x0c }, + { .rfmax = 330700, .val = 0x0b }, + { .rfmax = 343400, .val = 0x0a }, + { .rfmax = 356100, .val = 0x09 }, + { .rfmax = 368800, .val = 0x08 }, + { .rfmax = 381500, .val = 0x07 }, + { .rfmax = 394200, .val = 0x06 }, + { .rfmax = 406900, .val = 0x05 }, + { .rfmax = 419700, .val = 0x04 }, + { .rfmax = 432400, .val = 0x03 }, + { .rfmax = 445100, .val = 0x02 }, + { .rfmax = 457800, .val = 0x01 }, + { .rfmax = 476300, .val = 0x19 }, + { .rfmax = 494800, .val = 0x18 }, + { .rfmax = 513300, .val = 0x17 }, + { .rfmax = 531800, .val = 0x16 }, + { .rfmax = 550300, .val = 0x15 }, + { .rfmax = 568900, .val = 0x14 }, + { .rfmax = 587400, .val = 0x13 }, + { .rfmax = 605900, .val = 0x12 }, + { .rfmax = 624400, .val = 0x11 }, + { .rfmax = 642900, .val = 0x10 }, + { .rfmax = 661400, .val = 0x0f }, + { .rfmax = 679900, .val = 0x0e }, + { .rfmax = 698400, .val = 0x0d }, + { .rfmax = 716900, .val = 0x0c }, + { .rfmax = 735400, .val = 0x0b }, + { .rfmax = 753900, .val = 0x0a }, + { .rfmax = 772500, .val = 0x09 }, + { .rfmax = 791000, .val = 0x08 }, + { .rfmax = 809500, .val = 0x07 }, + { .rfmax = 828000, .val = 0x06 }, + { .rfmax = 846500, .val = 0x05 }, + { .rfmax = 865000, .val = 0x04 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +struct tda18271_map tda18271_rf_cal[] = { + { .rfmax = 41000, .val = 0x1e }, + { .rfmax = 43000, .val = 0x30 }, + { .rfmax = 45000, .val = 0x43 }, + { .rfmax = 46000, .val = 0x4d }, + { .rfmax = 47000, .val = 0x54 }, + { .rfmax = 47900, .val = 0x64 }, + { .rfmax = 49100, .val = 0x20 }, + { .rfmax = 50000, .val = 0x22 }, + { .rfmax = 51000, .val = 0x2a }, + { .rfmax = 53000, .val = 0x32 }, + { .rfmax = 55000, .val = 0x35 }, + { .rfmax = 56000, .val = 0x3c }, + { .rfmax = 57000, .val = 0x3f }, + { .rfmax = 58000, .val = 0x48 }, + { .rfmax = 59000, .val = 0x4d }, + { .rfmax = 60000, .val = 0x58 }, + { .rfmax = 61100, .val = 0x5f }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c deleted file mode 100644 index ad72ff69ce9..00000000000 --- a/drivers/media/dvb/frontends/tda18271.c +++ /dev/null @@ -1,1067 +0,0 @@ -/* - tda18271.c - driver for the Philips / NXP TDA18271 silicon tuner - - 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, or - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include "tuner-driver.h" - -#include "tda18271.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - -#define dprintk(level, fmt, arg...) do {\ - if (debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) - -#define R_ID 0x00 /* ID byte */ -#define R_TM 0x01 /* Thermo byte */ -#define R_PL 0x02 /* Power level byte */ -#define R_EP1 0x03 /* Easy Prog byte 1 */ -#define R_EP2 0x04 /* Easy Prog byte 2 */ -#define R_EP3 0x05 /* Easy Prog byte 3 */ -#define R_EP4 0x06 /* Easy Prog byte 4 */ -#define R_EP5 0x07 /* Easy Prog byte 5 */ -#define R_CPD 0x08 /* Cal Post-Divider byte */ -#define R_CD1 0x09 /* Cal Divider byte 1 */ -#define R_CD2 0x0a /* Cal Divider byte 2 */ -#define R_CD3 0x0b /* Cal Divider byte 3 */ -#define R_MPD 0x0c /* Main Post-Divider byte */ -#define R_MD1 0x0d /* Main Divider byte 1 */ -#define R_MD2 0x0e /* Main Divider byte 2 */ -#define R_MD3 0x0f /* Main Divider byte 3 */ -#define R_EB1 0x10 /* Extended byte 1 */ -#define R_EB2 0x11 /* Extended byte 2 */ -#define R_EB3 0x12 /* Extended byte 3 */ -#define R_EB4 0x13 /* Extended byte 4 */ -#define R_EB5 0x14 /* Extended byte 5 */ -#define R_EB6 0x15 /* Extended byte 6 */ -#define R_EB7 0x16 /* Extended byte 7 */ -#define R_EB8 0x17 /* Extended byte 8 */ -#define R_EB9 0x18 /* Extended byte 9 */ -#define R_EB10 0x19 /* Extended byte 10 */ -#define R_EB11 0x1a /* Extended byte 11 */ -#define R_EB12 0x1b /* Extended byte 12 */ -#define R_EB13 0x1c /* Extended byte 13 */ -#define R_EB14 0x1d /* Extended byte 14 */ -#define R_EB15 0x1e /* Extended byte 15 */ -#define R_EB16 0x1f /* Extended byte 16 */ -#define R_EB17 0x20 /* Extended byte 17 */ -#define R_EB18 0x21 /* Extended byte 18 */ -#define R_EB19 0x22 /* Extended byte 19 */ -#define R_EB20 0x23 /* Extended byte 20 */ -#define R_EB21 0x24 /* Extended byte 21 */ -#define R_EB22 0x25 /* Extended byte 22 */ -#define R_EB23 0x26 /* Extended byte 23 */ - -struct tda18271_pll_map { - u32 lomax; - u8 pd; /* post div */ - u8 d; /* div */ -}; - -static struct tda18271_pll_map tda18271_main_pll[] = { - { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, - { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, - { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, - { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, - { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, - { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, - { .lomax = 54000, .pd = 0x59, .d = 0x90 }, - { .lomax = 61000, .pd = 0x58, .d = 0x80 }, - { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, - { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, - { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, - { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, - { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, - { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, - { .lomax = 109000, .pd = 0x49, .d = 0x48 }, - { .lomax = 123000, .pd = 0x48, .d = 0x40 }, - { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, - { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, - { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, - { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, - { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, - { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, - { .lomax = 219000, .pd = 0x39, .d = 0x24 }, - { .lomax = 246000, .pd = 0x38, .d = 0x20 }, - { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, - { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, - { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, - { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, - { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, - { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, - { .lomax = 438000, .pd = 0x29, .d = 0x12 }, - { .lomax = 493000, .pd = 0x28, .d = 0x10 }, - { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, - { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, - { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, - { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, - { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, - { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, - { .lomax = 877000, .pd = 0x19, .d = 0x09 }, - { .lomax = 987000, .pd = 0x18, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271_cal_pll[] = { - { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, - { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, - { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, - { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, - { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, - { .lomax = 88000, .pd = 0xca, .d = 0x50 }, - { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, - { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, - { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, - { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, - { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, - { .lomax = 176000, .pd = 0xba, .d = 0x28 }, - { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, - { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, - { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, - { .lomax = 271000, .pd = 0xad, .d = 0x1a }, - { .lomax = 294000, .pd = 0xac, .d = 0x18 }, - { .lomax = 321000, .pd = 0xab, .d = 0x16 }, - { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, - { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, - { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, - { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, - { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 785000, .pd = 0x99, .d = 0x09 }, - { .lomax = 883000, .pd = 0x98, .d = 0x08 }, - { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -struct tda18271_map { - u32 rfmax; - u8 val; -}; - -static struct tda18271_map tda18271_bp_filter[] = { - { .rfmax = 62000, .val = 0x00 }, - { .rfmax = 84000, .val = 0x01 }, - { .rfmax = 100000, .val = 0x02 }, - { .rfmax = 140000, .val = 0x03 }, - { .rfmax = 170000, .val = 0x04 }, - { .rfmax = 180000, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_km[] = { - { .rfmax = 61100, .val = 0x74 }, - { .rfmax = 350000, .val = 0x40 }, - { .rfmax = 720000, .val = 0x30 }, - { .rfmax = 865000, .val = 0x40 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_band[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, - { .rfmax = 164700, .val = 0x03 }, - { .rfmax = 203500, .val = 0x04 }, - { .rfmax = 457800, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_gain_taper[] = { - { .rfmax = 45400, .val = 0x1f }, - { .rfmax = 45800, .val = 0x1e }, - { .rfmax = 46200, .val = 0x1d }, - { .rfmax = 46700, .val = 0x1c }, - { .rfmax = 47100, .val = 0x1b }, - { .rfmax = 47500, .val = 0x1a }, - { .rfmax = 47900, .val = 0x19 }, - { .rfmax = 49600, .val = 0x17 }, - { .rfmax = 51200, .val = 0x16 }, - { .rfmax = 52900, .val = 0x15 }, - { .rfmax = 54500, .val = 0x14 }, - { .rfmax = 56200, .val = 0x13 }, - { .rfmax = 57800, .val = 0x12 }, - { .rfmax = 59500, .val = 0x11 }, - { .rfmax = 61100, .val = 0x10 }, - { .rfmax = 67600, .val = 0x0d }, - { .rfmax = 74200, .val = 0x0c }, - { .rfmax = 80700, .val = 0x0b }, - { .rfmax = 87200, .val = 0x0a }, - { .rfmax = 93800, .val = 0x09 }, - { .rfmax = 100300, .val = 0x08 }, - { .rfmax = 106900, .val = 0x07 }, - { .rfmax = 113400, .val = 0x06 }, - { .rfmax = 119900, .val = 0x05 }, - { .rfmax = 126500, .val = 0x04 }, - { .rfmax = 133000, .val = 0x03 }, - { .rfmax = 139500, .val = 0x02 }, - { .rfmax = 146100, .val = 0x01 }, - { .rfmax = 152600, .val = 0x00 }, - { .rfmax = 154300, .val = 0x1f }, - { .rfmax = 156100, .val = 0x1e }, - { .rfmax = 157800, .val = 0x1d }, - { .rfmax = 159500, .val = 0x1c }, - { .rfmax = 161200, .val = 0x1b }, - { .rfmax = 163000, .val = 0x1a }, - { .rfmax = 164700, .val = 0x19 }, - { .rfmax = 170200, .val = 0x17 }, - { .rfmax = 175800, .val = 0x16 }, - { .rfmax = 181300, .val = 0x15 }, - { .rfmax = 186900, .val = 0x14 }, - { .rfmax = 192400, .val = 0x13 }, - { .rfmax = 198000, .val = 0x12 }, - { .rfmax = 203500, .val = 0x11 }, - { .rfmax = 216200, .val = 0x14 }, - { .rfmax = 228900, .val = 0x13 }, - { .rfmax = 241600, .val = 0x12 }, - { .rfmax = 254400, .val = 0x11 }, - { .rfmax = 267100, .val = 0x10 }, - { .rfmax = 279800, .val = 0x0f }, - { .rfmax = 292500, .val = 0x0e }, - { .rfmax = 305200, .val = 0x0d }, - { .rfmax = 317900, .val = 0x0c }, - { .rfmax = 330700, .val = 0x0b }, - { .rfmax = 343400, .val = 0x0a }, - { .rfmax = 356100, .val = 0x09 }, - { .rfmax = 368800, .val = 0x08 }, - { .rfmax = 381500, .val = 0x07 }, - { .rfmax = 394200, .val = 0x06 }, - { .rfmax = 406900, .val = 0x05 }, - { .rfmax = 419700, .val = 0x04 }, - { .rfmax = 432400, .val = 0x03 }, - { .rfmax = 445100, .val = 0x02 }, - { .rfmax = 457800, .val = 0x01 }, - { .rfmax = 476300, .val = 0x19 }, - { .rfmax = 494800, .val = 0x18 }, - { .rfmax = 513300, .val = 0x17 }, - { .rfmax = 531800, .val = 0x16 }, - { .rfmax = 550300, .val = 0x15 }, - { .rfmax = 568900, .val = 0x14 }, - { .rfmax = 587400, .val = 0x13 }, - { .rfmax = 605900, .val = 0x12 }, - { .rfmax = 624400, .val = 0x11 }, - { .rfmax = 642900, .val = 0x10 }, - { .rfmax = 661400, .val = 0x0f }, - { .rfmax = 679900, .val = 0x0e }, - { .rfmax = 698400, .val = 0x0d }, - { .rfmax = 716900, .val = 0x0c }, - { .rfmax = 735400, .val = 0x0b }, - { .rfmax = 753900, .val = 0x0a }, - { .rfmax = 772500, .val = 0x09 }, - { .rfmax = 791000, .val = 0x08 }, - { .rfmax = 809500, .val = 0x07 }, - { .rfmax = 828000, .val = 0x06 }, - { .rfmax = 846500, .val = 0x05 }, - { .rfmax = 865000, .val = 0x04 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_cal[] = { - { .rfmax = 41000, .val = 0x1e }, - { .rfmax = 43000, .val = 0x30 }, - { .rfmax = 45000, .val = 0x43 }, - { .rfmax = 46000, .val = 0x4d }, - { .rfmax = 47000, .val = 0x54 }, - { .rfmax = 47900, .val = 0x64 }, - { .rfmax = 49100, .val = 0x20 }, - { .rfmax = 50000, .val = 0x22 }, - { .rfmax = 51000, .val = 0x2a }, - { .rfmax = 53000, .val = 0x32 }, - { .rfmax = 55000, .val = 0x35 }, - { .rfmax = 56000, .val = 0x3c }, - { .rfmax = 57000, .val = 0x3f }, - { .rfmax = 58000, .val = 0x48 }, - { .rfmax = 59000, .val = 0x4d }, - { .rfmax = 60000, .val = 0x58 }, - { .rfmax = 61100, .val = 0x5f }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -/*---------------------------------------------------------------------*/ - -#define TDA18271_NUM_REGS 39 - -#define TDA18271_ANALOG 0 -#define TDA18271_DIGITAL 1 - -struct tda18271_priv { - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - unsigned char tda18271_regs[TDA18271_NUM_REGS]; - int mode; - - u32 frequency; - u32 bandwidth; -}; - -static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; - int ret = 0; - - switch (priv->mode) { - case TDA18271_ANALOG: - if (ops && ops->i2c_gate_ctrl) - ret = ops->i2c_gate_ctrl(fe, enable); - break; - case TDA18271_DIGITAL: - if (fe->ops.i2c_gate_ctrl) - ret = fe->ops.i2c_gate_ctrl(fe, enable); - break; - } - - return ret; -}; - -/*---------------------------------------------------------------------*/ - -static void tda18271_dump_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - dprintk(1, "=== TDA18271 REG DUMP ===\n"); - dprintk(1, "ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); - dprintk(1, "THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); - dprintk(1, "POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); - dprintk(1, "EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); - dprintk(1, "EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); - dprintk(1, "EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); - dprintk(1, "EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); - dprintk(1, "EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); - dprintk(1, "CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); - dprintk(1, "CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); - dprintk(1, "CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); - dprintk(1, "CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); - dprintk(1, "MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); - dprintk(1, "MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); - dprintk(1, "MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); - dprintk(1, "MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); -} - -static void tda18271_read_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf = 0x00; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->i2c_addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = regs, .len = 16 } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - printk("ERROR: %s: i2c_transfer returned: %d\n", - __FUNCTION__, ret); - - if (debug > 1) - tda18271_dump_regs(fe); -} - -static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf[TDA18271_NUM_REGS+1]; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = len+1 }; - int i, ret; - - BUG_ON((len == 0) || (idx+len > sizeof(buf))); - - buf[0] = idx; - for (i = 1; i <= len; i++) { - buf[i] = regs[idx-1+i]; - } - - tda18271_i2c_gate_ctrl(fe, 1); - - /* write registers */ - ret = i2c_transfer(priv->i2c_adap, &msg, 1); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 1) - printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", - __FUNCTION__, ret); -} - -/*---------------------------------------------------------------------*/ - -static int tda18271_init_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - printk(KERN_INFO "tda18271: initializing registers\n"); - - /* initialize registers */ - regs[R_ID] = 0x83; - regs[R_TM] = 0x08; - regs[R_PL] = 0x80; - regs[R_EP1] = 0xc6; - regs[R_EP2] = 0xdf; - regs[R_EP3] = 0x16; - regs[R_EP4] = 0x60; - regs[R_EP5] = 0x80; - regs[R_CPD] = 0x80; - regs[R_CD1] = 0x00; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0x00; - regs[R_MD1] = 0x00; - regs[R_MD2] = 0x00; - regs[R_MD3] = 0x00; - regs[R_EB1] = 0xff; - regs[R_EB2] = 0x01; - regs[R_EB3] = 0x84; - regs[R_EB4] = 0x41; - regs[R_EB5] = 0x01; - regs[R_EB6] = 0x84; - regs[R_EB7] = 0x40; - regs[R_EB8] = 0x07; - regs[R_EB9] = 0x00; - regs[R_EB10] = 0x00; - regs[R_EB11] = 0x96; - regs[R_EB12] = 0x0f; - regs[R_EB13] = 0xc1; - regs[R_EB14] = 0x00; - regs[R_EB15] = 0x8f; - regs[R_EB16] = 0x00; - regs[R_EB17] = 0x00; - regs[R_EB18] = 0x00; - regs[R_EB19] = 0x00; - regs[R_EB20] = 0x20; - regs[R_EB21] = 0x33; - regs[R_EB22] = 0x48; - regs[R_EB23] = 0xb0; - - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); - /* setup AGC1 & AGC2 */ - regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); - - regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - - /* image rejection calibration */ - - /* low-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x81; - regs[R_CPD] = 0xcc; - regs[R_CD1] = 0x6c; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0xcd; - regs[R_MD1] = 0x77; - regs[R_MD2] = 0x08; - regs[R_MD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - regs[R_EP1] = 0xc6; - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted low measurement */ - - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x85; - regs[R_CPD] = 0xcb; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0x70; - regs[R_CD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - regs[R_EP2] = 0xdf; - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image low optimization completion */ - - /* mid-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x82; - regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0xa9; - regs[R_MD1] = 0x73; - regs[R_MD2] = 0x1a; - regs[R_MD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - regs[R_EP1] = 0xc6; - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted mid measurement */ - - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x86; - regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0xa0; - regs[R_CD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - regs[R_EP2] = 0xdf; - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image mid optimization completion */ - - /* high-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x83; - regs[R_CPD] = 0x98; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0x99; - regs[R_MD1] = 0x71; - regs[R_MD2] = 0xcd; - regs[R_MD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - regs[R_EP1] = 0xc6; - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted high measurement */ - - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x87; - regs[R_CPD] = 0x98; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x50; - regs[R_CD3] = 0x00; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - regs[R_EP2] = 0xdf; - - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image high optimization completion */ - - regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); - - regs[R_EP1] = 0xc6; - tda18271_write_regs(fe, R_EP1, 1); - - return 0; -} - -static int tda18271_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u32 div, N = 0; - int i; - - tda18271_read_regs(fe); - - /* test IR_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x08) == 0) - tda18271_init_regs(fe); - - - dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); - - /* RF tracking filter calibration */ - - /* calculate BP_Filter */ - i = 0; - while ((tda18271_bp_filter[i].rfmax * 1000) < freq) { - if (tda18271_bp_filter[i + 1].rfmax == 0) - break; - i++; - } - dprintk(2, "bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); - - regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= tda18271_bp_filter[i].val; - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x60; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x60; - tda18271_write_regs(fe, R_EB7, 1); - - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - regs[R_EB20] = 0xcc; - tda18271_write_regs(fe, R_EB20, 1); - - /* set CAL mode to RF tracking filter calibration */ - regs[R_EB4] |= 0x03; - - /* calculate CAL PLL */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 1250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2; - break; - } - - i = 0; - while ((tda18271_cal_pll[i].lomax * 1000) < N) { - if (tda18271_cal_pll[i + 1].lomax == 0) - break; - i++; - } - dprintk(2, "cal pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); - - regs[R_CPD] = tda18271_cal_pll[i].pd; - - div = ((tda18271_cal_pll[i].d * (N / 1000)) << 7) / 125; - regs[R_CD1] = 0xff & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; - - /* calculate MAIN PLL */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2 + 1000000; - break; - } - - i = 0; - while ((tda18271_main_pll[i].lomax * 1000) < N) { - if (tda18271_main_pll[i + 1].lomax == 0) - break; - i++; - } - dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); - - regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0xff & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* RF tracking filter calibration initialization */ - - /* search for K,M,CO for RF Calibration */ - i = 0; - while ((tda18271_km[i].rfmax * 1000) < freq) { - if (tda18271_km[i + 1].rfmax == 0) - break; - i++; - } - dprintk(2, "km = 0x%x, i = %d\n", tda18271_km[i].val, i); - - regs[R_EB13] &= 0x83; - regs[R_EB13] |= tda18271_km[i].val; - tda18271_write_regs(fe, R_EB13, 1); - - /* search for RF_BAND */ - i = 0; - while ((tda18271_rf_band[i].rfmax * 1000) < freq) { - if (tda18271_rf_band[i + 1].rfmax == 0) - break; - i++; - } - dprintk(2, "rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); - - regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (tda18271_rf_band[i].val << 5); - - /* search for Gain_Taper */ - i = 0; - while ((tda18271_gain_taper[i].rfmax * 1000) < freq) { - if (tda18271_gain_taper[i + 1].rfmax == 0) - break; - i++; - } - dprintk(2, "gain taper = 0x%x, i = %d\n", - tda18271_gain_taper[i].val, i); - - regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= tda18271_gain_taper[i].val; - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x40; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x40; - tda18271_write_regs(fe, R_EB7, 1); - msleep(10); - - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - msleep(60); /* RF tracking filter calibration completion */ - - regs[R_EP4] &= ~0x03; /* set cal mode to normal */ - tda18271_write_regs(fe, R_EP4, 1); - - tda18271_write_regs(fe, R_EP1, 1); - - /* RF tracking filer correction for VHF_Low band */ - i = 0; - while ((tda18271_rf_cal[i].rfmax * 1000) < freq) { - if (tda18271_rf_cal[i].rfmax == 0) - break; - i++; - } - dprintk(2, "rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); - - /* VHF_Low band only */ - if (tda18271_rf_cal[i].rfmax != 0) { - regs[R_EB14] = tda18271_rf_cal[i].val; - tda18271_write_regs(fe, R_EB14, 1); - } - - /* Channel Configuration */ - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_EB22] = 0x2c; - break; - case TDA18271_DIGITAL: - regs[R_EB22] = 0x37; - break; - } - tda18271_write_regs(fe, R_EB22, 1); - - regs[R_EP1] |= 0x40; /* set dis power level on */ - - /* set standard */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - - /* see table 22 */ - regs[R_EP3] |= std; - - /* TO DO: * - * ================ * - * FM radio, 0x18 * - * ATSC 6MHz, 0x1c * - * DVB-T 6MHz, 0x1c * - * DVB-T 7MHz, 0x1d * - * DVB-T 8MHz, 0x1e * - * QAM 6MHz, 0x1d * - * QAM 8MHz, 0x1f */ - - regs[R_EP4] &= ~0x03; /* set cal mode to normal */ - - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x80; /* IF notch = 0 */ - break; - case TDA18271_DIGITAL: - regs[R_EP4] |= 0x04; - regs[R_MPD] |= 0x80; - break; - } - - regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ - - /* FIXME: image rejection validity EP5[2:0] */ - - /* calculate MAIN PLL */ - N = freq + ifc; - - i = 0; - while ((tda18271_main_pll[i].lomax * 1000) < N) { - if (tda18271_main_pll[i + 1].lomax == 0) - break; - i++; - } - dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); - - regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0xff & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; - - tda18271_write_regs(fe, R_TM, 15); - msleep(5); - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - u8 std; - u32 bw, sgIF = 0; - - u32 freq = params->frequency; - - priv->mode = TDA18271_DIGITAL; - - /* see table 22 */ - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - std = 0x1b; /* device-specific (spec says 0x1c) */ - sgIF = 5380000; - break; - case QAM_64: - case QAM_256: - std = 0x18; /* device-specific (spec says 0x1d) */ - sgIF = 4000000; - break; - default: - printk(KERN_WARNING "%s: modulation not set!\n", - __FUNCTION__); - return -EINVAL; - } - freq += 1750000; /* Adjust to center (+1.75MHZ) */ - bw = 6000000; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - std = 0x1c; - bw = 6000000; - break; - case BANDWIDTH_7_MHZ: - std = 0x1d; - bw = 7000000; - break; - case BANDWIDTH_8_MHZ: - std = 0x1e; - bw = 8000000; - break; - default: - printk(KERN_WARNING "%s: bandwidth not set!\n", - __FUNCTION__); - return -EINVAL; - } - } else { - printk(KERN_WARNING "%s: modulation type not supported!\n", - __FUNCTION__); - return -EINVAL; - } - - return tda18271_tune(fe, sgIF, freq, bw, std); -} - -static int tda18271_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - u8 std; - unsigned int sgIF; - char *mode; - - priv->mode = TDA18271_ANALOG; - - /* see table 22 */ - if (params->std & V4L2_STD_MN) { - std = 0x0d; - sgIF = 92; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - std = 0x0e; - sgIF = 108; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - std = 0x0f; - sgIF = 124; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - std = 0x0f; - sgIF = 124; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - std = 0x0f; - sgIF = 124; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - std = 0x0f; - sgIF = 124; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - std = 0x0f; - sgIF = 20; - mode = "LC"; - } else { - std = 0x0f; - sgIF = 124; - mode = "xx"; - } - - if (params->mode == V4L2_TUNER_RADIO) - sgIF = 88; /* if frequency is 5.5 MHz */ - - dprintk(1, "setting tda18271 to system %s\n", mode); - - return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, - 0, std); -} - -static int tda18271_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -static struct dvb_tuner_ops tda18271_tuner_ops = { - .info = { - .name = "NXP TDA18271HD", - .frequency_min = 45000000, - .frequency_max = 864000000, - .frequency_step = 62500 - }, - .init = tda18271_init_regs, - .set_params = tda18271_set_params, - .set_analog_params = tda18271_set_analog_params, - .release = tda18271_release, - .get_frequency = tda18271_get_frequency, - .get_bandwidth = tda18271_get_bandwidth, -}; - -struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c) -{ - struct tda18271_priv *priv = NULL; - - dprintk(1, "@ 0x%x\n", addr); - priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - - memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - return fe; -} -EXPORT_SYMBOL_GPL(tda18271_attach); -MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From 54465b082cc86921aa7d7b638d75803e6d919f25 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 23 Nov 2007 18:14:53 -0300 Subject: V4L/DVB (6681): tda18271: rename 'debug' to 'tda18271_debug' Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index ba980cf5811..726e102cbc5 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -25,12 +25,12 @@ #include "tda18271.h" #include "tda18271-priv.h" -static int debug; -module_param(debug, int, 0644); +static int tda18271_debug; +module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); #define dprintk(level, fmt, arg...) do {\ - if (debug >= level) \ + if (tda18271_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) /*---------------------------------------------------------------------*/ @@ -118,7 +118,7 @@ static void tda18271_read_regs(struct dvb_frontend *fe) printk("ERROR: %s: i2c_transfer returned: %d\n", __FUNCTION__, ret); - if (debug > 2) + if (tda18271_debug > 2) tda18271_dump_regs(fe); } -- cgit v1.2.3 From 5c15648a42016eebb9870dc3af44e94bca4f3604 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 2 Dec 2007 00:02:18 -0300 Subject: V4L/DVB (6683): Fix DVB compatibility DVB-S is not supported. Also, there are some QAM6 firmwares for xc3028, but it is reported that this doesn't work fine. Thanks to Manu Abraham, Michael Krufky and Patrick Boettcher for their insights. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index e1796ebb7c7..7acc175d805 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -957,12 +957,14 @@ static int xc2028_set_params(struct dvb_frontend *fe, type |= D2620; switch(fe->ops.info.type) { - case FE_QPSK: - break; case FE_OFDM: bw = p->u.ofdm.bandwidth; break; case FE_QAM: + tuner_info("WARN: There are some reports that " + "QAM 6 MHz doesn't work.\n" + "If this works for you, please report by " + "e-mail to: v4l-dvb-maintainer@linuxtv.org\n"); bw = BANDWIDTH_6_MHZ; type |= QAM; break; @@ -970,6 +972,9 @@ static int xc2028_set_params(struct dvb_frontend *fe, bw = BANDWIDTH_6_MHZ; type |= ATSC| D2633; break; + /* DVB-S is not supported */ + default: + return -EINVAL; } /* FIXME: -- cgit v1.2.3 From 102df6a785bd5ff22b0ca745f3107ab9780fc30b Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Mon, 26 Nov 2007 18:57:10 -0300 Subject: V4L/DVB (6685): ir-keymaps.c: extra keys on winfast Y04G0033 remote This change adds support for 4 extra keys on the remote currently being shipped by leadtek with their "WinFast TV2000 XP/Expert" and "WinFast PVR2000" cards. The remote P/N seems to be Y04G0033 and you can see a picture of it here: http://lespinasse.org/y04g0033.jpg The extra keys are at the bottom and are labeled MCE +VOL, -VOL, +CH, -CH. I chose to map them to the F21-F24 keycodes, following the precedent of ir_codes_gotview7135[], so as to differentiate these 'MCE' keys from the other +VOL, -VOL, +CH, -CH 'arrow' keys higher up on the remote. Signed-off-by: Michel Lespinasse Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 185e8a860c1..42762dfb738 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 0x35 ] = KEY_FASTFORWARD, [ 0x36 ] = KEY_TV, [ 0x37 ] = KEY_RADIO, /* FM */ - [ 0x38 ] = KEY_DVD + [ 0x38 ] = KEY_DVD, + + [ 0x3e ] = KEY_F21, /* MCE +VOL, on Y04G0033 */ + [ 0x3a ] = KEY_F22, /* MCE -VOL, on Y04G0033 */ + [ 0x3b ] = KEY_F23, /* MCE +CH, on Y04G0033 */ + [ 0x3f ] = KEY_F24 /* MCE -CH, on Y04G0033 */ }; EXPORT_SYMBOL_GPL(ir_codes_winfast); -- cgit v1.2.3 From cc76466b310f61e71ac10778781fdbdb97d333fd Mon Sep 17 00:00:00 2001 From: Hermann Pitton Date: Wed, 28 Nov 2007 21:54:35 -0300 Subject: V4L/DVB (6687): saa7134: add mute support for radio/analog-in on MD9717 and MD7134 Currently the saa7134 chips only have mute support for the TV input. Cards with mute from external audio muxes are already fine on the other inputs and some recent tuners mute at least the radio on exit. But these mostly hybrid tuners are not fully backward compatible, since they must power down and mute regardless. For some included above, the MD7134 knows several, to switch on mute/automute to the TV input is functional and backward compatible for the applications, except that the tuners with tda9887 always mute on exit. Signed-off-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 533fb02394f..9a2dd643025 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -350,6 +350,10 @@ struct saa7134_board saa7134_boards[] = { .name = name_radio, .amux = LINE2, }, + .mute = { + .name = name_mute, + .amux = TV, + }, }, [SAA7134_BOARD_TVSTATION_RDS] = { /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ @@ -566,6 +570,10 @@ struct saa7134_board saa7134_boards[] = { .radio = { .name = name_radio, .amux = LINE2, + }, + .mute = { + .name = name_mute, + .amux = TV, }, }, [SAA7134_BOARD_TYPHOON_90031] = { -- cgit v1.2.3 From 493977f016f2ff52fdca38d031c7211b4da658fd Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 30 Nov 2007 22:37:28 -0300 Subject: V4L/DVB (6688): V4L: fix copy and paste error in dprintk for videobuf-vmalloc.c Signed-off-by: Brandon Philips Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index e01259438bb..9b3898347ca 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); #define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) /***************************************************************************/ -- cgit v1.2.3 From 681c739944018d80dbcf7f19997eba97676c7116 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 01:48:52 -0300 Subject: V4L/DVB (6691): pvrusb2: Rework pipeline state control This is a new implementation for video pipeline control within the pvrusb2 driver. Actual start/stop of the pipeline is moved to the driver's kernel thread. Pipeline stages are controlled autonomously based on surrounding pipeline or application control state. Kernel thread management is also cleaned up and moved into the internal control structure of the driver, solving a set up / tear down race along the way. Better failure recovery is implemented with this new control strategy. Also with this change comes better control of the cx23416 encoder, building on additional information learned about the peculiarities of controlling this part (this information was the original trigger for this rework). With this change, overall encoder stability should be considerably improved. Yes, this is a large change for this driver, but due to the nature of the feature being worked on, the changes are fairly pervasive and would be difficult to break into smaller pieces with any semblence of step-wise stability. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-context.c | 55 +- drivers/media/video/pvrusb2/pvrusb2-context.h | 5 +- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 4 +- drivers/media/video/pvrusb2/pvrusb2-debug.h | 39 +- drivers/media/video/pvrusb2/pvrusb2-debugifc.c | 177 +-- drivers/media/video/pvrusb2/pvrusb2-encoder.c | 54 +- drivers/media/video/pvrusb2/pvrusb2-encoder.h | 1 + drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 64 +- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1139 +++++++++++++------- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 135 +-- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 6 +- drivers/media/video/pvrusb2/pvrusb2-video-v4l.c | 4 +- 13 files changed, 944 insertions(+), 741 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 22719ba861a..9d94aed2e12 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -31,52 +31,32 @@ static void pvr2_context_destroy(struct pvr2_context *mp) { - if (mp->hdw) pvr2_hdw_destroy(mp->hdw); pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); - if (mp->workqueue) { - flush_workqueue(mp->workqueue); - destroy_workqueue(mp->workqueue); - } + if (mp->hdw) pvr2_hdw_destroy(mp->hdw); kfree(mp); } -static void pvr2_context_trigger_poll(struct pvr2_context *mp) -{ - queue_work(mp->workqueue,&mp->workpoll); -} - - -static void pvr2_context_poll(struct work_struct *work) -{ - struct pvr2_context *mp = - container_of(work, struct pvr2_context, workpoll); - pvr2_context_enter(mp); do { - pvr2_hdw_poll(mp->hdw); - } while (0); pvr2_context_exit(mp); -} - - -static void pvr2_context_setup(struct work_struct *work) +static void pvr2_context_state_check(struct pvr2_context *mp) { - struct pvr2_context *mp = - container_of(work, struct pvr2_context, workinit); + if (mp->init_flag) return; + + switch (pvr2_hdw_get_state(mp->hdw)) { + case PVR2_STATE_WARM: break; + case PVR2_STATE_ERROR: break; + case PVR2_STATE_READY: break; + case PVR2_STATE_RUN: break; + default: return; + } pvr2_context_enter(mp); do { - if (!pvr2_hdw_dev_ok(mp->hdw)) break; - pvr2_hdw_setup(mp->hdw); - pvr2_hdw_setup_poll_trigger( - mp->hdw, - (void (*)(void *))pvr2_context_trigger_poll, - mp); - if (!pvr2_hdw_dev_ok(mp->hdw)) break; - if (!pvr2_hdw_init_ok(mp->hdw)) break; + mp->init_flag = !0; mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); if (mp->setup_func) { mp->setup_func(mp); } } while (0); pvr2_context_exit(mp); -} + } struct pvr2_context *pvr2_context_create( @@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create( mp = NULL; goto done; } - - mp->workqueue = create_singlethread_workqueue("pvrusb2"); - INIT_WORK(&mp->workinit, pvr2_context_setup); - INIT_WORK(&mp->workpoll, pvr2_context_poll); - queue_work(mp->workqueue,&mp->workinit); + pvr2_hdw_set_state_callback(mp->hdw, + (void (*)(void *))pvr2_context_state_check, + mp); + pvr2_context_state_check(mp); done: return mp; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 6327fa1f7e4..a04187a9322 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -45,14 +45,11 @@ struct pvr2_context { struct pvr2_context_stream video_stream; struct mutex mutex; int disconnect_flag; + int init_flag; /* Called after pvr2_context initialization is complete */ void (*setup_func)(struct pvr2_context *); - /* Work queue overhead for out-of-line processing */ - struct workqueue_struct *workqueue; - struct work_struct workinit; - struct work_struct workpoll; }; struct pvr2_channel { diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index e8a9252c7df..2cca817e414 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -140,7 +140,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = { static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt) { ctxt->client->handler = NULL; - ctxt->hdw->decoder_ctrl = NULL; + pvr2_hdw_set_decoder(ctxt->hdw,NULL); kfree(ctxt); } @@ -241,7 +241,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw, ctxt->client = cp; ctxt->hdw = hdw; ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1; - hdw->decoder_ctrl = &ctxt->ctrl; + pvr2_hdw_set_decoder(hdw,&ctxt->ctrl); cp->handler = &ctxt->handler; { /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index da6441b88f3..fca49d8a931 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -34,25 +34,26 @@ extern int pvrusb2_debug; #define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ #define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ #define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ -#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */ -#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */ -#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */ -#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */ -#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */ -#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */ -#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */ -#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */ -#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */ -#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */ -#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */ -#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */ -#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */ -#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */ -#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */ -#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */ -#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */ -#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */ -#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */ +#define PVR2_TRACE_STATE (1 << 8) /* Device state changes */ +#define PVR2_TRACE_STBITS (1 << 9) /* Individual bit state changes */ +#define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */ +#define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */ +#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */ +#define PVR2_TRACE_CREG (1 << 13) /* Main critical region entry / exit */ +#define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */ +#define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */ +#define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */ +#define PVR2_TRACE_I2C (1 << 17) /* I2C related stuff */ +#define PVR2_TRACE_I2C_CMD (1 << 18) /* Software commands to I2C modules */ +#define PVR2_TRACE_I2C_CORE (1 << 19) /* I2C core debugging */ +#define PVR2_TRACE_I2C_TRAF (1 << 20) /* I2C traffic through the adapter */ +#define PVR2_TRACE_V4LIOCTL (1 << 21) /* v4l ioctl details */ +#define PVR2_TRACE_ENCODER (1 << 22) /* mpeg2 encoder operation */ +#define PVR2_TRACE_BUF_POOL (1 << 23) /* Track buffer pool management */ +#define PVR2_TRACE_BUF_FLOW (1 << 24) /* Track buffer flow in system */ +#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ +#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ +#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index 6f135f4a249..b0687430fdd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -31,14 +31,6 @@ struct debugifc_mask_item { unsigned long msk; }; -static struct debugifc_mask_item mask_items[] = { - {"ENC_FIRMWARE",(1<name)) { - return mip->msk; - } - } - return 0; -} - - -static int debugifc_print_mask(char *buf,unsigned int sz, - unsigned long msk,unsigned long val) -{ - struct debugifc_mask_item *mip; - unsigned int idx; - int bcnt = 0; - int ccnt; - 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", - (bcnt ? " " : ""), - ((mip->msk & val) ? '+' : '-'), - mip->name); - sz -= ccnt; - buf += ccnt; - bcnt += ccnt; - } - return bcnt; -} - -static unsigned int debugifc_parse_subsys_mask(const char *buf, - unsigned int count, - unsigned long *mskPtr, - unsigned long *valPtr) -{ - const char *wptr; - unsigned int consume_cnt = 0; - unsigned int scnt; - unsigned int wlen; - int mode; - unsigned long m1,msk,val; - - msk = 0; - val = 0; - - while (count) { - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) break; - consume_cnt += scnt; count -= scnt; buf += scnt; - if (!wptr) break; - - mode = 0; - if (wlen) switch (wptr[0]) { - case '+': - wptr++; - wlen--; - break; - case '-': - mode = 1; - wptr++; - wlen--; - break; - } - if (!wlen) continue; - m1 = debugifc_find_mask(wptr,wlen); - if (!m1) break; - msk |= m1; - if (!mode) val |= m1; - } - *mskPtr = msk; - *valPtr = val; - return consume_cnt; -} - - int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) { int bcnt = 0; int ccnt; - struct pvr2_hdw_debug_info dbg; - - pvr2_hdw_get_debug_info(hdw,&dbg); - - ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s", - (dbg.big_lock_held ? "held" : "free"), - (dbg.ctl_lock_held ? "held" : "free")); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - if (dbg.ctl_lock_held) { - ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d" - " cmd_wlen=%d cmd_rlen=%d" - " wpend=%d rpend=%d tmout=%d rstatus=%d" - " wstatus=%d", - dbg.cmd_debug_state,dbg.cmd_code, - dbg.cmd_debug_write_len, - dbg.cmd_debug_read_len, - dbg.cmd_debug_write_pend, - dbg.cmd_debug_read_pend, - dbg.cmd_debug_timeout, - dbg.cmd_debug_rstatus, - dbg.cmd_debug_wstatus); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - } - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf( - buf,acnt,"driver flags: %s %s %s\n", - (dbg.flag_init_ok ? "initialized" : "uninitialized"), - (dbg.flag_ok ? "ok" : "fail"), - (dbg.flag_disconnected ? "disconnected" : "connected")); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); + ccnt = scnprintf(buf,acnt,"Driver state info:\n"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags); + ccnt = pvr2_hdw_state_report(hdw,buf,acnt); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; ccnt = pvr2_i2c_report(hdw,buf,acnt); @@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, { int bcnt = 0; int ccnt; - unsigned long msk; int ret; u32 gpio_dir,gpio_in,gpio_out; @@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, pvr2_hdw_get_streaming(hdw) ? "on" : "off"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - msk = pvr2_hdw_subsys_get(hdw); - ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,msk,msk); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,~msk,msk); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - - msk = pvr2_hdw_subsys_stream_get(hdw); - ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,msk,msk); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - return bcnt; } @@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, return pvr2_upload_firmware2(hdw); } else if (debugifc_match_keyword(wptr,wlen,"decoder")) { return pvr2_hdw_cmd_decoder_reset(hdw); + } else if (debugifc_match_keyword(wptr,wlen,"worker")) { + return pvr2_hdw_untrip(hdw); } return -EINVAL; - } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) { - unsigned long msk = 0; - unsigned long val = 0; - if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { - pvr2_trace(PVR2_TRACE_DEBUGIFC, - "debugifc parse error on subsys mask"); - return -EINVAL; - } - pvr2_hdw_subsys_bit_chg(hdw,msk,val); - return 0; - } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) { - unsigned long msk = 0; - unsigned long val = 0; - if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { - pvr2_trace(PVR2_TRACE_DEBUGIFC, - "debugifc parse error on stream mask"); - return -EINVAL; - } - pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val); - return 0; } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); if (!scnt) return -EINVAL; diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 205087a3e13..5ca548cc7e7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt, LOCK_TAKE(hdw->ctl_lock); do { - if (!hdw->flag_encoder_ok) { + if (!hdw->state_encoder_ok) { ret = -EIO; break; } @@ -278,7 +278,11 @@ static int pvr2_encoder_cmd(void *ctxt, ret = -EBUSY; } if (ret) { - hdw->flag_encoder_ok = 0; + hdw->state_encoder_ok = 0; + pvr2_trace(PVR2_TRACE_STBITS, + "State bit %s <-- %s", + "state_encoder_ok", + (hdw->state_encoder_ok ? "true" : "false")); pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Giving up on command." @@ -394,6 +398,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) return ret; } +int pvr2_encoder_adjust(struct pvr2_hdw *hdw) +{ + int ret; + ret = cx2341x_update(hdw,pvr2_encoder_cmd, + (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), + &hdw->enc_ctl_state); + if (ret) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Error from cx2341x module code=%d",ret); + } else { + memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state, + sizeof(struct cx2341x_mpeg_params)); + hdw->enc_cur_valid = !0; + } + return ret; +} + + int pvr2_encoder_configure(struct pvr2_hdw *hdw) { int ret; @@ -436,18 +458,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) return ret; } - ret = cx2341x_update(hdw,pvr2_encoder_cmd, - (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), - &hdw->enc_ctl_state); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error from cx2341x module code=%d",ret); - return ret; - } - - ret = 0; + ret = pvr2_encoder_adjust(hdw); + if (ret) return ret; - if (!ret) ret = pvr2_encoder_vcmd( + ret = pvr2_encoder_vcmd( hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); if (ret) { @@ -456,10 +470,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) return ret; } - hdw->subsys_enabled_mask |= (1<enc_cur_state,&hdw->enc_ctl_state, - sizeof(struct cx2341x_mpeg_params)); - hdw->enc_cur_valid = !0; return 0; } @@ -478,7 +488,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw) pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1, hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0); - switch (hdw->config) { + switch (hdw->active_stream_type) { case pvr2_config_vbi: status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, 0x01,0x14); @@ -492,9 +502,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw) 0,0x13); break; } - if (!status) { - hdw->subsys_enabled_mask |= (1<config) { + switch (hdw->active_stream_type) { case pvr2_config_vbi: status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, 0x01,0x01,0x14); @@ -526,9 +533,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw) pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401); pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); - if (!status) { - hdw->subsys_enabled_mask &= ~(1< #include +#include #include #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" @@ -179,6 +180,12 @@ struct pvr2_hdw { /* Device type, one of PVR2_HDW_TYPE_xxxxx */ unsigned int hdw_type; + /* Kernel worker thread handling */ + struct workqueue_struct *workqueue; + struct work_struct workpoll; /* Update driver state */ + struct work_struct worki2csync; /* Update i2c clients */ + struct work_struct workinit; /* Driver initialization sequence */ + /* Video spigot */ struct pvr2_stream *vid_stream; @@ -186,9 +193,6 @@ struct pvr2_hdw { struct mutex big_lock_mutex; int big_lock_held; /* For debugging */ - void (*poll_trigger_func)(void *); - void *poll_trigger_data; - char name[32]; /* I2C stuff */ @@ -225,14 +229,48 @@ struct pvr2_hdw { unsigned int cmd_debug_write_len; // unsigned int cmd_debug_read_len; // + /* Bits of state that describe what is going on with various parts + of the driver. */ + volatile int state_encoder_ok; /* Encoder is operational */ + volatile int state_encoder_run; /* Encoder is running */ + volatile int state_encoder_config; /* Encoder is configured */ + volatile int state_encoder_waitok; /* Encoder pre-wait done */ + volatile int state_decoder_run; /* Decoder is running */ + volatile int state_usbstream_run; /* FX2 is streaming */ + volatile int state_decoder_quiescent; /* Decoder idle for > 50msec */ + volatile int state_pipeline_config; /* Pipeline is configured */ + int state_pipeline_req; /* Somebody wants to stream */ + int state_pipeline_pause; /* Pipeline must be paused */ + int state_pipeline_idle; /* Pipeline not running */ + + /* This is the master state of the driver. It is the combined + result of other bits of state. Examining this will indicate the + overall state of the driver. Values here are one of + PVR2_STATE_xxxx */ + unsigned int master_state; + + /* True if states must be re-evaluated */ + int state_stale; + + void (*state_func)(void *); + void *state_data; + + /* Timer for measuring decoder settling time */ + struct timer_list quiescent_timer; + + /* Timer for measuring encoder pre-wait time */ + struct timer_list encoder_wait_timer; + + /* Place to block while waiting for state changes */ + wait_queue_head_t state_wait_data; + + int flag_ok; /* device in known good state */ int flag_disconnected; /* flag_ok == 0 due to disconnect */ int flag_init_ok; /* true if structure is fully initialized */ - int flag_streaming_enabled; /* true if streaming should be on */ int fw1_state; /* current situation with fw1 */ - int flag_encoder_ok; /* True if encoder is healthy */ - - int flag_decoder_is_tuned; + int flag_decoder_missed;/* We've noticed missing decoder */ + int flag_tripped; /* Indicates overall failure to start */ struct pvr2_decoder_ctrl *decoder_ctrl; @@ -241,12 +279,6 @@ struct pvr2_hdw { unsigned int fw_size; int fw_cpu_flag; /* True if we are dealing with the CPU */ - // Which subsystem pieces have been enabled / configured - unsigned long subsys_enabled_mask; - - // Which subsystems are manipulated to enable streaming - unsigned long subsys_stream_mask; - // True if there is a request to trigger logging of state in each // module. int log_requested; @@ -296,13 +328,16 @@ struct pvr2_hdw { /* Location of eeprom or a negative number if none */ int eeprom_addr; - enum pvr2_config config; + enum pvr2_config active_stream_type; + enum pvr2_config desired_stream_type; /* Control state needed for cx2341x module */ struct cx2341x_mpeg_params enc_cur_state; struct cx2341x_mpeg_params enc_ctl_state; /* True if an encoder attribute has changed */ int enc_stale; + /* True if an unsafe encoder attribute has changed */ + int enc_unsafe_stale; /* True if enc_cur_state is valid */ int enc_cur_valid; @@ -332,6 +367,7 @@ struct pvr2_hdw { /* This function gets the current frequency */ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *); +void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *); #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 402c5948825..4e55a2a8407 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -246,32 +246,46 @@ static const char *control_values_hsm[] = { }; -static const char *control_values_subsystem[] = { - [PVR2_SUBSYS_B_ENC_FIRMWARE] = "enc_firmware", - [PVR2_SUBSYS_B_ENC_CFG] = "enc_config", - [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run", - [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run", - [PVR2_SUBSYS_B_ENC_RUN] = "enc_run", +static const char *pvr2_state_names[] = { + [PVR2_STATE_NONE] = "none", + [PVR2_STATE_DEAD] = "dead", + [PVR2_STATE_COLD] = "cold", + [PVR2_STATE_WARM] = "warm", + [PVR2_STATE_ERROR] = "error", + [PVR2_STATE_READY] = "ready", + [PVR2_STATE_RUN] = "run", }; + +static void pvr2_hdw_state_sched(struct pvr2_hdw *); +static int pvr2_hdw_state_eval(struct pvr2_hdw *); static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); +static void pvr2_hdw_worker_i2c(struct work_struct *work); +static void pvr2_hdw_worker_poll(struct work_struct *work); +static void pvr2_hdw_worker_init(struct work_struct *work); +static int pvr2_hdw_wait(struct pvr2_hdw *,int state); +static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); +static void pvr2_hdw_state_log_state(struct pvr2_hdw *); 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_commit_setup(struct pvr2_hdw *hdw); static int pvr2_hdw_get_eeprom_addr(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); -static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val); -static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val); +static void pvr2_hdw_quiescent_timeout(unsigned long); +static void pvr2_hdw_encoder_wait_timeout(unsigned long); 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 void trace_stbit(const char *name,int val) +{ + pvr2_trace(PVR2_TRACE_STBITS, + "State bit %s <-- %s", + name,(val ? "true" : "false")); +} + static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) { struct pvr2_hdw *hdw = cptr->hdw; @@ -480,6 +494,7 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) { cptr->hdw->enc_stale = 0; + cptr->hdw->enc_unsafe_stale = 0; } static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) @@ -502,6 +517,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) { int ret; + struct pvr2_hdw *hdw = cptr->hdw; struct v4l2_ext_controls cs; struct v4l2_ext_control c1; memset(&cs,0,sizeof(cs)); @@ -510,10 +526,22 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, + ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, + hdw->state_encoder_run, &cs, VIDIOC_S_EXT_CTRLS); + if (ret == -EBUSY) { + /* Oops. cx2341x is telling us it's not safe to change + this control while we're capturing. Make a note of this + fact so that the pipeline will be stopped the next time + controls are committed. Then go on ahead and store this + change anyway. */ + ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, + 0, &cs, + VIDIOC_S_EXT_CTRLS); + if (!ret) hdw->enc_unsafe_stale = !0; + } if (ret) return ret; - cptr->hdw->enc_stale = !0; + hdw->enc_stale = !0; return 0; } @@ -544,7 +572,13 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) { - *vp = cptr->hdw->flag_streaming_enabled; + *vp = cptr->hdw->state_pipeline_req; + return 0; +} + +static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp) +{ + *vp = cptr->hdw->master_state; return 0; } @@ -657,29 +691,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp) return 0; } -static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->subsys_enabled_mask; - return 0; -} - -static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v) -{ - pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v); - return 0; -} - -static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->subsys_stream_mask; - return 0; -} - -static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v) -{ - pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v); - return 0; -} static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v) { @@ -914,6 +925,11 @@ static const struct pvr2_ctl_info control_defs[] = { .name = "usb_speed", .get_value = ctrl_hsm_get, DEFENUM(control_values_hsm), + },{ + .desc = "Master State", + .name = "master_state", + .get_value = ctrl_masterstate_get, + DEFENUM(pvr2_state_names), },{ .desc = "Signal Present", .name = "signal_present", @@ -954,20 +970,6 @@ static const struct pvr2_ctl_info control_defs[] = { .val_to_sym = ctrl_std_val_to_sym, .sym_to_val = ctrl_std_sym_to_val, .type = pvr2_ctl_bitmask, - },{ - .desc = "Subsystem enabled mask", - .name = "debug_subsys_mask", - .skip_init = !0, - .get_value = ctrl_subsys_get, - .set_value = ctrl_subsys_set, - DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), - },{ - .desc = "Subsystem stream mask", - .name = "debug_subsys_stream_mask", - .skip_init = !0, - .get_value = ctrl_subsys_stream_get, - .set_value = ctrl_subsys_stream_set, - DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), },{ .desc = "Video Standard Name", .name = "video_standard", @@ -1248,8 +1250,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) time we configure the encoder, then we'll fully configure it. */ hdw->enc_cur_valid = 0; - hdw->flag_encoder_ok = 0; - /* First prepare firmware loading */ ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ @@ -1347,293 +1347,129 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "firmware2 upload post-proc failure"); - } else { - hdw->flag_encoder_ok = !0; - hdw->subsys_enabled_mask |= (1<flag_ok) return; - - msk &= PVR2_SUBSYS_ALL; - nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk); - nmsk &= PVR2_SUBSYS_ALL; - - for (;;) { - tryCount++; - if (!((nmsk ^ hdw->subsys_enabled_mask) & - PVR2_SUBSYS_ALL)) break; - if (tryCount > 4) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Too many retries when configuring device;" - " giving up"); - pvr2_hdw_render_useless(hdw); - break; - } - if (tryCount > 1) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Retrying device reconfiguration"); - } - pvr2_trace(PVR2_TRACE_INIT, - "subsys mask changing 0x%lx:0x%lx" - " from 0x%lx to 0x%lx", - msk,val,hdw->subsys_enabled_mask,nmsk); - - vmsk = (nmsk ^ hdw->subsys_enabled_mask) & - hdw->subsys_enabled_mask; - if (vmsk) { - if (vmsk & (1<subsys_enabled_mask &= - ~FIRMWARE_RECOVERY_BITS; - continue; - } - } - if (vmsk & (1<decoder_ctrl) { - hdw->decoder_ctrl->enable( - hdw->decoder_ctrl->ctxt,0); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING:" - " No decoder present"); - } - hdw->subsys_enabled_mask &= - ~(1<subsys_enabled_mask &= - ~(vmsk & PVR2_SUBSYS_CFG_ALL); - } - } - vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk; - if (vmsk) { - if (vmsk & (1<subsys_enabled_mask &= - ~FIRMWARE_RECOVERY_BITS; - continue; - } - } - if (vmsk & (1<decoder_ctrl) { - hdw->decoder_ctrl->enable( - hdw->decoder_ctrl->ctxt,!0); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING:" - " No decoder present"); - } - hdw->subsys_enabled_mask |= - (1<subsys_enabled_mask &= - ~FIRMWARE_RECOVERY_BITS; - continue; - } - } - } +static const char *pvr2_get_state_name(unsigned int st) +{ + if (st < ARRAY_SIZE(pvr2_state_names)) { + return pvr2_state_names[st]; } + return "???"; } - -void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val) +static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) { - LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val); - } while (0); LOCK_GIVE(hdw->big_lock); + if (!hdw->decoder_ctrl) { + if (!hdw->flag_decoder_missed) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "WARNING: No decoder present"); + hdw->flag_decoder_missed = !0; + trace_stbit("flag_decoder_missed", + hdw->flag_decoder_missed); + } + return -EIO; + } + hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl); + return 0; } -unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw) +void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr) { - return hdw->subsys_enabled_mask; + if (hdw->decoder_ctrl == ptr) return; + hdw->decoder_ctrl = ptr; + if (hdw->decoder_ctrl && hdw->flag_decoder_missed) { + hdw->flag_decoder_missed = 0; + trace_stbit("flag_decoder_missed", + hdw->flag_decoder_missed); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Decoder has appeared"); + pvr2_hdw_state_sched(hdw); + } } -unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw) +int pvr2_hdw_get_state(struct pvr2_hdw *hdw) { - return hdw->subsys_stream_mask; + return hdw->master_state; } -static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) +static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw) { - unsigned long val2; - msk &= PVR2_SUBSYS_ALL; - val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk)); - pvr2_trace(PVR2_TRACE_INIT, - "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx", - msk,val,hdw->subsys_stream_mask,val2); - hdw->subsys_stream_mask = val2; + if (!hdw->flag_tripped) return 0; + hdw->flag_tripped = 0; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Clearing driver error statuss"); + return !0; } -void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) +int pvr2_hdw_untrip(struct pvr2_hdw *hdw) { + int fl; LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val); + fl = pvr2_hdw_untrip_unlocked(hdw); } while (0); LOCK_GIVE(hdw->big_lock); + if (fl) pvr2_hdw_state_sched(hdw); + return 0; } -static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl) +const char *pvr2_hdw_get_state_name(unsigned int id) { - if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0; - if (enableFl) { - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ enable"); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0); - } else { - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ disable"); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); - } - if (!hdw->flag_ok) return -EIO; - hdw->flag_streaming_enabled = enableFl != 0; - return 0; + if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL; + return pvr2_state_names[id]; } int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) { - return hdw->flag_streaming_enabled != 0; + return hdw->state_pipeline_req != 0; } int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) { - int ret; + int ret,st; LOCK_TAKE(hdw->big_lock); do { - ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag); + pvr2_hdw_untrip_unlocked(hdw); + if ((!enable_flag) != !(hdw->state_pipeline_req)) { + hdw->state_pipeline_req = enable_flag != 0; + pvr2_trace(PVR2_TRACE_START_STOP, + "/*--TRACE_STREAM--*/ %s", + enable_flag ? "enable" : "disable"); + } + pvr2_hdw_state_sched(hdw); } while (0); LOCK_GIVE(hdw->big_lock); - return ret; -} - - -static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw, - enum pvr2_config config) -{ - unsigned long sm = hdw->subsys_enabled_mask; - if (!hdw->flag_ok) return -EIO; - pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); - hdw->config = config; - pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm); + if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; + if (enable_flag) { + while ((st = hdw->master_state) != PVR2_STATE_RUN) { + if (st != PVR2_STATE_READY) return -EIO; + if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret; + } + } return 0; } int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) { - int ret; - if (!hdw->flag_ok) return -EIO; + int fl; LOCK_TAKE(hdw->big_lock); - ret = pvr2_hdw_set_stream_type_no_lock(hdw,config); + if ((fl = (hdw->desired_stream_type != config)) != 0) { + hdw->desired_stream_type = config; + hdw->state_pipeline_config = 0; + trace_stbit("state_pipeline_config", + hdw->state_pipeline_config); + pvr2_hdw_state_sched(hdw); + } LOCK_GIVE(hdw->big_lock); - return ret; + if (fl) return 0; + return pvr2_hdw_wait(hdw,0); } @@ -1866,12 +1702,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { pvr2_hdw_cmd_powerup(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; - - if (pvr2_upload_firmware2(hdw)){ - pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); - pvr2_hdw_render_useless(hdw); - return; - } } // This step MUST happen after the earlier powerup step. @@ -1924,8 +1754,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; - pvr2_hdw_commit_ctl_internal(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; + pvr2_hdw_commit_setup(hdw); hdw->vid_stream = pvr2_stream_create(); if (!pvr2_hdw_dev_ok(hdw)) return; @@ -1945,25 +1774,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; - /* Make sure everything is up to date */ - pvr2_i2c_core_sync(hdw); - - if (!pvr2_hdw_dev_ok(hdw)) return; - hdw->flag_init_ok = !0; + + pvr2_hdw_state_sched(hdw); } -int pvr2_hdw_setup(struct pvr2_hdw *hdw) +/* Set up the structure and attempt to put the device into a usable state. + This can be a time-consuming operation, which is why it is not done + internally as part of the create() step. */ +static void pvr2_hdw_setup(struct pvr2_hdw *hdw) { pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); - LOCK_TAKE(hdw->big_lock); do { + do { pvr2_hdw_setup_low(hdw); pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", - hdw,hdw->flag_ok,hdw->flag_init_ok); + hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok); if (pvr2_hdw_dev_ok(hdw)) { - if (pvr2_hdw_init_ok(hdw)) { + if (hdw->flag_init_ok) { pvr2_trace( PVR2_TRACE_INFO, "Device initialization" @@ -2013,9 +1842,8 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw) " the pvrusb2 device" " in order to recover."); } - } while (0); LOCK_GIVE(hdw->big_lock); + } while (0); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); - return hdw->flag_init_ok; } @@ -2044,6 +1872,19 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", hdw,pvr2_device_names[hdw_type]); if (!hdw) goto fail; + + init_timer(&hdw->quiescent_timer); + hdw->quiescent_timer.data = (unsigned long)hdw; + hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout; + + init_timer(&hdw->encoder_wait_timer); + hdw->encoder_wait_timer.data = (unsigned long)hdw; + hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout; + + hdw->master_state = PVR2_STATE_DEAD; + + init_waitqueue_head(&hdw->state_wait_data); + hdw->tuner_signal_stale = !0; cx2341x_fill_defaults(&hdw->enc_ctl_state); @@ -2184,18 +2025,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; hdw->name[cnt1] = 0; + hdw->workqueue = create_singlethread_workqueue(hdw->name); + INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); + INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c); + INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init); + pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", hdw->unit_number,hdw->name); hdw->tuner_type = -1; hdw->flag_ok = !0; - /* Initialize the mask of subsystems that we will shut down when we - stop streaming. */ - hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL; - hdw->subsys_stream_mask |= (1<subsys_stream_mask); hdw->usb_intf = intf; hdw->usb_dev = interface_to_usbdev(intf); @@ -2211,15 +2050,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, mutex_init(&hdw->ctl_lock_mutex); mutex_init(&hdw->big_lock_mutex); + queue_work(hdw->workqueue,&hdw->workinit); return hdw; fail: if (hdw) { + del_timer_sync(&hdw->quiescent_timer); + del_timer_sync(&hdw->encoder_wait_timer); + if (hdw->workqueue) { + flush_workqueue(hdw->workqueue); + destroy_workqueue(hdw->workqueue); + hdw->workqueue = NULL; + } usb_free_urb(hdw->ctl_read_urb); usb_free_urb(hdw->ctl_write_urb); kfree(hdw->ctl_read_buffer); kfree(hdw->ctl_write_buffer); kfree(hdw->controls); kfree(hdw->mpeg_ctrl_info); + kfree(hdw->std_defs); + kfree(hdw->std_enum_names); kfree(hdw); } return NULL; @@ -2250,10 +2099,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) kfree(hdw->ctl_write_buffer); hdw->ctl_write_buffer = NULL; } - pvr2_hdw_render_useless_unlocked(hdw); hdw->flag_disconnected = !0; hdw->usb_dev = NULL; hdw->usb_intf = NULL; + pvr2_hdw_render_useless(hdw); } @@ -2262,6 +2111,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) { if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); + del_timer_sync(&hdw->quiescent_timer); + del_timer_sync(&hdw->encoder_wait_timer); + if (hdw->workqueue) { + flush_workqueue(hdw->workqueue); + destroy_workqueue(hdw->workqueue); + hdw->workqueue = NULL; + } if (hdw->fw_buffer) { kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; @@ -2290,12 +2146,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) } -int pvr2_hdw_init_ok(struct pvr2_hdw *hdw) -{ - return hdw->flag_init_ok; -} - - int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) { return (hdw && hdw->flag_ok); @@ -2473,17 +2323,11 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp) } -/* Commit all control changes made up to this point. Subsystems can be - indirectly affected by these changes. For a given set of things being - committed, we'll clear the affected subsystem bits and then once we're - done committing everything we'll make a request to restore the subsystem - state(s) back to their previous value before this function was called. - Thus we can automatically reconfigure affected pieces of the driver as - controls are changed. */ -static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) +/* Figure out if we need to commit control changes. If so, mark internal + state flags to indicate this fact and return true. Otherwise do nothing + else and return false. */ +static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) { - unsigned long saved_subsys_mask = hdw->subsys_enabled_mask; - unsigned long stale_subsys_mask = 0; unsigned int idx; struct pvr2_ctrl *cptr; int value; @@ -2518,6 +2362,25 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) return 0; } + hdw->state_pipeline_config = 0; + trace_stbit("state_pipeline_config",hdw->state_pipeline_config); + pvr2_hdw_state_sched(hdw); + + return !0; +} + + +/* Perform all operations needed to commit all control changes. This must + be performed in synchronization with the pipeline state and is thus + expected to be called as part of the driver's worker thread. Return + true if commit successful, otherwise return false to indicate that + commit isn't possible at this time. */ +static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) +{ + unsigned int idx; + struct pvr2_ctrl *cptr; + int disruptive_change; + /* When video standard changes, reset the hres and vres values - but if the user has pending changes there, then let the changes take priority. */ @@ -2536,24 +2399,26 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) } } - if (hdw->std_dirty || - hdw->enc_stale || - hdw->srate_dirty || - hdw->res_ver_dirty || - hdw->res_hor_dirty || - 0) { - /* If any of this changes, then the encoder needs to be - reconfigured, and we need to reset the stream. */ - stale_subsys_mask |= (1<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< encoder connection be made quiescent before we + can proceed. */ + disruptive_change = + (hdw->std_dirty || + hdw->enc_unsafe_stale || + hdw->srate_dirty || + hdw->res_ver_dirty || + hdw->res_hor_dirty || + hdw->input_dirty || + (hdw->active_stream_type != hdw->desired_stream_type)); + if (disruptive_change && !hdw->state_pipeline_idle) { + /* Pipeline is not idle; we can't proceed. Arrange to + cause pipeline to stop so that we can try this again + later.... */ + hdw->state_pipeline_pause = !0; + return 0; } - if (hdw->srate_dirty) { /* Write new sample rate into control structure since * the master copy is stale. We must track srate @@ -2582,51 +2447,88 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) cptr->info->clear_dirty(cptr); } + if (hdw->active_stream_type != hdw->desired_stream_type) { + /* Handle any side effects of stream config here */ + hdw->active_stream_type = hdw->desired_stream_type; + } + /* Now execute i2c core update */ pvr2_i2c_core_sync(hdw); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask); + if (hdw->state_encoder_run) { + /* If encoder isn't running, then this will get worked out + later when we start the encoder. */ + if (pvr2_encoder_adjust(hdw) < 0) return !0; + } - return 0; + hdw->state_pipeline_config = !0; + trace_stbit("state_pipeline_config",hdw->state_pipeline_config); + return !0; } int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) { + int fl; + LOCK_TAKE(hdw->big_lock); + fl = pvr2_hdw_commit_setup(hdw); + LOCK_GIVE(hdw->big_lock); + if (!fl) return 0; + return pvr2_hdw_wait(hdw,0); +} + + +static void pvr2_hdw_worker_i2c(struct work_struct *work) +{ + struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync); LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_commit_ctl_internal(hdw); + pvr2_i2c_core_sync(hdw); } while (0); LOCK_GIVE(hdw->big_lock); - return 0; } -void pvr2_hdw_poll(struct pvr2_hdw *hdw) +static void pvr2_hdw_worker_poll(struct work_struct *work) { + int fl = 0; + struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll); LOCK_TAKE(hdw->big_lock); do { - pvr2_i2c_core_sync(hdw); + fl = pvr2_hdw_state_eval(hdw); } while (0); LOCK_GIVE(hdw->big_lock); + if (fl && hdw->state_func) { + hdw->state_func(hdw->state_data); + } } -void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw, - void (*func)(void *), - void *data) +static void pvr2_hdw_worker_init(struct work_struct *work) { + struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit); LOCK_TAKE(hdw->big_lock); do { - hdw->poll_trigger_func = func; - hdw->poll_trigger_data = data; + pvr2_hdw_setup(hdw); } while (0); LOCK_GIVE(hdw->big_lock); } -void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw) +static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) { - if (hdw->poll_trigger_func) { - hdw->poll_trigger_func(hdw->poll_trigger_data); - } + return wait_event_interruptible( + hdw->state_wait_data, + (hdw->state_stale == 0) && + (!state || (hdw->master_state != state))); +} + + +void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw, + void (*callback_func)(void *), + void *callback_data) +{ + LOCK_TAKE(hdw->big_lock); do { + hdw->state_data = callback_data; + hdw->state_func = callback_func; + } while (0); LOCK_GIVE(hdw->big_lock); } + /* Return name for this driver instance */ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) { @@ -2689,6 +2591,7 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) pvr2_i2c_core_sync(hdw); pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); + pvr2_hdw_state_log_state(hdw); printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); } while (0); LOCK_GIVE(hdw->big_lock); } @@ -2959,7 +2862,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, " without lock!!"); return -EDEADLK; } - if ((!hdw->flag_ok) && !probe_fl) { + if (!hdw->flag_ok && !probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " when device not ok"); @@ -3167,7 +3070,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, hdw->cmd_debug_state = 0; if ((status < 0) && (!probe_fl)) { - pvr2_hdw_render_useless_unlocked(hdw); + pvr2_hdw_render_useless(hdw); } return status; } @@ -3227,24 +3130,17 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) } -static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw) +void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) { if (!hdw->flag_ok) return; - pvr2_trace(PVR2_TRACE_INIT,"render_useless"); - hdw->flag_ok = 0; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Device being rendered inoperable"); if (hdw->vid_stream) { pvr2_stream_setup(hdw->vid_stream,NULL,0,0); } - hdw->flag_streaming_enabled = 0; - hdw->subsys_enabled_mask = 0; -} - - -void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) -{ - LOCK_TAKE(hdw->ctl_lock); - pvr2_hdw_render_useless_unlocked(hdw); - LOCK_GIVE(hdw->ctl_lock); + hdw->flag_ok = 0; + trace_stbit("flag_ok",hdw->flag_ok); + pvr2_hdw_state_sched(hdw); } @@ -3299,7 +3195,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) int status; LOCK_TAKE(hdw->ctl_lock); do { pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset"); - hdw->flag_ok = !0; 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); @@ -3349,26 +3244,473 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) (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) { - hdw->subsys_enabled_mask = - ((hdw->subsys_enabled_mask & - ~(1<state_encoder_ok) return 0; + if (hdw->flag_tripped) return 0; + if (hdw->state_encoder_run) return 0; + if (hdw->state_encoder_config) return 0; + if (hdw->state_decoder_run) return 0; + if (hdw->state_usbstream_run) return 0; + if (pvr2_upload_firmware2(hdw) < 0) { + hdw->flag_tripped = !0; + trace_stbit("flag_tripped",hdw->flag_tripped); + return !0; + } + hdw->state_encoder_ok = !0; + trace_stbit("state_encoder_ok",hdw->state_encoder_ok); + return !0; +} + + +/* Evaluate whether or not state_encoder_config can change */ +static int state_eval_encoder_config(struct pvr2_hdw *hdw) +{ + if (hdw->state_encoder_config) { + if (hdw->state_encoder_ok) { + if (hdw->state_pipeline_req && + !hdw->state_pipeline_pause) return 0; + } + hdw->state_encoder_config = 0; + hdw->state_encoder_waitok = 0; + trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); + /* paranoia - solve race if timer just completed */ + del_timer_sync(&hdw->encoder_wait_timer); + } else { + if (!hdw->state_encoder_ok || + !hdw->state_pipeline_idle || + hdw->state_pipeline_pause || + !hdw->state_pipeline_req || + !hdw->state_pipeline_config) { + /* We must reset the enforced wait interval if + anything has happened that might have disturbed + the encoder. This should be a rare case. */ + if (timer_pending(&hdw->encoder_wait_timer)) { + del_timer_sync(&hdw->encoder_wait_timer); + } + if (hdw->state_encoder_waitok) { + /* Must clear the state - therefore we did + something to a state bit and must also + return true. */ + hdw->state_encoder_waitok = 0; + trace_stbit("state_encoder_waitok", + hdw->state_encoder_waitok); + return !0; + } + return 0; + } + if (!hdw->state_encoder_waitok) { + if (!timer_pending(&hdw->encoder_wait_timer)) { + /* waitok flag wasn't set and timer isn't + running. Check flag once more to avoid + a race then start the timer. This is + the point when we measure out a minimal + quiet interval before doing something to + the encoder. */ + if (!hdw->state_encoder_waitok) { + hdw->encoder_wait_timer.expires = + jiffies + (HZ*50/1000); + add_timer(&hdw->encoder_wait_timer); + } + } + /* We can't continue until we know we have been + quiet for the interval measured by this + timer. */ + return 0; + } + pvr2_encoder_configure(hdw); + if (hdw->state_encoder_ok) hdw->state_encoder_config = !0; + } + trace_stbit("state_encoder_config",hdw->state_encoder_config); + return !0; +} + + +/* Evaluate whether or not state_encoder_run can change */ +static int state_eval_encoder_run(struct pvr2_hdw *hdw) +{ + if (hdw->state_encoder_run) { + if (hdw->state_encoder_ok) { + if (hdw->state_decoder_run) return 0; + if (pvr2_encoder_stop(hdw) < 0) return !0; + } + hdw->state_encoder_run = 0; + } else { + if (!hdw->state_encoder_ok) return 0; + if (!hdw->state_decoder_run) return 0; + if (pvr2_encoder_start(hdw) < 0) return !0; + hdw->state_encoder_run = !0; + } + trace_stbit("state_encoder_run",hdw->state_encoder_run); + return !0; +} + + +/* Timeout function for quiescent timer. */ +static void pvr2_hdw_quiescent_timeout(unsigned long data) +{ + struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; + hdw->state_decoder_quiescent = !0; + trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); + hdw->state_stale = !0; + queue_work(hdw->workqueue,&hdw->workpoll); +} + + +/* Timeout function for encoder wait timer. */ +static void pvr2_hdw_encoder_wait_timeout(unsigned long data) +{ + struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; + hdw->state_encoder_waitok = !0; + trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); + hdw->state_stale = !0; + queue_work(hdw->workqueue,&hdw->workpoll); +} + + +/* Evaluate whether or not state_decoder_run can change */ +static int state_eval_decoder_run(struct pvr2_hdw *hdw) +{ + if (hdw->state_decoder_run) { + if (hdw->state_encoder_ok) { + if (hdw->state_pipeline_req && + !hdw->state_pipeline_pause) return 0; + } + if (!hdw->flag_decoder_missed) { + pvr2_decoder_enable(hdw,0); + } + hdw->state_decoder_quiescent = 0; + hdw->state_decoder_run = 0; + /* paranoia - solve race if timer just completed */ + del_timer_sync(&hdw->quiescent_timer); + } else { + if (!hdw->state_decoder_quiescent) { + if (!timer_pending(&hdw->quiescent_timer)) { + /* We don't do something about the + quiescent timer until right here because + we also want to catch cases where the + decoder was already not running (like + after initialization) as opposed to + knowing that we had just stopped it. + The second flag check is here to cover a + race - the timer could have run and set + this flag just after the previous check + but before we did the pending check. */ + if (!hdw->state_decoder_quiescent) { + hdw->quiescent_timer.expires = + jiffies + (HZ*50/1000); + add_timer(&hdw->quiescent_timer); + } + } + /* Don't allow decoder to start again until it has + been quiesced first. This little detail should + hopefully further stabilize the encoder. */ + return 0; + } + if (!hdw->state_pipeline_req || + hdw->state_pipeline_pause || + !hdw->state_pipeline_config || + !hdw->state_encoder_config || + !hdw->state_encoder_ok) return 0; + del_timer_sync(&hdw->quiescent_timer); + if (hdw->flag_decoder_missed) return 0; + if (pvr2_decoder_enable(hdw,!0) < 0) return 0; + hdw->state_decoder_quiescent = 0; + hdw->state_decoder_run = !0; + } + trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); + trace_stbit("state_decoder_run",hdw->state_decoder_run); + return !0; +} + + +/* Evaluate whether or not state_usbstream_run can change */ +static int state_eval_usbstream_run(struct pvr2_hdw *hdw) +{ + if (hdw->state_usbstream_run) { + if (hdw->state_encoder_ok) { + if (hdw->state_encoder_run) return 0; + } + pvr2_hdw_cmd_usbstream(hdw,0); + hdw->state_usbstream_run = 0; + } else { + if (!hdw->state_encoder_ok || + !hdw->state_encoder_run || + !hdw->state_pipeline_req || + hdw->state_pipeline_pause) return 0; + if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0; + hdw->state_usbstream_run = !0; + } + trace_stbit("state_usbstream_run",hdw->state_usbstream_run); + return !0; +} + + +/* Attempt to configure pipeline, if needed */ +static int state_eval_pipeline_config(struct pvr2_hdw *hdw) +{ + if (hdw->state_pipeline_config || + hdw->state_pipeline_pause) return 0; + pvr2_hdw_commit_execute(hdw); + return !0; +} + + +/* Update pipeline idle and pipeline pause tracking states based on other + inputs. This must be called whenever the other relevant inputs have + changed. */ +static int state_update_pipeline_state(struct pvr2_hdw *hdw) +{ + unsigned int st; + int updatedFl = 0; + /* Update pipeline state */ + st = !(hdw->state_encoder_run || + hdw->state_decoder_run || + hdw->state_usbstream_run || + (!hdw->state_decoder_quiescent)); + if (!st != !hdw->state_pipeline_idle) { + hdw->state_pipeline_idle = st; + updatedFl = !0; + } + if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) { + hdw->state_pipeline_pause = 0; + updatedFl = !0; + } + return updatedFl; +} + + +typedef int (*state_eval_func)(struct pvr2_hdw *); + +/* Set of functions to be run to evaluate various states in the driver. */ +const static state_eval_func eval_funcs[] = { + state_eval_pipeline_config, + state_eval_encoder_ok, + state_eval_encoder_config, + state_eval_decoder_run, + state_eval_encoder_run, + state_eval_usbstream_run, +}; + + +/* Process various states and return true if we did anything interesting. */ +static int pvr2_hdw_state_update(struct pvr2_hdw *hdw) +{ + unsigned int i; + int state_updated = 0; + int check_flag; + + if (!hdw->state_stale) return 0; + if ((hdw->fw1_state != FW1_STATE_OK) || + !hdw->flag_ok) { + hdw->state_stale = 0; + return !0; + } + /* This loop is the heart of the entire driver. It keeps trying to + evaluate various bits of driver state until nothing changes for + one full iteration. Each "bit of state" tracks some global + aspect of the driver, e.g. whether decoder should run, if + pipeline is configured, usb streaming is on, etc. We separately + evaluate each of those questions based on other driver state to + arrive at the correct running configuration. */ + do { + check_flag = 0; + state_update_pipeline_state(hdw); + /* Iterate over each bit of state */ + for (i = 0; (iflag_ok; i++) { + if ((*eval_funcs[i])(hdw)) { + check_flag = !0; + state_updated = !0; + state_update_pipeline_state(hdw); + } + } + } while (check_flag && hdw->flag_ok); + hdw->state_stale = 0; + trace_stbit("state_stale",hdw->state_stale); + return state_updated; +} + + +static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, + char *buf,unsigned int acnt) +{ + switch (which) { + case 0: + return scnprintf( + buf,acnt, + "driver:%s%s%s%s%s", + (hdw->flag_ok ? " " : " "), + (hdw->flag_init_ok ? " " : " "), + (hdw->flag_disconnected ? " " : + " "), + (hdw->flag_tripped ? " " : ""), + (hdw->flag_decoder_missed ? " " : "")); + case 1: + return scnprintf( + buf,acnt, + "pipeline:%s%s%s%s", + (hdw->state_pipeline_idle ? " " : ""), + (hdw->state_pipeline_config ? + " " : " "), + (hdw->state_pipeline_req ? " " : ""), + (hdw->state_pipeline_pause ? " " : "")); + case 2: + return scnprintf( + buf,acnt, + "worker:%s%s%s%s%s%s", + (hdw->state_decoder_run ? + " " : + (hdw->state_decoder_quiescent ? + "" : " ")), + (hdw->state_decoder_quiescent ? + " " : ""), + (hdw->state_encoder_ok ? + "" : " "), + (hdw->state_encoder_run ? + " " : " "), + (hdw->state_encoder_config ? + " " : + (hdw->state_encoder_waitok ? + "" : " ")), + (hdw->state_usbstream_run ? + " " : " ")); + break; + case 3: + return scnprintf( + buf,acnt, + "state: %s", + pvr2_get_state_name(hdw->master_state)); + break; + default: break; + } + return 0; +} + + +unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, + char *buf,unsigned int acnt) +{ + unsigned int bcnt,ccnt,idx; + bcnt = 0; + LOCK_TAKE(hdw->big_lock); + for (idx = 0; ; idx++) { + ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt); + if (!ccnt) break; + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + if (!acnt) break; + buf[0] = '\n'; ccnt = 1; + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + } + LOCK_GIVE(hdw->big_lock); + return bcnt; +} + + +static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw) +{ + char buf[128]; + unsigned int idx,ccnt; + + for (idx = 0; ; idx++) { + ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf)); + if (!ccnt) break; + printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf); + } +} + + +/* Evaluate and update the driver's current state, taking various actions + as appropriate for the update. */ +static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) +{ + unsigned int st; + int state_updated = 0; + int callback_flag = 0; + + pvr2_trace(PVR2_TRACE_STBITS, + "Drive state check START"); + if (pvrusb2_debug & PVR2_TRACE_STBITS) { + pvr2_hdw_state_log_state(hdw); + } + + /* Process all state and get back over disposition */ + state_updated = pvr2_hdw_state_update(hdw); + + /* Update master state based upon all other states. */ + if (!hdw->flag_ok) { + st = PVR2_STATE_DEAD; + } else if (hdw->fw1_state != FW1_STATE_OK) { + st = PVR2_STATE_COLD; + } else if (!hdw->state_encoder_ok) { + st = PVR2_STATE_WARM; + } else if (hdw->flag_tripped || hdw->flag_decoder_missed) { + st = PVR2_STATE_ERROR; + } else if (hdw->state_encoder_run && + hdw->state_decoder_run && + hdw->state_usbstream_run) { + st = PVR2_STATE_RUN; + } else { + st = PVR2_STATE_READY; + } + if (hdw->master_state != st) { + pvr2_trace(PVR2_TRACE_STATE, + "Device state change from %s to %s", + pvr2_get_state_name(hdw->master_state), + pvr2_get_state_name(st)); + hdw->master_state = st; + state_updated = !0; + callback_flag = !0; + } + if (state_updated) { + /* Trigger anyone waiting on any state changes here. */ + wake_up(&hdw->state_wait_data); + } + + if (pvrusb2_debug & PVR2_TRACE_STBITS) { + pvr2_hdw_state_log_state(hdw); + } + pvr2_trace(PVR2_TRACE_STBITS, + "Drive state check DONE callback=%d",callback_flag); + + return callback_flag; +} + + +/* Cause kernel thread to check / update driver state */ +static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) +{ + if (hdw->state_stale) return; + hdw->state_stale = !0; + trace_stbit("state_stale",hdw->state_stale); + queue_work(hdw->workqueue,&hdw->workpoll); +} + + +void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *ptr) { ptr->big_lock_held = hdw->big_lock_held; ptr->ctl_lock_held = hdw->ctl_lock_held; - ptr->flag_ok = hdw->flag_ok; ptr->flag_disconnected = hdw->flag_disconnected; ptr->flag_init_ok = hdw->flag_init_ok; - ptr->flag_streaming_enabled = hdw->flag_streaming_enabled; - ptr->subsys_flags = hdw->subsys_enabled_mask; + ptr->flag_ok = hdw->flag_ok; + ptr->fw1_state = hdw->fw1_state; + ptr->flag_decoder_missed = hdw->flag_decoder_missed; + ptr->flag_tripped = hdw->flag_tripped; + ptr->state_encoder_ok = hdw->state_encoder_ok; + ptr->state_encoder_run = hdw->state_encoder_run; + ptr->state_decoder_run = hdw->state_decoder_run; + ptr->state_usbstream_run = hdw->state_usbstream_run; + ptr->state_decoder_quiescent = hdw->state_decoder_quiescent; + ptr->state_pipeline_config = hdw->state_pipeline_config; + ptr->state_pipeline_req = hdw->state_pipeline_req; + ptr->state_pipeline_pause = hdw->state_pipeline_pause; + ptr->state_pipeline_idle = hdw->state_pipeline_idle; ptr->cmd_debug_state = hdw->cmd_debug_state; ptr->cmd_code = hdw->cmd_debug_code; ptr->cmd_debug_write_len = hdw->cmd_debug_write_len; @@ -3381,6 +3723,15 @@ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, } +void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *ptr) +{ + LOCK_TAKE(hdw->ctl_lock); do { + pvr2_hdw_get_debug_info_unlocked(hdw,ptr); + } while(0); LOCK_GIVE(hdw->ctl_lock); +} + + int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) { return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index e2f9d5e4cb6..383685f7c81 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -44,27 +44,6 @@ #define PVR2_CVAL_INPUT_COMPOSITE 2 #define PVR2_CVAL_INPUT_RADIO 3 -/* 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 - for debugging. */ -#define PVR2_SUBSYS_B_ENC_FIRMWARE 0 -#define PVR2_SUBSYS_B_ENC_CFG 1 -#define PVR2_SUBSYS_B_DIGITIZER_RUN 2 -#define PVR2_SUBSYS_B_USBSTREAM_RUN 3 -#define PVR2_SUBSYS_B_ENC_RUN 4 - -#define PVR2_SUBSYS_CFG_ALL ( \ - (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \ - (1 << PVR2_SUBSYS_B_ENC_CFG) ) -#define PVR2_SUBSYS_RUN_ALL ( \ - (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \ - (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \ - (1 << PVR2_SUBSYS_B_ENC_RUN) ) -#define PVR2_SUBSYS_ALL ( \ - PVR2_SUBSYS_CFG_ALL | \ - PVR2_SUBSYS_RUN_ALL ) - enum pvr2_config { pvr2_config_empty, /* No configuration */ pvr2_config_mpeg, /* Encoded / compressed video */ @@ -79,8 +58,41 @@ enum pvr2_v4l_type { pvr2_v4l_type_radio, }; +/* Major states that we can be in: + * + * DEAD - Device is in an unusable state and cannot be recovered. This + * can happen if we completely lose the ability to communicate with it + * (but it might still on the bus). In this state there's nothing we can + * do; it must be replugged in order to recover. + * + * COLD - Device is in an unusuable state, needs microcontroller firmware. + * + * WARM - We can communicate with the device and the proper + * microcontroller firmware is running, but other device initialization is + * still needed (e.g. encoder firmware). + * + * ERROR - A problem prevents capture operation (e.g. encoder firmware + * missing). + * + * READY - Device is operational, but not streaming. + * + * RUN - Device is streaming. + * + */ +#define PVR2_STATE_NONE 0 +#define PVR2_STATE_DEAD 1 +#define PVR2_STATE_COLD 2 +#define PVR2_STATE_WARM 3 +#define PVR2_STATE_ERROR 4 +#define PVR2_STATE_READY 5 +#define PVR2_STATE_RUN 6 + +/* Translate configuration enum to a string label */ const char *pvr2_config_get_name(enum pvr2_config); +/* Translate a master state enum to a string label */ +const char *pvr2_hdw_get_state_name(unsigned int); + struct pvr2_hdw; /* Create and return a structure for interacting with the underlying @@ -88,28 +100,13 @@ struct pvr2_hdw; struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, const struct usb_device_id *devid); -/* Poll for background activity (if any) */ -void pvr2_hdw_poll(struct pvr2_hdw *); - -/* Trigger a poll to take place later at a convenient time */ -void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *); - -/* Register a callback used to trigger a future poll */ -void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *, - void (*func)(void *), - void *data); - /* Destroy hardware interaction structure */ void pvr2_hdw_destroy(struct pvr2_hdw *); -/* Set up the structure and attempt to put the device into a usable state. - This can be a time-consuming operation, which is why it is not done - internally as part of the create() step. Return value is exactly the - same as pvr2_hdw_init_ok(). */ -int pvr2_hdw_setup(struct pvr2_hdw *); - -/* Initialization succeeded */ -int pvr2_hdw_init_ok(struct pvr2_hdw *); +/* Register a function to be called whenever the master state changes. */ +void pvr2_hdw_set_state_callback(struct pvr2_hdw *, + void (*callback_func)(void *), + void *callback_data); /* Return true if in the ready (normal) state */ int pvr2_hdw_dev_ok(struct pvr2_hdw *); @@ -167,6 +164,9 @@ int pvr2_hdw_set_streaming(struct pvr2_hdw *,int); /* Find out if streaming is on */ int pvr2_hdw_get_streaming(struct pvr2_hdw *); +/* Retrieve driver overall state */ +int pvr2_hdw_get_state(struct pvr2_hdw *); + /* Configure the type of stream to generate */ int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config); @@ -177,26 +177,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, unsigned int idx); -/* Enable / disable various pieces of hardware. Items to change are - identified by bit positions within msk, and new state for each item is - identified by corresponding bit positions within val. */ -void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val); - -/* Retrieve mask indicating which pieces of hardware are currently enabled - / configured. */ -unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *); - -/* Adjust mask of what get shut down when streaming is stopped. This is a - debugging aid. */ -void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val); - -/* Retrieve mask indicating which pieces of hardware are disabled when - streaming is turned off. */ -unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); - - /* Enable / disable retrieval of CPU firmware or prom contents. This must be enabled before pvr2_hdw_cpufw_get() will function. Note that doing this may prevent the device from running (and leaving this mode may @@ -253,6 +233,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int); /* Execute a USB-commanded device reset */ void pvr2_hdw_device_reset(struct pvr2_hdw *); +/* Reset worker's error trapping circuit breaker */ +int pvr2_hdw_untrip(struct pvr2_hdw *); + /* Execute hard reset command (after this point it's likely that the encoder will have to be reconfigured). This also clears the "useless" state. */ @@ -275,11 +258,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val); struct pvr2_hdw_debug_info { int big_lock_held; int ctl_lock_held; - int flag_ok; int flag_disconnected; int flag_init_ok; - int flag_streaming_enabled; - unsigned long subsys_flags; + int flag_ok; + int fw1_state; + int flag_decoder_missed; + int flag_tripped; + int state_encoder_ok; + int state_encoder_run; + int state_decoder_run; + int state_usbstream_run; + int state_decoder_quiescent; + int state_pipeline_config; + int state_pipeline_req; + int state_pipeline_pause; + int state_pipeline_idle; int cmd_debug_state; int cmd_debug_write_len; int cmd_debug_read_len; @@ -295,8 +288,20 @@ struct pvr2_hdw_debug_info { diagnosing lockups. Note that this operation is completed without any kind of locking and so it is not atomic and may yield inconsistent results. This is *purely* a debugging aid. */ -void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); +void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *); + +/* Intrusively retrieve internal state info - this is useful for + diagnosing overall driver state. This operation synchronizes against + the overall driver mutex - so if there are locking problems this will + likely hang! This is *purely* a debugging aid. */ +void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *); + +/* Report out several lines of text that describes driver internal state. + Results are written into the passed-in buffer. */ +unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, + char *buf_ptr,unsigned int buf_size); /* Cause modules to log their state once */ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index c817c864e6a..f8b7bd1e0d8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) list_add_tail(&cp->list,&hdw->i2c_clients); hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT; } while (0); mutex_unlock(&hdw->i2c_list_lock); - if (fl) pvr2_hdw_poll_trigger_unlocked(hdw); + if (fl) queue_work(hdw->workqueue,&hdw->worki2csync); return 0; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 7a596ea7cfe..6f06f595b86 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1015,10 +1015,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) sp = fh->dev_info->stream->stream; pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); pvr2_hdw_set_stream_type(hdw,fh->dev_info->config); - pvr2_hdw_set_streaming(hdw,!0); - ret = pvr2_ioread_set_enabled(fh->rhp,!0); - - return ret; + if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret; + return pvr2_ioread_set_enabled(fh->rhp,!0); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 61efa6f0220..767e49022f9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -129,7 +129,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = { static void decoder_detach(struct pvr2_v4l_decoder *ctxt) { ctxt->client->handler = NULL; - ctxt->hdw->decoder_ctrl = NULL; + pvr2_hdw_set_decoder(ctxt->hdw,NULL); kfree(ctxt); } @@ -217,7 +217,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw, ctxt->client = cp; ctxt->hdw = hdw; ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1; - hdw->decoder_ctrl = &ctxt->ctrl; + pvr2_hdw_set_decoder(hdw,&ctxt->ctrl); cp->handler = &ctxt->handler; pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up", cp->client->addr); -- cgit v1.2.3 From 989eb154eafad00c3b5039a3eca03e108dac1df8 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 01:53:12 -0300 Subject: V4L/DVB (6692): pvrusb2: Centralize device specific attributes into a single place The pvrusb2 driver currently supports two variants of the Hauppauge PVR USB2. However there are other hardware types potentially supportable, but the driver at the moment is not structured to make it easy to describe these minor variations. This changeset is the first set of changes to make such additional device support possible. Device attributes are held in several tables all contained within pvrusb2-devattr.c; all other device-specific driver behavior now derives from these tables. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 101 +++++++++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-devattr.h | 87 ++++++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-encoder.c | 16 ++-- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 6 +- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 91 +++---------------- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 3 - drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 8 +- drivers/media/video/pvrusb2/pvrusb2-main.c | 1 + 8 files changed, 219 insertions(+), 94 deletions(-) create mode 100644 drivers/media/video/pvrusb2/pvrusb2-devattr.c create mode 100644 drivers/media/video/pvrusb2/pvrusb2-devattr.h diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c new file mode 100644 index 00000000000..aebcb846de6 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -0,0 +1,101 @@ +/* + * + * $Id$ + * + * Copyright (C) 2007 Mike Isely + * + * 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 + * + */ + +/* + +This source file should encompass ALL per-device type information for the +driver. To define a new device, add elements to the pvr2_device_table and +pvr2_device_desc structures. + +*/ + +#include "pvrusb2-devattr.h" +#include + +/* Known major hardware variants, keyed from device ID */ +#define PVR2_HDW_TYPE_29XXX 0 +#define PVR2_HDW_TYPE_24XXX 1 + +struct usb_device_id pvr2_device_table[] = { + [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, + [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, + { } +}; + +/* Names of other client modules to request for 24xxx model hardware */ +static const char *pvr2_client_24xxx[] = { + "cx25840", + "tuner", + "wm8775", +}; + +/* Names of other client modules to request for 29xxx model hardware */ +static const char *pvr2_client_29xxx[] = { + "msp3400", + "saa7115", + "tuner", +}; + +/* Firmware file name(s) for 29xxx devices */ +static const char *pvr2_fw1_names_29xxx[] = { + "v4l-pvrusb2-29xxx-01.fw", +}; + +/* Firmware file name(s) for 29xxx devices */ +static const char *pvr2_fw1_names_24xxx[] = { + "v4l-pvrusb2-24xxx-01.fw", +}; + +const struct pvr2_device_desc pvr2_device_descriptions[] = { + [PVR2_HDW_TYPE_29XXX] = { + .description = "WinTV PVR USB2 Model Category 29xxxx", + .shortname = "29xxx", + .client_modules.lst = pvr2_client_29xxx, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx), + .fx2_firmware.lst = pvr2_fw1_names_29xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), + }, + [PVR2_HDW_TYPE_24XXX] = { + .description = "WinTV PVR USB2 Model Category 24xxxx", + .shortname = "24xxx", + .client_modules.lst = pvr2_client_24xxx, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx), + .fx2_firmware.lst = pvr2_fw1_names_24xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx), + .flag_has_cx25840 = !0, + .flag_has_wm8775 = !0, + }, +}; + +const unsigned int pvr2_device_count = ARRAY_SIZE(pvr2_device_descriptions); + +MODULE_DEVICE_TABLE(usb, pvr2_device_table); + + +/* + 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-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h new file mode 100644 index 00000000000..6576aefd27c --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -0,0 +1,87 @@ +/* + * + * $Id$ + * + * Copyright (C) 2005 Mike Isely + * + * 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_DEVATTR_H +#define __PVRUSB2_DEVATTR_H + +#include + +/* + + This header defines structures used to describe attributes of a device. + +*/ + + +struct pvr2_string_table { + const char **lst; + unsigned int cnt; +}; + + +/* This describes a particular hardware type (except for the USB device ID + which must live in a separate structure due to environmental + constraints). See the top of pvrusb2-hdw.c for where this is + instantiated. */ +struct pvr2_device_desc { + /* Single line text description of hardware */ + const char *description; + + /* Single token identifier for hardware */ + const char *shortname; + + /* List of additional client modules we need to load */ + struct pvr2_string_table client_modules; + + /* List of FX2 firmware file names we should search; if empty then + FX2 firmware check / load is skipped and we assume the device + was initialized from internal ROM. */ + struct pvr2_string_table fx2_firmware; + + /* If set, we don't bother trying to load cx23416 firmware. */ + char flag_skip_cx23416_firmware; + + /* Device does not require a powerup command to be issued. */ + char flag_no_powerup; + + /* Device has a cx25840 - this enables special additional logic to + handle it. */ + char flag_has_cx25840; + + /* Device has a wm8775 - this enables special additional logic to + ensure that it is found. */ + char flag_has_wm8775; +}; + +extern const struct pvr2_device_desc pvr2_device_descriptions[]; +extern struct usb_device_id pvr2_device_table[]; +extern const unsigned int pvr2_device_count; + +#endif /* __PVRUSB2_HDW_INTERNAL_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-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 5ca548cc7e7..4271b413266 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -370,13 +370,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) /* 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; + saa7115 case is strange - the Windows driver is passing 1 + regardless of device type but if we have 1 for saa7115 + devices the video turns sluggish. */ + if (hdw->hdw_desc->flag_has_cx25840) { + encMisc3Arg = 1; + } else { + encMisc3Arg = 0; } ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3, encMisc3Arg,0,0); @@ -434,7 +434,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) /* saa7115: 0xf0 */ val = 0xf0; - if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { + if (hdw->hdw_desc->flag_has_cx25840) { /* ivtv cx25840: 0x140 */ val = 0x140; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 8ee4549b7a9..8c2d222960f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -40,6 +40,7 @@ #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" #include +#include "pvrusb2-devattr.h" /* Legal values for PVR2_CID_HSM */ #define PVR2_CVAL_HSM_FAIL 0 @@ -162,10 +163,6 @@ struct pvr2_decoder_ctrl { #define FW1_STATE_RELOAD 3 #define FW1_STATE_OK 4 -/* Known major hardware variants, keyed from device ID */ -#define PVR2_HDW_TYPE_29XXX 0 -#define PVR2_HDW_TYPE_24XXX 1 - typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16); #define PVR2_I2C_FUNC_CNT 128 @@ -179,6 +176,7 @@ struct pvr2_hdw { /* Device type, one of PVR2_HDW_TYPE_xxxxx */ unsigned int hdw_type; + const struct pvr2_device_desc *hdw_desc; /* Kernel worker thread handling */ struct workqueue_struct *workqueue; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 4e55a2a8407..c56208456bc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -41,47 +41,6 @@ #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) }, - [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, pvr2_device_table); - -static const char *pvr2_device_names[] = { - [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx", - [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx", -}; - -struct pvr2_string_table { - const char **lst; - unsigned int cnt; -}; - -// Names of other client modules to request for 24xxx model hardware -static const char *pvr2_client_24xxx[] = { - "cx25840", - "tuner", - "wm8775", -}; - -// Names of other client modules to request for 29xxx model hardware -static const char *pvr2_client_29xxx[] = { - "msp3400", - "saa7115", - "tuner", -}; - -static struct pvr2_string_table pvr2_client_lists[] = { - [PVR2_HDW_TYPE_29XXX] = { - pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx) - }, - [PVR2_HDW_TYPE_24XXX] = { - pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx) - }, -}; - static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; static DEFINE_MUTEX(pvr2_unit_mtx); @@ -394,8 +353,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) { - /* Actual minimum depends on device type. */ - if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { + /* Actual minimum depends on device digitizer type. */ + if (cptr->hdw->hdw_desc->flag_has_cx25840) { *vp = 75; } else { *vp = 17; @@ -1131,23 +1090,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) unsigned int pipe; int ret; u16 address; - static const char *fw_files_29xxx[] = { - "v4l-pvrusb2-29xxx-01.fw", - }; - static const char *fw_files_24xxx[] = { - "v4l-pvrusb2-24xxx-01.fw", - }; - static const struct pvr2_string_table fw_file_defs[] = { - [PVR2_HDW_TYPE_29XXX] = { - fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx) - }, - [PVR2_HDW_TYPE_24XXX] = { - fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx) - }, - }; - if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) || - (!fw_file_defs[hdw->hdw_type].lst)) { + if (!hdw->hdw_desc->fx2_firmware.cnt) { hdw->fw1_state = FW1_STATE_OK; return 0; } @@ -1157,8 +1101,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) trace_firmware("pvr2_upload_firmware1"); ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", - fw_file_defs[hdw->hdw_type].cnt, - fw_file_defs[hdw->hdw_type].lst); + hdw->hdw_desc->fx2_firmware.cnt, + hdw->hdw_desc->fx2_firmware.lst); if (ret < 0) { if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; return ret; @@ -1233,8 +1177,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) CX2341X_FIRM_ENC_FILENAME, }; - if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) && - (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) { + if (hdw->hdw_desc->flag_skip_cx23416_firmware) { return 0; } @@ -1652,8 +1595,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) unsigned int idx; struct pvr2_ctrl *cptr; int reloadFl = 0; - if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || - (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (hdw->hdw_desc->fx2_firmware.cnt) { if (!reloadFl) { reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints @@ -1689,17 +1631,11 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } if (!pvr2_hdw_dev_ok(hdw)) return; - if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) { - for (idx = 0; - idx < pvr2_client_lists[hdw->hdw_type].cnt; - idx++) { - request_module( - pvr2_client_lists[hdw->hdw_type].lst[idx]); - } + for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) { + request_module(hdw->hdw_desc->client_modules.lst[idx]); } - if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || - (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (!hdw->hdw_desc->flag_no_powerup) { pvr2_hdw_cmd_powerup(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; } @@ -1857,20 +1793,22 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, unsigned int hdw_type; int valid_std_mask; struct pvr2_ctrl *cptr; + const struct pvr2_device_desc *hdw_desc; __u8 ifnum; struct v4l2_queryctrl qctrl; struct pvr2_ctl_info *ciptr; hdw_type = devid - pvr2_device_table; - if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) { + if (hdw_type >= pvr2_device_count) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Bogus device type of %u reported",hdw_type); return NULL; } + hdw_desc = pvr2_device_descriptions + hdw_type; hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", - hdw,pvr2_device_names[hdw_type]); + hdw,hdw_desc->description); if (!hdw) goto fail; init_timer(&hdw->quiescent_timer); @@ -1894,6 +1832,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, GFP_KERNEL); if (!hdw->controls) goto fail; hdw->hdw_type = hdw_type; + hdw->hdw_desc = hdw_desc; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; cptr->hdw = hdw; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 383685f7c81..205fa03057e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -311,9 +311,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); a debugging aid. */ int pvr2_upload_firmware2(struct pvr2_hdw *hdw); -/* List of device types that we can match */ -extern struct usb_device_id pvr2_device_table[]; - #endif /* __PVRUSB2_HDW_H */ /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index f8b7bd1e0d8..7721ec85d57 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -980,14 +980,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { + if (hdw->hdw_desc->flag_has_cx25840) { hdw->i2c_func[0x18] = i2c_24xxx_ir; } } - if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { - hdw->i2c_func[0x1b] = i2c_hack_wm8775; + if (hdw->hdw_desc->flag_has_cx25840) { hdw->i2c_func[0x44] = i2c_hack_cx25840; } + if (hdw->hdw_desc->flag_has_wm8775) { + hdw->i2c_func[0x1b] = i2c_hack_wm8775; + } // Configure the adapter and set up everything else related to it. memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap)); diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 11b3b2e84b9..a8370737b50 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -28,6 +28,7 @@ #include #include "pvrusb2-hdw.h" +#include "pvrusb2-devattr.h" #include "pvrusb2-context.h" #include "pvrusb2-debug.h" #include "pvrusb2-v4l2.h" -- cgit v1.2.3 From f8bcec6d1814862e299e2a32ff9dbb0be0ff6ceb Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:30:20 -0300 Subject: V4L/DVB (6693): pvrusb2: Add pvrusb2-devattr.o to driver build Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index 69b3e43cd0e..47284e55864 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -6,7 +6,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ pvrusb2-encoder.o pvrusb2-video-v4l.o \ pvrusb2-eeprom.o pvrusb2-tuner.o \ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \ - pvrusb2-ctrl.o pvrusb2-std.o \ + pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y) -- cgit v1.2.3 From f66fbd71f24f5f0264bb8526cfb91ea5c6219f50 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 01:55:07 -0300 Subject: V4L/DVB (6694): pvrusb2: Remove obsolete global hardware type enumeration Device-specific driver behavior is now defined by generic device characteristics rather than by specific device model information. With this change, the hardware type field can go away, thus this change. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 4 ++-- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 8c2d222960f..894c630c95c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -174,8 +174,8 @@ struct pvr2_hdw { struct usb_device *usb_dev; struct usb_interface *usb_intf; - /* Device type, one of PVR2_HDW_TYPE_xxxxx */ - unsigned int hdw_type; + /* Device description, anything that must adjust behavior based on + device specific info will use information held here. */ const struct pvr2_device_desc *hdw_desc; /* Kernel worker thread handling */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index c56208456bc..c08162cc20a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1831,7 +1831,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, GFP_KERNEL); if (!hdw->controls) goto fail; - hdw->hdw_type = hdw_type; hdw->hdw_desc = hdw_desc; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; -- cgit v1.2.3 From 78a47101ac0ac75019a740d62c70ccb16ff7c7c1 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 01:58:20 -0300 Subject: V4L/DVB (6695): pvrusb2: Implement functions to pass descriptive hardware info Implement additional pvrusb2 device info table entries for a device identifier and a device description. Export this information via the driver's internal API. Make this information available via the sysfs driver interface. Also propagate this information into the v4l2 capability structure. An app can now retrieve and report a descriptive string about the particular type of hardware device it is operating. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 12 ++++++ drivers/media/video/pvrusb2/pvrusb2-hdw.h | 6 +++ drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 60 +++++++++++++++++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 1 + 4 files changed, 79 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index c08162cc20a..4ffaf3faff5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2474,6 +2474,18 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) } +const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw) +{ + return hdw->hdw_desc->description; +} + + +const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw) +{ + return hdw->hdw_desc->shortname; +} + + int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) { int result; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 205fa03057e..3ad7a13d6c3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -158,6 +158,12 @@ 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 *); +/* Return a string token representative of the hardware type */ +const char *pvr2_hdw_get_type(struct pvr2_hdw *); + +/* Return a single line description of the hardware type */ +const char *pvr2_hdw_get_desc(struct pvr2_hdw *); + /* Turn streaming on/off */ int pvr2_hdw_set_streaming(struct pvr2_hdw *,int); diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 3c57a7d8200..7a1cd878e31 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -43,10 +43,14 @@ struct pvr2_sysfs { struct device_attribute attr_v4l_radio_minor_number; struct device_attribute attr_unit_number; struct device_attribute attr_bus_info; + struct device_attribute attr_hdw_name; + struct device_attribute attr_hdw_desc; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; int bus_info_created_ok; + int hdw_name_created_ok; + int hdw_desc_created_ok; }; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC @@ -712,6 +716,14 @@ 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->hdw_desc_created_ok) { + device_remove_file(sfp->class_dev, + &sfp->attr_hdw_desc); + } + if (sfp->hdw_name_created_ok) { + device_remove_file(sfp->class_dev, + &sfp->attr_hdw_name); + } if (sfp->bus_info_created_ok) { device_remove_file(sfp->class_dev, &sfp->attr_bus_info); @@ -758,6 +770,28 @@ static ssize_t bus_info_show(struct device *class_dev, } +static ssize_t hdw_name_show(struct device *class_dev, + struct device_attribute *attr, char *buf) +{ + struct pvr2_sysfs *sfp; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; + if (!sfp) return -EINVAL; + return scnprintf(buf,PAGE_SIZE,"%s\n", + pvr2_hdw_get_type(sfp->channel.hdw)); +} + + +static ssize_t hdw_desc_show(struct device *class_dev, + struct device_attribute *attr, char *buf) +{ + struct pvr2_sysfs *sfp; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; + if (!sfp) return -EINVAL; + return scnprintf(buf,PAGE_SIZE,"%s\n", + pvr2_hdw_get_desc(sfp->channel.hdw)); +} + + static ssize_t v4l_radio_minor_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) @@ -871,6 +905,32 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->bus_info_created_ok = !0; } + sfp->attr_hdw_name.attr.name = "device_hardware_type"; + sfp->attr_hdw_name.attr.mode = S_IRUGO; + sfp->attr_hdw_name.show = hdw_name_show; + sfp->attr_hdw_name.store = NULL; + ret = device_create_file(sfp->class_dev, + &sfp->attr_hdw_name); + if (ret < 0) { + printk(KERN_WARNING "%s: device_create_file error: %d\n", + __FUNCTION__, ret); + } else { + sfp->hdw_name_created_ok = !0; + } + + sfp->attr_hdw_desc.attr.name = "device_hardware_description"; + sfp->attr_hdw_desc.attr.mode = S_IRUGO; + sfp->attr_hdw_desc.show = hdw_desc_show; + sfp->attr_hdw_desc.store = NULL; + ret = device_create_file(sfp->class_dev, + &sfp->attr_hdw_desc); + if (ret < 0) { + printk(KERN_WARNING "%s: device_create_file error: %d\n", + __FUNCTION__, ret); + } else { + sfp->hdw_desc_created_ok = !0; + } + pvr2_sysfs_add_controls(sfp); #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC pvr2_sysfs_add_debugifc(sfp); diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 6f06f595b86..8f0587ebd4b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -205,6 +205,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), sizeof(cap->bus_info)); + strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card)); ret = 0; break; -- cgit v1.2.3 From 56dcbfa0d5a46f137df5047ae8f3aab30f59954e Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:00:51 -0300 Subject: V4L/DVB (6696): pvrusb2: Miscellaneous tweaks for controlling tuner type and video standard Correctly mark when a tuner type is set. Report more faithfully information about known supported device video standards. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-eeprom.c | 1 + drivers/media/video/pvrusb2/pvrusb2-hdw.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c index 45cbca0143c..5ef005947b0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c @@ -144,6 +144,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) trace_eeprom("serial_number=%d",tvdata.serial_number); trace_eeprom("rev_str=%s",tvdata.rev_str); hdw->tuner_type = tvdata.tuner_type; + hdw->tuner_updated = !0; hdw->serial_number = tvdata.serial_number; hdw->std_mask_eeprom = tvdata.tuner_formats; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 4ffaf3faff5..6a7b9af55e4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1093,7 +1093,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) if (!hdw->hdw_desc->fx2_firmware.cnt) { hdw->fw1_state = FW1_STATE_OK; - return 0; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Connected device type defines" + " no firmware to upload; ignoring firmware"); + return -ENOTTY; } hdw->fw1_state = FW1_STATE_FAILED; // default result @@ -1524,7 +1527,8 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); pvr2_trace(PVR2_TRACE_STD, - "Supported video standard(s) reported by eeprom: %.*s", + "Supported video standard(s) reported available" + " in hardware: %.*s", bcnt,buf); hdw->std_mask_avail = hdw->std_mask_eeprom; @@ -1682,9 +1686,9 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_setup: Tuner type overridden to %d", hdw->tuner_type); + hdw->tuner_updated = !0; } - hdw->tuner_updated = !0; pvr2_i2c_core_check_stale(hdw); hdw->tuner_updated = 0; -- cgit v1.2.3 From aaf7884db395332ae8474f3ea5bcdd39c0a941ea Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:04:11 -0300 Subject: V4L/DVB (6697): pvrusb2: Existence of Hauppauge ROM is a device-specific attribute Arrange so that the pvrusb2 driver can optionally work without a Hauppauge ROM being present - which is fairly important for devices that happen to not come from Hauppauge. The expected existence of a Hauppauge ROM is now a device attribute. The tuner type is now also a device attribute, which is consulted if there is no ROM. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 2 ++ drivers/media/video/pvrusb2/pvrusb2-devattr.h | 7 +++++++ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 25 ++++++++++++++++--------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index aebcb846de6..54a401e8bb1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -72,6 +72,7 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx), .fx2_firmware.lst = pvr2_fw1_names_29xxx, .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), + .flag_has_hauppauge_rom = !0, }, [PVR2_HDW_TYPE_24XXX] = { .description = "WinTV PVR USB2 Model Category 24xxxx", @@ -82,6 +83,7 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx), .flag_has_cx25840 = !0, .flag_has_wm8775 = !0, + .flag_has_hauppauge_rom = !0, }, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index 6576aefd27c..f63c3ddb8a7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -55,9 +55,16 @@ struct pvr2_device_desc { was initialized from internal ROM. */ struct pvr2_string_table fx2_firmware; + /* V4L tuner type ID to use with this device (only used if the + driver could not discover the type any other way). */ + int default_tuner_type; + /* If set, we don't bother trying to load cx23416 firmware. */ char flag_skip_cx23416_firmware; + /* Device has a hauppauge eeprom which we can interrogate. */ + char flag_has_hauppauge_rom; + /* Device does not require a powerup command to be issued. */ char flag_no_powerup; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 6a7b9af55e4..b7b2d90a491 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1428,6 +1428,7 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw) } if (tp < 0) return -EINVAL; hdw->tuner_type = tp; + hdw->tuner_updated = !0; return 0; } @@ -1669,15 +1670,22 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) // thread-safe against the normal pvr2_send_request() mechanism. // (We should make it thread safe). - ret = pvr2_hdw_get_eeprom_addr(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to determine location of eeprom, skipping"); - } else { - hdw->eeprom_addr = ret; - pvr2_eeprom_analyze(hdw); + if (hdw->hdw_desc->flag_has_hauppauge_rom) { + ret = pvr2_hdw_get_eeprom_addr(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; + if (ret < 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Unable to determine location of eeprom," + " skipping"); + } else { + hdw->eeprom_addr = ret; + pvr2_eeprom_analyze(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; + } + } else { + hdw->tuner_type = hdw->hdw_desc->default_tuner_type; + hdw->tuner_updated = !0; + hdw->std_mask_eeprom = V4L2_STD_ALL; } pvr2_hdw_setup_std(hdw); @@ -1686,7 +1694,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_setup: Tuner type overridden to %d", hdw->tuner_type); - hdw->tuner_updated = !0; } pvr2_i2c_core_check_stale(hdw); -- cgit v1.2.3 From f5174af201f2e22c101bb02d06343e4bc5f056de Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:07:26 -0300 Subject: V4L/DVB (6698): pvrusb2: Implement signal routing schemes The exact routing of video and audio signals within a device is a device-specific attribute. Hauppauge devices do it one way; other types of device may route things differently. Unfortunately it is rather impractical to define chip-specific routing at the device attribute level, so instead what happens here is that "schemes" are defined. Each chip level interface implements its part of a given scheme and the scheme as a whole is made into a device specific attribute controlled via a table entry in pvrusb2-devattr.c. The only scheme defined here is for Hauppauge devices, but clearly this opens the door for other possibilities to follow. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-audio.c | 62 +++++++++++++------- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 69 ++++++++++++++++------- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 2 + drivers/media/video/pvrusb2/pvrusb2-devattr.h | 9 +++ drivers/media/video/pvrusb2/pvrusb2-video-v4l.c | 51 ++++++++++++----- 5 files changed, 140 insertions(+), 53 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 379645e481c..9a7c8e9c3e8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -35,34 +35,58 @@ struct pvr2_msp3400_handler { }; + +struct routing_scheme { + const int *def; + unsigned int cnt; +}; + +static const int routing_scheme0[] = { + [PVR2_CVAL_INPUT_TV] = MSP_INPUT_DEFAULT, + [PVR2_CVAL_INPUT_RADIO] = MSP_INPUT(MSP_IN_SCART2, + MSP_IN_TUNER1, + MSP_DSP_IN_SCART, + MSP_DSP_IN_SCART), + [PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1, + MSP_IN_TUNER1, + MSP_DSP_IN_SCART, + MSP_DSP_IN_SCART), + [PVR2_CVAL_INPUT_SVIDEO] = MSP_INPUT(MSP_IN_SCART1, + MSP_IN_TUNER1, + MSP_DSP_IN_SCART, + MSP_DSP_IN_SCART), +}; + +static const struct routing_scheme routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), + }, +}; + /* This function selects the correct audio input source */ static void set_stereo(struct pvr2_msp3400_handler *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; + const struct routing_scheme *sp; + unsigned int sid = hdw->hdw_desc->signal_routing_scheme; pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); - route.input = MSP_INPUT_DEFAULT; - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - switch (hdw->input_val) { - case PVR2_CVAL_INPUT_TV: - break; - case PVR2_CVAL_INPUT_RADIO: - /* Assume that msp34xx also handle FM decoding, in which case - we're still using the tuner. */ - /* HV: actually it is more likely to be the SCART2 input if - the ivtv experience is any indication. */ - route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case PVR2_CVAL_INPUT_SVIDEO: - case PVR2_CVAL_INPUT_COMPOSITE: - /* SCART 1 input */ - route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; + if ((sid < ARRAY_SIZE(routing_schemes)) && + ((sp = routing_schemes + sid) != 0) && + (hdw->input_val >= 0) && + (hdw->input_val < sp->cnt)) { + route.input = sp->def[hdw->input_val]; + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "*** WARNING *** i2c msp3400 v4l2 set_stereo:" + " Invalid routing scheme (%u) and/or input (%d)", + sid,hdw->input_val); + return; } + route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 2cca817e414..b6714c41ea7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -49,34 +49,65 @@ struct pvr2_v4l_cx2584x { }; +struct routing_scheme_item { + int vid; + int aud; +}; + +struct routing_scheme { + const struct routing_scheme_item *def; + unsigned int cnt; +}; + +static const struct routing_scheme_item routing_scheme0[] = { + [PVR2_CVAL_INPUT_TV] = { + .vid = CX25840_COMPOSITE7, + .aud = CX25840_AUDIO8, + }, + [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ + .vid = CX25840_COMPOSITE3, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE3, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = CX25840_SVIDEO1, + .aud = CX25840_AUDIO_SERIAL, + }, +}; + +static const struct routing_scheme routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), + }, +}; + static void set_input(struct pvr2_v4l_cx2584x *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; enum cx25840_video_input vid_input; enum cx25840_audio_input aud_input; + const struct routing_scheme *sp; + unsigned int sid = hdw->hdw_desc->signal_routing_scheme; memset(&route,0,sizeof(route)); - switch(hdw->input_val) { - case PVR2_CVAL_INPUT_TV: - 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; - break; - case PVR2_CVAL_INPUT_SVIDEO: - vid_input = CX25840_SVIDEO1; - aud_input = CX25840_AUDIO_SERIAL; - break; - default: - // Just set it to be composite input for now... - vid_input = CX25840_COMPOSITE3; - aud_input = CX25840_AUDIO_SERIAL; - break; + if ((sid < ARRAY_SIZE(routing_schemes)) && + ((sp = routing_schemes + sid) != 0) && + (hdw->input_val >= 0) && + (hdw->input_val < sp->cnt)) { + vid_input = sp->def[hdw->input_val].vid; + aud_input = sp->def[hdw->input_val].aud; + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "*** WARNING *** i2c cx2584x set_input:" + " Invalid routing scheme (%u) and/or input (%d)", + sid,hdw->input_val); + return; } pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x", diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 54a401e8bb1..464a13a0649 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -73,6 +73,7 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .fx2_firmware.lst = pvr2_fw1_names_29xxx, .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), .flag_has_hauppauge_rom = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, }, [PVR2_HDW_TYPE_24XXX] = { .description = "WinTV PVR USB2 Model Category 24xxxx", @@ -84,6 +85,7 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .flag_has_cx25840 = !0, .flag_has_wm8775 = !0, .flag_has_hauppauge_rom = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, }, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index f63c3ddb8a7..05eb2c669ee 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -35,6 +35,7 @@ struct pvr2_string_table { unsigned int cnt; }; +#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 /* This describes a particular hardware type (except for the USB device ID which must live in a separate structure due to environmental @@ -55,6 +56,14 @@ struct pvr2_device_desc { was initialized from internal ROM. */ struct pvr2_string_table fx2_firmware; + /* Signal routing scheme used by device, contains one of + PVR2_ROUTING_SCHEME_XXX. Schemes have to be defined as we + encounter them. This is an arbitrary integer scheme id; its + meaning is contained entirely within the driver and is + interpreted by logic which must send commands to the chip-level + drivers (search for things which touch this field). */ + unsigned int signal_routing_scheme; + /* V4L tuner type ID to use with this device (only used if the driver could not discover the type any other way). */ int default_tuner_type; diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 767e49022f9..7c47345501b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -49,29 +49,50 @@ struct pvr2_v4l_decoder { }; +struct routing_scheme { + const int *def; + unsigned int cnt; +}; + + +static const int routing_scheme0[] = { + [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4, + /* In radio mode, we mute the video, but point at one + spot just to stay consistent */ + [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5, + [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5, + [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, +}; + +static const struct routing_scheme routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), + }, +}; + static void set_input(struct pvr2_v4l_decoder *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; + const struct routing_scheme *sp; + unsigned int sid = hdw->hdw_desc->signal_routing_scheme; pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); - switch(hdw->input_val) { - case PVR2_CVAL_INPUT_TV: - route.input = SAA7115_COMPOSITE4; - break; - case PVR2_CVAL_INPUT_COMPOSITE: - route.input = SAA7115_COMPOSITE5; - break; - case PVR2_CVAL_INPUT_SVIDEO: - route.input = SAA7115_SVIDEO2; - break; - case PVR2_CVAL_INPUT_RADIO: - // In radio mode, we mute the video, but point at one - // spot just to stay consistent - route.input = SAA7115_COMPOSITE5; - default: + + if ((sid < ARRAY_SIZE(routing_schemes)) && + ((sp = routing_schemes + sid) != 0) && + (hdw->input_val >= 0) && + (hdw->input_val < sp->cnt)) { + route.input = sp->def[hdw->input_val]; + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "*** WARNING *** i2c v4l2 set_input:" + " Invalid routing scheme (%u) and/or input (%d)", + sid,hdw->input_val); return; } + route.output = 0; pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route); } -- cgit v1.2.3 From 056d1a899201f02777a35a32f8e6c9a2aac63f63 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:09:42 -0300 Subject: V4L/DVB (6699): pvrusb2: Use of virtual IR chip is a device-specific attribute For Hauppauge 24xxx devices, the IR receiver is a custom piece of logic that is very specific to the device. The pvrusb2 driver can virtualize this to make it look like a more normal IR receiver found in other Hauppauge devices. The decision of whether or not to enable this virtualization however is a device-specific attribute, thus this changeset. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 1 + drivers/media/video/pvrusb2/pvrusb2-devattr.h | 4 ++++ drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 464a13a0649..6ba0b79e3a1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -85,6 +85,7 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .flag_has_cx25840 = !0, .flag_has_wm8775 = !0, .flag_has_hauppauge_rom = !0, + .flag_has_hauppauge_custom_ir = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, }, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index 05eb2c669ee..2aff5a3d5a5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -84,6 +84,10 @@ struct pvr2_device_desc { /* Device has a wm8775 - this enables special additional logic to ensure that it is found. */ char flag_has_wm8775; + + /* Device has IR hardware that can be faked into looking like a + normal Hauppauge i2c IR receiver. */ + char flag_has_hauppauge_custom_ir; }; extern const struct pvr2_device_desc pvr2_device_descriptions[]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 7721ec85d57..62867fa3517 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -980,7 +980,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_desc->flag_has_cx25840) { + if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) { hdw->i2c_func[0x18] = i2c_24xxx_ir; } } -- cgit v1.2.3 From 65bd80fe18b6abb63776746646321b41b44d70a7 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:11:38 -0300 Subject: V4L/DVB (6700): pvrusb2: Soften the crashed encoder warning message The pvrusb2 driver has been successfully recovering from a crashed encoder now for over 2 years. I think it's time to reduce the perceived severity of the warning message. While I'd still very much like to stop these crashes, the recovery logic is solid enough that the problem is effectively benign. No point in panicing the users over it. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-encoder.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 4271b413266..52b39954f99 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -286,8 +286,7 @@ static int pvr2_encoder_cmd(void *ctxt, pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Giving up on command." - " It is likely that" - " this is a bad idea..."); + " This is normally recovered by the driver."); break; } wrData[0] = 0x7; -- cgit v1.2.3 From 9e2e3aeb2d2c8bf64b04e1f5747f1d9842df43de Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 26 Nov 2007 02:14:23 -0300 Subject: V4L/DVB (6701): pvrusb2: Enable support for "GOTVIEW USB2.0 DVD2" hardware This changeset allows the pvrusb2 driver to operate a new device type ("GOTVIEW USB2.0 DVD2"). Changes amount to defining a new routing scheme for the device and adding appropriate table entries into pvrusb2-devattr.c. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 24 +++++++++++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-devattr.c | 20 +++++++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-devattr.h | 1 + 3 files changed, 45 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index b6714c41ea7..ffdc45c324e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -78,11 +78,35 @@ static const struct routing_scheme_item routing_scheme0[] = { }, }; +/* Specific to gotview device */ +static const struct routing_scheme_item routing_schemegv[] = { + [PVR2_CVAL_INPUT_TV] = { + .vid = CX25840_COMPOSITE2, + .aud = CX25840_AUDIO5, + }, + [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ + .vid = CX25840_COMPOSITE1, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE1, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4), + .aud = CX25840_AUDIO_SERIAL, + }, +}; + static const struct routing_scheme routing_schemes[] = { [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { .def = routing_scheme0, .cnt = ARRAY_SIZE(routing_scheme0), }, + [PVR2_ROUTING_SCHEME_GOTVIEW] = { + .def = routing_schemegv, + .cnt = ARRAY_SIZE(routing_schemegv), + }, }; static void set_input(struct pvr2_v4l_cx2584x *ctxt) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 6ba0b79e3a1..e0a5bb9a958 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -29,14 +29,20 @@ pvr2_device_desc structures. #include "pvrusb2-devattr.h" #include +/* All this is needed in order to pull in tuner type ids... */ +#include +#include +#include /* Known major hardware variants, keyed from device ID */ #define PVR2_HDW_TYPE_29XXX 0 #define PVR2_HDW_TYPE_24XXX 1 +#define PVR2_HDW_TYPE_GOTVIEW_2 2 struct usb_device_id pvr2_device_table[] = { [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, + [PVR2_HDW_TYPE_GOTVIEW_2] = { USB_DEVICE(0x1164, 0x0622) }, { } }; @@ -54,6 +60,12 @@ static const char *pvr2_client_29xxx[] = { "tuner", }; +// Names of other client modules to request for Gotview 2 model hardware +static const char *pvr2_client_gotview_2[] = { + "cx25840", + "tuner", +}; + /* Firmware file name(s) for 29xxx devices */ static const char *pvr2_fw1_names_29xxx[] = { "v4l-pvrusb2-29xxx-01.fw", @@ -88,6 +100,14 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .flag_has_hauppauge_custom_ir = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, }, + [PVR2_HDW_TYPE_GOTVIEW_2] = { + .description = "Gotview USB 2.0 DVD 2", + .shortname = "gv2", + .client_modules.lst = pvr2_client_gotview_2, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2), + .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, + }, }; const unsigned int pvr2_device_count = ARRAY_SIZE(pvr2_device_descriptions); diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index 2aff5a3d5a5..b9517e1cac0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -36,6 +36,7 @@ struct pvr2_string_table { }; #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 +#define PVR2_ROUTING_SCHEME_GOTVIEW 1 /* This describes a particular hardware type (except for the USB device ID which must live in a separate structure due to environmental -- cgit v1.2.3 From 482cb9a75ba5df68f4bcbe806c838eaf28af34c0 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 27 Nov 2007 16:58:33 -0300 Subject: V4L/DVB (6702): pvrusb2: fix typo in comments Firmware file name(s) for 24xxx devices Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index e0a5bb9a958..e4a311a8100 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -71,7 +71,7 @@ static const char *pvr2_fw1_names_29xxx[] = { "v4l-pvrusb2-29xxx-01.fw", }; -/* Firmware file name(s) for 29xxx devices */ +/* Firmware file name(s) for 24xxx devices */ static const char *pvr2_fw1_names_24xxx[] = { "v4l-pvrusb2-24xxx-01.fw", }; -- cgit v1.2.3 From ea2562d94fade3d6ee9b22ed5addbbdba697d22a Mon Sep 17 00:00:00 2001 From: Roel Kluin <12o3l@tiscali.nl> Date: Sun, 2 Dec 2007 23:04:57 -0300 Subject: V4L/DVB (6703): pvrusb2: Change division to bit-or for tveeprom standards Signed-off-by: Roel Kluin <12o3l@tiscali.nl> Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index b7b2d90a491..a45721f7884 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1514,7 +1514,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = { }, { /* PAL(D/D1/K) */ .pat = V4L2_STD_DK, - .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K, + .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K, }, }; -- cgit v1.2.3 From 6a540254966f8a01de0f7c78a27db17458c2d8f5 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 2 Dec 2007 23:51:34 -0300 Subject: V4L/DVB (6705): pvrusb2: Implement default standard selection based on device type This adds a default video standard setting to the pvr2_device_desc structure for describing device types. With this change it is possible to set a reasonable default standard based on device type. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 3 +-- drivers/media/video/pvrusb2/pvrusb2-devattr.h | 7 +++++++ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 6 +++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index e4a311a8100..eed64571ca0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -29,9 +29,8 @@ pvr2_device_desc structures. #include "pvrusb2-devattr.h" #include -/* All this is needed in order to pull in tuner type ids... */ +/* This is needed in order to pull in tuner type ids... */ #include -#include #include /* Known major hardware variants, keyed from device ID */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index b9517e1cac0..830f27961e1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -22,6 +22,7 @@ #define __PVRUSB2_DEVATTR_H #include +#include /* @@ -69,6 +70,12 @@ struct pvr2_device_desc { driver could not discover the type any other way). */ int default_tuner_type; + /* Initial standard bits to use for this device, if not zero. + Anything set here is also implied as an available standard. + Note: This is ignored if overridden on the module load line via + the video_std module option. */ + v4l2_std_id default_std_mask; + /* If set, we don't bother trying to load cx23416 firmware. */ char flag_skip_cx23416_firmware; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index a45721f7884..08b513b6014 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1439,8 +1439,12 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) int tp = 0; if ((unit_number >= 0) && (unit_number < PVR_NUM)) { tp = video_std[unit_number]; + if (tp) return tp; } - return tp; + if (hdw->hdw_desc->default_std_mask) { + return hdw->hdw_desc->default_std_mask; + } + return 0; } -- cgit v1.2.3 From 26e33048aad0486c98155b1406037f02fe70cb1b Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 3 Dec 2007 01:43:23 -0300 Subject: V4L/DVB (6706): pvrusb2: Remove use of volatile in command sequencer pvrusb2: Remove use of volatile for command sequencer; these variables are set by interrupt-context code and we check their state in such a manner that there should be no race conditions. This had originally been done out of paranoia, and I have since been convinced that the paranoia is not required. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 894c630c95c..c79d3a68dbd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -217,9 +217,9 @@ struct pvr2_hdw { struct urb *ctl_read_urb; unsigned char *ctl_write_buffer; unsigned char *ctl_read_buffer; - volatile int ctl_write_pend_flag; - volatile int ctl_read_pend_flag; - volatile int ctl_timeout_flag; + int ctl_write_pend_flag; + int ctl_read_pend_flag; + int ctl_timeout_flag; struct completion ctl_done; unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE]; int cmd_debug_state; // Low level command debugging info -- cgit v1.2.3 From e802c14b91e3fddd50652270756124a69e550113 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 3 Dec 2007 01:44:43 -0300 Subject: V4L/DVB (6707): pvrusb2: Remove use of volatile in pipeline control state machine pvrusb2: Eliminate use of volatile in pipeline control state variables. These were all cases of paranoia; upon further review the overall mechanism employed here should not require use of volatile. This had originally been done out of paranoia, and I have since been convinced that the paranoia is not required. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index c79d3a68dbd..d7a216b41b7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -229,14 +229,14 @@ struct pvr2_hdw { /* Bits of state that describe what is going on with various parts of the driver. */ - volatile int state_encoder_ok; /* Encoder is operational */ - volatile int state_encoder_run; /* Encoder is running */ - volatile int state_encoder_config; /* Encoder is configured */ - volatile int state_encoder_waitok; /* Encoder pre-wait done */ - volatile int state_decoder_run; /* Decoder is running */ - volatile int state_usbstream_run; /* FX2 is streaming */ - volatile int state_decoder_quiescent; /* Decoder idle for > 50msec */ - volatile int state_pipeline_config; /* Pipeline is configured */ + int state_encoder_ok; /* Encoder is operational */ + int state_encoder_run; /* Encoder is running */ + int state_encoder_config; /* Encoder is configured */ + int state_encoder_waitok; /* Encoder pre-wait done */ + int state_decoder_run; /* Decoder is running */ + int state_usbstream_run; /* FX2 is streaming */ + int state_decoder_quiescent; /* Decoder idle for > 50msec */ + int state_pipeline_config; /* Pipeline is configured */ int state_pipeline_req; /* Somebody wants to stream */ int state_pipeline_pause; /* Pipeline must be paused */ int state_pipeline_idle; /* Pipeline not running */ -- cgit v1.2.3 From 4ca7f7092815cad5cb3a9377dce211202fe4b328 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 3 Dec 2007 01:45:26 -0300 Subject: V4L/DVB (6708): pvrusb2: Expand comment in device attributes description Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index 830f27961e1..a9c3d99b602 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -94,7 +94,13 @@ struct pvr2_device_desc { char flag_has_wm8775; /* Device has IR hardware that can be faked into looking like a - normal Hauppauge i2c IR receiver. */ + normal Hauppauge i2c IR receiver. This is currently very + specific to the 24xxx device, where Hauppauge had replaced their + 'standard' I2C IR receiver with a bunch of FPGA logic controlled + directly via the FX2. Turning this on tells the pvrusb2 driver + to virtualize the presence of the non-existant IR receiver chip and + implement the virtual receiver in terms of appropriate FX2 + commands. */ char flag_has_hauppauge_custom_ir; }; -- cgit v1.2.3 From 3d290bdb283c9dc897c5fd160fe3d07ead426c45 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 3 Dec 2007 01:47:12 -0300 Subject: V4L/DVB (6709): pvrusb2: minor rework for default video standard handling pvrusb2: When a per-device-type default video standard is declared, handle it in such a way that it can be correctly and unambiguously reported in the system log. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 08b513b6014..54d2c4ab7a3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1441,9 +1441,6 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) tp = video_std[unit_number]; if (tp) return tp; } - if (hdw->hdw_desc->default_std_mask) { - return hdw->hdw_desc->default_std_mask; - } return 0; } @@ -1526,9 +1523,10 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) { char buf[40]; unsigned int bcnt; - v4l2_std_id std1,std2; + v4l2_std_id std1,std2,std3; std1 = get_default_standard(hdw); + std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask; bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); pvr2_trace(PVR2_TRACE_STD, @@ -1538,7 +1536,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) hdw->std_mask_avail = hdw->std_mask_eeprom; - std2 = std1 & ~hdw->std_mask_avail; + std2 = (std1|std3) & ~hdw->std_mask_avail; if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); pvr2_trace(PVR2_TRACE_STD, @@ -1560,6 +1558,16 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) pvr2_hdw_internal_find_stdenum(hdw); return; } + if (std3) { + bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); + pvr2_trace(PVR2_TRACE_STD, + "Initial video standard" + " (determined by device type): %.*s",bcnt,buf); + hdw->std_mask_cur = std3; + hdw->std_dirty = !0; + pvr2_hdw_internal_find_stdenum(hdw); + return; + } { unsigned int idx; -- cgit v1.2.3 From 9de982d3117a3f83e4e7b14016a1df25b4a693d6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 3 Dec 2007 02:10:04 -0300 Subject: V4L/DVB (6710): pvrusb2: Recognize ATSC video standard bit values Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-std.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index 63e55bb59fc..da309288daa 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -50,6 +50,10 @@ struct std_name { V4L2_STD_NTSC_M_KR| \ V4L2_STD_NTSC_443) +#define CSTD_ATSC \ + (V4L2_STD_ATSC_8_VSB| \ + V4L2_STD_ATSC_16_VSB) + #define CSTD_SECAM \ (V4L2_STD_SECAM_B| \ V4L2_STD_SECAM_D| \ @@ -82,6 +86,7 @@ static const struct std_name std_groups[] = { {"PAL",CSTD_PAL}, {"NTSC",CSTD_NTSC}, {"SECAM",CSTD_SECAM}, + {"ATSC",CSTD_ATSC}, }; /* Mapping of standard bits to modulation system */ @@ -104,6 +109,8 @@ static const struct std_name std_items[] = { {"N",TSTD_N}, {"Nc",TSTD_Nc}, {"60",TSTD_60}, + {"8VSB",V4L2_STD_ATSC_8_VSB}, + {"16VSB",V4L2_STD_ATSC_16_VSB}, }; -- cgit v1.2.3 From c240ad00af78228726e6301ad6ffc54d3adce2a0 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Tue, 16 Oct 2007 03:21:46 -0300 Subject: V4L/DVB (6712): ivtv: ivtv yuv stream handling change Currently the yuv output stream buffer is divided into blocks whose size depend on the broadcast standard selected during the driver init phase. However, the standard can be changed after the init phase. This effectively breaks the yuv output stream handler, since it relies on the different yuv planes being block aligned. This patch changes the setup, so that the block size is always the same. The decoder dma function has been modified to cope with the fact that the second yuv plane may no longer be block aligned. The start of the yuv frame must still be at the beginning of a block, so the stream write function has also been modified to ensure this is always true. Also, the stream write function will now initiate a yuv dma transfer as soon as a full frame is ready. It will not wait until the current write request has completed, or the stream buffer becomes full. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 8 ++------ drivers/media/video/ivtv/ivtv-driver.h | 2 ++ drivers/media/video/ivtv/ivtv-fileops.c | 31 +++++++++++++++++++++++++++---- drivers/media/video/ivtv/ivtv-irq.c | 25 +++++++++++++++++++------ 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 04179b7d1af..48db22cc1bd 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -970,7 +970,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; - int yuv_buf_size; int vbi_buf_size; struct ivtv *itv; @@ -1122,11 +1121,8 @@ static int __devinit ivtv_probe(struct pci_dev *dev, itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; - - /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ - yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; + itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000; + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000; /* Setup VBI Raw Size. Should be big enough to hold PAL. It is possible to switch between PAL and NTSC, so we need to diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 49ce14d14a5..b6dd2360e61 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -485,6 +485,8 @@ struct yuv_playback_info void *blanking_ptr; dma_addr_t blanking_dmaptr; + + int stream_size; }; #define IVTV_VBI_FRAMES 32 diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index a200a8a95a2..58ad0d9c680 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -542,6 +542,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c struct ivtv_open_id *id = filp->private_data; struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; + struct yuv_playback_info *yi = &itv->yuv_info; struct ivtv_buffer *buf; struct ivtv_queue q; int bytes_written = 0; @@ -604,9 +605,16 @@ retry: /* copy user data into buffers */ while ((buf = ivtv_dequeue(s, &q))) { - /* Make sure we really got all the user data */ - rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); + /* yuv is a pain. Don't copy more data than needed for a single + frame, otherwise we lose sync with the incoming stream */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && + yi->stream_size + count > itv->dma_data_req_size) + rc = ivtv_buf_copy_from_user(s, buf, user_buf, + itv->dma_data_req_size - yi->stream_size); + else + rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); + /* Make sure we really got all the user data */ if (rc < 0) { ivtv_queue_move(s, &q, NULL, &s->q_free, 0); return rc; @@ -615,6 +623,16 @@ retry: count -= rc; bytes_written += rc; + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + yi->stream_size += rc; + /* If we have a complete yuv frame, break loop now */ + if (yi->stream_size == itv->dma_data_req_size) { + ivtv_enqueue(s, buf, &s->q_full); + yi->stream_size = 0; + break; + } + } + if (buf->bytesused != s->buf_size) { /* incomplete, leave in q_io for next time */ ivtv_enqueue(s, buf, &s->q_io); @@ -922,10 +940,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) { clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + /* For yuv, we need to know the dma size before we start */ + itv->dma_data_req_size = + itv->params.width * itv->params.height * 3 / 2; + itv->yuv_info.stream_size = 0; + } return 0; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fd1688e4757..bcf1c85991a 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -313,15 +313,28 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && + (bytes_written + buf->bytesused) >= y_size) { + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = y_size - bytes_written; offset = uv_offset; + if (s->sg_pending[idx].size != buf->bytesused) { + idx++; + s->sg_pending[idx].src = + buf->dma_handle + s->sg_pending[idx - 1].size; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = + buf->bytesused - s->sg_pending[idx - 1].size; + offset += s->sg_pending[idx].size; + } y_done = 1; + } else { + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; + offset += buf->bytesused; } - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = buf->bytesused; - - offset += buf->bytesused; bytes_written += buf->bytesused; /* Sync SG buffers */ -- cgit v1.2.3 From a3e5f5e2dfb50bebca24329e5377d804c6e3eb1b Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sat, 20 Oct 2007 14:52:55 -0300 Subject: V4L/DVB (6713): ivtv: ivtv_yuv_prep_frame breakup and yuv hardware buffer changes ivtv_yuv_prep_frame is split in smaller code blocks. Modified yuv buffer handling on the PVR350 itself. We now cycle through all 8 hardware buffers. With this patch in place, driver behaviour should remain unchanged from the existing release. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 1 + drivers/media/video/ivtv/ivtv-driver.h | 11 ++- drivers/media/video/ivtv/ivtv-irq.c | 31 +++---- drivers/media/video/ivtv/ivtv-yuv.c | 149 ++++++++++++++++++++------------- drivers/media/video/ivtv/ivtv-yuv.h | 7 +- 5 files changed, 117 insertions(+), 82 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 48db22cc1bd..e3020f45664 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -697,6 +697,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) atomic_set(&itv->yuv_info.next_dma_frame, -1); itv->yuv_info.lace_mode = ivtv_yuv_mode; itv->yuv_info.lace_threshold = ivtv_yuv_threshold; + itv->yuv_info.max_frames_buffered = 3; return 0; } diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index b6dd2360e61..12ff9382718 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -403,6 +403,8 @@ struct yuv_frame_info #define IVTV_YUV_SYNC_ODD 0x04 #define IVTV_YUV_SYNC_MASK 0x04 +#define IVTV_YUV_BUFFERS 8 + struct yuv_playback_info { u32 reg_2834; @@ -475,11 +477,11 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; - int sync_field[4]; /* Field to sync on */ - int field_delay[4]; /* Flag to extend duration of previous frame */ + int sync_field[IVTV_YUV_BUFFERS]; /* Field to sync on */ + int field_delay[IVTV_YUV_BUFFERS]; /* Flag to extend duration of previous frame */ u8 fields_lapsed; /* Counter used when delaying a frame */ - struct yuv_frame_info new_frame_info[4]; + struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; @@ -487,6 +489,9 @@ struct yuv_playback_info dma_addr_t blanking_dmaptr; int stream_size; + + u8 draw_frame; /* PVR350 buffer to draw into */ + u8 max_frames_buffered; /* Maximum number of frames to buffer */ }; #define IVTV_VBI_FRAMES 32 diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index bcf1c85991a..fc8eac09584 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -744,24 +744,25 @@ static void ivtv_irq_vsync(struct ivtv *itv) * one vsync per frame. */ unsigned int frame = read_reg(0x28c0) & 1; + struct yuv_playback_info *yi = &itv->yuv_info; int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { + if (((frame ^ yi->sync_field[last_dma_frame]) == 0 && + ((itv->last_vsync_field & 1) ^ yi->sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_field & 1) && !yi->frame_interlaced)) { int next_dma_frame = last_dma_frame; - if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { + if (!(yi->frame_interlaced && yi->field_delay[next_dma_frame] && yi->fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); - itv->yuv_info.fields_lapsed = -1; + next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; + atomic_set(&yi->next_dma_frame, next_dma_frame); + yi->fields_lapsed = -1; } } } @@ -794,20 +795,20 @@ static void ivtv_irq_vsync(struct ivtv *itv) } /* Check if we need to update the yuv registers */ - if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { - if (!itv->yuv_info.new_frame_info[last_dma_frame].update) + if ((yi->yuv_forced_update || yi->new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { + if (!yi->new_frame_info[last_dma_frame].update) last_dma_frame = (last_dma_frame - 1) & 3; - if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { - itv->yuv_info.update_frame = last_dma_frame; - itv->yuv_info.new_frame_info[last_dma_frame].update = 0; - itv->yuv_info.yuv_forced_update = 0; + if (yi->new_frame_info[last_dma_frame].src_w) { + yi->update_frame = last_dma_frame; + yi->new_frame_info[last_dma_frame].update = 0; + yi->yuv_forced_update = 0; set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } - itv->yuv_info.fields_lapsed ++; + yi->fields_lapsed++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 9091c4837bb..15e9bd2486d 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -22,11 +22,16 @@ #include "ivtv-udma.h" #include "ivtv-yuv.h" -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 +/* YUV buffer offsets */ +const u32 yuv_offset[IVTV_YUV_BUFFERS] = { + 0x001a8600, + 0x00240400, + 0x002d8200, + 0x00370000, + 0x00029000, + 0x000C0E00, + 0x006B0400, + 0x00748200 }; static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, @@ -37,10 +42,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, int i; int y_pages, uv_pages; - + u8 frame = itv->yuv_info.draw_frame; unsigned long y_buffer_offset, uv_buffer_offset; int y_decode_height, uv_decode_height, y_size; - int frame = atomic_read(&itv->yuv_info.next_fill_frame); y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; @@ -954,76 +958,105 @@ static void ivtv_yuv_init (struct ivtv *itv) atomic_set(&yi->next_dma_frame, 0); } -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +/* Get next available yuv buffer on PVR350 */ +void ivtv_yuv_next_free(struct ivtv *itv) { - DEFINE_WAIT(wait); - int rc = 0; - int got_sig = 0; - int frame, next_fill_frame, last_fill_frame; - int register_update = 0; + int draw, display; + struct yuv_playback_info *yi = &itv->yuv_info; - IVTV_DEBUG_INFO("yuv_prep_frame\n"); + if (atomic_read(&yi->next_dma_frame) == -1) + ivtv_yuv_init(itv); - if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); + draw = atomic_read(&yi->next_fill_frame); + display = atomic_read(&yi->next_dma_frame); - frame = atomic_read(&itv->yuv_info.next_fill_frame); - next_fill_frame = (frame + 1) & 0x3; - last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; + if (display > draw) + display -= IVTV_YUV_BUFFERS; - if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { - /* Buffers are full - Overwrite the last frame */ - next_fill_frame = frame; - frame = (frame - 1) & 3; - register_update = itv->yuv_info.new_frame_info[frame].update; - } + if (draw - display >= yi->max_frames_buffered) + draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; + else + yi->new_frame_info[draw].update = 0; + + yi->draw_frame = draw; +} + +/* Set up frame according to ivtv_dma_frame parameters */ +void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + + /* Preserve old update flag in case we're overwriting a queued frame */ + int register_update = yi->new_frame_info[frame].update; /* Take a snapshot of the yuv coordinate information */ - itv->yuv_info.new_frame_info[frame].src_x = args->src.left; - itv->yuv_info.new_frame_info[frame].src_y = args->src.top; - itv->yuv_info.new_frame_info[frame].src_w = args->src.width; - itv->yuv_info.new_frame_info[frame].src_h = args->src.height; - itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; - itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; - itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; - itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; - itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; + yi->new_frame_info[frame].src_x = args->src.left; + yi->new_frame_info[frame].src_y = args->src.top; + yi->new_frame_info[frame].src_w = args->src.width; + yi->new_frame_info[frame].src_h = args->src.height; + yi->new_frame_info[frame].dst_x = args->dst.left; + yi->new_frame_info[frame].dst_y = args->dst.top; + yi->new_frame_info[frame].dst_w = args->dst.width; + yi->new_frame_info[frame].dst_h = args->dst.height; + yi->new_frame_info[frame].tru_x = args->dst.left; + yi->new_frame_info[frame].tru_w = args->src_width; + yi->new_frame_info[frame].tru_h = args->src_height; /* Snapshot field order */ - itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; + yi->sync_field[frame] = yi->lace_sync_field; /* Are we going to offset the Y plane */ if (args->src.height + args->src.top < 512-16) - itv->yuv_info.new_frame_info[frame].offset_y = 1; + yi->new_frame_info[frame].offset_y = 1; else - itv->yuv_info.new_frame_info[frame].offset_y = 0; + yi->new_frame_info[frame].offset_y = 0; /* Snapshot the osd pan info */ - itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; - itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; - itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; - itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; - - itv->yuv_info.new_frame_info[frame].update = 0; - itv->yuv_info.new_frame_info[frame].interlaced_y = 0; - itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; - itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; - - if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], - sizeof (itv->yuv_info.new_frame_info[frame]))) { - memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); - itv->yuv_info.new_frame_info[frame].update = 1; -/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ + yi->new_frame_info[frame].pan_x = yi->osd_x_pan; + yi->new_frame_info[frame].pan_y = yi->osd_y_pan; + yi->new_frame_info[frame].vis_w = yi->osd_vis_w; + yi->new_frame_info[frame].vis_h = yi->osd_vis_h; + + yi->new_frame_info[frame].update = 0; + yi->new_frame_info[frame].interlaced_y = 0; + yi->new_frame_info[frame].interlaced_uv = 0; + yi->new_frame_info[frame].lace_mode = yi->lace_mode; + + if (memcmp(&yi->old_frame_info_args, &yi->new_frame_info[frame], + sizeof(yi->new_frame_info[frame]))) { + yi->old_frame_info_args = yi->new_frame_info[frame]; + yi->new_frame_info[frame].update = 1; +/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ } - itv->yuv_info.new_frame_info[frame].update |= register_update; + yi->new_frame_info[frame].update |= register_update; /* Should this frame be delayed ? */ - if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) - itv->yuv_info.field_delay[frame] = 1; + if (yi->sync_field[frame] != + yi->sync_field[(frame - 1) % IVTV_YUV_BUFFERS]) + yi->field_delay[frame] = 1; else - itv->yuv_info.field_delay[frame] = 0; + yi->field_delay[frame] = 0; +} + +/* Frame is complete & ready for display */ +void ivtv_yuv_frame_complete(struct ivtv *itv) +{ + atomic_set(&itv->yuv_info.next_fill_frame, + (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); +} + +int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + DEFINE_WAIT(wait); + int rc = 0; + int got_sig = 0; + + IVTV_DEBUG_INFO("yuv_prep_frame\n"); + + ivtv_yuv_next_free(itv); + ivtv_yuv_setup_frame(itv, args); /* DMA the frame */ mutex_lock(&itv->udma.lock); @@ -1057,7 +1090,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) return -EINTR; } - atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); + ivtv_yuv_frame_complete(itv); mutex_unlock(&itv->udma.lock); return rc; diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 3b966f0a204..3b290927d36 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -21,11 +21,6 @@ #ifndef IVTV_YUV_H #define IVTV_YUV_H -/* Buffers on hardware offsets */ -#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ /* Offset to filter table in firmware */ @@ -36,7 +31,7 @@ #define IVTV_YUV_UPDATE_VERTICAL 0x02 #define IVTV_YUV_UPDATE_INVALID 0x04 -extern const u32 yuv_offset[4]; +extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; int ivtv_yuv_filter_check(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); -- cgit v1.2.3 From 166983cdfbb2779bec98de89927669ed4c9ff8f2 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sun, 21 Oct 2007 08:09:10 -0300 Subject: V4L/DVB (6714): ivtv: yuv frame parameter fix Inadvertently missed a line when converting code to new hardware buffering method. In some circumstances, this would lead to a frame being displayed using parameters belonging to another frame. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fc8eac09584..8c00d8f6d4d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -797,7 +797,7 @@ static void ivtv_irq_vsync(struct ivtv *itv) /* Check if we need to update the yuv registers */ if ((yi->yuv_forced_update || yi->new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { if (!yi->new_frame_info[last_dma_frame].update) - last_dma_frame = (last_dma_frame - 1) & 3; + last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS; if (yi->new_frame_info[last_dma_frame].src_w) { yi->update_frame = last_dma_frame; -- cgit v1.2.3 From 406c8b0ff0891ace87440bcb298a91c1927f9ae5 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Sun, 21 Oct 2007 08:33:59 -0300 Subject: V4L/DVB (6715): ivtv: Remove unnecessary register update To reduce the number of display register accesses, the yuv code keeps track of the current video settings. Should there be a change in any single parameter, it will update the associated display registers to ensure everything is displayed correctly. The existing check also looks at the field order for the video. This is not required, since field reversal does not require any display register changes. This patch removes the field order from the check. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 15e9bd2486d..a23108fae4f 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -1021,7 +1021,7 @@ void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) yi->new_frame_info[frame].update = 0; yi->new_frame_info[frame].interlaced_y = 0; yi->new_frame_info[frame].interlaced_uv = 0; - yi->new_frame_info[frame].lace_mode = yi->lace_mode; + yi->new_frame_info[frame].lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; if (memcmp(&yi->old_frame_info_args, &yi->new_frame_info[frame], sizeof(yi->new_frame_info[frame]))) { -- cgit v1.2.3 From 3b5c1c8e71eb8fe2297a5884db59108e3c8b44c5 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Mon, 22 Oct 2007 14:24:26 -0300 Subject: V4L/DVB (6716): ivtv: yuv interlace mode change Interlace mode selection code moved into the frame setup phase, so it's now run before the frame is loaded into a hardware buffer. Given that it can affect how a new frame is displayed, it was a bit stupid running it after the frame was already visible. A few stray interlace related variables which were linked to individual frames have now been moved into the yuv_frame_info struct. This means that all variables linked to a specific frame are in the same place & not scattered. Minor code reformatting in areas touched by the above changes. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 7 +- drivers/media/video/ivtv/ivtv-irq.c | 19 +- drivers/media/video/ivtv/ivtv-yuv.c | 382 ++++++++++++++++----------------- 3 files changed, 199 insertions(+), 209 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 12ff9382718..0e4ad29821e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -392,6 +392,9 @@ struct yuv_frame_info u32 tru_h; u32 offset_y; s32 lace_mode; + u32 sync_field; + u32 delay; + u32 interlaced; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -465,8 +468,6 @@ struct yuv_playback_info int decode_height; - int frame_interlaced; - int lace_mode; int lace_threshold; int lace_sync_field; @@ -477,8 +478,6 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; - int sync_field[IVTV_YUV_BUFFERS]; /* Field to sync on */ - int field_delay[IVTV_YUV_BUFFERS]; /* Flag to extend duration of previous frame */ u8 fields_lapsed; /* Counter used when delaying a frame */ struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS]; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 8c00d8f6d4d..dd0dd8d126d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -746,15 +746,16 @@ static void ivtv_irq_vsync(struct ivtv *itv) unsigned int frame = read_reg(0x28c0) & 1; struct yuv_playback_info *yi = &itv->yuv_info; int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); + struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ yi->sync_field[last_dma_frame]) == 0 && - ((itv->last_vsync_field & 1) ^ yi->sync_field[last_dma_frame])) || - (frame != (itv->last_vsync_field & 1) && !yi->frame_interlaced)) { + if (((frame ^ f->sync_field) == 0 && + ((itv->last_vsync_field & 1) ^ f->sync_field)) || + (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { int next_dma_frame = last_dma_frame; - if (!(yi->frame_interlaced && yi->field_delay[next_dma_frame] && yi->fields_lapsed < 1)) { + if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); @@ -795,13 +796,15 @@ static void ivtv_irq_vsync(struct ivtv *itv) } /* Check if we need to update the yuv registers */ - if ((yi->yuv_forced_update || yi->new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { - if (!yi->new_frame_info[last_dma_frame].update) + if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) { + if (!f->update) { last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS; + f = &yi->new_frame_info[last_dma_frame]; + } - if (yi->new_frame_info[last_dma_frame].src_w) { + if (f->src_w) { yi->update_frame = last_dma_frame; - yi->new_frame_info[last_dma_frame].update = 0; + f->update = 0; yi->yuv_forced_update = 0; set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index a23108fae4f..cd42db9b5a1 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -39,19 +39,20 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, { struct ivtv_dma_page_info y_dma; struct ivtv_dma_page_info uv_dma; - + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + struct yuv_frame_info *f = &yi->new_frame_info[frame]; int i; int y_pages, uv_pages; - u8 frame = itv->yuv_info.draw_frame; unsigned long y_buffer_offset, uv_buffer_offset; int y_decode_height, uv_decode_height, y_size; y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; - y_decode_height = uv_decode_height = args->src.height + args->src.top; + y_decode_height = uv_decode_height = f->src_h + f->src_x; - if (y_decode_height < 512-16) + if (f->offset_y) y_buffer_offset += 720 * 16; if (y_decode_height & 15) @@ -106,13 +107,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); /* If we've offset the y plane, ensure top area is blanked */ - if (args->src.height + args->src.top < 512-16) { - if (itv->yuv_info.blanking_dmaptr) { - dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); - dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); - dma->SG_length++; - } + if (f->offset_y && itv->yuv_info.blanking_dmaptr) { + dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); + dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); + dma->SG_length++; } /* Tag SG Array with Interrupt Bit */ @@ -387,7 +386,7 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi } /* What is the source video being treated as... */ - if (itv->yuv_info.frame_interlaced) { + if (window->interlaced) { IVTV_DEBUG_WARN("Source video: Interlaced\n"); } else { @@ -631,192 +630,142 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi } /* Modify the supplied coordinate information to fit the visible osd area */ -static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window) +static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) { - int osd_crop, lace_threshold; + struct yuv_frame_info *of = &itv->yuv_info.old_frame_info; + int osd_crop; u32 osd_scale; u32 yuv_update = 0; - lace_threshold = itv->yuv_info.lace_threshold; - if (lace_threshold < 0) - lace_threshold = itv->yuv_info.decode_height - 1; - - /* Work out the lace settings */ - switch (itv->yuv_info.lace_mode) { - case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ - itv->yuv_info.frame_interlaced = 0; - if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021)) - window->interlaced_y = 0; - else - window->interlaced_y = 1; - - if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) - window->interlaced_uv = 0; - else - window->interlaced_uv = 1; - break; - - case IVTV_YUV_MODE_AUTO: - if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){ - itv->yuv_info.frame_interlaced = 0; - if ((window->tru_h < 512) || - (window->tru_h > 576 && window->tru_h < 1021) || - (window->tru_w > 720 && window->tru_h < 1021)) - window->interlaced_y = 0; - else - window->interlaced_y = 1; - - if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) - window->interlaced_uv = 0; - else - window->interlaced_uv = 1; - } - else { - itv->yuv_info.frame_interlaced = 1; - window->interlaced_y = 1; - window->interlaced_uv = 1; - } - break; - - case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ - default: - itv->yuv_info.frame_interlaced = 1; - window->interlaced_y = 1; - window->interlaced_uv = 1; - break; - } - /* Sorry, but no negative coords for src */ - if (window->src_x < 0) window->src_x = 0; - if (window->src_y < 0) window->src_y = 0; + if (f->src_x < 0) + f->src_x = 0; + if (f->src_y < 0) + f->src_y = 0; /* Can only reduce width down to 1/4 original size */ - if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) { - window->src_x += osd_crop / 2; - window->src_w = (window->src_w - osd_crop) & ~3; - window->dst_w = window->src_w / 4; - window->dst_w += window->dst_w & 1; + if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) { + f->src_x += osd_crop / 2; + f->src_w = (f->src_w - osd_crop) & ~3; + f->dst_w = f->src_w / 4; + f->dst_w += f->dst_w & 1; } /* Can only reduce height down to 1/4 original size */ - if (window->src_h / window->dst_h >= 2) { - /* Overflow may be because we're running progressive, so force mode switch */ - window->interlaced_y = 1; + if (f->src_h / f->dst_h >= 2) { + /* Overflow may be because we're running progressive, + so force mode switch */ + f->interlaced_y = 1; /* Make sure we're still within limits for interlace */ - if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) { + if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) { /* If we reach here we'll have to force the height. */ - window->src_y += osd_crop / 2; - window->src_h = (window->src_h - osd_crop) & ~3; - window->dst_h = window->src_h / 4; - window->dst_h += window->dst_h & 1; + f->src_y += osd_crop / 2; + f->src_h = (f->src_h - osd_crop) & ~3; + f->dst_h = f->src_h / 4; + f->dst_h += f->dst_h & 1; } } /* If there's nothing to safe to display, we may as well stop now */ - if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { + if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || + (int)f->src_w <= 2 || (int)f->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Ensure video remains inside OSD area */ - osd_scale = (window->src_h << 16) / window->dst_h; + osd_scale = (f->src_h << 16) / f->dst_h; - if ((osd_crop = window->pan_y - window->dst_y) > 0) { + if ((osd_crop = f->pan_y - f->dst_y) > 0) { /* Falls off the upper edge - crop */ - window->src_y += (osd_scale * osd_crop) >> 16; - window->src_h -= (osd_scale * osd_crop) >> 16; - window->dst_h -= osd_crop; - window->dst_y = 0; - } - else { - window->dst_y -= window->pan_y; + f->src_y += (osd_scale * osd_crop) >> 16; + f->src_h -= (osd_scale * osd_crop) >> 16; + f->dst_h -= osd_crop; + f->dst_y = 0; + } else { + f->dst_y -= f->pan_y; } - if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) { + if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) { /* Falls off the lower edge - crop */ - window->dst_h -= osd_crop; - window->src_h -= (osd_scale * osd_crop) >> 16; + f->dst_h -= osd_crop; + f->src_h -= (osd_scale * osd_crop) >> 16; } - osd_scale = (window->src_w << 16) / window->dst_w; + osd_scale = (f->src_w << 16) / f->dst_w; - if ((osd_crop = window->pan_x - window->dst_x) > 0) { + if ((osd_crop = f->pan_x - f->dst_x) > 0) { /* Fall off the left edge - crop */ - window->src_x += (osd_scale * osd_crop) >> 16; - window->src_w -= (osd_scale * osd_crop) >> 16; - window->dst_w -= osd_crop; - window->dst_x = 0; - } - else { - window->dst_x -= window->pan_x; + f->src_x += (osd_scale * osd_crop) >> 16; + f->src_w -= (osd_scale * osd_crop) >> 16; + f->dst_w -= osd_crop; + f->dst_x = 0; + } else { + f->dst_x -= f->pan_x; } - if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) { + if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) { /* Falls off the right edge - crop */ - window->dst_w -= osd_crop; - window->src_w -= (osd_scale * osd_crop) >> 16; + f->dst_w -= osd_crop; + f->src_w -= (osd_scale * osd_crop) >> 16; } /* The OSD can be moved. Track to it */ - window->dst_x += itv->yuv_info.osd_x_offset; - window->dst_y += itv->yuv_info.osd_y_offset; + f->dst_x += itv->yuv_info.osd_x_offset; + f->dst_y += itv->yuv_info.osd_y_offset; /* Width & height for both src & dst must be even. Same for coordinates. */ - window->dst_w &= ~1; - window->dst_x &= ~1; + f->dst_w &= ~1; + f->dst_x &= ~1; - window->src_w += window->src_x & 1; - window->src_x &= ~1; + f->src_w += f->src_x & 1; + f->src_x &= ~1; - window->src_w &= ~1; - window->dst_w &= ~1; + f->src_w &= ~1; + f->dst_w &= ~1; - window->dst_h &= ~1; - window->dst_y &= ~1; + f->dst_h &= ~1; + f->dst_y &= ~1; - window->src_h += window->src_y & 1; - window->src_y &= ~1; + f->src_h += f->src_y & 1; + f->src_y &= ~1; - window->src_h &= ~1; - window->dst_h &= ~1; + f->src_h &= ~1; + f->dst_h &= ~1; - /* Due to rounding, we may have reduced the output size to <1/4 of the source - Check again, but this time just resize. Don't change source coordinates */ - if (window->dst_w < window->src_w / 4) { - window->src_w &= ~3; - window->dst_w = window->src_w / 4; - window->dst_w += window->dst_w & 1; + /* Due to rounding, we may have reduced the output size to <1/4 of + the source. Check again, but this time just resize. Don't change + source coordinates */ + if (f->dst_w < f->src_w / 4) { + f->src_w &= ~3; + f->dst_w = f->src_w / 4; + f->dst_w += f->dst_w & 1; } - if (window->dst_h < window->src_h / 4) { - window->src_h &= ~3; - window->dst_h = window->src_h / 4; - window->dst_h += window->dst_h & 1; + if (f->dst_h < f->src_h / 4) { + f->src_h &= ~3; + f->dst_h = f->src_h / 4; + f->dst_h += f->dst_h & 1; } /* Check again. If there's nothing to safe to display, stop now */ - if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { + if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || + (int)f->src_w <= 2 || (int)f->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Both x offset & width are linked, so they have to be done together */ - if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || - (itv->yuv_info.old_frame_info.src_w != window->src_w) || - (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || - (itv->yuv_info.old_frame_info.src_x != window->src_x) || - (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || - (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { + if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || + (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || + (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; } - if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || - (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || - (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || - (itv->yuv_info.old_frame_info.src_y != window->src_y) || - (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || - (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || - (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || - (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || - (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { + if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || + (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || + (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || + (of->lace_mode != f->lace_mode) || + (of->interlaced_y != f->interlaced_y) || + (of->interlaced_uv != f->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; } @@ -826,22 +775,22 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo /* Update the scaling register to the requested value */ void ivtv_yuv_work_handler (struct ivtv *itv) { - struct yuv_frame_info window; + struct yuv_playback_info *yi = &itv->yuv_info; + struct yuv_frame_info f; + int frame = yi->update_frame; u32 yuv_update; - int frame = itv->yuv_info.update_frame; - /* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ - memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); + f = yi->new_frame_info[frame]; /* Update the osd pan info */ - window.pan_x = itv->yuv_info.osd_x_pan; - window.pan_y = itv->yuv_info.osd_y_pan; - window.vis_w = itv->yuv_info.osd_vis_w; - window.vis_h = itv->yuv_info.osd_vis_h; + f.pan_x = itv->yuv_info.osd_x_pan; + f.pan_y = itv->yuv_info.osd_y_pan; + f.vis_w = itv->yuv_info.osd_vis_w; + f.vis_h = itv->yuv_info.osd_vis_h; /* Calculate the display window coordinates. Exit if nothing left */ - if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) + if (!(yuv_update = ivtv_yuv_window_setup (itv, &f))) return; if (yuv_update & IVTV_YUV_UPDATE_INVALID) { @@ -850,13 +799,12 @@ void ivtv_yuv_work_handler (struct ivtv *itv) write_reg(0x00108080, 0x2898); if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) - ivtv_yuv_handle_horizontal(itv, &window); + ivtv_yuv_handle_horizontal(itv, &f); if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) - ivtv_yuv_handle_vertical(itv, &window); + ivtv_yuv_handle_vertical(itv, &f); } - - memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info)); + yi->old_frame_info = f; } static void ivtv_yuv_init (struct ivtv *itv) @@ -986,58 +934,98 @@ void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) { struct yuv_playback_info *yi = &itv->yuv_info; u8 frame = yi->draw_frame; + u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS; + struct yuv_frame_info *nf = &yi->new_frame_info[frame]; + struct yuv_frame_info *of = &yi->new_frame_info[last_frame]; + int lace_threshold = yi->lace_threshold; /* Preserve old update flag in case we're overwriting a queued frame */ - int register_update = yi->new_frame_info[frame].update; + int update = nf->update; /* Take a snapshot of the yuv coordinate information */ - yi->new_frame_info[frame].src_x = args->src.left; - yi->new_frame_info[frame].src_y = args->src.top; - yi->new_frame_info[frame].src_w = args->src.width; - yi->new_frame_info[frame].src_h = args->src.height; - yi->new_frame_info[frame].dst_x = args->dst.left; - yi->new_frame_info[frame].dst_y = args->dst.top; - yi->new_frame_info[frame].dst_w = args->dst.width; - yi->new_frame_info[frame].dst_h = args->dst.height; - yi->new_frame_info[frame].tru_x = args->dst.left; - yi->new_frame_info[frame].tru_w = args->src_width; - yi->new_frame_info[frame].tru_h = args->src_height; - - /* Snapshot field order */ - yi->sync_field[frame] = yi->lace_sync_field; + nf->src_x = args->src.left; + nf->src_y = args->src.top; + nf->src_w = args->src.width; + nf->src_h = args->src.height; + nf->dst_x = args->dst.left; + nf->dst_y = args->dst.top; + nf->dst_w = args->dst.width; + nf->dst_h = args->dst.height; + nf->tru_x = args->dst.left; + nf->tru_w = args->src_width; + nf->tru_h = args->src_height; /* Are we going to offset the Y plane */ - if (args->src.height + args->src.top < 512-16) - yi->new_frame_info[frame].offset_y = 1; - else - yi->new_frame_info[frame].offset_y = 0; + nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0; /* Snapshot the osd pan info */ - yi->new_frame_info[frame].pan_x = yi->osd_x_pan; - yi->new_frame_info[frame].pan_y = yi->osd_y_pan; - yi->new_frame_info[frame].vis_w = yi->osd_vis_w; - yi->new_frame_info[frame].vis_h = yi->osd_vis_h; - - yi->new_frame_info[frame].update = 0; - yi->new_frame_info[frame].interlaced_y = 0; - yi->new_frame_info[frame].interlaced_uv = 0; - yi->new_frame_info[frame].lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; - - if (memcmp(&yi->old_frame_info_args, &yi->new_frame_info[frame], - sizeof(yi->new_frame_info[frame]))) { - yi->old_frame_info_args = yi->new_frame_info[frame]; - yi->new_frame_info[frame].update = 1; -/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ + nf->pan_x = yi->osd_x_pan; + nf->pan_y = yi->osd_y_pan; + nf->vis_w = yi->osd_vis_w; + nf->vis_h = yi->osd_vis_h; + + nf->update = 0; + nf->interlaced_y = 0; + nf->interlaced_uv = 0; + nf->delay = 0; + nf->sync_field = 0; + nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; + + if (lace_threshold < 0) + lace_threshold = yi->decode_height - 1; + + /* Work out the lace settings */ + switch (nf->lace_mode) { + case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ + nf->interlaced = 0; + if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021)) + nf->interlaced_y = 0; + else + nf->interlaced_y = 1; + + if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) + nf->interlaced_uv = 0; + else + nf->interlaced_uv = 1; + break; + + case IVTV_YUV_MODE_AUTO: + if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { + nf->interlaced = 0; + if ((nf->tru_h < 512) || + (nf->tru_h > 576 && nf->tru_h < 1021) || + (nf->tru_w > 720 && nf->tru_h < 1021)) + nf->interlaced_y = 0; + else + nf->interlaced_y = 1; + if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) + nf->interlaced_uv = 0; + else + nf->interlaced_uv = 1; + } else { + nf->interlaced = 1; + nf->interlaced_y = 1; + nf->interlaced_uv = 1; + } + break; + + case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ + default: + nf->interlaced = 1; + nf->interlaced_y = 1; + nf->interlaced_uv = 1; + break; } - yi->new_frame_info[frame].update |= register_update; + if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { + yi->old_frame_info_args = *nf; + nf->update = 1; +/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ + } - /* Should this frame be delayed ? */ - if (yi->sync_field[frame] != - yi->sync_field[(frame - 1) % IVTV_YUV_BUFFERS]) - yi->field_delay[frame] = 1; - else - yi->field_delay[frame] = 0; + nf->update |= update; + nf->sync_field = yi->lace_sync_field; + nf->delay = nf->sync_field != of->sync_field; } /* Frame is complete & ready for display */ -- cgit v1.2.3 From 77aded6ba51f01335840ce8e18b413067810b68e Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Mon, 5 Nov 2007 14:27:09 -0300 Subject: V4L/DVB (6717): ivtv: Initial merge of video48 yuv handling into the IVTV_IOC_DMA_FRAME framework Previously, all yuv data written to /dev/video48 had only basic support with no double buffering to avoid display tearing. With this patch, yuv frames written to video48 are now handled by the existing IVTV_IOC_DMA_FRAME framework. As such, the frames are hardware buffered to avoid tearing, and honour scaling mode & field order options. Unlike the proprietary IVTV_IOC_DMA_FRAME ioctl, all parameters are controlled by the V4L2 API. Due to mpeg & yuv output restrictions being different, their V4L2 output controls have been separated. To control the yuv output, the V4L2 calls must be done via video48. If the ivtvfb module is loaded, there will be one side effect to this merge. The yuv output window will be constrained to the visible framebuffer area. In the event that a virtual framebuffer size is being used, the limit to the output size will be the virtual dimensions, but only the portion that falls within the currently visible area of the framebuffer will be shown. Like the IVTV_IOC_DMA_FRAME ioctl, the supplied frames must be padded to 720 pixels wide. However the height must only be padded up the nearest multiple of 32. This would mean an image of 102 lines must be padded to 128. As long as the true source image size is given, the padding will not be visible in the final output. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 6 ++ drivers/media/video/ivtv/ivtv-driver.h | 7 ++ drivers/media/video/ivtv/ivtv-fileops.c | 23 +++++- drivers/media/video/ivtv/ivtv-ioctl.c | 120 +++++++++++++++++++++----------- drivers/media/video/ivtv/ivtv-irq.c | 26 ++++++- drivers/media/video/ivtv/ivtv-streams.c | 17 +---- drivers/media/video/ivtv/ivtv-yuv.c | 58 +++++++++++++-- drivers/media/video/ivtv/ivtv-yuv.h | 5 +- drivers/media/video/ivtv/ivtvfb.c | 4 ++ 9 files changed, 196 insertions(+), 70 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index e3020f45664..7c600d0f48c 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -1117,6 +1117,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev, itv->is_50hz = 1; itv->is_out_50hz = 1; } + + itv->yuv_info.osd_full_w = 720; + itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480; + itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w; + itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h; + itv->params.video_gop_size = itv->is_60hz ? 15 : 12; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 0e4ad29821e..19a9b3bac19 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -466,6 +466,9 @@ struct yuv_playback_info u32 osd_vis_w; u32 osd_vis_h; + u32 osd_full_w; + u32 osd_full_h; + int decode_height; int lace_mode; @@ -491,6 +494,10 @@ struct yuv_playback_info u8 draw_frame; /* PVR350 buffer to draw into */ u8 max_frames_buffered; /* Maximum number of frames to buffer */ + + struct v4l2_rect main_rect; + u32 v4l2_src_w; + u32 v4l2_src_h; }; #define IVTV_VBI_FRAMES 32 diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 58ad0d9c680..6fb96f19a86 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -581,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c set_bit(IVTV_F_S_APPL_IO, &s->s_flags); retry: + /* If possible, just DMA the entire frame - Check the data transfer size + since we may get here before the stream has been fully set-up */ + if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { + while (count >= itv->dma_data_req_size) { + if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) { + bytes_written += itv->dma_data_req_size; + user_buf += itv->dma_data_req_size; + count -= itv->dma_data_req_size; + } else { + break; + } + } + if (count == 0) { + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + return bytes_written; + } + } + for (;;) { /* Gather buffers */ while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) @@ -660,6 +678,9 @@ retry: if (s->q_full.length >= itv->dma_data_req_size) { int got_sig; + if (mode == OUT_YUV) + ivtv_yuv_setup_stream_frame(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (!(got_sig = signal_pending(current)) && test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { @@ -946,7 +967,7 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); /* For yuv, we need to know the dma size before we start */ itv->dma_data_req_size = - itv->params.width * itv->params.height * 3 / 2; + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); itv->yuv_info.stream_size = 0; } return 0; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index fd6826f472e..57eb8dfe53f 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm fmt->fmt.pix.height = itv->main_rect.height; fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (itv->output_mode == OUT_UDMA_YUV) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { case IVTV_YUV_MODE_INTERLACED: fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? @@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm break; } fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; + fmt->fmt.pix.bytesperline = 720; + fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w; + fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } - else if (itv->output_mode == OUT_YUV || - streamtype == IVTV_ENC_STREAM_TYPE_YUV || - streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + 1080 * ((fmt->fmt.pix.height + 31) & ~31); + } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) { fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ fmt->fmt.pix.sizeimage = @@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt, int set_fmt) { + struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; u16 set; @@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, r.width = fmt->fmt.pix.width; r.height = fmt->fmt.pix.height; ivtv_get_fmt(itv, streamtype, fmt); - if (itv->output_mode != OUT_UDMA_YUV) { - /* TODO: would setting the rect also be valid for this mode? */ - fmt->fmt.pix.width = r.width; - fmt->fmt.pix.height = r.height; - } - if (itv->output_mode == OUT_UDMA_YUV) { - /* TODO: add checks for validity */ + fmt->fmt.pix.width = r.width; + fmt->fmt.pix.height = r.height; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { fmt->fmt.pix.field = field; + if (fmt->fmt.pix.width < 2) + fmt->fmt.pix.width = 2; + if (fmt->fmt.pix.width > 720) + fmt->fmt.pix.width = 720; + if (fmt->fmt.pix.height < 2) + fmt->fmt.pix.height = 2; + if (fmt->fmt.pix.height > 576) + fmt->fmt.pix.height = 576; } - if (set_fmt) { - if (itv->output_mode == OUT_UDMA_YUV) { - switch (field) { - case V4L2_FIELD_NONE: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - itv->yuv_info.lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED; - break; - } - itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + /* Return now if we already have some frame data */ + if (yi->stream_size) + return -EBUSY; - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - return 0; + yi->v4l2_src_w = r.width; + yi->v4l2_src_h = r.height; + + switch (field) { + case V4L2_FIELD_NONE: + yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; + break; + case V4L2_FIELD_ANY: + yi->lace_mode = IVTV_YUV_MODE_AUTO; + break; + case V4L2_FIELD_INTERLACED_BT: + yi->lace_mode = + IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; + break; + case V4L2_FIELD_INTERLACED_TB: + default: + yi->lace_mode = IVTV_YUV_MODE_INTERLACED; + break; } + yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + itv->dma_data_req_size = + 1080 * ((yi->v4l2_src_h + 31) & ~31); + + /* Force update of yuv registers */ + yi->yuv_forced_update = 1; + return 0; } return 0; } @@ -703,8 +716,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void { struct ivtv_open_id *id = NULL; u32 data[CX2341X_MBOX_MAX_DATA]; + int streamtype = 0; - if (filp) id = (struct ivtv_open_id *)filp->private_data; + if (filp) { + id = (struct ivtv_open_id *)filp->private_data; + streamtype = id->type; + } switch (cmd) { case VIDIOC_G_PRIORITY: @@ -822,6 +839,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void cropcap->bounds.height = itv->is_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; + } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + cropcap->bounds.width = itv->yuv_info.osd_full_w; + cropcap->bounds.height = itv->yuv_info.osd_full_h; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; } else { cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; @@ -836,10 +858,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + itv->yuv_info.main_rect = crop->c; return 0; + } else { + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { + itv->main_rect = crop->c; + return 0; + } } return -EINVAL; } @@ -853,7 +880,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - crop->c = itv->main_rect; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) + crop->c = itv->yuv_info.main_rect; + else + crop->c = itv->main_rect; return 0; } if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -864,7 +894,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_ENUM_FMT: { static struct v4l2_fmtdesc formats[] = { { 0, 0, 0, - "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, + "HM12 (YUV 4:2:2)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } }, { 1, 0, V4L2_FMT_FLAG_COMPRESSED, @@ -1043,6 +1073,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void itv->main_rect.height = itv->params.height; ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 720, itv->main_rect.height, 0, 0); + itv->yuv_info.main_rect = itv->main_rect; + if (!itv->osd_info) { + itv->yuv_info.osd_full_w = 720; + itv->yuv_info.osd_full_h = + itv->is_out_50hz ? 576 : 480; + } } break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index dd0dd8d126d..ebc200320e6 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s) void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) { struct ivtv *itv = s->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + struct yuv_frame_info *f = &yi->new_frame_info[frame]; struct ivtv_buffer *buf; - u32 y_size = itv->params.height * itv->params.width; + u32 y_size = 720 * ((f->src_h + 31) & ~31); u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; int bytes_written = 0; @@ -311,6 +314,18 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); + + /* Insert buffer block for YUV if needed */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { + if (yi->blanking_dmaptr) { + s->sg_pending[idx].src = yi->blanking_dmaptr; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = 720 * 16; + } + offset += 720 * 16; + idx++; + } + list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && @@ -713,8 +728,11 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; - itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; + itv->dma_data_req_size = + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); + itv->dma_data_req_offset = data[1]; + if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) + ivtv_yuv_frame_complete(itv); s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; } else { @@ -728,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); } else { + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + ivtv_yuv_setup_stream_frame(itv); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index a5bfbd98a49..3ca2a1a62a7 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); - /* Clear Streamoff */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - /* Initialize Decoder */ - /* Reprogram Decoder YUV Buffers for YUV */ - write_reg(yuv_offset[0] >> 4, 0x82c); - write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[0] >> 4, 0x834); - write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - - write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24); - - write_reg_sync(0x00108080, 0x2898); - /* Enable YUV decoder output */ - write_reg_sync(0x01, IVTV_REG_VDM); - } - ivtv_setup_v4l2_decode_stream(s); /* set dma size to 65536 bytes */ ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); + /* Clear Streamoff */ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); /* Zero out decoder counters */ diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index cd42db9b5a1..711ce5b5a20 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -1035,17 +1035,11 @@ void ivtv_yuv_frame_complete(struct ivtv *itv) (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); } -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) { DEFINE_WAIT(wait); int rc = 0; int got_sig = 0; - - IVTV_DEBUG_INFO("yuv_prep_frame\n"); - - ivtv_yuv_next_free(itv); - ivtv_yuv_setup_frame(itv, args); - /* DMA the frame */ mutex_lock(&itv->udma.lock); @@ -1084,6 +1078,56 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) return rc; } +/* Setup frame according to V4L2 parameters */ +void ivtv_yuv_setup_stream_frame(struct ivtv *itv) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_dma_frame dma_args; + + ivtv_yuv_next_free(itv); + + /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ + dma_args.y_source = 0L; + dma_args.uv_source = 0L; + dma_args.src.left = 0; + dma_args.src.top = 0; + dma_args.src.width = yi->v4l2_src_w; + dma_args.src.height = yi->v4l2_src_h; + dma_args.dst = yi->main_rect; + dma_args.src_width = yi->v4l2_src_w; + dma_args.src_height = yi->v4l2_src_h; + + /* ... and use the same setup routine as ivtv_yuv_prep_frame */ + ivtv_yuv_setup_frame(itv, &dma_args); + + if (!itv->dma_data_req_offset) + itv->dma_data_req_offset = yuv_offset[yi->draw_frame]; +} + +/* Attempt to dma a frame from a user buffer */ +int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_dma_frame dma_args; + + ivtv_yuv_setup_stream_frame(itv); + + /* We only need to supply source addresses for this */ + dma_args.y_source = src; + dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); + return ivtv_yuv_udma_frame(itv, &dma_args); +} + +/* IVTV_IOC_DMA_FRAME ioctl handler */ +int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + IVTV_DEBUG_INFO("yuv_prep_frame\n"); + + ivtv_yuv_next_free(itv); + ivtv_yuv_setup_frame(itv, args); + return ivtv_yuv_udma_frame(itv, args); +} + void ivtv_yuv_close(struct ivtv *itv) { int h_filter, v_filter_1, v_filter_2; diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 3b290927d36..2fe5f125076 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -34,8 +34,11 @@ extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; int ivtv_yuv_filter_check(struct ivtv *itv); +void ivtv_yuv_setup_stream_frame(struct ivtv *itv); +int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src); +void ivtv_yuv_frame_complete(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); void ivtv_yuv_close(struct ivtv *itv); -void ivtv_yuv_work_handler (struct ivtv *itv); +void ivtv_yuv_work_handler(struct ivtv *itv); #endif diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 52ffd154a3d..1a73038ea81 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtvfb_set_display_window(itv, &ivtv_window); + /* Pass screen size back to yuv handler */ + itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride; + itv->yuv_info.osd_full_h = ivtv_osd.lines; + /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; -- cgit v1.2.3 From 368f080b6870e65d43c346e085e8f81ade5d3e07 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Mon, 5 Nov 2007 14:30:03 -0300 Subject: V4L/DVB (6718): ivtv: ivtv yuv format description correction The driver was incorrectly reporting that it supported YUV 4:2:2 output, when it is actually YUV 4:2:0. Though I believe the hardware can be pushed to 4:2:2, we don't currently support that. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 57eb8dfe53f..0618fee2495 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -894,7 +894,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_ENUM_FMT: { static struct v4l2_fmtdesc formats[] = { { 0, 0, 0, - "HM12 (YUV 4:2:2)", V4L2_PIX_FMT_HM12, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } }, { 1, 0, V4L2_FMT_FLAG_COMPRESSED, -- cgit v1.2.3 From 2b057e8dc6cc8318956fef92b77a4e86985e84d9 Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Tue, 13 Nov 2007 19:15:25 -0300 Subject: V4L/DVB (6719): ivtv: ivtv-yuv clean-up + source cropping bug-fix ivtv-yuv code clean up & reformat. Includes minor changes to some debug lines. Also fixes a bug found during the reformatting, which would cause the incorrect amount of yuv data to be sent to the card if source cropping coordinates were used. Apart from the bug-fix, there should be no functional difference to the previous version. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 635 ++++++++++++++++++------------------ 1 file changed, 320 insertions(+), 315 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 711ce5b5a20..85183480a22 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -35,7 +35,7 @@ const u32 yuv_offset[IVTV_YUV_BUFFERS] = { }; static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, - struct ivtv_dma_frame *args) + struct ivtv_dma_frame *args) { struct ivtv_dma_page_info y_dma; struct ivtv_dma_page_info uv_dma; @@ -50,7 +50,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; - y_decode_height = uv_decode_height = f->src_h + f->src_x; + y_decode_height = uv_decode_height = f->src_h + f->src_y; if (f->offset_y) y_buffer_offset += 720 * 16; @@ -65,8 +65,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* Still in USE */ if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); + IVTV_DEBUG_WARN + ("prep_user_dma: SG_length %d page_count %d still full?\n", + dma->SG_length, dma->page_count); return -EBUSY; } @@ -82,8 +83,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->page_count = y_dma.page_count + uv_dma.page_count; if (y_pages + uv_pages != dma->page_count) { - IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", - y_pages + uv_pages, dma->page_count); + IVTV_DEBUG_WARN + ("failed to map user pages, returned %d instead of %d\n", + y_pages + uv_pages, dma->page_count); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); @@ -104,12 +106,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); + ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); /* If we've offset the y plane, ensure top area is blanked */ - if (f->offset_y && itv->yuv_info.blanking_dmaptr) { + if (f->offset_y && yi->blanking_dmaptr) { dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); - dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); + dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); dma->SG_length++; } @@ -124,11 +126,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* We rely on a table held in the firmware - Quick check. */ int ivtv_yuv_filter_check(struct ivtv *itv) { - int i, offset_y, offset_uv; + int i, y, uv; - for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) { - if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) || - (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) { + for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) { + if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) || + (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) { IVTV_WARN ("YUV filter table not found in firmware.\n"); return -1; } @@ -138,69 +140,67 @@ int ivtv_yuv_filter_check(struct ivtv *itv) static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) { - int filter_index, filter_line; + u32 i, line; /* If any filter is -1, then don't update it */ if (h_filter > -1) { - if (h_filter > 4) h_filter = 4; - filter_index = h_filter * 384; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c); - filter_index += 8; + if (h_filter > 4) + h_filter = 4; + i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x02804); + write_reg(read_dec(i), 0x0281c); + i += 4; + write_reg(read_dec(i), 0x02808); + write_reg(read_dec(i), 0x02820); + i += 4; + write_reg(read_dec(i), 0x0280c); + write_reg(read_dec(i), 0x02824); + i += 4; + write_reg(read_dec(i), 0x02810); + write_reg(read_dec(i), 0x02828); + i += 4; + write_reg(read_dec(i), 0x02814); + write_reg(read_dec(i), 0x0282c); + i += 8; write_reg(0, 0x02818); write_reg(0, 0x02830); - filter_line ++; } - IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter); + IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter); } if (v_filter_1 > -1) { - if (v_filter_1 > 4) v_filter_1 = 4; - filter_index = v_filter_1 * 192; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904); - filter_index += 8; + if (v_filter_1 > 4) + v_filter_1 = 4; + i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x02900); + i += 4; + write_reg(read_dec(i), 0x02904); + i += 8; write_reg(0, 0x02908); - filter_line ++; } - IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1); + IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1); } if (v_filter_2 > -1) { - if (v_filter_2 > 4) v_filter_2 = 4; - filter_index = v_filter_2 * 192; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910); - filter_index += 8; + if (v_filter_2 > 4) + v_filter_2 = 4; + i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x0290c); + i += 4; + write_reg(read_dec(i), 0x02910); + i += 8; write_reg(0, 0x02914); - filter_line ++; } - IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2); + IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2); } } -static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window) +static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f) { + struct yuv_playback_info *yi = &itv->yuv_info; u32 reg_2834, reg_2838, reg_283c; u32 reg_2844, reg_2854, reg_285c; u32 reg_2864, reg_2874, reg_2890; @@ -209,18 +209,19 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * int h_filter; u32 master_width; - IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", - window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x); + IVTV_DEBUG_WARN + ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", + f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x); /* How wide is the src image */ - x_cutoff = window->src_w + window->src_x; + x_cutoff = f->src_w + f->src_x; /* Set the display width */ - reg_2834 = window->dst_w; + reg_2834 = f->dst_w; reg_2838 = reg_2834; /* Set the display position */ - reg_2890 = window->dst_x; + reg_2890 = f->dst_x; /* Index into the image horizontally */ reg_2870 = 0; @@ -231,32 +232,31 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * Gradually adjust the offset to avoid the video 'snapping' left/right if it gets dragged through this region. Only do this if osd is full width. */ - if (window->vis_w == 720) { - if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){ - reg_2870 = 10 - (window->tru_x - window->pan_x) / 4; - } - else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) { - reg_2870 = (10 + (window->tru_x - window->pan_x) / 2); - } + if (f->vis_w == 720) { + if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680)) + reg_2870 = 10 - (f->tru_x - f->pan_x) / 4; + else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660)) + reg_2870 = (10 + (f->tru_x - f->pan_x) / 2); - if (window->dst_w >= window->src_w) + if (f->dst_w >= f->src_w) reg_2870 = reg_2870 << 16 | reg_2870; else reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); } - if (window->dst_w < window->src_w) + if (f->dst_w < f->src_w) reg_2870 = 0x000d000e - reg_2870; else reg_2870 = 0x0012000e - reg_2870; /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ - reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19; + reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19; - if (window->dst_w >= window->src_w) { + if (f->dst_w >= f->src_w) { x_cutoff &= ~1; - master_width = (window->src_w * 0x00200000) / (window->dst_w); - if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++; + master_width = (f->src_w * 0x00200000) / (f->dst_w); + if (master_width * f->dst_w != f->src_w * 0x00200000) + master_width++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -267,17 +267,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * /* We also need to factor in the scaling (src_w - dst_w) / (src_w / 4) */ - if (window->dst_w > window->src_w) - reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14); + if (f->dst_w > f->src_w) + reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14); else reg_2870_base = 0; reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); reg_2874 = 0; - } - else if (window->dst_w < window->src_w / 2) { - master_width = (window->src_w * 0x00080000) / window->dst_w; - if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++; + } else if (f->dst_w < f->src_w / 2) { + master_width = (f->src_w * 0x00080000) / f->dst_w; + if (master_width * f->dst_w != f->src_w * 0x00080000) + master_width++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -285,13 +285,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * reg_2854 = master_width; reg_285c = master_width >> 1; reg_2864 = master_width >> 1; - reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset); - reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16; + reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset; + reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16; reg_2874 = 0x00000012; - } - else { - master_width = (window->src_w * 0x00100000) / window->dst_w; - if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++; + } else { + master_width = (f->src_w * 0x00100000) / f->dst_w; + if (master_width * f->dst_w != f->src_w * 0x00100000) + master_width++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -299,62 +299,70 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * reg_2854 = master_width; reg_285c = master_width >> 1; reg_2864 = master_width >> 1; - reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1); - reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16; + reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1; + reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16; reg_2874 = 0x00000001; } /* Select the horizontal filter */ - if (window->src_w == window->dst_w) { + if (f->src_w == f->dst_w) { /* An exact size match uses filter 0 */ h_filter = 0; - } - else { + } else { /* Figure out which filter to use */ - h_filter = ((window->src_w << 16) / window->dst_w) >> 15; + h_filter = ((f->src_w << 16) / f->dst_w) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0 */ - if (h_filter == 0) h_filter = 1; + h_filter += !h_filter; } write_reg(reg_2834, 0x02834); write_reg(reg_2838, 0x02838); - IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838); + IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n", + yi->reg_2834, reg_2834, yi->reg_2838, reg_2838); write_reg(reg_283c, 0x0283c); write_reg(reg_2844, 0x02844); - IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844); + IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n", + yi->reg_283c, reg_283c, yi->reg_2844, reg_2844); write_reg(0x00080514, 0x02840); write_reg(0x00100514, 0x02848); - IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514); + IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n", + yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514); write_reg(reg_2854, 0x02854); - IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854); + IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n", + yi->reg_2854, reg_2854); write_reg(reg_285c, 0x0285c); write_reg(reg_2864, 0x02864); - IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864); + IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n", + yi->reg_285c, reg_285c, yi->reg_2864, reg_2864); write_reg(reg_2874, 0x02874); - IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874); + IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n", + yi->reg_2874, reg_2874); write_reg(reg_2870, 0x02870); - IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870); + IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n", + yi->reg_2870, reg_2870); - write_reg( reg_2890,0x02890); - IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890); + write_reg(reg_2890, 0x02890); + IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n", + yi->reg_2890, reg_2890); /* Only update the filter if we really need to */ - if (h_filter != itv->yuv_info.h_filter) { - ivtv_yuv_filter (itv,h_filter,-1,-1); - itv->yuv_info.h_filter = h_filter; + if (h_filter != yi->h_filter) { + ivtv_yuv_filter(itv, h_filter, -1, -1); + yi->h_filter = h_filter; } } -static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window) +static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) { + struct yuv_playback_info *yi = &itv->yuv_info; u32 master_height; u32 reg_2918, reg_291c, reg_2920, reg_2928; u32 reg_2930, reg_2934, reg_293c; @@ -362,69 +370,59 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi u32 reg_2950, reg_2954, reg_2958, reg_295c; u32 reg_2960, reg_2964, reg_2968, reg_296c; u32 reg_289c; - u32 src_y_major_y, src_y_minor_y; - u32 src_y_major_uv, src_y_minor_uv; + u32 src_major_y, src_minor_y; + u32 src_major_uv, src_minor_uv; u32 reg_2964_base, reg_2968_base; int v_filter_1, v_filter_2; - IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", - window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y); + IVTV_DEBUG_WARN + ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", + f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y); /* What scaling mode is being used... */ - if (window->interlaced_y) { - IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n"); - } - else { - IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n"); - } + IVTV_DEBUG_YUV("Scaling mode Y: %s\n", + f->interlaced_y ? "Interlaced" : "Progressive"); - if (window->interlaced_uv) { - IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n"); - } - else { - IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n"); - } + IVTV_DEBUG_YUV("Scaling mode UV: %s\n", + f->interlaced_uv ? "Interlaced" : "Progressive"); /* What is the source video being treated as... */ - if (window->interlaced) { - IVTV_DEBUG_WARN("Source video: Interlaced\n"); - } - else { - IVTV_DEBUG_WARN("Source video: Non-interlaced\n"); - } + IVTV_DEBUG_WARN("Source video: %s\n", + f->interlaced ? "Interlaced" : "Progressive"); /* We offset into the image using two different index methods, so split the y source coord into two parts. */ - if (window->src_y < 8) { - src_y_minor_uv = window->src_y; - src_y_major_uv = 0; - } - else { - src_y_minor_uv = 8; - src_y_major_uv = window->src_y - 8; + if (f->src_y < 8) { + src_minor_uv = f->src_y; + src_major_uv = 0; + } else { + src_minor_uv = 8; + src_major_uv = f->src_y - 8; } - src_y_minor_y = src_y_minor_uv; - src_y_major_y = src_y_major_uv; + src_minor_y = src_minor_uv; + src_major_y = src_major_uv; - if (window->offset_y) src_y_minor_y += 16; + if (f->offset_y) + src_minor_y += 16; - if (window->interlaced_y) - reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y); + if (f->interlaced_y) + reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y); else - reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1); + reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1); - if (window->interlaced_uv) - reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1); + if (f->interlaced_uv) + reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1); else - reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv); + reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv); - reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14; - reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14; + reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14; + reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14; - if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) { - master_height = (window->src_h * 0x00400000) / window->dst_h; - if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++; + if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) { + master_height = (f->src_h * 0x00400000) / f->dst_h; + if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2) + master_height++; reg_2920 = master_height >> 2; reg_2928 = master_height >> 3; reg_2930 = master_height; @@ -432,45 +430,42 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi reg_2964_base >>= 3; reg_2968_base >>= 3; reg_296c = 0x00000000; - } - else if (window->dst_h >= window->src_h) { - master_height = (window->src_h * 0x00400000) / window->dst_h; + } else if (f->dst_h >= f->src_h) { + master_height = (f->src_h * 0x00400000) / f->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; reg_2930 = master_height; reg_2940 = master_height >> 1; reg_296c = 0x00000000; - if (window->interlaced_y) { + if (f->interlaced_y) { reg_2964_base >>= 3; - } - else { - reg_296c ++; + } else { + reg_296c++; reg_2964_base >>= 2; } - if (window->interlaced_uv) reg_2928 >>= 1; + if (f->interlaced_uv) + reg_2928 >>= 1; reg_2968_base >>= 3; - } - else if (window->dst_h >= window->src_h / 2) { - master_height = (window->src_h * 0x00200000) / window->dst_h; + } else if (f->dst_h >= f->src_h / 2) { + master_height = (f->src_h * 0x00200000) / f->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; reg_2930 = master_height; reg_2940 = master_height; reg_296c = 0x00000101; - if (window->interlaced_y) { + if (f->interlaced_y) { reg_2964_base >>= 2; - } - else { - reg_296c ++; + } else { + reg_296c++; reg_2964_base >>= 1; } - if (window->interlaced_uv) reg_2928 >>= 1; + if (f->interlaced_uv) + reg_2928 >>= 1; reg_2968_base >>= 2; - } - else { - master_height = (window->src_h * 0x00100000) / window->dst_h; + } else { + master_height = (f->src_h * 0x00100000) / f->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; @@ -483,13 +478,12 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi /* FIXME These registers change depending on scaled / unscaled output We really need to work out what they should be */ - if (window->src_h == window->dst_h){ + if (f->src_h == f->dst_h) { reg_2934 = 0x00020000; reg_293c = 0x00100000; reg_2944 = 0x00040000; reg_294c = 0x000b0000; - } - else { + } else { reg_2934 = 0x00000FF0; reg_293c = 0x00000FF0; reg_2944 = 0x00000FF0; @@ -497,34 +491,36 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi } /* The first line to be displayed */ - reg_2950 = 0x00010000 + src_y_major_y; - if (window->interlaced_y) reg_2950 += 0x00010000; + reg_2950 = 0x00010000 + src_major_y; + if (f->interlaced_y) + reg_2950 += 0x00010000; reg_2954 = reg_2950 + 1; - reg_2958 = 0x00010000 + (src_y_major_y >> 1); - if (window->interlaced_uv) reg_2958 += 0x00010000; + reg_2958 = 0x00010000 + (src_major_y >> 1); + if (f->interlaced_uv) + reg_2958 += 0x00010000; reg_295c = reg_2958 + 1; - if (itv->yuv_info.decode_height == 480) + if (yi->decode_height == 480) reg_289c = 0x011e0017; else reg_289c = 0x01500017; - if (window->dst_y < 0) - reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1); + if (f->dst_y < 0) + reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1); else - reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1); + reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1); /* How much of the source to decode. Take into account the source offset */ - reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) | - ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15); + reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) | + (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15); /* Calculate correct value for register 2964 */ - if (window->src_h == window->dst_h) + if (f->src_h == f->dst_h) { reg_2964 = 1; - else { - reg_2964 = 2 + ((window->dst_h << 1) / window->src_h); + } else { + reg_2964 = 2 + ((f->dst_h << 1) / f->src_h); reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); } reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); @@ -539,94 +535,107 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi /* Deviate further from what it should be. I find the flicker headache inducing so try to reduce it slightly. Leave 2968 as-is otherwise colours foul. */ - if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h)) - reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2); + if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h)) + reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2); - if (!window->interlaced_y) reg_2964 -= 0x00010001; - if (!window->interlaced_uv) reg_2968 -= 0x00010001; + if (!f->interlaced_y) + reg_2964 -= 0x00010001; + if (!f->interlaced_uv) + reg_2968 -= 0x00010001; reg_2964 += ((reg_2964_base << 16) | reg_2964_base); reg_2968 += ((reg_2968_base << 16) | reg_2968_base); /* Select the vertical filter */ - if (window->src_h == window->dst_h) { + if (f->src_h == f->dst_h) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; - } - else { + } else { /* Figure out which filter to use */ - v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15; + v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ - if (v_filter_1 == 0) v_filter_1 = 1; + v_filter_1 += !v_filter_1; v_filter_2 = v_filter_1; } write_reg(reg_2934, 0x02934); write_reg(reg_293c, 0x0293c); - IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c); + IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n", + yi->reg_2934, reg_2934, yi->reg_293c, reg_293c); write_reg(reg_2944, 0x02944); write_reg(reg_294c, 0x0294c); - IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c); + IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n", + yi->reg_2944, reg_2944, yi->reg_294c, reg_294c); /* Ensure 2970 is 0 (does it ever change ?) */ /* write_reg(0,0x02970); */ -/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */ +/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */ write_reg(reg_2930, 0x02938); write_reg(reg_2930, 0x02930); - IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930); + IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n", + yi->reg_2930, reg_2930, yi->reg_2938, reg_2930); write_reg(reg_2928, 0x02928); - write_reg(reg_2928+0x514, 0x0292C); - IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514); + write_reg(reg_2928 + 0x514, 0x0292C); + IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n", + yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514); write_reg(reg_2920, 0x02920); - write_reg(reg_2920+0x514, 0x02924); - IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920); + write_reg(reg_2920 + 0x514, 0x02924); + IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n", + yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514); - write_reg (reg_2918,0x02918); - write_reg (reg_291c,0x0291C); - IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c); + write_reg(reg_2918, 0x02918); + write_reg(reg_291c, 0x0291C); + IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n", + yi->reg_2918, reg_2918, yi->reg_291c, reg_291c); write_reg(reg_296c, 0x0296c); - IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c); + IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n", + yi->reg_296c, reg_296c); write_reg(reg_2940, 0x02948); write_reg(reg_2940, 0x02940); - IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940); + IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n", + yi->reg_2940, reg_2940, yi->reg_2948, reg_2940); write_reg(reg_2950, 0x02950); write_reg(reg_2954, 0x02954); - IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954); + IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n", + yi->reg_2950, reg_2950, yi->reg_2954, reg_2954); write_reg(reg_2958, 0x02958); write_reg(reg_295c, 0x0295C); - IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c); + IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n", + yi->reg_2958, reg_2958, yi->reg_295c, reg_295c); write_reg(reg_2960, 0x02960); - IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960); + IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n", + yi->reg_2960, reg_2960); write_reg(reg_2964, 0x02964); write_reg(reg_2968, 0x02968); - IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968); + IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n", + yi->reg_2964, reg_2964, yi->reg_2968, reg_2968); - write_reg( reg_289c,0x0289c); - IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c); + write_reg(reg_289c, 0x0289c); + IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n", + yi->reg_289c, reg_289c); /* Only update filter 1 if we really need to */ - if (v_filter_1 != itv->yuv_info.v_filter_1) { - ivtv_yuv_filter (itv,-1,v_filter_1,-1); - itv->yuv_info.v_filter_1 = v_filter_1; + if (v_filter_1 != yi->v_filter_1) { + ivtv_yuv_filter(itv, -1, v_filter_1, -1); + yi->v_filter_1 = v_filter_1; } /* Only update filter 2 if we really need to */ - if (v_filter_2 != itv->yuv_info.v_filter_2) { - ivtv_yuv_filter (itv,-1,-1,v_filter_2); - itv->yuv_info.v_filter_2 = v_filter_2; + if (v_filter_2 != yi->v_filter_2) { + ivtv_yuv_filter(itv, -1, -1, v_filter_2); + yi->v_filter_2 = v_filter_2; } - } /* Modify the supplied coordinate information to fit the visible osd area */ @@ -668,7 +677,7 @@ static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) /* If there's nothing to safe to display, we may as well stop now */ if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || - (int)f->src_w <= 2 || (int)f->src_h <= 2) { + (int)f->src_w <= 2 || (int)f->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } @@ -749,23 +758,23 @@ static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) /* Check again. If there's nothing to safe to display, stop now */ if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || - (int)f->src_w <= 2 || (int)f->src_h <= 2) { + (int)f->src_w <= 2 || (int)f->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Both x offset & width are linked, so they have to be done together */ if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || - (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || - (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { + (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || + (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; } if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || - (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || - (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || - (of->lace_mode != f->lace_mode) || - (of->interlaced_y != f->interlaced_y) || - (of->interlaced_uv != f->interlaced_uv)) { + (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || + (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || + (of->lace_mode != f->lace_mode) || + (of->interlaced_y != f->interlaced_y) || + (of->interlaced_uv != f->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; } @@ -773,24 +782,24 @@ static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) } /* Update the scaling register to the requested value */ -void ivtv_yuv_work_handler (struct ivtv *itv) +void ivtv_yuv_work_handler(struct ivtv *itv) { struct yuv_playback_info *yi = &itv->yuv_info; struct yuv_frame_info f; int frame = yi->update_frame; u32 yuv_update; -/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ + IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame); f = yi->new_frame_info[frame]; /* Update the osd pan info */ - f.pan_x = itv->yuv_info.osd_x_pan; - f.pan_y = itv->yuv_info.osd_y_pan; - f.vis_w = itv->yuv_info.osd_vis_w; - f.vis_h = itv->yuv_info.osd_vis_h; + f.pan_x = yi->osd_x_pan; + f.pan_y = yi->osd_y_pan; + f.vis_w = yi->osd_vis_w; + f.vis_h = yi->osd_vis_h; /* Calculate the display window coordinates. Exit if nothing left */ - if (!(yuv_update = ivtv_yuv_window_setup (itv, &f))) + if (!(yuv_update = ivtv_yuv_window_setup(itv, &f))) return; if (yuv_update & IVTV_YUV_UPDATE_INVALID) { @@ -807,7 +816,7 @@ void ivtv_yuv_work_handler (struct ivtv *itv) yi->old_frame_info = f; } -static void ivtv_yuv_init (struct ivtv *itv) +static void ivtv_yuv_init(struct ivtv *itv) { struct yuv_playback_info *yi = &itv->yuv_info; @@ -876,25 +885,23 @@ static void ivtv_yuv_init (struct ivtv *itv) if (!yi->osd_vis_w) yi->osd_vis_w = 720 - yi->osd_x_offset; - if (!yi->osd_vis_h) + if (!yi->osd_vis_h) { yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - else { + } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { /* If output video standard has changed, requested height may - not be legal */ - if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { - IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", - yi->osd_vis_h + yi->osd_y_offset, - yi->decode_height); - yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - } + not be legal */ + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + yi->osd_vis_h + yi->osd_y_offset, + yi->decode_height); + yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; } } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL); - if (yi->blanking_ptr) + yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL); + if (yi->blanking_ptr) { yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); - else { + } else { yi->blanking_dmaptr = 0; IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); } @@ -993,8 +1000,8 @@ void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { nf->interlaced = 0; if ((nf->tru_h < 512) || - (nf->tru_h > 576 && nf->tru_h < 1021) || - (nf->tru_w > 720 && nf->tru_h < 1021)) + (nf->tru_h > 576 && nf->tru_h < 1021) || + (nf->tru_w > 720 && nf->tru_h < 1021)) nf->interlaced_y = 0; else nf->interlaced_y = 1; @@ -1020,7 +1027,7 @@ void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { yi->old_frame_info_args = *nf; nf->update = 1; -/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ + IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame); } nf->update |= update; @@ -1051,10 +1058,10 @@ int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) ivtv_udma_prepare(itv); prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ + is finished */ while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ + a still pending DMA. */ got_sig = signal_pending(current); if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) break; @@ -1121,7 +1128,7 @@ int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src) /* IVTV_IOC_DMA_FRAME ioctl handler */ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) { - IVTV_DEBUG_INFO("yuv_prep_frame\n"); +/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ ivtv_yuv_next_free(itv); ivtv_yuv_setup_frame(itv, args); @@ -1130,91 +1137,90 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) void ivtv_yuv_close(struct ivtv *itv) { + struct yuv_playback_info *yi = &itv->yuv_info; int h_filter, v_filter_1, v_filter_2; IVTV_DEBUG_YUV("ivtv_yuv_close\n"); ivtv_waitq(&itv->vsync_waitq); - atomic_set(&itv->yuv_info.next_dma_frame, -1); - atomic_set(&itv->yuv_info.next_fill_frame, 0); + atomic_set(&yi->next_dma_frame, -1); + atomic_set(&yi->next_fill_frame, 0); /* Reset registers we have changed so mpeg playback works */ /* If we fully restore this register, the display may remain active. Restore, but set one bit to blank the video. Firmware will always clear this bit when needed, so not a problem. */ - write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); - - write_reg(itv->yuv_info.reg_2834, 0x02834); - write_reg(itv->yuv_info.reg_2838, 0x02838); - write_reg(itv->yuv_info.reg_283c, 0x0283c); - write_reg(itv->yuv_info.reg_2840, 0x02840); - write_reg(itv->yuv_info.reg_2844, 0x02844); - write_reg(itv->yuv_info.reg_2848, 0x02848); - write_reg(itv->yuv_info.reg_2854, 0x02854); - write_reg(itv->yuv_info.reg_285c, 0x0285c); - write_reg(itv->yuv_info.reg_2864, 0x02864); - write_reg(itv->yuv_info.reg_2870, 0x02870); - write_reg(itv->yuv_info.reg_2874, 0x02874); - write_reg(itv->yuv_info.reg_2890, 0x02890); - write_reg(itv->yuv_info.reg_289c, 0x0289c); - - write_reg(itv->yuv_info.reg_2918, 0x02918); - write_reg(itv->yuv_info.reg_291c, 0x0291c); - write_reg(itv->yuv_info.reg_2920, 0x02920); - write_reg(itv->yuv_info.reg_2924, 0x02924); - write_reg(itv->yuv_info.reg_2928, 0x02928); - write_reg(itv->yuv_info.reg_292c, 0x0292c); - write_reg(itv->yuv_info.reg_2930, 0x02930); - write_reg(itv->yuv_info.reg_2934, 0x02934); - write_reg(itv->yuv_info.reg_2938, 0x02938); - write_reg(itv->yuv_info.reg_293c, 0x0293c); - write_reg(itv->yuv_info.reg_2940, 0x02940); - write_reg(itv->yuv_info.reg_2944, 0x02944); - write_reg(itv->yuv_info.reg_2948, 0x02948); - write_reg(itv->yuv_info.reg_294c, 0x0294c); - write_reg(itv->yuv_info.reg_2950, 0x02950); - write_reg(itv->yuv_info.reg_2954, 0x02954); - write_reg(itv->yuv_info.reg_2958, 0x02958); - write_reg(itv->yuv_info.reg_295c, 0x0295c); - write_reg(itv->yuv_info.reg_2960, 0x02960); - write_reg(itv->yuv_info.reg_2964, 0x02964); - write_reg(itv->yuv_info.reg_2968, 0x02968); - write_reg(itv->yuv_info.reg_296c, 0x0296c); - write_reg(itv->yuv_info.reg_2970, 0x02970); + write_reg(yi->reg_2898 | 0x01000000, 0x2898); + + write_reg(yi->reg_2834, 0x02834); + write_reg(yi->reg_2838, 0x02838); + write_reg(yi->reg_283c, 0x0283c); + write_reg(yi->reg_2840, 0x02840); + write_reg(yi->reg_2844, 0x02844); + write_reg(yi->reg_2848, 0x02848); + write_reg(yi->reg_2854, 0x02854); + write_reg(yi->reg_285c, 0x0285c); + write_reg(yi->reg_2864, 0x02864); + write_reg(yi->reg_2870, 0x02870); + write_reg(yi->reg_2874, 0x02874); + write_reg(yi->reg_2890, 0x02890); + write_reg(yi->reg_289c, 0x0289c); + + write_reg(yi->reg_2918, 0x02918); + write_reg(yi->reg_291c, 0x0291c); + write_reg(yi->reg_2920, 0x02920); + write_reg(yi->reg_2924, 0x02924); + write_reg(yi->reg_2928, 0x02928); + write_reg(yi->reg_292c, 0x0292c); + write_reg(yi->reg_2930, 0x02930); + write_reg(yi->reg_2934, 0x02934); + write_reg(yi->reg_2938, 0x02938); + write_reg(yi->reg_293c, 0x0293c); + write_reg(yi->reg_2940, 0x02940); + write_reg(yi->reg_2944, 0x02944); + write_reg(yi->reg_2948, 0x02948); + write_reg(yi->reg_294c, 0x0294c); + write_reg(yi->reg_2950, 0x02950); + write_reg(yi->reg_2954, 0x02954); + write_reg(yi->reg_2958, 0x02958); + write_reg(yi->reg_295c, 0x0295c); + write_reg(yi->reg_2960, 0x02960); + write_reg(yi->reg_2964, 0x02964); + write_reg(yi->reg_2968, 0x02968); + write_reg(yi->reg_296c, 0x0296c); + write_reg(yi->reg_2970, 0x02970); /* Prepare to restore filters */ /* First the horizontal filter */ - if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { + if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) { /* An exact size match uses filter 0 */ h_filter = 0; - } - else { + } else { /* Figure out which filter to use */ - h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; + h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0. */ - if (h_filter < 1) h_filter = 1; + h_filter += !h_filter; } /* Now the vertical filter */ - if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { + if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; - } - else { + } else { /* Figure out which filter to use */ - v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; + v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ - if (v_filter_1 == 0) v_filter_1 = 1; + v_filter_1 += !v_filter_1; v_filter_2 = v_filter_1; } /* Now restore the filters */ - ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); + ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2); /* and clear a few registers */ write_reg(0, 0x02814); @@ -1223,19 +1229,18 @@ void ivtv_yuv_close(struct ivtv *itv) write_reg(0, 0x02910); /* Release the blanking buffer */ - if (itv->yuv_info.blanking_ptr) { - kfree (itv->yuv_info.blanking_ptr); - itv->yuv_info.blanking_ptr = NULL; - pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); + if (yi->blanking_ptr) { + kfree(yi->blanking_ptr); + yi->blanking_ptr = NULL; + pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); } /* Invalidate the old dimension information */ - itv->yuv_info.old_frame_info.src_w = 0; - itv->yuv_info.old_frame_info.src_h = 0; - itv->yuv_info.old_frame_info_args.src_w = 0; - itv->yuv_info.old_frame_info_args.src_h = 0; + yi->old_frame_info.src_w = 0; + yi->old_frame_info.src_h = 0; + yi->old_frame_info_args.src_w = 0; + yi->old_frame_info_args.src_h = 0; /* All done. */ clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); } - -- cgit v1.2.3 From efce841093589bfef571a07e18e5446def9e04b4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 1 Dec 2007 17:40:16 -0300 Subject: V4L/DVB (6723): tda18271: only force init once during attach Once the image rejection calibration procedure has been successful, we should not initialize the tuner registers again. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 726e102cbc5..25c127f67c2 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -337,6 +337,20 @@ static int tda18271_init_regs(struct dvb_frontend *fe) return 0; } +static int tda18271_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda18271_read_regs(fe); + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) == 0) + tda18271_init_regs(fe); + + return 0; +} + static int tda18271_tune(struct dvb_frontend *fe, u32 ifc, u32 freq, u32 bw, u8 std) { @@ -742,7 +756,7 @@ static struct dvb_tuner_ops tda18271_tuner_ops = { .frequency_max = 864000000, .frequency_step = 62500 }, - .init = tda18271_init_regs, + .init = tda18271_init, .set_params = tda18271_set_params, .set_analog_params = tda18271_set_analog_params, .release = tda18271_release, @@ -768,6 +782,8 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, fe->tuner_priv = priv; + tda18271_init_regs(fe); + return fe; } EXPORT_SYMBOL_GPL(tda18271_attach); -- cgit v1.2.3 From 1457263e9df6911384c474532a49d1b25bc9d248 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 2 Dec 2007 02:32:49 -0300 Subject: V4L/DVB (6724): tda18271: remove duplicated code Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 25c127f67c2..1944177da87 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -359,12 +359,7 @@ static int tda18271_tune(struct dvb_frontend *fe, u32 div, N = 0; int i; - tda18271_read_regs(fe); - - /* test IR_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x08) == 0) - tda18271_init_regs(fe); - + tda18271_init(fe); dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); -- cgit v1.2.3 From 293da0ec468addf891856e9ffee88af2fd00e25a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 2 Dec 2007 02:45:04 -0300 Subject: V4L/DVB (6725): tda18271: improve debug flexibility converted debug module option to an or-able setting. 1 = info 2 = table map values 4 = register dumps Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 70 +++++++++++++++++-------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 1944177da87..01de75e369e 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -27,12 +27,20 @@ static int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); #define dprintk(level, fmt, arg...) do {\ - if (tda18271_debug >= level) \ + if (tda18271_debug & level) \ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) +#define DBG_INFO 1 +#define DBG_MAP 2 +#define DBG_REG 4 + +#define dbg_info(fmt, arg...) dprintk(DBG_INFO, fmt, ##arg) +#define dbg_map(fmt, arg...) dprintk(DBG_MAP, fmt, ##arg) +#define dbg_reg(fmt, arg...) dprintk(DBG_REG, fmt, ##arg) + /*---------------------------------------------------------------------*/ #define TDA18271_ANALOG 0 @@ -75,23 +83,23 @@ static void tda18271_dump_regs(struct dvb_frontend *fe) struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - dprintk(1, "=== TDA18271 REG DUMP ===\n"); - dprintk(1, "ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); - dprintk(1, "THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); - dprintk(1, "POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); - dprintk(1, "EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); - dprintk(1, "EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); - dprintk(1, "EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); - dprintk(1, "EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); - dprintk(1, "EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); - dprintk(1, "CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); - dprintk(1, "CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); - dprintk(1, "CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); - dprintk(1, "CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); - dprintk(1, "MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); - dprintk(1, "MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); - dprintk(1, "MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); - dprintk(1, "MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); + dbg_reg("=== TDA18271 REG DUMP ===\n"); + dbg_reg("ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); + dbg_reg("THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); + dbg_reg("POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); + dbg_reg("EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); + dbg_reg("EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); + dbg_reg("EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); + dbg_reg("EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); + dbg_reg("EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); + dbg_reg("CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); + dbg_reg("CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); + dbg_reg("CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); + dbg_reg("CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); + dbg_reg("MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); + dbg_reg("MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); + dbg_reg("MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); + dbg_reg("MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); } static void tda18271_read_regs(struct dvb_frontend *fe) @@ -118,7 +126,7 @@ static void tda18271_read_regs(struct dvb_frontend *fe) printk("ERROR: %s: i2c_transfer returned: %d\n", __FUNCTION__, ret); - if (tda18271_debug > 2) + if (tda18271_debug & DBG_REG) tda18271_dump_regs(fe); } @@ -361,7 +369,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_init(fe); - dprintk(1, "freq = %d, ifc = %d\n", freq, ifc); + dbg_info("freq = %d, ifc = %d\n", freq, ifc); /* RF tracking filter calibration */ @@ -372,7 +380,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); + dbg_map("bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); regs[R_EP1] &= ~0x07; /* clear bp filter bits */ regs[R_EP1] |= tda18271_bp_filter[i].val; @@ -411,7 +419,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "cal pll, pd = 0x%x, d = 0x%x, i = %d\n", + dbg_map("cal pll, pd = 0x%x, d = 0x%x, i = %d\n", tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); regs[R_CPD] = tda18271_cal_pll[i].pd; @@ -438,7 +446,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + dbg_map("main pll, pd = 0x%x, d = 0x%x, i = %d\n", tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); @@ -467,7 +475,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "km = 0x%x, i = %d\n", tda18271_km[i].val, i); + dbg_map("km = 0x%x, i = %d\n", tda18271_km[i].val, i); regs[R_EB13] &= 0x83; regs[R_EB13] |= tda18271_km[i].val; @@ -480,7 +488,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); + dbg_map("rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); regs[R_EP2] &= ~0xe0; /* clear rf band bits */ regs[R_EP2] |= (tda18271_rf_band[i].val << 5); @@ -492,7 +500,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "gain taper = 0x%x, i = %d\n", + dbg_map("gain taper = 0x%x, i = %d\n", tda18271_gain_taper[i].val, i); regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ @@ -527,7 +535,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); + dbg_map("rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); /* VHF_Low band only */ if (tda18271_rf_cal[i].rfmax != 0) { @@ -581,7 +589,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; i++; } - dprintk(2, "main pll, pd = 0x%x, d = 0x%x, i = %d\n", + dbg_map("main pll, pd = 0x%x, d = 0x%x, i = %d\n", tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); @@ -717,7 +725,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, if (params->mode == V4L2_TUNER_RADIO) sgIF = 88; /* if frequency is 5.5 MHz */ - dprintk(1, "setting tda18271 to system %s\n", mode); + dbg_info("setting tda18271 to system %s\n", mode); return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, 0, std); @@ -764,7 +772,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, { struct tda18271_priv *priv = NULL; - dprintk(1, "@ %d-%04x\n", i2c_adapter_id(i2c), addr); + dbg_info("@ %d-%04x\n", i2c_adapter_id(i2c), addr); priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); if (priv == NULL) return NULL; -- cgit v1.2.3 From aaeccba68a60eedee5fe90f9e1478367b1f97345 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 2 Dec 2007 11:03:57 -0300 Subject: V4L/DVB (6726): tda18271: set image rejection validity Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 11 ++++++++++- drivers/media/dvb/frontends/tda18271-priv.h | 1 + drivers/media/dvb/frontends/tda18271-tables.c | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 01de75e369e..fee38c1657e 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -578,7 +578,16 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ - /* FIXME: image rejection validity EP5[2:0] */ + /* image rejection validity EP5[2:0] */ + i = 0; + while ((tda18271_ir_measure[i].rfmax * 1000) < freq) { + if (tda18271_ir_measure[i].rfmax == 0) + break; + i++; + } + dbg_map("ir measure, i = %d\n", i); + regs[R_EP5] &= ~0x07; + regs[R_EP5] |= tda18271_ir_measure[i].val; /* calculate MAIN PLL */ N = freq + ifc; diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 71b4d796369..a3158eb2559 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -84,6 +84,7 @@ extern struct tda18271_map tda18271_km[]; extern struct tda18271_map tda18271_rf_band[]; extern struct tda18271_map tda18271_gain_taper[]; extern struct tda18271_map tda18271_rf_cal[]; +extern struct tda18271_map tda18271_ir_measure[]; #endif /* __TDA18271_PRIV_H__ */ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index a018b514087..d65d3411e36 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -244,6 +244,14 @@ struct tda18271_map tda18271_rf_cal[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; +struct tda18271_map tda18271_ir_measure[] = { + { .rfmax = 30000, .val = 4}, + { .rfmax = 200000, .val = 5}, + { .rfmax = 600000, .val = 6}, + { .rfmax = 865000, .val = 7}, + { .rfmax = 0, .val = 0}, /* end */ +}; + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- -- cgit v1.2.3 From b5f3e1e153b60f7bc338cdd6eefacd59c2dfb375 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 2 Dec 2007 16:36:05 -0300 Subject: V4L/DVB (6727): tda18271: convert table lookup loops to functions Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 119 ++++++-------------------- drivers/media/dvb/frontends/tda18271-priv.h | 46 +++++----- drivers/media/dvb/frontends/tda18271-tables.c | 106 +++++++++++++++++++++-- 3 files changed, 149 insertions(+), 122 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index fee38c1657e..5d3c4b0975f 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -25,22 +25,10 @@ #include "tda18271.h" #include "tda18271-priv.h" -static int tda18271_debug; +int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); -#define dprintk(level, fmt, arg...) do {\ - if (tda18271_debug & level) \ - printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) - -#define DBG_INFO 1 -#define DBG_MAP 2 -#define DBG_REG 4 - -#define dbg_info(fmt, arg...) dprintk(DBG_INFO, fmt, ##arg) -#define dbg_map(fmt, arg...) dprintk(DBG_MAP, fmt, ##arg) -#define dbg_reg(fmt, arg...) dprintk(DBG_REG, fmt, ##arg) - /*---------------------------------------------------------------------*/ #define TDA18271_ANALOG 0 @@ -365,7 +353,7 @@ static int tda18271_tune(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; u32 div, N = 0; - int i; + u8 d, pd, val; tda18271_init(fe); @@ -374,16 +362,10 @@ static int tda18271_tune(struct dvb_frontend *fe, /* RF tracking filter calibration */ /* calculate BP_Filter */ - i = 0; - while ((tda18271_bp_filter[i].rfmax * 1000) < freq) { - if (tda18271_bp_filter[i + 1].rfmax == 0) - break; - i++; - } - dbg_map("bp filter = 0x%x, i = %d\n", tda18271_bp_filter[i].val, i); + tda18271_calc_bp_filter(&freq, &val); regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= tda18271_bp_filter[i].val; + regs[R_EP1] |= val; tda18271_write_regs(fe, R_EP1, 1); regs[R_EB4] &= 0x07; @@ -413,18 +395,11 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - i = 0; - while ((tda18271_cal_pll[i].lomax * 1000) < N) { - if (tda18271_cal_pll[i + 1].lomax == 0) - break; - i++; - } - dbg_map("cal pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); + tda18271_calc_cal_pll(&N, &pd, &d); - regs[R_CPD] = tda18271_cal_pll[i].pd; + regs[R_CPD] = pd; - div = ((tda18271_cal_pll[i].d * (N / 1000)) << 7) / 125; + div = ((d * (N / 1000)) << 7) / 125; regs[R_CD1] = 0xff & (div >> 16); regs[R_CD2] = 0xff & (div >> 8); regs[R_CD3] = 0xff & div; @@ -440,16 +415,9 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - i = 0; - while ((tda18271_main_pll[i].lomax * 1000) < N) { - if (tda18271_main_pll[i + 1].lomax == 0) - break; - i++; - } - dbg_map("main pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + tda18271_calc_main_pll(&N, &pd, &d); - regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + regs[R_MPD] = (0x7f & pd); switch (priv->mode) { case TDA18271_ANALOG: @@ -460,7 +428,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + div = ((d * (N / 1000)) << 7) / 125; regs[R_MD1] = 0xff & (div >> 16); regs[R_MD2] = 0xff & (div >> 8); regs[R_MD3] = 0xff & div; @@ -469,42 +437,23 @@ static int tda18271_tune(struct dvb_frontend *fe, msleep(5); /* RF tracking filter calibration initialization */ /* search for K,M,CO for RF Calibration */ - i = 0; - while ((tda18271_km[i].rfmax * 1000) < freq) { - if (tda18271_km[i + 1].rfmax == 0) - break; - i++; - } - dbg_map("km = 0x%x, i = %d\n", tda18271_km[i].val, i); + tda18271_calc_km(&freq, &val); regs[R_EB13] &= 0x83; - regs[R_EB13] |= tda18271_km[i].val; + regs[R_EB13] |= val; tda18271_write_regs(fe, R_EB13, 1); /* search for RF_BAND */ - i = 0; - while ((tda18271_rf_band[i].rfmax * 1000) < freq) { - if (tda18271_rf_band[i + 1].rfmax == 0) - break; - i++; - } - dbg_map("rf band = 0x%x, i = %d\n", tda18271_rf_band[i].val, i); + tda18271_calc_rf_band(&freq, &val); regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (tda18271_rf_band[i].val << 5); + regs[R_EP2] |= (val << 5); /* search for Gain_Taper */ - i = 0; - while ((tda18271_gain_taper[i].rfmax * 1000) < freq) { - if (tda18271_gain_taper[i + 1].rfmax == 0) - break; - i++; - } - dbg_map("gain taper = 0x%x, i = %d\n", - tda18271_gain_taper[i].val, i); + tda18271_calc_gain_taper(&freq, &val); regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= tda18271_gain_taper[i].val; + regs[R_EP2] |= val; tda18271_write_regs(fe, R_EP2, 1); tda18271_write_regs(fe, R_EP1, 1); @@ -529,17 +478,11 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP1, 1); /* RF tracking filer correction for VHF_Low band */ - i = 0; - while ((tda18271_rf_cal[i].rfmax * 1000) < freq) { - if (tda18271_rf_cal[i].rfmax == 0) - break; - i++; - } - dbg_map("rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); + tda18271_calc_rf_cal(&freq, &val); /* VHF_Low band only */ - if (tda18271_rf_cal[i].rfmax != 0) { - regs[R_EB14] = tda18271_rf_cal[i].val; + if (val != 0) { + regs[R_EB14] = val; tda18271_write_regs(fe, R_EB14, 1); } @@ -579,29 +522,17 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ /* image rejection validity EP5[2:0] */ - i = 0; - while ((tda18271_ir_measure[i].rfmax * 1000) < freq) { - if (tda18271_ir_measure[i].rfmax == 0) - break; - i++; - } - dbg_map("ir measure, i = %d\n", i); + tda18271_calc_ir_measure(&freq, &val); + regs[R_EP5] &= ~0x07; - regs[R_EP5] |= tda18271_ir_measure[i].val; + regs[R_EP5] |= val; /* calculate MAIN PLL */ N = freq + ifc; - i = 0; - while ((tda18271_main_pll[i].lomax * 1000) < N) { - if (tda18271_main_pll[i + 1].lomax == 0) - break; - i++; - } - dbg_map("main pll, pd = 0x%x, d = 0x%x, i = %d\n", - tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); + tda18271_calc_main_pll(&N, &pd, &d); - regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); + regs[R_MPD] = (0x7f & pd); switch (priv->mode) { case TDA18271_ANALOG: regs[R_MPD] &= ~0x08; @@ -611,7 +542,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; + div = ((d * (N / 1000)) << 7) / 125; regs[R_MD1] = 0xff & (div >> 16); regs[R_MD2] = 0xff & (div >> 8); regs[R_MD3] = 0xff & div; diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index a3158eb2559..d56c2fe3efa 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -21,6 +21,7 @@ #ifndef __TDA18271_PRIV_H__ #define __TDA18271_PRIV_H__ +#include #include #define R_ID 0x00 /* ID byte */ @@ -65,26 +66,31 @@ #define TDA18271_NUM_REGS 39 -struct tda18271_pll_map { - u32 lomax; - u8 pd; /* post div */ - u8 d; /* div */ -}; - -extern struct tda18271_pll_map tda18271_main_pll[]; -extern struct tda18271_pll_map tda18271_cal_pll[]; - -struct tda18271_map { - u32 rfmax; - u8 val; -}; - -extern struct tda18271_map tda18271_bp_filter[]; -extern struct tda18271_map tda18271_km[]; -extern struct tda18271_map tda18271_rf_band[]; -extern struct tda18271_map tda18271_gain_taper[]; -extern struct tda18271_map tda18271_rf_cal[]; -extern struct tda18271_map tda18271_ir_measure[]; +extern int tda18271_debug; + +#define dprintk(level, fmt, arg...) do {\ + if (tda18271_debug & level) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) + +#define DBG_INFO 1 +#define DBG_MAP 2 +#define DBG_REG 4 + +#define dbg_info(fmt, arg...) dprintk(DBG_INFO, fmt, ##arg) +#define dbg_map(fmt, arg...) dprintk(DBG_MAP, fmt, ##arg) +#define dbg_reg(fmt, arg...) dprintk(DBG_REG, fmt, ##arg) + +/*---------------------------------------------------------------------*/ + +extern void tda18271_calc_cal_pll(u32 *freq, u8 *post_div, u8 *div); +extern void tda18271_calc_main_pll(u32 *freq, u8 *post_div, u8 *div); + +extern void tda18271_calc_bp_filter(u32 *freq, u8 *val); +extern void tda18271_calc_km(u32 *freq, u8 *val); +extern void tda18271_calc_rf_band(u32 *freq, u8 *val); +extern void tda18271_calc_gain_taper(u32 *freq, u8 *val); +extern void tda18271_calc_rf_cal(u32 *freq, u8 *val); +extern void tda18271_calc_ir_measure(u32 *freq, u8 *val); #endif /* __TDA18271_PRIV_H__ */ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index d65d3411e36..65387bb059e 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -20,7 +20,20 @@ #include "tda18271-priv.h" -struct tda18271_pll_map tda18271_main_pll[] = { +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_pll_map tda18271_main_pll[] = { { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, @@ -64,7 +77,7 @@ struct tda18271_pll_map tda18271_main_pll[] = { { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ }; -struct tda18271_pll_map tda18271_cal_pll[] = { +static struct tda18271_pll_map tda18271_cal_pll[] = { { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, @@ -103,7 +116,7 @@ struct tda18271_pll_map tda18271_cal_pll[] = { { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ }; -struct tda18271_map tda18271_bp_filter[] = { +static struct tda18271_map tda18271_bp_filter[] = { { .rfmax = 62000, .val = 0x00 }, { .rfmax = 84000, .val = 0x01 }, { .rfmax = 100000, .val = 0x02 }, @@ -114,7 +127,7 @@ struct tda18271_map tda18271_bp_filter[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -struct tda18271_map tda18271_km[] = { +static struct tda18271_map tda18271_km[] = { { .rfmax = 61100, .val = 0x74 }, { .rfmax = 350000, .val = 0x40 }, { .rfmax = 720000, .val = 0x30 }, @@ -122,7 +135,7 @@ struct tda18271_map tda18271_km[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -struct tda18271_map tda18271_rf_band[] = { +static struct tda18271_map tda18271_rf_band[] = { { .rfmax = 47900, .val = 0x00 }, { .rfmax = 61100, .val = 0x01 }, /* { .rfmax = 152600, .val = 0x02 }, */ @@ -134,7 +147,7 @@ struct tda18271_map tda18271_rf_band[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -struct tda18271_map tda18271_gain_taper[] = { +static struct tda18271_map tda18271_gain_taper[] = { { .rfmax = 45400, .val = 0x1f }, { .rfmax = 45800, .val = 0x1e }, { .rfmax = 46200, .val = 0x1d }, @@ -223,7 +236,7 @@ struct tda18271_map tda18271_gain_taper[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -struct tda18271_map tda18271_rf_cal[] = { +static struct tda18271_map tda18271_rf_cal[] = { { .rfmax = 41000, .val = 0x1e }, { .rfmax = 43000, .val = 0x30 }, { .rfmax = 45000, .val = 0x43 }, @@ -244,7 +257,7 @@ struct tda18271_map tda18271_rf_cal[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -struct tda18271_map tda18271_ir_measure[] = { +static struct tda18271_map tda18271_ir_measure[] = { { .rfmax = 30000, .val = 4}, { .rfmax = 200000, .val = 5}, { .rfmax = 600000, .val = 6}, @@ -252,6 +265,83 @@ struct tda18271_map tda18271_ir_measure[] = { { .rfmax = 0, .val = 0}, /* end */ }; +/*---------------------------------------------------------------------*/ + +static void tda18271_lookup_map(struct tda18271_map *map, + u32 *freq, u8 *val) +{ + int i = 0; + while ((map[i].rfmax * 1000) < *freq) { + if (map[i + 1].rfmax == 0) + break; + i++; + } + *val = map[i].val; +} + +static void tda18271_lookup_pll_map(struct tda18271_pll_map *map, + u32 *freq, u8 *post_div, u8 *div) +{ + int i = 0; + while ((map[i].lomax * 1000) < *freq) { + if (map[i + 1].lomax == 0) + break; + i++; + } + *post_div = map[i].pd; + *div = map[i].d; +} + +/*---------------------------------------------------------------------*/ + +void tda18271_calc_cal_pll(u32 *freq, u8 *post_div, u8 *div) +{ + tda18271_lookup_pll_map(tda18271_cal_pll, freq, post_div, div); + dbg_map("post div = 0x%02x, div = 0x%02x\n", *post_div, *div); +} + +void tda18271_calc_main_pll(u32 *freq, u8 *post_div, u8 *div) +{ + tda18271_lookup_pll_map(tda18271_main_pll, freq, post_div, div); + dbg_map("post div = 0x%02x, div = 0x%02x\n", *post_div, *div); +} + +void tda18271_calc_bp_filter(u32 *freq, u8 *val) +{ + tda18271_lookup_map(tda18271_bp_filter, freq, val); + dbg_map("0x%02x\n", *val); +} + +void tda18271_calc_km(u32 *freq, u8 *val) +{ + tda18271_lookup_map(tda18271_km, freq, val); + dbg_map("0x%02x\n", *val); +} + +void tda18271_calc_rf_band(u32 *freq, u8 *val) +{ + tda18271_lookup_map(tda18271_rf_band, freq, val); + dbg_map("0x%02x\n", *val); +} + +void tda18271_calc_gain_taper(u32 *freq, u8 *val) +{ + tda18271_lookup_map(tda18271_gain_taper, freq, val); + dbg_map("0x%02x\n", *val); +} + +void tda18271_calc_rf_cal(u32 *freq, u8 *val) +{ + tda18271_lookup_map(tda18271_rf_cal, freq, val); + dbg_map("0x%02x\n", *val); +} + +void tda18271_calc_ir_measure(u32 *freq, u8 *val) +{ + tda18271_lookup_map(tda18271_ir_measure, freq, val); + dbg_map("0x%02x\n", *val); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- -- cgit v1.2.3 From 5d2bf930a2f4586a3e19318ed821a34193c4b7cd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 2 Dec 2007 17:37:38 -0300 Subject: V4L/DVB (6728): tda18271: fix register dump format Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 5d3c4b0975f..e8f4ac2325d 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -72,22 +72,22 @@ static void tda18271_dump_regs(struct dvb_frontend *fe) unsigned char *regs = priv->tda18271_regs; dbg_reg("=== TDA18271 REG DUMP ===\n"); - dbg_reg("ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); - dbg_reg("THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); - dbg_reg("POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); - dbg_reg("EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); - dbg_reg("EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); - dbg_reg("EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); - dbg_reg("EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); - dbg_reg("EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); - dbg_reg("CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); - dbg_reg("CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); - dbg_reg("CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); - dbg_reg("CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); - dbg_reg("MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); - dbg_reg("MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); - dbg_reg("MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); - dbg_reg("MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); + dbg_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); + dbg_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); + dbg_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); + dbg_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); + dbg_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); + dbg_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); + dbg_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); + dbg_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); + dbg_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); + dbg_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); + dbg_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); + dbg_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); + dbg_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); + dbg_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); + dbg_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); + dbg_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); } static void tda18271_read_regs(struct dvb_frontend *fe) -- cgit v1.2.3 From e1ba33df0cbc6a7ab339dc093f37825775b9caca Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Sun, 2 Dec 2007 14:47:01 -0300 Subject: V4L/DVB (6731): ivtv: Remove a invalid shadow-variable Remove the shadowing 'struct v4l2_chip_ident *chip', since it already exists and makes the if-statement useless. Signed-off-by: Richard Knutsson Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 0618fee2495..25b68843a28 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -673,11 +673,8 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) chip->ident = V4L2_IDENT_NONE; chip->revision = 0; if (reg->match_type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { - struct v4l2_chip_ident *chip = arg; - + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; - } return 0; } if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) -- cgit v1.2.3 From 863c86dd7e014e645207fd16f4e06bc223567984 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 3 Dec 2007 06:48:43 -0300 Subject: V4L/DVB (6732): dsbr100 violates DMA coherency rules Signed-off-by: Oliver Neukum Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 3bd07f7e377..36c0e365150 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -33,6 +33,9 @@ History: + Version 0.43: + Oliver Neukum: avoided DMA coherency issue + Version 0.42: Converted dsbr100 to use video_ioctl2 by Douglas Landgraf @@ -135,7 +138,7 @@ module_param(radio_nr, int, 0); struct dsbr100_device { struct usb_device *usbdev; struct video_device *videodev; - unsigned char transfer_buffer[TB_LEN]; + u8 *transfer_buffer; int curfreq; int stereo; int users; @@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio) /* handle unplugging of the device, release data structures if nothing keeps us from doing it. If something is still keeping us busy, the release callback of v4l will take care -of releasing it. stv680.c does not relase its private -data, so I don't do this here either. Checking out the -code I'd expect I better did that, but if there's a memory -leak here it's tiny (~50 bytes per disconnect) */ +of releasing it. */ static void usb_dsbr100_disconnect(struct usb_interface *intf) { struct dsbr100_device *radio = usb_get_intfdata(intf); @@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf) video_unregister_device(radio->videodev); radio->videodev = NULL; if (radio->users) { + kfree(radio->transfer_buffer); kfree(radio); } else { radio->removed = 1; @@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file) return -ENODEV; radio->users = 0; if (radio->removed) { + kfree(radio->transfer_buffer); kfree(radio); } return 0; @@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf, if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL))) return -ENOMEM; + if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) { + kfree(radio); + return -ENOMEM; + } if (!(radio->videodev = video_device_alloc())) { + kfree(radio->transfer_buffer); kfree(radio); return -ENOMEM; } @@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) { warn("Could not register video device"); video_device_release(radio->videodev); + kfree(radio->transfer_buffer); kfree(radio); return -EIO; } -- cgit v1.2.3 From 8f61ae2f4ff698c7cd83b1f17b1ca2ecfc7f0696 Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Fri, 7 Dec 2007 17:09:53 -0300 Subject: V4L/DVB (6734): Converted saa7134-video to use video_ioctl2 Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 1212 ++++++++++++++------------- 1 file changed, 610 insertions(+), 602 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9c160b2bca3..954542e5c99 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1119,8 +1119,11 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) { + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; const struct v4l2_queryctrl* ctrl; ctrl = ctrl_by_id(c->id); @@ -1166,13 +1169,16 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) return 0; } -static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_control *c) +static int vidioc_s_ctrl(struct file *file, void *f, + struct v4l2_control *c) { const struct v4l2_queryctrl* ctrl; + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; unsigned long flags; int restart_overlay = 0; + mutex_lock(&dev->lock); ctrl = ctrl_by_id(c->id); if (NULL == ctrl) return -EINVAL; @@ -1255,6 +1261,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, break; } default: + mutex_unlock(&dev->lock); return -EINVAL; } if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { @@ -1263,6 +1270,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } + mutex_unlock(&dev->lock); return 0; } @@ -1502,9 +1510,12 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) } -static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); @@ -1532,9 +1543,11 @@ static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, } } -static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; int err; switch (f->type) { @@ -1602,15 +1615,17 @@ static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, } } -static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; unsigned long flags; int err; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - err = saa7134_try_fmt(dev,fh,f); + err = vidioc_try_fmt_cap(file, priv, f); if (0 != err) return err; @@ -1655,682 +1670,625 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, } } -int saa7134_common_ioctl(struct saa7134_dev *dev, - unsigned int cmd, void *arg) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - int err; + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - switch (cmd) { - case VIDIOC_QUERYCTRL: - { - const struct v4l2_queryctrl *ctrl; - struct v4l2_queryctrl *c = arg; + *i = dev->ctl_input; + return 0; +} - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - ctrl = ctrl_by_id(c->id); - *c = (NULL != ctrl) ? *ctrl : no_ctrl; - return 0; - } - case VIDIOC_G_CTRL: - return get_control(dev,arg); - case VIDIOC_S_CTRL: - { - mutex_lock(&dev->lock); - err = set_control(dev,NULL,arg); - mutex_unlock(&dev->lock); - return err; - } - /* --- input switching --------------------------------------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - n = i->index; - if (n >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev,i->index).name) - return -EINVAL; - memset(i,0,sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,card_in(dev,n).name); - if (card_in(dev,n).tv) - i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; - if (n == dev->ctl_input) { - int v1 = saa_readb(SAA7134_STATUS_VIDEO1); - int v2 = saa_readb(SAA7134_STATUS_VIDEO2); - - if (0 != (v1 & 0x40)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - if (0 != (v2 & 0x40)) - i->status |= V4L2_IN_ST_NO_SYNC; - if (0 != (v2 & 0x0e)) - i->status |= V4L2_IN_ST_MACROVISION; - } - for (n = 0; n < TVNORMS; n++) - i->std |= tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = dev->ctl_input; - return 0; - } - case VIDIOC_S_INPUT: - { - int *i = arg; + if (i < 0 || i >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i).name) + return -EINVAL; + mutex_lock(&dev->lock); + video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} - if (*i < 0 || *i >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev,*i).name) - return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev,*i); - mutex_unlock(&dev->lock); - return 0; - } +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; - } + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + ctrl = ctrl_by_id(c->id); + *c = (NULL != ctrl) ? *ctrl : no_ctrl; return 0; } -EXPORT_SYMBOL(saa7134_common_ioctl); -/* - * This function is _not_ called directly, but from - * video_generic_ioctl (and maybe others). userspace - * copying is done already, arg is a kernel pointer. - */ -static int video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) { - struct saa7134_fh *fh = file->private_data; + struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - unsigned long flags; - int err; + unsigned int n; - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); + n = i->index; + if (n >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i->index).name) + return -EINVAL; + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, card_in(dev, n).name); + if (card_in(dev, n).tv) + i->type = V4L2_INPUT_TYPE_TUNER; + i->audioset = 1; + if (n == dev->ctl_input) { + int v1 = saa_readb(SAA7134_STATUS_VIDEO1); + int v2 = saa_readb(SAA7134_STATUS_VIDEO2); + + if (0 != (v1 & 0x40)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + if (0 != (v2 & 0x40)) + i->status |= V4L2_IN_ST_NO_SYNC; + if (0 != (v2 & 0x0e)) + i->status |= V4L2_IN_ST_MACROVISION; + } + for (n = 0; n < TVNORMS; n++) + i->std |= tvnorms[n].id; + return 0; +} - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - err = v4l2_prio_check(&dev->prio,&fh->prio); - if (0 != err) - return err; - } +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - unsigned int tuner_type = dev->tuner_type; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - if (saa7134_no_overlay <= 0) { - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - } + unsigned int tuner_type = dev->tuner_type; + + memset(cap, 0, sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + if (saa7134_no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; + return 0; +} - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * id) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + unsigned long flags; + unsigned int i; + v4l2_std_id fixup; - return 0; + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if (secam[0] == 'L' || secam[0] == 'l') { + if (secam[1] == 'C' || secam[1] == 'c') + fixup = V4L2_STD_SECAM_LC; + else + fixup = V4L2_STD_SECAM_L; + } else { + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; + } + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; } + mutex_lock(&dev->lock); + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock, flags); + stop_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + + set_tvnorm(dev, &tvnorms[i]); + + spin_lock_irqsave(&dev->slock, flags); + start_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + } else + set_tvnorm(dev, &tvnorms[i]); + saa7134_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} - /* --- tv standards ------------------------------------------ */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - err = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (err < 0) - return err; - return 0; + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + cap->bounds = dev->crop_bounds; + cap->defrect = dev->crop_defrect; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + if (dev->tvnorm->id & V4L2_STD_525_60) { + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + } + if (dev->tvnorm->id & V4L2_STD_625_50) { + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + return 0; +} - *id = dev->tvnorm->id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; - v4l2_std_id fixup; +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int n; - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { - if (secam[0] == 'L' || secam[0] == 'l') { - if (secam[1] == 'C' || secam[1] == 'c') - fixup = V4L2_STD_SECAM_LC; - else - fixup = V4L2_STD_SECAM_L; - } else { - if (secam[0] == 'D' || secam[0] == 'd') - fixup = V4L2_STD_SECAM_DK; - else - fixup = V4L2_STD_SECAM; - } - for (i = 0; i < TVNORMS; i++) - if (fixup == tvnorms[i].id) - break; - } - mutex_lock(&dev->lock); - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock, flags); + if (0 != t->index) + return -EINVAL; + memset(t, 0, sizeof(*t)); + for (n = 0; n < SAA7134_INPUT_MAX; n++) + if (card_in(dev, n).tv) + break; + if (NULL != card_in(dev, n).name) { + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + t->rangehigh = 0xffffffffUL; + t->rxsubchans = saa7134_tvaudio_getstereo(dev); + t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); + } + if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) + t->signal = 0xffff; + return 0; +} - set_tvnorm(dev,&tvnorms[i]); +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int rx, mode; - spin_lock_irqsave(&dev->slock, flags); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } else - set_tvnorm(dev,&tvnorms[i]); - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; + mode = dev->thread.mode; + if (UNSET == mode) { + rx = saa7134_tvaudio_getstereo(dev); + mode = saa7134_tvaudio_rx2mode(t->rxsubchans); } + if (mode != t->audmode) + dev->thread.mode = t->audmode; + return 0; +} - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cap = arg; +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - cap->bounds = dev->crop_bounds; - cap->defrect = dev->crop_defrect; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - if (dev->tvnorm->id & V4L2_STD_525_60) { - cap->pixelaspect.numerator = 11; - cap->pixelaspect.denominator = 10; - } - if (dev->tvnorm->id & V4L2_STD_625_50) { - cap->pixelaspect.numerator = 54; - cap->pixelaspect.denominator = 59; - } - return 0; - } + memset(f, 0, sizeof(*f)); + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + return 0; +} - case VIDIOC_G_CROP: - { - struct v4l2_crop * crop = arg; +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - crop->c = dev->crop_current; - return 0; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *crop = arg; - struct v4l2_rect *b = &dev->crop_bounds; + if (0 != f->tuner) + return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; + mutex_lock(&dev->lock); + dev->ctl_freq = f->frequency; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - if (crop->c.height < 0) - return -EINVAL; - if (crop->c.width < 0) - return -EINVAL; + saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - if (res_locked(fh->dev,RESOURCE_OVERLAY)) - return -EBUSY; - if (res_locked(fh->dev,RESOURCE_VIDEO)) - return -EBUSY; + saa7134_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dev->crop_current = crop->c; - return 0; - } +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "audio"); + return 0; +} - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - int n; +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + return 0; +} - if (0 != t->index) - return -EINVAL; - memset(t,0,sizeof(*t)); - for (n = 0; n < SAA7134_INPUT_MAX; n++) - if (card_in(dev,n).tv) - break; - if (NULL != card_in(dev,n).name) { - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = saa7134_tvaudio_getstereo(dev); - t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) - t->signal = 0xffff; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; - int rx,mode; +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int res = saa7134_resource(fh); - mode = dev->thread.mode; - if (UNSET == mode) { - rx = saa7134_tvaudio_getstereo(dev); - mode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (mode != t->audmode) { - dev->thread.mode = t->audmode; - } - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + if (!res_get(dev, fh, res)) + return -EBUSY; - memset(f,0,sizeof(*f)); - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; + return videobuf_streamon(saa7134_queue(fh)); +} - if (0 != f->tuner) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int err; + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int res = saa7134_resource(fh); - saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); + err = videobuf_streamoff(saa7134_queue(fh)); + if (err < 0) + return err; + res_free(dev, fh, res); + return 0; +} - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; - } +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct saa7134_fh *fh = priv; + return videobuf_reqbufs(saa7134_queue(fh), p); +} - /* --- control ioctls ---------------------------------------- */ - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_QUERYCTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - return saa7134_common_ioctl(dev, cmd, arg); +static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + struct v4l2_rect *b = &dev->crop_bounds; - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + if (crop->c.height < 0) + return -EINVAL; + if (crop->c.width < 0) + return -EINVAL; - memset(a,0,sizeof(*a)); - strcpy(a->name,"audio"); - return 0; - } - case VIDIOC_S_AUDIO: - return 0; - case VIDIOC_G_PARM: - { - struct v4l2_captureparm *parm = arg; - memset(parm,0,sizeof(*parm)); - return 0; - } + if (res_locked(fh->dev, RESOURCE_OVERLAY)) + return -EBUSY; + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.left = b->left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = b->left - crop->c.left + b->width; + + dev->crop_current = crop->c; + return 0; +} - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; +static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; - *p = v4l2_prio_max(&dev->prio); - return 0; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + crop->c = dev->crop_current; + return 0; +} - return v4l2_prio_change(&dev->prio, &fh->prio, *prio); - } +static int vidioc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + memset(parm, 0, sizeof(*parm)); + return 0; +} - /* --- preview ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int index; - - index = f->index; - type = f->type; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - if (index >= FORMATS) - return -EINVAL; - if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && - formats[index].planar) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (0 != index) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description,"vbi data"); - break; - default: - return -EINVAL; - } - return 0; - } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *fb = arg; +static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; - *fb = dev->ovbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - return 0; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *fb = arg; - struct saa7134_format *fmt; + *p = v4l2_prio_max(&dev->prio); + return 0; +} - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; +static int vidioc_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; + return v4l2_prio_change(&dev->prio, &fh->prio, prio); +} - /* ok, accept it */ - dev->ovbuf = *fb; - dev->ovfmt = fmt; - if (0 == dev->ovbuf.fmt.bytesperline) - dev->ovbuf.fmt.bytesperline = - dev->ovbuf.fmt.width*fmt->depth/8; - return 0; - } - case VIDIOC_OVERLAY: - { - int *on = arg; +static int vidioc_g_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; - if (*on) { - if (saa7134_no_overlay > 0) { - printk ("no_overlay\n"); - return -EINVAL; - } + *fb = dev->ovbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - if (!res_get(dev,fh,RESOURCE_OVERLAY)) - return -EBUSY; - spin_lock_irqsave(&dev->slock,flags); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } - if (!*on) { - if (!res_check(fh, RESOURCE_OVERLAY)) - return -EINVAL; - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - res_free(dev,fh,RESOURCE_OVERLAY); - } - return 0; - } + return 0; +} - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return saa7134_g_fmt(dev,fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return saa7134_s_fmt(dev,fh,f); - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return saa7134_try_fmt(dev,fh,f); - } -#ifdef CONFIG_VIDEO_V4L1_COMPAT - case VIDIOCGMBUF: - return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); -#endif - case VIDIOC_REQBUFS: - return videobuf_reqbufs(saa7134_queue(fh),arg); +static int vidioc_s_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + struct saa7134_format *fmt; + + if (!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; - case VIDIOC_QUERYBUF: - return videobuf_querybuf(saa7134_queue(fh),arg); + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; - case VIDIOC_QBUF: - return videobuf_qbuf(saa7134_queue(fh),arg); + /* ok, accept it */ + dev->ovbuf = *fb; + dev->ovfmt = fmt; + if (0 == dev->ovbuf.fmt.bytesperline) + dev->ovbuf.fmt.bytesperline = + dev->ovbuf.fmt.width*fmt->depth/8; + return 0; +} - case VIDIOC_DQBUF: - return videobuf_dqbuf(saa7134_queue(fh),arg, - file->f_flags & O_NONBLOCK); +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_querybuf(saa7134_queue(fh), b); +} - case VIDIOC_STREAMON: - { - int res = saa7134_resource(fh); +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_qbuf(saa7134_queue(fh), b); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_dqbuf(saa7134_queue(fh), b, + file->f_flags & O_NONBLOCK); +} + +static int vidioc_overlay(struct file *file, void *f, unsigned int on) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + unsigned long flags; - if (!res_get(dev,fh,res)) + if (on) { + if (saa7134_no_overlay > 0) { + dprintk("no_overlay\n"); + return -EINVAL; + } + + if (!res_get(dev, fh, RESOURCE_OVERLAY)) return -EBUSY; - return videobuf_streamon(saa7134_queue(fh)); + spin_lock_irqsave(&dev->slock, flags); + start_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); } - case VIDIOC_STREAMOFF: - { - int res = saa7134_resource(fh); - - err = videobuf_streamoff(saa7134_queue(fh)); - if (err < 0) - return err; - res_free(dev,fh,res); - return 0; + if (!on) { + if (!res_check(fh, RESOURCE_OVERLAY)) + return -EINVAL; + spin_lock_irqsave(&dev->slock, flags); + stop_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + res_free(dev, fh, RESOURCE_OVERLAY); } + return 0; +} + +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + enum v4l2_buf_type type; + unsigned int index; + index = f->index; + type = f->type; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) + return -EINVAL; + + if (index >= FORMATS) + return -EINVAL; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && + formats[index].planar) + return -EINVAL; + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + strlcpy(f->description, formats[index].name, + sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (0 != index) + return -EINVAL; + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); + break; default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - video_do_ioctl); + return -EINVAL; } return 0; } -static int video_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) { - return video_usercopy(inode, file, cmd, arg, video_do_ioctl); + struct saa7134_fh *fh = file->private_data; + return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); } +#endif -static int radio_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; + memset(cap, 0, sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} - if (0 != t->index) - return -EINVAL; +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; - memset(t,0,sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; + if (0 != t->index) + return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - if (dev->input->amux == TV) { - t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); - t->rxsubchans = (saa_readb(0x529) & 0x08) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } - return 0; + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + if (dev->input->amux == TV) { + t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); + t->rxsubchans = (saa_readb(0x529) & 0x08) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; + return 0; +} +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; - if (0 != t->index) - return -EINVAL; + if (0 != t->index) + return -EINVAL; + + saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + return 0; +} - saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t); +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; - return 0; - } - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; - if (i->index != 0) - return -EINVAL; - strcpy(i->name,"Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = 0; - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + return 0; +} - memset(a,0,sizeof(*a)); - strcpy(a->name,"Radio"); - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - *id = 0; - return 0; - } - case VIDIOC_S_AUDIO: - case VIDIOC_S_INPUT: - case VIDIOC_S_STD: - return 0; +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} - case VIDIOC_QUERYCTRL: - { - const struct v4l2_queryctrl *ctrl; - struct v4l2_queryctrl *c = arg; +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctrl; - return 0; - } +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return 0; +} - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - return video_do_ioctl(inode,file,cmd,arg); +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + return 0; +} - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - radio_do_ioctl); - } +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ return 0; } -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) { - return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctrl; + return 0; } static const struct file_operations video_fops = @@ -2341,7 +2299,7 @@ static const struct file_operations video_fops = .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2351,7 +2309,7 @@ static const struct file_operations radio_fops = .owner = THIS_MODULE, .open = video_open, .release = video_release, - .ioctl = radio_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2361,11 +2319,47 @@ static const struct file_operations radio_fops = struct video_device saa7134_video_template = { - .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| - VID_TYPE_CLIPPING|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, + .name = "saa7134-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | + VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_crop = vidioc_g_crop, + .vidioc_s_crop = vidioc_s_crop, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + .vidioc_overlay = vidioc_overlay, + .vidioc_g_priority = vidioc_g_priority, + .vidioc_s_priority = vidioc_s_priority, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, }; struct video_device saa7134_vbi_template = @@ -2382,6 +2376,20 @@ struct video_device saa7134_radio_template = .type = VID_TYPE_TUNER, .fops = &radio_fops, .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, }; int saa7134_video_init1(struct saa7134_dev *dev) -- cgit v1.2.3 From 90bdc14533fa37b86ada57fcf60c634106ddbb3f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 7 Dec 2007 17:23:38 -0300 Subject: V4L/DVB (6735): Reorder functions to make easier to compare with the previous code After this patch, the order of the functions will be the same as before the patch converting the driver to user video_ioctl2. This makes easier to diff between the previous version and the newer one. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 348 ++++++++++++++-------------- 1 file changed, 174 insertions(+), 174 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 954542e5c99..76b841dd7ec 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1670,30 +1670,6 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, } } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - *i = dev->ctl_input; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - if (i < 0 || i >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i).name) - return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev, i); - mutex_unlock(&dev->lock); - return 0; -} - static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { @@ -1744,6 +1720,30 @@ static int vidioc_enum_input(struct file *file, void *priv, return 0; } +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + *i = dev->ctl_input; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + if (i < 0 || i >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i).name) + return -EINVAL; + mutex_lock(&dev->lock); + video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1847,6 +1847,55 @@ static int vidioc_cropcap(struct file *file, void *priv, return 0; } +static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + crop->c = dev->crop_current; + return 0; +} + +static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + struct v4l2_rect *b = &dev->crop_bounds; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + if (crop->c.height < 0) + return -EINVAL; + if (crop->c.width < 0) + return -EINVAL; + + if (res_locked(fh->dev, RESOURCE_OVERLAY)) + return -EBUSY; + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.left = b->left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = b->left - crop->c.left + b->width; + + dev->crop_current = crop->c; + return 0; +} + static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { @@ -1939,113 +1988,64 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) return 0; } -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int res = saa7134_resource(fh); - - if (!res_get(dev, fh, res)) - return -EBUSY; - - return videobuf_streamon(saa7134_queue(fh)); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - int err; - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int res = saa7134_resource(fh); - - err = videobuf_streamoff(saa7134_queue(fh)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct saa7134_fh *fh = priv; - return videobuf_reqbufs(saa7134_queue(fh), p); -} - -static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; - struct v4l2_rect *b = &dev->crop_bounds; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - if (crop->c.height < 0) - return -EINVAL; - if (crop->c.width < 0) - return -EINVAL; - - if (res_locked(fh->dev, RESOURCE_OVERLAY)) - return -EBUSY; - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dev->crop_current = crop->c; + *p = v4l2_prio_max(&dev->prio); return 0; } -static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int vidioc_s_priority(struct file *file, void *f, + enum v4l2_priority prio) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - crop->c = dev->crop_current; - return 0; -} - -static int vidioc_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - memset(parm, 0, sizeof(*parm)); - return 0; + return v4l2_prio_change(&dev->prio, &fh->prio, prio); } -static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; + enum v4l2_buf_type type; + unsigned int index; - *p = v4l2_prio_max(&dev->prio); - return 0; -} + index = f->index; + type = f->type; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) + return -EINVAL; -static int vidioc_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; + if (index >= FORMATS) + return -EINVAL; - return v4l2_prio_change(&dev->prio, &fh->prio, prio); + if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && + formats[index].planar) + return -EINVAL; + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + strlcpy(f->description, formats[index].name, + sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (0 != index) + return -EINVAL; + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = type; + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); + break; + default: + return -EINVAL; + } + return 0; } static int vidioc_g_fbuf(struct file *file, void *f, @@ -2085,26 +2085,6 @@ static int vidioc_s_fbuf(struct file *file, void *f, return 0; } -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_querybuf(saa7134_queue(fh), b); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_qbuf(saa7134_queue(fh), b); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_dqbuf(saa7134_queue(fh), b, - file->f_flags & O_NONBLOCK); -} - static int vidioc_overlay(struct file *file, void *f, unsigned int on) { struct saa7134_fh *fh = f; @@ -2134,55 +2114,75 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on) return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) { - enum v4l2_buf_type type; - unsigned int index; + struct saa7134_fh *fh = file->private_data; + return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); +} +#endif - index = f->index; - type = f->type; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) - return -EINVAL; +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct saa7134_fh *fh = priv; + return videobuf_reqbufs(saa7134_queue(fh), p); +} - if (index >= FORMATS) - return -EINVAL; +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_querybuf(saa7134_queue(fh), b); +} - if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && - formats[index].planar) - return -EINVAL; - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description, formats[index].name, - sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (0 != index) - return -EINVAL; - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description, "vbi data"); - break; - default: - return -EINVAL; - } +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_qbuf(saa7134_queue(fh), b); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_dqbuf(saa7134_queue(fh), b, + file->f_flags & O_NONBLOCK); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int res = saa7134_resource(fh); + + if (!res_get(dev, fh, res)) + return -EBUSY; + + return videobuf_streamon(saa7134_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int err; + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int res = saa7134_resource(fh); + + err = videobuf_streamoff(saa7134_queue(fh)); + if (err < 0) + return err; + res_free(dev, fh, res); return 0; } -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +static int vidioc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) { - struct saa7134_fh *fh = file->private_data; - return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); + memset(parm, 0, sizeof(*parm)); + return 0; } -#endif static int radio_querycap(struct file *file, void *priv, struct v4l2_capability *cap) -- cgit v1.2.3 From 8c85454a5963747fca7d0699e2450f676314c176 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 7 Dec 2007 17:34:48 -0300 Subject: V4L/DVB (6736): Fix some errors at the video_ioctl2 conversion Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 1 + drivers/media/video/saa7134/saa7134-video.c | 388 ++++++++++++++++------------ drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 218 insertions(+), 172 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index cbddd35f161..92c48ee1591 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -834,6 +834,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, vfd->minor = -1; vfd->dev = &dev->pci->dev; vfd->release = video_device_release; + vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, saa7134_boards[dev->board].name); return vfd; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 76b841dd7ec..043e1396857 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -38,7 +38,7 @@ /* ------------------------------------------------------------------ */ -static unsigned int video_debug = 0; +unsigned int video_debug; static unsigned int gbuffers = 8; static unsigned int noninterlaced = 0; static unsigned int gbufsize = 720*576*4; @@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644); MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); -#define dprintk(fmt, arg...) if (video_debug) \ +#define dprintk(fmt, arg...) if (video_debug&0x04) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ @@ -217,6 +217,12 @@ static struct saa7134_format formats[] = { .vbi_v_start_1 = 273, \ .src_timing = 7 +#define SAA7134_NORMS \ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60 + static struct saa7134_tvnorm tvnorms[] = { { .name = "PAL", /* autodetect */ @@ -542,7 +548,6 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; @@ -561,7 +566,6 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_current = dev->crop_defrect; saa7134_set_tvnorm_hw(dev); - } static void video_mux(struct saa7134_dev *dev, int input) @@ -1177,11 +1181,18 @@ static int vidioc_s_ctrl(struct file *file, void *f, struct saa7134_dev *dev = fh->dev; unsigned long flags; int restart_overlay = 0; + int err = -EINVAL; + + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; mutex_lock(&dev->lock); + ctrl = ctrl_by_id(c->id); if (NULL == ctrl) - return -EINVAL; + goto error; + dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: @@ -1261,8 +1272,7 @@ static int vidioc_s_ctrl(struct file *file, void *f, break; } default: - mutex_unlock(&dev->lock); - return -EINVAL; + goto error; } if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); @@ -1270,8 +1280,11 @@ static int vidioc_s_ctrl(struct file *file, void *f, start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } + err = 0; + +error: mutex_unlock(&dev->lock); - return 0; + return err; } /* ------------------------------------------------------------------ */ @@ -1494,8 +1507,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) +static int vidioc_try_get_set_fmt_vbi(struct file *file, void *priv, + struct v4l2_format *f) { + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; struct saa7134_tvnorm *norm = dev->tvnorm; f->fmt.vbi.sampling_rate = 6750000 * 4; @@ -1508,39 +1524,37 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ + return 0; } static int vidioc_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - f->fmt.win = fh->win; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - saa7134_vbi_fmt(dev,f); - return 0; - default: + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + +static int vidioc_g_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } + f->fmt.win = fh->win; + + return 0; } static int vidioc_try_fmt_cap(struct file *file, void *priv, @@ -1548,126 +1562,122 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - int err; + struct saa7134_format *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - struct saa7134_format *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; + field = f->fmt.pix.field; + maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); + maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); - field = f->fmt.pix.field; - maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); - maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } + f->fmt.pix.field = field; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.field = field; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} - return 0; - } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - err = verify_preview(dev,&f->fmt.win); - if (0 != err) - return err; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - saa7134_vbi_fmt(dev,f); - return 0; - default: +static int vidioc_try_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } + + return verify_preview(dev, &f->fmt.win); } static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + int err; + + err = vidioc_try_fmt_cap(file, priv, f); + if (0 != err) + return err; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->cap.field = f->fmt.pix.field; + return 0; +} + +static int vidioc_s_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - unsigned long flags; int err; + unsigned int flags; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - err = vidioc_try_fmt_cap(file, priv, f); - if (0 != err) - return err; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->cap.field = f->fmt.pix.field; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - err = verify_preview(dev,&f->fmt.win); - if (0 != err) - return err; - - mutex_lock(&dev->lock); - fh->win = f->fmt.win; - fh->nclips = f->fmt.win.clipcount; - if (fh->nclips > 8) - fh->nclips = 8; - if (copy_from_user(fh->clips,f->fmt.win.clips, - sizeof(struct v4l2_clip)*fh->nclips)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + err = verify_preview(dev, &f->fmt.win); + if (0 != err) + return err; - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } + mutex_lock(&dev->lock); + + fh->win = f->fmt.win; + fh->nclips = f->fmt.win.clipcount; + + if (fh->nclips > 8) + fh->nclips = 8; + + if (copy_from_user(fh->clips, f->fmt.win.clips, + sizeof(struct v4l2_clip)*fh->nclips)) { mutex_unlock(&dev->lock); - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - saa7134_vbi_fmt(dev,f); - return 0; - default: - return -EINVAL; + return -EFAULT; } + + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock, flags); + stop_preview(dev, fh); + start_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + } + + mutex_unlock(&dev->lock); + return 0; } static int vidioc_queryctrl(struct file *file, void *priv, @@ -1715,8 +1725,7 @@ static int vidioc_enum_input(struct file *file, void *priv, if (0 != (v2 & 0x0e)) i->status |= V4L2_IN_ST_MACROVISION; } - for (n = 0; n < TVNORMS; n++) - i->std |= tvnorms[n].id; + i->std = SAA7134_NORMS; return 0; } @@ -1733,6 +1742,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; + int err; + + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; if (i < 0 || i >= SAA7134_INPUT_MAX) return -EINVAL; @@ -1752,7 +1766,6 @@ static int vidioc_querycap(struct file *file, void *priv, unsigned int tuner_type = dev->tuner_type; - memset(cap, 0, sizeof(*cap)); strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); @@ -1779,16 +1792,23 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * id) unsigned long flags; unsigned int i; v4l2_std_id fixup; + int err; + + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; for (i = 0; i < TVNORMS; i++) if (*id == tvnorms[i].id) break; + if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) if (*id & tvnorms[i].id) break; if (i == TVNORMS) return -EINVAL; + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { if (secam[0] == 'L' || secam[0] == 'l') { if (secam[1] == 'C' || secam[1] == 'c') @@ -1805,6 +1825,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * id) if (fixup == tvnorms[i].id) break; } + + *id = tvnorms[i].id; + mutex_lock(&dev->lock); if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock, flags); @@ -1818,6 +1841,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * id) spin_unlock_irqrestore(&dev->slock, flags); } else set_tvnorm(dev, &tvnorms[i]); + saa7134_tvaudio_do_scan(dev); mutex_unlock(&dev->lock); return 0; @@ -1930,7 +1954,11 @@ static int vidioc_s_tuner(struct file *file, void *priv, { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - int rx, mode; + int rx, mode, err; + + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; mode = dev->thread.mode; if (UNSET == mode) { @@ -1939,6 +1967,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } if (mode != t->audmode) dev->thread.mode = t->audmode; + return 0; } @@ -1948,9 +1977,9 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - memset(f, 0, sizeof(*f)); f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; + return 0; } @@ -1959,6 +1988,11 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; + int err; + + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; if (0 != f->tuner) return -EINVAL; @@ -1978,7 +2012,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - memset(a, 0, sizeof(*a)); strcpy(a->name, "audio"); return 0; } @@ -2009,42 +2042,45 @@ static int vidioc_s_priority(struct file *file, void *f, static int vidioc_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - enum v4l2_buf_type type; - unsigned int index; + if (f->index >= FORMATS) + return -EINVAL; - index = f->index; - type = f->type; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) - return -EINVAL; + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); - if (index >= FORMATS) - return -EINVAL; + f->pixelformat = formats[f->index].fourcc; - if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && - formats[index].planar) - return -EINVAL; - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description, formats[index].name, - sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (0 != index) - return -EINVAL; - memset(f, 0, sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description, "vbi data"); - break; - default: + return 0; +} + +static int vidioc_enum_fmt_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } + + if ((f->index >= FORMATS) || formats[f->index].planar) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int vidioc_enum_fmt_vbi(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (0 != f->index) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); + return 0; } @@ -2180,7 +2216,6 @@ static int vidioc_streamoff(struct file *file, void *priv, static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm) { - memset(parm, 0, sizeof(*parm)); return 0; } @@ -2190,7 +2225,6 @@ static int radio_querycap(struct file *file, void *priv, struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; - memset(cap, 0, sizeof(*cap)); strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); @@ -2329,6 +2363,14 @@ struct video_device saa7134_video_template = .vidioc_g_fmt_cap = vidioc_g_fmt_cap, .vidioc_try_fmt_cap = vidioc_try_fmt_cap, .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_overlay = vidioc_enum_fmt_overlay, + .vidioc_g_fmt_overlay = vidioc_g_fmt_overlay, + .vidioc_try_fmt_overlay = vidioc_try_fmt_overlay, + .vidioc_s_fmt_overlay = vidioc_s_fmt_overlay, + .vidioc_enum_fmt_vbi = vidioc_enum_fmt_vbi, + .vidioc_g_fmt_vbi = vidioc_try_get_set_fmt_vbi, + .vidioc_try_fmt_vbi = vidioc_try_get_set_fmt_vbi, + .vidioc_s_fmt_vbi = vidioc_try_get_set_fmt_vbi, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, @@ -2360,6 +2402,8 @@ struct video_device saa7134_video_template = .vidioc_g_parm = vidioc_g_parm, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .tvnorms = SAA7134_NORMS, + .current_norm = V4L2_STD_PAL, }; struct video_device saa7134_vbi_template = diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 5c5b0741307..8fb95094ba8 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -625,6 +625,7 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, /* ----------------------------------------------------------- */ /* saa7134-video.c */ +extern unsigned int video_debug; extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -- cgit v1.2.3 From 842441d42de8f22d8f530b19da984df81fed8f7e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Nov 2007 07:35:41 -0300 Subject: V4L/DVB (6737): wm8775: codingstyle cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/wm8775.c | 66 +++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index c31a0c34b08..869f9e7946b 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -68,17 +68,15 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) return -1; } - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, (reg << 1) | - (val >> 8), val & 0xff) == 0) { + for (i = 0; i < 3; i++) + if (i2c_smbus_write_byte_data(client, + (reg << 1) | (val >> 8), val & 0xff) == 0) return 0; - } - } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } -static int wm8775_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) { struct wm8775_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -127,7 +125,8 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, void *arg break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0); + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_WM8775, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Input: %d%s\n", state->input, @@ -168,34 +167,45 @@ static int wm8775_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } state->input = 2; state->muted = 0; i2c_set_clientdata(client, state); - /* initialize wm8775 */ - wm8775_write(client, R23, 0x000); /* RESET */ - wm8775_write(client, R7, 0x000); /* Disable zero cross detect timeout */ - wm8775_write(client, R11, 0x021); /* Left justified, 24-bit mode */ - wm8775_write(client, R12, 0x102); /* Master mode, clock ratio 256fs */ - wm8775_write(client, R13, 0x000); /* Powered up */ - wm8775_write(client, R14, 0x1d4); /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(client, R15, 0x1d4); /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(client, R16, 0x1bf); /* ALC Stereo, ALC target level -1dB FS */ - /* max gain +8dB */ - wm8775_write(client, R17, 0x185); /* Enable gain control, use zero cross */ - /* detection, ALC hold time 42.6 ms */ - wm8775_write(client, R18, 0x0a2); /* ALC gain ramp up delay 34 s, */ - /* ALC gain ramp down delay 33 ms */ - wm8775_write(client, R19, 0x005); /* Enable noise gate, threshold -72dBfs */ - wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */ - /* limit -1dB */ - wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */ + /* Initialize wm8775 */ + + /* RESET */ + wm8775_write(client, R23, 0x000); + /* Disable zero cross detect timeout */ + wm8775_write(client, R7, 0x000); + /* Left justified, 24-bit mode */ + wm8775_write(client, R11, 0x021); + /* Master mode, clock ratio 256fs */ + wm8775_write(client, R12, 0x102); + /* Powered up */ + wm8775_write(client, R13, 0x000); + /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(client, R14, 0x1d4); + /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(client, R15, 0x1d4); + /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ + wm8775_write(client, R16, 0x1bf); + /* Enable gain control, use zero cross detection, + ALC hold time 42.6 ms */ + wm8775_write(client, R17, 0x185); + /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ + wm8775_write(client, R18, 0x0a2); + /* Enable noise gate, threshold -72dBfs */ + wm8775_write(client, R19, 0x005); + /* Transient window 4ms, lower PGA gain limit -1dB */ + wm8775_write(client, R20, 0x07a); + /* LRBOTH = 1, use input 2. */ + wm8775_write(client, R21, 0x102); return 0; } -- cgit v1.2.3 From 099b8e7361512ebfef2dd51f2e81126cc93c22e9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Nov 2007 07:45:54 -0300 Subject: V4L/DVB (6738): wm8739: codingstyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/wm8739.c | 65 ++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 3d9e709833c..ac4fee1d025 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -36,7 +36,7 @@ MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END }; module_param(debug, int, 0644); @@ -76,12 +76,10 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val) v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val); - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, (reg << 1) | - (val >> 8), val & 0xff) == 0) { + for (i = 0; i < 3; i++) + if (i2c_smbus_write_byte_data(client, + (reg << 1) | (val >> 8), val & 0xff) == 0) return 0; - } - } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } @@ -168,7 +166,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { .default_value = 58880, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, - },{ + }, { .id = V4L2_CID_AUDIO_MUTE, .name = "Mute", .minimum = 0, @@ -177,7 +175,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { .default_value = 1, .flags = 0, .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ + }, { .id = V4L2_CID_AUDIO_BALANCE, .name = "Balance", .minimum = 0, @@ -191,7 +189,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { /* ------------------------------------------------------------------------ */ -static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) { struct wm8739_state *state = i2c_get_clientdata(client); @@ -201,21 +199,26 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg u32 audiofreq = *(u32 *)arg; state->clock_freq = audiofreq; - wm8739_write(client, R9, 0x000); /* de-activate */ + /* de-activate */ + wm8739_write(client, R9, 0x000); switch (audiofreq) { case 44100: - wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k */ + /* 256fps, fs=44.1k */ + wm8739_write(client, R8, 0x020); break; case 48000: - wm8739_write(client, R8, 0x000); /* 256fps, fs=48k */ + /* 256fps, fs=48k */ + wm8739_write(client, R8, 0x000); break; case 32000: - wm8739_write(client, R8, 0x018); /* 256fps, fs=32k */ + /* 256fps, fs=32k */ + wm8739_write(client, R8, 0x018); break; default: break; } - wm8739_write(client, R9, 0x001); /* activate */ + /* activate */ + wm8739_write(client, R9, 0x001); break; } @@ -239,7 +242,8 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0); + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_WM8739, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); @@ -268,7 +272,8 @@ static int wm8739_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); if (state == NULL) { @@ -284,17 +289,23 @@ static int wm8739_probe(struct i2c_client *client) state->clock_freq = 48000; i2c_set_clientdata(client, state); - /* initialize wm8739 */ - wm8739_write(client, R15, 0x00); /* reset */ - wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */ - wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */ - wm8739_write(client, R7, 0x049); /* Digital Audio interface format */ - /* Enable Master mode */ - /* 24 bit, MSB first/left justified */ - wm8739_write(client, R8, 0x000); /* sampling control */ - /* normal, 256fs, 48KHz sampling rate */ - wm8739_write(client, R9, 0x001); /* activate */ - wm8739_set_audio(client); /* set volume/mute */ + /* Initialize wm8739 */ + + /* reset */ + wm8739_write(client, R15, 0x00); + /* filter setting, high path, offet clear */ + wm8739_write(client, R5, 0x000); + /* ADC, OSC, Power Off mode Disable */ + wm8739_write(client, R6, 0x000); + /* Digital Audio interface format: + Enable Master mode, 24 bit, MSB first/left justified */ + wm8739_write(client, R7, 0x049); + /* sampling control: normal, 256fs, 48KHz sampling rate */ + wm8739_write(client, R8, 0x000); + /* activate */ + wm8739_write(client, R9, 0x001); + /* set volume/mute */ + wm8739_set_audio(client); return 0; } -- cgit v1.2.3 From 4c05de9c971b70a61d81cd2f1c78db85e2632d1c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Nov 2007 07:54:57 -0300 Subject: V4L/DVB (6739): cs53l32a: codingstyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs53l32a.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index 65bb6afd8df..f41bfde045f 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -35,7 +35,7 @@ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, bool, 0644); @@ -58,7 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) { struct v4l2_routing *route = arg; struct v4l2_control *ctrl = arg; @@ -105,7 +105,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, void *a break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0); + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_CS53l32A, 0); case VIDIOC_LOG_STATUS: { @@ -144,7 +145,8 @@ static int cs53l32a_probe(struct i2c_client *client) snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); -- cgit v1.2.3 From 574dec611f1578b52dd37df5c95f855a28652e42 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Nov 2007 07:58:17 -0300 Subject: V4L/DVB (6740): tlv320aic23b: codingstyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tlv320aic23b.c | 63 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index e906528348a..dc7b9c220b9 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -57,37 +57,35 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val) return -1; } - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, (reg << 1) | - (val >> 8), val & 0xff) == 0) { + for (i = 0; i < 3; i++) + if (i2c_smbus_write_byte_data(client, + (reg << 1) | (val >> 8), val & 0xff) == 0) return 0; - } - } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } -static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int tlv320aic23b_command(struct i2c_client *client, + unsigned int cmd, void *arg) { struct tlv320aic23b_state *state = i2c_get_clientdata(client); struct v4l2_control *ctrl = arg; - u32* freq = arg; + u32 *freq = arg; switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: switch (*freq) { - case 32000: /* set sample rate to 32 kHz */ - tlv320aic23b_write(client, 8, 0x018); - break; - case 44100: /* set sample rate to 44.1 kHz */ - tlv320aic23b_write(client, 8, 0x022); - break; - case 48000: /* set sample rate to 48 kHz */ - tlv320aic23b_write(client, 8, 0x000); - break; - default: - return -EINVAL; + case 32000: /* set sample rate to 32 kHz */ + tlv320aic23b_write(client, 8, 0x018); + break; + case 44100: /* set sample rate to 44.1 kHz */ + tlv320aic23b_write(client, 8, 0x022); + break; + case 48000: /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 8, 0x000); + break; + default: + return -EINVAL; } break; @@ -135,22 +133,29 @@ static int tlv320aic23b_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } state->muted = 0; i2c_set_clientdata(client, state); - /* initialize tlv320aic23b */ - tlv320aic23b_write(client, 15, 0x000); /* RESET */ - tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */ - tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */ - tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ - tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ - tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ + /* Initialize tlv320aic23b */ + + /* RESET */ + tlv320aic23b_write(client, 15, 0x000); + /* turn off DAC & mic input */ + tlv320aic23b_write(client, 6, 0x00A); + /* left-justified, 24-bit, master mode */ + tlv320aic23b_write(client, 7, 0x049); + /* set gain on both channels to +3.0 dB */ + tlv320aic23b_write(client, 0, 0x119); + /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 8, 0x000); + /* activate digital interface */ + tlv320aic23b_write(client, 9, 0x001); return 0; } -- cgit v1.2.3 From 737bd410e70c3daa02f203dec24351951e89d82f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Nov 2007 13:38:12 -0300 Subject: V4L/DVB (6741): cx2341x: codingstyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 313 +++++++++++++++++++++++------------------- 1 file changed, 174 insertions(+), 139 deletions(-) diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 62304255dca..890c8867af1 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); @@ -75,6 +75,7 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, 0 }; +EXPORT_SYMBOL(cx2341x_mpeg_ctrls); /* Map the control ID to the correct field in the cx2341x_mpeg_params @@ -281,13 +282,14 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = - (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || - params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { + (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : + V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) /* MPEG-1 implies CBR */ - params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; - } + params->video_bitrate_mode = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; break; case V4L2_CID_MPEG_STREAM_VBI_FMT: params->stream_vbi_fmt = ctrl->value; @@ -334,7 +336,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return 0; } -static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) +static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, + s32 min, s32 max, s32 step, s32 def) { const char *name; @@ -417,7 +420,8 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma return 0; } -int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl) +int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, + struct v4l2_queryctrl *qctrl) { int err; @@ -440,7 +444,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + if (err == 0 && + params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; @@ -455,13 +460,16 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + if (err == 0 && + params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + if (err == 0 && + params->video_bitrate_mode == + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; @@ -476,80 +484,90 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl /* CX23415/6 specific */ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); - if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, + 1, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); - if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + 1, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_temporal_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: @@ -560,6 +578,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl } } +EXPORT_SYMBOL(cx2341x_ctrl_query); const char **cx2341x_ctrl_get_menu(u32 id) { @@ -629,6 +648,7 @@ const char **cx2341x_ctrl_get_menu(u32 id) return v4l2_ctrl_get_menu(id); } } +EXPORT_SYMBOL(cx2341x_ctrl_get_menu); static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) { @@ -637,9 +657,8 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) ((1 + params->audio_l2_bitrate) << 4) | (params->audio_mode << 8) | (params->audio_mode_extension << 10) | - (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ? - 3 : - params->audio_emphasis) << 12) | + (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) + ? 3 : params->audio_emphasis) << 12) | (params->audio_crc << 14); } @@ -679,19 +698,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, if (err) break; } - if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - params->video_bitrate_peak < params->video_bitrate) { + if (err == 0 && + params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + params->video_bitrate_peak < params->video_bitrate) { err = -ERANGE; ctrls->error_idx = ctrls->count; } - if (err) { + if (err) ctrls->error_idx = i; - } - else { + else cx2341x_calc_audio_properties(params); - } return err; } +EXPORT_SYMBOL(cx2341x_ext_ctrls); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) { @@ -732,13 +751,18 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) .video_mute_yuv = 0x008080, /* YCbCr value for black */ /* encoding filters */ - .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + .video_spatial_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, .video_spatial_filter = 0, - .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + .video_luma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_chroma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_temporal_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, .video_temporal_filter = 8, - .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + .video_median_filter_type = + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, .video_luma_median_filter_top = 255, .video_luma_median_filter_bottom = 0, .video_chroma_median_filter_top = 255, @@ -748,8 +772,10 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) *p = default_params; cx2341x_calc_audio_properties(p); } +EXPORT_SYMBOL(cx2341x_fill_defaults); -static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...) +static int cx2341x_api(void *priv, cx2341x_mbox_func func, + int cmd, int args, ...) { u32 data[CX2341X_MBOX_MAX_DATA]; va_list vargs; @@ -757,15 +783,17 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, .. va_start(vargs, args); - for (i = 0; i < args; i++) { + for (i = 0; i < args; i++) data[i] = va_arg(vargs, int); - } va_end(vargs); return func(priv, cmd, args, 0, data); } +#define NEQ(field) (old->field != new->field) + int cx2341x_update(void *priv, cx2341x_mbox_func func, - const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new) + const struct cx2341x_mpeg_params *old, + const struct cx2341x_mpeg_params *new) { static int mpeg_stream_type[] = { 0, /* MPEG-2 PS */ @@ -777,17 +805,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, }; int err = 0; + int force = (old == NULL); u16 temporal = new->video_temporal_filter; cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); - if (old == NULL || old->is_50hz != new->is_50hz) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz); + if (force || NEQ(is_50hz)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, + new->is_50hz); if (err) return err; } - if (old == NULL || old->width != new->width || old->height != new->height || - old->video_encoding != new->video_encoding) { + if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { u16 w = new->width; u16 h = new->height; @@ -795,69 +824,74 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, w /= 2; h /= 2; } - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, + h, w); if (err) return err; } if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) { - /* Adjust temporal filter if necessary. The problem with the temporal - filter is that it works well with full resolution capturing, but - not when the capture window is scaled (the filter introduces - a ghosting effect). So if the capture window is scaled, then - force the filter to 0. + /* Adjust temporal filter if necessary. The problem with the + temporal filter is that it works well with full resolution + capturing, but not when the capture window is scaled (the + filter introduces a ghosting effect). So if the capture + window is scaled, then force the filter to 0. For full resolution the filter really improves the video - quality, especially if the original video quality is suboptimal. */ + quality, especially if the original video quality is + suboptimal. */ temporal = 0; } - if (old == NULL || old->stream_type != new->stream_type) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]); + if (force || NEQ(stream_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, + mpeg_stream_type[new->stream_type]); if (err) return err; } - if (old == NULL || old->video_aspect != new->video_aspect) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect); + if (force || NEQ(video_aspect)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, + 1 + new->video_aspect); if (err) return err; } - if (old == NULL || old->video_b_frames != new->video_b_frames || - old->video_gop_size != new->video_gop_size) { + if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, new->video_gop_size, new->video_b_frames + 1); if (err) return err; } - if (old == NULL || old->video_gop_closure != new->video_gop_closure) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure); + if (force || NEQ(video_gop_closure)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, + new->video_gop_closure); if (err) return err; } - if (old == NULL || old->audio_properties != new->audio_properties) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); + if (force || NEQ(audio_properties)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, + 1, new->audio_properties); if (err) return err; } - if (old == NULL || old->audio_mute != new->audio_mute) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); + if (force || NEQ(audio_mute)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, + new->audio_mute); if (err) return err; } - if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || - old->video_bitrate != new->video_bitrate || - old->video_bitrate_peak != new->video_bitrate_peak) { + if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || + NEQ(video_bitrate_peak)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, new->video_bitrate_mode, new->video_bitrate, new->video_bitrate_peak / 400, 0, 0); if (err) return err; } - if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode || - old->video_temporal_filter_mode != new->video_temporal_filter_mode || - old->video_median_filter_type != new->video_median_filter_type) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, - new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1), + if (force || NEQ(video_spatial_filter_mode) || + NEQ(video_temporal_filter_mode) || + NEQ(video_median_filter_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, + 2, new->video_spatial_filter_mode | + (new->video_temporal_filter_mode << 1), new->video_median_filter_type); if (err) return err; } - if (old == NULL || - old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom || - old->video_luma_median_filter_top != new->video_luma_median_filter_top || - old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom || - old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) { + if (force || NEQ(video_luma_median_filter_bottom) || + NEQ(video_luma_median_filter_top) || + NEQ(video_chroma_median_filter_bottom) || + NEQ(video_chroma_median_filter_top)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, new->video_luma_median_filter_bottom, new->video_luma_median_filter_top, @@ -865,36 +899,39 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, new->video_chroma_median_filter_top); if (err) return err; } - if (old == NULL || - old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type || - old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, - new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type); + if (force || NEQ(video_luma_spatial_filter_type) || + NEQ(video_chroma_spatial_filter_type)) { + err = cx2341x_api(priv, func, + CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, + 2, new->video_luma_spatial_filter_type, + new->video_chroma_spatial_filter_type); if (err) return err; } - if (old == NULL || - old->video_spatial_filter != new->video_spatial_filter || - old->video_temporal_filter != temporal) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, - new->video_spatial_filter, temporal); + if (force || NEQ(video_spatial_filter) || + old->video_temporal_filter != temporal) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, + 2, new->video_spatial_filter, temporal); if (err) return err; } - if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1, - new->video_temporal_decimation); + if (force || NEQ(video_temporal_decimation)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, + 1, new->video_temporal_decimation); if (err) return err; } - if (old == NULL || old->video_mute != new->video_mute || - (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8)); + if (force || NEQ(video_mute) || + (new->video_mute && NEQ(video_mute_yuv))) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, + new->video_mute | (new->video_mute_yuv << 8)); if (err) return err; } - if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) { - err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets); + if (force || NEQ(stream_insert_nav_packets)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, + 7, new->stream_insert_nav_packets); if (err) return err; } return 0; } +EXPORT_SYMBOL(cx2341x_update); static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id) { @@ -943,18 +980,17 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), p->video_bitrate); - if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { + if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) printk(", Peak %d", p->video_bitrate_peak); - } printk("\n"); - printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", + printk(KERN_INFO + "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", prefix, p->video_gop_size, p->video_b_frames, p->video_gop_closure ? "" : "No "); - if (p->video_temporal_decimation) { + if (p->video_temporal_decimation) printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", prefix, p->video_temporal_decimation); - } /* Audio */ printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", @@ -964,10 +1000,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), p->audio_mute ? " (muted)" : ""); - if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { - printk(", %s", - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); - } + if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + printk(", %s", cx2341x_menu_item(p, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); printk(", %s, %s\n", cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); @@ -975,33 +1010,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) /* Encoding filters */ printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), p->video_spatial_filter); - if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) { + + if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) temporal = 0; - } + printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), temporal); - printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", + printk(KERN_INFO + "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), p->video_luma_median_filter_bottom, p->video_luma_median_filter_top, p->video_chroma_median_filter_bottom, p->video_chroma_median_filter_top); } - -EXPORT_SYMBOL(cx2341x_fill_defaults); -EXPORT_SYMBOL(cx2341x_ctrl_query); -EXPORT_SYMBOL(cx2341x_ctrl_get_menu); -EXPORT_SYMBOL(cx2341x_ext_ctrls); -EXPORT_SYMBOL(cx2341x_update); EXPORT_SYMBOL(cx2341x_log_status); -EXPORT_SYMBOL(cx2341x_mpeg_ctrls); /* * Local variables: -- cgit v1.2.3 From 6b1e56763b50f169d8446c43df6adb70f69552db Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 2 Dec 2007 06:56:00 -0300 Subject: V4L/DVB (6742): ivtv: fix incorrect debug message Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index ebc200320e6..c5ea54e6527 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -436,7 +436,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); + IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name); } s->dma_xfer_cnt++; -- cgit v1.2.3 From 4a56eb3f535f92b0585aa01dba05b3f17a547df0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 2 Dec 2007 07:03:45 -0300 Subject: V4L/DVB (6743): cx25840: fix endianness inconsistency cx25840_read4 reads a little-endian 32-bit value whereas cx25840_write4 writes the 32-bit value as big-endian. Convert write4 to use little-endian as well (that's the correct endianness). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 70 ++++++++++++++--------------- drivers/media/video/cx25840/cx25840-core.c | 8 ++-- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 3d46a776df3..51fc0af0157 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -38,71 +38,71 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040610); + cx25840_write4(client, 0x108, 0x1006040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xee39bb01); + cx25840_write4(client, 0x110, 0x01bb39ee); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x0801f77f */ - cx25840_write4(client, 0x900, 0x7ff70108); - cx25840_write4(client, 0x904, 0x7ff70108); - cx25840_write4(client, 0x90c, 0x7ff70108); + cx25840_write4(client, 0x900, 0x0801f77f); + cx25840_write4(client, 0x904, 0x0801f77f); + cx25840_write4(client, 0x90c, 0x0801f77f); break; case 44100: /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040910); + cx25840_write4(client, 0x108, 0x1009040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xd66bec00); + cx25840_write4(client, 0x110, 0x00ec6bd6); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x08016d59 */ - cx25840_write4(client, 0x900, 0x596d0108); - cx25840_write4(client, 0x904, 0x596d0108); - cx25840_write4(client, 0x90c, 0x596d0108); + cx25840_write4(client, 0x900, 0x08016d59); + cx25840_write4(client, 0x904, 0x08016d59); + cx25840_write4(client, 0x90c, 0x08016d59); break; case 48000: /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040a10); + cx25840_write4(client, 0x108, 0x100a040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xe5d69800); + cx25840_write4(client, 0x110, 0x0098d6e5); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x08014faa */ - cx25840_write4(client, 0x900, 0xaa4f0108); - cx25840_write4(client, 0x904, 0xaa4f0108); - cx25840_write4(client, 0x90c, 0xaa4f0108); + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); break; } } else { switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f04081e); + cx25840_write4(client, 0x108, 0x1e08040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x69082a01); + cx25840_write4(client, 0x110, 0x012a0869); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x00000108); + cx25840_write4(client, 0x8f8, 0x08010000); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x00000208); - cx25840_write4(client, 0x904, 0x00000208); - cx25840_write4(client, 0x90c, 0x00000208); + cx25840_write4(client, 0x900, 0x08020000); + cx25840_write4(client, 0x904, 0x08020000); + cx25840_write4(client, 0x90c, 0x08020000); /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ cx25840_write(client, 0x127, 0x54); @@ -110,40 +110,40 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) case 44100: /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040918); + cx25840_write4(client, 0x108, 0x1809040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xd66bec00); + cx25840_write4(client, 0x110, 0x00ec6bd6); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0xcd600108); + cx25840_write4(client, 0x8f8, 0x080160cd); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x85730108); - cx25840_write4(client, 0x904, 0x85730108); - cx25840_write4(client, 0x90c, 0x85730108); + cx25840_write4(client, 0x900, 0x08017385); + cx25840_write4(client, 0x904, 0x08017385); + cx25840_write4(client, 0x90c, 0x08017385); break; case 48000: /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040a18); + cx25840_write4(client, 0x108, 0x180a040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xe5d69800); + cx25840_write4(client, 0x110, 0x0098d6e5); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x00800108); + cx25840_write4(client, 0x8f8, 0x08018000); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x55550108); - cx25840_write4(client, 0x904, 0x55550108); - cx25840_write4(client, 0x90c, 0x55550108); + cx25840_write4(client, 0x900, 0x08015555); + cx25840_write4(client, 0x904, 0x08015555); + cx25840_write4(client, 0x90c, 0x08015555); break; } } @@ -168,14 +168,14 @@ void cx25840_audio_set_path(struct i2c_client *client) if (state->aud_input == CX25840_AUDIO_SERIAL) { /* Set Path1 to Serial Audio Input */ - cx25840_write4(client, 0x8d0, 0x12100101); + cx25840_write4(client, 0x8d0, 0x01011012); /* The microcontroller should not be started for the * non-tuner inputs: autodetection is specific for * TV audio. */ } else { /* Set Path1 to Analog Demod Main Channel */ - cx25840_write4(client, 0x8d0, 0x7038061f); + cx25840_write4(client, 0x8d0, 0x1f063870); } set_audclk_freq(client, state->audclk_freq); diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 6d2ca822a63..0d3d24aff50 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -73,10 +73,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) u8 buffer[6]; buffer[0] = addr >> 8; buffer[1] = addr & 0xff; - buffer[2] = value >> 24; - buffer[3] = (value >> 16) & 0xff; - buffer[4] = (value >> 8) & 0xff; - buffer[5] = value & 0xff; + buffer[2] = value & 0xff; + buffer[3] = (value >> 8) & 0xff; + buffer[4] = (value >> 16) & 0xff; + buffer[5] = value >> 24; return i2c_master_send(client, buffer, 6); } -- cgit v1.2.3 From 14e3c152a14cb96b5f584d3885d2aedf1a1353fc Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Dec 2007 00:33:08 -0300 Subject: V4L/DVB (6745): tda18271: remove tuning offset for atsc/qam The tuning request coming in from userspace is already center adjusted, so we should not adjust to center (+1.75mhz) within the driver. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index e8f4ac2325d..aecc0a5ac7b 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -584,7 +584,10 @@ static int tda18271_set_params(struct dvb_frontend *fe, __FUNCTION__); return -EINVAL; } +#if 0 + /* userspace request is already center adjusted */ freq += 1750000; /* Adjust to center (+1.75MHZ) */ +#endif bw = 6000000; } else if (fe->ops.info.type == FE_OFDM) { switch (params->u.ofdm.bandwidth) { -- cgit v1.2.3 From 105354a0f0410d4715f38e67d5790dead5dafdad Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Fri, 7 Dec 2007 17:57:38 -0300 Subject: V4L/DVB (6748): Subject: v4l: nopage Convert v4l from nopage to fault. Remove redundant vma range checks. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-sg.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 44ee408e145..eea5b4ecfc3 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -385,30 +385,26 @@ videobuf_vm_close(struct vm_area_struct *vma) * now ...). Bounce buffers don't work very well for the data rates * video capture has. */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) +static int +videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *page; - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; + dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n", + (unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end); page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) - return NOPAGE_OOM; + return VM_FAULT_OOM; clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = page; + return 0; } static struct vm_operations_struct videobuf_vm_ops = { .open = videobuf_vm_open, .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, + .fault = videobuf_vm_fault, }; /* --------------------------------------------------------------------- -- cgit v1.2.3 From d172b8bdab3812a6ad710e4cc78ceea3e8a40cd5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 7 Dec 2007 21:14:43 -0300 Subject: V4L/DVB (6749): v4l-nopage-fix dont just copy-and-paste stuff. (compile-tested this time) Signed-off-by: Andrew Morton Cc: Nick Piggin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-sg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index eea5b4ecfc3..98efd7ab1f5 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -395,7 +395,8 @@ videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) return VM_FAULT_OOM; - clear_user_page(page_address(page), vaddr, page); + clear_user_page(page_address(page), (unsigned long)vmf->virtual_address, + page); vmf->page = page; return 0; } -- cgit v1.2.3 From d2761f227162f610d35b9d68564f5c64774be581 Mon Sep 17 00:00:00 2001 From: Albert Graham Date: Sun, 9 Dec 2007 09:44:38 -0300 Subject: V4L/DVB (6752): saa7134: Enable remote control support for Avermedia M102 This patch enabled the IR remote control for the Avermedia M102 (card=110), which appears to be the same IR as the already supported device on the Avermedia AVerTV GO 007 FM (card=57) model, the code is two one liners which enable the IR for this device (subsystem: 1461:f31e) Signed-off-by: Albert Graham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 1 + drivers/media/video/saa7134/saa7134-input.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 9a2dd643025..b29427aaa88 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -4544,6 +4544,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_AVERMEDIA_M102: /* enable tuner */ + dev->has_remote = SAA7134_REMOTE_GPIO; saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); break; diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index a485185357c..8cfeb2bde90 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -260,6 +260,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: + case SAA7134_BOARD_AVERMEDIA_M102: ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; mask_keydown = 0x000010; -- cgit v1.2.3 From f905c442e5b19f75fe4e8ce96f2acffa565f2392 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Dec 2007 04:07:03 -0300 Subject: V4L/DVB (6753): Fix vivi to support non-zero minor node There were a trouble at vivi driver when using non-zero inodes. This where due to not properly preserving the minor inode after calling video_register. Since this driver is a reference for newer drivers, and it is possible to have more than one video device inside the machine, this patch makes vivi to dynamically allocate video_device struct. Thanks to Gregor Jasny for pointing the issue. Also, this patch removes a very anoying (but useless) message of not having a proper release call. CC: Gregor Jasny Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index fe9784a0cc2..5ddaaa370cb 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -170,7 +170,7 @@ struct vivi_dev { int users; /* various device info */ - struct video_device vfd; + struct video_device *vfd; struct vivi_dmaqueue vidq; @@ -986,7 +986,7 @@ static int vivi_open(struct inode *inode, struct file *file) printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) - if (dev->vfd.minor == minor) + if (dev->vfd->minor == minor) goto found; return -ENODEV; found: @@ -1067,7 +1067,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) return videobuf_poll_stream(file, q, wait); } -static int vivi_release(struct inode *inode, struct file *file) +static int vivi_close(struct inode *inode, struct file *file) { struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; @@ -1088,6 +1088,18 @@ static int vivi_release(struct inode *inode, struct file *file) return 0; } +static int vivi_release(struct vivi_dev *dev) +{ + if (-1 != dev->vfd->minor) + video_unregister_device(dev->vfd); + else + video_device_release(dev->vfd); + + dev->vfd = NULL; + + return 0; +} + static int vivi_mmap(struct file *file, struct vm_area_struct * vma) { @@ -1109,7 +1121,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma) static const struct file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, - .release = vivi_release, + .release = vivi_close, .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ @@ -1117,12 +1129,12 @@ static const struct file_operations vivi_fops = { .llseek = no_llseek, }; -static struct video_device vivi = { +static struct video_device vivi_template = { .name = "vivi", .type = VID_TYPE_CAPTURE, .fops = &vivi_fops, .minor = -1, -// .release = video_device_release, + .release = video_device_release, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, @@ -1156,6 +1168,7 @@ static int __init vivi_init(void) { int ret; struct vivi_dev *dev; + struct video_device *vfd; dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) @@ -1174,7 +1187,18 @@ static int __init vivi_init(void) dev->vidq.timeout.data = (unsigned long)dev; init_timer(&dev->vidq.timeout); - ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr); + vfd = video_device_alloc(); + if (NULL == vfd) + return -ENOMEM; + + *vfd = vivi_template; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); + snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", + vivi_template.name, vfd->minor); + + dev->vfd = vfd; + printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); return ret; } @@ -1188,9 +1212,9 @@ static void __exit vivi_exit(void) list = vivi_devlist.next; list_del(list); h = list_entry(list, struct vivi_dev, vivi_devlist); + vivi_release(h); kfree (h); } - video_unregister_device(&vivi); } module_init(vivi_init); -- cgit v1.2.3 From 55712ff7e06b721fbeebd36499bad4a11b7d8327 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Dec 2007 04:38:11 -0300 Subject: V4L/DVB (6754): Allow vivi to open multiple video devices Now, it is possible to open multiple vivi devices, by using n_devs parameter. This makes vivi driver closer to a real one. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 106 ++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 5ddaaa370cb..fda01f49efd 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -59,6 +59,7 @@ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ static struct video_device vivi; /* Video device */ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ +static int n_devs = 1; /* Number of virtual devices */ /* supported controls */ static struct v4l2_queryctrl vivi_qctrl[] = { @@ -1079,7 +1080,7 @@ static int vivi_close(struct inode *inode, struct file *file) videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); - kfree (fh); + kfree(fh); dev->users--; @@ -1088,14 +1089,23 @@ static int vivi_close(struct inode *inode, struct file *file) return 0; } -static int vivi_release(struct vivi_dev *dev) +static int vivi_release(void) { - if (-1 != dev->vfd->minor) - video_unregister_device(dev->vfd); - else - video_device_release(dev->vfd); + struct vivi_dev *dev; + struct list_head *list; + + while (!list_empty(&vivi_devlist)) { + list = vivi_devlist.next; + list_del(list); + dev = list_entry(list, struct vivi_dev, vivi_devlist); - dev->vfd = NULL; + if (-1 != dev->vfd->minor) + video_unregister_device(dev->vfd); + else + video_device_release(dev->vfd); + + kfree(dev); + } return 0; } @@ -1166,55 +1176,60 @@ static struct video_device vivi_template = { static int __init vivi_init(void) { - int ret; + int ret = -ENOMEM, i; struct vivi_dev *dev; struct video_device *vfd; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - list_add_tail(&dev->vivi_devlist,&vivi_devlist); + for (i = 0; i < n_devs; i++) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (NULL == dev) + break; - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - init_waitqueue_head(&dev->vidq.wq); + list_add_tail(&dev->vivi_devlist, &vivi_devlist); - /* initialize locks */ - mutex_init(&dev->lock); + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + init_waitqueue_head(&dev->vidq.wq); - dev->vidq.timeout.function = vivi_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); + /* initialize locks */ + mutex_init(&dev->lock); - vfd = video_device_alloc(); - if (NULL == vfd) - return -ENOMEM; + dev->vidq.timeout.function = vivi_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); - *vfd = vivi_template; + vfd = video_device_alloc(); + if (NULL == vfd) + break; + + *vfd = vivi_template; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); + if (ret < 0) + break; + + snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", + vivi_template.name, vfd->minor); - ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", - vivi_template.name, vfd->minor); + if (video_nr >= 0) + video_nr++; - dev->vfd = vfd; + dev->vfd = vfd; + } - printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); + if (ret < 0) { + vivi_release(); + printk(KERN_INFO "Error %d while loading vivi driver\n", ret); + } else + printk(KERN_INFO "Video Technology Magazine Virtual Video " + "Capture Board successfully loaded.\n"); return ret; } static void __exit vivi_exit(void) { - struct vivi_dev *h; - struct list_head *list; - - while (!list_empty(&vivi_devlist)) { - list = vivi_devlist.next; - list_del(list); - h = list_entry(list, struct vivi_dev, vivi_devlist); - vivi_release(h); - kfree (h); - } + vivi_release(); } module_init(vivi_init); @@ -1225,10 +1240,13 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); MODULE_LICENSE("Dual BSD/GPL"); module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr, "video iminor start number"); -module_param_named(debug,vivi.debug, int, 0644); -MODULE_PARM_DESC(debug,"activates debug info"); +module_param(n_devs, int, 0); +MODULE_PARM_DESC(n_devs, "number of video devices to create"); -module_param(vid_limit,int,0644); -MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); +module_param_named(debug, vivi.debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); -- cgit v1.2.3 From 025341d4f0caa58f0e5eddbffd11d44e37cff974 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Dec 2007 04:43:38 -0300 Subject: V4L/DVB (6755): Avoid troubles when using multiple devices mv_count is a counter used to move the vertical bars. Before this patch, it where a static var. This works fine for just one device. However, when using multiple devices, every device would increment it. This patch moves it to its correct place: struct vivi_dev. So, now, each device has its own data. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index fda01f49efd..ea9ff8a9bfd 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -178,6 +178,8 @@ struct vivi_dev { /* Several counters */ int h,m,s,us,jiffies; char timestr[13]; + + int mv_count; /* Controls bars movement */ }; struct vivi_fh { @@ -327,14 +329,12 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) struct timeval ts; char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); void *vbuf=videobuf_to_vmalloc (&buf->vb); - /* FIXME: move to dev struct */ - static int mv_count=0; if (!tmpbuf) return; for (h=0;hmv_count, dev->timestr); /* FIXME: replacing to __copy_to_user */ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) @@ -342,7 +342,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) pos += wmax*2; } - mv_count++; + dev->mv_count++; kfree(tmpbuf); -- cgit v1.2.3 From 543323bcf49422c76cf13755ec4a90564065bb60 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Dec 2007 09:33:52 -0300 Subject: V4L/DVB (6758): Miscelaneous cleanups Manually fixed all pertinent checkpatch.pl errors inside the source code. Also removed some unused code at the driver and a few minor cleanups. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 487 +++++++++++++++++++++++---------------------- 1 file changed, 246 insertions(+), 241 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index ea9ff8a9bfd..2bbefd92625 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -44,16 +44,13 @@ #define WAKE_DENOMINATOR 1001 #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ -/* These timers are for 1 fps - used only for testing */ -//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */ -//#define BUFFER_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ - #include "font.h" #define VIVI_MAJOR_VERSION 0 #define VIVI_MINOR_VERSION 4 #define VIVI_RELEASE 0 -#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) +#define VIVI_VERSION \ + KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ @@ -72,7 +69,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = { .default_value = 65535, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, - },{ + }, { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", @@ -113,7 +110,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = { static int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; -#define dprintk(level,fmt, arg...) \ +#define dprintk(level, fmt, arg...) \ do { \ if (vivi.debug >= (level)) \ printk(KERN_DEBUG "vivi: " fmt , ## arg); \ @@ -176,7 +173,7 @@ struct vivi_dev { struct vivi_dmaqueue vidq; /* Several counters */ - int h,m,s,us,jiffies; + int h, m, s, us, jiffies; char timestr[13]; int mv_count; /* Controls bars movement */ @@ -187,7 +184,7 @@ struct vivi_fh { /* video capture */ struct vivi_fmt *fmt; - unsigned int width,height; + unsigned int width, height; struct videobuf_queue vb_vidq; enum v4l2_buf_type type; @@ -206,109 +203,113 @@ enum colors { GREEN, MAGENTA, RED, - BLUE + BLUE, + BLACK, }; static u8 bars[8][3] = { /* R G B */ - {204,204,204}, /* white */ - {208,208, 0}, /* ambar */ - { 0,206,206}, /* cyan */ - { 0,239, 0}, /* green */ - {239, 0,239}, /* magenta */ - {205, 0, 0}, /* red */ - { 0, 0,255}, /* blue */ - { 0, 0, 0} + {204, 204, 204}, /* white */ + {208, 208, 0}, /* ambar */ + { 0, 206, 206}, /* cyan */ + { 0, 239, 0}, /* green */ + {239, 0, 239}, /* magenta */ + {205, 0, 0}, /* red */ + { 0, 0, 255}, /* blue */ + { 0, 0, 0}, /* black */ }; -#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b + 32768)>>16)+16) +#define TO_Y(r, g, b) \ + (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) /* RGB to V(Cr) Color transform */ -#define TO_V(r,g,b) (((28784*r -24103*g -4681*b + 32768)>>16)+128) +#define TO_V(r, g, b) \ + (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) /* RGB to U(Cb) Color transform */ -#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128) +#define TO_U(r, g, b) \ + (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) #define TSTAMP_MIN_Y 24 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 -static void gen_line(char *basep,int inipos,int wmax, - int hmax, int line, int count, char *timestr) +static void gen_line(char *basep, int inipos, int wmax, + int hmax, int line, int count, char *timestr) { - int w,i,j,pos=inipos,y; - char *p,*s; - u8 chr,r,g,b,color; + int w, i, j, y; + int pos = inipos; + char *p, *s; + u8 chr, r, g, b, color; /* We will just duplicate the second pixel at the packet */ - wmax/=2; + wmax /= 2; /* Generate a standard color bar pattern */ - for (w=0;w=hmax) + if (TSTAMP_MAX_Y >= hmax) goto end; - if (TSTAMP_MIN_X+strlen(timestr)>=wmax) + if (TSTAMP_MIN_X + strlen(timestr) >= wmax) goto end; /* Print stream time */ - if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) { - j=TSTAMP_MIN_X; - for (s=timestr;*s;s++) { - chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; - for (i=0;i<7;i++) { - if (chr&1<<(7-i)) { /* Font color*/ - r=bars[BLUE][0]; - g=bars[BLUE][1]; - b=bars[BLUE][2]; - r=g=b=0; - g=198; - } else { /* Background color */ - r=bars[WHITE][0]; - g=bars[WHITE][1]; - b=bars[WHITE][2]; - r=g=b=0; + if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { + j = TSTAMP_MIN_X; + for (s = timestr; *s; s++) { + chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; + for (i = 0; i < 7; i++) { + if (chr & 1 << (7 - i)) { + /* Font color*/ + r = 0; + g = 198; + b = 0; + } else { + /* Background color */ + r = bars[BLACK][0]; + g = bars[BLACK][1]; + b = bars[BLACK][2]; } - pos=inipos+j*2; - for (color=0;color<4;color++) { - p=basep+pos; + pos = inipos + j * 2; + for (color = 0; color < 4; color++) { + p = basep + pos; - y=TO_Y(r,g,b); + y = TO_Y(r, g, b); switch (color) { - case 0: - case 2: - *p=TO_Y(r,g,b); /* Luminance */ - break; - case 1: - *p=TO_U(r,g,b); /* Cb */ - break; - case 3: - *p=TO_V(r,g,b); /* Cr */ - break; + case 0: + case 2: + *p = TO_Y(r, g, b); /* Luma */ + break; + case 1: + *p = TO_U(r, g, b); /* Cb */ + break; + case 3: + *p = TO_V(r, g, b); /* Cr */ + break; } pos++; } @@ -317,28 +318,27 @@ static void gen_line(char *basep,int inipos,int wmax, } } - end: return; } -static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) +static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) { - int h,pos=0; + int h , pos = 0; int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; - char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); - void *vbuf=videobuf_to_vmalloc (&buf->vb); + char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL); + void *vbuf = videobuf_to_vmalloc(&buf->vb); if (!tmpbuf) return; - for (h=0;hmv_count, dev->timestr); /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) - dprintk(2,"vivifill copy_to_user failed.\n"); + if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0) + dprintk(2, "vivifill copy_to_user failed.\n"); pos += wmax*2; } @@ -348,27 +348,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) /* Updates stream time */ - dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); - dev->jiffies=jiffies; - if (dev->us>=1000000) { - dev->us-=1000000; + dev->us += jiffies_to_usecs(jiffies-dev->jiffies); + dev->jiffies = jiffies; + if (dev->us >= 1000000) { + dev->us -= 1000000; dev->s++; - if (dev->s>=60) { - dev->s-=60; + if (dev->s >= 60) { + dev->s -= 60; dev->m++; - if (dev->m>60) { - dev->m-=60; + if (dev->m > 60) { + dev->m -= 60; dev->h++; - if (dev->h>24) - dev->h-=24; + if (dev->h > 24) + dev->h -= 24; } } } - sprintf(dev->timestr,"%02d:%02d:%02d:%03d", - dev->h,dev->m,dev->s,(dev->us+500)/1000); + sprintf(dev->timestr, "%02d:%02d:%02d:%03d", + dev->h, dev->m, dev->s, (dev->us + 500) / 1000); - dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)tmpbuf,pos); + dprintk(2, "vivifill at %s: Buffer 0x%08lx size= %d\n", dev->timestr, + (unsigned long)tmpbuf, pos); /* Advice that buffer was filled */ buf->vb.state = VIDEOBUF_DONE; @@ -385,14 +385,14 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q); static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf; - struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq); + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); int bc; /* Announces videobuf that all went ok */ for (bc = 0;; bc++) { if (list_empty(&dma_q->active)) { - dprintk(1,"No active queue to serve\n"); + dprintk(1, "No active queue to serve\n"); break; } @@ -406,19 +406,20 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) } do_gettimeofday(&buf->vb.ts); - dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i); + dprintk(2, "[%p/%d] wakeup\n", buf, buf->vb. i); /* Fill buffer */ - vivi_fillbuff(dev,buf); + vivi_fillbuff(dev, buf); if (list_empty(&dma_q->active)) { del_timer(&dma_q->timeout); } else { - mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT); } } if (bc != 1) - dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); + dprintk(1, "%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); } static void vivi_sleep(struct vivi_dmaqueue *dma_q) @@ -426,30 +427,38 @@ static void vivi_sleep(struct vivi_dmaqueue *dma_q) int timeout; DECLARE_WAITQUEUE(wait, current); - dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); + dprintk(1, "%s dma_q=0x%08lx\n", __FUNCTION__, (unsigned long)dma_q); add_wait_queue(&dma_q->wq, &wait); if (!kthread_should_stop()) { dma_q->frame++; /* Calculate time to wake up */ - timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; + timeout = dma_q->ini_jiffies+ + msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR * 1000) + / WAKE_DENOMINATOR) - jiffies; if (timeout <= 0) { - int old=dma_q->frame; - dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1; - - timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; - - dprintk(1,"underrun, losed %d frames. " - "Now, frame is %d. Waking on %d jiffies\n", - dma_q->frame-old,dma_q->frame,timeout); + int old = dma_q->frame; + dma_q->frame = (jiffies_to_msecs(jiffies - + dma_q->ini_jiffies) * + WAKE_DENOMINATOR) / + (WAKE_NUMERATOR * 1000) + 1; + + timeout = dma_q->ini_jiffies+ + msecs_to_jiffies((dma_q->frame * + WAKE_NUMERATOR * 1000) + / WAKE_DENOMINATOR) - jiffies; + + dprintk(1, "underrun, losed %d frames. " + "Now, frame is %d. Waking on %d jiffies\n", + dma_q->frame-old, dma_q->frame, timeout); } else - dprintk(1,"will sleep for %i jiffies\n",timeout); + dprintk(1, "will sleep for %i jiffies\n", timeout); vivi_thread_tick(dma_q); - schedule_timeout_interruptible (timeout); + schedule_timeout_interruptible(timeout); } remove_wait_queue(&dma_q->wq, &wait); @@ -458,9 +467,9 @@ static void vivi_sleep(struct vivi_dmaqueue *dma_q) static int vivi_thread(void *data) { - struct vivi_dmaqueue *dma_q=data; + struct vivi_dmaqueue *dma_q = data; - dprintk(1,"thread started\n"); + dprintk(1, "thread started\n"); mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); set_freezable(); @@ -477,10 +486,10 @@ static int vivi_thread(void *data) static int vivi_start_thread(struct vivi_dmaqueue *dma_q) { - dma_q->frame=0; - dma_q->ini_jiffies=jiffies; + dma_q->frame = 0; + dma_q->ini_jiffies = jiffies; - dprintk(1,"%s\n",__FUNCTION__); + dprintk(1, "%s\n", __FUNCTION__); dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); @@ -491,17 +500,17 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q) /* Wakes thread */ wake_up_interruptible(&dma_q->wq); - dprintk(1,"returning from %s\n",__FUNCTION__); + dprintk(1, "returning from %s\n", __FUNCTION__); return 0; } static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) { - dprintk(1,"%s\n",__FUNCTION__); + dprintk(1, "%s\n", __FUNCTION__); /* shutdown control thread */ if (dma_q->kthread) { kthread_stop(dma_q->kthread); - dma_q->kthread=NULL; + dma_q->kthread = NULL; } } @@ -509,16 +518,16 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf, *prev; - dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); + dprintk(1, "%s dma_q=0x%08lx\n", __FUNCTION__, (unsigned long)dma_q); if (!list_empty(&dma_q->active)) { - buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf = list_entry(dma_q->active.next, + struct vivi_buffer, vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); - dprintk(1,"Restarting video dma\n"); + dprintk(1, "Restarting video dma\n"); vivi_stop_thread(dma_q); -// vivi_start_thread(dma_q); /* cancel all outstanding capture / vbi requests */ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { @@ -535,28 +544,29 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) for (;;) { if (list_empty(&dma_q->queued)) return 0; - buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue); + buf = list_entry(dma_q->queued.next, + struct vivi_buffer, vb.queue); if (NULL == prev) { list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&dma_q->active); + list_add_tail(&buf->vb.queue, &dma_q->active); - dprintk(1,"Restarting video dma\n"); + dprintk(1, "Restarting video dma\n"); vivi_stop_thread(dma_q); vivi_start_thread(dma_q); buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); + dprintk(2, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&dma_q->active); + list_add_tail(&buf->vb.queue, &dma_q->active); buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); + dprintk(2, "[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); } else { return 0; } @@ -566,16 +576,17 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) static void vivi_vid_timeout(unsigned long data) { - struct vivi_dev *dev = (struct vivi_dev*)data; + struct vivi_dev *dev = (struct vivi_dev *)data; struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *buf; while (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); + buf = list_entry(vidq->active.next, + struct vivi_buffer, vb.queue); list_del(&buf->vb.queue); buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); - printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); + printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); } restart_video_queue(vidq); @@ -597,19 +608,19 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) while (*size * *count > vid_limit * 1024 * 1024) (*count)--; - dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size); + dprintk(1, "%s, count=%d, size=%d\n", __FUNCTION__, *count, *size); return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - dprintk(1,"%s\n",__FUNCTION__); + dprintk(1, "%s\n", __FUNCTION__); if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(&buf->vb, 0, 0); videobuf_vmalloc_free(&buf->vb); buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -621,10 +632,10 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { struct vivi_fh *fh = vq->priv_data; - struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); + struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); int rc, init_buffer = 0; - dprintk(1,"%s, field=%d\n",__FUNCTION__,field); + dprintk(1, "%s, field=%d\n", __FUNCTION__, field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -646,7 +657,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, } if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL))) + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) goto fail; } @@ -655,65 +667,68 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, return 0; fail: - free_buffer(vq,buf); + free_buffer(vq, buf); return rc; } static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); - struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = fh->dev; - struct vivi_dmaqueue *vidq = &dev->vidq; + struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; + struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *prev; if (!list_empty(&vidq->queued)) { - dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue); - list_add_tail(&buf->vb.queue,&vidq->queued); + dprintk(1, "adding vb queue=0x%08lx\n", + (unsigned long)&buf->vb.queue); + list_add_tail(&buf->vb.queue, &vidq->queued); buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2,"[%p/%d] buffer_queue - append to queued\n", + dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&vidq->active)) { - list_add_tail(&buf->vb.queue,&vidq->active); + list_add_tail(&buf->vb.queue, &vidq->active); buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] buffer_queue - first active\n", + dprintk(2, "[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); vivi_start_thread(vidq); } else { - prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue); + prev = list_entry(vidq->active.prev, + struct vivi_buffer, vb.queue); if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue,&vidq->active); + list_add_tail(&buf->vb.queue, &vidq->active); buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2,"[%p/%d] buffer_queue - append to active\n", + dprintk(2, "[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { - list_add_tail(&buf->vb.queue,&vidq->queued); + list_add_tail(&buf->vb.queue, &vidq->queued); buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2,"[%p/%d] buffer_queue - first queued\n", + dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } } } -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) { - struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); + struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = (struct vivi_dev*)fh->dev; + struct vivi_dev *dev = (struct vivi_dev *)fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; - dprintk(1,"%s\n",__FUNCTION__); + dprintk(1, "%s\n", __FUNCTION__); vivi_stop_thread(vidq); - free_buffer(vq,buf); + free_buffer(vq, buf); } static struct videobuf_queue_ops vivi_video_qops = { @@ -726,7 +741,7 @@ static struct videobuf_queue_ops vivi_video_qops = { /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ -static int vidioc_querycap (struct file *file, void *priv, +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { strcpy(cap->driver, "vivi"); @@ -738,21 +753,21 @@ static int vidioc_querycap (struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index > 0) return -EINVAL; - strlcpy(f->description,format.name,sizeof(f->description)); + strlcpy(f->description, format.name, sizeof(f->description)); f->pixelformat = format.fourcc; return 0; } -static int vidioc_g_fmt_cap (struct file *file, void *priv, +static int vidioc_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; f->fmt.pix.width = fh->width; f->fmt.pix.height = fh->height; @@ -766,7 +781,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv, return (0); } -static int vidioc_try_fmt_cap (struct file *file, void *priv, +static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivi_fmt *fmt; @@ -774,18 +789,18 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, unsigned int maxw, maxh; if (format.fourcc != f->fmt.pix.pixelformat) { - dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts " - "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc); + dprintk(1, "Fourcc format (0x%08x) invalid. Driver accepts " + "only 0x%08x\n", f->fmt.pix.pixelformat, format.fourcc); return -EINVAL; } - fmt=&format; + fmt = &format; field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { - field=V4L2_FIELD_INTERLACED; + field = V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { - dprintk(1,"Field type invalid.\n"); + dprintk(1, "Field type invalid.\n"); return -EINVAL; } @@ -811,11 +826,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, } /*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_cap (struct file *file, void *priv, +static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh=priv; - int ret = vidioc_try_fmt_cap(file,fh,f); + struct vivi_fh *fh = priv; + int ret = vidioc_try_fmt_cap(file, fh, f); if (ret < 0) return (ret); @@ -828,47 +843,48 @@ static int vidioc_s_fmt_cap (struct file *file, void *priv, return (0); } -static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_reqbufs(&fh->vb_vidq, p)); } -static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_querybuf(&fh->vb_vidq, p)); } -static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_qbuf(&fh->vb_vidq, p)); } -static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK)); } #ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; - return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8); + return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); } #endif static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -880,7 +896,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -890,13 +906,13 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->vb_vidq); } -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) { return 0; } /* only one input in this sample driver */ -static int vidioc_enum_input (struct file *file, void *priv, +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { if (inp->index != 0) @@ -904,18 +920,18 @@ static int vidioc_enum_input (struct file *file, void *priv, inp->type = V4L2_INPUT_TYPE_CAMERA; inp->std = V4L2_STD_NTSC_M; - strcpy(inp->name,"Camera"); + strcpy(inp->name, "Camera"); return (0); } -static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { *i = 0; return (0); } -static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { if (i > 0) return -EINVAL; @@ -924,8 +940,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) } /* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) { int i; @@ -939,33 +955,31 @@ static int vidioc_queryctrl (struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctrl) +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) { int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { - ctrl->value=qctl_regs[i]; + ctrl->value = qctl_regs[i]; return (0); } return -EINVAL; } -static int vidioc_s_ctrl (struct file *file, void *priv, +static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { - if (ctrl->value < - vivi_qctrl[i].minimum - || ctrl->value > - vivi_qctrl[i].maximum) { + if (ctrl->value < vivi_qctrl[i].minimum + || ctrl->value > vivi_qctrl[i].maximum) { return (-ERANGE); } - qctl_regs[i]=ctrl->value; + qctl_regs[i] = ctrl->value; return (0); } return -EINVAL; @@ -984,16 +998,14 @@ static int vivi_open(struct inode *inode, struct file *file) struct vivi_fh *fh; int i; - printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); + printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) if (dev->vfd->minor == minor) goto found; return -ENODEV; -found: - - +found: /* If more than one user, mutex should be added */ dev->users++; @@ -1001,7 +1013,7 @@ found: v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); + fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { dev->users--; return -ENOMEM; @@ -1017,27 +1029,21 @@ found: /* Put all controls at a sane state */ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) - qctl_regs[i] =vivi_qctrl[i].default_value; - - dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", - (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq); - dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued)); - dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active)); + qctl_regs[i] = vivi_qctrl[i].default_value; /* Resets frame counters */ - dev->h=0; - dev->m=0; - dev->s=0; - dev->us=0; - dev->jiffies=jiffies; - sprintf(dev->timestr,"%02d:%02d:%02d:%03d", - dev->h,dev->m,dev->s,(dev->us+500)/1000); + dev->h = 0; + dev->m = 0; + dev->s = 0; + dev->us = 0; + dev->mv_count = 0; + dev->jiffies = jiffies; + sprintf(dev->timestr, "%02d:%02d:%02d:%03d", + dev->h, dev->m, dev->s, (dev->us + 500) / 1000); videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, - NULL, NULL, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct vivi_buffer),fh); + NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, + sizeof(struct vivi_buffer), fh); return 0; } @@ -1045,9 +1051,9 @@ found: static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct vivi_fh *fh = file->private_data; + struct vivi_fh *fh = file->private_data; - if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } @@ -1060,7 +1066,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) struct vivi_fh *fh = file->private_data; struct videobuf_queue *q = &fh->vb_vidq; - dprintk(1,"%s\n",__FUNCTION__); + dprintk(1, "%s\n", __FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; @@ -1084,7 +1090,7 @@ static int vivi_close(struct inode *inode, struct file *file) dev->users--; - printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users); + dprintk(1, "close called (minor=%d, users=%d)\n", minor, dev->users); return 0; } @@ -1110,17 +1116,16 @@ static int vivi_release(void) return 0; } -static int -vivi_mmap(struct file *file, struct vm_area_struct * vma) +static int vivi_mmap(struct file *file, struct vm_area_struct *vma) { - struct vivi_fh *fh = file->private_data; + struct vivi_fh *fh = file->private_data; int ret; - dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma); + dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - ret=videobuf_mmap_mapper(&fh->vb_vidq, vma); + ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n", + dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, ret); -- cgit v1.2.3 From e2c77314c9444c994087c96eb370b333d57657a7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Dec 2007 10:53:20 -0300 Subject: V4L/DVB (6759): CodingStyle fixes Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 292 ++++++++++++++++++------------------ 1 file changed, 146 insertions(+), 146 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 26d1a500173..9662d1e40a0 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -22,29 +22,32 @@ #include #define MAGIC_BUFFER 0x20070728 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } +#define MAGIC_CHECK(is, should) do { \ + if (unlikely((is) != (should))) { \ + printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \ + BUG(); } } while (0) -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_DESCRIPTION("helper module to manage video4linux buffers"); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0) /* --------------------------------------------------------------------- */ #define CALL(q, f, arg...) \ - ( (q->int_ops->f)? q->int_ops->f(arg) : 0) + ((q->int_ops->f) ? q->int_ops->f(arg) : 0) -void* videobuf_alloc(struct videobuf_queue* q) +void *videobuf_alloc(struct videobuf_queue *q) { struct videobuf_buffer *vb; - BUG_ON (q->msizemsize < sizeof(*vb)); if (!q->int_ops || !q->int_ops->alloc) { printk(KERN_ERR "No specific ops defined!\n"); @@ -66,7 +69,7 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) int retval = 0; DECLARE_WAITQUEUE(wait, current); - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); add_wait_queue(&vb->done, &wait); while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) { if (non_blocking) { @@ -75,11 +78,12 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) } set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) + if (vb->state == VIDEOBUF_ACTIVE || + vb->state == VIDEOBUF_QUEUED) schedule(); set_current_state(TASK_RUNNING); if (intr && signal_pending(current)) { - dprintk(1,"buffer waiton: -EINTR\n"); + dprintk(1, "buffer waiton: -EINTR\n"); retval = -EINTR; break; } @@ -88,27 +92,27 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) return retval; } -int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, +int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf) { - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper() - method should be called before _iolock. + /* FIXME: This is required to avoid OOPS on some cases, + since mmap_mapper() method should be called before _iolock. On some cases, the mmap_mapper() is called only after scheduling. However, this way is just too dirty! Better to wait for some event. */ schedule_timeout(HZ); - return CALL(q,iolock,q,vb,fbuf); + return CALL(q, iolock, q, vb, fbuf); } /* --------------------------------------------------------------------- */ -void videobuf_queue_core_init(struct videobuf_queue* q, +void videobuf_queue_core_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, @@ -118,7 +122,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q, void *priv, struct videobuf_qtype_ops *int_ops) { - memset(q,0,sizeof(*q)); + memset(q, 0, sizeof(*q)); q->irqlock = irqlock; q->dev = dev; q->type = type; @@ -129,13 +133,13 @@ void videobuf_queue_core_init(struct videobuf_queue* q, q->int_ops = int_ops; /* All buffer operations are mandatory */ - BUG_ON (!q->ops->buf_setup); - BUG_ON (!q->ops->buf_prepare); - BUG_ON (!q->ops->buf_queue); - BUG_ON (!q->ops->buf_release); + BUG_ON(!q->ops->buf_setup); + BUG_ON(!q->ops->buf_prepare); + BUG_ON(!q->ops->buf_queue); + BUG_ON(!q->ops->buf_release); /* Having implementations for abstract methods are mandatory */ - BUG_ON (!q->int_ops); + BUG_ON(!q->int_ops); mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); @@ -146,33 +150,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) { int i; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); if (q->streaming) { - dprintk(1,"busy: streaming active\n"); + dprintk(1, "busy: streaming active\n"); return 1; } if (q->reading) { - dprintk(1,"busy: pending read #1\n"); + dprintk(1, "busy: pending read #1\n"); return 1; } if (q->read_buf) { - dprintk(1,"busy: pending read #2\n"); + dprintk(1, "busy: pending read #2\n"); return 1; } for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; if (q->bufs[i]->map) { - dprintk(1,"busy: buffer #%d mapped\n",i); + dprintk(1, "busy: buffer #%d mapped\n", i); return 1; } if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - dprintk(1,"busy: buffer #%d queued\n",i); + dprintk(1, "busy: buffer #%d queued\n", i); return 1; } if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { - dprintk(1,"busy: buffer #%d avtive\n",i); + dprintk(1, "busy: buffer #%d avtive\n", i); return 1; } } @@ -182,12 +186,12 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) /* Locking: Caller holds q->lock */ void videobuf_queue_cancel(struct videobuf_queue *q) { - unsigned long flags=0; + unsigned long flags = 0; int i; /* remove queued buffers from list */ if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -197,13 +201,13 @@ void videobuf_queue_cancel(struct videobuf_queue *q) } } if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); /* free all buffers + clear queue */ for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(q,q->bufs[i]); + q->ops->buf_release(q, q->bufs[i]); } INIT_LIST_HEAD(&q->stream); } @@ -233,8 +237,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, struct videobuf_buffer *vb, enum v4l2_buf_type type) { - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); b->index = vb->i; b->type = type; @@ -294,16 +298,16 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) if (!q) return 0; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - rc = CALL(q,mmap_free,q); - if (rc<0) + rc = CALL(q, mmap_free, q); + if (rc < 0) return rc; for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(q,q->bufs[i]); + q->ops->buf_release(q, q->bufs[i]); kfree(q->bufs[i]); q->bufs[i] = NULL; } @@ -328,7 +332,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int i; int err; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); err = __videobuf_mmap_free(q); if (0 != err) @@ -359,7 +363,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, if (!i) return -ENOMEM; - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize); return i; @@ -379,35 +383,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q, int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) { - unsigned int size,count; + unsigned int size, count; int retval; if (req->count < 1) { - dprintk(1,"reqbufs: count invalid (%d)\n",req->count); + dprintk(1, "reqbufs: count invalid (%d)\n", req->count); return -EINVAL; } if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR && req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1,"reqbufs: memory type invalid\n"); + dprintk(1, "reqbufs: memory type invalid\n"); return -EINVAL; } mutex_lock(&q->lock); if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); + dprintk(1, "reqbufs: queue type invalid\n"); retval = -EINVAL; goto done; } if (q->streaming) { - dprintk(1,"reqbufs: streaming already exists\n"); + dprintk(1, "reqbufs: streaming already exists\n"); retval = -EBUSY; goto done; } if (!list_empty(&q->stream)) { - dprintk(1,"reqbufs: stream running\n"); + dprintk(1, "reqbufs: stream running\n"); retval = -EBUSY; goto done; } @@ -416,14 +420,14 @@ int videobuf_reqbufs(struct videobuf_queue *q, if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; size = 0; - q->ops->buf_setup(q,&count,&size); + q->ops->buf_setup(q, &count, &size); size = PAGE_ALIGN(size); - dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n", count, size, (count*size)>>PAGE_SHIFT); - retval = __videobuf_mmap_setup(q,count,size,req->memory); + retval = __videobuf_mmap_setup(q, count, size, req->memory); if (retval < 0) { - dprintk(1,"reqbufs: mmap setup returned %d\n",retval); + dprintk(1, "reqbufs: mmap setup returned %d\n", retval); goto done; } @@ -440,19 +444,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) mutex_lock(&q->lock); if (unlikely(b->type != q->type)) { - dprintk(1,"querybuf: Wrong type.\n"); + dprintk(1, "querybuf: Wrong type.\n"); goto done; } if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1,"querybuf: index out of range.\n"); + dprintk(1, "querybuf: index out of range.\n"); goto done; } if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1,"querybuf: buffer is null.\n"); + dprintk(1, "querybuf: buffer is null.\n"); goto done; } - videobuf_status(q,b,q->bufs[b->index],q->type); + videobuf_status(q, b, q->bufs[b->index], q->type); ret = 0; done: @@ -465,10 +469,10 @@ int videobuf_qbuf(struct videobuf_queue *q, { struct videobuf_buffer *buf; enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); if (b->memory == V4L2_MEMORY_MMAP) down_read(¤t->mm->mmap_sem); @@ -476,36 +480,36 @@ int videobuf_qbuf(struct videobuf_queue *q, mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { - dprintk(1,"qbuf: Reading running...\n"); + dprintk(1, "qbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { - dprintk(1,"qbuf: Wrong type.\n"); + dprintk(1, "qbuf: Wrong type.\n"); goto done; } if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1,"qbuf: index out of range.\n"); + dprintk(1, "qbuf: index out of range.\n"); goto done; } buf = q->bufs[b->index]; if (NULL == buf) { - dprintk(1,"qbuf: buffer is null.\n"); + dprintk(1, "qbuf: buffer is null.\n"); goto done; } - MAGIC_CHECK(buf->magic,MAGIC_BUFFER); + MAGIC_CHECK(buf->magic, MAGIC_BUFFER); if (buf->memory != b->memory) { - dprintk(1,"qbuf: memory type is wrong.\n"); + dprintk(1, "qbuf: memory type is wrong.\n"); goto done; } if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { - dprintk(1,"qbuf: buffer is already queued or active.\n"); + dprintk(1, "qbuf: buffer is already queued or active.\n"); goto done; } if (b->flags & V4L2_BUF_FLAG_INPUT) { if (b->input >= q->inputs) { - dprintk(1,"qbuf: wrong input.\n"); + dprintk(1, "qbuf: wrong input.\n"); goto done; } buf->input = b->input; @@ -516,44 +520,46 @@ int videobuf_qbuf(struct videobuf_queue *q, switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { - dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); + dprintk(1, "qbuf: mmap requested " + "but buffer addr is zero!\n"); goto done; } break; case V4L2_MEMORY_USERPTR: if (b->length < buf->bsize) { - dprintk(1,"qbuf: buffer length is not enough\n"); + dprintk(1, "qbuf: buffer length is not enough\n"); goto done; } - if (VIDEOBUF_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(q,buf); + if (VIDEOBUF_NEEDS_INIT != buf->state && + buf->baddr != b->m.userptr) + q->ops->buf_release(q, buf); buf->baddr = b->m.userptr; break; case V4L2_MEMORY_OVERLAY: buf->boff = b->m.offset; break; default: - dprintk(1,"qbuf: wrong memory type\n"); + dprintk(1, "qbuf: wrong memory type\n"); goto done; } - dprintk(1,"qbuf: requesting next field\n"); + dprintk(1, "qbuf: requesting next field\n"); field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,buf,field); + retval = q->ops->buf_prepare(q, buf, field); if (0 != retval) { - dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); + dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); goto done; } - list_add_tail(&buf->stream,&q->stream); + list_add_tail(&buf->stream, &q->stream); if (q->streaming) { if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,buf); + spin_lock_irqsave(q->irqlock, flags); + q->ops->buf_queue(q, buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); } - dprintk(1,"qbuf: succeded\n"); + dprintk(1, "qbuf: succeded\n"); retval = 0; done: @@ -571,49 +577,49 @@ int videobuf_dqbuf(struct videobuf_queue *q, struct videobuf_buffer *buf; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { - dprintk(1,"dqbuf: Reading running...\n"); + dprintk(1, "dqbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { - dprintk(1,"dqbuf: Wrong type.\n"); + dprintk(1, "dqbuf: Wrong type.\n"); goto done; } if (list_empty(&q->stream)) { - dprintk(1,"dqbuf: stream running\n"); + dprintk(1, "dqbuf: stream running\n"); goto done; } buf = list_entry(q->stream.next, struct videobuf_buffer, stream); retval = videobuf_waiton(buf, nonblocking, 1); if (retval < 0) { - dprintk(1,"dqbuf: waiton returned %d\n",retval); + dprintk(1, "dqbuf: waiton returned %d\n", retval); goto done; } switch (buf->state) { case VIDEOBUF_ERROR: - dprintk(1,"dqbuf: state is error\n"); + dprintk(1, "dqbuf: state is error\n"); retval = -EIO; - CALL(q,sync,q, buf); + CALL(q, sync, q, buf); buf->state = VIDEOBUF_IDLE; break; case VIDEOBUF_DONE: - dprintk(1,"dqbuf: state is done\n"); - CALL(q,sync,q, buf); + dprintk(1, "dqbuf: state is done\n"); + CALL(q, sync, q, buf); buf->state = VIDEOBUF_IDLE; break; default: - dprintk(1,"dqbuf: state invalid\n"); + dprintk(1, "dqbuf: state invalid\n"); retval = -EINVAL; goto done; } list_del(&buf->stream); - memset(b,0,sizeof(*b)); - videobuf_status(q,b,buf,q->type); + memset(b, 0, sizeof(*b)); + videobuf_status(q, b, buf, q->type); done: mutex_unlock(&q->lock); @@ -623,7 +629,7 @@ int videobuf_dqbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; - unsigned long flags=0; + unsigned long flags = 0; int retval; mutex_lock(&q->lock); @@ -635,12 +641,12 @@ int videobuf_streamon(struct videobuf_queue *q) goto done; q->streaming = 1; if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); list_for_each_entry(buf, &q->stream, stream) if (buf->state == VIDEOBUF_PREPARED) - q->ops->buf_queue(q,buf); + q->ops->buf_queue(q, buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); done: mutex_unlock(&q->lock); @@ -676,10 +682,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, size_t count, loff_t *ppos) { enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); /* setup stuff */ q->read_buf = videobuf_alloc(q); @@ -691,19 +697,19 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, q->read_buf->bsize = count; field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); + retval = q->ops->buf_prepare(q, q->read_buf, field); if (0 != retval) goto done; /* start capture & wait */ if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); + spin_lock_irqsave(q->irqlock, flags); + q->ops->buf_queue(q, q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - retval = videobuf_waiton(q->read_buf,0,0); + spin_unlock_irqrestore(q->irqlock, flags); + retval = videobuf_waiton(q->read_buf, 0, 0); if (0 == retval) { - CALL(q,sync,q,q->read_buf); + CALL(q, sync, q, q->read_buf); if (VIDEOBUF_ERROR == q->read_buf->state) retval = -EIO; else @@ -712,7 +718,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, done: /* cleanup */ - q->ops->buf_release(q,q->read_buf); + q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; return retval; @@ -723,21 +729,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, int nonblocking) { enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; unsigned size, nbufs; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); mutex_lock(&q->lock); nbufs = 1; size = 0; - q->ops->buf_setup(q,&nbufs,&size); + q->ops->buf_setup(q, &nbufs, &size); if (NULL == q->read_buf && count >= size && !nonblocking) { - retval = videobuf_read_zerocopy(q,data,count,ppos); + retval = videobuf_read_zerocopy(q, data, count, ppos); if (retval >= 0 || retval == -EIO) /* ok, all done */ goto done; @@ -749,25 +755,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, retval = -ENOMEM; q->read_buf = videobuf_alloc(q); - dprintk(1,"video alloc=0x%p\n", q->read_buf); + dprintk(1, "video alloc=0x%p\n", q->read_buf); if (NULL == q->read_buf) goto done; q->read_buf->memory = V4L2_MEMORY_USERPTR; q->read_buf->bsize = count; /* preferred size */ field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); + retval = q->ops->buf_prepare(q, q->read_buf, field); if (0 != retval) { - kfree (q->read_buf); + kfree(q->read_buf); q->read_buf = NULL; goto done; } if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q,q->read_buf); + q->ops->buf_queue(q, q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); q->read_off = 0; } @@ -776,11 +782,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, if (0 != retval) goto done; - CALL(q,sync,q,q->read_buf); + CALL(q, sync, q, q->read_buf); if (VIDEOBUF_ERROR == q->read_buf->state) { /* catch I/O errors */ - q->ops->buf_release(q,q->read_buf); + q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; retval = -EIO; @@ -788,14 +794,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Copy to userspace */ - retval=CALL(q,video_copy_to_user,q,data,count,nonblocking); - if (retval<0) + retval = CALL(q, video_copy_to_user, q, data, count, nonblocking); + if (retval < 0) goto done; q->read_off += retval; if (q->read_off == q->read_buf->size) { /* all data copied, cleanup */ - q->ops->buf_release(q,q->read_buf); + q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; } @@ -809,11 +815,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; unsigned int count = 0, size = 0; int err, i; - q->ops->buf_setup(q,&count,&size); + q->ops->buf_setup(q, &count, &size); if (count < 2) count = 2; if (count > VIDEO_MAX_FRAME) @@ -828,17 +834,17 @@ int __videobuf_read_start(struct videobuf_queue *q) for (i = 0; i < count; i++) { field = videobuf_next_field(q); - err = q->ops->buf_prepare(q,q->bufs[i],field); + err = q->ops->buf_prepare(q, q->bufs[i], field); if (err) return err; list_add_tail(&q->bufs[i]->stream, &q->stream); } if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); for (i = 0; i < count; i++) - q->ops->buf_queue(q,q->bufs[i]); + q->ops->buf_queue(q, q->bufs[i]); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); q->reading = 1; return 0; } @@ -859,7 +865,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q) } q->read_buf = NULL; q->reading = 0; - + } int videobuf_read_start(struct videobuf_queue *q) @@ -899,11 +905,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, int vbihack, int nonblocking) { int rc, retval; - unsigned long flags=0; + unsigned long flags = 0; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - dprintk(2,"%s\n",__FUNCTION__); + dprintk(2, "%s\n", __FUNCTION__); mutex_lock(&q->lock); retval = -EBUSY; if (q->streaming) @@ -932,7 +938,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, } if (q->read_buf->state == VIDEOBUF_DONE) { - rc = CALL (q,copy_stream, q, data + retval, count, + rc = CALL(q, copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { retval = rc; @@ -953,10 +959,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, list_add_tail(&q->read_buf->stream, &q->stream); if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); + spin_lock_irqsave(q->irqlock, flags); + q->ops->buf_queue(q, q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); q->read_buf = NULL; } if (retval < 0) @@ -1012,10 +1018,10 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, { int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); mutex_lock(&q->lock); - retval=CALL(q,mmap_mapper,q,vma); + retval = CALL(q, mmap_mapper, q, vma); mutex_unlock(&q->lock); return retval; @@ -1026,15 +1032,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q, struct video_mbuf *mbuf, int count) { struct v4l2_requestbuffers req; - int rc,i; + int rc, i; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - memset(&req,0,sizeof(req)); + memset(&req, 0, sizeof(req)); req.type = q->type; req.count = count; req.memory = V4L2_MEMORY_MMAP; - rc = videobuf_reqbufs(q,&req); + rc = videobuf_reqbufs(q, &req); if (rc < 0) return rc; @@ -1079,9 +1085,3 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream); EXPORT_SYMBOL_GPL(videobuf_mmap_setup); EXPORT_SYMBOL_GPL(videobuf_mmap_free); EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From 0170a48274acbed20b3b8d1f4a6cecd08ae5015e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Dec 2007 20:31:17 -0300 Subject: V4L/DVB (6762): ivtv: update version number to 1.2 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index d050de2a722..0f1d4cc4b4d 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -22,7 +22,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 1 +#define IVTV_DRIVER_VERSION_MINOR 2 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) -- cgit v1.2.3 From e08323f099b5aba28610a856fa7d21d0d86fd4f0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Dec 2007 20:40:16 -0300 Subject: V4L/DVB (6763): ivtv: add AVerMedia EZMaker PCI Deluxe support Add support for the AVerMedia EZMaker PCI Deluxe and update the ivtv cardlist. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.ivtv | 6 ++++++ drivers/media/video/ivtv/ivtv-cards.c | 29 +++++++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-cards.h | 3 ++- drivers/media/video/ivtv/ivtv-driver.c | 1 + 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.ivtv b/Documentation/video4linux/CARDLIST.ivtv index ddd76a0eb10..a019e27e42b 100644 --- a/Documentation/video4linux/CARDLIST.ivtv +++ b/Documentation/video4linux/CARDLIST.ivtv @@ -16,3 +16,9 @@ 16 -> GOTVIEW PCI DVD2 Deluxe [ffac:0600] 17 -> Yuan MPC622 [ff01:d998] 18 -> Digital Cowboy DCT-MTVP1 [1461:bfff] +19 -> Yuan PG600V2/GotView PCI DVD Lite [ffab:0600,ffad:0600] +20 -> Club3D ZAP-TV1x01 [ffab:0600] +21 -> AverTV MCE 116 Plus [1461:c439] +22 -> ASUS Falcon2 [1043:4b66,1043:462e,1043:4b2e] +23 -> AverMedia PVR-150 Plus [1461:c035] +24 -> AverMedia EZMaker PCI Deluxe [1461:c03f] diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 4bb2fe8bce0..715285e6008 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -956,6 +956,34 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = { /* ------------------------------------------------------------------------- */ +/* AVerMedia EZMaker PCI Deluxe card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_ezmaker = { + .type = IVTV_CARD_AVER_EZMAKER, + .name = "AVerMedia EZMaker PCI Deluxe", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 0 }, + }, + .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 }, + .pci_list = ivtv_pci_aver_ezmaker, +}; + +/* ------------------------------------------------------------------------- */ + /* ASUS Falcon2 */ static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { @@ -1016,6 +1044,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_avertv_mce116, &ivtv_card_asus_falcon2, &ivtv_card_aver_pvr150, + &ivtv_card_aver_ezmaker, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 881b0447316..b982fb06c58 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -47,7 +47,8 @@ #define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ #define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ #define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ -#define IVTV_CARD_LAST 22 +#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ +#define IVTV_CARD_LAST 23 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 7c600d0f48c..4595c7807f2 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -187,6 +187,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t21 = AverTV MCE 116 Plus\n" "\t\t\t22 = ASUS Falcon2\n" "\t\t\t23 = AverMedia PVR-150 Plus\n" + "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); -- cgit v1.2.3 From 9d1a16a4fc39bd908d85e0b7ce167048200d2d2b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Dec 2007 20:48:29 -0300 Subject: V4L/DVB (6764): ivtv: select VIDEO_IR in Kconfig Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 6e5eed5e243..270906fc314 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -3,6 +3,7 @@ config VIDEO_IVTV depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL select I2C_ALGOBIT select FW_LOADER + select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X -- cgit v1.2.3 From d9009201207c4bdce9b95a0bd903b3f087e8eda1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 7 Dec 2007 21:01:15 -0300 Subject: V4L/DVB (6765): ivtv: convert to bus-based i2c API Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 47 ++++++++++++++ drivers/media/video/ivtv/ivtv-cards.h | 24 ++++--- drivers/media/video/ivtv/ivtv-driver.c | 86 ++++++++++++-------------- drivers/media/video/ivtv/ivtv-driver.h | 2 +- drivers/media/video/ivtv/ivtv-i2c.c | 110 +++++++++++++++++++++++++-------- drivers/media/video/ivtv/ivtv-i2c.h | 1 + 6 files changed, 187 insertions(+), 83 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 715285e6008..26322e93399 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -40,6 +40,27 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +/* usual i2c tuner addresses to probe */ +static struct ivtv_card_tuner_i2c ivtv_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* as above, but with possible radio tuner */ +static struct ivtv_card_tuner_i2c ivtv_i2c_radio = { + .radio = { 0x60, I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, I2C_CLIENT_END }, +}; + +/* using the tda8290+75a combo */ +static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { + .radio = { I2C_CLIENT_END }, + .demod = { I2C_CLIENT_END }, + .tv = { 0x4b, I2C_CLIENT_END }, +}; + /********************** card configuration *******************************/ /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii @@ -73,6 +94,7 @@ static const struct ivtv_card ivtv_card_pvr250 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -127,6 +149,7 @@ static const struct ivtv_card ivtv_card_pvr350 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, }; /* PVR-350 V1 boards have a different audio tuner input and use a @@ -158,6 +181,7 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -193,6 +217,7 @@ static const struct ivtv_card ivtv_card_pvr150 = { CX25840_AUDIO_SERIAL, WM8775_AIN4 }, /* apparently needed for the IR blaster */ .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -235,6 +260,7 @@ static const struct ivtv_card ivtv_card_m179 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, }, .pci_list = ivtv_pci_m179, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -276,6 +302,7 @@ static const struct ivtv_card ivtv_card_mpg600 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -316,6 +343,7 @@ static const struct ivtv_card ivtv_card_mpg160 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -351,6 +379,7 @@ static const struct ivtv_card ivtv_card_pg600 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -394,6 +423,7 @@ static const struct ivtv_card ivtv_card_avc2410 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_avc2410, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -464,6 +494,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -494,6 +525,7 @@ static const struct ivtv_card ivtv_card_va2000 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -538,6 +570,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, + .i2c = &ivtv_i2c_std, }; static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { @@ -568,6 +601,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, + .i2c = &ivtv_i2c_std, }; static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { @@ -597,6 +631,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -636,6 +671,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -672,6 +708,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -706,6 +743,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -744,6 +782,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -779,6 +818,7 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, }, .pci_list = ivtv_pci_yuan_mpc622, + .i2c = &ivtv_i2c_tda8290, }; /* ------------------------------------------------------------------------- */ @@ -820,6 +860,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -852,6 +893,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_pg600v2, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -883,6 +925,7 @@ static const struct ivtv_card ivtv_card_club3d = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_club3d, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -914,6 +957,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_avertv_mce116, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -952,6 +996,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = { { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, }, .pci_list = ivtv_pci_aver_pvr150, + .i2c = &ivtv_i2c_radio, }; /* ------------------------------------------------------------------------- */ @@ -979,6 +1024,7 @@ static const struct ivtv_card ivtv_card_aver_ezmaker = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 0 }, }, .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 }, + /* Does not have a tuner */ .pci_list = ivtv_pci_aver_ezmaker, }; @@ -1018,6 +1064,7 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_asus_falcon2, + .i2c = &ivtv_i2c_std, }; static const struct ivtv_card *ivtv_card_list[] = { diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index b982fb06c58..191aafdd996 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -84,7 +84,7 @@ #define IVTV_PCI_ID_GOTVIEW1 0xffac #define IVTV_PCI_ID_GOTVIEW2 0xffad -/* hardware flags */ +/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */ #define IVTV_HW_CX25840 (1 << 0) #define IVTV_HW_SAA7115 (1 << 1) #define IVTV_HW_SAA7127 (1 << 2) @@ -94,14 +94,13 @@ #define IVTV_HW_CS53L32A (1 << 6) #define IVTV_HW_TVEEPROM (1 << 7) #define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_TVAUDIO (1 << 9) -#define IVTV_HW_UPD64031A (1 << 10) -#define IVTV_HW_UPD6408X (1 << 11) -#define IVTV_HW_SAA717X (1 << 12) -#define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_VP27SMPX (1 << 14) -#define IVTV_HW_M52790 (1 << 15) -#define IVTV_HW_GPIO (1 << 16) +#define IVTV_HW_UPD64031A (1 << 9) +#define IVTV_HW_UPD6408X (1 << 10) +#define IVTV_HW_SAA717X (1 << 11) +#define IVTV_HW_WM8739 (1 << 12) +#define IVTV_HW_VP27SMPX (1 << 13) +#define IVTV_HW_M52790 (1 << 14) +#define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) @@ -235,6 +234,12 @@ struct ivtv_card_tuner { int tuner; /* tuner ID (from tuner.h) */ }; +struct ivtv_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[2];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + /* for card information/parameters */ struct ivtv_card { int type; @@ -262,6 +267,7 @@ struct ivtv_card { struct ivtv_gpio_audio_detect gpio_audio_detect; struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; + struct ivtv_card_tuner_i2c *i2c; /* list of device and subsystem vendor/devices that correspond to this card type. */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 4595c7807f2..4994dc59d40 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -400,6 +400,7 @@ static void ivtv_process_eeprom(struct ivtv *itv) itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; + itv->card_i2c = itv->card->i2c; /* If this is a PVR500 then it should be possible to detect whether it is the first or second unit by looking at the subsystem device ID: is bit 4 is @@ -417,7 +418,14 @@ static void ivtv_process_eeprom(struct ivtv *itv) This detection is needed since the eeprom reports incorrectly that a radio is present on the second unit. */ if (tv.model / 1000 == 23) { + static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = { + .radio = { 0x60, I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, I2C_CLIENT_END }, + }; + itv->card_name = "WinTV PVR 500"; + itv->card_i2c = &ivtv_i2c_radio; if (pci_slot == 8 || pci_slot == 9) { int is_first = (pci_slot & 1) == 0; @@ -635,6 +643,7 @@ done: } itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; + itv->card_i2c = itv->card->i2c; } /* Precondition: the ivtv structure has been memset to 0. Only @@ -816,79 +825,66 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, return 0; } -static void ivtv_request_module(struct ivtv *itv, const char *name) +static u32 ivtv_request_module(struct ivtv *itv, u32 hw, + const char *name, u32 id) { + if ((hw & id) == 0) + return hw; if (request_module(name) != 0) { IVTV_ERR("Failed to load module %s\n", name); - } else { - IVTV_DEBUG_INFO("Loaded module %s\n", name); + return hw & ~id; } + IVTV_DEBUG_INFO("Loaded module %s\n", name); + return hw; } static void ivtv_load_and_init_modules(struct ivtv *itv) { u32 hw = itv->card->hw_all; - int i; + unsigned i; /* load modules */ -#ifndef CONFIG_VIDEO_TUNER - if (hw & IVTV_HW_TUNER) { - if (itv->options.tuner == TUNER_XC2028) { - IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); - itv->tunerid = 1; - } - else { - ivtv_request_module(itv, "tuner"); - } + if ((hw & IVTV_HW_TUNER) && itv->options.tuner == TUNER_XC2028) { + IVTV_INFO("Xceive tuner not yet supported, only composite\n"); + IVTV_INFO("and S-Video inputs will be available\n"); + hw &= ~IVTV_HW_TUNER; } +#ifndef CONFIG_VIDEO_TUNER + hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif #ifndef CONFIG_VIDEO_CX25840 - if (hw & IVTV_HW_CX25840) - ivtv_request_module(itv, "cx25840"); + hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840); #endif #ifndef CONFIG_VIDEO_SAA711X - if (hw & IVTV_HW_SAA711X) - ivtv_request_module(itv, "saa7115"); + hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X); #endif #ifndef CONFIG_VIDEO_SAA7127 - if (hw & IVTV_HW_SAA7127) - ivtv_request_module(itv, "saa7127"); + hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127); #endif - if (hw & IVTV_HW_SAA717X) - ivtv_request_module(itv, "saa717x"); + hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X); #ifndef CONFIG_VIDEO_UPD64031A - if (hw & IVTV_HW_UPD64031A) - ivtv_request_module(itv, "upd64031a"); + hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A); #endif #ifndef CONFIG_VIDEO_UPD64083 - if (hw & IVTV_HW_UPD6408X) - ivtv_request_module(itv, "upd64083"); + hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X); #endif #ifndef CONFIG_VIDEO_MSP3400 - if (hw & IVTV_HW_MSP34XX) - ivtv_request_module(itv, "msp3400"); + hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX); #endif #ifndef CONFIG_VIDEO_VP27SMPX - if (hw & IVTV_HW_VP27SMPX) - ivtv_request_module(itv, "vp27smpx"); + hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX); #endif - if (hw & IVTV_HW_TVAUDIO) - ivtv_request_module(itv, "tvaudio"); #ifndef CONFIG_VIDEO_WM8775 - if (hw & IVTV_HW_WM8775) - ivtv_request_module(itv, "wm8775"); + hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775); #endif #ifndef CONFIG_VIDEO_WM8739 - if (hw & IVTV_HW_WM8739) - ivtv_request_module(itv, "wm8739"); + hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739); #endif #ifndef CONFIG_VIDEO_CS53L32A - if (hw & IVTV_HW_CS53L32A) - ivtv_request_module(itv, "cs53l32a"); + hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A); #endif #ifndef CONFIG_VIDEO_M52790 - if (hw & IVTV_HW_M52790) - ivtv_request_module(itv, "m52790"); + hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790); #endif /* check which i2c devices are actually found */ @@ -897,11 +893,12 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) if (!(device & hw)) continue; - if (device == IVTV_HW_GPIO) { - /* GPIO is always available */ - itv->hw_flags |= IVTV_HW_GPIO; + if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) { + /* GPIO and TVEEPROM do not use i2c probing */ + itv->hw_flags |= device; continue; } + ivtv_i2c_register(itv, i); if (ivtv_i2c_hw_addr(itv, device) > 0) itv->hw_flags |= device; } @@ -1075,9 +1072,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); if (itv->card->hw_all & IVTV_HW_TVEEPROM) { -#ifdef CONFIG_VIDEO_TVEEPROM_MODULE - ivtv_request_module(itv, "tveeprom"); -#endif /* Based on the model number the cardtype may be changed. The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); @@ -1150,7 +1144,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; - if (itv->options.tuner > -1 && itv->tunerid == 0) { + if (itv->options.tuner > -1) { struct tuner_setup setup; setup.addr = ADDR_UNSET; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 19a9b3bac19..8eeea3a0c70 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -590,13 +590,13 @@ struct ivtv { struct pci_dev *dev; /* PCI device */ const struct ivtv_card *card; /* card information */ const char *card_name; /* full name of the card */ + const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ u8 nof_inputs; /* number of video inputs */ u8 nof_audio_inputs; /* number of audio inputs */ u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* hardware description of the board */ - int tunerid; /* userspace tuner ID for experimental Xceive tuner support */ v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ /* controlling video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 7f513ecc078..9acfde68116 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -92,7 +92,8 @@ #define IVTV_TEA5767_I2C_ADDR 0x60 #define IVTV_UPD64031A_I2C_ADDR 0x12 #define IVTV_UPD64083_I2C_ADDR 0x5c -#define IVTV_TDA985X_I2C_ADDR 0x5b +#define IVTV_VP27SMPX_I2C_ADDR 0x5b +#define IVTV_M52790_I2C_ADDR 0x48 /* This array should match the IVTV_HW_ defines */ static const u8 hw_driverids[] = { @@ -105,7 +106,6 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_CS53L32A, I2C_DRIVERID_TVEEPROM, I2C_DRIVERID_SAA711X, - I2C_DRIVERID_TVAUDIO, I2C_DRIVERID_UPD64031A, I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, @@ -115,9 +115,29 @@ static const u8 hw_driverids[] = { 0 /* IVTV_HW_GPIO dummy driver ID */ }; +/* This array should match the IVTV_HW_ defines */ +static const u8 hw_addrs[] = { + IVTV_CX25840_I2C_ADDR, + IVTV_SAA7115_I2C_ADDR, + IVTV_SAA7127_I2C_ADDR, + IVTV_MSP3400_I2C_ADDR, + 0, + IVTV_WM8775_I2C_ADDR, + IVTV_CS53L32A_I2C_ADDR, + 0, + IVTV_SAA7115_I2C_ADDR, + IVTV_UPD64031A_I2C_ADDR, + IVTV_UPD64083_I2C_ADDR, + IVTV_SAA717x_I2C_ADDR, + IVTV_WM8739_I2C_ADDR, + IVTV_VP27SMPX_I2C_ADDR, + IVTV_M52790_I2C_ADDR, + 0 /* IVTV_HW_GPIO dummy driver ID */ +}; + /* This array should match the IVTV_HW_ defines */ static const char * const hw_drivernames[] = { - "cx2584x", + "cx25840", "saa7115", "saa7127", "msp3400", @@ -125,8 +145,7 @@ static const char * const hw_drivernames[] = { "wm8775", "cs53l32a", "tveeprom", - "saa7114", - "tvaudio", + "saa7115", "upd64031a", "upd64083", "saa717x", @@ -136,21 +155,57 @@ static const char * const hw_drivernames[] = { "gpio", }; -static int attach_inform(struct i2c_client *client) +int ivtv_i2c_register(struct ivtv *itv, unsigned idx) { - struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); + struct i2c_board_info info; + struct i2c_client *c; + u8 id; int i; - IVTV_DEBUG_I2C("i2c client attach\n"); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (itv->i2c_clients[i] == NULL) { - itv->i2c_clients[i] = client; - break; - } - } + IVTV_DEBUG_I2C("i2c client register\n"); + if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) + return -1; + id = hw_driverids[idx]; + memset(&info, 0, sizeof(info)); + strcpy(info.driver_name, hw_drivernames[idx]); + info.addr = hw_addrs[idx]; + for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} + if (i == I2C_CLIENTS_MAX) { - IVTV_ERR("Insufficient room for new I2C client\n"); + IVTV_ERR("insufficient room for new I2C client!\n"); + return -ENOMEM; } + + if (id != I2C_DRIVERID_TUNER) { + c = i2c_new_device(&itv->i2c_adap, &info); + if (c->driver == NULL) + i2c_unregister_device(c); + else + itv->i2c_clients[i] = c; + return itv->i2c_clients[i] ? 0 : -ENODEV; + } + + /* special tuner handling */ + c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + itv->i2c_clients[i++] = c; + c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + itv->i2c_clients[i++] = c; + c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + itv->i2c_clients[i++] = c; + return 0; +} + +static int attach_inform(struct i2c_client *client) +{ return 0; } @@ -478,9 +533,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = { .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif }; static void ivtv_setscl_old(void *data, int state) @@ -534,9 +586,6 @@ static struct i2c_adapter ivtv_i2c_adap_template = { .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif }; static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { @@ -561,12 +610,9 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; - if (client == NULL) { - continue; - } - if (client->driver->command == NULL) { + if (client == NULL || client->driver == NULL || + client->driver->command == NULL) continue; - } if (addr == client->addr) { retval = client->driver->command(client, cmd, arg); return retval; @@ -587,7 +633,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id) for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; - if (client == NULL) + if (client == NULL || client->driver == NULL) continue; if (id == client->driver->id) { retval = client->addr; @@ -713,6 +759,16 @@ int init_ivtv_i2c(struct ivtv *itv) { IVTV_DEBUG_I2C("i2c init\n"); + /* Sanity checks for the I2C hardware arrays. They must be the + * same size and GPIO must be the last entry. + */ + if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || + ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) || + IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || + hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { + IVTV_ERR("Mismatched I2C hardware arrays\n"); + return -ENODEV; + } if (itv->options.newi2c > 0) { memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, sizeof(struct i2c_adapter)); diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 987042c09b6..022978cf533 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -33,6 +33,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg); int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg); int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); +int ivtv_i2c_register(struct ivtv *itv, unsigned idx); /* init + register i2c algo-bit adapter */ int init_ivtv_i2c(struct ivtv *itv); -- cgit v1.2.3 From 2a2bfbff3d867c62a49f43266ca993c9c2c2ff28 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 Dec 2007 07:43:14 -0300 Subject: V4L/DVB (6766): ivtv: remove i2c legacy support from drivers that no longer need it Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/m52790.c | 4 ---- drivers/media/video/saa7127.c | 4 ---- drivers/media/video/upd64031a.c | 4 ---- drivers/media/video/upd64083.c | 4 ---- drivers/media/video/vp27smpx.c | 4 ---- drivers/media/video/wm8739.c | 3 --- include/media/v4l2-i2c-drv.h | 1 - 7 files changed, 24 deletions(-) diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 51ecbfbc1ae..4d2a52204ad 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -36,10 +36,6 @@ MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static unsigned short normal_i2c[] = { 0x90 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; struct m52790_state { u16 input; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 0262acde088..a5fbfe02533 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -69,10 +69,6 @@ module_param(test_image, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_PARM_DESC(test_image, "test_image (0-1)"); -static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; /* * SAA7127 registers diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 0318432d85f..1b162f2dca9 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -49,10 +49,6 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; enum { R00 = 0, R01, R02, R03, R04, diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 7e32c5b0c29..0f9e86cfc62 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -39,10 +39,6 @@ module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; enum { R00 = 0, R01, R02, R03, R04, diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 97e24769e65..cd98084ac09 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -36,10 +36,6 @@ MODULE_DESCRIPTION("vp27smpx driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index ac4fee1d025..1c30a5c8455 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -37,15 +37,12 @@ MODULE_AUTHOR("T. Adachi, Hans Verkuil"); MODULE_LICENSE("GPL"); static int debug; -static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END }; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -I2C_CLIENT_INSMOD; - /* ------------------------------------------------------------------------ */ enum { diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h index bc61ab27779..d758b765e0f 100644 --- a/include/media/v4l2-i2c-drv.h +++ b/include/media/v4l2-i2c-drv.h @@ -34,7 +34,6 @@ struct v4l2_i2c_driver_data { }; static struct v4l2_i2c_driver_data v4l2_i2c_data; -static struct i2c_client_address_data addr_data; static struct i2c_driver v4l2_i2c_driver; -- cgit v1.2.3 From 787f5abb9519fd420c4681a560aabc449632a6c2 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Dec 2007 17:08:32 -0300 Subject: V4L/DVB (6768): pvrusb2: Mark Gotview hardware as having a cx2584x part Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index eed64571ca0..7c2b976960e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -104,6 +104,7 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .shortname = "gv2", .client_modules.lst = pvr2_client_gotview_2, .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2), + .flag_has_cx25840 = !0, .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, }, -- cgit v1.2.3 From 4542783c3733de9a21099cd0c42e1a2392c68a88 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Dec 2007 17:11:13 -0300 Subject: V4L/DVB (6769): pvrusb2: Implement experimental support for OnAir Creator and USB2 devices Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 7c2b976960e..2d6519d20f0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -37,13 +37,34 @@ pvr2_device_desc structures. #define PVR2_HDW_TYPE_29XXX 0 #define PVR2_HDW_TYPE_24XXX 1 #define PVR2_HDW_TYPE_GOTVIEW_2 2 +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR +#define PVR2_HDW_TYPE_ONAIR_CREATOR 3 +#endif +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 +#define PVR2_HDW_TYPE_ONAIR_USB2 4 +#endif struct usb_device_id pvr2_device_table[] = { [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, [PVR2_HDW_TYPE_GOTVIEW_2] = { USB_DEVICE(0x1164, 0x0622) }, +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR + [PVR2_HDW_TYPE_ONAIR_CREATOR] = { USB_DEVICE(0x11ba, 0x1003) }, +#endif +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 + [PVR2_HDW_TYPE_ONAIR_USB2] = { USB_DEVICE(0x11ba, 0x1001) }, +#endif { } }; +#if defined(CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR) || defined(CONFIG_VIDEO_PVRUSB2_ONAIR_USB2) + +/* Names of other client modules to request for Creator model hardware */ +static const char *pvr2_client_onair[] = { + "saa7115", + "tuner", + "cs53l32a", +}; +#endif /* Names of other client modules to request for 24xxx model hardware */ static const char *pvr2_client_24xxx[] = { @@ -108,6 +129,26 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, }, +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR + [PVR2_HDW_TYPE_ONAIR_CREATOR] = { + .description = "OnAir Creator Hybrid USB tuner", + .shortname = "oac", + .client_modules.lst = pvr2_client_onair, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair), + .default_tuner_type = TUNER_LG_TDVS_H06XF, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + }, +#endif +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 + [PVR2_HDW_TYPE_ONAIR_USB2] = { + .description = "OnAir USB2 Hybrid USB tuner", + .shortname = "oa2", + .client_modules.lst = pvr2_client_onair, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair), + .default_tuner_type = TUNER_PHILIPS_ATSC, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + }, +#endif }; const unsigned int pvr2_device_count = ARRAY_SIZE(pvr2_device_descriptions); -- cgit v1.2.3 From 5edfded4811175283c745c9309c9315b721cf674 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Dec 2007 17:15:55 -0300 Subject: V4L/DVB (6770): pvrusb2: Device CONFIG flags for OnAir device support Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/Kconfig | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index d0c2cd78543..e8e231d8446 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -12,6 +12,32 @@ config VIDEO_PVRUSB2 To compile this driver as a module, choose M here: the module will be called pvrusb2 +config VIDEO_PVRUSB2_ONAIR_CREATOR + bool "pvrusb2 driver support for OnAir Creator model" + depends on VIDEO_PVRUSB2 && EXPERIMENTAL + select VIDEO_SAA711X + select VIDEO_CS53L32A + ---help--- + + This option enables support for the OnAir Creator USB tuner + device. This is a hybrid device, however currently only + analog mode is supported. + + If you are in doubt, say Y. + +config VIDEO_PVRUSB2_ONAIR_USB2 + bool "pvrusb2 driver support for OnAir USB2 model" + depends on VIDEO_PVRUSB2 && EXPERIMENTAL + select VIDEO_SAA711X + select VIDEO_CS53L32A + ---help--- + + This option enables support for the OnAir USB2 tuner device + (also known as the Sasem tuner). This is a hybrid device, + however currently only analog mode is supported. + + If you are in doubt, say Y. + config VIDEO_PVRUSB2_29XXX bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series" depends on VIDEO_PVRUSB2 && EXPERIMENTAL -- cgit v1.2.3 From 577e4023df8e6111bf7c63d182acc967af060054 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Dec 2007 17:17:09 -0300 Subject: V4L/DVB (6771): pvrusb2: Remove old obsolete CONFIG flags for pvrusb2 driver Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/Kconfig | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index e8e231d8446..95e4396011c 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -38,35 +38,6 @@ config VIDEO_PVRUSB2_ONAIR_USB2 If you are in doubt, say Y. -config VIDEO_PVRUSB2_29XXX - bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_MSP3400 - ---help--- - This option enables support for WinTV-PVR USB2 devices whose - model number is of the form "29xxx" (leading prefix of "29" - followed by 3 digits). - To see if you may need this option, examine the white - sticker on the underside of your device. - - If you are in doubt, say Y. - -config VIDEO_PVRUSB2_24XXX - bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_CX25840 - select VIDEO_WM8775 - ---help--- - This option enables inclusion of additional logic to operate - newer WinTV-PVR USB2 devices whose model number is of the - form "24xxx" (leading prefix of "24" followed by 3 digits). - To see if you may need this option, examine the white - sticker on the underside of your device. Enabling this - option will not harm support for older devices. - - If you are in doubt, say Y. - config VIDEO_PVRUSB2_SYSFS bool "pvrusb2 sysfs support (EXPERIMENTAL)" default y -- cgit v1.2.3 From 066bba2d1ccdac2005a64f4c87f8b542744ed94c Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Dec 2007 17:17:44 -0300 Subject: V4L/DVB (6772): pvrusb2: Remove obsolete (and misleading) comment Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index a8370737b50..b63b2265503 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -149,11 +149,6 @@ static void __exit pvr_exit(void) module_init(pvr_init); module_exit(pvr_exit); -/* Mike Isely 11-Mar-2006: See pvrusb2-hdw.c for - MODULE_DEVICE_TABLE(). We have to declare that attribute there - because that's where the device table actually is now and it seems - that certain gcc configurations get angry if MODULE_DEVICE_TABLE() - is used on what ends up being an external symbol. */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From d130fa8a05ee5f39c786df02dd75d1eebb12633b Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 8 Dec 2007 17:20:06 -0300 Subject: V4L/DVB (6773): pvrusb2: rework device descriptor layout The pvrusb2 driver tries to keep all device specific attributes in a single data structure in one source file. This change further cleans up how that table is set up. We now try to group everything together for each specific device, and the number of symbols exported from this module has now been reduced to a single global. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 155 +++++++++++++++----------- drivers/media/video/pvrusb2/pvrusb2-devattr.h | 2 - drivers/media/video/pvrusb2/pvrusb2-hdw.c | 9 +- 3 files changed, 89 insertions(+), 77 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 2d6519d20f0..9a08670d406 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -33,71 +33,22 @@ pvr2_device_desc structures. #include #include -/* Known major hardware variants, keyed from device ID */ -#define PVR2_HDW_TYPE_29XXX 0 -#define PVR2_HDW_TYPE_24XXX 1 -#define PVR2_HDW_TYPE_GOTVIEW_2 2 -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR -#define PVR2_HDW_TYPE_ONAIR_CREATOR 3 -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 -#define PVR2_HDW_TYPE_ONAIR_USB2 4 -#endif - -struct usb_device_id pvr2_device_table[] = { - [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, - [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, - [PVR2_HDW_TYPE_GOTVIEW_2] = { USB_DEVICE(0x1164, 0x0622) }, -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR - [PVR2_HDW_TYPE_ONAIR_CREATOR] = { USB_DEVICE(0x11ba, 0x1003) }, -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 - [PVR2_HDW_TYPE_ONAIR_USB2] = { USB_DEVICE(0x11ba, 0x1001) }, -#endif - { } -}; -#if defined(CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR) || defined(CONFIG_VIDEO_PVRUSB2_ONAIR_USB2) -/* Names of other client modules to request for Creator model hardware */ -static const char *pvr2_client_onair[] = { - "saa7115", - "tuner", - "cs53l32a", -}; -#endif -/* Names of other client modules to request for 24xxx model hardware */ -static const char *pvr2_client_24xxx[] = { - "cx25840", - "tuner", - "wm8775", -}; +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 29xxx */ -/* Names of other client modules to request for 29xxx model hardware */ static const char *pvr2_client_29xxx[] = { "msp3400", "saa7115", "tuner", }; -// Names of other client modules to request for Gotview 2 model hardware -static const char *pvr2_client_gotview_2[] = { - "cx25840", - "tuner", -}; - -/* Firmware file name(s) for 29xxx devices */ static const char *pvr2_fw1_names_29xxx[] = { "v4l-pvrusb2-29xxx-01.fw", }; -/* Firmware file name(s) for 24xxx devices */ -static const char *pvr2_fw1_names_24xxx[] = { - "v4l-pvrusb2-24xxx-01.fw", -}; - -const struct pvr2_device_desc pvr2_device_descriptions[] = { - [PVR2_HDW_TYPE_29XXX] = { +static const struct pvr2_device_desc pvr2_device_29xxx = { .description = "WinTV PVR USB2 Model Category 29xxxx", .shortname = "29xxx", .client_modules.lst = pvr2_client_29xxx, @@ -106,8 +57,24 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), .flag_has_hauppauge_rom = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - }, - [PVR2_HDW_TYPE_24XXX] = { +}; + + + +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 24xxx */ + +static const char *pvr2_client_24xxx[] = { + "cx25840", + "tuner", + "wm8775", +}; + +static const char *pvr2_fw1_names_24xxx[] = { + "v4l-pvrusb2-24xxx-01.fw", +}; + +static const struct pvr2_device_desc pvr2_device_24xxx = { .description = "WinTV PVR USB2 Model Category 24xxxx", .shortname = "24xxx", .client_modules.lst = pvr2_client_24xxx, @@ -119,8 +86,19 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .flag_has_hauppauge_rom = !0, .flag_has_hauppauge_custom_ir = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - }, - [PVR2_HDW_TYPE_GOTVIEW_2] = { +}; + + + +/*------------------------------------------------------------------------*/ +/* GOTVIEW USB2.0 DVD2 */ + +static const char *pvr2_client_gotview_2[] = { + "cx25840", + "tuner", +}; + +static const struct pvr2_device_desc pvr2_device_gotview_2 = { .description = "Gotview USB 2.0 DVD 2", .shortname = "gv2", .client_modules.lst = pvr2_client_gotview_2, @@ -128,30 +106,73 @@ const struct pvr2_device_desc pvr2_device_descriptions[] = { .flag_has_cx25840 = !0, .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, - }, +}; + + + #ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR - [PVR2_HDW_TYPE_ONAIR_CREATOR] = { +/*------------------------------------------------------------------------*/ +/* OnAir Creator */ + +static const char *pvr2_client_onair_creator[] = { + "saa7115", + "tuner", + "cs53l32a", +}; + +static const struct pvr2_device_desc pvr2_device_onair_creator = { .description = "OnAir Creator Hybrid USB tuner", .shortname = "oac", - .client_modules.lst = pvr2_client_onair, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair), + .client_modules.lst = pvr2_client_onair_creator, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator), .default_tuner_type = TUNER_LG_TDVS_H06XF, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - }, +}; #endif + + + #ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 - [PVR2_HDW_TYPE_ONAIR_USB2] = { +/*------------------------------------------------------------------------*/ +/* OnAir USB 2.0 */ + +static const char *pvr2_client_onair_usb2[] = { + "saa7115", + "tuner", + "cs53l32a", +}; + +static const struct pvr2_device_desc pvr2_device_onair_usb2 = { .description = "OnAir USB2 Hybrid USB tuner", .shortname = "oa2", - .client_modules.lst = pvr2_client_onair, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair), + .client_modules.lst = pvr2_client_onair_usb2, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2), .default_tuner_type = TUNER_PHILIPS_ATSC, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - }, -#endif }; +#endif + + -const unsigned int pvr2_device_count = ARRAY_SIZE(pvr2_device_descriptions); +/*------------------------------------------------------------------------*/ + +struct usb_device_id pvr2_device_table[] = { + { USB_DEVICE(0x2040, 0x2900), + .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, + { USB_DEVICE(0x2040, 0x2400), + .driver_info = (kernel_ulong_t)&pvr2_device_24xxx}, + { USB_DEVICE(0x1164, 0x0622), + .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR + { USB_DEVICE(0x11ba, 0x1003), + .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, +#endif +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 + { USB_DEVICE(0x11ba, 0x1001), + .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, +#endif + { } +}; MODULE_DEVICE_TABLE(usb, pvr2_device_table); diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h index a9c3d99b602..64b467f0637 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -104,9 +104,7 @@ struct pvr2_device_desc { char flag_has_hauppauge_custom_ir; }; -extern const struct pvr2_device_desc pvr2_device_descriptions[]; extern struct usb_device_id pvr2_device_table[]; -extern const unsigned int pvr2_device_count; #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 54d2c4ab7a3..41ae980405e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1813,7 +1813,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, { unsigned int idx,cnt1,cnt2; struct pvr2_hdw *hdw; - unsigned int hdw_type; int valid_std_mask; struct pvr2_ctrl *cptr; const struct pvr2_device_desc *hdw_desc; @@ -1821,13 +1820,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, struct v4l2_queryctrl qctrl; struct pvr2_ctl_info *ciptr; - hdw_type = devid - pvr2_device_table; - if (hdw_type >= pvr2_device_count) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Bogus device type of %u reported",hdw_type); - return NULL; - } - hdw_desc = pvr2_device_descriptions + hdw_type; + hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", -- cgit v1.2.3 From 14d5deba2737c59444e805c10764d58a3d73e9b2 Mon Sep 17 00:00:00 2001 From: Richard Knutsson Date: Sat, 8 Dec 2007 10:35:06 -0300 Subject: V4L/DVB (6776): ivtv: Some general fixes Fix "warning: Using plain integer as NULL pointer". Convert 'x < y ? x : y' to use min() instead. Signed-off-by: Richard Knutsson Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 2 +- drivers/media/video/ivtv/ivtv-irq.c | 4 ++-- drivers/media/video/ivtv/ivtv-streams.c | 4 ++-- drivers/media/video/ivtv/ivtvfb.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 4994dc59d40..2765624b230 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -983,7 +983,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, } itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); - if (itv == 0) { + if (itv == NULL) { spin_unlock(&ivtv_cards_lock); return -ENOMEM; } diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 25b68843a28..edef2a57961 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -698,7 +698,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) ivtv_reset_ir_gpio(itv); } if (val & 0x02) { - itv->video_dec_func(itv, cmd, 0); + itv->video_dec_func(itv, cmd, NULL); } break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index c5ea54e6527..65604dde972 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->sg_pending[idx].dst = buf->dma_handle; s->sg_pending[idx].src = offset; s->sg_pending[idx].size = s->buf_size; - buf->bytesused = (size < s->buf_size) ? size : s->buf_size; + buf->bytesused = min(size, s->buf_size); buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; @@ -736,7 +736,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; } else { - itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2]; + itv->dma_data_req_size = min_t(u32, data[2], 0x10000); itv->dma_data_req_offset = data[1]; s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 3ca2a1a62a7..24d98ecf35a 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ - itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); + itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL); ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - itv->video_dec_func(itv, VIDIOC_STREAMON, 0); + itv->video_dec_func(itv, VIDIOC_STREAMON, NULL); } /* begin_capture */ diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 1a73038ea81..3b23fc05f7c 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1057,7 +1057,7 @@ static int ivtvfb_init_card(struct ivtv *itv) } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); - if (itv->osd_info == 0) { + if (itv->osd_info == NULL) { IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } -- cgit v1.2.3 From 6881647cce09931f3d787ab83b5250436427ceb9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Dec 2007 16:25:41 -0300 Subject: V4L/DVB (6782): tda8290: access frontend structure directly, where possible Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 09efb6a60db..d5517bcf6ff 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -587,7 +587,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if (data == 0x83) { priv->ver |= TDA18271; - tda18271_attach(&t->fe, priv->tda827x_addr, + tda18271_attach(fe, priv->tda827x_addr, priv->i2c_props.adap); } else { if ((data & 0x3c) == 0) @@ -595,14 +595,14 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) else priv->ver |= TDA8275A; - tda827x_attach(&t->fe, priv->tda827x_addr, + tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); } - if (t->fe.ops.tuner_ops.init) - t->fe.ops.tuner_ops.init(&t->fe); + if (fe->ops.tuner_ops.init) + fe->ops.tuner_ops.init(fe); - if (t->fe.ops.tuner_ops.sleep) - t->fe.ops.tuner_ops.sleep(&t->fe); + if (fe->ops.tuner_ops.sleep) + fe->ops.tuner_ops.sleep(fe); ops->i2c_gate_ctrl(fe, 0); -- cgit v1.2.3 From c7919d520f4c9a064ae14bc4dd170c4c12ead2af Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 8 Dec 2007 17:06:30 -0300 Subject: V4L/DVB (6783): tuner: combine set_tv_freq and set_radio_freq into a single set_params method We can tell whether we are tuning television or radio by testing for struct analog_parameters *params->mode == V4L2_TUNER_RADIO There is no longer any need for separate set_tv_freq and set_radio_freq functions in the analog tuner demodulator modules. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 53 ++++++++++++++------------------------ drivers/media/video/tda9887.c | 6 ++--- drivers/media/video/tuner-core.c | 41 +++++++++++++++++------------ drivers/media/video/tuner-driver.h | 4 +-- 4 files changed, 49 insertions(+), 55 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index d5517bcf6ff..245b202560b 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -110,31 +110,32 @@ static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) /*---------------------------------------------------------------------*/ -static void set_audio(struct dvb_frontend *fe) +static void set_audio(struct dvb_frontend *fe, + struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; struct tuner *t = priv->t; char* mode; - if (t->std & V4L2_STD_MN) { + if (params->std & V4L2_STD_MN) { priv->tda8290_easy_mode = 0x01; mode = "MN"; - } else if (t->std & V4L2_STD_B) { + } else if (params->std & V4L2_STD_B) { priv->tda8290_easy_mode = 0x02; mode = "B"; - } else if (t->std & V4L2_STD_GH) { + } else if (params->std & V4L2_STD_GH) { priv->tda8290_easy_mode = 0x04; mode = "GH"; - } else if (t->std & V4L2_STD_PAL_I) { + } else if (params->std & V4L2_STD_PAL_I) { priv->tda8290_easy_mode = 0x08; mode = "I"; - } else if (t->std & V4L2_STD_DK) { + } else if (params->std & V4L2_STD_DK) { priv->tda8290_easy_mode = 0x10; mode = "DK"; - } else if (t->std & V4L2_STD_SECAM_L) { + } else if (params->std & V4L2_STD_SECAM_L) { priv->tda8290_easy_mode = 0x20; mode = "L"; - } else if (t->std & V4L2_STD_SECAM_LC) { + } else if (params->std & V4L2_STD_SECAM_LC) { priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { @@ -145,7 +146,8 @@ static void set_audio(struct dvb_frontend *fe) tuner_dbg("setting tda829x to system %s\n", mode); } -static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) +static void tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; struct tuner *t = priv->t; @@ -172,14 +174,7 @@ static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) pll_stat; int i; - struct analog_parameters params = { - .frequency = freq, - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - - set_audio(fe); + set_audio(fe, params); tuner_dbg("tda827xa config is 0x%02x\n", t->config); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); @@ -200,7 +195,7 @@ static void tda8290_set_freq(struct dvb_frontend *fe, unsigned int freq) tda8290_i2c_bridge(fe, 1); if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + fe->ops.tuner_ops.set_analog_params(fe, params); for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); @@ -363,23 +358,17 @@ static int tda8295_has_signal(struct dvb_frontend *fe) /*---------------------------------------------------------------------*/ -static void tda8295_set_freq(struct dvb_frontend *fe, unsigned int freq) +static void tda8295_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; struct tuner *t = priv->t; unsigned char blanking_mode[] = { 0x1d, 0x00 }; - struct analog_parameters params = { - .frequency = freq, - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - - set_audio(fe); + set_audio(fe, params); - tuner_dbg("%s: freq = %d\n", __FUNCTION__, freq); + tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency); tda8295_power(fe, 1); tda8295_agc1_out(fe, 1); @@ -396,7 +385,7 @@ static void tda8295_set_freq(struct dvb_frontend *fe, unsigned int freq) tda8295_i2c_bridge(fe, 1); if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + fe->ops.tuner_ops.set_analog_params(fe, params); if (priv->cfg.agcf) priv->cfg.agcf(fe); @@ -673,8 +662,7 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) } static struct analog_tuner_ops tda8290_tuner_ops = { - .set_tv_freq = tda8290_set_freq, - .set_radio_freq = tda8290_set_freq, + .set_params = tda8290_set_params, .has_signal = tda8290_has_signal, .standby = tda8290_standby, .release = tda829x_release, @@ -682,8 +670,7 @@ static struct analog_tuner_ops tda8290_tuner_ops = { }; static struct analog_tuner_ops tda8295_tuner_ops = { - .set_tv_freq = tda8295_set_freq, - .set_radio_freq = tda8295_set_freq, + .set_params = tda8295_set_params, .has_signal = tda8295_has_signal, .standby = tda8295_standby, .release = tda829x_release, diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index dfa2964d7ef..d506d4bf825 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -622,7 +622,8 @@ static void tda9887_standby(struct dvb_frontend *fe) tda9887_configure(fe); } -static void tda9887_set_freq(struct dvb_frontend *fe, unsigned int freq) +static void tda9887_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { tda9887_configure(fe); } @@ -634,8 +635,7 @@ static void tda9887_release(struct dvb_frontend *fe) } static struct analog_tuner_ops tda9887_tuner_ops = { - .set_tv_freq = tda9887_set_freq, - .set_radio_freq = tda9887_set_freq, + .set_params = tda9887_set_params, .standby = tda9887_standby, .tuner_status = tda9887_tuner_status, .get_afc = tda9887_get_afc, diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e56a4194148..5f8bffc8209 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -78,23 +78,17 @@ MODULE_LICENSE("GPL"); /* ---------------------------------------------------------------------- */ -static void fe_set_freq(struct dvb_frontend *fe, unsigned int freq) +static void fe_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; struct tuner *t = fe->analog_demod_priv; - struct analog_parameters params = { - .frequency = freq, - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - if (NULL == fe_tuner_ops->set_analog_params) { tuner_warn("Tuner frontend module has no way to set freq\n"); return; } - fe_tuner_ops->set_analog_params(fe, ¶ms); + fe_tuner_ops->set_analog_params(fe, params); } static void fe_release(struct dvb_frontend *fe) @@ -136,8 +130,7 @@ static int fe_has_signal(struct dvb_frontend *fe) static void tuner_status(struct dvb_frontend *fe); static struct analog_tuner_ops tuner_core_ops = { - .set_tv_freq = fe_set_freq, - .set_radio_freq = fe_set_freq, + .set_params = fe_set_params, .standby = fe_standby, .release = fe_release, .has_signal = fe_has_signal, @@ -150,11 +143,17 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_parameters params = { + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if ((NULL == ops) || (NULL == ops->set_tv_freq)) { + if ((NULL == ops) || (NULL == ops->set_params)) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -169,7 +168,9 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - ops->set_tv_freq(&t->fe, freq); + params.frequency = freq; + + ops->set_params(&t->fe, ¶ms); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -177,11 +178,17 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_parameters params = { + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if ((NULL == ops) || (NULL == ops->set_radio_freq)) { + if ((NULL == ops) || (NULL == ops->set_params)) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -196,8 +203,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) else freq = radio_range[1] * 16000; } + params.frequency = freq; - ops->set_radio_freq(&t->fe, freq); + ops->set_params(&t->fe, ¶ms); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -359,8 +367,7 @@ static void set_type(struct i2c_client *c, unsigned int type, ops = t->fe.ops.analog_demod_ops; - if (((NULL == ops) || - ((NULL == ops->set_tv_freq) && (NULL == ops->set_radio_freq))) && + if (((NULL == ops) || (NULL == ops->set_params)) && (fe_tuner_ops->set_analog_params)) { strlcpy(t->i2c->name, fe_tuner_ops->info.name, sizeof(t->i2c->name)); diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index a4db32d97a1..91913ee08a0 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -32,8 +32,8 @@ extern unsigned const int tuner_count; struct tuner; struct analog_tuner_ops { - void (*set_tv_freq)(struct dvb_frontend *fe, unsigned int freq); - void (*set_radio_freq)(struct dvb_frontend *fe, unsigned int freq); + void (*set_params)(struct dvb_frontend *fe, + struct analog_parameters *params); int (*has_signal)(struct dvb_frontend *fe); int (*is_stereo)(struct dvb_frontend *fe); int (*get_afc)(struct dvb_frontend *fe); -- cgit v1.2.3 From fa746aee336fedfe25e6945e5967399966948420 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Dec 2007 05:16:10 -0300 Subject: V4L/DVB (6784): tda8290: prevent possible memory leak Always call tda829x_release if tda829x_attach fails for a reason other than failure to allocate memory for private structure. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 245b202560b..a39cb1f9e87 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -704,7 +704,7 @@ int tda829x_attach(struct tuner *t) } if (tda829x_find_tuner(fe) < 0) - return -EINVAL; + goto fail; if (priv->ver & TDA8290) { tda8290_init_tuner(fe); @@ -717,6 +717,11 @@ int tda829x_attach(struct tuner *t) t->mode = V4L2_TUNER_ANALOG_TV; return 0; + +fail: + tda829x_release(fe); + fe->ops.analog_demod_ops = NULL; + return -EINVAL; } EXPORT_SYMBOL_GPL(tda829x_attach); -- cgit v1.2.3 From ab1660503ac3af7febfcf987648509b484d4feda Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Dec 2007 02:26:48 -0300 Subject: V4L/DVB (6785): tda8290: remove dependency on struct tuner - remove dependency of tda8290 module on struct tuner - move tuner_foo printk macros from tuner-driver.h into tuner-core.c - clean up #includes of tuner-i2c.h / tuner-driver.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 103 ++++++++++++++++++------------------- drivers/media/video/tda8290.h | 24 ++++++--- drivers/media/video/tda9887.c | 1 + drivers/media/video/tuner-core.c | 43 ++++++++++++++-- drivers/media/video/tuner-driver.h | 27 ---------- drivers/media/video/tuner-i2c.h | 2 - include/media/tuner.h | 2 - 7 files changed, 109 insertions(+), 93 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a39cb1f9e87..d0d13bc6125 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -23,12 +23,14 @@ #include #include #include +#include "tuner-driver.h" +#include "tuner-i2c.h" #include "tda8290.h" #include "tda827x.h" #include "tda18271.h" -static int tuner_debug; -module_param_named(debug, tuner_debug, int, 0644); +static int debug; +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); #define PREFIX "tda8290" @@ -50,8 +52,6 @@ struct tda8290_priv { #define TDA18271 16 struct tda827x_config cfg; - - struct tuner *t; }; /*---------------------------------------------------------------------*/ @@ -114,7 +114,6 @@ static void set_audio(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; char* mode; if (params->std & V4L2_STD_MN) { @@ -150,7 +149,6 @@ static void tda8290_set_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; @@ -176,7 +174,8 @@ static void tda8290_set_params(struct dvb_frontend *fe, set_audio(fe, params); - tuner_dbg("tda827xa config is 0x%02x\n", t->config); + if (priv->cfg.config) + tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -362,7 +361,6 @@ static void tda8295_set_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; unsigned char blanking_mode[] = { 0x1d, 0x00 }; @@ -442,13 +440,13 @@ static void tda8295_standby(struct dvb_frontend *fe) static void tda8290_init_if(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((t->config == 1) || (t->config == 2)) + if ((priv->cfg.config) && + ((*priv->cfg.config == 1) || (*priv->cfg.config == 2))) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); @@ -516,7 +514,6 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; - struct tuner *t = priv->t; int i, ret, tuners_found; u32 tuner_addrs; u8 data; @@ -595,29 +592,6 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) ops->i2c_gate_ctrl(fe, 0); - switch (priv->ver) { - case TDA8290 | TDA8275: - strlcpy(t->i2c->name, "tda8290+75", sizeof(t->i2c->name)); - break; - case TDA8295 | TDA8275: - strlcpy(t->i2c->name, "tda8295+75", sizeof(t->i2c->name)); - break; - case TDA8290 | TDA8275A: - strlcpy(t->i2c->name, "tda8290+75a", sizeof(t->i2c->name)); - break; - case TDA8295 | TDA8275A: - strlcpy(t->i2c->name, "tda8295+75a", sizeof(t->i2c->name)); - break; - case TDA8290 | TDA18271: - strlcpy(t->i2c->name, "tda8290+18271", sizeof(t->i2c->name)); - break; - case TDA8295 | TDA18271: - strlcpy(t->i2c->name, "tda8295+18271", sizeof(t->i2c->name)); - break; - default: - return -EINVAL; - } - return 0; } @@ -631,7 +605,7 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props) tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); if (tda8290_id[1] == TDA8290_ID) { - if (tuner_debug) + if (debug) printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", __FUNCTION__, i2c_adapter_id(i2c_props->adap), i2c_props->addr); @@ -651,7 +625,7 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); if (tda8295_id[1] == TDA8295_ID) { - if (tuner_debug) + if (debug) printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n", __FUNCTION__, i2c_adapter_id(i2c_props->adap), i2c_props->addr); @@ -677,21 +651,24 @@ static struct analog_tuner_ops tda8295_tuner_ops = { .i2c_gate_ctrl = tda8295_i2c_bridge, }; -int tda829x_attach(struct tuner *t) +struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, + struct tda829x_config *cfg) { - struct dvb_frontend *fe = &t->fe; struct tda8290_priv *priv = NULL; + char *name; priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; + return NULL; fe->analog_demod_priv = priv; - priv->i2c_props.addr = t->i2c->addr; - priv->i2c_props.adap = t->i2c->adapter; - priv->cfg.config = &t->config; - priv->cfg.tuner_callback = t->tuner_callback; - priv->t = t; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + if (cfg) { + priv->cfg.config = cfg->lna_cfg; + priv->cfg.tuner_callback = cfg->tuner_callback; + } if (tda8290_probe(&priv->i2c_props) == 0) { priv->ver = TDA8290; @@ -706,30 +683,50 @@ int tda829x_attach(struct tuner *t) if (tda829x_find_tuner(fe) < 0) goto fail; + switch (priv->ver) { + case TDA8290 | TDA8275: + name = "tda8290+75"; + break; + case TDA8295 | TDA8275: + name = "tda8295+75"; + break; + case TDA8290 | TDA8275A: + name = "tda8290+75a"; + break; + case TDA8295 | TDA8275A: + name = "tda8295+75a"; + break; + case TDA8290 | TDA18271: + name = "tda8290+18271"; + break; + case TDA8295 | TDA18271: + name = "tda8295+18271"; + break; + default: + goto fail; + } + tuner_info("type set to %s\n", name); + if (priv->ver & TDA8290) { tda8290_init_tuner(fe); tda8290_init_if(fe); } else if (priv->ver & TDA8295) tda8295_init_if(fe); - tuner_info("type set to %s\n", t->i2c->name); - - t->mode = V4L2_TUNER_ANALOG_TV; - - return 0; + return fe; fail: tda829x_release(fe); fe->ops.analog_demod_ops = NULL; - return -EINVAL; + return NULL; } EXPORT_SYMBOL_GPL(tda829x_attach); -int tda829x_probe(struct tuner *t) +int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) { struct tuner_i2c_props i2c_props = { - .adap = t->i2c->adapter, - .addr = t->i2c->addr + .adap = i2c_adap, + .addr = i2c_addr, }; unsigned char soft_reset[] = { 0x00, 0x00 }; diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 3a1f0452061..4c547577e7c 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -18,24 +18,36 @@ #define __TDA8290_H__ #include -#include "tuner-driver.h" +#include "dvb_frontend.h" + +struct tda829x_config +{ + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command, int arg); +}; #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda829x_probe(struct tuner *t); +extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); -extern int tda829x_attach(struct tuner *t); +extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct tda829x_config *cfg); #else -static inline int tda829x_probe(struct tuner *t) +static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return -EINVAL; } -static inline int tda829x_attach(struct tuner *t) +static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + struct tda829x_config *cfg) { printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", __FUNCTION__); - return -EINVAL; + return NULL; } #endif diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d506d4bf825..98d45c4912b 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,6 +9,7 @@ #include #include #include +#include "tuner-i2c.h" #include "tda9887.h" diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5f8bffc8209..0cc190761e2 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -52,7 +52,34 @@ static unsigned int no_autodetect = 0; static unsigned int show_i2c = 0; /* insmod options used at runtime => read/write */ -int tuner_debug = 0; +static int tuner_debug; + +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +/* ------------------------------------------------------------------------ */ static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; @@ -261,6 +288,15 @@ static void attach_simple_tuner(struct tuner *t) simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } +static void attach_tda829x(struct tuner *t) +{ + struct tda829x_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback, + }; + tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); +} + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -303,7 +339,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_PHILIPS_TDA8290: { - tda829x_attach(t); + attach_tda829x(t); break; } case TUNER_TEA5767: @@ -1045,7 +1081,8 @@ static int tuner_probe(struct i2c_client *client) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda829x_probe(t) == 0) { + if (tda829x_probe(t->i2c->adapter, + t->i2c->addr) == 0) { tuner_dbg("tda829x detected\n"); } else { /* Default is being tda9887 */ diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 91913ee08a0..a215161d024 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -24,13 +24,10 @@ #include #include -#include "tuner-i2c.h" #include "dvb_frontend.h" extern unsigned const int tuner_count; -struct tuner; - struct analog_tuner_ops { void (*set_params)(struct dvb_frontend *fe, struct analog_parameters *params); @@ -69,28 +66,4 @@ struct tuner { int (*tuner_callback) (void *dev, int command,int arg); }; -/* ------------------------------------------------------------------------ */ - -#define tuner_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ - } while (0) - -#define tuner_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ - } while (0) - -#define tuner_dbg(fmt, arg...) do { \ - extern int tuner_debug; \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), t->i2c->addr , ##arg); \ - } while (0) - #endif /* __TUNER_DRIVER_H__ */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h index d7cf72c3fd7..de52e8ffd34 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/video/tuner-i2c.h @@ -59,7 +59,6 @@ static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, return (ret == 2) ? ilen : ret; } -#ifndef __TUNER_DRIVER_H__ #define tuner_warn(fmt, arg...) do { \ printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ i2c_adapter_id(priv->i2c_props.adap), \ @@ -84,6 +83,5 @@ static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, i2c_adapter_id(priv->i2c_props.adap), \ priv->i2c_props.addr , ##arg); \ } while (0) -#endif /* __TUNER_DRIVER_H__ */ #endif /* __TUNER_I2C_H__ */ diff --git a/include/media/tuner.h b/include/media/tuner.h index d49392d90e5..97be269afbe 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -24,8 +24,6 @@ #include -extern int tuner_debug; - #define ADDR_UNSET (255) #define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ -- cgit v1.2.3 From a55db8cd7f8a107f3abcb4c803b1873b2be63663 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Dec 2007 13:52:51 -0300 Subject: V4L/DVB (6786): tuner: add struct analog_demod_info to struct analog_tuner_ops Store the analog demodulator name in fe.ops.analog_demod_ops.info.name Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 6 ++++++ drivers/media/video/tda9887.c | 3 +++ drivers/media/video/tuner-core.c | 3 +++ drivers/media/video/tuner-driver.h | 7 +++++++ 4 files changed, 19 insertions(+) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index d0d13bc6125..403f96f998e 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -636,6 +636,9 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) } static struct analog_tuner_ops tda8290_tuner_ops = { + .info = { + .name = "TDA8290", + }, .set_params = tda8290_set_params, .has_signal = tda8290_has_signal, .standby = tda8290_standby, @@ -644,6 +647,9 @@ static struct analog_tuner_ops tda8290_tuner_ops = { }; static struct analog_tuner_ops tda8295_tuner_ops = { + .info = { + .name = "TDA8295", + }, .set_params = tda8295_set_params, .has_signal = tda8295_has_signal, .standby = tda8295_standby, diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 98d45c4912b..8a95f097ba2 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -636,6 +636,9 @@ static void tda9887_release(struct dvb_frontend *fe) } static struct analog_tuner_ops tda9887_tuner_ops = { + .info = { + .name = "TDA9887", + }, .set_params = tda9887_set_params, .standby = tda9887_standby, .tuner_status = tda9887_tuner_status, diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 0cc190761e2..59e67c92575 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -410,6 +410,9 @@ static void set_type(struct i2c_client *c, unsigned int type, t->fe.ops.analog_demod_ops = &tuner_core_ops; t->fe.analog_demod_priv = t; + } else { + strlcpy(t->i2c->name, ops->info.name, + sizeof(t->i2c->name)); } tuner_dbg("type set to %s\n", t->i2c->name); diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index a215161d024..c245f501a31 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -28,7 +28,14 @@ extern unsigned const int tuner_count; +struct analog_demod_info { + char name[128]; +}; + struct analog_tuner_ops { + + struct analog_demod_info info; + void (*set_params)(struct dvb_frontend *fe, struct analog_parameters *params); int (*has_signal)(struct dvb_frontend *fe); -- cgit v1.2.3 From 864a6b813ab6cb69f3552553899ae443329ecfa9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Dec 2007 17:21:54 -0300 Subject: V4L/DVB (6787): tuner: bug-fix: default mode was set to bogus value Fix type inconsistency in t->mode value, causing the following: tuner' 1-0043: freq set: unknown mode: 0x0004! (only visible with tuner debug enabled) Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 59e67c92575..355f9810fac 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1138,11 +1138,11 @@ register_client: /* Sets a default mode */ if (t->mode_mask & T_ANALOG_TV) { - t->mode = T_ANALOG_TV; + t->mode = V4L2_TUNER_ANALOG_TV; } else if (t->mode_mask & T_RADIO) { - t->mode = T_RADIO; + t->mode = V4L2_TUNER_RADIO; } else { - t->mode = T_DIGITAL_TV; + t->mode = V4L2_TUNER_DIGITAL_TV; } set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); list_add_tail(&t->list, &tuner_list); -- cgit v1.2.3 From 2dcf84b36c23a2c34207ab650071f9ee33d3c4a2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 10 Dec 2007 11:12:59 -0300 Subject: V4L/DVB (6788): tda8290: fix codingstyle, open brace following struct on the same line Fix codingstyle issue discovered after using new checkpatch.pl ERROR: open brace '{' following struct go on the same line 396: FILE: linux/drivers/media/video/tda8290.h:24: +struct tda829x_config +{ Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 4c547577e7c..7bce03183d0 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -20,8 +20,7 @@ #include #include "dvb_frontend.h" -struct tda829x_config -{ +struct tda829x_config { unsigned int *lna_cfg; int (*tuner_callback) (void *dev, int command, int arg); }; -- cgit v1.2.3 From bd2b19a78cb215b67d8d016ea6607f04e48fa523 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 10 Dec 2007 16:08:25 -0300 Subject: V4L/DVB (6789): tuner: use char *name instead of 128 byte fixed array for demod info Don't waste 128 bytes of memory for a name that might not actually need it. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index c245f501a31..65ced435018 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -29,7 +29,7 @@ extern unsigned const int tuner_count; struct analog_demod_info { - char name[128]; + char *name; }; struct analog_tuner_ops { -- cgit v1.2.3 From bfb12e38a8f828bb6394fd4f18010bad86832623 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Dec 2007 11:51:53 -0300 Subject: V4L/DVB (6791): Rename all vidioc_ to saa7134_ Some functions are used also by saa7134-empress, and need to be exported. To avoid namespace confusion, rename all of them to saa7134_ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 178 ++++++++++++++-------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 043e1396857..6f9f9dbdfdd 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1123,7 +1123,7 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -static int vidioc_g_ctrl(struct file *file, void *priv, +static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) { struct saa7134_fh *fh = priv; @@ -1173,7 +1173,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, return 0; } -static int vidioc_s_ctrl(struct file *file, void *f, +static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { const struct v4l2_queryctrl* ctrl; @@ -1507,7 +1507,7 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static int vidioc_try_get_set_fmt_vbi(struct file *file, void *priv, +static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1527,7 +1527,7 @@ static int vidioc_try_get_set_fmt_vbi(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_cap(struct file *file, void *priv, +static int saa7134_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1543,7 +1543,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_overlay(struct file *file, void *priv, +static int saa7134_g_fmt_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1557,7 +1557,7 @@ static int vidioc_g_fmt_overlay(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap(struct file *file, void *priv, +static int saa7134_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1608,7 +1608,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_overlay(struct file *file, void *priv, +static int saa7134_try_fmt_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1622,13 +1622,13 @@ static int vidioc_try_fmt_overlay(struct file *file, void *priv, return verify_preview(dev, &f->fmt.win); } -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int saa7134_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; int err; - err = vidioc_try_fmt_cap(file, priv, f); + err = saa7134_try_fmt_cap(file, priv, f); if (0 != err) return err; @@ -1639,7 +1639,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_overlay(struct file *file, void *priv, +static int saa7134_s_fmt_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_fh *fh = priv; @@ -1680,7 +1680,7 @@ static int vidioc_s_fmt_overlay(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, +static int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { const struct v4l2_queryctrl *ctrl; @@ -1695,7 +1695,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, return 0; } -static int vidioc_enum_input(struct file *file, void *priv, +static int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct saa7134_fh *fh = priv; @@ -1729,7 +1729,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return 0; } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; @@ -1738,7 +1738,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int saa7134_s_input(struct file *file, void *priv, unsigned int i) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; @@ -1758,7 +1758,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_querycap(struct file *file, void *priv, +static int saa7134_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct saa7134_fh *fh = priv; @@ -1785,7 +1785,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * id) +static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; @@ -1847,7 +1847,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * id) return 0; } -static int vidioc_cropcap(struct file *file, void *priv, +static int saa7134_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap) { struct saa7134_fh *fh = priv; @@ -1871,7 +1871,7 @@ static int vidioc_cropcap(struct file *file, void *priv, return 0; } -static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; @@ -1883,7 +1883,7 @@ static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) return 0; } -static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; @@ -1920,7 +1920,7 @@ static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, +static int saa7134_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct saa7134_fh *fh = priv; @@ -1949,7 +1949,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, +static int saa7134_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct saa7134_fh *fh = priv; @@ -1971,7 +1971,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, return 0; } -static int vidioc_g_frequency(struct file *file, void *priv, +static int saa7134_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct saa7134_fh *fh = priv; @@ -1983,7 +1983,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, +static int saa7134_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct saa7134_fh *fh = priv; @@ -2010,18 +2010,18 @@ static int vidioc_s_frequency(struct file *file, void *priv, return 0; } -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { strcpy(a->name, "audio"); return 0; } -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { return 0; } -static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; @@ -2030,7 +2030,7 @@ static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) return 0; } -static int vidioc_s_priority(struct file *file, void *f, +static int saa7134_s_priority(struct file *file, void *f, enum v4l2_priority prio) { struct saa7134_fh *fh = f; @@ -2039,7 +2039,7 @@ static int vidioc_s_priority(struct file *file, void *f, return v4l2_prio_change(&dev->prio, &fh->prio, prio); } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, +static int saa7134_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= FORMATS) @@ -2053,7 +2053,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_overlay(struct file *file, void *priv, +static int saa7134_enum_fmt_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (saa7134_no_overlay > 0) { @@ -2072,7 +2072,7 @@ static int vidioc_enum_fmt_overlay(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_vbi(struct file *file, void *priv, +static int saa7134_enum_fmt_vbi(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (0 != f->index) @@ -2084,7 +2084,7 @@ static int vidioc_enum_fmt_vbi(struct file *file, void *priv, return 0; } -static int vidioc_g_fbuf(struct file *file, void *f, +static int saa7134_g_fbuf(struct file *file, void *f, struct v4l2_framebuffer *fb) { struct saa7134_fh *fh = f; @@ -2096,7 +2096,7 @@ static int vidioc_g_fbuf(struct file *file, void *f, return 0; } -static int vidioc_s_fbuf(struct file *file, void *f, +static int saa7134_s_fbuf(struct file *file, void *f, struct v4l2_framebuffer *fb) { struct saa7134_fh *fh = f; @@ -2121,7 +2121,7 @@ static int vidioc_s_fbuf(struct file *file, void *f, return 0; } -static int vidioc_overlay(struct file *file, void *f, unsigned int on) +static int saa7134_overlay(struct file *file, void *f, unsigned int on) { struct saa7134_fh *fh = f; struct saa7134_dev *dev = fh->dev; @@ -2158,34 +2158,34 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) } #endif -static int vidioc_reqbufs(struct file *file, void *priv, +static int saa7134_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { struct saa7134_fh *fh = priv; return videobuf_reqbufs(saa7134_queue(fh), p); } -static int vidioc_querybuf(struct file *file, void *priv, +static int saa7134_querybuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct saa7134_fh *fh = priv; return videobuf_querybuf(saa7134_queue(fh), b); } -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct saa7134_fh *fh = priv; return videobuf_qbuf(saa7134_queue(fh), b); } -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct saa7134_fh *fh = priv; return videobuf_dqbuf(saa7134_queue(fh), b, file->f_flags & O_NONBLOCK); } -static int vidioc_streamon(struct file *file, void *priv, +static int saa7134_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct saa7134_fh *fh = priv; @@ -2198,7 +2198,7 @@ static int vidioc_streamon(struct file *file, void *priv, return videobuf_streamon(saa7134_queue(fh)); } -static int vidioc_streamoff(struct file *file, void *priv, +static int saa7134_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { int err; @@ -2213,7 +2213,7 @@ static int vidioc_streamoff(struct file *file, void *priv, return 0; } -static int vidioc_g_parm(struct file *file, void *fh, +static int saa7134_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm) { return 0; @@ -2358,50 +2358,50 @@ struct video_device saa7134_video_template = VID_TYPE_CLIPPING|VID_TYPE_SCALES, .fops = &video_fops, .minor = -1, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, - .vidioc_enum_fmt_overlay = vidioc_enum_fmt_overlay, - .vidioc_g_fmt_overlay = vidioc_g_fmt_overlay, - .vidioc_try_fmt_overlay = vidioc_try_fmt_overlay, - .vidioc_s_fmt_overlay = vidioc_s_fmt_overlay, - .vidioc_enum_fmt_vbi = vidioc_enum_fmt_vbi, - .vidioc_g_fmt_vbi = vidioc_try_get_set_fmt_vbi, - .vidioc_try_fmt_vbi = vidioc_try_get_set_fmt_vbi, - .vidioc_s_fmt_vbi = vidioc_try_get_set_fmt_vbi, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_querycap = saa7134_querycap, + .vidioc_enum_fmt_cap = saa7134_enum_fmt_cap, + .vidioc_g_fmt_cap = saa7134_g_fmt_cap, + .vidioc_try_fmt_cap = saa7134_try_fmt_cap, + .vidioc_s_fmt_cap = saa7134_s_fmt_cap, + .vidioc_enum_fmt_overlay = saa7134_enum_fmt_overlay, + .vidioc_g_fmt_overlay = saa7134_g_fmt_overlay, + .vidioc_try_fmt_overlay = saa7134_try_fmt_overlay, + .vidioc_s_fmt_overlay = saa7134_s_fmt_overlay, + .vidioc_enum_fmt_vbi = saa7134_enum_fmt_vbi, + .vidioc_g_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_try_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_s_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_g_audio = saa7134_g_audio, + .vidioc_s_audio = saa7134_s_audio, + .vidioc_cropcap = saa7134_cropcap, + .vidioc_reqbufs = saa7134_reqbufs, + .vidioc_querybuf = saa7134_querybuf, + .vidioc_qbuf = saa7134_qbuf, + .vidioc_dqbuf = saa7134_dqbuf, + .vidioc_s_std = saa7134_s_std, + .vidioc_enum_input = saa7134_enum_input, + .vidioc_g_input = saa7134_g_input, + .vidioc_s_input = saa7134_s_input, + .vidioc_queryctrl = saa7134_queryctrl, + .vidioc_g_ctrl = saa7134_g_ctrl, + .vidioc_s_ctrl = saa7134_s_ctrl, + .vidioc_streamon = saa7134_streamon, + .vidioc_streamoff = saa7134_streamoff, + .vidioc_g_tuner = saa7134_g_tuner, + .vidioc_s_tuner = saa7134_s_tuner, #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif - .vidioc_g_crop = vidioc_g_crop, - .vidioc_s_crop = vidioc_s_crop, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_fbuf = vidioc_s_fbuf, - .vidioc_overlay = vidioc_overlay, - .vidioc_g_priority = vidioc_g_priority, - .vidioc_s_priority = vidioc_s_priority, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_crop = saa7134_g_crop, + .vidioc_s_crop = saa7134_s_crop, + .vidioc_g_fbuf = saa7134_g_fbuf, + .vidioc_s_fbuf = saa7134_s_fbuf, + .vidioc_overlay = saa7134_overlay, + .vidioc_g_priority = saa7134_g_priority, + .vidioc_s_priority = saa7134_s_priority, + .vidioc_g_parm = saa7134_g_parm, + .vidioc_g_frequency = saa7134_g_frequency, + .vidioc_s_frequency = saa7134_s_frequency, .tvnorms = SAA7134_NORMS, .current_norm = V4L2_STD_PAL, }; @@ -2416,10 +2416,10 @@ struct video_device saa7134_vbi_template = struct video_device saa7134_radio_template = { - .name = "saa7134-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, + .name = "saa7134-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .minor = -1, .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -2430,10 +2430,10 @@ struct video_device saa7134_radio_template = .vidioc_s_std = radio_s_std, .vidioc_queryctrl = radio_queryctrl, .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_ctrl = saa7134_g_ctrl, + .vidioc_s_ctrl = saa7134_s_ctrl, + .vidioc_g_frequency = saa7134_g_frequency, + .vidioc_s_frequency = saa7134_s_frequency, }; int saa7134_video_init1(struct saa7134_dev *dev) -- cgit v1.2.3 From a9622391acbcdb124b55eb674dc5196eb55dc105 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Dec 2007 12:05:06 -0300 Subject: V4L/DVB (6792): Fix VBI support VBI were broken, since there weren't any function handlers for it. This patch fixes it, by removing the vbi_template, using, instead video_template. This also saves some space at the data segment. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 4 +++- drivers/media/video/saa7134/saa7134-video.c | 8 -------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 92c48ee1591..52baa4f7f7d 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1053,7 +1053,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s: registered device video%d [v4l2]\n", dev->name,dev->video_dev->minor & 0x1f); - dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi"); + dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); + dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT; + err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 6f9f9dbdfdd..6a29b75beaa 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2406,14 +2406,6 @@ struct video_device saa7134_video_template = .current_norm = V4L2_STD_PAL, }; -struct video_device saa7134_vbi_template = -{ - .name = "saa7134-vbi", - .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, - .fops = &video_fops, - .minor = -1, -}; - struct video_device saa7134_radio_template = { .name = "saa7134-radio", -- cgit v1.2.3 From 2c10e8a8985e41addbbbe54b403418c27462f854 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Dec 2007 12:56:23 -0300 Subject: V4L/DVB (6793): Convert saa7134-empress to video_ioctl2 saa7134 were converted to video_ioctl2, but saa7134_empress weren't. This broke saa7134-empress, since it were dependent of saa7134_common_ioctl. With the conversion, the module had a size decrease of 436 bytes on x86_64: text data bss dec hex filename 5196 4912 4 10112 2780 old/saa7134-empress.ko 4760 4912 4 9676 25cc new/saa7134-empress.ko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-empress.c | 293 +++++++++++++++----------- drivers/media/video/saa7134/saa7134-video.c | 15 +- drivers/media/video/saa7134/saa7134.h | 13 +- 3 files changed, 183 insertions(+), 138 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 9322f44865b..b1b01fa8672 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -161,152 +161,176 @@ ts_mmap(struct file *file, struct vm_area_struct * vma) * video_generic_ioctl (and maybe others). userspace * copying is done already, arg is a kernel pointer. */ -static int ts_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) + +static int empress_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { - struct saa7134_dev *dev = file->private_data; - struct v4l2_ext_controls *ctrls = arg; - - if (debug > 1) - v4l_print_ioctl(dev->name,cmd); - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - return 0; - } + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + return 0; +} - /* --- input switching --------------------------------------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; +static int empress_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; - if (i->index != 0) - return -EINVAL; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,"CCIR656"); - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = 0; - return 0; - } - case VIDIOC_S_INPUT: - { - int *i = arg; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, "CCIR656"); - if (*i != 0) - return -EINVAL; - return 0; - } - /* --- capture ioctls ---------------------------------------- */ - - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - int index; - - index = f->index; - if (index != 0) - return -EINVAL; - - memset(f,0,sizeof(*f)); - f->index = index; - strlcpy(f->description, "MPEG TS", sizeof(f->description)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->pixelformat = V4L2_PIX_FMT_MPEG; - return 0; - } + return 0; +} - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; +static int empress_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} - memset(f,0,sizeof(*f)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +static int empress_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; - saa7134_i2c_call_clients(dev, cmd, arg); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - return 0; - } + return 0; +} - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; +static int empress_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + strlcpy(f->description, "MPEG TS", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_MPEG; - saa7134_i2c_call_clients(dev, cmd, arg); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE* dev->ts.nr_packets; - return 0; - } + return 0; +} - case VIDIOC_REQBUFS: - return videobuf_reqbufs(&dev->empress_tsq,arg); +static int empress_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - case VIDIOC_QUERYBUF: - return videobuf_querybuf(&dev->empress_tsq,arg); + saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f); - case VIDIOC_QBUF: - return videobuf_qbuf(&dev->empress_tsq,arg); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - case VIDIOC_DQBUF: - return videobuf_dqbuf(&dev->empress_tsq,arg, - file->f_flags & O_NONBLOCK); + return 0; +} - case VIDIOC_STREAMON: - return videobuf_streamon(&dev->empress_tsq); +static int empress_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - case VIDIOC_STREAMOFF: - return videobuf_streamoff(&dev->empress_tsq); + saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f); - case VIDIOC_QUERYCTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - return saa7134_common_ioctl(dev, cmd, arg); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - case VIDIOC_S_EXT_CTRLS: - /* count == 0 is abused in saa6752hs.c, so that special - case is handled here explicitly. */ - if (ctrls->count == 0) - return 0; - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg); - ts_init_encoder(dev); - return 0; - case VIDIOC_G_EXT_CTRLS: - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg); + return 0; +} + + +static int empress_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_reqbufs(&dev->empress_tsq, p); +} + +static int empress_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_querybuf(&dev->empress_tsq, b); +} + +static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_qbuf(&dev->empress_tsq, b); +} + +static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_dqbuf(&dev->empress_tsq, b, + file->f_flags & O_NONBLOCK); +} + +static int empress_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_streamon(&dev->empress_tsq); +} + +static int empress_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_streamoff(&dev->empress_tsq); +} + +static int empress_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + /* count == 0 is abused in saa6752hs.c, so that special + case is handled here explicitly. */ + if (ctrls->count == 0) return 0; - default: - return -ENOIOCTLCMD; - } + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls); + ts_init_encoder(dev); + return 0; } -static int ts_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int empress_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) { - return video_usercopy(inode, file, cmd, arg, ts_do_ioctl); + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls); + + return 0; } static const struct file_operations ts_fops = @@ -317,7 +341,7 @@ static const struct file_operations ts_fops = .read = ts_read, .poll = ts_poll, .mmap = ts_mmap, - .ioctl = ts_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, }; @@ -330,6 +354,29 @@ static struct video_device saa7134_empress_template = .type2 = 0 /* FIXME */, .fops = &ts_fops, .minor = -1, + + .vidioc_querycap = empress_querycap, + .vidioc_enum_fmt_cap = empress_enum_fmt_cap, + .vidioc_s_fmt_cap = empress_s_fmt_cap, + .vidioc_g_fmt_cap = empress_g_fmt_cap, + .vidioc_reqbufs = empress_reqbufs, + .vidioc_querybuf = empress_querybuf, + .vidioc_qbuf = empress_qbuf, + .vidioc_dqbuf = empress_dqbuf, + .vidioc_streamon = empress_streamon, + .vidioc_streamoff = empress_streamoff, + .vidioc_s_ext_ctrls = empress_s_ext_ctrls, + .vidioc_g_ext_ctrls = empress_g_ext_ctrls, + .vidioc_enum_input = empress_enum_input, + .vidioc_g_input = empress_g_input, + .vidioc_s_input = empress_s_input, + + .vidioc_queryctrl = saa7134_queryctrl, + .vidioc_g_ctrl = saa7134_g_ctrl, + .vidioc_s_ctrl = saa7134_s_ctrl, + + .tvnorms = SAA7134_NORMS, + .current_norm = V4L2_STD_PAL, }; static void empress_signal_update(struct work_struct *work) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 6a29b75beaa..9705f1f3950 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -217,12 +217,6 @@ static struct saa7134_format formats[] = { .vbi_v_start_1 = 273, \ .src_timing = 7 -#define SAA7134_NORMS \ - V4L2_STD_PAL | V4L2_STD_PAL_N | \ - V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ - V4L2_STD_NTSC | V4L2_STD_PAL_M | \ - V4L2_STD_PAL_60 - static struct saa7134_tvnorm tvnorms[] = { { .name = "PAL", /* autodetect */ @@ -1123,8 +1117,7 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -static int saa7134_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) +int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; @@ -1173,8 +1166,7 @@ static int saa7134_g_ctrl(struct file *file, void *priv, return 0; } -static int saa7134_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) +int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { const struct v4l2_queryctrl* ctrl; struct saa7134_fh *fh = f; @@ -1680,8 +1672,7 @@ static int saa7134_s_fmt_overlay(struct file *file, void *priv, return 0; } -static int saa7134_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) +int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { const struct v4l2_queryctrl *ctrl; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 8fb95094ba8..3e77aeb7974 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -566,6 +566,12 @@ struct saa7134_dev { #define saa_wait(us) { udelay(us); } +#define SAA7134_NORMS (\ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60) + /* ----------------------------------------------------------- */ /* saa7134-core.c */ @@ -629,12 +635,13 @@ extern unsigned int video_debug; extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; +int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c); +int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c); +int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); + int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); -int saa7134_common_ioctl(struct saa7134_dev *dev, - unsigned int cmd, void *arg); - int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); void saa7134_irq_video_signalchange(struct saa7134_dev *dev); -- cgit v1.2.3 From f6e90a66cde270cd6cc7aa1f4f0650930aa7f6bc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Dec 2007 15:01:57 -0300 Subject: V4L/DVB (6795): Add EXPORT_SYMBOL_GPL to the saa7134 video control routines Those newer functions are used by saa7134-empress. Adds export for them: +EXPORT_SYMBOL_GPL(saa7134_g_ctrl); +EXPORT_SYMBOL_GPL(saa7134_s_ctrl); +EXPORT_SYMBOL_GPL(saa7134_queryctrl); Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-video.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9705f1f3950..1184d359e84 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1165,6 +1165,7 @@ int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) } return 0; } +EXPORT_SYMBOL_GPL(saa7134_g_ctrl); int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { @@ -1278,6 +1279,7 @@ error: mutex_unlock(&dev->lock); return err; } +EXPORT_SYMBOL_GPL(saa7134_s_ctrl); /* ------------------------------------------------------------------ */ @@ -1685,6 +1687,7 @@ int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) *c = (NULL != ctrl) ? *ctrl : no_ctrl; return 0; } +EXPORT_SYMBOL_GPL(saa7134_queryctrl); static int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i) -- cgit v1.2.3 From 7206abbc2d19b6846b879fb266672b40da9961cb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Dec 2007 22:13:01 -0300 Subject: V4L/DVB (6800): tda18271: use an enum rather than an integer to store analog / digital state Use an enum rather than an integer #define to store analog / digital state. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index aecc0a5ac7b..dbf0f619a90 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -31,14 +31,16 @@ MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); /*---------------------------------------------------------------------*/ -#define TDA18271_ANALOG 0 -#define TDA18271_DIGITAL 1 +enum tda18271_mode { + TDA18271_ANALOG, + TDA18271_DIGITAL, +}; struct tda18271_priv { u8 i2c_addr; struct i2c_adapter *i2c_adap; unsigned char tda18271_regs[TDA18271_NUM_REGS]; - int mode; + enum tda18271_mode mode; u32 frequency; u32 bandwidth; -- cgit v1.2.3 From e435f95ce6468f0240f050e14c9eac93e2fe7e71 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 9 Dec 2007 22:23:30 -0300 Subject: V4L/DVB (6801): tda18271: pass i2c gate configuration into tda18271_attach() If we pass TDA18271_GATE_DIGITAL into tda18271_attach(), it will always try to use the digital demodulator's i2c gate. If we pass TDA18271_GATE_ANALOG into tda18271_attach(), it will always try to use the analog demodulator's i2c gate. If we pass TDA18271_GATE_AUTO into tda18271_attach(), it will try to use the analog demodulator's i2c gate when tuning in analog mode, and it will try to use the digital demodulator's i2c gate when tuning in digital mode. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 34 +++++++++++++++++++++++++++---- drivers/media/dvb/frontends/tda18271.h | 12 +++++++++-- drivers/media/video/tda8290.c | 3 ++- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index dbf0f619a90..28c63fd4493 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -40,7 +40,9 @@ struct tda18271_priv { u8 i2c_addr; struct i2c_adapter *i2c_adap; unsigned char tda18271_regs[TDA18271_NUM_REGS]; + enum tda18271_mode mode; + enum tda18271_i2c_gate gate; u32 frequency; u32 bandwidth; @@ -50,17 +52,39 @@ static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct tda18271_priv *priv = fe->tuner_priv; struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + enum tda18271_i2c_gate gate; int ret = 0; - switch (priv->mode) { - case TDA18271_ANALOG: + switch (priv->gate) { + case TDA18271_GATE_DIGITAL: + case TDA18271_GATE_ANALOG: + gate = priv->gate; + break; + case TDA18271_GATE_AUTO: + default: + switch (priv->mode) { + case TDA18271_DIGITAL: + gate = TDA18271_GATE_DIGITAL; + break; + case TDA18271_ANALOG: + default: + gate = TDA18271_GATE_ANALOG; + break; + } + } + + switch (gate) { + case TDA18271_GATE_ANALOG: if (ops && ops->i2c_gate_ctrl) ret = ops->i2c_gate_ctrl(fe, enable); break; - case TDA18271_DIGITAL: + case TDA18271_GATE_DIGITAL: if (fe->ops.i2c_gate_ctrl) ret = fe->ops.i2c_gate_ctrl(fe, enable); break; + default: + ret = -EINVAL; + break; } return ret; @@ -713,7 +737,8 @@ static struct dvb_tuner_ops tda18271_tuner_ops = { }; struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c) + struct i2c_adapter *i2c, + enum tda18271_i2c_gate gate) { struct tda18271_priv *priv = NULL; @@ -724,6 +749,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, priv->i2c_addr = addr; priv->i2c_adap = i2c; + priv->gate = gate; memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, sizeof(struct dvb_tuner_ops)); diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index a8a19a7197f..d8400337263 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -24,13 +24,21 @@ #include #include "dvb_frontend.h" +enum tda18271_i2c_gate { + TDA18271_GATE_AUTO = 0, + TDA18271_GATE_ANALOG, + TDA18271_GATE_DIGITAL, +}; + #if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c); + struct i2c_adapter *i2c, + enum tda18271_i2c_gate gate); #else static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c) + struct i2c_adapter *i2c, + enum tda18271_i2c_gate gate); { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 403f96f998e..a451d9480c1 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -574,7 +574,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if (data == 0x83) { priv->ver |= TDA18271; tda18271_attach(fe, priv->tda827x_addr, - priv->i2c_props.adap); + priv->i2c_props.adap, + TDA18271_GATE_ANALOG); } else { if ((data & 0x3c) == 0) priv->ver |= TDA8275; -- cgit v1.2.3 From 225ba900886f6d2d3447dd5bfdb95217f0619755 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Dec 2007 21:46:26 -0300 Subject: V4L/DVB (6804): __videobuf_read_start is static Thanks to Jean Delvare for pointing this. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 9662d1e40a0..43fe3f78c8d 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -812,7 +812,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Locking: Caller holds q->lock */ -int __videobuf_read_start(struct videobuf_queue *q) +static int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags = 0; -- cgit v1.2.3 From 63736784f73e7c38b2bad5ed3ed783dc102ba01e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Dec 2007 06:34:12 -0300 Subject: V4L/DVB (6805): video std is a bitmask. Better to print in hexa Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 9611c399028..28655f8983c 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, *id = vfd->current_norm; - dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); + dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); ret=0; break; @@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *id = arg,norm; - dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); + dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); norm = (*id) & vfd->tvnorms; if ( vfd->tvnorms && !norm) /* Check if std is supported */ @@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; ret=vfd->vidioc_querystd(file, fh, arg); if (!ret) - dbgarg (cmd, "detected std=%Lu\n", + dbgarg (cmd, "detected std=%08Lx\n", (unsigned long long)*p); break; } @@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!ret) dbgarg (cmd, "index=%d, name=%s, type=%d, " "audioset=%d, " - "tuner=%d, std=%Ld, status=%d\n", + "tuner=%d, std=%08Lx, status=%d\n", p->index,p->name,p->type,p->audioset, p->tuner, (unsigned long long)p->std, -- cgit v1.2.3 From 784c668b24dede8acd7044b490a538b5b6cd6b20 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Dec 2007 06:35:26 -0300 Subject: V4L/DVB (6806): Allow emulating changes of video std by vivi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 2bbefd92625..0b5c1426bb9 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -919,7 +919,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_NTSC_M; + inp->std = V4L2_STD_525_60; strcpy(inp->name, "Camera"); return (0); @@ -1172,7 +1172,7 @@ static struct video_device vivi_template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif - .tvnorms = V4L2_STD_NTSC_M, + .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M, }; /* ----------------------------------------------------------------- -- cgit v1.2.3 From 8996b3f3cfa9d21ba9ed31a116d5066e38827878 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Dec 2007 06:36:22 -0300 Subject: V4L/DVB (6807): fix debug enable The changes at vivi_template make debug option to not work properly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 0b5c1426bb9..889e6611e03 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1250,7 +1250,7 @@ MODULE_PARM_DESC(video_nr, "video iminor start number"); module_param(n_devs, int, 0); MODULE_PARM_DESC(n_devs, "number of video devices to create"); -module_param_named(debug, vivi.debug, int, 0644); +module_param_named(debug, vivi_template.debug, int, 0444); MODULE_PARM_DESC(debug, "activates debug info"); module_param(vid_limit, int, 0644); -- cgit v1.2.3 From 39b43b1a61f3c4b540b024843e592b14533aa961 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 12 Dec 2007 19:27:57 -0300 Subject: V4L/DVB (6808): git-dvb: fix build in drivers/media/dvb/frontends/tda18271.h Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index d8400337263..b98a9331c59 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -38,7 +38,7 @@ extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, - enum tda18271_i2c_gate gate); + enum tda18271_i2c_gate gate) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; -- cgit v1.2.3 From 7cd355e7c0c02e499784c77e88720f7cc8f98473 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 12 Dec 2007 19:55:49 -0300 Subject: V4L/DVB (6809): git-dvb: drivers/media/video/et61x251/et61x251_core.c: fix warnings drivers/media/video/et61x251/et61x251_core.c:390: warning: 'et61x251_i2c_read' defined but not used drivers/media/video/et61x251/et61x251_core.c:397: warning: 'et61x251_i2c_write' defined but not used Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/et61x251/et61x251_core.c | 155 +++++++++++++-------------- 1 file changed, 77 insertions(+), 78 deletions(-) diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 38d2ad0aade..06b6a3ae06c 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -268,72 +268,6 @@ et61x251_i2c_wait(struct et61x251_device* cam, } -static int et61x251_i2c_try_read(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, - u8 address) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x10; - data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - if (err) - DBG(3, "I2C read failed for %s image sensor", sensor->name); - - PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); - - return err ? -1 : (int)data[0]; -} - - -static int et61x251_i2c_try_write(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, - u8 address, u8 value) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x12; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - data[0] = value; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); - - return err ? -1 : 0; -} - - int et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, @@ -386,18 +320,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, } -static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) -{ - return et61x251_i2c_try_read(cam, &cam->sensor, address); -} - - -static int et61x251_i2c_write(struct et61x251_device* cam, - u8 address, u8 value) -{ - return et61x251_i2c_try_write(cam, &cam->sensor, address, value); -} - /*****************************************************************************/ static void et61x251_urb_complete(struct urb *urb) @@ -675,6 +597,83 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam) /*****************************************************************************/ #ifdef CONFIG_VIDEO_ADV_DEBUG + +static int et61x251_i2c_try_read(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x10; + data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, sensor); + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, + 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + if (err) + DBG(3, "I2C read failed for %s image sensor", sensor->name); + + PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); + + return err ? -1 : (int)data[0]; +} + + +static int et61x251_i2c_try_write(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address, u8 value) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x12; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + data[0] = value; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, sensor); + + if (err) + DBG(3, "I2C write failed for %s image sensor", sensor->name); + + PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); + + return err ? -1 : 0; +} + +static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) +{ + return et61x251_i2c_try_read(cam, &cam->sensor, address); +} + +static int et61x251_i2c_write(struct et61x251_device* cam, + u8 address, u8 value) +{ + return et61x251_i2c_try_write(cam, &cam->sensor, address, value); +} + static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) { char str[5]; -- cgit v1.2.3 From 0991112c1c4625323df8a582de1b2f8609922248 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 12 Dec 2007 18:22:48 -0300 Subject: V4L/DVB (6810): media: video: usbvision: add mutex_unlock() to error paths There are a few error paths which don't unlock the usbvision->lock. So I've added mutex_unlock() calls to fix those paths. Signed-off-by: Daniel Walker Signed-off-by: Andrew Morton Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-video.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index e34f311124e..d929ced58ec 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1290,6 +1290,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) errCode = usbvision_set_alternate(usbvision); if (errCode < 0) { usbvision->last_error = errCode; + mutex_unlock(&usbvision->lock); return -EBUSY; } @@ -1807,6 +1808,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->num_alt,GFP_KERNEL); if (usbvision->alt_max_pkt_size == NULL) { err("usbvision: out of memory!\n"); + mutex_unlock(&usbvision->lock); return -ENOMEM; } -- cgit v1.2.3 From 544e6175330c86ad87abeeb1b048f56bafd96c31 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 12 Dec 2007 18:25:23 -0300 Subject: V4L/DVB (6811): media-video-usbvision-add-mutex_unlock-to-error-paths-fix Signed-off-by: Andrew Morton Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index d929ced58ec..92e72910792 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1290,8 +1290,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) errCode = usbvision_set_alternate(usbvision); if (errCode < 0) { usbvision->last_error = errCode; - mutex_unlock(&usbvision->lock); - return -EBUSY; + errCode = -EBUSY; + goto out; } // If so far no errors then we shall start the radio @@ -1308,6 +1308,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } +out: mutex_unlock(&usbvision->lock); return errCode; } -- cgit v1.2.3 From 1fe934ddfc8e6e5663c0308ae216219be87b8d4f Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 12 Dec 2007 18:37:54 -0300 Subject: V4L/DVB (6812): media: video: usbvision: remove ctrlUrbLock The ctrlUrbLock has all it's users commented out, and so it's unused. This patch removes it. Signed-off-by: Daniel Walker Signed-off-by: Andrew Morton Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 3 --- drivers/media/video/usbvision/usbvision-video.c | 1 - drivers/media/video/usbvision/usbvision.h | 1 - 3 files changed, 5 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 2038d409f1d..9e404b87d00 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -1561,13 +1561,10 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address, if (len > 8) { return -EFAULT; } -// down(&usbvision->ctrlUrbLock); if (usbvision->ctrlUrbBusy) { -// up(&usbvision->ctrlUrbLock); return -EBUSY; } usbvision->ctrlUrbBusy = 1; -// up(&usbvision->ctrlUrbLock); usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 92e72910792..b52b826a30b 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1651,7 +1651,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) goto err_exit; } init_waitqueue_head(&usbvision->ctrlUrb_wq); - init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ usbvision_init_powerOffTimer(usbvision); diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index dd80a98780f..20d7ec62499 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -370,7 +370,6 @@ struct usb_usbvision { int ctrlUrbBusy; struct usb_ctrlrequest ctrlUrbSetup; wait_queue_head_t ctrlUrb_wq; // Processes waiting - struct semaphore ctrlUrbLock; /* configuration part */ int have_tuner; -- cgit v1.2.3 From 6c2f990105acd360e83b95b41c60ed8bf25e67fe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Dec 2007 13:30:14 -0300 Subject: V4L/DVB (6815): Fix vivi internal debug messages Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 109 ++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 889e6611e03..0346d1af3e6 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -54,7 +54,6 @@ /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ -static struct video_device vivi; /* Video device */ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ static int n_devs = 1; /* Number of virtual devices */ @@ -110,9 +109,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = { static int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; -#define dprintk(level, fmt, arg...) \ +#define dprintk(dev, level, fmt, arg...) \ do { \ - if (vivi.debug >= (level)) \ + if (dev->vfd->debug >= (level)) \ printk(KERN_DEBUG "vivi: " fmt , ## arg); \ } while (0) @@ -338,7 +337,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) dev->timestr); /* FIXME: replacing to __copy_to_user */ if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0) - dprintk(2, "vivifill copy_to_user failed.\n"); + dprintk(dev, 2, "vivifill copy_to_user failed.\n"); pos += wmax*2; } @@ -367,8 +366,8 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) sprintf(dev->timestr, "%02d:%02d:%02d:%03d", dev->h, dev->m, dev->s, (dev->us + 500) / 1000); - dprintk(2, "vivifill at %s: Buffer 0x%08lx size= %d\n", dev->timestr, - (unsigned long)tmpbuf, pos); + dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", + dev->timestr, (unsigned long)tmpbuf, pos); /* Advice that buffer was filled */ buf->vb.state = VIDEOBUF_DONE; @@ -392,7 +391,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) /* Announces videobuf that all went ok */ for (bc = 0;; bc++) { if (list_empty(&dma_q->active)) { - dprintk(1, "No active queue to serve\n"); + dprintk(dev, 1, "No active queue to serve\n"); break; } @@ -406,7 +405,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) } do_gettimeofday(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup\n", buf, buf->vb. i); + dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); /* Fill buffer */ vivi_fillbuff(dev, buf); @@ -418,16 +417,18 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) } } if (bc != 1) - dprintk(1, "%s: %d buffers handled (should be 1)\n", + dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); } static void vivi_sleep(struct vivi_dmaqueue *dma_q) { + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); int timeout; DECLARE_WAITQUEUE(wait, current); - dprintk(1, "%s dma_q=0x%08lx\n", __FUNCTION__, (unsigned long)dma_q); + dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, + (unsigned long)dma_q); add_wait_queue(&dma_q->wq, &wait); if (!kthread_should_stop()) { @@ -450,11 +451,12 @@ static void vivi_sleep(struct vivi_dmaqueue *dma_q) WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) - jiffies; - dprintk(1, "underrun, losed %d frames. " + dprintk(dev, 1, "underrun, losed %d frames. " "Now, frame is %d. Waking on %d jiffies\n", dma_q->frame-old, dma_q->frame, timeout); } else - dprintk(1, "will sleep for %i jiffies\n", timeout); + dprintk(dev, 1, "will sleep for %i jiffies\n", + timeout); vivi_thread_tick(dma_q); @@ -468,8 +470,9 @@ static void vivi_sleep(struct vivi_dmaqueue *dma_q) static int vivi_thread(void *data) { struct vivi_dmaqueue *dma_q = data; + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); - dprintk(1, "thread started\n"); + dprintk(dev, 1, "thread started\n"); mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); set_freezable(); @@ -480,16 +483,18 @@ static int vivi_thread(void *data) if (kthread_should_stop()) break; } - dprintk(1, "thread: exit\n"); + dprintk(dev, 1, "thread: exit\n"); return 0; } static int vivi_start_thread(struct vivi_dmaqueue *dma_q) { + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + dma_q->frame = 0; dma_q->ini_jiffies = jiffies; - dprintk(1, "%s\n", __FUNCTION__); + dprintk(dev, 1, "%s\n", __FUNCTION__); dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); @@ -500,13 +505,15 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q) /* Wakes thread */ wake_up_interruptible(&dma_q->wq); - dprintk(1, "returning from %s\n", __FUNCTION__); + dprintk(dev, 1, "returning from %s\n", __FUNCTION__); return 0; } static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) { - dprintk(1, "%s\n", __FUNCTION__); + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + + dprintk(dev, 1, "%s\n", __FUNCTION__); /* shutdown control thread */ if (dma_q->kthread) { kthread_stop(dma_q->kthread); @@ -516,17 +523,19 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) static int restart_video_queue(struct vivi_dmaqueue *dma_q) { + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); struct vivi_buffer *buf, *prev; - dprintk(1, "%s dma_q=0x%08lx\n", __FUNCTION__, (unsigned long)dma_q); + dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, + (unsigned long)dma_q); if (!list_empty(&dma_q->active)) { buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", + dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); - dprintk(1, "Restarting video dma\n"); + dprintk(dev, 1, "Restarting video dma\n"); vivi_stop_thread(dma_q); /* cancel all outstanding capture / vbi requests */ @@ -550,13 +559,14 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &dma_q->active); - dprintk(1, "Restarting video dma\n"); + dprintk(dev, 1, "Restarting video dma\n"); vivi_stop_thread(dma_q); vivi_start_thread(dma_q); buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", + dprintk(dev, 2, + "[%p/%d] restart_queue - first active\n", buf, buf->vb.i); } else if (prev->vb.width == buf->vb.width && @@ -565,7 +575,8 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &dma_q->active); buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2, "[%p/%d] restart_queue - move to active\n", + dprintk(dev, 2, + "[%p/%d] restart_queue - move to active\n", buf, buf->vb.i); } else { return 0; @@ -598,7 +609,8 @@ static void vivi_vid_timeout(unsigned long data) static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { - struct vivi_fh *fh = vq->priv_data; + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; *size = fh->width*fh->height*2; @@ -608,14 +620,18 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) while (*size * *count > vid_limit * 1024 * 1024) (*count)--; - dprintk(1, "%s, count=%d, size=%d\n", __FUNCTION__, *count, *size); + dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__, + *count, *size); return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - dprintk(1, "%s\n", __FUNCTION__); + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; + + dprintk(dev, 1, "%s\n", __FUNCTION__); if (in_interrupt()) BUG(); @@ -632,10 +648,11 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); int rc, init_buffer = 0; - dprintk(1, "%s, field=%d\n", __FUNCTION__, field); + dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -681,18 +698,18 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct vivi_buffer *prev; if (!list_empty(&vidq->queued)) { - dprintk(1, "adding vb queue=0x%08lx\n", + dprintk(dev, 1, "adding vb queue=0x%08lx\n", (unsigned long)&buf->vb.queue); list_add_tail(&buf->vb.queue, &vidq->queued); buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", + dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&vidq->active)) { list_add_tail(&buf->vb.queue, &vidq->active); buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active\n", + dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); vivi_start_thread(vidq); @@ -704,13 +721,15 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue, &vidq->active); buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2, "[%p/%d] buffer_queue - append to active\n", + dprintk(dev, 2, + "[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { list_add_tail(&buf->vb.queue, &vidq->queued); buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", + dprintk(dev, 2, + "[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } } @@ -724,7 +743,7 @@ static void buffer_release(struct videobuf_queue *vq, struct vivi_dev *dev = (struct vivi_dev *)fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; - dprintk(1, "%s\n", __FUNCTION__); + dprintk(dev, 1, "%s\n", __FUNCTION__); vivi_stop_thread(vidq); @@ -784,13 +803,16 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct vivi_fh *fh = priv; + struct vivi_dev *dev = fh->dev; struct vivi_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; if (format.fourcc != f->fmt.pix.pixelformat) { - dprintk(1, "Fourcc format (0x%08x) invalid. Driver accepts " - "only 0x%08x\n", f->fmt.pix.pixelformat, format.fourcc); + dprintk(dev, 1, "Fourcc format (0x%08x) invalid. " + "Driver accepts only 0x%08x\n", + f->fmt.pix.pixelformat, format.fourcc); return -EINVAL; } fmt = &format; @@ -800,7 +822,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, if (field == V4L2_FIELD_ANY) { field = V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { - dprintk(1, "Field type invalid.\n"); + dprintk(dev, 1, "Field type invalid.\n"); return -EINVAL; } @@ -1009,7 +1031,7 @@ found: /* If more than one user, mutex should be added */ dev->users++; - dprintk(1, "open minor=%d type=%s users=%d\n", minor, + dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor, v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ @@ -1064,9 +1086,10 @@ static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; struct videobuf_queue *q = &fh->vb_vidq; - dprintk(1, "%s\n", __FUNCTION__); + dprintk(dev, 1, "%s\n", __FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; @@ -1090,7 +1113,8 @@ static int vivi_close(struct inode *inode, struct file *file) dev->users--; - dprintk(1, "close called (minor=%d, users=%d)\n", minor, dev->users); + dprintk(dev, 1, "close called (minor=%d, users=%d)\n", + minor, dev->users); return 0; } @@ -1118,14 +1142,15 @@ static int vivi_release(void) static int vivi_mmap(struct file *file, struct vm_area_struct *vma) { - struct vivi_fh *fh = file->private_data; + struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; int ret; - dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n", + dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, ret); -- cgit v1.2.3 From 55862ac9b2e656c35ab1e25d9b162e5bda81281f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Dec 2007 16:13:37 -0300 Subject: V4L/DVB (6816): Add proper locking for buffer filling Avoids de-alocating buffers before finishing to fill a buffer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 0346d1af3e6..004209d5449 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -163,6 +163,7 @@ struct vivi_dev { struct list_head vivi_devlist; struct mutex lock; + spinlock_t slock; int users; @@ -388,6 +389,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) int bc; + spin_lock(&dev->slock); /* Announces videobuf that all went ok */ for (bc = 0;; bc++) { if (list_empty(&dma_q->active)) { @@ -401,6 +403,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) /* Nobody is waiting something to be done, just return */ if (!waitqueue_active(&buf->vb.done)) { mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); + spin_unlock(&dev->slock); return; } @@ -419,6 +422,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) if (bc != 1) dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); + spin_unlock(&dev->slock); } static void vivi_sleep(struct vivi_dmaqueue *dma_q) @@ -591,6 +595,8 @@ static void vivi_vid_timeout(unsigned long data) struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *buf; + spin_lock(&dev->slock); + while (!list_empty(&vidq->active)) { buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); @@ -599,8 +605,9 @@ static void vivi_vid_timeout(unsigned long data) wake_up(&buf->vb.done); printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); } - restart_video_queue(vidq); + + spin_unlock(&dev->slock); } /* ------------------------------------------------------------------ @@ -1064,7 +1071,7 @@ found: dev->h, dev->m, dev->s, (dev->us + 500) / 1000); videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, - NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, + NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer), fh); return 0; @@ -1224,6 +1231,7 @@ static int __init vivi_init(void) /* initialize locks */ mutex_init(&dev->lock); + spin_lock_init(&dev->slock); dev->vidq.timeout.function = vivi_vid_timeout; dev->vidq.timeout.data = (unsigned long)dev; -- cgit v1.2.3 From 6594ad829a98d5a9fe720d8d182a4e50fc81953a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Dec 2007 16:15:41 -0300 Subject: V4L/DVB (6817): Cleanup kernel thread and provide overrun detection The previous code were a little bit messy. Cleans it up. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 73 ++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 004209d5449..c9d23633fe4 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -425,48 +425,57 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) spin_unlock(&dev->slock); } +#define frames_to_ms(frames) \ + ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) + static void vivi_sleep(struct vivi_dmaqueue *dma_q) { struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); - int timeout; + int timeout, running_time; DECLARE_WAITQUEUE(wait, current); dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, (unsigned long)dma_q); add_wait_queue(&dma_q->wq, &wait); - if (!kthread_should_stop()) { - dma_q->frame++; - - /* Calculate time to wake up */ - timeout = dma_q->ini_jiffies+ - msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR * 1000) - / WAKE_DENOMINATOR) - jiffies; - - if (timeout <= 0) { - int old = dma_q->frame; - dma_q->frame = (jiffies_to_msecs(jiffies - - dma_q->ini_jiffies) * - WAKE_DENOMINATOR) / - (WAKE_NUMERATOR * 1000) + 1; - - timeout = dma_q->ini_jiffies+ - msecs_to_jiffies((dma_q->frame * - WAKE_NUMERATOR * 1000) - / WAKE_DENOMINATOR) - jiffies; - - dprintk(dev, 1, "underrun, losed %d frames. " - "Now, frame is %d. Waking on %d jiffies\n", - dma_q->frame-old, dma_q->frame, timeout); - } else - dprintk(dev, 1, "will sleep for %i jiffies\n", - timeout); - - vivi_thread_tick(dma_q); - - schedule_timeout_interruptible(timeout); - } + if (kthread_should_stop()) + goto stop_task; + + running_time = jiffies - dma_q->ini_jiffies; + dma_q->frame++; + + /* Calculate time to wake up */ + timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time; + + if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) { + int old = dma_q->frame; + int nframes; + + dma_q->frame = (jiffies_to_msecs(running_time) / + frames_to_ms(1)) + 1; + + timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) + - running_time; + + if (unlikely (timeout <= 0)) + timeout = 1; + + nframes = (dma_q->frame > old)? + dma_q->frame - old : old - dma_q->frame; + + dprintk(dev, 1, "%ld: %s %d frames. " + "Current frame is %d. Will sleep for %d jiffies\n", + jiffies, + (dma_q->frame > old)? "Underrun, losed" : "Overrun of", + nframes, dma_q->frame, timeout); + } else + dprintk(dev, 1, "will sleep for %d jiffies\n", timeout); + + vivi_thread_tick(dma_q); + + schedule_timeout_interruptible(timeout); +stop_task: remove_wait_queue(&dma_q->wq, &wait); try_to_freeze(); } -- cgit v1.2.3 From 18ff605a18b29ab1b52d31f96e2ecbaf7a042a3e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 12 Dec 2007 21:43:57 -0300 Subject: V4L/DVB (6818): git-dvb: drivers/media/dvb/frontends/zl10353.c: avoid 64-bit divide Signed-off-by: Andrew Morton Acked-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/zl10353.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 091fbcced00..e874ec8df60 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -144,7 +144,8 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, break; } - value = (bw * (u64)10 * (1 << 23) / 7 * 125 + adc_clock / 2); + value = (u64)10 * (1 << 23) / 7 * 125; + value = (bw * value) + adc_clock / 2; do_div(value, adc_clock); *nominal_rate = value; -- cgit v1.2.3 From 2b03238a79295aff30afc3d9a82afa617fd33971 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 13 Dec 2007 10:04:10 -0300 Subject: V4L/DVB (6821): s5h1409: fix IF frequency configuration On the s5h1409 demod, the IF frequency for VSB is limited to 44 / 5.38 MHz. Hardcode VSB IF frequency within the driver to 44 / 5.38 MHz. QAM IF frequency remains configurable via attach-time configuration. Acked-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 14 +++++++++++++- drivers/media/dvb/frontends/s5h1409.h | 4 ++-- drivers/media/video/cx23885/cx23885-dvb.c | 4 ++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 562d9208857..b80a3ee91ba 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -42,6 +42,7 @@ struct s5h1409_state { fe_modulation_t current_modulation; u32 current_frequency; + int if_freq; u32 is_qam_locked; u32 qam_state; @@ -348,6 +349,9 @@ static int s5h1409_softreset(struct dvb_frontend* fe) return 0; } +#define S5H1409_VSB_IF_FREQ 5380 +#define S5H1409_QAM_IF_FREQ state->config->qam_if + static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) { struct s5h1409_state* state = fe->demodulator_priv; @@ -369,6 +373,9 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) ret = -1; } + if (0 == ret) + state->if_freq = KHz; + return ret; } @@ -394,11 +401,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, switch(m) { case VSB_8: dprintk("%s() VSB_8\n", __FUNCTION__); + if (state->if_freq != S5H1409_VSB_IF_FREQ) + s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); s5h1409_writereg(state, 0xf4, 0); break; case QAM_64: case QAM_256: dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__); + if (state->if_freq != S5H1409_QAM_IF_FREQ) + s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); s5h1409_writereg(state, 0xf4, 1); s5h1409_writereg(state, 0x85, 0x110); break; @@ -571,7 +582,7 @@ static int s5h1409_init (struct dvb_frontend* fe) s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ s5h1409_set_spectralinversion(fe, state->config->inversion); - s5h1409_set_if_freq(fe, state->config->if_freq); + s5h1409_set_if_freq(fe, state->if_freq); s5h1409_set_gpio(fe, state->config->gpio); s5h1409_softreset(fe); @@ -751,6 +762,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, state->config = config; state->i2c = i2c; state->current_modulation = 0; + state->if_freq = S5H1409_VSB_IF_FREQ; /* check if the demod exists */ if (s5h1409_readreg(state, 0x04) != 0x0066) diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index 20f9af1af44..b1f43390666 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -39,8 +39,8 @@ struct s5h1409_config #define S5H1409_GPIO_ON 1 u8 gpio; - /* IF Freq in KHz */ - u16 if_freq; + /* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */ + u16 qam_if; /* Spectral Inversion */ #define S5H1409_INVERSION_OFF 0 diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index eda8c05d093..96d732098a0 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -85,7 +85,7 @@ static struct s5h1409_config hauppauge_generic_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, + .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING }; @@ -94,7 +94,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, - .if_freq = 44000, + .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING }; -- cgit v1.2.3 From 6b7daa88f23bb23f61977063e3f8ea9598e65e32 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 13 Dec 2007 10:11:49 -0300 Subject: V4L/DVB (6822): s5h1409: use VSB IF frequency ( 44 / 5.38 MHz ) unless otherwise specified use VSB IF frequency ( 44 / 5.38 MHz ) if qam_if is invalid or unspecified Acked-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index b80a3ee91ba..d3b148ddad2 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -355,28 +355,26 @@ static int s5h1409_softreset(struct dvb_frontend* fe) static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) { struct s5h1409_state* state = fe->demodulator_priv; - int ret = 0; dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); - if( (KHz == 44000) || (KHz == 5380) ) { - s5h1409_writereg(state, 0x87, 0x01be); - s5h1409_writereg(state, 0x88, 0x0436); - s5h1409_writereg(state, 0x89, 0x054d); - } else - if (KHz == 4000) { + switch (KHz) { + case 4000: s5h1409_writereg(state, 0x87, 0x014b); s5h1409_writereg(state, 0x88, 0x0cb5); s5h1409_writereg(state, 0x89, 0x03e2); - } else { - printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); - ret = -1; + break; + case 5380: + case 44000: + default: + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + break; } + state->if_freq = KHz; - if (0 == ret) - state->if_freq = KHz; - - return ret; + return 0; } static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) -- cgit v1.2.3 From 4bfae52b69360a966f41ba3308e57a6df41ff8e1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 16 Dec 2007 09:24:30 -0300 Subject: V4L/DVB (6827): Auto-selects D2633 for ATSC ATSC standard-specific firmware is D2633 on both v2.5 and v2.7. Better to auto-select this firmware, overriding ctrl.d2633. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 7acc175d805..fd248a19c25 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -970,7 +970,10 @@ static int xc2028_set_params(struct dvb_frontend *fe, break; case FE_ATSC: bw = BANDWIDTH_6_MHZ; + /* The only ATSC firmware (at least on v2.7) is D2633, + so overrides ctrl->d2633 */ type |= ATSC| D2633; + type &= ~D2620; break; /* DVB-S is not supported */ default: -- cgit v1.2.3 From f9e54e0c84da869ad9bc372fb4eab26d558dbfc2 Mon Sep 17 00:00:00 2001 From: Jelle Foks Date: Mon, 21 May 2007 14:36:01 -0300 Subject: V4L/DVB (6828): cx88-blackbird: audio improvements This patch should fix the 'muted audio' and 'raspy audio' problem for mpeg2 streams out of cx88-blackbird devices. Especially mythtv users would find that the audio would often sound bad (aliased, or 'raspy'), mainly related to channel changes, many (all?) other users would find that there was no audio at all in the mpeg data from the encoder chip, unless the audio was manually unmuted. The patch includes the following modifications: Don't actually start the mpeg2 encoder until the device is read from by the application. Wait until the audio is stable for at least 400ms before starting the mpeg encoder. Mute/Unmute the audio when starting/stopping the mpeg encoder. Stop the mpeg encoder when changing parameters and when changing tuner frequency. Add a variable 'mpeg_active' to struct cx8802_dev to allow tracking of whether or not the mpeg2 encoder is active. Load the firmware on cx88-blackbird driver load. Signed-off-by: Jelle Foks Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 89 ++++++++++++++++++++++++------- drivers/media/video/cx88/cx88.h | 1 + 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index f802b565356..7ce37f46b75 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -536,6 +536,9 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) dprintk(1,"Initialize codec\n"); retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ if (retval < 0) { + + dev->mpeg_active = 0; + /* ping was not successful, reset and upload firmware */ cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ msleep(1); @@ -572,38 +575,80 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) blackbird_codec_settings(dev); msleep(1); - /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef); - blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0); - blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */ blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, BLACKBIRD_FIELD1_SAA7115, BLACKBIRD_FIELD2_SAA7115 ); - /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */ blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - /* initialize the video input */ - blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); - msleep(1); + return 0; +} + +static int blackbird_start_codec(struct file *file, void *priv) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx88_core *core = dev->core; + /* start capturing to the host interface */ + u32 reg; + + int i; + int lastchange = -1; + int lastval = 0; + + for (i=0; (i < 10) && (i < (lastchange + 4)); i++) + { + reg = cx_read(AUD_STATUS); + + dprintk(1,"AUD_STATUS:%dL: 0x%x\n", i, reg); + if ((reg & 0x0F) != lastval) + { + lastval = reg & 0x0F; + lastchange = i; + } + msleep(100); + } + + /* unmute audio source */ + cx_clear(AUD_VOL_CTL, (1 << 6)); blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE); msleep(1); blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); msleep(1); + blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); + + /* initialize the video input */ + blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + /* start capturing to the host interface */ - /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE ); msleep(10); - blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); + dev->mpeg_active = 1; + return 0; +} + +static int blackbird_stop_codec(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + + blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + BLACKBIRD_END_NOW, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE + ); + /* mute audio source */ + cx_set(AUD_VOL_CTL, (1 << 6)); + + dev->mpeg_active = 0; return 0; } @@ -833,6 +878,10 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; + + if (dev->mpeg_active) + blackbird_stop_codec(dev); + p = dev->params; err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { @@ -864,10 +913,9 @@ static int vidioc_s_frequency (struct file *file, void *priv, struct cx8802_dev *dev = fh->dev; struct cx88_core *core = dev->core; - blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE); + if (dev->mpeg_active) + blackbird_stop_codec(dev); + cx88_set_freq (core,f); blackbird_initialize_codec(dev); cx88_set_scale(dev->core, dev->width, dev->height, @@ -1073,15 +1121,11 @@ static int mpeg_open(struct inode *inode, struct file *file) static int mpeg_release(struct inode *inode, struct file *file) { struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = NULL; + struct cx8802_dev *dev = fh->dev; struct cx8802_driver *drv = NULL; - /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ - blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); + if (dev->mpeg_active) + blackbird_stop_codec(dev); cx8802_cancel_buffers(fh->dev); /* stop mpeg capture */ @@ -1107,6 +1151,10 @@ static ssize_t mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); @@ -1282,6 +1330,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) core->name); host_setup(dev->core); + blackbird_initialize_codec(dev); blackbird_register_video(dev); /* initial device configuration: needed ? */ diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index bb1036a5c6c..f10d432eb3e 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -461,6 +461,7 @@ struct cx8802_dev { u32 mailbox; int width; int height; + unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ /* mpeg params */ struct cx2341x_mpeg_params params; -- cgit v1.2.3 From e21a5c68deab7cd300e8502488f844f77e0f26d0 Mon Sep 17 00:00:00 2001 From: Jelle Foks Date: Mon, 21 May 2007 14:46:06 -0300 Subject: V4L/DVB (6829): cx88-blackbird: remove unnecessary msleep()'s Remove the unnecessary msleep()'s in cx88-blackbird.c Signed-off-by: Jelle Foks Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 7ce37f46b75..4a0e1f8992c 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -541,9 +541,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) /* ping was not successful, reset and upload firmware */ cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ - msleep(1); cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */ - msleep(1); retval = blackbird_load_firmware(dev); if (retval < 0) return retval; @@ -565,7 +563,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) } dprintk(0, "Firmware version is 0x%08x\n", version); } - msleep(1); cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */ cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */ @@ -573,7 +570,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ blackbird_codec_settings(dev); - msleep(1); blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, BLACKBIRD_FIELD1_SAA7115, @@ -584,7 +580,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - msleep(1); return 0; } @@ -616,9 +611,7 @@ static int blackbird_start_codec(struct file *file, void *priv) cx_clear(AUD_VOL_CTL, (1 << 6)); blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE); - msleep(1); blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); - msleep(1); blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); @@ -630,7 +623,6 @@ static int blackbird_start_codec(struct file *file, void *priv) BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE ); - msleep(10); dev->mpeg_active = 1; return 0; -- cgit v1.2.3 From 4423a9a3395ef652d80d848161444b417f1f78c0 Mon Sep 17 00:00:00 2001 From: Jelle Foks Date: Mon, 21 May 2007 14:48:58 -0300 Subject: V4L/DVB (6830): cx88-blackbird: remove unnecessary encoder unmute Remove the unnecessary BLACKBIRD_UNMUTE calls to the mpeg encoder in cx88-blackbird.c The encoder is never muted, hence unmuting should then only be necessary once after hardware initialization. I tested this from warm boots and cold boots (with long power down time to ensure the sram in the chip is emptied), and found that after the firmware upload the encoder is apparently not muted, making the unmutes unnecessary. Signed-off-by: Jelle Foks Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 4a0e1f8992c..165c0fdd3d1 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -610,9 +610,6 @@ static int blackbird_start_codec(struct file *file, void *priv) /* unmute audio source */ cx_clear(AUD_VOL_CTL, (1 << 6)); - blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE); - blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); - blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); /* initialize the video input */ -- cgit v1.2.3 From 7b27d45bb50498c86aa87e7ef174b2a0f5b6f361 Mon Sep 17 00:00:00 2001 From: Ricardo Cerqueira Date: Sun, 30 Sep 2007 13:02:49 -0300 Subject: V4L/DVB (6831): Audio routes fix for blackbird boards with the wm8775 ADC Fix lack of audio on the MPEG-2 stream of wm8775 based blackbirds. The wm8775 module initializes the audio input at "route 2", which doesn't hold true for all boards. The HVR-1300, for example, uses route 1 for tuner audio, and route 2 for baseband. So we must route the audio to the proper input depending on what video input is being used. Signed-off-by: Ricardo Cerqueira Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 38 +++++++++++++++++------------------ drivers/media/video/cx88/cx88-video.c | 16 +++++++++++++-- drivers/media/video/cx88/cx88.h | 2 +- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f8a786ae475..d484e5ce579 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -302,22 +302,22 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, - .extadc = 1, + .audioroute = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -378,7 +378,7 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, @@ -549,7 +549,7 @@ static const struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .extadc = 1, + .audioroute = 1, }}, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -672,22 +672,22 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, - .extadc = 1, + .audioroute = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -826,23 +826,23 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, .vmux = 2, .gpio0 = 0x0000cdf3, - .extadc = 1, + .audioroute = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -1110,12 +1110,12 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, @@ -1340,17 +1340,17 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xe780, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xe780, - .extadc = 1, + .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xe780, - .extadc = 1, + .audioroute = 2, }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 6d5ea8ce983..1b80f0f700e 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -394,9 +394,21 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { /* sets sound input from external adc */ - if (INPUT(input).extadc) + if (INPUT(input).audioroute) { + /* The wm8775 module has the "2" route hardwired into + the initialization. Some boards may use different + routes for different inputs. HVR-1300 surely does */ + if (core->board.audio_chip && + core->board.audio_chip == AUDIO_CHIP_WM8775) { + struct v4l2_routing route; + + route.input = INPUT(input).audioroute; + cx88_call_i2c_clients(core, + VIDIOC_INT_S_AUDIO_ROUTING,&route); + } + cx_set(AUD_CTL, EN_I2SIN_ENABLE); - else + } else cx_clear(AUD_CTL, EN_I2SIN_ENABLE); } return 0; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index f10d432eb3e..a10f94de0d3 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -228,7 +228,7 @@ struct cx88_input { enum cx88_itype type; u32 gpio0, gpio1, gpio2, gpio3; unsigned int vmux:2; - unsigned int extadc:1; + unsigned int audioroute; }; struct cx88_board { -- cgit v1.2.3 From 6a0bc9a0162d10c551bb916a1a21bfede4db3203 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 13 Oct 2007 20:42:45 -0300 Subject: V4L/DVB (6832): cx88-blackbird: don't mute audio when stopping the codec We should not mute the audio input when we stop the codec, because it will interfere with the live uncompressed stream. Signed-off-by: Michael Krufky Reviewed-by: Jelle Foks Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 165c0fdd3d1..d83facf00dc 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -627,15 +627,11 @@ static int blackbird_start_codec(struct file *file, void *priv) static int blackbird_stop_codec(struct cx8802_dev *dev) { - struct cx88_core *core = dev->core; - blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE ); - /* mute audio source */ - cx_set(AUD_VOL_CTL, (1 << 6)); dev->mpeg_active = 0; return 0; -- cgit v1.2.3 From 66e6fbdf99420efe58685feda0ac1b73b33400e0 Mon Sep 17 00:00:00 2001 From: Ricardo Cerqueira Date: Tue, 16 Oct 2007 20:52:08 -0300 Subject: V4L/DVB (6833): Don't limit cx88 audio routing to blackbird boards All cx2388 boards need the line-in audio to be routed from an external ADC (refered to as "ADC mode" in the spec sheet), since the chip is uncapable of dealing with baseband audio directly. So... this patch enables normal mode when using the tuner (TV or Radio), and enables ADC mode with any other source. It'll probably only work with boards that have supported ADCs (such as the Wolfson wm9775) Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 46 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 1b80f0f700e..c8a5cd5eedf 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -392,25 +392,41 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { - /* sets sound input from external adc */ - if (INPUT(input).audioroute) { - /* The wm8775 module has the "2" route hardwired into - the initialization. Some boards may use different - routes for different inputs. HVR-1300 surely does */ - if (core->board.audio_chip && - core->board.audio_chip == AUDIO_CHIP_WM8775) { - struct v4l2_routing route; - - route.input = INPUT(input).audioroute; - cx88_call_i2c_clients(core, - VIDIOC_INT_S_AUDIO_ROUTING,&route); - } + /* if there are audioroutes defined, we have an external + ADC to deal with audio */ + if (INPUT(input).audioroute) { + + /* cx2388's C-ADC is connected to the tuner only. + When used with S-Video, that ADC is busy dealing with + chroma, so an external must be used for baseband audio */ + + if (INPUT(input).type != CX88_VMUX_TELEVISION && + INPUT(input).type != CX88_RADIO) { + /* "ADC mode" */ + cx_write(AUD_I2SCNTL, 0x1); cx_set(AUD_CTL, EN_I2SIN_ENABLE); - } else + } else { + /* Normal mode */ + cx_write(AUD_I2SCNTL, 0x0); cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + } + + /* The wm8775 module has the "2" route hardwired into + the initialization. Some boards may use different + routes for different inputs. HVR-1300 surely does */ + if (core->board.audio_chip && + core->board.audio_chip == AUDIO_CHIP_WM8775) { + struct v4l2_routing route; + + route.input = INPUT(input).audioroute; + cx88_call_i2c_clients(core, + VIDIOC_INT_S_AUDIO_ROUTING,&route); + + } + } + return 0; } EXPORT_SYMBOL(cx88_video_mux); -- cgit v1.2.3 From 36e05a44756efe562ad1f49ada9bd6a598242828 Mon Sep 17 00:00:00 2001 From: Frej Drejhammar Date: Mon, 5 Nov 2007 17:57:11 -0300 Subject: V4L/DVB (6834): cx88-video: Enable selection of the WM8775 for cx88 cards The auto selection of pertinent helper chips (VIDEO_HELPER_CHIPS_AUTO) should select the wm8775 driver, which is used by at least one Conexant 2388x based card (Hauppauge HVR-1300), if VIDEO_CX88 is selected. Signed-off-by: Frej Drejhammar Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index ceb31d4a251..49d3813a9b4 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -8,6 +8,7 @@ config VIDEO_CX88 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO ---help--- This is a video4linux driver for Conexant 2388x based TV cards. -- cgit v1.2.3 From d8f69971d8d6c137e42928492f8d469078113db9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 17 Dec 2007 10:35:59 -0300 Subject: V4L/DVB (6836): Fix CodingStyle troubles caused by the previous cx88 commits Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 10 ++++------ drivers/media/video/cx88/cx88-video.c | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index d83facf00dc..5f79442924f 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -594,13 +594,11 @@ static int blackbird_start_codec(struct file *file, void *priv) int lastchange = -1; int lastval = 0; - for (i=0; (i < 10) && (i < (lastchange + 4)); i++) - { + for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) { reg = cx_read(AUD_STATUS); - dprintk(1,"AUD_STATUS:%dL: 0x%x\n", i, reg); - if ((reg & 0x0F) != lastval) - { + dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg); + if ((reg & 0x0F) != lastval) { lastval = reg & 0x0F; lastchange = i; } @@ -610,7 +608,7 @@ static int blackbird_start_codec(struct file *file, void *priv) /* unmute audio source */ cx_clear(AUD_VOL_CTL, (1 << 6)); - blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); + blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0); /* initialize the video input */ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index c8a5cd5eedf..7f1931aed20 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -421,7 +421,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) route.input = INPUT(input).audioroute; cx88_call_i2c_clients(core, - VIDIOC_INT_S_AUDIO_ROUTING,&route); + VIDIOC_INT_S_AUDIO_ROUTING, &route); } -- cgit v1.2.3 From 35e420357bd835d43c76d3ab5e35694be0b56f95 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 17 Dec 2007 10:54:06 -0300 Subject: V4L/DVB (6837): Convert cx88_input.audioroute to a bitfield Prevent us from wasting some extra bytes of memory Thanks to Trent Piepho, for pointing this out. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index a10f94de0d3..0cd2946a278 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -228,7 +228,7 @@ struct cx88_input { enum cx88_itype type; u32 gpio0, gpio1, gpio2, gpio3; unsigned int vmux:2; - unsigned int audioroute; + unsigned int audioroute:2; }; struct cx88_board { -- cgit v1.2.3 From daae58956bebeab6631ba078669970a27bdfbdbe Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 19:14:31 -0300 Subject: V4L/DVB (6838): tda9887: remove references to struct tuner from printk macros Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 8a95f097ba2..f265c702cde 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -25,14 +25,14 @@ static int tda9887_debug; module_param_named(debug, tda9887_debug, int, 0644); #define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \ - i2c_adapter_id(priv->t->i2c->adapter), \ - priv->t->i2c->addr, ##arg); } while (0) + printk(KERN_INFO "tda9887 %d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr, ##arg); } while (0) #define tda9887_dbg(fmt, arg...) do {\ if (tda9887_debug) \ - printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \ - i2c_adapter_id(priv->t->i2c->adapter), \ - priv->t->i2c->addr, ##arg); } while (0) + printk(KERN_INFO "tda9887 %d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr, ##arg); } while (0) struct tda9887_priv { struct tuner_i2c_props i2c_props; -- cgit v1.2.3 From f1c9a281005f714fdc57c830a23f2b6bd6e2b714 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 19:27:23 -0300 Subject: V4L/DVB (6839): tuner: add set_config to struct analog_tuner_ops Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 14 ++++++++++++++ drivers/media/video/tuner-driver.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 355f9810fac..9134b997ef2 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -154,6 +154,19 @@ static int fe_has_signal(struct dvb_frontend *fe) return strength; } +static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct tuner *t = fe->analog_demod_priv; + + if (fe_tuner_ops->set_config) + return fe_tuner_ops->set_config(fe, priv_cfg); + + tuner_warn("Tuner frontend module has no way to set config\n"); + + return 0; +} + static void tuner_status(struct dvb_frontend *fe); static struct analog_tuner_ops tuner_core_ops = { @@ -161,6 +174,7 @@ static struct analog_tuner_ops tuner_core_ops = { .standby = fe_standby, .release = fe_release, .has_signal = fe_has_signal, + .set_config = fe_set_config, .tuner_status = tuner_status }; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 65ced435018..7f43dc68ab2 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -45,6 +45,9 @@ struct analog_tuner_ops { void (*standby)(struct dvb_frontend *fe); void (*release)(struct dvb_frontend *fe); int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); + + /** This is to allow setting tuner-specific configuration */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); }; struct tuner { -- cgit v1.2.3 From 710401b837f8849dc9c28385eb5298746b811305 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 19:53:32 -0300 Subject: V4L/DVB (6840): tuner: convert tda9887 to use TUNER_SET_CONFIG Use TUNER_SET_CONFIG to set configuration in tda9887's private state structure, rather than storing tda9887-specific configuration within struct tuner. Update handling of TUNER_SET_CONFIG by tuner-core, to call &t->fe.ops.analog_demod_ops rather than &t->fe.ops.tuner_ops analog_demod_ops.set_config passes the request to tuner_ops.set_config, so this does not break other drivers. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 47 ++++++++++++++++++++++++-------------- drivers/media/video/tuner-core.c | 12 +++------- drivers/media/video/tuner-driver.h | 3 --- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index f265c702cde..7686f52cfcf 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -38,6 +38,7 @@ struct tda9887_priv { struct tuner_i2c_props i2c_props; unsigned char data[4]; + unsigned int config; struct tuner *t; }; @@ -473,31 +474,31 @@ static int tda9887_set_insmod(struct dvb_frontend *fe) return 0; } -static int tda9887_set_config(struct dvb_frontend *fe) +static int tda9887_do_config(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; struct tuner *t = priv->t; char *buf = priv->data; - if (t->tda9887_config & TDA9887_PORT1_ACTIVE) + if (priv->config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; - if (t->tda9887_config & TDA9887_PORT1_INACTIVE) + if (priv->config & TDA9887_PORT1_INACTIVE) buf[1] |= cOutputPort1Inactive; - if (t->tda9887_config & TDA9887_PORT2_ACTIVE) + if (priv->config & TDA9887_PORT2_ACTIVE) buf[1] &= ~cOutputPort2Inactive; - if (t->tda9887_config & TDA9887_PORT2_INACTIVE) + if (priv->config & TDA9887_PORT2_INACTIVE) buf[1] |= cOutputPort2Inactive; - if (t->tda9887_config & TDA9887_QSS) + if (priv->config & TDA9887_QSS) buf[1] |= cQSS; - if (t->tda9887_config & TDA9887_INTERCARRIER) + if (priv->config & TDA9887_INTERCARRIER) buf[1] &= ~cQSS; - if (t->tda9887_config & TDA9887_AUTOMUTE) + if (priv->config & TDA9887_AUTOMUTE) buf[1] |= cAutoMuteFmActive; - if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { + if (priv->config & TDA9887_DEEMPHASIS_MASK) { buf[2] &= ~0x60; - switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { + switch (priv->config & TDA9887_DEEMPHASIS_MASK) { case TDA9887_DEEMPHASIS_NONE: buf[2] |= cDeemphasisOFF; break; @@ -509,21 +510,22 @@ static int tda9887_set_config(struct dvb_frontend *fe) break; } } - if (t->tda9887_config & TDA9887_TOP_SET) { + if (priv->config & TDA9887_TOP_SET) { buf[2] &= ~cTopMask; - buf[2] |= (t->tda9887_config >> 8) & cTopMask; + buf[2] |= (priv->config >> 8) & cTopMask; } - if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) + if ((priv->config & TDA9887_INTERCARRIER_NTSC) && + (t->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; - if (t->tda9887_config & TDA9887_GATING_18) + if (priv->config & TDA9887_GATING_18) buf[3] &= ~cGating_36; if (t->mode == V4L2_TUNER_RADIO) { - if (t->tda9887_config & TDA9887_RIF_41_3) { + if (priv->config & TDA9887_RIF_41_3) { buf[3] &= ~cVideoIFMask; buf[3] |= cRadioIF_41_30; } - if (t->tda9887_config & TDA9887_GAIN_NORMAL) + if (priv->config & TDA9887_GAIN_NORMAL) buf[3] &= ~cTunerGainLow; } @@ -570,7 +572,7 @@ static void tda9887_configure(struct dvb_frontend *fe) priv->data[1] |= cOutputPort1Inactive; priv->data[1] |= cOutputPort2Inactive; - tda9887_set_config(fe); + tda9887_do_config(fe); tda9887_set_insmod(fe); if (t->mode == T_STANDBY) { @@ -629,6 +631,16 @@ static void tda9887_set_params(struct dvb_frontend *fe, tda9887_configure(fe); } +static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->config = *(unsigned int *)priv_cfg; + tda9887_configure(fe); + + return 0; +} + static void tda9887_release(struct dvb_frontend *fe) { kfree(fe->analog_demod_priv); @@ -644,6 +656,7 @@ static struct analog_tuner_ops tda9887_tuner_ops = { .tuner_status = tda9887_tuner_status, .get_afc = tda9887_get_afc, .release = tda9887_release, + .set_config = tda9887_set_config, }; int tda9887_attach(struct tuner *t) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9134b997ef2..695f39ebe77 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -833,25 +833,19 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) #endif case TUNER_SET_CONFIG: { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; struct v4l2_priv_tun_config *cfg = arg; if (t->type != cfg->tuner) break; - if (t->type == TUNER_TDA9887) { - t->tda9887_config = *(unsigned int *)cfg->priv; - set_freq(client, t->tv_freq); - break; - } - - if (NULL == fe_tuner_ops->set_config) { + if ((NULL == ops) || (NULL == ops->set_config)) { tuner_warn("Tuner frontend module has no way to " "set config\n"); break; } - fe_tuner_ops->set_config(&t->fe, cfg->priv); + ops->set_config(&t->fe, cfg->priv); break; } /* --- v4l ioctls --- */ diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 7f43dc68ab2..417753b7c3f 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -69,9 +69,6 @@ struct tuner { struct dvb_frontend fe; - /* used by tda9887 */ - unsigned int tda9887_config; - unsigned int config; int (*tuner_callback) (void *dev, int command,int arg); }; -- cgit v1.2.3 From 91c9d4a16710b047781248a38e7000ce9de324af Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 20:05:00 -0300 Subject: V4L/DVB (6841): tda9887: maintain private state independent of struct tuner Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 7686f52cfcf..95d974298fe 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -39,8 +39,9 @@ struct tda9887_priv { unsigned char data[4]; unsigned int config; - - struct tuner *t; + unsigned int mode; + unsigned int audmode; + v4l2_std_id std; }; /* ---------------------------------------------------------------------- */ @@ -402,19 +403,18 @@ static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) static int tda9887_set_tvnorm(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; struct tvnorm *norm = NULL; char *buf = priv->data; int i; - if (t->mode == V4L2_TUNER_RADIO) { - if (t->audmode == V4L2_TUNER_MODE_MONO) + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->audmode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else norm = &radio_stereo; } else { for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { - if (tvnorms[i].std & t->std) { + if (tvnorms[i].std & priv->std) { norm = tvnorms+i; break; } @@ -477,7 +477,6 @@ static int tda9887_set_insmod(struct dvb_frontend *fe) static int tda9887_do_config(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; char *buf = priv->data; if (priv->config & TDA9887_PORT1_ACTIVE) @@ -515,12 +514,12 @@ static int tda9887_do_config(struct dvb_frontend *fe) buf[2] |= (priv->config >> 8) & cTopMask; } if ((priv->config & TDA9887_INTERCARRIER_NTSC) && - (t->std & V4L2_STD_NTSC)) + (priv->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; if (priv->config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->mode == V4L2_TUNER_RADIO) { + if (priv->mode == V4L2_TUNER_RADIO) { if (priv->config & TDA9887_RIF_41_3) { buf[3] &= ~cVideoIFMask; buf[3] |= cRadioIF_41_30; @@ -550,7 +549,6 @@ static int tda9887_status(struct dvb_frontend *fe) static void tda9887_configure(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; - struct tuner *t = priv->t; int rc; memset(priv->data,0,sizeof(priv->data)); @@ -575,9 +573,8 @@ static void tda9887_configure(struct dvb_frontend *fe) tda9887_do_config(fe); tda9887_set_insmod(fe); - if (t->mode == T_STANDBY) { + if (priv->mode == T_STANDBY) priv->data[1] |= cForcedMuteAudioON; - } tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1],priv->data[2],priv->data[3]); @@ -622,12 +619,21 @@ static int tda9887_get_afc(struct dvb_frontend *fe) static void tda9887_standby(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->mode = T_STANDBY; + tda9887_configure(fe); } static void tda9887_set_params(struct dvb_frontend *fe, struct analog_parameters *params) { + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->mode = params->mode; + priv->audmode = params->audmode; + priv->std = params->std; tda9887_configure(fe); } @@ -670,7 +676,6 @@ int tda9887_attach(struct tuner *t) priv->i2c_props.addr = t->i2c->addr; priv->i2c_props.adap = t->i2c->adapter; - priv->t = t; strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name)); -- cgit v1.2.3 From 8ca4083b50752d588f8b8b1e5e5776fb17d00304 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 20:11:46 -0300 Subject: V4L/DVB (6842): tda9887: remove dependency on struct tuner Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 22 +++++++++++----------- drivers/media/video/tda9887.h | 13 +++++++++---- drivers/media/video/tuner-core.c | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 95d974298fe..0b5dc37fea5 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,6 +9,7 @@ #include #include #include +#include "tuner-driver.h" #include "tuner-i2c.h" #include "tda9887.h" @@ -665,26 +666,25 @@ static struct analog_tuner_ops tda9887_tuner_ops = { .set_config = tda9887_set_config, }; -int tda9887_attach(struct tuner *t) +struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) { struct tda9887_priv *priv = NULL; priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->fe.analog_demod_priv = priv; + return NULL; + fe->analog_demod_priv = priv; - priv->i2c_props.addr = t->i2c->addr; - priv->i2c_props.adap = t->i2c->adapter; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; - strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name)); + tda9887_info("tda988[5/6/7] found\n"); - tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr, - t->i2c->driver->driver.name); + fe->ops.analog_demod_ops = &tda9887_tuner_ops; - t->fe.ops.analog_demod_ops = &tda9887_tuner_ops; - - return 0; + return fe; } EXPORT_SYMBOL_GPL(tda9887_attach); diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h index b879f0ec285..8f873a8e6ed 100644 --- a/drivers/media/video/tda9887.h +++ b/drivers/media/video/tda9887.h @@ -17,16 +17,21 @@ #ifndef __TDA9887_H__ #define __TDA9887_H__ -#include "tuner-driver.h" +#include +#include "dvb_frontend.h" /* ------------------------------------------------------------------------ */ #if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) -extern int tda9887_attach(struct tuner *t); +extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr); #else -static inline int tda9887_attach(struct tuner *t) +static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return -EINVAL; + return NULL; } #endif diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 695f39ebe77..d51f3afa969 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -408,7 +408,7 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TDA9887: - tda9887_attach(t); + tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); break; default: attach_simple_tuner(t); -- cgit v1.2.3 From 790ba18ec7a5f15c854f52835b0e6f39de2369dd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 21:20:21 -0300 Subject: V4L/DVB (6843): tda9887: use printk macros from tuner-i2c.h replace tda9887_info and tda9887_dbg printk macros with tuner_info and tuner_dbg, defined in tuner-i2c.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 145 ++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 75 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 0b5dc37fea5..5085cb90212 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -22,18 +22,11 @@ Used as part of several tuners */ -static int tda9887_debug; -module_param_named(debug, tda9887_debug, int, 0644); - -#define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "tda9887 %d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), \ - priv->i2c_props.addr, ##arg); } while (0) -#define tda9887_dbg(fmt, arg...) do {\ - if (tda9887_debug) \ - printk(KERN_INFO "tda9887 %d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), \ - priv->i2c_props.addr, ##arg); } while (0) +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tda9887" struct tda9887_priv { struct tuner_i2c_props i2c_props; @@ -295,12 +288,12 @@ static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) "+ 37.5 kHz", "+ 12.5 kHz", }; - tda9887_info("read: 0x%2x\n", buf[0]); - tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); - tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); + tuner_info("read: 0x%2x\n", buf[0]); + tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); + tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); } static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) @@ -345,58 +338,60 @@ static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) "44 MHz", }; - tda9887_info("write: byte B 0x%02x\n",buf[1]); - tda9887_info(" B0 video mode : %s\n", - (buf[1] & 0x01) ? "video trap" : "sound trap"); - tda9887_info(" B1 auto mute fm : %s\n", - (buf[1] & 0x02) ? "yes" : "no"); - tda9887_info(" B2 carrier mode : %s\n", - (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - tda9887_info(" B3-4 tv sound/radio : %s\n", - sound[(buf[1] & 0x18) >> 3]); - tda9887_info(" B5 force mute audio: %s\n", - (buf[1] & 0x20) ? "yes" : "no"); - tda9887_info(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); - tda9887_info(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); - - tda9887_info("write: byte C 0x%02x\n",buf[2]); - tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]); - tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]); - tda9887_info(" C7 audio gain : %s\n", - (buf[2] & 0x80) ? "-6" : "0"); - - tda9887_info("write: byte E 0x%02x\n",buf[3]); - tda9887_info(" E0-1 sound carrier : %s\n", - carrier[(buf[3] & 0x03)]); - tda9887_info(" E6 l pll gating : %s\n", - (buf[3] & 0x40) ? "36" : "13"); + tuner_info("write: byte B 0x%02x\n", buf[1]); + tuner_info(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + tuner_info(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + tuner_info(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + tuner_info(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + tuner_info(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + tuner_info(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); + tuner_info(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); + + tuner_info("write: byte C 0x%02x\n", buf[2]); + tuner_info(" C0-4 top adjustment : %s dB\n", + adjust[buf[2] & 0x1f]); + tuner_info(" C5-6 de-emphasis : %s\n", + deemph[(buf[2] & 0x60) >> 5]); + tuner_info(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + tuner_info("write: byte E 0x%02x\n", buf[3]); + tuner_info(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + tuner_info(" E6 l pll gating : %s\n", + (buf[3] & 0x40) ? "36" : "13"); if (buf[1] & 0x08) { /* radio */ - tda9887_info(" E2-4 video if : %s\n", - rif[(buf[3] & 0x0c) >> 2]); - tda9887_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio") - : "fm radio carrier afc"); + tuner_info(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : + "sif-agc radio") + : "fm radio carrier afc"); } else { /* video */ - tda9887_info(" E2-4 video if : %s\n", - vif[(buf[3] & 0x1c) >> 2]); - tda9887_info(" E5 tuner gain : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) ? "external" : "normal") - : ((buf[3] & 0x20) ? "minimum" : "normal")); - tda9887_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) - ? "pin3 port, pin22 vif agc out" - : "pin22 port, pin3 vif acg ext in") - : "pin3+pin22 port"); + tuner_info(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + tuner_info(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); } - tda9887_info("--\n"); + tuner_info("--\n"); } /* ---------------------------------------------------------------------- */ @@ -422,11 +417,11 @@ static int tda9887_set_tvnorm(struct dvb_frontend *fe) } } if (NULL == norm) { - tda9887_dbg("Unsupported tvnorm entry - audio muted\n"); + tuner_dbg("Unsupported tvnorm entry - audio muted\n"); return -1; } - tda9887_dbg("configure for: %s\n",norm->name); + tuner_dbg("configure for: %s\n", norm->name); buf[1] = norm->b; buf[2] = norm->c; buf[3] = norm->e; @@ -542,7 +537,7 @@ static int tda9887_status(struct dvb_frontend *fe) memset(buf,0,sizeof(buf)); if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) - tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); + tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); dump_read_message(fe, buf); return 0; } @@ -577,15 +572,15 @@ static void tda9887_configure(struct dvb_frontend *fe) if (priv->mode == T_STANDBY) priv->data[1] |= cForcedMuteAudioON; - tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1],priv->data[2],priv->data[3]); - if (tda9887_debug > 1) + tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); + if (debug > 1) dump_write_message(fe, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) - tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); + tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); - if (tda9887_debug > 2) { + if (debug > 2) { msleep_interruptible(1000); tda9887_status(fe); } @@ -596,8 +591,8 @@ static void tda9887_configure(struct dvb_frontend *fe) static void tda9887_tuner_status(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; - tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); + tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); } static int tda9887_get_afc(struct dvb_frontend *fe) @@ -680,7 +675,7 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, priv->i2c_props.addr = i2c_addr; priv->i2c_props.adap = i2c_adap; - tda9887_info("tda988[5/6/7] found\n"); + tuner_info("tda988[5/6/7] found\n"); fe->ops.analog_demod_ops = &tda9887_tuner_ops; -- cgit v1.2.3 From f7f427e4cc6078e23078dcd7f321676e0b0f544c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 16 Dec 2007 22:02:26 -0300 Subject: V4L/DVB (6844): tuner: remove struct tuner from tuner-driver.h struct tuner holds state for tuner-core, only -- move it into tuner-core.c Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 21 +++++++++++++++++++++ drivers/media/video/tuner-driver.h | 23 ----------------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index d51f3afa969..f22c41bb97e 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -33,6 +33,27 @@ #define PREFIX t->i2c->driver->driver.name +struct tuner { + /* device */ + struct dvb_frontend fe; + struct i2c_client *i2c; + struct list_head list; + unsigned int using_v4l2:1; + + /* keep track of the current settings */ + v4l2_std_id std; + unsigned int tv_freq; + unsigned int radio_freq; + unsigned int audmode; + + unsigned int mode; + unsigned int mode_mask; /* Combination of allowable modes */ + + unsigned int type; /* chip type id */ + unsigned int config; + int (*tuner_callback) (void *dev, int command, int arg); +}; + /* standard i2c insmod options */ static unsigned short normal_i2c[] = { #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 417753b7c3f..7b1adfaf7ac 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -50,27 +50,4 @@ struct analog_tuner_ops { int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); }; -struct tuner { - /* device */ - struct i2c_client *i2c; - struct list_head list; /* list of tuners */ - - unsigned int type; /* chip type */ - - unsigned int mode; - unsigned int mode_mask; /* Combination of allowable modes */ - - unsigned int tv_freq; /* keep track of the current settings */ - unsigned int radio_freq; - unsigned int audmode; - v4l2_std_id std; - - int using_v4l2; - - struct dvb_frontend fe; - - unsigned int config; - int (*tuner_callback) (void *dev, int command,int arg); -}; - #endif /* __TUNER_DRIVER_H__ */ -- cgit v1.2.3 From dabe61565e3b02bc4a841f317896536068f94e63 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 17 Dec 2007 01:21:08 -0300 Subject: V4L/DVB (6845): tuner: remove unneeded #includes from tuner-driver.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 7b1adfaf7ac..5eaa30ccbda 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -22,8 +22,6 @@ #ifndef __TUNER_DRIVER_H__ #define __TUNER_DRIVER_H__ -#include -#include #include "dvb_frontend.h" extern unsigned const int tuner_count; -- cgit v1.2.3 From 71021d2601c54eee6df3afaf79aed430b17e1366 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 17 Dec 2007 09:49:33 -0300 Subject: V4L/DVB (6846): tda9887: initialize mode to T_STANDBY at startup Ensure that the audio is muted at attach-time Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 5085cb90212..2abb76fba9a 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -674,6 +674,7 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, priv->i2c_props.addr = i2c_addr; priv->i2c_props.adap = i2c_adap; + priv->mode = T_STANDBY; tuner_info("tda988[5/6/7] found\n"); -- cgit v1.2.3 From 9e7e85ebaeba22979209268423f5aae8a352df4c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 17 Dec 2007 14:26:29 -0300 Subject: V4L/DVB (6848): bttv: check pci_register_driver() error Check pci_register_driver() error in module_init. Signed-off-by: Akinobu Mita Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index eb2c12eb2fc..e04113f0b7e 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -4404,14 +4404,17 @@ static int __init bttv_init_module(void) printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); return ret; } - return pci_register_driver(&bttv_pci_driver); + ret = pci_register_driver(&bttv_pci_driver); + if (ret < 0) + bus_unregister(&bttv_sub_bus_type); + + return ret; } static void __exit bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); bus_unregister(&bttv_sub_bus_type); - return; } module_init(bttv_init_module); -- cgit v1.2.3 From aec2aef267203d9ac06ce3508682c0aa81a069dc Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 17 Dec 2007 13:49:17 -0300 Subject: V4L/DVB (em28xx): Add support for Pinnacle Dazzle DVC 100 The patch below adds the "Pinnacle Dazzle DVC 100" to the list of cards supported by the em28xx driver. As the configuration is the same as the DVC 90 one, it simply adds a new USB ID to the list of devices supported by the DVC 90 configuration. Signed-off-by: Aurelien Jarno Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index ceb277543f5..dbc19ca9e48 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -7,7 +7,7 @@ 6 -> Terratec Cinergy 200 USB (em2800) 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) - 9 -> Pinnacle Dazzle DVC 90 (em2820/em2840) [2304:0207] + 9 -> Pinnacle Dazzle DVC 90/DVC 100 (em2820/em2840) [2304:0207,2304:021a] 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] 11 -> Terratec Hybrid XS (em2880) [0ccd:0042] 12 -> Kworld PVR TV 2800 RF (em2820/em2840) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index c4204c90fb0..e00de328605 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -329,7 +329,7 @@ struct em28xx_board em28xx_boards[] = { } }, }, [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90", + .name = "Pinnacle Dazzle DVC 90/DVC 100", .vchannels = 3, .has_tuner = 0, .decoder = EM28XX_SAA7113, @@ -416,6 +416,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x021a), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x2040, 0x6513), -- cgit v1.2.3 From e026268870b5f05a3f74b37816d96ed3b19a9e33 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sun, 2 Dec 2007 06:30:50 -0300 Subject: V4L/DVB (6851): xc2028: include int_freq in firmware version display Add "int_freq" to the debugging output when selecting firmware and the HAS_IF flag when dumping firmware during load. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index fd248a19c25..416c717eb78 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -144,7 +144,8 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) return 0; } -void dump_firm_type(unsigned int type) +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { if (type & BASE) printk("BASE "); @@ -206,6 +207,8 @@ void dump_firm_type(unsigned int type) printk("INPUT2 "); if (type & SCODE) printk("SCODE "); + if (type & HAS_IF) + printk("HAS_IF_%d ", int_freq); } static v4l2_std_id parse_audio_std_option(void) @@ -350,9 +353,9 @@ static int load_all_firmwares(struct dvb_frontend *fe) } tuner_dbg("Reading firmware type "); if (debug) { - dump_firm_type(type); + dump_firm_type_and_int_freq(type, int_freq); printk("(%x), id %llx, size=%d.\n", - type, (unsigned long long)id, size); + type, (unsigned long long)id, size); } memcpy(priv->firm[n].ptr, p, size); @@ -612,7 +615,8 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, } tuner_info("Loading SCODE for type="); - dump_firm_type(priv->firm[pos].type); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); printk("(%x), id %016llx.\n", priv->firm[pos].type, (unsigned long long)*id); @@ -670,11 +674,15 @@ retry: tuner_dbg("checking firmware, user requested type="); if (debug) { dump_firm_type(new_fw.type); - printk("(%x), id %016llx, scode_tbl ", new_fw.type, + printk("(%x), id %016llx, ", new_fw.type, (unsigned long long)new_fw.std_req); - dump_firm_type(priv->ctrl.scode_table); - printk("(%x), scode_nr %d\n", priv->ctrl.scode_table, - new_fw.scode_nr); + if (!int_freq) { + printk("scode_tbl "); + dump_firm_type(priv->ctrl.scode_table); + printk("(%x), ", priv->ctrl.scode_table); + } else + printk("int_freq %d, ", new_fw.int_freq); + printk("scode_nr %d\n", new_fw.scode_nr); } /* No need to reload base firmware if it matches */ -- cgit v1.2.3 From ad35ce9e3e03b1515c8581bababb0e64d05cf1ad Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sun, 2 Dec 2007 06:36:42 -0300 Subject: V4L/DVB (6852): xc2028: s-code offset should not modify internal control structure Don't modify the control structure that was provided at attach when applying an offset to the S-Code, otherwise it will be incorrect on subsequent tunes. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 416c717eb78..81cc7f607d4 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -956,6 +956,7 @@ static int xc2028_set_params(struct dvb_frontend *fe, struct xc2028_data *priv = fe->tuner_priv; unsigned int type=0; fe_bandwidth_t bw = BANDWIDTH_8_MHZ; + u16 demod = 0; tuner_dbg("%s called\n", __FUNCTION__); @@ -1009,10 +1010,10 @@ static int xc2028_set_params(struct dvb_frontend *fe, /* All S-code tables need a 200kHz shift */ if (priv->ctrl.demod) - priv->ctrl.demod += 200; + demod = priv->ctrl.demod + 200; return generic_set_freq(fe, p->frequency, - T_DIGITAL_TV, type, 0, priv->ctrl.demod); + T_DIGITAL_TV, type, 0, demod); } static int xc2028_sleep(struct dvb_frontend *fe) -- cgit v1.2.3 From 9ca01e780f8966a7a94f88ef5c54f340e117abea Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sun, 2 Dec 2007 06:54:17 -0300 Subject: V4L/DVB (6853): xc2028: check HAS_IF flag against table When searching for the right S-Code table to load, check the HAS_IF flag against the firmware we are checking instead of against the the "type" requested. We already ignore the scode type requested if the caller passed an int_freq; this makes the search by frequency consistent with that behaviour. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 81cc7f607d4..a6b05dfd670 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -592,7 +592,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, } else { for (pos = 0; pos < priv->firm_size; pos++) { if ((priv->firm[pos].int_freq == int_freq) && - (type & HAS_IF)) + (priv->firm[pos].type & HAS_IF)) break; } if (pos == priv->firm_size) @@ -601,7 +601,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, p = priv->firm[pos].ptr; - if (type & HAS_IF) { + if (priv->firm[pos].type & HAS_IF) { if (priv->firm[pos].size != 12 * 16 || scode >= 16) return -EINVAL; p += 12 * scode; -- cgit v1.2.3 From 897b842296f1285a6b58e9170f7017022e2e2603 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sun, 2 Dec 2007 09:39:18 -0300 Subject: V4L/DVB (6854): xc2028: be more specific about when applying offset for 7MHz channels We have been inserting a mystery 500kHz offset for tuning 7MHz channels, however some experimentation reveals it is only needed under certain conditions with specific firmware combinations. Document these and only apply the offset when we know it is required. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index a6b05dfd670..63a6fca1f8c 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -875,7 +875,16 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, rc = send_seq(priv, {0x00, 0x00}); } else { offset = 2750000; - if (priv->cur_fw.type & DTV7) + /* + * We must adjust the offset by 500kHz in two cases in order + * to correctly center the IF output: + * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly + * selected and a 7MHz channel is tuned; + * 2) When tuning a VHF channel with DTV78 firmware. + */ + if (((priv->cur_fw.type & DTV7) && + (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) || + ((priv->cur_fw.type & DTV78) && freq < 470000000)) offset -= 500000; } -- cgit v1.2.3 From 3dfefc50ff45744ffb97ce0bf9c213a3fb6d5d3d Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sun, 2 Dec 2007 10:07:06 -0300 Subject: V4L/DVB (6855): xc2028: select DTV78 firmware if tuning 7MHz VHF / 8MHz UHF It seems that the DTV78 firmware is intended for use in locations where VHF channels have 7MHz bandwidth and UHF channels have 8MHz bandwidth. If we switch to DTV78 firmware when we detect this condition, we can avoid firmware reloads when switching between VHF and UHF transponders. Place the state for this in the control structure so that card drivers can hint to us to use DTV78 firmware from the first tuning attempt. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 23 +++++++++++++++-------- drivers/media/video/tuner-xc2028.h | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 63a6fca1f8c..0565edd224b 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -998,20 +998,27 @@ static int xc2028_set_params(struct dvb_frontend *fe, return -EINVAL; } - /* FIXME: - There are two Scodes that will never be selected: - DTV78 ZARLINK456, DTV78 DIBCOM52 - When it should opt for DTV78 instead of DTV7 or DTV8? - */ switch (bw) { case BANDWIDTH_8_MHZ: - type |= DTV8 | F8MHZ; + if (p->frequency < 470000000) + priv->ctrl.vhfbw7 = 0; + else + priv->ctrl.uhfbw8 = 1; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; + type |= F8MHZ; break; case BANDWIDTH_7_MHZ: - type |= DTV7 | F8MHZ; + if (p->frequency < 470000000) + priv->ctrl.vhfbw7 = 1; + else + priv->ctrl.uhfbw8 = 0; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; + type |= F8MHZ; break; case BANDWIDTH_6_MHZ: - type |= DTV6 ; + type |= DTV6; + priv->ctrl.vhfbw7 = 0; + priv->ctrl.uhfbw8 = 0; break; default: tuner_err("error: bandwidth not supported.\n"); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 1fe8b195960..7462629b98f 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -30,6 +30,8 @@ struct xc2028_ctrl { unsigned int mts :1; unsigned int d2633 :1; unsigned int input1:1; + unsigned int vhfbw7:1; + unsigned int uhfbw8:1; unsigned int demod; }; -- cgit v1.2.3 From bc514710889ebb975be9e84ca9c04f698225b656 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sat, 15 Dec 2007 03:24:00 -0300 Subject: V4L/DVB (6856): zl10353: improve tuning parameters and update register map Some more I2C traces and a experimentation with register values on both the ZL10353 and MT352 mean that I can now guess at what more of the ZL10353 registers do. Guess at the registers' names (based on the equivalent names in MT352) and update set_parameters/get_parameters with the new knowledge. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/zl10353.c | 243 +++++++++++++++++++++++++++-- drivers/media/dvb/frontends/zl10353_priv.h | 15 ++ 2 files changed, 245 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index e874ec8df60..276e3b631dc 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -36,6 +36,8 @@ struct zl10353_state { struct dvb_frontend frontend; struct zl10353_config config; + + enum fe_bandwidth bandwidth; }; static int debug; @@ -195,27 +197,156 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, { struct zl10353_state *state = fe->demodulator_priv; u16 nominal_rate, input_freq; - u8 pllbuf[6] = { 0x67 }; + u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; + u16 tps = 0; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - /* These settings set "auto-everything" and start the FSM. */ - zl10353_single_write(fe, 0x55, 0x80); + zl10353_single_write(fe, RESET, 0x80); udelay(200); zl10353_single_write(fe, 0xEA, 0x01); udelay(200); zl10353_single_write(fe, 0xEA, 0x00); - zl10353_single_write(fe, 0x56, 0x28); - zl10353_single_write(fe, 0x89, 0x20); - zl10353_single_write(fe, 0x5E, 0x00); + zl10353_single_write(fe, AGC_TARGET, 0x28); + + if (op->transmission_mode != TRANSMISSION_MODE_AUTO) + acq_ctl |= (1 << 0); + if (op->guard_interval != GUARD_INTERVAL_AUTO) + acq_ctl |= (1 << 1); + zl10353_single_write(fe, ACQ_CTL, acq_ctl); - zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate); + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + /* These are extrapolated from the 7 and 8MHz values */ + zl10353_single_write(fe, MCLK_RATIO, 0x97); + zl10353_single_write(fe, 0x64, 0x34); + break; + case BANDWIDTH_7_MHZ: + zl10353_single_write(fe, MCLK_RATIO, 0x86); + zl10353_single_write(fe, 0x64, 0x35); + break; + case BANDWIDTH_8_MHZ: + default: + zl10353_single_write(fe, MCLK_RATIO, 0x75); + zl10353_single_write(fe, 0x64, 0x36); + } + + zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); + state->bandwidth = op->bandwidth; zl10353_calc_input_freq(fe, &input_freq); zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); + /* Hint at TPS settings */ + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + break; + default: + return -EINVAL; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + break; + case FEC_NONE: + if (op->hierarchy_information == HIERARCHY_AUTO || + op->hierarchy_information == HIERARCHY_NONE) + break; + default: + return -EINVAL; + } + + switch (op->constellation) { + case QPSK: + break; + case QAM_AUTO: + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + default: + return -EINVAL; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + break; + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + default: + return -EINVAL; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + break; + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + default: + return -EINVAL; + } + + switch (op->hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + default: + return -EINVAL; + } + + zl10353_single_write(fe, TPS_GIVEN_1, msb(tps)); + zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps)); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -244,12 +375,97 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, else zl10353_single_write(fe, TUNER_GO, 0x01); - udelay(250); - zl10353_single_write(fe, 0xE4, 0x00); - zl10353_single_write(fe, 0xE5, 0x2A); - zl10353_single_write(fe, 0xE9, 0x02); - zl10353_single_write(fe, 0xE7, 0x40); - zl10353_single_write(fe, 0xE8, 0x10); + return 0; +} + +static int zl10353_get_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct zl10353_state *state = fe->demodulator_priv; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + int s6, s9; + u16 tps; + static const u8 tps_fec_to_api[8] = { + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_5_6, + FEC_7_8, + FEC_AUTO, + FEC_AUTO, + FEC_AUTO + }; + + s6 = zl10353_read_register(state, STATUS_6); + s9 = zl10353_read_register(state, STATUS_9); + if (s6 < 0 || s9 < 0) + return -EREMOTEIO; + if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0) + return -EINVAL; /* no FE or TPS lock */ + + tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | + zl10353_read_register(state, TPS_RECEIVED_0); + + op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; + op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; + + switch ((tps >> 13) & 3) { + case 0: + op->constellation = QPSK; + break; + case 1: + op->constellation = QAM_16; + break; + case 2: + op->constellation = QAM_64; + break; + default: + op->constellation = QAM_AUTO; + break; + } + + op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : + TRANSMISSION_MODE_2K; + + switch ((tps >> 2) & 3) { + case 0: + op->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + op->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + op->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + op->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + op->guard_interval = GUARD_INTERVAL_AUTO; + break; + } + + switch ((tps >> 10) & 7) { + case 0: + op->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + op->hierarchy_information = HIERARCHY_1; + break; + case 2: + op->hierarchy_information = HIERARCHY_2; + break; + case 3: + op->hierarchy_information = HIERARCHY_4; + break; + default: + op->hierarchy_information = HIERARCHY_AUTO; + break; + } + + param->frequency = 0; + op->bandwidth = state->bandwidth; + param->inversion = INVERSION_AUTO; return 0; } @@ -438,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = { .write = zl10353_write, .set_frontend = zl10353_set_parameters, + .get_frontend = zl10353_get_parameters, .get_tune_settings = zl10353_get_tune_settings, .read_status = zl10353_read_status, diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h index fcad9221945..055ff1f7e34 100644 --- a/drivers/media/dvb/frontends/zl10353_priv.h +++ b/drivers/media/dvb/frontends/zl10353_priv.h @@ -46,13 +46,28 @@ enum zl10353_reg_addr { RS_ERR_CNT_0 = 0x13, RS_UBC_1 = 0x14, RS_UBC_0 = 0x15, + TPS_RECEIVED_1 = 0x1D, + TPS_RECEIVED_0 = 0x1E, + TPS_CURRENT_1 = 0x1F, + TPS_CURRENT_0 = 0x20, + RESET = 0x55, + AGC_TARGET = 0x56, + MCLK_RATIO = 0x5C, + ACQ_CTL = 0x5E, TRL_NOMINAL_RATE_1 = 0x65, TRL_NOMINAL_RATE_0 = 0x66, INPUT_FREQ_1 = 0x6C, INPUT_FREQ_0 = 0x6D, + TPS_GIVEN_1 = 0x6E, + TPS_GIVEN_0 = 0x6F, TUNER_GO = 0x70, FSM_GO = 0x71, CHIP_ID = 0x7F, + CHAN_STEP_1 = 0xE4, + CHAN_STEP_0 = 0xE5, + OFDM_LOCK_TIME = 0xE7, + FEC_LOCK_TIME = 0xE8, + ACQ_DELAY = 0xE9, }; #endif /* _ZL10353_PRIV_ */ -- cgit v1.2.3 From 5e3c5967da48b54e5d4ee528b51b565e2f7a3178 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sat, 15 Dec 2007 03:31:09 -0300 Subject: V4L/DVB (6857): cx23885: correctly join I2C writes and reads from same address When an I2C message specifies a write then a read from the same I2C address, we need to tell the chip to not release the bus between the message parts. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-i2c.c | 53 +++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 08e92df3316..20f3fb450f8 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); -#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg); \ + } while (0) #define I2C_WAIT_DELAY 32 #define I2C_WAIT_RETRY 64 @@ -77,14 +79,18 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) } static int i2c_sendbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int last) + const struct i2c_msg *msg, int joined_rlen) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; u32 wdata, addr, ctrl; int retval, cnt; - dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); + if (joined_rlen) + dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__, + msg->len, joined_rlen); + else + dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { @@ -107,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (msg->len > 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); @@ -130,6 +138,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); @@ -151,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; err: - printk(" ERR: %d\n", retval); + if (i2c_debug) + printk(" ERR: %d\n", retval); return retval; } static int i2c_readbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int last) + const struct i2c_msg *msg, int joined) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; u32 ctrl, cnt; int retval; - dprintk(1, "%s(msg->len=%d, last=%d)\n", __FUNCTION__, msg->len, last); + + if (i2c_debug && !joined) + dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { @@ -179,8 +192,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, return 0; } - if (i2c_debug) - printk(" addr << 1) + 1); + if (i2c_debug) { + if (joined) + printk(" R"); + else + printk(" addr << 1) + 1); + } for(cnt = 0; cnt < msg->len; cnt++) { @@ -209,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; err: - printk(" ERR: %d\n", retval); + if (i2c_debug) + printk(" ERR: %d\n", retval); return retval; } @@ -227,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, __FUNCTION__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { /* read */ - retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); + retval = i2c_readbytes(i2c_adap, &msgs[i], 0); + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* write then read from same address */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); if (retval < 0) goto err; + i++; + retval = i2c_readbytes(i2c_adap, &msgs[i], 1); } else { /* write */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); - if (retval < 0) - goto err; + retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); } + if (retval < 0) + goto err; } return num; -- cgit v1.2.3 From 3ac510e6097368695ddff20918ab5822823b548e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Dec 2007 00:30:52 -0300 Subject: V4L/DVB (6858): Fix offset for ATSC ATSC works with offset=0 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 0565edd224b..d367f205c98 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -873,7 +873,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, */ if (new_mode == T_ANALOG_TV) { rc = send_seq(priv, {0x00, 0x00}); - } else { + } else if (!(priv->cur_fw.type & ATSC)) { offset = 2750000; /* * We must adjust the offset by 500kHz in two cases in order -- cgit v1.2.3 From 5412c8204f8c4f733acef511979fe1a738b74767 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 06:21:58 -0300 Subject: V4L/DVB (6859): tveeprom: add support for Hauppauge models 74xxx Thanks to Steve Toth from Hauppauge with providing me with the information needed to add support for these models. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 403fbd0afa3..4d294e2becb 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -405,9 +405,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ** # of inputs/outputs ??? */ - int i, j, len, done, beenhere, tag,start; + int i, j, len, done, beenhere, tag, start; - int tuner1 = 0, t_format1 = 0, audioic=-1; + int tuner1 = 0, t_format1 = 0, audioic = -1; char *t_name1 = NULL; const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; @@ -418,17 +418,24 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, memset(tvee, 0, sizeof(*tvee)); done = len = beenhere = 0; - /* Hack for processing eeprom for em28xx and cx 2388x*/ - if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) && - (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95)) - start=0xa0; /* Generic em28xx offset */ - else if (((eeprom_data[0] & 0xe1) == 0x01) && - (eeprom_data[1] == 0x00) && - (eeprom_data[2] == 0x00) && - (eeprom_data[8] == 0x84)) - start=8; /* Generic cx2388x offset */ + /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ + if (eeprom_data[0] == 0x1a && + eeprom_data[1] == 0xeb && + eeprom_data[2] == 0x67 && + eeprom_data[3] == 0x95) + start = 0xa0; /* Generic em28xx offset */ + else if ((eeprom_data[0] & 0xe1) == 0x01 && + eeprom_data[1] == 0x00 && + eeprom_data[2] == 0x00 && + eeprom_data[8] == 0x84) + start = 8; /* Generic cx2388x offset */ + else if (eeprom_data[1] == 0x70 && + eeprom_data[2] == 0x00 && + eeprom_data[4] == 0x74 && + eeprom_data[8] == 0x84) + start = 8; /* Generic cx23418 offset (models 74xxx) */ else - start=0; + start = 0; for (i = start; !done && i < 256; i += len) { if (eeprom_data[i] == 0x84) { -- cgit v1.2.3 From f19a73d620c5412e2413b778f4dad21febdd6115 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 06:50:20 -0300 Subject: V4L/DVB (6860): tveeprom: CodingStyle cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 471 +++++++++++++++++++++-------------------- 1 file changed, 237 insertions(+), 234 deletions(-) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4d294e2becb..11c15787e25 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -46,11 +46,12 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); MODULE_AUTHOR("John Klar"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") +#define STRM(array, i) \ + (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") #define tveeprom_info(fmt, arg...) \ v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) @@ -58,7 +59,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) #define tveeprom_dbg(fmt, arg...) do { \ if (debug) \ - v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \ + v4l_printk(KERN_DEBUG, "tveeprom", \ + c->adapter, c->addr, fmt , ## arg); \ } while (0) /* @@ -94,170 +96,170 @@ static struct HAUPPAUGE_TUNER hauppauge_tuner[] = { /* 0-9 */ - { TUNER_ABSENT, "None" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_PHILIPS_PAL, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + { TUNER_ABSENT, "None" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_PHILIPS_PAL, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, + { TUNER_PHILIPS_PAL_DK, "Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, /* 10-19 */ - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" }, - { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" }, + { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, /* 20-29 */ - { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, + { TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_PHILIPS_PAL_DK, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, /* 30-39 */ - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, - { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, - { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, - { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ - { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, + { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, + { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, + { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ + { TUNER_ABSENT, "Philips FI1256MP" }, /* 40-49 */ - { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, - { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, - { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, + { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, + { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, - { TUNER_ABSENT, "Philips TD1536D FH 44"}, - { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, - { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, - { TUNER_LG_PAL, "LG TP18PSB11D"}, - { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, + { TUNER_ABSENT, "Philips TD1536D FH 44"}, + { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, + { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, + { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, /* 50-59 */ - { TUNER_LG_PAL_I, "LG TAPC-I701D"}, - { TUNER_ABSENT, "Temic 4042FI5"}, - { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, - { TUNER_ABSENT, "LG TPI8NSR11F"}, - { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, - { TUNER_ABSENT, "Philips FI1236 MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, - { TUNER_ABSENT, "Philips FM1216MP MK3"}, + { TUNER_LG_PAL_I, "LG TAPC-I701D"}, + { TUNER_ABSENT, "Temic 4042FI5"}, + { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, + { TUNER_ABSENT, "LG TPI8NSR11F"}, + { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, + { TUNER_ABSENT, "Philips FI1236 MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, + { TUNER_ABSENT, "Philips FM1216MP MK3"}, /* 60-69 */ - { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, - { TUNER_ABSENT, "LG M001D MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, - { TUNER_ABSENT, "LG M701D MK3"}, - { TUNER_ABSENT, "Temic 4146FM5"}, - { TUNER_ABSENT, "Temic 4136FY5"}, - { TUNER_ABSENT, "Temic 4106FH5"}, - { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, + { TUNER_ABSENT, "LG M001D MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, + { TUNER_ABSENT, "LG M701D MK3"}, + { TUNER_ABSENT, "Temic 4146FM5"}, + { TUNER_ABSENT, "Temic 4136FY5"}, + { TUNER_ABSENT, "Temic 4106FH5"}, + { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, /* 70-79 */ - { TUNER_ABSENT, "LG TALN H200T"}, - { TUNER_ABSENT, "LG TALN H250T"}, - { TUNER_ABSENT, "LG TALN M200T"}, - { TUNER_ABSENT, "LG TALN Z200T"}, - { TUNER_ABSENT, "LG TALN S200T"}, - { TUNER_ABSENT, "Thompson DTT7595"}, - { TUNER_ABSENT, "Thompson DTT7592"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, - { TUNER_ABSENT, "Thompson DTT757"}, + { TUNER_ABSENT, "LG TALN H200T"}, + { TUNER_ABSENT, "LG TALN H250T"}, + { TUNER_ABSENT, "LG TALN M200T"}, + { TUNER_ABSENT, "LG TALN Z200T"}, + { TUNER_ABSENT, "LG TALN S200T"}, + { TUNER_ABSENT, "Thompson DTT7595"}, + { TUNER_ABSENT, "Thompson DTT7592"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, + { TUNER_ABSENT, "Thompson DTT757"}, /* 80-89 */ - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, - { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, - { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, - { TUNER_TCL_2002N, "TCL 2002N 6A"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, - { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, - { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, + { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, + { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, + { TUNER_TCL_2002N, "TCL 2002N 6A"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, + { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, + { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, /* 90-99 */ - { TUNER_ABSENT, "LG TALN H202T"}, - { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, - { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, - { TUNER_ABSENT, "Philips FQ1286A MK4"}, - { TUNER_ABSENT, "Philips FQ1216ME MK5"}, - { TUNER_ABSENT, "Philips FQ1236 MK5"}, - { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, - { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, - { TUNER_ABSENT, "TCL 2002MI_3H"}, - { TUNER_TCL_2002N, "TCL 2002N 5H"}, + { TUNER_ABSENT, "LG TALN H202T"}, + { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, + { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, + { TUNER_ABSENT, "Philips FQ1286A MK4"}, + { TUNER_ABSENT, "Philips FQ1216ME MK5"}, + { TUNER_ABSENT, "Philips FQ1236 MK5"}, + { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, + { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, + { TUNER_ABSENT, "TCL 2002MI_3H"}, + { TUNER_TCL_2002N, "TCL 2002N 5H"}, /* 100-109 */ - { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, - { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, - { TUNER_ABSENT, "Panasonic ENV57H12D5"}, - { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, - { TUNER_ABSENT, "TCL MNM05-4"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, - { TUNER_ABSENT, "TCL MQNM05-4"}, - { TUNER_ABSENT, "LG TAPC-W701D"}, - { TUNER_ABSENT, "TCL 9886P-WM"}, - { TUNER_ABSENT, "TCL 1676NM-WM"}, + { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, + { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, + { TUNER_ABSENT, "Panasonic ENV57H12D5"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, + { TUNER_ABSENT, "TCL MNM05-4"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, + { TUNER_ABSENT, "TCL MQNM05-4"}, + { TUNER_ABSENT, "LG TAPC-W701D"}, + { TUNER_ABSENT, "TCL 9886P-WM"}, + { TUNER_ABSENT, "TCL 1676NM-WM"}, /* 110-119 */ - { TUNER_ABSENT, "Thompson DTT75105"}, - { TUNER_ABSENT, "Conexant_CX24109"}, - { TUNER_TCL_2002N, "TCL M2523_5N_E"}, - { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, - { TUNER_ABSENT, "Philips 8275A"}, - { TUNER_ABSENT, "Microtune MT2060"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, - { TUNER_ABSENT, "TCL M2523_3DI_E"}, - { TUNER_ABSENT, "Samsung THPD5222FG30A"}, + { TUNER_ABSENT, "Thompson DTT75105"}, + { TUNER_ABSENT, "Conexant_CX24109"}, + { TUNER_TCL_2002N, "TCL M2523_5N_E"}, + { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, + { TUNER_ABSENT, "Philips 8275A"}, + { TUNER_ABSENT, "Microtune MT2060"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, + { TUNER_ABSENT, "TCL M2523_3DI_E"}, + { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ - { TUNER_XC2028, "Xceive XC3028"}, - { TUNER_ABSENT, "Philips FQ1216LME MK5"}, - { TUNER_ABSENT, "Philips FQD1216LME"}, - { TUNER_ABSENT, "Conexant CX24118A"}, - { TUNER_ABSENT, "TCL DMF11WIP"}, - { TUNER_ABSENT, "TCL MFNM05_4H_E"}, - { TUNER_ABSENT, "TCL MNM05_4H_E"}, - { TUNER_ABSENT, "TCL MPE05_2H_E"}, - { TUNER_ABSENT, "TCL MQNM05_4_U"}, - { TUNER_ABSENT, "TCL M2523_5NH_E"}, + { TUNER_XC2028, "Xceive XC3028"}, + { TUNER_ABSENT, "Philips FQ1216LME MK5"}, + { TUNER_ABSENT, "Philips FQD1216LME"}, + { TUNER_ABSENT, "Conexant CX24118A"}, + { TUNER_ABSENT, "TCL DMF11WIP"}, + { TUNER_ABSENT, "TCL MFNM05_4H_E"}, + { TUNER_ABSENT, "TCL MNM05_4H_E"}, + { TUNER_ABSENT, "TCL MPE05_2H_E"}, + { TUNER_ABSENT, "TCL MQNM05_4_U"}, + { TUNER_ABSENT, "TCL M2523_5NH_E"}, /* 130-139 */ - { TUNER_ABSENT, "TCL M2523_3DBH_E"}, - { TUNER_ABSENT, "TCL M2523_3DIH_E"}, - { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_ABSENT, "Philips FMD1216MEX"}, - { TUNER_ABSENT, "Philips FRH2036B"}, - { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, - { TUNER_ABSENT, "MaxLinear MXL5005"}, - { TUNER_ABSENT, "MaxLinear MXL5003"}, - { TUNER_ABSENT, "Xceive XC2028"}, - { TUNER_ABSENT, "Microtune MT2131"}, + { TUNER_ABSENT, "TCL M2523_3DBH_E"}, + { TUNER_ABSENT, "TCL M2523_3DIH_E"}, + { TUNER_ABSENT, "TCL MFPE05_2_U"}, + { TUNER_ABSENT, "Philips FMD1216MEX"}, + { TUNER_ABSENT, "Philips FRH2036B"}, + { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, + { TUNER_ABSENT, "MaxLinear MXL5005"}, + { TUNER_ABSENT, "MaxLinear MXL5003"}, + { TUNER_ABSENT, "Xceive XC2028"}, + { TUNER_ABSENT, "Microtune MT2131"}, /* 140-149 */ - { TUNER_ABSENT, "Philips 8275A_8295"}, - { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, - { TUNER_ABSENT, "Microtune MT2266"}, - { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, - { TUNER_ABSENT, "LG TAPQ_H702F"}, - { TUNER_ABSENT, "TCL M09WPP_4N_E"}, - { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, + { TUNER_ABSENT, "Philips 8275A_8295"}, + { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, + { TUNER_ABSENT, "Microtune MT2266"}, + { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, + { TUNER_ABSENT, "LG TAPQ_H702F"}, + { TUNER_ABSENT, "TCL M09WPP_4N_E"}, + { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, + { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, }; static struct HAUPPAUGE_AUDIOIC @@ -344,37 +346,37 @@ static const char *decoderIC[] = { static int hasRadioTuner(int tunerType) { switch (tunerType) { - case 18: //PNPEnv_TUNER_FR1236_MK2: - case 23: //PNPEnv_TUNER_FM1236: - case 38: //PNPEnv_TUNER_FMR1236: - case 16: //PNPEnv_TUNER_FR1216_MK2: - case 19: //PNPEnv_TUNER_FR1246_MK2: - case 21: //PNPEnv_TUNER_FM1216: - case 24: //PNPEnv_TUNER_FM1246: - case 17: //PNPEnv_TUNER_FR1216MF_MK2: - case 22: //PNPEnv_TUNER_FM1216MF: - case 20: //PNPEnv_TUNER_FR1256_MK2: - case 25: //PNPEnv_TUNER_FM1256: - case 33: //PNPEnv_TUNER_4039FR5: - case 42: //PNPEnv_TUNER_4009FR5: - case 52: //PNPEnv_TUNER_4049FM5: - case 54: //PNPEnv_TUNER_4049FM5_AltI2C: - case 44: //PNPEnv_TUNER_4009FN5: - case 31: //PNPEnv_TUNER_TCPB9085P: - case 30: //PNPEnv_TUNER_TCPN9085D: - case 46: //PNPEnv_TUNER_TP18NSR01F: - case 47: //PNPEnv_TUNER_TP18PSB01D: - case 49: //PNPEnv_TUNER_TAPC_I001D: - case 60: //PNPEnv_TUNER_TAPE_S001D_MK3: - case 57: //PNPEnv_TUNER_FM1216ME_MK3: - case 59: //PNPEnv_TUNER_FM1216MP_MK3: - case 58: //PNPEnv_TUNER_FM1236_MK3: - case 68: //PNPEnv_TUNER_TAPE_H001F_MK3: - case 61: //PNPEnv_TUNER_TAPE_M001D_MK3: - case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM: - case 89: //PNPEnv_TUNER_TCL_MFPE05_2: - case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4: - case 105: + case 18: /* PNPEnv_TUNER_FR1236_MK2 */ + case 23: /* PNPEnv_TUNER_FM1236 */ + case 38: /* PNPEnv_TUNER_FMR1236 */ + case 16: /* PNPEnv_TUNER_FR1216_MK2 */ + case 19: /* PNPEnv_TUNER_FR1246_MK2 */ + case 21: /* PNPEnv_TUNER_FM1216 */ + case 24: /* PNPEnv_TUNER_FM1246 */ + case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */ + case 22: /* PNPEnv_TUNER_FM1216MF */ + case 20: /* PNPEnv_TUNER_FR1256_MK2 */ + case 25: /* PNPEnv_TUNER_FM1256 */ + case 33: /* PNPEnv_TUNER_4039FR5 */ + case 42: /* PNPEnv_TUNER_4009FR5 */ + case 52: /* PNPEnv_TUNER_4049FM5 */ + case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */ + case 44: /* PNPEnv_TUNER_4009FN5 */ + case 31: /* PNPEnv_TUNER_TCPB9085P */ + case 30: /* PNPEnv_TUNER_TCPN9085D */ + case 46: /* PNPEnv_TUNER_TP18NSR01F */ + case 47: /* PNPEnv_TUNER_TP18PSB01D */ + case 49: /* PNPEnv_TUNER_TAPC_I001D */ + case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */ + case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */ + case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ + case 58: /* PNPEnv_TUNER_FM1236_MK3 */ + case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ + case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ + case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ + case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ + case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ + case 105: return 1; } return 0; @@ -392,7 +394,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ** ** In our (ivtv) case we're interested in the following: ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into + ** hauppauge_tuner_fmt) ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) ** decoder proc: tag [09].01) @@ -451,16 +454,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ++i; } else { tveeprom_warn("Encountered bad packet header [%02x]. " - "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); + "Corrupt or not a Hauppauge eeprom.\n", + eeprom_data[i]); return; } if (debug) { - tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1); - for(j = 1; j < len; j++) { - printk(" %02x", eeprom_data[i + j]); - } - printk("\n"); + tveeprom_info("Tag [%02x] + %d bytes:", + eeprom_data[i], len - 1); + for (j = 1; j < len; j++) + printk(KERN_CONT " %02x", eeprom_data[i + j]); + printk(KERN_CONT "\n"); } /* process by tag */ @@ -511,16 +515,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); - if ( (eeprom_data[i + 8] & 0xf0) && - (tvee->serial_number < 0xffffff) ) { - tvee->MAC_address[0] = 0x00; - tvee->MAC_address[1] = 0x0D; - tvee->MAC_address[2] = 0xFE; - tvee->MAC_address[3] = eeprom_data[i + 7]; - tvee->MAC_address[4] = eeprom_data[i + 6]; - tvee->MAC_address[5] = eeprom_data[i + 5]; - tvee->has_MAC_address = 1; - } + if ((eeprom_data[i + 8] & 0xf0) && + (tvee->serial_number < 0xffffff)) { + tvee->MAC_address[0] = 0x00; + tvee->MAC_address[1] = 0x0D; + tvee->MAC_address[2] = 0xFE; + tvee->MAC_address[3] = eeprom_data[i + 7]; + tvee->MAC_address[4] = eeprom_data[i + 6]; + tvee->MAC_address[5] = eeprom_data[i + 5]; + tvee->has_MAC_address = 1; + } break; case 0x05: @@ -544,7 +548,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i + 3] << 16) + (eeprom_data[i + 4] << 24); tvee->revision = - eeprom_data[i +5 ] + + eeprom_data[i + 5] + (eeprom_data[i + 6] << 8) + (eeprom_data[i + 7] << 16); break; @@ -564,16 +568,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, case 0x0a: /* tag 'Tuner' */ if (beenhere == 0) { - tuner1 = eeprom_data[i+2]; - t_format1 = eeprom_data[i+1]; + tuner1 = eeprom_data[i + 2]; + t_format1 = eeprom_data[i + 1]; beenhere = 1; } else { /* a second (radio) tuner may be present */ - tuner2 = eeprom_data[i+2]; - t_format2 = eeprom_data[i+1]; - if (t_format2 == 0) { /* not a TV tuner? */ + tuner2 = eeprom_data[i + 2]; + t_format2 = eeprom_data[i + 1]; + /* not a TV tuner? */ + if (t_format2 == 0) tvee->has_radio = 1; /* must be radio */ - } } break; @@ -601,7 +605,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, /* case 0x12: tag 'InfoBits' */ default: - tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag); + tveeprom_dbg("Not sure what to do with tag [%02x]\n", + tag); /* dump the rest of the packet? */ } } @@ -615,7 +620,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); - tvee->rev_str[3] = 32 + ( tvee->revision & 0x3f); + tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); tvee->rev_str[4] = 0; } @@ -658,44 +663,40 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", tvee->model, tvee->rev_str, tvee->serial_number); - if (tvee->has_MAC_address == 1) { + if (tvee->has_MAC_address == 1) tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n", tvee->MAC_address[0], tvee->MAC_address[1], tvee->MAC_address[2], tvee->MAC_address[3], tvee->MAC_address[4], tvee->MAC_address[5]); - } tveeprom_info("tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], - t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], - t_format1); - if (tuner2) { + t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], + t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], + t_fmt_name1[6], t_fmt_name1[7], t_format1); + if (tuner2) tveeprom_info("second tuner model is %s (idx %d, type %d)\n", t_name2, tuner2, tvee->tuner2_type); - } - if (t_format2) { + if (t_format2) tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], - t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], - t_format2); - } - if (audioic<0) { + t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], + t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], + t_fmt_name2[6], t_fmt_name2[7], t_format2); + if (audioic < 0) { tveeprom_info("audio processor is unknown (no idx)\n"); - tvee->audio_processor=AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = AUDIO_CHIP_UNKNOWN; } else { if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", - audioIC[audioic].name,audioic); + audioIC[audioic].name, audioic); else tveeprom_info("audio processor is unknown (idx %d)\n", audioic); } - if (tvee->decoder_processor) { + if (tvee->decoder_processor) tveeprom_info("decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); - } if (tvee->has_ir == -1) tveeprom_info("has %sradio\n", tvee->has_radio ? "" : "no "); @@ -716,11 +717,13 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) int err; buf = 0; - if (1 != (err = i2c_master_send(c, &buf, 1))) { + err = i2c_master_send(c, &buf, 1); + if (err != 1) { tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } - if (len != (err = i2c_master_recv(c, eedata, len))) { + err = i2c_master_recv(c, eedata, len); + if (err != len) { tveeprom_warn("i2c eeprom read error (err=%d)\n", err); return -1; } @@ -731,9 +734,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) for (i = 0; i < len; i++) { if (0 == (i % 16)) tveeprom_info("%02x:", i); - printk(" %02x", eedata[i]); + printk(KERN_CONT " %02x", eedata[i]); if (15 == (i % 16)) - printk("\n"); + printk(KERN_CONT "\n"); } } return 0; @@ -765,9 +768,9 @@ tveeprom_command(struct i2c_client *client, switch (cmd) { case 0: - buf = kzalloc(256,GFP_KERNEL); - tveeprom_read(client,buf,256); - tveeprom_hauppauge_analog(client, &eeprom,buf); + buf = kzalloc(256, GFP_KERNEL); + tveeprom_read(client, buf, 256); + tveeprom_hauppauge_analog(client, &eeprom, buf); kfree(buf); eeprom_props[0] = eeprom.tuner_type; eeprom_props[1] = eeprom.tuner_formats; @@ -801,7 +804,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter, } static int -tveeprom_attach_adapter (struct i2c_adapter *adapter) +tveeprom_attach_adapter(struct i2c_adapter *adapter) { if (adapter->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adapter, &addr_data, tveeprom_detect_client); @@ -809,7 +812,7 @@ tveeprom_attach_adapter (struct i2c_adapter *adapter) } static int -tveeprom_detach_client (struct i2c_client *client) +tveeprom_detach_client(struct i2c_client *client) { int err; -- cgit v1.2.3 From ea48c13ad0e5626b827bd7076c22df1a352e3983 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 07:04:58 -0300 Subject: V4L/DVB (6861): cx2341x: command argument should be u32 instead of int Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx2341x.c | 2 +- drivers/media/video/cx88/cx88-blackbird.c | 2 +- drivers/media/video/ivtv/ivtv-mailbox.c | 2 +- drivers/media/video/ivtv/ivtv-mailbox.h | 2 +- drivers/media/video/pvrusb2/pvrusb2-encoder.c | 2 +- include/media/cx2341x.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 890c8867af1..c592899a231 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -775,7 +775,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) EXPORT_SYMBOL(cx2341x_fill_defaults); static int cx2341x_api(void *priv, cx2341x_mbox_func func, - int cmd, int args, ...) + u32 cmd, int args, ...) { u32 data[CX2341X_MBOX_MAX_DATA]; va_list vargs; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 5f79442924f..a99e9d5950a 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value) /* ------------------------------------------------------------------ */ -static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { struct cx8802_dev *dev = priv; unsigned long timeout; diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c index b05436da713..13a6c374d2d 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/drivers/media/video/ivtv/ivtv-mailbox.c @@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; } -int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { return ivtv_api(priv, cmd, in, data); } diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 71a54eef8fc..6ef12091e3f 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); -int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); +int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); #endif diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 52b39954f99..64062879981 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw, cx2341x.ko to write to our encoder (by handing it a pointer to this function). For earlier kernels this doesn't really matter. */ static int pvr2_encoder_cmd(void *ctxt, - int cmd, + u32 cmd, int arg_cnt_send, int arg_cnt_recv, u32 *argp) diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h index af8071d7620..5f4608e8847 100644 --- a/include/media/cx2341x.h +++ b/include/media/cx2341x.h @@ -83,7 +83,7 @@ struct cx2341x_mpeg_params { #define CX2341X_MBOX_MAX_DATA 16 extern const u32 cx2341x_mpeg_ctrls[]; -typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out, +typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); int cx2341x_update(void *priv, cx2341x_mbox_func func, const struct cx2341x_mpeg_params *old, -- cgit v1.2.3 From f69d419a0bdf4cd2551200b6777a226fea527d1a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 07:24:27 -0300 Subject: V4L/DVB (6862): ivtv: really remove i2c legacy support from drivers that no longer need it For some reason the include header wasn't changed from v4l2-i2c-drv-legacy.h to v4l2-i2c-drv.h in the previous patch. This is now corrected. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/m52790.c | 2 +- drivers/media/video/saa7127.c | 2 +- drivers/media/video/upd64031a.c | 2 +- drivers/media/video/upd64083.c | 2 +- drivers/media/video/vp27smpx.c | 2 +- drivers/media/video/wm8739.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 4d2a52204ad..d4bf14c284e 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); MODULE_AUTHOR("Hans Verkuil"); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index a5fbfe02533..b146eedfc7a 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -55,7 +55,7 @@ #include #include #include -#include +#include #include static int debug = 0; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 1b162f2dca9..bc8db9943b7 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include // --------------------- read registers functions define ----------------------- diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 0f9e86cfc62..d467cc34ac4 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include MODULE_DESCRIPTION("uPD64083 driver"); diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index cd98084ac09..2d97914d309 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include MODULE_DESCRIPTION("vp27smpx driver"); MODULE_AUTHOR("Hans Verkuil"); diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 1c30a5c8455..31795b4f8b6 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); -- cgit v1.2.3 From 8c9fc8de546134d021de58c7ade6f025c9d1da1c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 07:30:02 -0300 Subject: V4L/DVB (6863): upd64083: CodingStyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/upd64083.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index d467cc34ac4..2d9a88f70c8 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -17,7 +17,8 @@ * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ #include @@ -34,7 +35,7 @@ MODULE_DESCRIPTION("uPD64083 driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); @@ -85,7 +86,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val) buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val); + v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); } @@ -106,7 +107,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg) /* ------------------------------------------------------------------------ */ -static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) { struct upd64083_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -142,20 +143,23 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) + if (cmd == VIDIOC_DBG_G_REGISTER) { reg->val = upd64083_read(client, reg->reg & 0xff); - else - upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); + break; + } + upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); break; } #endif case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0); + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_UPD64083, 0); default: break; @@ -176,20 +180,19 @@ static int upd64083_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } i2c_set_clientdata(client, state); /* Initially assume that a ghost reduction chip is present */ state->mode = 0; /* YCS mode */ state->ext_y_adc = (1 << 5); memcpy(state->regs, upd64083_init, TOT_REGS); - for (i = 0; i < TOT_REGS; i++) { + for (i = 0; i < TOT_REGS; i++) upd64083_write(client, i, state->regs[i]); - } return 0; } -- cgit v1.2.3 From 79f998a71b9bca5a16b0b8c30e5c0c849705a5ec Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 07:34:15 -0300 Subject: V4L/DVB (6864): upd64031a: CodingStyle cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/upd64031a.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index bc8db9943b7..bd201397a2a 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -31,20 +31,20 @@ #include #include -// --------------------- read registers functions define ----------------------- +/* --------------------- read registers functions define -------------------- */ /* bit masks */ #define GR_MODE_MASK 0xc0 #define DIRECT_3DYCS_CONNECT_MASK 0xc0 #define SYNC_CIRCUIT_MASK 0xa0 -// ----------------------------------------------------------------------------- +/* -------------------------------------------------------------------------- */ MODULE_DESCRIPTION("uPD64031A driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); @@ -96,7 +96,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val) buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val); + v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); } @@ -116,7 +116,7 @@ static void upd64031a_change(struct i2c_client *client) /* ------------------------------------------------------------------------ */ -static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) { struct upd64031a_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -140,8 +140,10 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * state->gr_mode = (route->input & 3) << 6; state->direct_3dycs_connect = (route->input & 0xc) << 4; - state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; - state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; + state->ext_comp_sync = + (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; + state->ext_vert_sync = + (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode; r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) | state->ext_comp_sync | state->ext_vert_sync; @@ -165,20 +167,23 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) + if (cmd == VIDIOC_DBG_G_REGISTER) { reg->val = upd64031a_read(client, reg->reg & 0xff); - else - upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff); + break; + } + upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff); break; } #endif case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0); + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_UPD64031A, 0); default: break; @@ -198,20 +203,19 @@ static int upd64031a_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } i2c_set_clientdata(client, state); memcpy(state->regs, upd64031a_init, sizeof(state->regs)); state->gr_mode = UPD64031A_GR_ON << 6; state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4; state->ext_comp_sync = state->ext_vert_sync = 0; - for (i = 0; i < TOT_REGS; i++) { + for (i = 0; i < TOT_REGS; i++) upd64031a_write(client, i, state->regs[i]); - } return 0; } -- cgit v1.2.3 From 35df38c015866b3c28bfb1914b14eba92086cdd1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 07:40:54 -0300 Subject: V4L/DVB (6865): vp27smpx: CodingStyle cleanup Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vp27smpx.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 2d97914d309..282c81403c9 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -50,27 +50,26 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) u8 data[3] = { 0x00, 0x00, 0x04 }; switch (audmode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - data[1] = 0x01; - break; - case V4L2_TUNER_MODE_LANG2: - data[1] = 0x02; - break; + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; } - if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { - v4l_err(client, "%s: I/O error setting audmode\n", client->name); - } - else { + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) + v4l_err(client, "%s: I/O error setting audmode\n", + client->name); + else state->audmode = audmode; - } } -static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) { struct vp27smpx_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; @@ -99,7 +98,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, void *a break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_VP27SMPX, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Audio Mode: %u%s\n", state->audmode, @@ -131,12 +131,12 @@ static int vp27smpx_probe(struct i2c_client *client) snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); - v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } state->audmode = V4L2_TUNER_MODE_STEREO; i2c_set_clientdata(client, state); -- cgit v1.2.3 From d52c7385ec8d4d2081b0db47e309723ce3eae816 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 08:25:18 -0300 Subject: V4L/DVB (6866): msp3400: CodingStyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-driver.c | 167 +++++++++++++++++++-------------- drivers/media/video/msp3400-kthreads.c | 166 ++++++++++++++++++-------------- 2 files changed, 195 insertions(+), 138 deletions(-) diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index f4c14604b0b..7a11f3159e3 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -42,7 +42,8 @@ * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ @@ -72,7 +73,8 @@ int msp_debug; /* msp_debug output */ int msp_once; /* no continous stereo monitoring */ int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ -int msp_standard = 1; /* Override auto detect of audio msp_standard, if needed. */ +int msp_standard = 1; /* Override auto detect of audio msp_standard, + if needed. */ int msp_dolby; int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual @@ -82,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual module_param(opmode, int, 0444); /* read-write */ -module_param_named(once,msp_once, bool, 0644); -module_param_named(debug,msp_debug, int, 0644); -module_param_named(stereo_threshold,msp_stereo_thresh, int, 0644); -module_param_named(standard,msp_standard, int, 0644); -module_param_named(amsound,msp_amsound, bool, 0644); -module_param_named(dolby,msp_dolby, bool, 0644); +module_param_named(once, msp_once, bool, 0644); +module_param_named(debug, msp_debug, int, 0644); +module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); +module_param_named(standard, msp_standard, int, 0644); +module_param_named(amsound, msp_amsound, bool, 0644); +module_param_named(dolby, msp_dolby, bool, 0644); MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); @@ -161,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); + v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", + dev, addr, retval); return retval; } @@ -191,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); + v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", + dev, addr, val); for (err = 0; err < 3; err++) { if (i2c_master_send(client, buffer, 5) == 5) break; @@ -200,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } @@ -274,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) state->acb = 0xf60; /* Mute Input and SCART 1 Output */ v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); + scart_names[in], out, state->acb); msp_write_dsp(client, 0x13, state->acb); /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ @@ -293,7 +297,8 @@ void msp_set_audio(struct i2c_client *client) val = (state->volume * 0x7f / 65535) << 8; v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", - state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no", + state->muted ? "on" : "off", + state->scan_in_progress ? "yes" : "no", state->volume); msp_write_dsp(client, 0x0000, val); @@ -682,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a); switch (*a) { - case 1024000: - state->i2s_mode = 0; - break; - case 2048000: - state->i2s_mode = 1; - break; - default: - return -EINVAL; + case 1024000: + state->i2s_mode = 0; + break; + case 2048000: + state->i2s_mode = 1; + break; + default: + return -EINVAL; } break; } @@ -699,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - default: - break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; } if (!state->has_sound_processing) return -EINVAL; switch (qc->id) { - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); - default: - return -EINVAL; + case V4L2_CID_AUDIO_LOUDNESS: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; } } @@ -736,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) state->volume, state->muted ? " (muted)" : ""); if (state->has_sound_processing) { v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", - state->balance, state->bass, state->treble, + state->balance, state->bass, + state->treble, state->loudness ? "on" : "off"); } switch (state->mode) { case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; case MSP_MODE_FM_RADIO: p = "FM Radio"; break; - case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break; + case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; @@ -773,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); + return v4l2_chip_ident_i2c_client(client, arg, state->ident, + (state->rev1 << 16) | state->rev2); default: /* unknown */ @@ -816,9 +823,8 @@ static int msp_probe(struct i2c_client *client) } state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) { + if (!state) return -ENOMEM; - } i2c_set_clientdata(client, state); @@ -840,9 +846,11 @@ static int msp_probe(struct i2c_client *client) state->rev1 = msp_read_dsp(client, 0x1e); if (state->rev1 != -1) state->rev2 = msp_read_dsp(client, 0x1f); - v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); + v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", + state->rev1, state->rev2); if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); + v4l_dbg(1, msp_debug, client, + "not an msp3400 (cannot read chip version)\n"); kfree(state); return -ENODEV; } @@ -860,37 +868,55 @@ static int msp_probe(struct i2c_client *client) msp_family, msp_product, msp_revision, msp_hard, msp_rom); /* Rev B=2, C=3, D=4, G=7 */ - state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; + state->ident = msp_family * 10000 + 4000 + msp_product * 10 + + msp_revision - '@'; /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ - state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; + state->has_nicam = + msp_prod_hi == 1 || msp_prod_hi == 5; /* Has radio support: was added with revision G */ - state->has_radio = msp_revision >= 'G'; + state->has_radio = + msp_revision >= 'G'; /* Has headphones output: not for stripped down products */ - state->has_headphones = msp_prod_lo < 5; + state->has_headphones = + msp_prod_lo < 5; /* Has scart2 input: not in stripped down products of the '3' family */ - state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7; + state->has_scart2 = + msp_family >= 4 || msp_prod_lo < 7; /* Has scart3 input: not in stripped down products of the '3' family */ - state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5; + state->has_scart3 = + msp_family >= 4 || msp_prod_lo < 5; /* Has scart4 input: not in pre D revisions, not in stripped D revs */ - state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); - /* Has scart2 output: not in stripped down products of the '3' family */ - state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5; + state->has_scart4 = + msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); + /* Has scart2 output: not in stripped down products of + * the '3' family */ + state->has_scart2_out = + msp_family >= 4 || msp_prod_lo < 5; /* Has scart2 a volume control? Not in pre-D revisions. */ - state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out; + state->has_scart2_out_volume = + msp_revision > 'C' && state->has_scart2_out; /* Has a configurable i2s out? */ - state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7; - /* Has subwoofer output: not in pre-D revs and not in stripped down products */ - state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5; - /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in - stripped down products */ - state->has_sound_processing = msp_prod_lo < 7; + state->has_i2s_conf = + msp_revision >= 'G' && msp_prod_lo < 7; + /* Has subwoofer output: not in pre-D revs and not in stripped down + * products */ + state->has_subwoofer = + msp_revision >= 'D' && msp_prod_lo < 5; + /* Has soundprocessing (bass/treble/balance/loudness/equalizer): + * not in stripped down products */ + state->has_sound_processing = + msp_prod_lo < 7; /* Has Virtual Dolby Surround: only in msp34x1 */ - state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1; + state->has_virtual_dolby_surround = + msp_revision == 'G' && msp_prod_lo == 1; /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ - state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2; - /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */ - state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; + state->has_dolby_pro_logic = + msp_revision == 'G' && msp_prod_lo == 2; + /* The msp343xG supports BTSC only and cannot do Automatic Standard + * Detection. */ + state->force_btsc = + msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; state->opmode = opmode; if (state->opmode == OPMODE_AUTO) { @@ -905,32 +931,33 @@ static int msp_probe(struct i2c_client *client) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) - printk("supports nicam and radio, "); + printk(KERN_CONT "supports nicam and radio, "); else if (state->has_nicam) - printk("supports nicam, "); + printk(KERN_CONT "supports nicam, "); else if (state->has_radio) - printk("supports radio, "); - printk("mode is "); + printk(KERN_CONT "supports radio, "); + printk(KERN_CONT "mode is "); /* version-specific initialization */ switch (state->opmode) { case OPMODE_MANUAL: - printk("manual"); + printk(KERN_CONT "manual"); thread_func = msp3400c_thread; break; case OPMODE_AUTODETECT: - printk("autodetect"); + printk(KERN_CONT "autodetect"); thread_func = msp3410d_thread; break; case OPMODE_AUTOSELECT: - printk("autodetect and autoselect"); + printk(KERN_CONT "autodetect and autoselect"); thread_func = msp34xxg_thread; break; } - printk("\n"); + printk(KERN_CONT "\n"); /* startup control thread if needed */ if (thread_func) { diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index d5ee2629121..61ec794a737 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -15,7 +15,8 @@ * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ @@ -78,37 +79,37 @@ static struct msp3400c_init_data_dem { {75, 19, 36, 35, 39, 40}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0500, 0x0020, 0x3000 - },{ /* AM (for carrier detect / msp3410) */ + }, { /* AM (for carrier detect / msp3410) */ {-1, -1, -8, 2, 59, 126}, {-1, -1, -8, 2, 59, 126}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0100, 0x0020, 0x3000 - },{ /* FM Radio */ + }, { /* FM Radio */ {-8, -8, 4, 6, 78, 107}, {-8, -8, 4, 6, 78, 107}, MSP_CARRIER(10.7), MSP_CARRIER(10.7), 0x00d0, 0x0480, 0x0020, 0x3000 - },{ /* Terrestial FM-mono + FM-stereo */ + }, { /* Terrestial FM-mono + FM-stereo */ {3, 18, 27, 48, 66, 72}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000 - },{ /* Sat FM-mono */ + }, { /* Sat FM-mono */ { 1, 9, 14, 24, 33, 37}, { 3, 18, 27, 48, 66, 72}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000 - },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ + }, { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ {-2, -8, -10, 10, 50, 86}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000 - },{ /* NICAM/FM -- I (6.0/6.552) */ + }, { /* NICAM/FM -- I (6.0/6.552) */ {2, 4, -6, -4, 40, 94}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(6.0), MSP_CARRIER(6.0), 0x00d0, 0x0040, 0x0120, 0x3000 - },{ /* NICAM/AM -- L (6.5/5.85) */ + }, { /* NICAM/AM -- L (6.5/5.85) */ {-2, -8, -10, 10, 50, 86}, {-4, -12, -9, 23, 79, 126}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), @@ -224,7 +225,9 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) nor do they support stereo BTSC. */ static void msp3400c_set_audmode(struct i2c_client *client) { - static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" }; + static char *strmode[] = { + "mono", "stereo", "lang2", "lang1", "lang1+lang2" + }; struct msp_state *state = i2c_get_clientdata(client); char *modestr = (state->audmode >= 0 && state->audmode < 5) ? strmode[state->audmode] : "unknown"; @@ -298,19 +301,23 @@ static void msp3400c_set_audmode(struct i2c_client *client) case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "NICAM set_audmode: %s\n", modestr); if (state->nicam_on) src = 0x0100; /* NICAM */ break; case MSP_MODE_BTSC: - v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "BTSC set_audmode: %s\n", modestr); break; case MSP_MODE_EXTERN: - v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "extern set_audmode: %s\n", modestr); src = 0x0200; /* SCART */ break; case MSP_MODE_FM_RADIO: - v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "FM-Radio set_audmode: %s\n", modestr); break; default: v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); @@ -342,7 +349,8 @@ static void msp3400c_set_audmode(struct i2c_client *client) src |= 0x0010; break; } - v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src); + v4l_dbg(1, msp_debug, client, + "set_audmode final source/matrix = 0x%x\n", src); msp_set_source(client, src); } @@ -351,22 +359,26 @@ static void msp3400c_print_mode(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (state->main == state->second) { - v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - } else { - v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - } + if (state->main == state->second) + v4l_dbg(1, msp_debug, client, + "mono sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + else + v4l_dbg(1, msp_debug, client, + "main sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) - v4l_dbg(1, msp_debug, client, "NICAM/FM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second/910) % 1000); + v4l_dbg(1, msp_debug, client, + "NICAM/FM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second/910) % 1000); if (state->mode == MSP_MODE_AM_NICAM) - v4l_dbg(1, msp_debug, client, "NICAM/AM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); + v4l_dbg(1, msp_debug, client, + "NICAM/AM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { - v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); + v4l_dbg(1, msp_debug, client, + "FM-stereo carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); } } @@ -385,7 +397,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client) val = msp_read_dsp(client, 0x18); if (val > 32767) val -= 65536; - v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val); + v4l_dbg(2, msp_debug, client, + "stereo detect register: %d\n", val); if (val > 8192) { rxsubchans = V4L2_TUNER_SUB_STEREO; } else if (val < -4096) { @@ -430,7 +443,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client) } if (rxsubchans != state->rxsubchans) { update = 1; - v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n", + v4l_dbg(1, msp_debug, client, + "watch: rxsubchans %02x => %02x\n", state->rxsubchans, rxsubchans); state->rxsubchans = rxsubchans; } @@ -452,9 +466,8 @@ static void watch_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (msp_detect_stereo(client)) { + if (msp_detect_stereo(client)) msp_set_audmode(client); - } if (msp_once) state->watch_stereo = 0; @@ -465,7 +478,7 @@ int msp3400c_thread(void *data) struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); struct msp3400c_carrier_detect *cd; - int count, max1, max2, val1, val2, val, this; + int count, max1, max2, val1, val2, val, i; v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); @@ -475,7 +488,7 @@ int msp3400c_thread(void *data) msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); - restart: +restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -483,7 +496,8 @@ int msp3400c_thread(void *data) if (state->radio || MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ - v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -514,16 +528,17 @@ int msp3400c_thread(void *data) v4l_dbg(1, msp_debug, client, "AM sound override\n"); } - for (this = 0; this < count; this++) { - msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); - if (msp_sleep(state,100)) + for (i = 0; i < count; i++) { + msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); + if (msp_sleep(state, 100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val1 < val) - val1 = val, max1 = this; - v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name); + val1 = val, max1 = i; + v4l_dbg(1, msp_debug, client, + "carrier1 val: %5d / %s\n", val, cd[i].name); } /* carrier detect pass #2 -- second (stereo) carrier */ @@ -550,16 +565,17 @@ int msp3400c_thread(void *data) count = 0; max2 = 0; } - for (this = 0; this < count; this++) { - msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); - if (msp_sleep(state,100)) + for (i = 0; i < count; i++) { + msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); + if (msp_sleep(state, 100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val2 < val) - val2 = val, max2 = this; - v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name); + val2 = val, max2 = i; + v4l_dbg(1, msp_debug, client, + "carrier2 val: %5d / %s\n", val, cd[i].name); } /* program the msp3400 according to the results */ @@ -611,7 +627,7 @@ int msp3400c_thread(void *data) break; case 0: /* 4.5 */ default: - no_second: +no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); break; @@ -632,7 +648,8 @@ int msp3400c_thread(void *data) while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; - if (count) count--; + if (count) + count--; watch_stereo(client); } } @@ -651,10 +668,10 @@ int msp3410d_thread(void *data) set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); - msp_sleep(state,-1); + msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); - restart: +restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -662,7 +679,8 @@ int msp3410d_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -673,7 +691,8 @@ int msp3410d_thread(void *data) msp_set_audio(client); /* start autodetect. Note: autodetect is not supported for - NTSC-M and radio, hence we force the standard in those cases. */ + NTSC-M and radio, hence we force the standard in those + cases. */ if (state->radio) std = 0x40; else @@ -686,8 +705,9 @@ int msp3410d_thread(void *data) goto restart; if (msp_debug) - v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n", - msp_standard_std_name(std), std); + v4l_dbg(2, msp_debug, client, + "setting standard: %s (0x%04x)\n", + msp_standard_std_name(std), std); if (std != 1) { /* programmed some specific mode */ @@ -703,7 +723,8 @@ int msp3410d_thread(void *data) val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; - v4l_dbg(2, msp_debug, client, "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, + "detection still in progress\n"); } } for (i = 0; msp_stdlist[i].name != NULL; i++) @@ -716,12 +737,13 @@ int msp3410d_thread(void *data) state->std = val; state->rxsubchans = V4L2_TUNER_SUB_MONO; - if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && - (val != 0x0009)) { + if (msp_amsound && !state->radio && + (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { /* autodetection has failed, let backup */ v4l_dbg(1, msp_debug, client, "autodetection failed," " switching to backup standard: %s (0x%04x)\n", - msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); + msp_stdlist[8].name ? + msp_stdlist[8].name : "unknown", val); state->std = val = 0x0009; msp_write_dem(client, 0x20, val); } @@ -786,7 +808,8 @@ int msp3410d_thread(void *data) while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; - if (count) count--; + if (count) + count--; watch_stereo(client); } } @@ -872,8 +895,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) else source = (in << 8) | matrix; - v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n", - in, source, reg); + v4l_dbg(1, msp_debug, client, + "set source to %d (0x%x) for output %02x\n", in, source, reg); msp_write_dsp(client, reg, source); } @@ -948,7 +971,7 @@ int msp34xxg_thread(void *data) msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); - restart: +restart: v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -956,7 +979,8 @@ int msp34xxg_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -972,7 +996,8 @@ int msp34xxg_thread(void *data) goto unmute; /* watch autodetect */ - v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n"); + v4l_dbg(1, msp_debug, client, + "started autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { if (msp_sleep(state, 100)) goto restart; @@ -983,15 +1008,18 @@ int msp34xxg_thread(void *data) state->std = val; break; } - v4l_dbg(2, msp_debug, client, "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, + "detection still in progress\n"); } if (state->std == 1) { - v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); + v4l_dbg(1, msp_debug, client, + "detection still in progress after 10 tries. giving up.\n"); continue; } - unmute: - v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n", +unmute: + v4l_dbg(1, msp_debug, client, + "detected standard: %s (0x%04x)\n", msp_standard_std_name(state->std), state->std); if (state->std == 9) { @@ -1046,9 +1074,11 @@ static int msp34xxg_detect_stereo(struct i2c_client *client) if (state->std == 0x20) state->rxsubchans |= V4L2_TUNER_SUB_SAP; else - state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + state->rxsubchans = + V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } - v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", + v4l_dbg(1, msp_debug, client, + "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", status, is_stereo, is_bilingual, state->rxsubchans); return (oldrx != state->rxsubchans); } -- cgit v1.2.3 From 9fad368b6dff95b8b009a6b8eed42a549a05b263 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 12 Dec 2007 10:23:52 -0300 Subject: V4L/DVB (6867): saa7127: CodingStyle cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7127.c | 61 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index b146eedfc7a..06c88db656b 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -58,8 +58,8 @@ #include #include -static int debug = 0; -static int test_image = 0; +static int debug; +static int test_image; MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver"); MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); @@ -357,9 +357,10 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data if (enable && (data->field != 0 || data->line != 21)) return -EINVAL; if (state->cc_enable != enable) { - v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off"); + v4l_dbg(1, debug, client, + "Turn CC %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, - (state->xds_enable << 7) | (enable << 6) | 0x11); + (state->xds_enable << 7) | (enable << 6) | 0x11); state->cc_enable = enable; } if (!enable) @@ -417,7 +418,8 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat saa7127_write(client, 0x26, data->data[0]); saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f)); - v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); + v4l_dbg(1, debug, client, + "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; return 0; } @@ -504,7 +506,8 @@ static int saa7127_set_output_type(struct i2c_client *client, int output) default: return -EINVAL; } - v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]); + v4l_dbg(1, debug, client, + "Selecting %s output type\n", output_strs[output]); /* Configure Encoder */ saa7127_write(client, 0x2d, state->reg_2d); @@ -566,12 +569,10 @@ static int saa7127_command(struct i2c_client *client, { int rc = 0; - if (state->input_type != route->input) { + if (state->input_type != route->input) rc = saa7127_set_input_type(client, route->input); - } - if (rc == 0 && state->output_type != route->output) { + if (rc == 0 && state->output_type != route->output) rc = saa7127_set_output_type(client, route->output); - } return rc; } @@ -617,7 +618,8 @@ static int saa7127_command(struct i2c_client *client, { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -634,16 +636,16 @@ static int saa7127_command(struct i2c_client *client, struct v4l2_sliced_vbi_data *data = arg; switch (data->id) { - case V4L2_SLICED_WSS_625: - return saa7127_set_wss(client, data); - case V4L2_SLICED_VPS: - return saa7127_set_vps(client, data); - case V4L2_SLICED_CAPTION_525: - if (data->field == 0) - return saa7127_set_cc(client, data); - return saa7127_set_xds(client, data); - default: - return -EINVAL; + case V4L2_SLICED_WSS_625: + return saa7127_set_wss(client, data); + case V4L2_SLICED_VPS: + return saa7127_set_vps(client, data); + case V4L2_SLICED_CAPTION_525: + if (data->field == 0) + return saa7127_set_cc(client, data); + return saa7127_set_xds(client, data); + default: + return -EINVAL; } break; } @@ -671,7 +673,8 @@ static int saa7127_probe(struct i2c_client *client) snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", client->addr << 1); + v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", + client->addr << 1); /* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0. @@ -685,9 +688,8 @@ static int saa7127_probe(struct i2c_client *client) } state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } i2c_set_clientdata(client, state); @@ -701,25 +703,26 @@ static int saa7127_probe(struct i2c_client *client) saa7127_set_wss(client, &vbi); saa7127_set_cc(client, &vbi); saa7127_set_xds(client, &vbi); - if (test_image == 1) { + if (test_image == 1) /* The Encoder has an internal Colorbar generator */ /* This can be used for debugging */ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE); - } else { + else saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL); - } saa7127_set_video_enable(client, 1); /* Detect if it's an saa7129 */ read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - v4l_info(client, "saa7129 found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "saa7129 found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); saa7127_write_inittab(client, saa7129_init_config_extra); state->ident = V4L2_IDENT_SAA7129; } else { - v4l_info(client, "saa7127 found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + v4l_info(client, "saa7127 found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state->ident = V4L2_IDENT_SAA7127; } return 0; -- cgit v1.2.3 From 0b394def21e7d3bd02aeee5570473582ce7984ec Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 18 Dec 2007 19:27:31 -0300 Subject: V4L/DVB (6868): i2c-id.h: add I2C_DRIVERID_CS5345 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/i2c-id.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index adbdc6da39c..c7a51a196f5 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -126,6 +126,7 @@ #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */ #define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */ +#define I2C_DRIVERID_CS5345 96 /* cs5345 audio processor */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ -- cgit v1.2.3 From 6fb377f85cb8c2c1580ce8b134c887a7b53c7aa9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 18 Dec 2007 19:40:44 -0300 Subject: V4L/DVB (6869): cs5345: new i2c driver Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 10 +++ drivers/media/video/Makefile | 1 + drivers/media/video/cs5345.c | 168 ++++++++++++++++++++++++++++++++++++++++ include/media/cs5345.h | 39 ++++++++++ include/media/v4l2-chip-ident.h | 3 + 5 files changed, 221 insertions(+) create mode 100644 drivers/media/video/cs5345.c create mode 100644 include/media/cs5345.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 6c7835629bc..7431f6da5ca 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -109,6 +109,16 @@ config VIDEO_MSP3400 To compile this driver as a module, choose M here: the module will be called msp3400. +config VIDEO_CS5345 + tristate "Cirrus Logic CS5345 audio ADC" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the Cirrus Logic CS5345 24-bit, 192 kHz + stereo A/D converter. + + To compile this driver as a module, choose M here: the + module will be called cs5345. + config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index a837e1ea518..74a2a1c45fe 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o +obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c new file mode 100644 index 00000000000..fae469ce16f --- /dev/null +++ b/drivers/media/video/cs5345.c @@ -0,0 +1,168 @@ +/* + * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC + * Copyright (C) 2007 Hans Verkuil + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug; + +module_param(debug, bool, 0644); + +MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); + + +/* ----------------------------------------------------------------------- */ + +static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int cs5345_read(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) +{ + struct v4l2_routing *route = arg; + struct v4l2_control *ctrl = arg; + + switch (cmd) { + case VIDIOC_INT_G_AUDIO_ROUTING: + route->input = cs5345_read(client, 0x09) & 7; + route->input |= cs5345_read(client, 0x05) & 0x70; + route->output = 0; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + if ((route->input & 0xf) > 6) { + v4l_err(client, "Invalid input %d.\n", route->input); + return -EINVAL; + } + cs5345_write(client, 0x09, route->input & 0xf); + cs5345_write(client, 0x05, route->input & 0xf0); + break; + + case VIDIOC_G_CTRL: + if (ctrl->id == V4L2_CID_AUDIO_MUTE) { + ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0; + break; + } + if (ctrl->id != V4L2_CID_AUDIO_VOLUME) + return -EINVAL; + ctrl->value = cs5345_read(client, 0x07) & 0x3f; + if (ctrl->value >= 32) + ctrl->value = ctrl->value - 64; + break; + + case VIDIOC_S_CTRL: + break; + if (ctrl->id == V4L2_CID_AUDIO_MUTE) { + cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0); + break; + } + if (ctrl->id != V4L2_CID_AUDIO_VOLUME) + return -EINVAL; + if (ctrl->value > 24 || ctrl->value < -24) + return -EINVAL; + cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f); + cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = cs5345_read(client, reg->reg & 0x1f); + else + cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f); + break; + } +#endif + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_CS5345, 0); + + case VIDIOC_LOG_STATUS: + { + u8 v = cs5345_read(client, 0x09) & 7; + u8 m = cs5345_read(client, 0x04); + int vol = cs5345_read(client, 0x08) & 0x3f; + + v4l_info(client, "Input: %d%s\n", v, + (m & 0x80) ? " (muted)" : ""); + if (vol >= 32) + vol = vol - 64; + v4l_info(client, "Volume: %d dB\n", vol); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int cs5345_probe(struct i2c_client *client) +{ + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + cs5345_write(client, 0x02, 0x00); + cs5345_write(client, 0x04, 0x01); + cs5345_write(client, 0x09, 0x01); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cs5345", + .driverid = I2C_DRIVERID_CS5345, + .command = cs5345_command, + .probe = cs5345_probe, +}; + diff --git a/include/media/cs5345.h b/include/media/cs5345.h new file mode 100644 index 00000000000..6ccae24e65e --- /dev/null +++ b/include/media/cs5345.h @@ -0,0 +1,39 @@ +/* + cs5345.h - definition for cs5345 inputs and outputs + + Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) + + 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 + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _CS5345_H_ +#define _CS5345_H_ + +/* CS5345 HW inputs */ +#define CS5345_IN_MIC 0 +#define CS5345_IN_1 1 +#define CS5345_IN_2 2 +#define CS5345_IN_3 3 +#define CS5345_IN_4 4 +#define CS5345_IN_5 5 +#define CS5345_IN_6 6 + +#define CS5345_MCLK_1 0x00 +#define CS5345_MCLK_1_5 0x10 +#define CS5345_MCLK_2 0x20 +#define CS5345_MCLK_3 0x30 +#define CS5345_MCLK_4 0x40 + +#endif diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 2442c281e4f..032bb75f69c 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -68,6 +68,9 @@ enum { /* module vp27smpx: just ident 2700 */ V4L2_IDENT_VP27SMPX = 2700, + /* module cs5345: just ident 5345 */ + V4L2_IDENT_CS5345 = 5345, + /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, -- cgit v1.2.3 From 89f6475857b89e956a8bcfef64944409ce4173b4 Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Fri, 21 Dec 2007 08:56:44 -0300 Subject: V4L/DVB (6873): Fixes issues listed by checkpatch Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt312.c | 131 ++++++++++++++++++++---------------- drivers/media/dvb/frontends/mt312.h | 15 ++--- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 0606b9a5b61..55d42440e97 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -37,9 +37,9 @@ struct mt312_state { - struct i2c_adapter* i2c; + struct i2c_adapter *i2c; /* configuration settings */ - const struct mt312_config* config; + const struct mt312_config *config; struct dvb_frontend frontend; u8 id; @@ -49,14 +49,15 @@ struct mt312_state { static int debug; #define dprintk(args...) \ do { \ - if (debug) printk(KERN_DEBUG "mt312: " args); \ + if (debug) \ + printk(KERN_DEBUG "mt312: " args); \ } while (0) #define MT312_SYS_CLK 90000000UL /* 90 MHz */ #define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */ #define MT312_PLL_CLK 10000000UL /* 10 MHz */ -static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, +static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, void *buf, const size_t count) { int ret; @@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, return -EREMOTEIO; } - if(debug) { + if (debug) { int i; dprintk("R(%d):", reg & 0x7f); for (i = 0; i < count; i++) @@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, return 0; } -static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg, +static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, const void *src, const size_t count) { int ret; u8 buf[count + 1]; struct i2c_msg msg; - if(debug) { + if (debug) { int i; dprintk("W(%d):", reg & 0x7f); for (i = 0; i < count; i++) @@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg, return 0; } -static inline int mt312_readreg(struct mt312_state* state, +static inline int mt312_readreg(struct mt312_state *state, const enum mt312_reg_addr reg, u8 *val) { return mt312_read(state, reg, val, 1); } -static inline int mt312_writereg(struct mt312_state* state, +static inline int mt312_writereg(struct mt312_state *state, const enum mt312_reg_addr reg, const u8 val) { return mt312_write(state, reg, &val, 1); @@ -140,12 +141,12 @@ static inline u32 mt312_div(u32 a, u32 b) return (a + (b / 2)) / b; } -static int mt312_reset(struct mt312_state* state, const u8 full) +static int mt312_reset(struct mt312_state *state, const u8 full) { return mt312_writereg(state, RESET, full ? 0x80 : 0x40); } -static int mt312_get_inversion(struct mt312_state* state, +static int mt312_get_inversion(struct mt312_state *state, fe_spectral_inversion_t *i) { int ret; @@ -160,7 +161,7 @@ static int mt312_get_inversion(struct mt312_state* state, return 0; } -static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) +static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) { int ret; u8 sym_rate_h; @@ -172,7 +173,8 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0) return ret; - if (sym_rate_h & 0x80) { /* symbol rate search was used */ + if (sym_rate_h & 0x80) { + /* symbol rate search was used */ if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0) return ret; @@ -192,7 +194,8 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) dec_ratio = ((buf[0] >> 5) & 0x07) * 32; - if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) + if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, + sizeof(buf))) < 0) return ret; sym_rat_op = (buf[0] << 8) | buf[1]; @@ -207,7 +210,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) return 0; } -static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) +static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) { const fe_code_rate_t fec_tab[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, @@ -224,14 +227,15 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) return 0; } -static int mt312_initfe(struct dvb_frontend* fe) +static int mt312_initfe(struct dvb_frontend *fe) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; /* wake up */ - if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0) + if ((ret = mt312_writereg(state, CONFIG, + (state->frequency == 60 ? 0x88 : 0x8c))) < 0) return ret; /* wait at least 150 usec */ @@ -241,17 +245,20 @@ static int mt312_initfe(struct dvb_frontend* fe) if ((ret = mt312_reset(state, 1)) < 0) return ret; -// Per datasheet, write correct values. 09/28/03 ACCJr. -// If we don't do this, we won't get FE_HAS_VITERBI in the VP310. +/* Per datasheet, write correct values. 09/28/03 ACCJr. + * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */ { - u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00}; + u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02, + 0x01, 0x00, 0x00, 0x00 }; - if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0) + if ((ret = mt312_write(state, VIT_SETUP, buf_def, + sizeof(buf_def))) < 0) return ret; } /* SYS_CLK */ - buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000); + buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : + MT312_SYS_CLK) * 2, 1000000); /* DISEQC_RATIO */ buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); @@ -278,7 +285,7 @@ static int mt312_initfe(struct dvb_frontend* fe) return 0; } -static int mt312_send_master_cmd(struct dvb_frontend* fe, +static int mt312_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *c) { struct mt312_state *state = fe->demodulator_priv; @@ -303,14 +310,14 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe, /* set DISEQC_MODE[2:0] to zero if a return message is expected */ if (c->msg[0] & 0x02) - if ((ret = - mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) + if ((ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40))) < 0) return ret; return 0; } -static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) +static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) { struct mt312_state *state = fe->demodulator_priv; const u8 mini_tab[2] = { 0x02, 0x03 }; @@ -332,7 +339,7 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) return 0; } -static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) +static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) { struct mt312_state *state = fe->demodulator_priv; const u8 tone_tab[2] = { 0x01, 0x00 }; @@ -354,7 +361,7 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) return 0; } -static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) +static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) { struct mt312_state *state = fe->demodulator_priv; const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; @@ -365,7 +372,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) return mt312_writereg(state, DISEQC_MODE, volt_tab[v]); } -static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) +static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -376,7 +383,8 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) return ret; - dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); + dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," + " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); if (status[0] & 0xc0) *s |= FE_HAS_SIGNAL; /* signal noise ratio */ @@ -392,7 +400,7 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) return 0; } -static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) +static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -406,7 +414,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) return 0; } -static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength) +static int mt312_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -427,7 +436,7 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren return 0; } -static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) +static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -441,7 +450,7 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) return 0; } -static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) +static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -455,7 +464,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) return 0; } -static int mt312_set_frontend(struct dvb_frontend* fe, +static int mt312_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct mt312_state *state = fe->demodulator_priv; @@ -491,22 +500,24 @@ static int mt312_set_frontend(struct dvb_frontend* fe, switch (state->id) { case ID_VP310: - // For now we will do this only for the VP310. - // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03 + /* For now we will do this only for the VP310. + * It should be better for the mt312 as well, + * but tuning will be slower. ACCJr 09/29/03 + */ ret = mt312_readreg(state, CONFIG, &config_val); if (ret < 0) return ret; - if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz - { - if ((config_val & 0x0c) == 0x08) { //We are running 60MHz + if (p->u.qpsk.symbol_rate >= 30000000) { + /* Note that 30MS/s should use 90MHz */ + if ((config_val & 0x0c) == 0x08) { + /* We are running 60MHz */ state->frequency = 90; if ((ret = mt312_initfe(fe)) < 0) return ret; } - } - else - { - if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz + } else { + if ((config_val & 0x0c) == 0x0C) { + /* We are running 90MHz */ state->frequency = 60; if ((ret = mt312_initfe(fe)) < 0) return ret; @@ -523,7 +534,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe, if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } /* sr = (u16)(sr * 256.0 / 1000000.0) */ @@ -553,7 +565,7 @@ static int mt312_set_frontend(struct dvb_frontend* fe, return 0; } -static int mt312_get_frontend(struct dvb_frontend* fe, +static int mt312_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct mt312_state *state = fe->demodulator_priv; @@ -571,9 +583,9 @@ static int mt312_get_frontend(struct dvb_frontend* fe, return 0; } -static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct mt312_state* state = fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; if (enable) { return mt312_writereg(state, GPP_CTRL, 0x40); @@ -582,7 +594,7 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) } } -static int mt312_sleep(struct dvb_frontend* fe) +static int mt312_sleep(struct dvb_frontend *fe) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -602,7 +614,8 @@ static int mt312_sleep(struct dvb_frontend* fe) return 0; } -static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +static int mt312_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) { fesettings->min_delay_ms = 50; fesettings->step_size = 0; @@ -610,9 +623,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_ return 0; } -static void mt312_release(struct dvb_frontend* fe) +static void mt312_release(struct dvb_frontend *fe) { - struct mt312_state* state = fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; kfree(state); } @@ -655,10 +668,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = { .set_voltage = mt312_set_voltage, }; -struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, - struct i2c_adapter* i2c) +struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, + struct i2c_adapter *i2c) { - struct mt312_state* state = NULL; + struct mt312_state *state = NULL; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL); @@ -674,7 +687,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &vp310_mt312_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; switch (state->id) { @@ -687,7 +701,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, state->frequency = 60; break; default: - printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n"); + printk(KERN_WARNING "Only Zarlink VP310/MT312" + " are supported chips.\n"); goto error; } @@ -697,6 +712,7 @@ error: kfree(state); return NULL; } +EXPORT_SYMBOL(vp310_mt312_attach); module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); @@ -705,4 +721,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver"); MODULE_AUTHOR("Andreas Oberritter "); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(vp310_mt312_attach); diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h index cf9a1505ad4..f17cb93ba9b 100644 --- a/drivers/media/dvb/frontends/mt312.h +++ b/drivers/media/dvb/frontends/mt312.h @@ -28,22 +28,21 @@ #include -struct mt312_config -{ +struct mt312_config { /* the demodulator's i2c address */ u8 demod_address; }; #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) -struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, - struct i2c_adapter* i2c); +struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, + struct i2c_adapter *i2c); #else -static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, - struct i2c_adapter* i2c) +static inline struct dvb_frontend *vp310_mt312_attach( + const struct mt312_config *config, struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_MT312 +#endif /* CONFIG_DVB_MT312 */ -#endif // MT312_H +#endif /* MT312_H */ -- cgit v1.2.3 From 0b6a3342a645208feaab76332f1eee33e1688bd5 Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Fri, 21 Dec 2007 08:58:09 -0300 Subject: V4L/DVB (6874): removes duplicated KERN_DEBUG flags from dprintk calls in mt312.c do { \ if (debug) printk(KERN_DEBUG "mt312: " args); \ } while (0) So no caller need to specify KERN_DEBUG. Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt312.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 55d42440e97..2d68fafc0ef 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -183,7 +183,7 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) monitor = (buf[0] << 8) | buf[1]; - dprintk(KERN_DEBUG "sr(auto) = %u\n", + dprintk("sr(auto) = %u\n", mt312_div(monitor * 15625, 4)); } else { if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0) @@ -200,9 +200,9 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) sym_rat_op = (buf[0] << 8) | buf[1]; - dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", + dprintk("sym_rat_op=%d dec_ratio=%d\n", sym_rat_op, dec_ratio); - dprintk(KERN_DEBUG "*sr(manual) = %lu\n", + dprintk("*sr(manual) = %lu\n", (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * 2) - dec_ratio); } @@ -383,7 +383,7 @@ static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) return ret; - dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," + dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); if (status[0] & 0xc0) @@ -431,7 +431,7 @@ static int mt312_read_signal_strength(struct dvb_frontend *fe, *signal_strength = agc; - dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db); + dprintk("agc=%08x err_db=%hd\n", agc, err_db); return 0; } -- cgit v1.2.3 From d536c9df41f5e47a37e22b46ea98451ce8134e55 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 18 Dec 2007 10:42:33 -0300 Subject: V4L/DVB (6875): tuner-xc2028: ATSC requires 1.75 MHz tuning offset In my testing yesterday, I was using a scan file tailored specifically for a unique test situation -- As it turns out, this scan file was bad, and I will use the one included inside dvb-apps for testing for now on. I've tested with other ATSC tuners just to confirm, using: us-ATSC-center-frequencies-8VSB Anyhow, as it turns out, the tuner-xc2028 *does* require a tuning offset for ATSC. Even though the linux-dvb api passes in center frequencies from userspace, apparantly the xceive firmware is already factoring in the tuning offset to center. In order to make the device function using the same scan files / channels.conf configurations as other atsc devices, we must offset by 1.75 MHz. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index d367f205c98..5ed12e2272e 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -873,7 +873,9 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, */ if (new_mode == T_ANALOG_TV) { rc = send_seq(priv, {0x00, 0x00}); - } else if (!(priv->cur_fw.type & ATSC)) { + } else if (priv->cur_fw.type & ATSC) { + offset = 1750000; + } else { offset = 2750000; /* * We must adjust the offset by 500kHz in two cases in order -- cgit v1.2.3 From b624aa86cd92b32d66653609e4896f54c0d6111d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 20 Dec 2007 23:19:14 -0300 Subject: V4L/DVB (6878): tuner: remove extraneous variable declaration tuner_count is already declared as "extern unsigned const int" in -- Remove it from tuner-driver.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-driver.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 5eaa30ccbda..999ad7715a0 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -24,8 +24,6 @@ #include "dvb_frontend.h" -extern unsigned const int tuner_count; - struct analog_demod_info { char *name; }; -- cgit v1.2.3 From 807ffe8df23e1977d4e702697a08047f346eb974 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 02:55:43 -0300 Subject: V4L/DVB (6879): move struct analog_tuner_ops into dvb_frontend.h struct analog_tuner_ops no longer has any dependencies specific to v4l2, so we can move this into dvb_frontend.h with the rest of the tuning structures. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 24 ++++++++++++++++++++++-- drivers/media/video/tuner-driver.h | 22 ---------------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 50dc5568efa..417802f83f7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -62,8 +62,6 @@ struct dvb_tuner_info { u32 bandwidth_step; }; -struct analog_tuner_ops; - struct analog_parameters { unsigned int frequency; unsigned int mode; @@ -103,6 +101,28 @@ struct dvb_tuner_ops { int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); }; +struct analog_demod_info { + char *name; +}; + +struct analog_tuner_ops { + + struct analog_demod_info info; + + void (*set_params)(struct dvb_frontend *fe, + struct analog_parameters *params); + int (*has_signal)(struct dvb_frontend *fe); + int (*is_stereo)(struct dvb_frontend *fe); + int (*get_afc)(struct dvb_frontend *fe); + void (*tuner_status)(struct dvb_frontend *fe); + void (*standby)(struct dvb_frontend *fe); + void (*release)(struct dvb_frontend *fe); + int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); + + /** This is to allow setting tuner-specific configuration */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); +}; + struct dvb_frontend_ops { struct dvb_frontend_info info; diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 999ad7715a0..79efecc9334 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h @@ -24,26 +24,4 @@ #include "dvb_frontend.h" -struct analog_demod_info { - char *name; -}; - -struct analog_tuner_ops { - - struct analog_demod_info info; - - void (*set_params)(struct dvb_frontend *fe, - struct analog_parameters *params); - int (*has_signal)(struct dvb_frontend *fe); - int (*is_stereo)(struct dvb_frontend *fe); - int (*get_afc)(struct dvb_frontend *fe); - void (*tuner_status)(struct dvb_frontend *fe); - void (*standby)(struct dvb_frontend *fe); - void (*release)(struct dvb_frontend *fe); - int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); - - /** This is to allow setting tuner-specific configuration */ - int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); -}; - #endif /* __TUNER_DRIVER_H__ */ -- cgit v1.2.3 From 9ad89f0104314786138d580ab2c1119e7e470f56 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 03:00:59 -0300 Subject: V4L/DVB (6880): kill tuner-driver.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 1 - drivers/media/video/tda8290.c | 1 - drivers/media/video/tda9887.c | 1 - drivers/media/video/tuner-core.c | 1 - drivers/media/video/tuner-driver.h | 27 --------------------------- 5 files changed, 31 deletions(-) delete mode 100644 drivers/media/video/tuner-driver.h diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 28c63fd4493..406520f6310 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -20,7 +20,6 @@ #include #include -#include "tuner-driver.h" #include "tda18271.h" #include "tda18271-priv.h" diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a451d9480c1..71d38ba37f2 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -23,7 +23,6 @@ #include #include #include -#include "tuner-driver.h" #include "tuner-i2c.h" #include "tda8290.h" #include "tda827x.h" diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 2abb76fba9a..1b017d52bfb 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,7 +9,6 @@ #include #include #include -#include "tuner-driver.h" #include "tuner-i2c.h" #include "tda9887.h" diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f22c41bb97e..ad20af84809 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -20,7 +20,6 @@ #include #include #include -#include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h deleted file mode 100644 index 79efecc9334..00000000000 --- a/drivers/media/video/tuner-driver.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - tuner-driver.h - interface for different tuners - - Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) - minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de) - - 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 - (at your option) any later version. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __TUNER_DRIVER_H__ -#define __TUNER_DRIVER_H__ - -#include "dvb_frontend.h" - -#endif /* __TUNER_DRIVER_H__ */ -- cgit v1.2.3 From bc3e5c7fc20d3c09667067878fb7a55dd9fc041d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 11:18:32 -0300 Subject: V4L/DVB (6881): include struct analog_demod_ops directly inside struct dvb_frontend Rather than using a pointer, include struct analog_demod_ops directly inside struct dvb_frontend. This will allow us to use dvb_attach in the future, along with removing the need to check the ops structure before having to check the pointer to the method being called. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 4 +- drivers/media/dvb/frontends/tda18271-fe.c | 5 +- drivers/media/video/tda8290.c | 23 +++---- drivers/media/video/tda9887.c | 5 +- drivers/media/video/tuner-core.c | 99 +++++++++++++++---------------- 5 files changed, 66 insertions(+), 70 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 417802f83f7..aa4133f0bd1 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -105,7 +105,7 @@ struct analog_demod_info { char *name; }; -struct analog_tuner_ops { +struct analog_demod_ops { struct analog_demod_info info; @@ -168,7 +168,7 @@ struct dvb_frontend_ops { int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); struct dvb_tuner_ops tuner_ops; - struct analog_tuner_ops *analog_demod_ops; + struct analog_demod_ops analog_ops; }; #define MAX_EVENT 8 diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 406520f6310..3c0f06e1f47 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -50,7 +50,6 @@ struct tda18271_priv { static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct tda18271_priv *priv = fe->tuner_priv; - struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; enum tda18271_i2c_gate gate; int ret = 0; @@ -74,8 +73,8 @@ static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) switch (gate) { case TDA18271_GATE_ANALOG: - if (ops && ops->i2c_gate_ctrl) - ret = ops->i2c_gate_ctrl(fe, enable); + if (fe->ops.analog_ops.i2c_gate_ctrl) + ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); break; case TDA18271_GATE_DIGITAL: if (fe->ops.i2c_gate_ctrl) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 71d38ba37f2..2e1d9b663a9 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -512,16 +512,16 @@ static void tda829x_release(struct dvb_frontend *fe) static int tda829x_find_tuner(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; - struct analog_tuner_ops *ops = fe->ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; int i, ret, tuners_found; u32 tuner_addrs; u8 data; struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - if (NULL == ops) + if (NULL == analog_ops->i2c_gate_ctrl) return -EINVAL; - ops->i2c_gate_ctrl(fe, 1); + analog_ops->i2c_gate_ctrl(fe, 1); /* probe for tuner chip */ tuners_found = 0; @@ -539,7 +539,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) give a response now */ - ops->i2c_gate_ctrl(fe, 0); + analog_ops->i2c_gate_ctrl(fe, 0); if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { @@ -562,7 +562,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - ops->i2c_gate_ctrl(fe, 1); + analog_ops->i2c_gate_ctrl(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) { @@ -590,7 +590,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if (fe->ops.tuner_ops.sleep) fe->ops.tuner_ops.sleep(fe); - ops->i2c_gate_ctrl(fe, 0); + analog_ops->i2c_gate_ctrl(fe, 0); return 0; } @@ -635,7 +635,7 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) return -ENODEV; } -static struct analog_tuner_ops tda8290_tuner_ops = { +static struct analog_demod_ops tda8290_ops = { .info = { .name = "TDA8290", }, @@ -646,7 +646,7 @@ static struct analog_tuner_ops tda8290_tuner_ops = { .i2c_gate_ctrl = tda8290_i2c_bridge, }; -static struct analog_tuner_ops tda8295_tuner_ops = { +static struct analog_demod_ops tda8295_ops = { .info = { .name = "TDA8295", }, @@ -678,12 +678,14 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, if (tda8290_probe(&priv->i2c_props) == 0) { priv->ver = TDA8290; - fe->ops.analog_demod_ops = &tda8290_tuner_ops; + memcpy(&fe->ops.analog_ops, &tda8290_ops, + sizeof(struct analog_demod_ops)); } if (tda8295_probe(&priv->i2c_props) == 0) { priv->ver = TDA8295; - fe->ops.analog_demod_ops = &tda8295_tuner_ops; + memcpy(&fe->ops.analog_ops, &tda8295_ops, + sizeof(struct analog_demod_ops)); } if (tda829x_find_tuner(fe) < 0) @@ -723,7 +725,6 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, fail: tda829x_release(fe); - fe->ops.analog_demod_ops = NULL; return NULL; } EXPORT_SYMBOL_GPL(tda829x_attach); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 1b017d52bfb..d3aabe2d146 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -648,7 +648,7 @@ static void tda9887_release(struct dvb_frontend *fe) fe->analog_demod_priv = NULL; } -static struct analog_tuner_ops tda9887_tuner_ops = { +static struct analog_demod_ops tda9887_ops = { .info = { .name = "TDA9887", }, @@ -677,7 +677,8 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, tuner_info("tda988[5/6/7] found\n"); - fe->ops.analog_demod_ops = &tda9887_tuner_ops; + memcpy(&fe->ops.analog_ops, &tda9887_ops, + sizeof(struct analog_demod_ops)); return fe; } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index ad20af84809..f792871582f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -143,8 +143,6 @@ static void fe_release(struct dvb_frontend *fe) if (fe->ops.tuner_ops.release) fe->ops.tuner_ops.release(fe); - fe->ops.analog_demod_ops = NULL; - /* DO NOT kfree(fe->analog_demod_priv) * * If we are in this function, analog_demod_priv contains a pointer @@ -189,7 +187,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) static void tuner_status(struct dvb_frontend *fe); -static struct analog_tuner_ops tuner_core_ops = { +static struct analog_demod_ops tuner_core_ops = { .set_params = fe_set_params, .standby = fe_standby, .release = fe_release, @@ -202,7 +200,7 @@ static struct analog_tuner_ops tuner_core_ops = { static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct analog_parameters params = { .mode = t->mode, @@ -214,7 +212,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if ((NULL == ops) || (NULL == ops->set_params)) { + if (NULL == analog_ops->set_params) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -231,13 +229,13 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) } params.frequency = freq; - ops->set_params(&t->fe, ¶ms); + analog_ops->set_params(&t->fe, ¶ms); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct analog_parameters params = { .mode = t->mode, @@ -249,7 +247,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if ((NULL == ops) || (NULL == ops->set_params)) { + if (analog_ops->set_params) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -266,7 +264,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) } params.frequency = freq; - ops->set_params(&t->fe, ¶ms); + analog_ops->set_params(&t->fe, ¶ms); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -337,7 +335,7 @@ static void set_type(struct i2c_client *c, unsigned int type, { struct tuner *t = i2c_get_clientdata(c); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -364,8 +362,8 @@ static void set_type(struct i2c_client *c, unsigned int type, } /* discard private data, in case set_type() was previously called */ - if (ops && ops->release) - ops->release(&t->fe); + if (analog_ops->release) + analog_ops->release(&t->fe); switch (t->type) { case TUNER_MT2032: @@ -435,17 +433,16 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } - ops = t->fe.ops.analog_demod_ops; - - if (((NULL == ops) || (NULL == ops->set_params)) && + if ((NULL == analog_ops->set_params) && (fe_tuner_ops->set_analog_params)) { strlcpy(t->i2c->name, fe_tuner_ops->info.name, sizeof(t->i2c->name)); - t->fe.ops.analog_demod_ops = &tuner_core_ops; t->fe.analog_demod_priv = t; + memcpy(analog_ops, &tuner_core_ops, + sizeof(struct analog_demod_ops)); } else { - strlcpy(t->i2c->name, ops->info.name, + strlcpy(t->i2c->name, analog_ops->info.name, sizeof(t->i2c->name)); } @@ -624,7 +621,7 @@ static void tuner_status(struct dvb_frontend *fe) struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; const char *p; switch (t->mode) { @@ -654,14 +651,12 @@ static void tuner_status(struct dvb_frontend *fe) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if (ops) { - if (ops->has_signal) - tuner_info("Signal strength: %d\n", - ops->has_signal(fe)); - if (ops->is_stereo) - tuner_info("Stereo: %s\n", - ops->is_stereo(fe) ? "yes" : "no"); - } + if (analog_ops->has_signal) + tuner_info("Signal strength: %d\n", + analog_ops->has_signal(fe)); + if (analog_ops->is_stereo) + tuner_info("Stereo: %s\n", + analog_ops->is_stereo(fe) ? "yes" : "no"); } /* ---------------------------------------------------------------------- */ @@ -675,7 +670,7 @@ static void tuner_status(struct dvb_frontend *fe) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; if (mode == t->mode) return 0; @@ -684,8 +679,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (ops && ops->standby) - ops->standby(&t->fe); + if (analog_ops->standby) + analog_ops->standby(&t->fe); return EINVAL; } return 0; @@ -708,7 +703,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; if (tuner_debug>1) v4l_i2c_print_ioctl(client,cmd); @@ -735,8 +730,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if (ops && ops->standby) - ops->standby(&t->fe); + if (analog_ops->standby) + analog_ops->standby(&t->fe); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -804,8 +799,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { - if (ops && ops->is_stereo) { - if (ops->is_stereo(&t->fe)) + if (analog_ops->is_stereo) { + if (analog_ops->is_stereo(&t->fe)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -813,8 +808,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ~VIDEO_TUNER_STEREO_ON; } } - if (ops && ops->has_signal) - vt->signal = ops->has_signal(&t->fe); + if (analog_ops->has_signal) + vt->signal = + analog_ops->has_signal(&t->fe); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -844,8 +840,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - } else if (ops && ops->is_stereo) - va->mode = ops->is_stereo(&t->fe) + } else if (analog_ops->is_stereo) + va->mode = analog_ops->is_stereo(&t->fe) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } return 0; @@ -853,19 +849,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) #endif case TUNER_SET_CONFIG: { - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; struct v4l2_priv_tun_config *cfg = arg; if (t->type != cfg->tuner) break; - if ((NULL == ops) || (NULL == ops->set_config)) { + if (analog_ops->set_config) { tuner_warn("Tuner frontend module has no way to " "set config\n"); break; } - ops->set_config(&t->fe, cfg->priv); + analog_ops->set_config(&t->fe, cfg->priv); break; } /* --- v4l ioctls --- */ @@ -929,8 +924,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if (ops && ops->get_afc) - tuner->afc = ops->get_afc(&t->fe); + if (analog_ops->get_afc) + tuner->afc = analog_ops->get_afc(&t->fe); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -951,15 +946,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } else { - if (ops && ops->is_stereo) { + if (analog_ops->is_stereo) { tuner->rxsubchans = - ops->is_stereo(&t->fe) ? + analog_ops->is_stereo(&t->fe) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } } - if (ops && ops->has_signal) - tuner->signal = ops->has_signal(&t->fe); + if (analog_ops->has_signal) + tuner->signal = analog_ops->has_signal(&t->fe); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -984,8 +979,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if (ops && ops->tuner_status) - ops->tuner_status(&t->fe); + if (analog_ops->tuner_status) + analog_ops->tuner_status(&t->fe); break; } @@ -1214,10 +1209,10 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) static int tuner_remove(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); - struct analog_tuner_ops *ops = t->fe.ops.analog_demod_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (ops && ops->release) - ops->release(&t->fe); + if (analog_ops->release) + analog_ops->release(&t->fe); list_del(&t->list); kfree(t); -- cgit v1.2.3 From 2426a27e4d25cf932ce73aa84a085ee94b4189a8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 11:34:45 -0300 Subject: V4L/DVB (6882): dvb_frontend: release analog demod in dvb_frontend_detach Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 445f0266557..925cfa6221a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe) fe->ops.tuner_ops.release(fe); symbol_put_addr(fe->ops.tuner_ops.release); } + if (fe->ops.analog_ops.release) { + fe->ops.analog_ops.release(fe); + symbol_put_addr(fe->ops.analog_ops.release); + } ptr = (void*)fe->ops.release; if (ptr) { fe->ops.release(fe); @@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe) fe->ops.release_sec(fe); if (fe->ops.tuner_ops.release) fe->ops.tuner_ops.release(fe); + if (fe->ops.analog_ops.release) + fe->ops.analog_ops.release(fe); if (fe->ops.release) fe->ops.release(fe); } -- cgit v1.2.3 From aacb9d31ee65c0685745ca4dfc7cdd24f8b7d92b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 18 Dec 2007 01:55:51 -0300 Subject: V4L/DVB (6884): Add support for the Xceive xc5000 silicon tuner This is an all formats tuner, QAM, ATSC, DVB-T and others. Only ATSC and QAM have been tested. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 9 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/xc5000.c | 802 ++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/xc5000.h | 51 ++ drivers/media/dvb/frontends/xc5000_priv.h | 37 ++ 5 files changed, 900 insertions(+) create mode 100644 drivers/media/dvb/frontends/xc5000.c create mode 100644 drivers/media/dvb/frontends/xc5000.h create mode 100644 drivers/media/dvb/frontends/xc5000_priv.h diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 57178d6e1cf..9ad86ce4a4e 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -360,6 +360,15 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called togther with a demodulator for now. +config DVB_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called togther with a + demodulator for now. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 784565208fb..1c082a6a949 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -50,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o +obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c new file mode 100644 index 00000000000..048f9a79b91 --- /dev/null +++ b/drivers/media/dvb/frontends/xc5000.c @@ -0,0 +1,802 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" + +#include "xc5000.h" +#include "xc5000_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) + +#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" +#define XC5000_DEFAULT_FIRMWARE_SIZE 12400 + +/* Misc Defines */ +#define MAX_TV_STANDARD 23 +#define XC_MAX_I2C_WRITE_LENGTH 64 + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Result codes */ +#define XC_RESULT_SUCCESS 0 +#define XC_RESULT_RESET_FAILURE 1 +#define XC_RESULT_I2C_WRITE_FAILURE 2 +#define XC_RESULT_I2C_READ_FAILURE 3 +#define XC_RESULT_OUT_OF_RANGE 5 + +/* Registers */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_IF_OUT 0x05 +#define XREG_SEEK_MODE 0x07 +#define XREG_POWER_DOWN 0x0A +#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_XTALFREQ 0x0F +#define XREG_FINERFFREQ 0x10 +#define XREG_DDIMODE 0x11 + +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 +#define XREG_BUSY 0x09 + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. + +*/ +typedef struct { + char *Name; + unsigned short AudioMode; + unsigned short VideoMode; +} XC_TV_STANDARD; + +/* Tuner standards */ +#define DTV6 17 + +XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, + {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, + {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, + {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, + {"B/G-PAL-A2", 0x0A00, 0x8049}, + {"B/G-PAL-NICAM", 0x0C04, 0x8049}, + {"B/G-PAL-MONO", 0x0878, 0x8059}, + {"I-PAL-NICAM", 0x1080, 0x8009}, + {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, + {"D/K-PAL-A2", 0x1600, 0x8009}, + {"D/K-PAL-NICAM", 0x0E80, 0x8009}, + {"D/K-PAL-MONO", 0x1478, 0x8009}, + {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, + {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009}, + {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, + {"L-SECAM-NICAM", 0x8E82, 0x0009}, + {"L'-SECAM-NICAM", 0x8E82, 0x4009}, + {"DTV6", 0x00C0, 0x8002}, + {"DTV8", 0x00C0, 0x800B}, + {"DTV7/8", 0x00C0, 0x801B}, + {"DTV7", 0x00C0, 0x8007}, + {"FM Radio-INPUT2", 0x9802, 0x9002}, + {"FM Radio-INPUT1", 0x0208, 0x9002} +}; + +static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); +static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); +static void xc5000_TunerReset(struct dvb_frontend *fe); + +int xc_send_i2c_data(struct xc5000_priv *priv, + unsigned char *bytes_to_send, int nb_bytes_to_send) +{ + return xc5000_writeregs(priv, bytes_to_send, nb_bytes_to_send) + ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS; +} + +int xc_read_i2c_data(struct xc5000_priv *priv, unsigned char *bytes_received, + int nb_bytes_to_receive) +{ + return xc5000_readregs(priv, bytes_received, nb_bytes_to_receive) + ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS; +} + +int xc_reset(struct dvb_frontend *fe) +{ + xc5000_TunerReset(fe); + return XC_RESULT_SUCCESS; +} + +void xc_wait(int wait_ms) +{ + msleep( wait_ms ); +} + +static void xc5000_TunerReset(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __FUNCTION__); + + if(priv->cfg->tuner_reset) { + ret = priv->cfg->tuner_reset(fe); + if (ret) + printk(KERN_ERR "xc5000: reset failed\n"); + } else + printk(KERN_ERR "xc5000: no tuner reset function, fatal\n"); +} + +int xc_write_reg(struct xc5000_priv *priv, unsigned short int regAddr, + unsigned short int i2cData) +{ + unsigned char buf[4]; + int WatchDogTimer = 5; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + if ( result == XC_RESULT_SUCCESS) { + /* wait for busy flag to clear */ + while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { + buf[0] = 0; + buf[1] = XREG_BUSY; + + result = xc_send_i2c_data(priv, buf, 2); + if (result == XC_RESULT_SUCCESS) { + result = xc_read_i2c_data(priv, buf, 2); + if (result == XC_RESULT_SUCCESS) { + if ((buf[0] == 0) && (buf[1] == 0)) { + /* busy flag cleared */ + break; + } else { + xc_wait(100); /* wait 5 ms */ + WatchDogTimer--; + } + } + } + } + } + if (WatchDogTimer < 0) + result = XC_RESULT_I2C_WRITE_FAILURE; + + return result; +} + +int xc_read_reg(struct xc5000_priv *priv, unsigned short int regAddr, + unsigned short int *i2cData) +{ + unsigned char buf[2]; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + result = xc_send_i2c_data(priv, buf, 2); + if (result!=XC_RESULT_SUCCESS) + return result; + + result = xc_read_i2c_data(priv, buf, 2); + if (result!=XC_RESULT_SUCCESS) + return result; + + *i2cData = buf[0] * 256 + buf[1]; + return result; +} + +int xc_load_i2c_sequence(struct dvb_frontend *fe, unsigned char i2c_sequence[]) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + unsigned char buf[XC_MAX_I2C_WRITE_LENGTH]; + + index=0; + while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { + + len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; + if (len==0x0000) { + /* RESET command */ + result = xc_reset(fe); + index += 2; + if (result!=XC_RESULT_SUCCESS) + return result; + } else if (len & 0x8000) { + /* WAIT command */ + xc_wait(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) { + nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH; + } else { + nbytes_to_send = (len - pos + 2); + } + for (i=2; ivideo_standard].Name); + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); + if (ret == XC_RESULT_SUCCESS) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); + + return ret; +} + +int xc_shutdown(struct xc5000_priv *priv) +{ + return xc_write_reg(priv, XREG_POWER_DOWN, 0); +} + +int xc_SetSignalSource(struct xc5000_priv *priv, unsigned short int rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if( (rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE) ) + { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __FUNCTION__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +int xc_set_RF_frequency(struct xc5000_priv *priv, long frequency_in_hz) +{ + unsigned int frequency_code = (unsigned int)(frequency_in_hz / 15625); + + if ((frequency_in_hz>1023000000) || (frequency_in_hz<1000000)) + return XC_RESULT_OUT_OF_RANGE; + + return xc_write_reg(priv, XREG_RF_FREQ ,frequency_code); +} + +int xc_FineTune_RF_frequency(struct xc5000_priv *priv, long frequency_in_hz) +{ + unsigned int frequency_code = (unsigned int)(frequency_in_hz / 15625); + if ((frequency_in_hz>1023000000) || (frequency_in_hz<1000000)) + return XC_RESULT_OUT_OF_RANGE; + + return xc_write_reg(priv, XREG_FINERFFREQ ,frequency_code); +} + +int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_hz) +{ + u32 freq_code = (freq_hz * 1024)/1000000; + dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); + + printk(KERN_ERR "FIXME - Hardcoded IF, FIXME\n"); + freq_code = 0x1585; + + return xc_write_reg(priv, XREG_IF_OUT ,freq_code); +} + +int xc_set_Xtal_frequency(struct xc5000_priv *priv, long xtalFreqInKHz) +{ + unsigned int xtalRatio = (32000 * 0x8000)/xtalFreqInKHz; + return xc_write_reg(priv, XREG_XTALFREQ ,xtalRatio); +} + +int xc_get_ADC_Envelope(struct xc5000_priv *priv, + unsigned short int *adc_envelope) +{ + return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope); +} + +int xc_get_frequency_error(struct xc5000_priv *priv, u32 *frequency_error_hz) +{ + int result; + unsigned short int regData; + u32 tmp; + + result = xc_read_reg(priv, XREG_FREQ_ERROR, ®Data); + if (result) + return result; + + tmp = (u32)regData; + (*frequency_error_hz) = (tmp * 15625) / 1000; + return result; +} + +int xc_get_lock_status(struct xc5000_priv *priv, + unsigned short int *lock_status) +{ + return xc_read_reg(priv, XREG_LOCK, lock_status); +} + +int xc_get_version(struct xc5000_priv *priv, + unsigned char* hw_majorversion, + unsigned char* hw_minorversion, + unsigned char* fw_majorversion, + unsigned char* fw_minorversion) +{ + unsigned short int data; + int result; + + result = xc_read_reg(priv, XREG_VERSION, &data); + if (result) + return result; + + (*hw_majorversion) = (data>>12) & 0x0F; + (*hw_minorversion) = (data>>8) & 0x0F; + (*fw_majorversion) = (data>>4) & 0x0F; + (*fw_minorversion) = (data) & 0x0F; + + return 0; +} + +int xc_get_product_id(struct xc5000_priv *priv, unsigned short int *product_id) +{ + return xc_read_reg(priv, XREG_PRODUCT_ID, product_id); +} + +int xc_get_hsync_freq(struct xc5000_priv *priv, int *hsync_freq_hz) +{ + unsigned short int regData; + int result; + + result = xc_read_reg(priv, XREG_HSYNC_FREQ, ®Data); + if (result) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +int xc_get_frame_lines(struct xc5000_priv *priv, + unsigned short int *frame_lines) +{ + return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines); +} + +int xc_get_quality(struct xc5000_priv *priv, unsigned short int *quality) +{ + return xc_read_reg(priv, XREG_QUALITY, quality); +} + +unsigned short int WaitForLock(struct xc5000_priv *priv) +{ + unsigned short int lockState = 0; + int watchDogCount = 40; + while ((lockState == 0) && (watchDogCount > 0)) + { + xc_get_lock_status(priv, &lockState); + if (lockState != 1) + { + xc_wait(5); + watchDogCount--; + } + } + return lockState; +} + +int xc_tune_channel(struct xc5000_priv *priv, u32 freq) +{ + int found = 0; + + dprintk(1, "%s(%d)\n", __FUNCTION__, freq); + + if (xc_set_RF_frequency(priv, freq) != XC_RESULT_SUCCESS) + return 0; + + if (WaitForLock(priv)== 1) + found = 1; + + return found; +} + +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "xc5000 I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return 0; +} + +static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C write failed (len=%i)\n", + (int)len); + return -EREMOTEIO; + } + return 0; +} + +static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +static int xc5000_fwupload(struct dvb_frontend* fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + const struct firmware *fw; + int ret; + + /* request the firmware, this will block until someone uploads it */ + printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", + XC5000_DEFAULT_FIRMWARE); + + if(!priv->cfg->request_firmware) { + printk(KERN_ERR "xc5000: no firmware callback, fatal\n"); + return -EIO; + } + + ret = priv->cfg->request_firmware(fe, &fw, XC5000_DEFAULT_FIRMWARE); + if (ret) { + printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); + ret = XC_RESULT_RESET_FAILURE; + } else { + printk(KERN_INFO "xc5000: firmware read %d bytes.\n", fw->size); + ret = XC_RESULT_SUCCESS; + } + + if(fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { + printk(KERN_ERR "xc5000: firmware incorrect size\n"); + ret = XC_RESULT_RESET_FAILURE; + } else { + printk(KERN_INFO "xc5000: firmware upload\n"); + ret = xc_load_i2c_sequence(fe, fw->data ); + } + + release_firmware(fw); + return ret; +} + +void xc_debug_dump(struct xc5000_priv *priv) +{ + unsigned short adc_envelope; + u32 frequency_error_hz; + unsigned short lock_status; + unsigned char hw_majorversion, hw_minorversion = 0; + unsigned char fw_majorversion, fw_minorversion = 0; + int hsync_freq_hz; + unsigned short frame_lines; + unsigned short quality; + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + xc_wait( 100 ); + + xc_get_ADC_Envelope(priv, &adc_envelope ); + dprintk(1, "*** ADC envelope (0-1023) = %u\n", adc_envelope); + + xc_get_frequency_error(priv, &frequency_error_hz ); + dprintk(1, "*** Frequency error = %d Hz\n", frequency_error_hz); + + xc_get_lock_status(priv, &lock_status ); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %u\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion ); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion); + + xc_get_hsync_freq(priv, &hsync_freq_hz ); + dprintk(1, "*** Horizontal sync frequency = %u Hz\n", hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines ); + dprintk(1, "*** Frame lines = %u\n", frame_lines); + + xc_get_quality(priv, &quality ); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %u\n", quality); +} + +static int xc5000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s() frequency=%d\n", __FUNCTION__, params->frequency); + + priv->frequency = params->frequency - 1750000; + priv->bandwidth = 6; + priv->video_standard = DTV6; + + switch(params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __FUNCTION__); + priv->rf_mode = XC_RF_MODE_AIR; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __FUNCTION__); + priv->rf_mode = XC_RF_MODE_CABLE; + break; + default: + return -EINVAL; + } + + dprintk(1, "%s() frequency=%d (compensated)\n", + __FUNCTION__, priv->frequency); + + /* FIXME: check result codes */ + xc_SetSignalSource(priv, priv->rf_mode); + + xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + + xc_set_IF_frequency(priv, priv->cfg->if_frequency); + xc_tune_channel(priv, priv->frequency); + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *freq = priv->frequency; + return 0; +} + +static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *bw = priv->bandwidth; + return 0; +} + +static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc5000_priv *priv = fe->tuner_priv; + unsigned short int lock_status = 0; + + xc_get_lock_status(priv, &lock_status); + + dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status); + + *status = lock_status; + + return 0; +} + +int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + if(priv->fwloaded == 0) { + ret = xc5000_fwupload(fe); + if( ret != XC_RESULT_SUCCESS ) + return -EREMOTEIO; + + priv->fwloaded = 1; + } + + /* Start the tuner self-calibration process */ + ret |= xc_initialize(priv); + + /* Wait for calibration to complete. + * We could continue but XC5000 will clock stretch subsequent + * I2C transactions until calibration is complete. This way we + * don't have to rely on clock stretching working. + */ + xc_wait( 100 ); + + /* Default to "CABLE" mode */ + ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); + + return ret; +} + +static int xc5000_init(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + + xc_load_fw_and_init_tuner(fe); + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __FUNCTION__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops xc5000_tuner_ops = { + .info = { + .name = "Xceive XC5000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc5000_release, + .init = xc5000_init, + + .set_params = xc5000_set_params, + .get_frequency = xc5000_get_frequency, + .get_bandwidth = xc5000_get_bandwidth, + .get_status = xc5000_get_status +}; + +struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc5000_config *cfg) +{ + struct xc5000_priv *priv = NULL; + u16 id = 0; + + dprintk(1, "%s()\n", __FUNCTION__); + + priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = 6000000; /* 6MHz */ + priv->i2c = i2c; + priv->fwloaded = 0; + + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { + kfree(priv); + return NULL; + } + + if ( (id != 0x2000) && (id != 0x1388) ) { + printk(KERN_ERR + "xc5000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + kfree(priv); + return NULL; + } + + printk(KERN_INFO "xc5000: successfully identified at address 0x%02x\n", + cfg->i2c_address); + + memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL(xc5000_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Xceive XC5000 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h new file mode 100644 index 00000000000..ce5a3212f8f --- /dev/null +++ b/drivers/media/dvb/frontends/xc5000.h @@ -0,0 +1,51 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __XC5000_H__ +#define __XC5000_H__ + +#include + +struct dvb_frontend; +struct i2c_adapter; + +struct xc5000_config { + u8 i2c_address; + u32 if_frequency; + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); + int (*tuner_reset)(struct dvb_frontend* fe); +}; + +#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) +extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc5000_config *cfg); +#else +static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc5000_config *cfg); +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_XC5000 + +#endif // __XC5000_H__ diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/dvb/frontends/xc5000_priv.h new file mode 100644 index 00000000000..a2b54535db0 --- /dev/null +++ b/drivers/media/dvb/frontends/xc5000_priv.h @@ -0,0 +1,37 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef XC5000_PRIV_H +#define XC5000_PRIV_H + +struct xc5000_priv { + struct xc5000_config *cfg; + struct i2c_adapter *i2c; + + u32 frequency; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + + u8 fwloaded; +}; + +#endif -- cgit v1.2.3 From d1987d55a1eda774dfbab240a432607c17241d07 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 18 Dec 2007 01:57:06 -0300 Subject: V4L/DVB (6885): Add support for the Hauppauge HVR1500Q The express card ATSC/QAM tuner. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 1 + drivers/media/video/cx23885/cx23885-cards.c | 17 +++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 54 +++++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-i2c.c | 2 +- drivers/media/video/cx23885/cx23885.h | 1 + 5 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 00cb646a4bd..54d06e4ff74 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -3,3 +3,4 @@ 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801] 3 -> Hauppauge WinTV-HVR1250 [0070:7911] 4 -> DViCO FusionHDTV5 Express [18ac:d500] + 5 -> Hauppauge WinTV-HVR1500Q [0070:7797] diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 134b931b160..515f415564d 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -113,6 +113,11 @@ struct cx23885_board cx23885_boards[] = { .name = "DViCO FusionHDTV5 Express", .portb = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { + .name = "Hauppauge WinTV-HVR1500Q", + .portc = CX23885_MPEG_DVB, + }, + }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -144,6 +149,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xd500, .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, + },{ + .subvendor = 0x0070, + .subdevice = 0x7797, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -204,6 +213,11 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-0 cx24227 demodulator reset */ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + /* GPIO-0 cx24227 demodulator reset */ + /* GPIO-2 xc5000 tuner reset */ + cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ /* GPIO-1 656_D0 */ @@ -221,6 +235,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) { switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* FIXME: Implement me */ break; @@ -244,6 +259,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: if (dev->i2c_bus[0].i2c_rc == 0) @@ -258,6 +274,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: default: diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 96d732098a0..5fa65ef08bf 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -33,6 +33,7 @@ #include "s5h1409.h" #include "mt2131.h" #include "lgdt330x.h" +#include "xc5000.h" #include "dvb-pll.h" static unsigned int debug = 0; @@ -74,6 +75,32 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer*)vb); } +static int cx23885_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s(?,?,%s)\n", __FUNCTION__, name); + + return request_firmware(fw, name, &dev->pci->dev); +} + +static int hauppauge_hvr1500q_tuner_reset(struct dvb_frontend *fe) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s()\n", __FUNCTION__); + + /* Drive the tuner into reset back back */ + cx_clear(GP0_IO, 0x00000004); + mdelay(200); + cx_set(GP0_IO, 0x00000004); + + return 0; +} + static struct videobuf_queue_ops dvb_qops = { .buf_setup = dvb_buf_setup, .buf_prepare = dvb_buf_prepare, @@ -109,6 +136,22 @@ static struct lgdt330x_config fusionhdtv_5_express = { .serial_mpeg = 0x40, }; +static struct s5h1409_config hauppauge_hvr1500q_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + +static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { + .i2c_address = 0x61, + .if_frequency = 4570000, + .request_firmware = cx23885_request_firmware, + .tuner_reset = hauppauge_hvr1500q_tuner_reset +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -152,6 +195,17 @@ static int dvb_register(struct cx23885_tsport *port) &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + i2c_bus = &dev->i2c_bus[1]; + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1500q_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(xc5000_attach, port->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_hvr1500q_tunerconfig); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 20f3fb450f8..b2ffbf04ef2 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -332,7 +332,7 @@ static char *i2c_devs[128] = { [ 0x84 >> 1 ] = "tda8295", [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", - [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275", + [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 205640cc48f..3f019f3cb29 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -53,6 +53,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 +#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From e12671cf0c3c8460dfa3ab945023803612827fb7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 20 Dec 2007 01:14:43 -0300 Subject: V4L/DVB (6886): xc5000: Cleanups of types, result codes etc This translates much of the xceive coding style, adds some result codes and generally cleans up whitespace and function arguments. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.c | 300 ++++++++++++++++-------------- drivers/media/dvb/frontends/xc5000.h | 5 +- drivers/media/dvb/frontends/xc5000_priv.h | 3 +- drivers/media/video/cx23885/cx23885-dvb.c | 6 +- 4 files changed, 163 insertions(+), 151 deletions(-) diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index 048f9a79b91..9edd0711539 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -117,8 +117,8 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); */ typedef struct { char *Name; - unsigned short AudioMode; - unsigned short VideoMode; + u16 AudioMode; + u16 VideoMode; } XC_TV_STANDARD; /* Tuner standards */ @@ -154,29 +154,27 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); static void xc5000_TunerReset(struct dvb_frontend *fe); -int xc_send_i2c_data(struct xc5000_priv *priv, - unsigned char *bytes_to_send, int nb_bytes_to_send) +static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { - return xc5000_writeregs(priv, bytes_to_send, nb_bytes_to_send) + return xc5000_writeregs(priv, buf, len) ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS; } -int xc_read_i2c_data(struct xc5000_priv *priv, unsigned char *bytes_received, - int nb_bytes_to_receive) +static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { - return xc5000_readregs(priv, bytes_received, nb_bytes_to_receive) + return xc5000_readregs(priv, buf, len) ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS; } -int xc_reset(struct dvb_frontend *fe) +static int xc_reset(struct dvb_frontend *fe) { xc5000_TunerReset(fe); return XC_RESULT_SUCCESS; } -void xc_wait(int wait_ms) +static void xc_wait(int wait_ms) { - msleep( wait_ms ); + msleep(wait_ms); } static void xc5000_TunerReset(struct dvb_frontend *fe) @@ -186,7 +184,7 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) dprintk(1, "%s()\n", __FUNCTION__); - if(priv->cfg->tuner_reset) { + if (priv->cfg->tuner_reset) { ret = priv->cfg->tuner_reset(fe); if (ret) printk(KERN_ERR "xc5000: reset failed\n"); @@ -194,10 +192,9 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) printk(KERN_ERR "xc5000: no tuner reset function, fatal\n"); } -int xc_write_reg(struct xc5000_priv *priv, unsigned short int regAddr, - unsigned short int i2cData) +static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) { - unsigned char buf[4]; + u8 buf[4]; int WatchDogTimer = 5; int result; @@ -206,7 +203,7 @@ int xc_write_reg(struct xc5000_priv *priv, unsigned short int regAddr, buf[2] = (i2cData >> 8) & 0xFF; buf[3] = i2cData & 0xFF; result = xc_send_i2c_data(priv, buf, 4); - if ( result == XC_RESULT_SUCCESS) { + if (result == XC_RESULT_SUCCESS) { /* wait for busy flag to clear */ while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { buf[0] = 0; @@ -233,43 +230,42 @@ int xc_write_reg(struct xc5000_priv *priv, unsigned short int regAddr, return result; } -int xc_read_reg(struct xc5000_priv *priv, unsigned short int regAddr, - unsigned short int *i2cData) +static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData) { - unsigned char buf[2]; + u8 buf[2]; int result; buf[0] = (regAddr >> 8) & 0xFF; buf[1] = regAddr & 0xFF; result = xc_send_i2c_data(priv, buf, 2); - if (result!=XC_RESULT_SUCCESS) + if (result != XC_RESULT_SUCCESS) return result; result = xc_read_i2c_data(priv, buf, 2); - if (result!=XC_RESULT_SUCCESS) + if (result != XC_RESULT_SUCCESS) return result; *i2cData = buf[0] * 256 + buf[1]; return result; } -int xc_load_i2c_sequence(struct dvb_frontend *fe, unsigned char i2c_sequence[]) +static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[]) { struct xc5000_priv *priv = fe->tuner_priv; int i, nbytes_to_send, result; unsigned int len, pos, index; - unsigned char buf[XC_MAX_I2C_WRITE_LENGTH]; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; index=0; while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; - if (len==0x0000) { + if (len == 0x0000) { /* RESET command */ result = xc_reset(fe); index += 2; - if (result!=XC_RESULT_SUCCESS) + if (result != XC_RESULT_SUCCESS) return result; } else if (len & 0x8000) { /* WAIT command */ @@ -294,7 +290,7 @@ int xc_load_i2c_sequence(struct dvb_frontend *fe, unsigned char i2c_sequence[]) } result = xc_send_i2c_data(priv, buf, nbytes_to_send); - if (result!=XC_RESULT_SUCCESS) + if (result != XC_RESULT_SUCCESS) return result; pos += nbytes_to_send - 2; @@ -305,14 +301,14 @@ int xc_load_i2c_sequence(struct dvb_frontend *fe, unsigned char i2c_sequence[]) return XC_RESULT_SUCCESS; } -int xc_initialize(struct xc5000_priv *priv) +static int xc_initialize(struct xc5000_priv *priv) { dprintk(1, "%s()\n", __FUNCTION__); return xc_write_reg(priv, XREG_INIT, 0); } -int xc_SetTVStandard(struct xc5000_priv *priv, unsigned short int VideoMode, - unsigned short int AudioMode) +static int xc_SetTVStandard(struct xc5000_priv *priv, + u16 VideoMode, u16 AudioMode) { int ret; dprintk(1, "%s(%d,%d)\n", __FUNCTION__, VideoMode, AudioMode); @@ -327,17 +323,17 @@ int xc_SetTVStandard(struct xc5000_priv *priv, unsigned short int VideoMode, return ret; } -int xc_shutdown(struct xc5000_priv *priv) +static int xc_shutdown(struct xc5000_priv *priv) { return xc_write_reg(priv, XREG_POWER_DOWN, 0); } -int xc_SetSignalSource(struct xc5000_priv *priv, unsigned short int rf_mode) +static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) { dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode, rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); - if( (rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE) ) + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { rf_mode = XC_RF_MODE_CABLE; printk(KERN_ERR @@ -347,52 +343,43 @@ int xc_SetSignalSource(struct xc5000_priv *priv, unsigned short int rf_mode) return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); } -int xc_set_RF_frequency(struct xc5000_priv *priv, long frequency_in_hz) -{ - unsigned int frequency_code = (unsigned int)(frequency_in_hz / 15625); +static const struct dvb_tuner_ops xc5000_tuner_ops; - if ((frequency_in_hz>1023000000) || (frequency_in_hz<1000000)) - return XC_RESULT_OUT_OF_RANGE; +static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) +{ + u16 freq_code; - return xc_write_reg(priv, XREG_RF_FREQ ,frequency_code); -} + dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); -int xc_FineTune_RF_frequency(struct xc5000_priv *priv, long frequency_in_hz) -{ - unsigned int frequency_code = (unsigned int)(frequency_in_hz / 15625); - if ((frequency_in_hz>1023000000) || (frequency_in_hz<1000000)) + if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || + (freq_hz < xc5000_tuner_ops.info.frequency_min)) return XC_RESULT_OUT_OF_RANGE; - return xc_write_reg(priv, XREG_FINERFFREQ ,frequency_code); + freq_code = (u16)(freq_hz / 15625); + + return xc_write_reg(priv, XREG_RF_FREQ, freq_code); } -int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_hz) -{ - u32 freq_code = (freq_hz * 1024)/1000000; - dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); - printk(KERN_ERR "FIXME - Hardcoded IF, FIXME\n"); - freq_code = 0x1585; +static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) +{ + u32 freq_code = (freq_khz * 1024)/1000; + dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", + __FUNCTION__, freq_khz, freq_code); - return xc_write_reg(priv, XREG_IF_OUT ,freq_code); + return xc_write_reg(priv, XREG_IF_OUT, freq_code); } -int xc_set_Xtal_frequency(struct xc5000_priv *priv, long xtalFreqInKHz) -{ - unsigned int xtalRatio = (32000 * 0x8000)/xtalFreqInKHz; - return xc_write_reg(priv, XREG_XTALFREQ ,xtalRatio); -} -int xc_get_ADC_Envelope(struct xc5000_priv *priv, - unsigned short int *adc_envelope) +static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) { return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope); } -int xc_get_frequency_error(struct xc5000_priv *priv, u32 *frequency_error_hz) +static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) { int result; - unsigned short int regData; + u16 regData; u32 tmp; result = xc_read_reg(priv, XREG_FREQ_ERROR, ®Data); @@ -400,45 +387,37 @@ int xc_get_frequency_error(struct xc5000_priv *priv, u32 *frequency_error_hz) return result; tmp = (u32)regData; - (*frequency_error_hz) = (tmp * 15625) / 1000; + (*freq_error_hz) = (tmp * 15625) / 1000; return result; } -int xc_get_lock_status(struct xc5000_priv *priv, - unsigned short int *lock_status) +static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) { return xc_read_reg(priv, XREG_LOCK, lock_status); } -int xc_get_version(struct xc5000_priv *priv, - unsigned char* hw_majorversion, - unsigned char* hw_minorversion, - unsigned char* fw_majorversion, - unsigned char* fw_minorversion) +static int xc_get_version(struct xc5000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) { - unsigned short int data; + u16 data; int result; result = xc_read_reg(priv, XREG_VERSION, &data); if (result) return result; - (*hw_majorversion) = (data>>12) & 0x0F; - (*hw_minorversion) = (data>>8) & 0x0F; - (*fw_majorversion) = (data>>4) & 0x0F; - (*fw_minorversion) = (data) & 0x0F; + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; return 0; } -int xc_get_product_id(struct xc5000_priv *priv, unsigned short int *product_id) -{ - return xc_read_reg(priv, XREG_PRODUCT_ID, product_id); -} - -int xc_get_hsync_freq(struct xc5000_priv *priv, int *hsync_freq_hz) +static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) { - unsigned short int regData; + u16 regData; int result; result = xc_read_reg(priv, XREG_HSYNC_FREQ, ®Data); @@ -449,26 +428,24 @@ int xc_get_hsync_freq(struct xc5000_priv *priv, int *hsync_freq_hz) return result; } -int xc_get_frame_lines(struct xc5000_priv *priv, - unsigned short int *frame_lines) +static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) { return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines); } -int xc_get_quality(struct xc5000_priv *priv, unsigned short int *quality) +static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) { return xc_read_reg(priv, XREG_QUALITY, quality); } -unsigned short int WaitForLock(struct xc5000_priv *priv) +static u16 WaitForLock(struct xc5000_priv *priv) { - unsigned short int lockState = 0; + u16 lockState = 0; int watchDogCount = 40; - while ((lockState == 0) && (watchDogCount > 0)) - { + + while ((lockState == 0) && (watchDogCount > 0)) { xc_get_lock_status(priv, &lockState); - if (lockState != 1) - { + if (lockState != 1) { xc_wait(5); watchDogCount--; } @@ -476,16 +453,16 @@ unsigned short int WaitForLock(struct xc5000_priv *priv) return lockState; } -int xc_tune_channel(struct xc5000_priv *priv, u32 freq) +static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) { int found = 0; - dprintk(1, "%s(%d)\n", __FUNCTION__, freq); + dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); - if (xc_set_RF_frequency(priv, freq) != XC_RESULT_SUCCESS) + if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) return 0; - if (WaitForLock(priv)== 1) + if (WaitForLock(priv) == 1) found = 1; return found; @@ -542,15 +519,15 @@ static int xc5000_fwupload(struct dvb_frontend* fe) const struct firmware *fw; int ret; - /* request the firmware, this will block until someone uploads it */ - printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", - XC5000_DEFAULT_FIRMWARE); - - if(!priv->cfg->request_firmware) { + if (!priv->cfg->request_firmware) { printk(KERN_ERR "xc5000: no firmware callback, fatal\n"); return -EIO; } + /* request the firmware, this will block and timeout */ + printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", + XC5000_DEFAULT_FIRMWARE); + ret = priv->cfg->request_firmware(fe, &fw, XC5000_DEFAULT_FIRMWARE); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); @@ -560,7 +537,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe) ret = XC_RESULT_SUCCESS; } - if(fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { + if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { printk(KERN_ERR "xc5000: firmware incorrect size\n"); ret = XC_RESULT_RESET_FAILURE; } else { @@ -572,89 +549,110 @@ static int xc5000_fwupload(struct dvb_frontend* fe) return ret; } -void xc_debug_dump(struct xc5000_priv *priv) +static void xc_debug_dump(struct xc5000_priv *priv) { - unsigned short adc_envelope; - u32 frequency_error_hz; - unsigned short lock_status; - unsigned char hw_majorversion, hw_minorversion = 0; - unsigned char fw_majorversion, fw_minorversion = 0; - int hsync_freq_hz; - unsigned short frame_lines; - unsigned short quality; + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; /* Wait for stats to stabilize. * Frame Lines needs two frame times after initial lock * before it is valid. */ - xc_wait( 100 ); + xc_wait(100); - xc_get_ADC_Envelope(priv, &adc_envelope ); - dprintk(1, "*** ADC envelope (0-1023) = %u\n", adc_envelope); + xc_get_ADC_Envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); - xc_get_frequency_error(priv, &frequency_error_hz ); - dprintk(1, "*** Frequency error = %d Hz\n", frequency_error_hz); + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); - xc_get_lock_status(priv, &lock_status ); - dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %u\n", + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", lock_status); xc_get_version(priv, &hw_majorversion, &hw_minorversion, - &fw_majorversion, &fw_minorversion ); + &fw_majorversion, &fw_minorversion); dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", hw_majorversion, hw_minorversion, fw_majorversion, fw_minorversion); - xc_get_hsync_freq(priv, &hsync_freq_hz ); - dprintk(1, "*** Horizontal sync frequency = %u Hz\n", hsync_freq_hz); + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); - xc_get_frame_lines(priv, &frame_lines ); - dprintk(1, "*** Frame lines = %u\n", frame_lines); + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); - xc_get_quality(priv, &quality ); - dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %u\n", quality); + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); } static int xc5000_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct xc5000_priv *priv = fe->tuner_priv; + int ret; - dprintk(1, "%s() frequency=%d\n", __FUNCTION__, params->frequency); + dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); - priv->frequency = params->frequency - 1750000; - priv->bandwidth = 6; - priv->video_standard = DTV6; switch(params->u.vsb.modulation) { case VSB_8: case VSB_16: dprintk(1, "%s() VSB modulation\n", __FUNCTION__); priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; break; case QAM_64: case QAM_256: case QAM_AUTO: dprintk(1, "%s() QAM modulation\n", __FUNCTION__); priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; break; default: return -EINVAL; } dprintk(1, "%s() frequency=%d (compensated)\n", - __FUNCTION__, priv->frequency); + __FUNCTION__, priv->freq_hz); - /* FIXME: check result codes */ - xc_SetSignalSource(priv, priv->rf_mode); + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } - xc_SetTVStandard(priv, + ret = xc_SetTVStandard(priv, XC5000_Standard[priv->video_standard].VideoMode, XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->cfg->if_khz); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->cfg->if_khz); + return -EIO; + } + + xc_tune_channel(priv, priv->freq_hz); - xc_set_IF_frequency(priv, priv->cfg->if_frequency); - xc_tune_channel(priv, priv->frequency); - xc_debug_dump(priv); + if (debug) + xc_debug_dump(priv); return 0; } @@ -663,7 +661,7 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; dprintk(1, "%s()\n", __FUNCTION__); - *freq = priv->frequency; + *freq = priv->freq_hz; return 0; } @@ -678,7 +676,7 @@ static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) { struct xc5000_priv *priv = fe->tuner_priv; - unsigned short int lock_status = 0; + u16 lock_status = 0; xc_get_lock_status(priv, &lock_status); @@ -689,15 +687,15 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) return 0; } -int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; int ret; - if(priv->fwloaded == 0) { + if (priv->fwloaded == 0) { ret = xc5000_fwupload(fe); - if( ret != XC_RESULT_SUCCESS ) - return -EREMOTEIO; + if (ret != XC_RESULT_SUCCESS) + return ret; priv->fwloaded = 1; } @@ -718,13 +716,26 @@ int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) return ret; } +static int xc5000_sleep(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + + return xc_shutdown(priv); +} + static int xc5000_init(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; dprintk(1, "%s()\n", __FUNCTION__); - xc_load_fw_and_init_tuner(fe); - xc_debug_dump(priv); + if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); + return -EREMOTEIO; + } + + if (debug) + xc_debug_dump(priv); return 0; } @@ -747,6 +758,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .release = xc5000_release, .init = xc5000_init, + .sleep = xc5000_sleep, .set_params = xc5000_set_params, .get_frequency = xc5000_get_frequency, @@ -768,7 +780,7 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, return NULL; priv->cfg = cfg; - priv->bandwidth = 6000000; /* 6MHz */ + priv->bandwidth = BANDWIDTH_6_MHZ; priv->i2c = i2c; priv->fwloaded = 0; @@ -777,7 +789,7 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, return NULL; } - if ( (id != 0x2000) && (id != 0x1388) ) { + if ((id != 0x2000) && (id != 0x1388)) { printk(KERN_ERR "xc5000: Device not found at addr 0x%02x (0x%x)\n", cfg->i2c_address, id); @@ -798,5 +810,5 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, EXPORT_SYMBOL(xc5000_attach); MODULE_AUTHOR("Steven Toth"); -MODULE_DESCRIPTION("Xceive XC5000 silicon tuner driver"); +MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h index ce5a3212f8f..9286a03822c 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/dvb/frontends/xc5000.h @@ -29,8 +29,9 @@ struct i2c_adapter; struct xc5000_config { u8 i2c_address; - u32 if_frequency; - int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); + u32 if_khz; + int (*request_firmware)(struct dvb_frontend *fe, + const struct firmware **fw, char *name); int (*tuner_reset)(struct dvb_frontend* fe); }; diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/dvb/frontends/xc5000_priv.h index a2b54535db0..13b2d19341d 100644 --- a/drivers/media/dvb/frontends/xc5000_priv.h +++ b/drivers/media/dvb/frontends/xc5000_priv.h @@ -26,11 +26,10 @@ struct xc5000_priv { struct xc5000_config *cfg; struct i2c_adapter *i2c; - u32 frequency; + u32 freq_hz; u32 bandwidth; u8 video_standard; u8 rf_mode; - u8 fwloaded; }; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 5fa65ef08bf..f0882dd30d3 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -146,10 +146,10 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { }; static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { - .i2c_address = 0x61, - .if_frequency = 4570000, + .i2c_address = 0x61, + .if_khz = 5380, .request_firmware = cx23885_request_firmware, - .tuner_reset = hauppauge_hvr1500q_tuner_reset + .tuner_reset = hauppauge_hvr1500q_tuner_reset }; static int dvb_register(struct cx23885_tsport *port) -- cgit v1.2.3 From 6df9366857335c6406659ce31554b103a00c3b96 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 20 Dec 2007 01:17:15 -0300 Subject: V4L/DVB (6887): Avoid 'unknown model' message for the HVR1500-Q Avoid 'unknown model' message for the HVR1500-Q Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 515f415564d..d40232cda46 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -194,6 +194,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) { case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 77041: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */ case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ break; -- cgit v1.2.3 From 2800b439e090aa06194dbbfb939cd259b74c42a3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 20 Dec 2007 01:20:38 -0300 Subject: V4L/DVB (6888): Add Hauppauge tuner type 150 defintion Add Hauppauge tuner type 150 defintion. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 11c15787e25..0b8fbad3c72 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -260,6 +260,8 @@ hauppauge_tuner[] = { TUNER_ABSENT, "TCL M09WPP_4N_E"}, { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, + /* 150-159 */ + { TUNER_ABSENT, "Xceive XC5000"}, }; static struct HAUPPAUGE_AUDIOIC -- cgit v1.2.3 From 26501a703d9eca3b42d793d2e2553c33744097b9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 14:28:46 -0300 Subject: V4L/DVB (6890): tda18271: fix typo in RF tracking filter calibration We want to set bits 1 & 2 on easy programming byte 4, not extended byte 4. Thanks to David Wong for pointing this out. Signed-off-by: Michael Krufky Cc: David Wong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 3c0f06e1f47..8eaeb057282 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -406,7 +406,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EB20, 1); /* set CAL mode to RF tracking filter calibration */ - regs[R_EB4] |= 0x03; + regs[R_EP4] |= 0x03; /* calculate CAL PLL */ -- cgit v1.2.3 From fb6d8e2c7fe1667d8ce057e333b18deb91191be5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 16:00:45 -0300 Subject: V4L/DVB (6892): xc5000: fix build when DVB_TUNER_XC5000 is disabled Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h index 9286a03822c..941b3194813 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/dvb/frontends/xc5000.h @@ -42,7 +42,7 @@ extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, #else static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, - struct xc5000_config *cfg); + struct xc5000_config *cfg) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; -- cgit v1.2.3 From 7972f9880c8c812332a56da7cfa4523d01ea310b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 16:12:09 -0300 Subject: V4L/DVB (6893): tuner-xc2028: fix xc2028_attach function xc2028_attach was returning an integer when disabled from the build, where it should instead be returning NULL. Declare xc2028_attach as type dvb_frontend * instead of void *. The prototype declaration must be marked as extern in the header. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 3 ++- drivers/media/video/tuner-xc2028.h | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 5ed12e2272e..ddd94f1d6a6 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -1140,7 +1140,8 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { }; -void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg) +struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) { struct xc2028_data *priv; void *video_dev; diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 7462629b98f..3eb8420379a 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -48,14 +48,15 @@ struct xc2028_config { #define XC2028_RESET_CLK 1 #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) -void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); +extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg); #else -void *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) +static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) { printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", __FUNCTION__); - return -EINVAL; + return NULL; } #endif -- cgit v1.2.3 From 3f51451b516eeb19d3c1ea311ee8845fc80b5135 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 21 Dec 2007 16:20:23 -0300 Subject: V4L/DVB (6894): xc5000: fix build warning Fix the following build warning: xc5000.c:560: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' On many architectrues size_t is unsigned long, and may not be printed with %d. Use %Zu instead. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index 9edd0711539..106004e1245 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -533,7 +533,8 @@ static int xc5000_fwupload(struct dvb_frontend* fe) printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; } else { - printk(KERN_INFO "xc5000: firmware read %d bytes.\n", fw->size); + printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n", + fw->size); ret = XC_RESULT_SUCCESS; } -- cgit v1.2.3 From 0e614cd1a5a09b36a3b6d0fff8a08a97800d3cce Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 21 Dec 2007 21:33:36 -0300 Subject: V4L/DVB (6896): ivtv: add XC2028 support for Club3D cards Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-cards.c | 18 ++++++++---------- drivers/media/video/ivtv/ivtv-driver.c | 19 ++++++++++++++----- drivers/media/video/ivtv/ivtv-driver.h | 1 - drivers/media/video/ivtv/ivtv-gpio.c | 24 ++++++++++++++++++++++++ drivers/media/video/ivtv/ivtv-i2c.c | 4 ++-- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index 26322e93399..f23c6b8d691 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -880,7 +880,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .hw_all = IVTV_HW_CX25840, .video_inputs = { { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, @@ -889,9 +889,6 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .audio_inputs = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, .pci_list = ivtv_pci_pg600v2, .i2c = &ivtv_i2c_std, }; @@ -914,13 +911,17 @@ static const struct ivtv_card ivtv_card_club3d = { .hw_audio_ctrl = IVTV_HW_CX25840, .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, }, .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, @@ -944,7 +945,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, @@ -953,9 +954,6 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, .pci_list = ivtv_pci_avertv_mce116, .i2c = &ivtv_i2c_std, }; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 2765624b230..0cb832a2135 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -59,6 +59,7 @@ #include #include #include +#include "tuner-xc2028.h" /* var to keep track of the number of array elements in use */ int ivtv_cards_active = 0; @@ -844,11 +845,6 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) unsigned i; /* load modules */ - if ((hw & IVTV_HW_TUNER) && itv->options.tuner == TUNER_XC2028) { - IVTV_INFO("Xceive tuner not yet supported, only composite\n"); - IVTV_INFO("and S-Video inputs will be available\n"); - hw &= ~IVTV_HW_TUNER; - } #ifndef CONFIG_VIDEO_TUNER hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif @@ -1150,7 +1146,20 @@ static int __devinit ivtv_probe(struct pci_dev *dev, setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + ivtv_reset_tuner_gpio : NULL; ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = itv->options.tuner, + .priv = &ctrl, + }; + ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg); + } } /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8eeea3a0c70..536140f0c19 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -65,7 +65,6 @@ #include - /* Memory layout */ #define IVTV_ENCODER_OFFSET 0x00000000 #define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 132fb5f7136..688cd385668 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -22,6 +22,7 @@ #include "ivtv-driver.h" #include "ivtv-cards.h" #include "ivtv-gpio.h" +#include "tuner-xc2028.h" #include /* @@ -122,6 +123,29 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) write_reg(curdir, IVTV_REG_GPIO_DIR); } +/* Xceive tuner reset function */ +int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct ivtv *itv = algo->data; + int curdir, curout; + + if (cmd != XC2028_TUNER_RESET) + return 0; + IVTV_DEBUG_INFO("Resetting tuner\n"); + curout = read_reg(IVTV_REG_GPIO_OUT); + curdir = read_reg(IVTV_REG_GPIO_DIR); + curdir |= (1 << 12); /* GPIO bit 12 */ + + curout &= ~(1 << 12); + write_reg(curout, IVTV_REG_GPIO_OUT); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + + curout |= (1 << 12); + write_reg(curout, IVTV_REG_GPIO_OUT); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + return 0; +} void ivtv_gpio_init(struct ivtv *itv) { diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9acfde68116..efd4a1324dc 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -777,9 +777,9 @@ int init_ivtv_i2c(struct ivtv *itv) sizeof(struct i2c_adapter)); memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); - itv->i2c_algo.data = itv; - itv->i2c_adap.algo_data = &itv->i2c_algo; } + itv->i2c_algo.data = itv; + itv->i2c_adap.algo_data = &itv->i2c_algo; sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", itv->num); -- cgit v1.2.3 From ef207feddf826f099562b239543c447e68991b84 Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Sun, 2 Dec 2007 09:30:55 -0300 Subject: V4L/DVB (6897): xc2028: ignore HAS_IF during specific S-Code type searches If we are selecting the S-Code firmware to load by name, then we must mask off the HAS_IF bit during the search. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index ddd94f1d6a6..1817bf67dad 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -395,6 +395,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, { struct xc2028_data *priv = fe->tuner_priv; int i, best_i = -1, best_nr_matches = 0; + unsigned int ign_firm_type_mask = 0; tuner_dbg("%s called, want type=", __FUNCTION__); if (debug) { @@ -412,16 +413,18 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, if (type & BASE) type &= BASE_TYPES; - else if (type & SCODE) + else if (type & SCODE) { type &= SCODE_TYPES; - else if (type & DTV_TYPES) + ign_firm_type_mask = HAS_IF; + } else if (type & DTV_TYPES) type &= DTV_TYPES; else if (type & STD_SPECIFIC_TYPES) type &= STD_SPECIFIC_TYPES; /* Seek for exact match */ for (i = 0; i < priv->firm_size; i++) { - if ((type == priv->firm[i].type) && (*id == priv->firm[i].id)) + if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) && + (*id == priv->firm[i].id)) goto found; } @@ -430,7 +433,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id match_mask; int nr_matches; - if (type != priv->firm[i].type) + if (type != (priv->firm[i].type & ~ign_firm_type_mask)) continue; match_mask = *id & priv->firm[i].id; -- cgit v1.2.3 From 07b4a835d42d6d59e84cbafdc8b7090f97d7b67a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 18 Dec 2007 01:09:11 -0300 Subject: V4L/DVB (6898): cx23885: add support for Hauppauge WinTV HVR-1500 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 1 + drivers/media/video/cx23885/cx23885-cards.c | 24 ++++++++++- drivers/media/video/cx23885/cx23885-dvb.c | 65 +++++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885.h | 1 + 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 54d06e4ff74..698971d23f4 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -4,3 +4,4 @@ 3 -> Hauppauge WinTV-HVR1250 [0070:7911] 4 -> DViCO FusionHDTV5 Express [18ac:d500] 5 -> Hauppauge WinTV-HVR1500Q [0070:7797] + 6 -> Hauppauge WinTV-HVR1500 [0070:7717] diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index d40232cda46..e11fa10a13a 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -117,7 +117,10 @@ struct cx23885_board cx23885_boards[] = { .name = "Hauppauge WinTV-HVR1500Q", .portc = CX23885_MPEG_DVB, }, - + [CX23885_BOARD_HAUPPAUGE_HVR1500] = { + .name = "Hauppauge WinTV-HVR1500", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -153,6 +156,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7797, .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, + },{ + .subvendor = 0x0070, + .subdevice = 0x7717, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -214,6 +221,18 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-0 cx24227 demodulator reset */ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + /* GPIO-0 cx24227 demodulator */ + /* GPIO-2 xc3028 tuner */ + + /* Put the parts into reset */ + cx_set(GP0_IO, 0x00050000); + cx_clear(GP0_IO, 0x00000005); + msleep(5); + + /* Bring the parts out of reset */ + cx_set(GP0_IO, 0x00050005); + break; case CX23885_BOARD_HAUPPAUGE_HVR1500Q: /* GPIO-0 cx24227 demodulator reset */ /* GPIO-2 xc5000 tuner reset */ @@ -236,6 +255,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) { switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* FIXME: Implement me */ @@ -260,6 +280,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: @@ -275,6 +296,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index f0882dd30d3..c1309118ea8 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -35,6 +35,8 @@ #include "lgdt330x.h" #include "xc5000.h" #include "dvb-pll.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" static unsigned int debug = 0; @@ -126,6 +128,14 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .status_mode = S5H1409_DEMODLOCKING }; +static struct s5h1409_config hauppauge_hvr1500_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING +}; + static struct mt2131_config hauppauge_generic_tunerconfig = { 0x61 }; @@ -152,6 +162,36 @@ static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .tuner_reset = hauppauge_hvr1500q_tuner_reset }; +static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) +{ + struct cx23885_tsport *port = ptr; + struct cx23885_dev *dev = port->dev; + + switch (command) { + case XC2028_TUNER_RESET: + /* Send the tuner in then out of reset */ + /* GPIO-2 xc3028 tuner */ + dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); + + cx_set(GP0_IO, 0x00040000); + cx_clear(GP0_IO, 0x00000004); + msleep(5); + + cx_set(GP0_IO, 0x00040004); + msleep(5); + break; + case XC2028_RESET_CLK: + dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); + break; + default: + dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__, + command, arg); + return -EINVAL; + } + + return 0; +} + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -206,6 +246,31 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1500q_tunerconfig); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + i2c_bus = &dev->i2c_bus[1]; + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1500_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &i2c_bus->i2c_adap, + .i2c_addr = 0x61, + .video_dev = port, + .callback = cx23885_hvr1500_xc3028_callback, + }; + static struct xc2028_ctrl ctl = { + .fname = "xc3028-v27.fw", + .max_len = 64, + .scode_table = OREN538, + }; + + fe = dvb_attach(xc2028_attach, + port->dvb.frontend, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 3f019f3cb29..974ec14782d 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -54,6 +54,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 #define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 +#define CX23885_BOARD_HAUPPAUGE_HVR1500 6 enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From 4cd8a7bd65a29c5b7833de177622cb2534d5e868 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 22 Dec 2007 16:59:08 -0300 Subject: V4L/DVB (6899): Kconfig: VIDEO_CX23885 must select TUNER_XC2028 if !DVB_FE_CUSTOMIZE Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 081ee6e1536..30c48b6262d 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -12,6 +12,7 @@ config VIDEO_CX23885 select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE + select TUNER_XC2028 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. -- cgit v1.2.3 From 3ba71d2194500d1a9fef1b8491b9e0c168e7d46e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 7 Dec 2007 01:40:36 -0300 Subject: V4L/DVB (6900): cx23885: enable EZ-QAM mode for Hauppauge WinTV HVR-1800 Add module option 'alt_tuner' disabled by default. When set to one, the dvb_frontend of HVR1800 will consist of: s5h1409 demod + tda18271 tuner When set zero (default), the dvb_frontend of HVR1800 will consist of: s5h1409 demod + mt2131 tuner If the tda18271 is used in digital mode, you will not be able to tune an analog channel at the same time. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 3 +- drivers/media/video/cx23885/cx23885-dvb.c | 47 ++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index e11fa10a13a..fbf93c63dca 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -246,7 +246,8 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-11-14 cx23417 addr0-3 */ /* GPIO-15-18 cx23417 READY, CS, RD, WR */ /* GPIO-19 IR_RX */ - // FIXME: Analog requires the tuner is brought out of reset + + cx_set(GP0_IO, 0x00040004); /* Bring the tuner out of reset */ break; } } diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index c1309118ea8..0f7e9dfcd73 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -32,6 +32,7 @@ #include "s5h1409.h" #include "mt2131.h" +#include "tda8290.h" #include "lgdt330x.h" #include "xc5000.h" #include "dvb-pll.h" @@ -45,6 +46,12 @@ static unsigned int debug = 0; /* ------------------------------------------------------------------ */ +static unsigned int alt_tuner; +module_param(alt_tuner, int, 0644); +MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); + +/* ------------------------------------------------------------------ */ + static int dvb_buf_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { @@ -119,6 +126,15 @@ static struct s5h1409_config hauppauge_generic_config = { .status_mode = S5H1409_DEMODLOCKING }; +static struct s5h1409_config hauppauge_ezqam_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .qam_if = 4000, + .inversion = S5H1409_INVERSION_ON, + .status_mode = S5H1409_DEMODLOCKING +}; + static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, @@ -203,7 +219,6 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800: i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, @@ -214,6 +229,33 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + i2c_bus = &dev->i2c_bus[0]; + switch (alt_tuner) { + case 1: + port->dvb.frontend = + dvb_attach(s5h1409_attach, + &hauppauge_ezqam_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, port->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, 0x42, + NULL); + } + break; + case 0: + default: + port->dvb.frontend = + dvb_attach(s5h1409_attach, + &hauppauge_generic_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) + dvb_attach(mt2131_attach, port->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_generic_tunerconfig, 0); + break; + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, @@ -284,6 +326,9 @@ static int dvb_register(struct cx23885_tsport *port) /* Put the analog decoder in standby to keep it quiet */ cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); + if (port->dvb.frontend->ops.analog_ops.standby) + port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend); + /* register everything */ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); -- cgit v1.2.3 From 478f42292df86a618afbe3c22d11cf08c036d413 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 22 Dec 2007 17:56:25 -0300 Subject: V4L/DVB (6901): Kconfig: VIDEO_CX23885 selects TUNER_TDA8290 and DVB_TDA18271 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 30c48b6262d..3393dd6153e 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -13,6 +13,8 @@ config VIDEO_CX23885 select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE select TUNER_XC2028 if !DVB_FE_CUSTOMIZE + select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select DVB_TDA18271 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. -- cgit v1.2.3 From 994fc28b6cd087cf6ef8d3ebd4eeef97c8194e4e Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Mon, 24 Dec 2007 07:12:55 -0300 Subject: V4L/DVB (6903): mt312: CodingStyle fix Fixes all occurences of assignment in if checkpatch marks them as ERROR. Signed-off-by: Matthias Schwarzott Reviewed-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/mt312.c | 134 ++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 2d68fafc0ef..1638301fbd6 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -152,7 +152,8 @@ static int mt312_get_inversion(struct mt312_state *state, int ret; u8 vit_mode; - if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0) + ret = mt312_readreg(state, VIT_MODE, &vit_mode); + if (ret < 0) return ret; if (vit_mode & 0x80) /* auto inversion was used */ @@ -170,15 +171,18 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) u16 monitor; u8 buf[2]; - if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0) + ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h); + if (ret < 0) return ret; if (sym_rate_h & 0x80) { /* symbol rate search was used */ - if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0) + ret = mt312_writereg(state, MON_CTRL, 0x03); + if (ret < 0) return ret; - if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); + if (ret < 0) return ret; monitor = (buf[0] << 8) | buf[1]; @@ -186,16 +190,18 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) dprintk("sr(auto) = %u\n", mt312_div(monitor * 15625, 4)); } else { - if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0) + ret = mt312_writereg(state, MON_CTRL, 0x05); + if (ret < 0) return ret; - if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); + if (ret < 0) return ret; dec_ratio = ((buf[0] >> 5) & 0x07) * 32; - if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, - sizeof(buf))) < 0) + ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf)); + if (ret < 0) return ret; sym_rat_op = (buf[0] << 8) | buf[1]; @@ -219,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) int ret; u8 fec_status; - if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0) + ret = mt312_readreg(state, FEC_STATUS, &fec_status); + if (ret < 0) return ret; *cr = fec_tab[(fec_status >> 4) & 0x07]; @@ -234,15 +241,17 @@ static int mt312_initfe(struct dvb_frontend *fe) u8 buf[2]; /* wake up */ - if ((ret = mt312_writereg(state, CONFIG, - (state->frequency == 60 ? 0x88 : 0x8c))) < 0) + ret = mt312_writereg(state, CONFIG, + (state->frequency == 60 ? 0x88 : 0x8c)); + if (ret < 0) return ret; /* wait at least 150 usec */ udelay(150); /* full reset */ - if ((ret = mt312_reset(state, 1)) < 0) + ret = mt312_reset(state, 1); + if (ret < 0) return ret; /* Per datasheet, write correct values. 09/28/03 ACCJr. @@ -251,8 +260,8 @@ static int mt312_initfe(struct dvb_frontend *fe) u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00 }; - if ((ret = mt312_write(state, VIT_SETUP, buf_def, - sizeof(buf_def))) < 0) + ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def)); + if (ret < 0) return ret; } @@ -263,23 +272,28 @@ static int mt312_initfe(struct dvb_frontend *fe) /* DISEQC_RATIO */ buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); - if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0) + ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); + if (ret < 0) return ret; - if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0) + ret = mt312_writereg(state, SNR_THS_HIGH, 0x32); + if (ret < 0) return ret; - if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0) + ret = mt312_writereg(state, OP_CTRL, 0x53); + if (ret < 0) return ret; /* TS_SW_LIM */ buf[0] = 0x8c; buf[1] = 0x98; - if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0) + ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); + if (ret < 0) return ret; - if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0) + ret = mt312_writereg(state, CS_SW_LIM, 0x69); + if (ret < 0) return ret; return 0; @@ -295,24 +309,26 @@ static int mt312_send_master_cmd(struct dvb_frontend *fe, if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) return -EINVAL; - if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) return ret; - if ((ret = - mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) + ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len); + if (ret < 0) return ret; - if ((ret = - mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) - | 0x04)) < 0) + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) + | 0x04); + if (ret < 0) return ret; /* set DISEQC_MODE[2:0] to zero if a return message is expected */ - if (c->msg[0] & 0x02) - if ((ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40))) < 0) + if (c->msg[0] & 0x02) { + ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40)); + if (ret < 0) return ret; + } return 0; } @@ -328,12 +344,13 @@ static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) if (c > SEC_MINI_B) return -EINVAL; - if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) return ret; - if ((ret = - mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | mini_tab[c])) < 0) + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | mini_tab[c]); + if (ret < 0) return ret; return 0; @@ -350,12 +367,13 @@ static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) if (t > SEC_TONE_OFF) return -EINVAL; - if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) return ret; - if ((ret = - mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | tone_tab[t])) < 0) + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | tone_tab[t]); + if (ret < 0) return ret; return 0; @@ -380,7 +398,8 @@ static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) *s = 0; - if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) + ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status)); + if (ret < 0) return ret; dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," @@ -406,7 +425,8 @@ static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) int ret; u8 buf[3]; - if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0) + ret = mt312_read(state, RS_BERCNT_H, buf, 3); + if (ret < 0) return ret; *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; @@ -423,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend *fe, u16 agc; s16 err_db; - if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, AGC_H, buf, sizeof(buf)); + if (ret < 0) return ret; agc = (buf[0] << 6) | (buf[1] >> 2); @@ -442,7 +463,8 @@ static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) int ret; u8 buf[2]; - if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0) + ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf)); + if (ret < 0) return ret; *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); @@ -456,7 +478,8 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) int ret; u8 buf[2]; - if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0) + ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf)); + if (ret < 0) return ret; *ubc = (buf[0] << 8) | buf[1]; @@ -512,14 +535,16 @@ static int mt312_set_frontend(struct dvb_frontend *fe, if ((config_val & 0x0c) == 0x08) { /* We are running 60MHz */ state->frequency = 90; - if ((ret = mt312_initfe(fe)) < 0) + ret = mt312_initfe(fe); + if (ret < 0) return ret; } } else { if ((config_val & 0x0c) == 0x0C) { /* We are running 90MHz */ state->frequency = 60; - if ((ret = mt312_initfe(fe)) < 0) + ret = mt312_initfe(fe); + if (ret < 0) return ret; } } @@ -557,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend *fe, /* GO */ buf[4] = 0x01; - if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0) + ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf)); + if (ret < 0) return ret; mt312_reset(state, 0); @@ -571,13 +597,16 @@ static int mt312_get_frontend(struct dvb_frontend *fe, struct mt312_state *state = fe->demodulator_priv; int ret; - if ((ret = mt312_get_inversion(state, &p->inversion)) < 0) + ret = mt312_get_inversion(state, &p->inversion); + if (ret < 0) return ret; - if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0) + ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); + if (ret < 0) return ret; - if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0) + ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); + if (ret < 0) return ret; return 0; @@ -601,14 +630,17 @@ static int mt312_sleep(struct dvb_frontend *fe) u8 config; /* reset all registers to defaults */ - if ((ret = mt312_reset(state, 1)) < 0) + ret = mt312_reset(state, 1); + if (ret < 0) return ret; - if ((ret = mt312_readreg(state, CONFIG, &config)) < 0) + ret = mt312_readreg(state, CONFIG, &config); + if (ret < 0) return ret; /* enter standby */ - if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0) + ret = mt312_writereg(state, CONFIG, config & 0x7f); + if (ret < 0) return ret; return 0; -- cgit v1.2.3 From 7e946c8a4242e3ed944cececddd3f2294299ed65 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 03:47:30 -0300 Subject: V4L/DVB (6904): tda18271: divider byte 1, bit 7 is always 0 Bit 7 of both Main Divider byte 1 and Cal Divider byte 1 is always zero. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 8eaeb057282..d9994aeeb14 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -424,7 +424,7 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_CPD] = pd; div = ((d * (N / 1000)) << 7) / 125; - regs[R_CD1] = 0xff & (div >> 16); + regs[R_CD1] = 0x7f & (div >> 16); regs[R_CD2] = 0xff & (div >> 8); regs[R_CD3] = 0xff & div; @@ -453,7 +453,7 @@ static int tda18271_tune(struct dvb_frontend *fe, } div = ((d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD1] = 0x7f & (div >> 16); regs[R_MD2] = 0xff & (div >> 8); regs[R_MD3] = 0xff & div; @@ -567,7 +567,7 @@ static int tda18271_tune(struct dvb_frontend *fe, } div = ((d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0xff & (div >> 16); + regs[R_MD1] = 0x7f & (div >> 16); regs[R_MD2] = 0xff & (div >> 8); regs[R_MD3] = 0xff & div; -- cgit v1.2.3 From 49e7aaf0ff14a270f3c481ab200dcf361c4155a5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 04:15:20 -0300 Subject: V4L/DVB (6905): tda18271: check ID register during attach Identify the silicon during attach, return NULL if unsupported device. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 40 +++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index d9994aeeb14..4a32c2e6371 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -719,6 +719,36 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int tda18271_get_id(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + char *name; + int ret = 0; + + tda18271_read_regs(fe); + + switch (regs[R_ID] & 0x7f) { + case 3: + name = "TDA18271HD/C1"; + break; + case 4: + name = "TDA18271HD/C2"; + ret = -EPROTONOSUPPORT; + break; + default: + name = "Unknown device"; + ret = -EINVAL; + break; + } + + dbg_info("%s detected @ %d-%04x%s\n", name, + i2c_adapter_id(priv->i2c_adap), priv->i2c_addr, + (0 == ret) ? "" : ", device not supported."); + + return ret; +} + static struct dvb_tuner_ops tda18271_tuner_ops = { .info = { .name = "NXP TDA18271HD", @@ -749,14 +779,20 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, priv->i2c_adap = i2c; priv->gate = gate; + fe->tuner_priv = priv; + + if (tda18271_get_id(fe) < 0) + goto fail; + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - tda18271_init_regs(fe); return fe; +fail: + tda18271_release(fe); + return NULL; } EXPORT_SYMBOL_GPL(tda18271_attach); MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); -- cgit v1.2.3 From f0bd504fb91c8929bfbacbad759a8e3fe572589f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 04:35:21 -0300 Subject: V4L/DVB (6906): tda18271: rename tda18271_calc_* functions to tda18271_lookup_* Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 18 +++++++++--------- drivers/media/dvb/frontends/tda18271-priv.h | 18 +++++++++--------- drivers/media/dvb/frontends/tda18271-tables.c | 16 ++++++++-------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 4a32c2e6371..4c105853d93 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -386,7 +386,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* RF tracking filter calibration */ /* calculate BP_Filter */ - tda18271_calc_bp_filter(&freq, &val); + tda18271_lookup_bp_filter(&freq, &val); regs[R_EP1] &= ~0x07; /* clear bp filter bits */ regs[R_EP1] |= val; @@ -419,7 +419,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - tda18271_calc_cal_pll(&N, &pd, &d); + tda18271_lookup_cal_pll(&N, &pd, &d); regs[R_CPD] = pd; @@ -439,7 +439,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - tda18271_calc_main_pll(&N, &pd, &d); + tda18271_lookup_main_pll(&N, &pd, &d); regs[R_MPD] = (0x7f & pd); @@ -461,20 +461,20 @@ static int tda18271_tune(struct dvb_frontend *fe, msleep(5); /* RF tracking filter calibration initialization */ /* search for K,M,CO for RF Calibration */ - tda18271_calc_km(&freq, &val); + tda18271_lookup_km(&freq, &val); regs[R_EB13] &= 0x83; regs[R_EB13] |= val; tda18271_write_regs(fe, R_EB13, 1); /* search for RF_BAND */ - tda18271_calc_rf_band(&freq, &val); + tda18271_lookup_rf_band(&freq, &val); regs[R_EP2] &= ~0xe0; /* clear rf band bits */ regs[R_EP2] |= (val << 5); /* search for Gain_Taper */ - tda18271_calc_gain_taper(&freq, &val); + tda18271_lookup_gain_taper(&freq, &val); regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ regs[R_EP2] |= val; @@ -502,7 +502,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP1, 1); /* RF tracking filer correction for VHF_Low band */ - tda18271_calc_rf_cal(&freq, &val); + tda18271_lookup_rf_cal(&freq, &val); /* VHF_Low band only */ if (val != 0) { @@ -546,7 +546,7 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ /* image rejection validity EP5[2:0] */ - tda18271_calc_ir_measure(&freq, &val); + tda18271_lookup_ir_measure(&freq, &val); regs[R_EP5] &= ~0x07; regs[R_EP5] |= val; @@ -554,7 +554,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* calculate MAIN PLL */ N = freq + ifc; - tda18271_calc_main_pll(&N, &pd, &d); + tda18271_lookup_main_pll(&N, &pd, &d); regs[R_MPD] = (0x7f & pd); switch (priv->mode) { diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index d56c2fe3efa..e1fa9a46793 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -82,15 +82,15 @@ extern int tda18271_debug; /*---------------------------------------------------------------------*/ -extern void tda18271_calc_cal_pll(u32 *freq, u8 *post_div, u8 *div); -extern void tda18271_calc_main_pll(u32 *freq, u8 *post_div, u8 *div); - -extern void tda18271_calc_bp_filter(u32 *freq, u8 *val); -extern void tda18271_calc_km(u32 *freq, u8 *val); -extern void tda18271_calc_rf_band(u32 *freq, u8 *val); -extern void tda18271_calc_gain_taper(u32 *freq, u8 *val); -extern void tda18271_calc_rf_cal(u32 *freq, u8 *val); -extern void tda18271_calc_ir_measure(u32 *freq, u8 *val); +extern void tda18271_lookup_cal_pll(u32 *freq, u8 *post_div, u8 *div); +extern void tda18271_lookup_main_pll(u32 *freq, u8 *post_div, u8 *div); + +extern void tda18271_lookup_bp_filter(u32 *freq, u8 *val); +extern void tda18271_lookup_km(u32 *freq, u8 *val); +extern void tda18271_lookup_rf_band(u32 *freq, u8 *val); +extern void tda18271_lookup_gain_taper(u32 *freq, u8 *val); +extern void tda18271_lookup_rf_cal(u32 *freq, u8 *val); +extern void tda18271_lookup_ir_measure(u32 *freq, u8 *val); #endif /* __TDA18271_PRIV_H__ */ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 65387bb059e..cce0e0d8223 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -294,49 +294,49 @@ static void tda18271_lookup_pll_map(struct tda18271_pll_map *map, /*---------------------------------------------------------------------*/ -void tda18271_calc_cal_pll(u32 *freq, u8 *post_div, u8 *div) +void tda18271_lookup_cal_pll(u32 *freq, u8 *post_div, u8 *div) { tda18271_lookup_pll_map(tda18271_cal_pll, freq, post_div, div); dbg_map("post div = 0x%02x, div = 0x%02x\n", *post_div, *div); } -void tda18271_calc_main_pll(u32 *freq, u8 *post_div, u8 *div) +void tda18271_lookup_main_pll(u32 *freq, u8 *post_div, u8 *div) { tda18271_lookup_pll_map(tda18271_main_pll, freq, post_div, div); dbg_map("post div = 0x%02x, div = 0x%02x\n", *post_div, *div); } -void tda18271_calc_bp_filter(u32 *freq, u8 *val) +void tda18271_lookup_bp_filter(u32 *freq, u8 *val) { tda18271_lookup_map(tda18271_bp_filter, freq, val); dbg_map("0x%02x\n", *val); } -void tda18271_calc_km(u32 *freq, u8 *val) +void tda18271_lookup_km(u32 *freq, u8 *val) { tda18271_lookup_map(tda18271_km, freq, val); dbg_map("0x%02x\n", *val); } -void tda18271_calc_rf_band(u32 *freq, u8 *val) +void tda18271_lookup_rf_band(u32 *freq, u8 *val) { tda18271_lookup_map(tda18271_rf_band, freq, val); dbg_map("0x%02x\n", *val); } -void tda18271_calc_gain_taper(u32 *freq, u8 *val) +void tda18271_lookup_gain_taper(u32 *freq, u8 *val) { tda18271_lookup_map(tda18271_gain_taper, freq, val); dbg_map("0x%02x\n", *val); } -void tda18271_calc_rf_cal(u32 *freq, u8 *val) +void tda18271_lookup_rf_cal(u32 *freq, u8 *val) { tda18271_lookup_map(tda18271_rf_cal, freq, val); dbg_map("0x%02x\n", *val); } -void tda18271_calc_ir_measure(u32 *freq, u8 *val) +void tda18271_lookup_ir_measure(u32 *freq, u8 *val) { tda18271_lookup_map(tda18271_ir_measure, freq, val); dbg_map("0x%02x\n", *val); -- cgit v1.2.3 From fe0bf6d783d8057bd3dd0dd69613a390d6986c47 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 05:05:05 -0300 Subject: V4L/DVB (6907): tda18271: create separate calc_pll functions Consolidate duplicated code by creating functions: tda18271_calc_main_pll tda18271_calc_cal_pll Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 99 +++++++++++++++++-------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 4c105853d93..19c9be92de5 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -371,13 +371,64 @@ static int tda18271_init(struct dvb_frontend *fe) return 0; } +static int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) +{ + /* Sets Main Post-Divider & Divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + tda18271_lookup_main_pll(&freq, &pd, &d); + + regs[R_MPD] = (0x77 & pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_MD1] = 0x7f & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + return 0; +} + +static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) +{ + /* Sets Cal Post-Divider & Divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + tda18271_lookup_cal_pll(&freq, &pd, &d); + + regs[R_CPD] = pd; + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_CD1] = 0x7f & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; + + return 0; +} + static int tda18271_tune(struct dvb_frontend *fe, u32 ifc, u32 freq, u32 bw, u8 std) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - u32 div, N = 0; - u8 d, pd, val; + u32 N = 0; + u8 val; tda18271_init(fe); @@ -419,14 +470,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - tda18271_lookup_cal_pll(&N, &pd, &d); - - regs[R_CPD] = pd; - - div = ((d * (N / 1000)) << 7) / 125; - regs[R_CD1] = 0x7f & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; + tda18271_calc_cal_pll(fe, N); /* calculate MAIN PLL */ @@ -439,23 +483,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - tda18271_lookup_main_pll(&N, &pd, &d); - - regs[R_MPD] = (0x7f & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0x7f & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; + tda18271_calc_main_pll(fe, N); tda18271_write_regs(fe, R_EP3, 11); msleep(5); /* RF tracking filter calibration initialization */ @@ -554,22 +582,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* calculate MAIN PLL */ N = freq + ifc; - tda18271_lookup_main_pll(&N, &pd, &d); - - regs[R_MPD] = (0x7f & pd); - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0x7f & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; + tda18271_calc_main_pll(fe, N); tda18271_write_regs(fe, R_TM, 15); msleep(5); -- cgit v1.2.3 From c90762799c42df203fc2c9c1a2ac39f154f8faca Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 04:36:14 -0300 Subject: V4L/DVB (6908): tda8290: add the option not to probe for tuners passed into tda829x_config Prevent the tda8290 module from probing for tuners during tda829x_attach, by passing: .probe_tuner = TDA829X_DONT_PROBE, ...in struct tda829x_config Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 9 ++++++++- drivers/media/video/tda8290.h | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 2e1d9b663a9..bb62d5629af 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -688,10 +688,17 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, sizeof(struct analog_demod_ops)); } - if (tda829x_find_tuner(fe) < 0) + if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) && + (tda829x_find_tuner(fe) < 0)) goto fail; switch (priv->ver) { + case TDA8290: + name = "tda8290"; + break; + case TDA8295: + name = "tda8295"; + break; case TDA8290 | TDA8275: name = "tda8290+75"; break; diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 7bce03183d0..dc8ef310b7b 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -23,6 +23,10 @@ struct tda829x_config { unsigned int *lna_cfg; int (*tuner_callback) (void *dev, int command, int arg); + + unsigned int probe_tuner:1; +#define TDA829X_PROBE_TUNER 0 +#define TDA829X_DONT_PROBE 1 }; #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -- cgit v1.2.3 From 4041f1a58774249f5f26163e68b844521ece1fb4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 04:52:08 -0300 Subject: V4L/DVB (6909): cx23885: fix bad use count caused by tda18271 being probed by tda8290 Don't allow the tda8290 module to probe and attach the tuner module, causing incorrect use counts when using dvb_attach. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 0f7e9dfcd73..81dd47f6f65 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -33,6 +33,7 @@ #include "s5h1409.h" #include "mt2131.h" #include "tda8290.h" +#include "tda18271.h" #include "lgdt330x.h" #include "xc5000.h" #include "dvb-pll.h" @@ -178,6 +179,10 @@ static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .tuner_reset = hauppauge_hvr1500q_tuner_reset }; +static struct tda829x_config tda829x_no_probe = { + .probe_tuner = TDA829X_DONT_PROBE, +}; + static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) { struct cx23885_tsport *port = ptr; @@ -240,7 +245,10 @@ static int dvb_register(struct cx23885_tsport *port) if (port->dvb.frontend != NULL) { dvb_attach(tda829x_attach, port->dvb.frontend, &dev->i2c_bus[1].i2c_adap, 0x42, - NULL); + &tda829x_no_probe); + dvb_attach(tda18271_attach, port->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + TDA18271_GATE_ANALOG); } break; case 0: -- cgit v1.2.3 From 402aa76aa5e57801b4db5ccf8c7beea9f580bb1b Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Thu, 27 Dec 2007 22:20:58 -0300 Subject: V4L/DVB (6911): Converted bttv to use video_ioctl2 Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 2033 +++++++++++++++++-------------- drivers/media/video/bt8xx/bttv-vbi.c | 52 +- drivers/media/video/bt8xx/bttvp.h | 11 +- 3 files changed, 1134 insertions(+), 962 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index e04113f0b7e..d6a305ddc53 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -476,7 +476,7 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); /* ----------------------------------------------------------------------- */ /* bttv format list packed pixel formats must come first */ -static const struct bttv_format bttv_formats[] = { +static const struct bttv_format formats[] = { { .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY, @@ -609,7 +609,7 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_RAW, } }; -static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats); +static const unsigned int FORMATS = ARRAY_SIZE(formats); /* ----------------------------------------------------------------------- */ @@ -787,6 +787,16 @@ static const struct v4l2_queryctrl bttv_ctls[] = { }; static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); +static const struct v4l2_queryctrl *ctrl_by_id(int id) +{ + int i; + + for (i = 0; i < BTTV_CTLS; i++) + if (bttv_ctls[i].id == id) + return bttv_ctls+i; + return NULL; +} + /* ----------------------------------------------------------------------- */ /* resource management */ @@ -1432,157 +1442,6 @@ static void bttv_reinit_bt848(struct bttv *btv) set_input(btv, btv->input, btv->tvnorm); } -static int get_control(struct bttv *btv, struct v4l2_control *c) -{ - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = btv->bright; - break; - case V4L2_CID_HUE: - c->value = btv->hue; - break; - case V4L2_CID_CONTRAST: - c->value = btv->contrast; - break; - case V4L2_CID_SATURATION: - c->value = btv->saturation; - break; - - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - c->value = btv->opt_chroma_agc; - break; - case V4L2_CID_PRIVATE_COMBFILTER: - c->value = btv->opt_combfilter; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - c->value = btv->opt_lumafilter; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = btv->opt_automute; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - c->value = btv->opt_adc_crush; - break; - case V4L2_CID_PRIVATE_VCR_HACK: - c->value = btv->opt_vcr_hack; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - c->value = btv->opt_whitecrush_upper; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - c->value = btv->opt_whitecrush_lower; - break; - case V4L2_CID_PRIVATE_UV_RATIO: - c->value = btv->opt_uv_ratio; - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - c->value = btv->opt_full_luma_range; - break; - case V4L2_CID_PRIVATE_CORING: - c->value = btv->opt_coring; - break; - default: - return -EINVAL; - } - return 0; -} - -static int set_control(struct bttv *btv, struct v4l2_control *c) -{ - int val; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - bt848_bright(btv,c->value); - break; - case V4L2_CID_HUE: - bt848_hue(btv,c->value); - break; - case V4L2_CID_CONTRAST: - bt848_contrast(btv,c->value); - break; - case V4L2_CID_SATURATION: - bt848_sat(btv,c->value); - break; - case V4L2_CID_AUDIO_MUTE: - audio_mute(btv, c->value); - /* fall through */ - case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) { - btv->volume_gpio (btv, c->value); - } - bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); - break; - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - break; - case V4L2_CID_PRIVATE_COMBFILTER: - btv->opt_combfilter = c->value; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - btv->opt_lumafilter = c->value; - if (btv->opt_lumafilter) { - btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); - btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); - } else { - btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - btv->opt_automute = c->value; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - btv->opt_adc_crush = c->value; - btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - break; - case V4L2_CID_PRIVATE_VCR_HACK: - btv->opt_vcr_hack = c->value; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - btv->opt_whitecrush_upper = c->value; - btwrite(c->value, BT848_WC_UP); - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - btv->opt_whitecrush_lower = c->value; - btwrite(c->value, BT848_WC_DOWN); - break; - case V4L2_CID_PRIVATE_UV_RATIO: - btv->opt_uv_ratio = c->value; - bt848_sat(btv, btv->saturation); - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - btv->opt_full_luma_range = c->value; - btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); - break; - case V4L2_CID_PRIVATE_CORING: - btv->opt_coring = c->value; - btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); - break; - default: - return -EINVAL; - } - return 0; -} - /* ----------------------------------------------------------------------- */ void bttv_gpio_tracking(struct bttv *btv, char *comment) @@ -1616,11 +1475,11 @@ format_by_fourcc(int fourcc) { unsigned int i; - for (i = 0; i < BTTV_FORMATS; i++) { - if (-1 == bttv_formats[i].fourcc) + for (i = 0; i < FORMATS; i++) { + if (-1 == formats[i].fourcc) continue; - if (bttv_formats[i].fourcc == fourcc) - return bttv_formats+i; + if (formats[i].fourcc == fourcc) + return formats+i; } return NULL; } @@ -1821,215 +1680,430 @@ static struct videobuf_queue_ops bttv_video_qops = { .buf_release = buffer_release, }; -static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) { - switch (cmd) { - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int index = e->index; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + unsigned int i; + int err; - if (index >= BTTV_TVNORMS) - return -EINVAL; - v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id, - bttv_tvnorms[e->index].name); - e->index = index; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - *id = bttv_tvnorms[btv->tvnorm].v4l2_id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; - for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) - break; - if (i == BTTV_TVNORMS) - return -EINVAL; + for (i = 0; i < BTTV_TVNORMS; i++) + if (*id & bttv_tvnorms[i].v4l2_id) + break; + if (i == BTTV_TVNORMS) + return -EINVAL; - mutex_lock(&btv->lock); - set_tvnorm(btv,i); - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *id = arg; + mutex_lock(&btv->lock); + set_tvnorm(btv, i); + mutex_unlock(&btv->lock); - if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) - *id = V4L2_STD_625_50; - else - *id = V4L2_STD_525_60; - return 0; - } + return 0; +} - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; +static int vidioc_querystd(struct file *file, void *f, v4l2_std_id *id) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - n = i->index; - if (n >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - memset(i,0,sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; - if (i->index == bttv_tvcards[btv->c.type].tuner) { - sprintf(i->name, "Television"); - i->type = V4L2_INPUT_TYPE_TUNER; - i->tuner = 0; - } else if (i->index == btv->svhs) { - sprintf(i->name, "S-Video"); - } else { - sprintf(i->name,"Composite%d",i->index); - } - if (i->index == btv->input) { - __u32 dstatus = btread(BT848_DSTATUS); - if (0 == (dstatus & BT848_DSTATUS_PRES)) - i->status |= V4L2_IN_ST_NO_SIGNAL; - if (0 == (dstatus & BT848_DSTATUS_HLOC)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - } - for (n = 0; n < BTTV_TVNORMS; n++) - i->std |= bttv_tvnorms[n].v4l2_id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = btv->input; - return 0; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; + if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) + *id = V4L2_STD_625_50; + else + *id = V4L2_STD_525_60; + return 0; +} - if (*i > bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - mutex_lock(&btv->lock); - set_input(btv, *i, btv->tvnorm); - mutex_unlock(&btv->lock); - return 0; - } +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + unsigned int n; - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; + n = i->index; - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); + if (n >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; - if (btv->audio_mode_gpio) { - btv->audio_mode_gpio (btv,t,1); - } - mutex_unlock(&btv->lock); - return 0; - } + memset(i, 0, sizeof(*i)); - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->audioset = 1; - memset(f,0,sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = btv->freq; - return 0; + if (i->index == bttv_tvcards[btv->c.type].tuner) { + sprintf(i->name, "Television"); + i->type = V4L2_INPUT_TYPE_TUNER; + i->tuner = 0; + } else if (i->index == btv->svhs) { + sprintf(i->name, "S-Video"); + } else { + sprintf(i->name, "Composite%d", i->index); } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - if (unlikely(f->tuner != 0)) - return -EINVAL; - if (unlikely (f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - mutex_lock(&btv->lock); - btv->freq = f->frequency; - bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv,btv->freq); - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOC_LOG_STATUS: - { - printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr); - bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); - printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); - return 0; - } - case VIDIOC_G_CTRL: - return get_control(btv,arg); - case VIDIOC_S_CTRL: - return set_control(btv,arg); -#ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *reg = arg; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - if (cmd == VIDIOC_DBG_G_REGISTER) - reg->val = btread(reg->reg); - else - btwrite(reg->val, reg->reg); - return 0; + if (i->index == btv->input) { + __u32 dstatus = btread(BT848_DSTATUS); + if (0 == (dstatus & BT848_DSTATUS_PRES)) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 == (dstatus & BT848_DSTATUS_HLOC)) + i->status |= V4L2_IN_ST_NO_H_LOCK; } -#endif - default: - return -ENOIOCTLCMD; + for (n = 0; n < BTTV_TVNORMS; n++) + i->std |= bttv_tvnorms[n].v4l2_id; - } return 0; } -/* Given cropping boundaries b and the scaled width and height of a - single field or frame, which must not exceed hardware limits, this - function adjusts the cropping parameters c. */ -static void -bttv_crop_adjust (struct bttv_crop * c, - const struct v4l2_rect * b, - __s32 width, - __s32 height, - enum v4l2_field field) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); - __s32 max_left; - __s32 max_top; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - if (width < c->min_scaled_width) { - /* Max. hor. scale factor 16:1. */ - c->rect.width = width * 16; - } else if (width > c->max_scaled_width) { - /* Min. hor. scale factor 1:1. */ - c->rect.width = width; + *i = btv->input; + return 0; +} - max_left = b->left + b->width - width; - max_left = min(max_left, (__s32) MAX_HDELAY); - if (c->rect.left > max_left) - c->rect.left = max_left; - } +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - if (height < c->min_scaled_height) { - /* Max. vert. scale factor 16:1, single fields 8:1. */ - c->rect.height = height * 16; - } else if (frame_height > c->max_scaled_height) { + int err; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + if (i > bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + + mutex_lock(&btv->lock); + set_input(btv, i, btv->tvnorm); + mutex_unlock(&btv->lock); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + + if (0 != t->index) + return -EINVAL; + + mutex_lock(&btv->lock); + bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 1); + + mutex_unlock(&btv->lock); + + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = btv->freq; + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + if (unlikely(f->tuner != 0)) + return -EINVAL; + if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + mutex_lock(&btv->lock); + btv->freq = f->frequency; + bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv, btv->freq); + mutex_unlock(&btv->lock); + return 0; +} + +static int vidioc_log_status(struct file *file, void *f) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); + bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); + printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); + return 0; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = btv->bright; + break; + case V4L2_CID_HUE: + c->value = btv->hue; + break; + case V4L2_CID_CONTRAST: + c->value = btv->contrast; + break; + case V4L2_CID_SATURATION: + c->value = btv->saturation; + break; + + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + c->value = btv->opt_chroma_agc; + break; + case V4L2_CID_PRIVATE_COMBFILTER: + c->value = btv->opt_combfilter; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + c->value = btv->opt_lumafilter; + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + c->value = btv->opt_automute; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + c->value = btv->opt_adc_crush; + break; + case V4L2_CID_PRIVATE_VCR_HACK: + c->value = btv->opt_vcr_hack; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + c->value = btv->opt_whitecrush_upper; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + c->value = btv->opt_whitecrush_lower; + break; + case V4L2_CID_PRIVATE_UV_RATIO: + c->value = btv->opt_uv_ratio; + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + c->value = btv->opt_full_luma_range; + break; + case V4L2_CID_PRIVATE_CORING: + c->value = btv->opt_coring; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_s_ctrl(struct file *file, void *f, + struct v4l2_control *c) +{ + int err; + int val; + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + bt848_bright(btv, c->value); + break; + case V4L2_CID_HUE: + bt848_hue(btv, c->value); + break; + case V4L2_CID_CONTRAST: + bt848_contrast(btv, c->value); + break; + case V4L2_CID_SATURATION: + bt848_sat(btv, c->value); + break; + case V4L2_CID_AUDIO_MUTE: + audio_mute(btv, c->value); + /* fall through */ + case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) + btv->volume_gpio(btv, c->value); + + bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); + break; + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + btv->opt_chroma_agc = c->value; + val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); + break; + case V4L2_CID_PRIVATE_COMBFILTER: + btv->opt_combfilter = c->value; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + btv->opt_lumafilter = c->value; + if (btv->opt_lumafilter) { + btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); + btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); + } else { + btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + btv->opt_automute = c->value; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + btv->opt_adc_crush = c->value; + btwrite(BT848_ADC_RESERVED | + (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); + break; + case V4L2_CID_PRIVATE_VCR_HACK: + btv->opt_vcr_hack = c->value; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + btv->opt_whitecrush_upper = c->value; + btwrite(c->value, BT848_WC_UP); + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + btv->opt_whitecrush_lower = c->value; + btwrite(c->value, BT848_WC_DOWN); + break; + case V4L2_CID_PRIVATE_UV_RATIO: + btv->opt_uv_ratio = c->value; + bt848_sat(btv, btv->saturation); + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + btv->opt_full_luma_range = c->value; + btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + break; + case V4L2_CID_PRIVATE_CORING: + btv->opt_coring = c->value; + btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + break; + default: + return -EINVAL; + } + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *f, + struct v4l2_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + reg->val = btread(reg->reg); + + return 0; +} + +static int vidioc_s_register(struct file *file, void *f, + struct v4l2_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + btwrite(reg->val, reg->reg); + + return 0; +} +#endif + +/* Given cropping boundaries b and the scaled width and height of a + single field or frame, which must not exceed hardware limits, this + function adjusts the cropping parameters c. */ +static void +bttv_crop_adjust (struct bttv_crop * c, + const struct v4l2_rect * b, + __s32 width, + __s32 height, + enum v4l2_field field) +{ + __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); + __s32 max_left; + __s32 max_top; + + if (width < c->min_scaled_width) { + /* Max. hor. scale factor 16:1. */ + c->rect.width = width * 16; + } else if (width > c->max_scaled_width) { + /* Min. hor. scale factor 1:1. */ + c->rect.width = width; + + max_left = b->left + b->width - width; + max_left = min(max_left, (__s32) MAX_HDELAY); + if (c->rect.left > max_left) + c->rect.left = max_left; + } + + if (height < c->min_scaled_height) { + /* Max. vert. scale factor 16:1, single fields 8:1. */ + c->rect.height = height * 16; + } else if (frame_height > c->max_scaled_height) { /* Min. vert. scale factor 1:1. Top and height count field lines times two. */ c->rect.height = (frame_height + 1) & ~1; @@ -2373,652 +2447,633 @@ pix_format_set_size (struct v4l2_pix_format * f, } } -static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f) +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format)); - pix_format_set_size (&f->fmt.pix, fh->fmt, - fh->width, fh->height); - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - memset(&f->fmt.win,0,sizeof(struct v4l2_window)); - f->fmt.win.w = fh->ov.w; - f->fmt.win.field = fh->ov.field; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - bttv_vbi_get_fmt(fh, &f->fmt.vbi); - return 0; - default: - return -EINVAL; - } + struct bttv_fh *fh = priv; + + pix_format_set_size(&f->fmt.pix, fh->fmt, + fh->width, fh->height); + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + + return 0; } -static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, - struct v4l2_format *f, int adjust_crop) +static int vidioc_g_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - const struct bttv_format *fmt; - enum v4l2_field field; - __s32 width, height; - int rc; + struct bttv_fh *fh = priv; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; + f->fmt.win.w = fh->ov.w; + f->fmt.win.field = fh->ov.field; - field = f->fmt.pix.field; - if (V4L2_FIELD_ANY == field) { - __s32 height2; + return 0; +} - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (f->fmt.pix.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - if (V4L2_FIELD_SEQ_BT == field) - field = V4L2_FIELD_SEQ_TB; - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - case V4L2_FIELD_INTERLACED: - break; - case V4L2_FIELD_SEQ_TB: - if (fmt->flags & FORMAT_FLAGS_PLANAR) - return -EINVAL; - break; - default: - return -EINVAL; - } +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + enum v4l2_field field; + __s32 width, height; - width = f->fmt.pix.width; - height = f->fmt.pix.height; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - rc = limit_scaled_size(fh, &width, &height, field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - adjust_crop); - if (0 != rc) - return rc; + field = f->fmt.pix.field; - /* update data for the application */ - f->fmt.pix.field = field; - pix_format_set_size(&f->fmt.pix, fmt, width, height); + if (V4L2_FIELD_ANY == field) { + __s32 height2; - return 0; + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (f->fmt.pix.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - return verify_window(fh, &f->fmt.win, - /* adjust_size */ 1, - /* adjust_crop */ 0); - case V4L2_BUF_TYPE_VBI_CAPTURE: - return bttv_vbi_try_fmt(fh, &f->fmt.vbi); + + if (V4L2_FIELD_SEQ_BT == field) + field = V4L2_FIELD_SEQ_TB; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_SEQ_TB: + if (fmt->flags & FORMAT_FLAGS_PLANAR) + return -EINVAL; + break; default: return -EINVAL; } + + width = f->fmt.pix.width; + height = f->fmt.pix.height; + + /* update data for the application */ + f->fmt.pix.field = field; + pix_format_set_size(&f->fmt.pix, fmt, width, height); + + return 0; } -static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, - struct v4l2_format *f) +static int vidioc_try_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + return verify_window(fh, &f->fmt.win, + /* adjust_size */ 1, + /* adjust_crop */ 0); +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { int retval; + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - const struct bttv_format *fmt; + retval = bttv_switch_type(fh, f->type); + if (0 != retval) + return retval; - retval = bttv_switch_type(fh,f->type); - if (0 != retval) - return retval; - retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1); - if (0 != retval) - return retval; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); + retval = vidioc_try_fmt_cap(file, priv, f); + if (0 != retval) + return retval; - /* update our state informations */ - mutex_lock(&fh->cap.lock); - fh->fmt = fmt; - fh->cap.field = f->fmt.pix.field; - fh->cap.last = V4L2_FIELD_NONE; - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - btv->init.fmt = fmt; - btv->init.width = f->fmt.pix.width; - btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.lock); + fmt = format_by_fourcc(f->fmt.pix.pixelformat); - return 0; - } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - return setup_window(fh, btv, &f->fmt.win, 1); - case V4L2_BUF_TYPE_VBI_CAPTURE: - retval = bttv_switch_type(fh,f->type); - if (0 != retval) - return retval; - return bttv_vbi_set_fmt(fh, &f->fmt.vbi); - default: + /* update our state informations */ + mutex_lock(&fh->cap.lock); + fh->fmt = fmt; + fh->cap.field = f->fmt.pix.field; + fh->cap.last = V4L2_FIELD_NONE; + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + btv->init.fmt = fmt; + btv->init.width = f->fmt.pix.width; + btv->init.height = f->fmt.pix.height; + mutex_unlock(&fh->cap.lock); + + return 0; +} + +static int vidioc_s_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (no_overlay > 0) return -EINVAL; + + return setup_window(fh, btv, &f->fmt.win, 1); +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + int retval; + unsigned int i; + struct bttv_fh *fh = priv; + + mutex_lock(&fh->cap.lock); + retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, + V4L2_MEMORY_MMAP); + if (retval < 0) { + mutex_unlock(&fh->cap.lock); + return retval; } + + gbuffers = retval; + memset(mbuf, 0, sizeof(*mbuf)); + mbuf->frames = gbuffers; + mbuf->size = gbuffers * gbufsize; + + for (i = 0; i < gbuffers; i++) + mbuf->offsets[i] = i * gbufsize; + + mutex_unlock(&fh->cap.lock); + return 0; } +#endif -static int bttv_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - int retval = 0; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - if (bttv_debug > 1) - v4l_print_ioctl(btv->c.name, cmd); + if (0 == v4l2) + return -EINVAL; - if (btv->errors) - bttv_reinit_bt848(btv); + strlcpy(cap->driver, "bttv", sizeof(cap->driver)); + strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + if (bttv_tvcards[btv->c.type].tuner != UNSET && + bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - retval = v4l2_prio_check(&btv->prio,&fh->prio); - if (0 != retval) - return retval; - }; +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >= FORMATS) + return -EINVAL; - switch (cmd) { -#ifdef CONFIG_VIDEO_V4L1_COMPAT - case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - unsigned int i; + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; - retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize, - V4L2_MEMORY_MMAP); - if (retval < 0) - return retval; + return 0; +} - gbuffers = retval; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = gbuffers; - mbuf->size = gbuffers * gbufsize; - for (i = 0; i < gbuffers; i++) - mbuf->offsets[i] = i * gbufsize; - return 0; +static int vidioc_enum_fmt_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; } -#endif - /* *** v4l2 *** ************************************************ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; + if (f->index >= FORMATS) + return -EINVAL; - if (0 == v4l2) - return -EINVAL; - memset(cap, 0, sizeof (*cap)); - strlcpy(cap->driver, "bttv", sizeof (cap->driver)); - strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card)); - snprintf(cap->bus_info, sizeof (cap->bus_info), - "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - if (bttv_tvcards[btv->c.type].tuner != UNSET && - bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; - } - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int i; - int index; - - type = f->type; - if (V4L2_BUF_TYPE_VBI_CAPTURE == type) { - /* vbi */ - index = f->index; - if (0 != index) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description,"vbi data"); - return 0; - } + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); - /* video capture + overlay */ - index = -1; - for (i = 0; i < BTTV_FORMATS; i++) { - if (bttv_formats[i].fourcc != -1) - index++; - if ((unsigned int)index == f->index) - break; - } - if (BTTV_FORMATS == i) - return -EINVAL; + f->pixelformat = formats[f->index].fourcc; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - break; - default: + return 0; +} + +static int vidioc_enum_fmt_vbi(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (0 != f->index) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); + + return 0; +} + +static int vidioc_g_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + *fb = btv->fbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + if (fh->ovfmt) + fb->fmt.pixelformat = fh->ovfmt->fourcc; + return 0; +} + +static int vidioc_overlay(struct file *file, void *f, unsigned int on) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + struct bttv_buffer *new; + int retval; + + if (on) { + /* verify args */ + if (NULL == btv->fbuf.base) + return -EINVAL; + if (!fh->ov.setup_ok) { + dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); return -EINVAL; } - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = bttv_formats[i].fourcc; - strlcpy(f->description,bttv_formats[i].name,sizeof(f->description)); - return 0; } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0); - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return bttv_g_fmt(fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return bttv_s_fmt(fh,btv,f); + + if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY)) + return -EBUSY; + + mutex_lock(&fh->cap.lock); + if (on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_pci_alloc(sizeof(*new)); + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *fb = arg; + /* switch over */ + retval = bttv_switch_overlay(btv, fh, new); + mutex_unlock(&fh->cap.lock); + return retval; +} + +static int vidioc_s_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_format *fmt; + int retval; + + if (!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; - *fb = btv->fbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - if (fh->ovfmt) - fb->fmt.pixelformat = fh->ovfmt->fourcc; - return 0; + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + + retval = -EINVAL; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + __s32 width = fb->fmt.width; + __s32 height = fb->fmt.height; + + retval = limit_scaled_size(fh, &width, &height, + V4L2_FIELD_INTERLACED, + /* width_mask */ ~3, + /* width_bias */ 2, + /* adjust_size */ 0, + /* adjust_crop */ 0); + if (0 != retval) + return retval; } - case VIDIOC_OVERLAY: - { - struct bttv_buffer *new; - int *on = arg; - if (*on) { - /* verify args */ - if (NULL == btv->fbuf.base) - return -EINVAL; - if (!fh->ov.setup_ok) { - dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); - return -EINVAL; - } - } + /* ok, accept it */ + mutex_lock(&fh->cap.lock); + btv->fbuf.base = fb->base; + btv->fbuf.fmt.width = fb->fmt.width; + btv->fbuf.fmt.height = fb->fmt.height; + if (0 != fb->fmt.bytesperline) + btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; + else + btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; - if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) - return -EBUSY; + retval = 0; + fh->ovfmt = fmt; + btv->init.ovfmt = fmt; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + fh->ov.w.left = 0; + fh->ov.w.top = 0; + fh->ov.w.width = fb->fmt.width; + fh->ov.w.height = fb->fmt.height; + btv->init.ov.w.width = fb->fmt.width; + btv->init.ov.w.height = fb->fmt.height; + kfree(fh->ov.clips); + fh->ov.clips = NULL; + fh->ov.nclips = 0; + + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; - mutex_lock(&fh->cap.lock); - if (*on) { - fh->ov.tvnorm = btv->tvnorm; new = videobuf_pci_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; + retval = bttv_switch_overlay(btv, fh, new); } - - /* switch over */ - retval = bttv_switch_overlay(btv,fh,new); - mutex_unlock(&fh->cap.lock); - return retval; } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *fb = arg; - const struct bttv_format *fmt; + mutex_unlock(&fh->cap.lock); + return retval; +} - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct bttv_fh *fh = priv; + return videobuf_reqbufs(bttv_queue(fh), p); +} - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_querybuf(bttv_queue(fh), b); +} - retval = -EINVAL; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - __s32 width = fb->fmt.width; - __s32 height = fb->fmt.height; - - retval = limit_scaled_size(fh, &width, &height, - V4L2_FIELD_INTERLACED, - /* width_mask */ ~3, - /* width_bias */ 2, - /* adjust_size */ 0, - /* adjust_crop */ 0); - if (0 != retval) - return retval; - } +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); - /* ok, accept it */ - mutex_lock(&fh->cap.lock); - btv->fbuf.base = fb->base; - btv->fbuf.fmt.width = fb->fmt.width; - btv->fbuf.fmt.height = fb->fmt.height; - if (0 != fb->fmt.bytesperline) - btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; - - retval = 0; - fh->ovfmt = fmt; - btv->init.ovfmt = fmt; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - fh->ov.w.left = 0; - fh->ov.w.top = 0; - fh->ov.w.width = fb->fmt.width; - fh->ov.w.height = fb->fmt.height; - btv->init.ov.w.width = fb->fmt.width; - btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); - fh->ov.clips = NULL; - fh->ov.nclips = 0; - - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_pci_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); - retval = bttv_switch_overlay(btv,fh,new); - } - } - mutex_unlock(&fh->cap.lock); - return retval; - } - case VIDIOC_REQBUFS: - return videobuf_reqbufs(bttv_queue(fh),arg); - case VIDIOC_QUERYBUF: - return videobuf_querybuf(bttv_queue(fh),arg); - case VIDIOC_QBUF: - { - int res = bttv_resource(fh); + if (!check_alloc_btres(btv, fh, res)) + return -EBUSY; - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; - return videobuf_qbuf(bttv_queue(fh),arg); - } - case VIDIOC_DQBUF: - return videobuf_dqbuf(bttv_queue(fh),arg, - file->f_flags & O_NONBLOCK); - case VIDIOC_STREAMON: - { - int res = bttv_resource(fh); + return videobuf_qbuf(bttv_queue(fh), b); +} - if (!check_alloc_btres(btv,fh,res)) - return -EBUSY; - return videobuf_streamon(bttv_queue(fh)); - } - case VIDIOC_STREAMOFF: - { - int res = bttv_resource(fh); +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_dqbuf(bttv_queue(fh), b, + file->f_flags & O_NONBLOCK); +} - retval = videobuf_streamoff(bttv_queue(fh)); - if (retval < 0) - return retval; - free_btres(btv,fh,res); - return 0; - } +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *c = arg; - int i; + if (!check_alloc_btres(btv, fh, res)) + return -EBUSY; + return videobuf_streamon(bttv_queue(fh)); +} - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) { - *c = no_ctl; - return 0; - } - *c = bttv_ctls[i]; - if (!btv->volume_gpio && - (bttv_ctls[i].id == V4L2_CID_AUDIO_VOLUME)) - *c = no_ctl; +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int retval; + int res = bttv_resource(fh); - return 0; - } - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *parm = arg; - struct v4l2_standard s; - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(parm,0,sizeof(*parm)); - v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, - bttv_tvnorms[btv->tvnorm].name); - parm->parm.capture.timeperframe = s.frameperiod; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - memset(t,0,sizeof(*t)); - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_mode_gpio) { - btv->audio_mode_gpio (btv,t,0); - } + retval = videobuf_streamoff(bttv_queue(fh)); + if (retval < 0) + return retval; + free_btres(btv, fh, res); + return 0; +} - mutex_unlock(&btv->lock); - return 0; - } +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + const struct v4l2_queryctrl *ctrl; - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; - *p = v4l2_prio_max(&btv->prio); - return 0; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; + ctrl = ctrl_by_id(c->id); + *c = (NULL != ctrl) ? *ctrl : no_ctl; - return v4l2_prio_change(&btv->prio, &fh->prio, *prio); - } + if (!btv->volume_gpio && + (ctrl->id == V4L2_CID_AUDIO_VOLUME)) + * c = no_ctl; - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cap = arg; - enum v4l2_buf_type type; + return 0; +} - type = cap->type; +static int vidioc_g_parm(struct file *file, void *f, + struct v4l2_streamparm *parm) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + struct v4l2_standard s; - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, + bttv_tvnorms[btv->tvnorm].name); + parm->parm.capture.timeperframe = s.frameperiod; + return 0; +} - *cap = bttv_tvnorms[btv->tvnorm].cropcap; - cap->type = type; +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - return 0; - } - case VIDIOC_G_CROP: - { - struct v4l2_crop * crop = arg; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + mutex_lock(&btv->lock); + memset(t, 0, sizeof(*t)); + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); - /* No fh->do_crop = 1; because btv->crop[1] may be - inconsistent with fh->width or fh->height and apps - do not expect a change here. */ + mutex_unlock(&btv->lock); + return 0; +} - crop->c = btv->crop[!!fh->do_crop].rect; +static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - return 0; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *crop = arg; - const struct v4l2_rect *b; - struct bttv_crop c; - __s32 b_left; - __s32 b_top; - __s32 b_right; - __s32 b_bottom; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + *p = v4l2_prio_max(&btv->prio); - retval = v4l2_prio_check(&btv->prio,&fh->prio); - if (0 != retval) - return retval; + return 0; +} - /* Make sure tvnorm, vbi_end and the current cropping - parameters remain consistent until we're done. Note - read() may change vbi_end in check_alloc_btres(). */ - mutex_lock(&btv->lock); +static int vidioc_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + return v4l2_prio_change(&btv->prio, &fh->prio, prio); +} + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + *cap = bttv_tvnorms[btv->tvnorm].cropcap; + + return 0; +} - retval = -EBUSY; +static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - if (locked_btres(fh->btv, VIDEO_RESOURCES)) - goto btv_unlock_and_return; + /* No fh->do_crop = 1; because btv->crop[1] may be + inconsistent with fh->width or fh->height and apps + do not expect a change here. */ - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; + crop->c = btv->crop[!!fh->do_crop].rect; - b_left = b->left; - b_right = b_left + b->width; - b_bottom = b->top + b->height; + return 0; +} + +static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct v4l2_rect *b; + int retval; + struct bttv_crop c; + __s32 b_left; + __s32 b_top; + __s32 b_right; + __s32 b_bottom; - b_top = max(b->top, btv->vbi_end); - if (b_top + 32 >= b_bottom) - goto btv_unlock_and_return; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - /* Min. scaled size 48 x 32. */ - c.rect.left = clamp(crop->c.left, b_left, b_right - 48); - c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); + retval = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != retval) + return retval; - c.rect.width = clamp(crop->c.width, - 48, b_right - c.rect.left); + /* Make sure tvnorm, vbi_end and the current cropping + parameters remain consistent until we're done. Note + read() may change vbi_end in check_alloc_btres(). */ + mutex_lock(&btv->lock); - c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); - /* Top and height must be a multiple of two. */ - c.rect.top = (c.rect.top + 1) & ~1; + retval = -EBUSY; - c.rect.height = clamp(crop->c.height, - 32, b_bottom - c.rect.top); - c.rect.height = (c.rect.height + 1) & ~1; + if (locked_btres(fh->btv, VIDEO_RESOURCES)) { + mutex_unlock(&btv->lock); + return retval; + } - bttv_crop_calc_limits(&c); + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - btv->crop[1] = c; + b_left = b->left; + b_right = b_left + b->width; + b_bottom = b->top + b->height; + b_top = max(b->top, btv->vbi_end); + if (b_top + 32 >= b_bottom) { mutex_unlock(&btv->lock); + return retval; + } - fh->do_crop = 1; + /* Min. scaled size 48 x 32. */ + c.rect.left = clamp(crop->c.left, b_left, b_right - 48); + c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); - mutex_lock(&fh->cap.lock); + c.rect.width = clamp(crop->c.width, + 48, b_right - c.rect.left); - if (fh->width < c.min_scaled_width) { - fh->width = c.min_scaled_width; - btv->init.width = c.min_scaled_width; - } else if (fh->width > c.max_scaled_width) { - fh->width = c.max_scaled_width; - btv->init.width = c.max_scaled_width; - } + c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); + /* Top and height must be a multiple of two. */ + c.rect.top = (c.rect.top + 1) & ~1; - if (fh->height < c.min_scaled_height) { - fh->height = c.min_scaled_height; - btv->init.height = c.min_scaled_height; - } else if (fh->height > c.max_scaled_height) { - fh->height = c.max_scaled_height; - btv->init.height = c.max_scaled_height; - } + c.rect.height = clamp(crop->c.height, + 32, b_bottom - c.rect.top); + c.rect.height = (c.rect.height + 1) & ~1; - mutex_unlock(&fh->cap.lock); + bttv_crop_calc_limits(&c); - return 0; + btv->crop[1] = c; + + mutex_unlock(&btv->lock); + + fh->do_crop = 1; + + mutex_lock(&fh->cap.lock); + + if (fh->width < c.min_scaled_width) { + fh->width = c.min_scaled_width; + btv->init.width = c.min_scaled_width; + } else if (fh->width > c.max_scaled_width) { + fh->width = c.max_scaled_width; + btv->init.width = c.max_scaled_width; } - case VIDIOC_ENUMSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - case VIDIOC_LOG_STATUS: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - return bttv_common_ioctls(btv,cmd,arg); - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - bttv_do_ioctl); + if (fh->height < c.min_scaled_height) { + fh->height = c.min_scaled_height; + btv->init.height = c.min_scaled_height; + } else if (fh->height > c.max_scaled_height) { + fh->height = c.max_scaled_height; + btv->init.height = c.max_scaled_height; } - return 0; - fh_unlock_and_return: mutex_unlock(&fh->cap.lock); - return retval; - btv_unlock_and_return: - mutex_unlock(&btv->lock); - return retval; + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + strcpy(a->name, "audio"); + return 0; } -static int bttv_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); + return 0; } static ssize_t bttv_read(struct file *file, char __user *data, @@ -3240,7 +3295,7 @@ static const struct file_operations bttv_fops = .owner = THIS_MODULE, .open = bttv_open, .release = bttv_release, - .ioctl = bttv_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, .read = bttv_read, @@ -3255,6 +3310,57 @@ static struct video_device bttv_video_template = VID_TYPE_CLIPPING|VID_TYPE_SCALES, .fops = &bttv_fops, .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_enum_fmt_overlay = vidioc_enum_fmt_overlay, + .vidioc_g_fmt_overlay = vidioc_g_fmt_overlay, + .vidioc_try_fmt_overlay = vidioc_try_fmt_overlay, + .vidioc_s_fmt_overlay = vidioc_s_fmt_overlay, + .vidioc_enum_fmt_vbi = vidioc_enum_fmt_vbi, + .vidioc_g_fmt_vbi = vidioc_g_fmt_vbi, + .vidioc_try_fmt_vbi = vidioc_try_fmt_vbi, + .vidioc_s_fmt_vbi = vidioc_s_fmt_vbi, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_crop = vidioc_g_crop, + .vidioc_g_crop = vidioc_g_crop, + .vidioc_s_crop = vidioc_s_crop, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + .vidioc_overlay = vidioc_overlay, + .vidioc_g_priority = vidioc_g_priority, + .vidioc_s_priority = vidioc_s_priority, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_log_status = vidioc_log_status, + .vidioc_querystd = vidioc_querystd, + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, + .tvnorms = BTTV_NORMS, + .current_norm = V4L2_STD_PAL, }; static struct video_device bttv_vbi_template = @@ -3301,7 +3407,7 @@ static int radio_open(struct inode *inode, struct file *file) static int radio_release(struct inode *inode, struct file *file) { - struct bttv *btv = file->private_data; + struct bttv *btv = file->private_data; struct rds_command cmd; btv->radio_user--; @@ -3311,67 +3417,116 @@ static int radio_release(struct inode *inode, struct file *file) return 0; } -static int radio_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { - struct bttv *btv = file->private_data; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "bttv"); - strlcpy(cap->card, btv->radio_dev->name,sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; + strcpy(cap->driver, "bttv"); + strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - memset(t,0,sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; + return 0; +} - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); +static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - if (btv->audio_mode_gpio) { - btv->audio_mode_gpio (btv,t,0); - } + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; - mutex_unlock(&btv->lock); + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); + + mutex_unlock(&btv->lock); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (0 != t->index) + return -EINVAL; + + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + return 0; +} + +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + return 0; +} + +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctl; - return 0; - } - case VIDIOC_S_TUNER: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - case VIDIOC_LOG_STATUS: - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - return bttv_common_ioctls(btv,cmd,arg); - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - radio_do_ioctl); - } return 0; } -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) { - return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); + *i = 0; + return 0; } static ssize_t radio_read(struct file *file, char __user *data, @@ -3407,7 +3562,7 @@ static const struct file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = radio_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, .poll = radio_poll, }; @@ -3418,6 +3573,20 @@ static struct video_device radio_template = .type = VID_TYPE_TUNER, .fops = &radio_fops, .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index b924f05e3b7..da2708176aa 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = { /* ----------------------------------------------------------------------- */ -static int -try_fmt (struct v4l2_vbi_format * f, - const struct bttv_tvnorm * tvnorm, - __s32 crop_start) +static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, + __s32 crop_start) { __s32 min_start, max_start, max_end, f2_offset; unsigned int i; @@ -305,10 +303,9 @@ try_fmt (struct v4l2_vbi_format * f, return 0; } -int -bttv_vbi_try_fmt (struct bttv_fh * fh, - struct v4l2_vbi_format * f) +int vidioc_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { + struct bttv_fh *fh = f; struct bttv *btv = fh->btv; const struct bttv_tvnorm *tvnorm; __s32 crop_start; @@ -320,13 +317,13 @@ bttv_vbi_try_fmt (struct bttv_fh * fh, mutex_unlock(&btv->lock); - return try_fmt(f, tvnorm, crop_start); + return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); } -int -bttv_vbi_set_fmt (struct bttv_fh * fh, - struct v4l2_vbi_format * f) + +int vidioc_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { + struct bttv_fh *fh = f; struct bttv *btv = fh->btv; const struct bttv_tvnorm *tvnorm; __s32 start1, end; @@ -340,11 +337,12 @@ bttv_vbi_set_fmt (struct bttv_fh * fh, tvnorm = &bttv_tvnorms[btv->tvnorm]; - rc = try_fmt(f, tvnorm, btv->crop_start); + rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); if (0 != rc) goto fail; - start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0]; + start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + + tvnorm->vbistart[0]; /* First possible line of video capturing. Should be max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 @@ -352,11 +350,11 @@ bttv_vbi_set_fmt (struct bttv_fh * fh, pretend the VBI and video capture window may overlap, so end = start + 1, the lowest possible value, times two because vbi_fmt.end counts field lines times two. */ - end = max(f->start[0], start1) * 2 + 2; + end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; mutex_lock(&fh->vbi.lock); - fh->vbi_fmt.fmt = *f; + fh->vbi_fmt.fmt = frt->fmt.vbi; fh->vbi_fmt.tvnorm = tvnorm; fh->vbi_fmt.end = end; @@ -370,13 +368,13 @@ bttv_vbi_set_fmt (struct bttv_fh * fh, return rc; } -void -bttv_vbi_get_fmt (struct bttv_fh * fh, - struct v4l2_vbi_format * f) + +int vidioc_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { + struct bttv_fh *fh = f; const struct bttv_tvnorm *tvnorm; - *f = fh->vbi_fmt.fmt; + frt->fmt.vbi = fh->vbi_fmt.fmt; tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; @@ -391,28 +389,28 @@ bttv_vbi_get_fmt (struct bttv_fh * fh, max_end = (tvnorm->cropcap.bounds.top + tvnorm->cropcap.bounds.height) >> 1; - f->sampling_rate = tvnorm->Fsc; + frt->fmt.vbi.sampling_rate = tvnorm->Fsc; for (i = 0; i < 2; ++i) { __s32 new_start; - new_start = f->start[i] + new_start = frt->fmt.vbi.start[i] + tvnorm->vbistart[i] - fh->vbi_fmt.tvnorm->vbistart[i]; - f->start[i] = min(new_start, max_end - 1); - f->count[i] = min((__s32) f->count[i], - max_end - f->start[i]); + frt->fmt.vbi.start[i] = min(new_start, max_end - 1); + frt->fmt.vbi.count[i] = + min((__s32) frt->fmt.vbi.count[i], + max_end - frt->fmt.vbi.start[i]); max_end += tvnorm->vbistart[1] - tvnorm->vbistart[0]; } } + return 0; } -void -bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f, - int norm) +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm) { const struct bttv_tvnorm *tvnorm; unsigned int real_samples_per_line; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 4a02f0a8a46..260303065c1 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -84,6 +84,11 @@ #define clamp(x, low, high) min (max (low, x), high) +#define BTTV_NORMS (\ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60) /* ---------------------------------------------------------- */ struct bttv_tvnorm { @@ -252,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); -void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); -int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); +int vidioc_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int vidioc_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int vidioc_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); extern struct videobuf_queue_ops bttv_vbi_qops; -- cgit v1.2.3 From e5ae3db461f2de1f4fb455bc73c059c0b97b1230 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Dec 2007 22:22:59 -0300 Subject: V4L/DVB (6912): Replace vidioc_ to bttv_ Since there are a few vidioc_ functions that were exported, rename those functions to bttv_ in order to avoid poluting namespace. The other functions were also renamed, to standardize inside the driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 186 ++++++++++++++++---------------- drivers/media/video/bt8xx/bttv-vbi.c | 6 +- drivers/media/video/bt8xx/bttvp.h | 6 +- 3 files changed, 99 insertions(+), 99 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index d6a305ddc53..30cc2d3ba52 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1680,7 +1680,7 @@ static struct videobuf_queue_ops bttv_video_qops = { .buf_release = buffer_release, }; -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1704,7 +1704,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_querystd(struct file *file, void *f, v4l2_std_id *id) +static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1716,7 +1716,7 @@ static int vidioc_querystd(struct file *file, void *f, v4l2_std_id *id) return 0; } -static int vidioc_enum_input(struct file *file, void *priv, +static int bttv_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct bttv_fh *fh = priv; @@ -1758,7 +1758,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return 0; } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +static int bttv_g_input(struct file *file, void *priv, unsigned int *i) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1767,7 +1767,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int bttv_s_input(struct file *file, void *priv, unsigned int i) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1787,7 +1787,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, +static int bttv_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct bttv_fh *fh = priv; @@ -1815,7 +1815,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, return 0; } -static int vidioc_g_frequency(struct file *file, void *priv, +static int bttv_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct bttv_fh *fh = priv; @@ -1832,7 +1832,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, +static int bttv_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct bttv_fh *fh = priv; @@ -1856,7 +1856,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, return 0; } -static int vidioc_log_status(struct file *file, void *f) +static int bttv_log_status(struct file *file, void *f) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1869,7 +1869,7 @@ static int vidioc_log_status(struct file *file, void *f) return 0; } -static int vidioc_g_ctrl(struct file *file, void *priv, +static int bttv_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) { struct bttv_fh *fh = priv; @@ -1936,7 +1936,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, return 0; } -static int vidioc_s_ctrl(struct file *file, void *f, +static int bttv_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { int err; @@ -2034,7 +2034,7 @@ static int vidioc_s_ctrl(struct file *file, void *f, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *f, +static int bttv_g_register(struct file *file, void *f, struct v4l2_register *reg) { struct bttv_fh *fh = f; @@ -2053,7 +2053,7 @@ static int vidioc_g_register(struct file *file, void *f, return 0; } -static int vidioc_s_register(struct file *file, void *f, +static int bttv_s_register(struct file *file, void *f, struct v4l2_register *reg) { struct bttv_fh *fh = f; @@ -2447,7 +2447,7 @@ pix_format_set_size (struct v4l2_pix_format * f, } } -static int vidioc_g_fmt_cap(struct file *file, void *priv, +static int bttv_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2460,7 +2460,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_overlay(struct file *file, void *priv, +static int bttv_g_fmt_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2471,7 +2471,7 @@ static int vidioc_g_fmt_overlay(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_cap(struct file *file, void *priv, +static int bttv_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { const struct bttv_format *fmt; @@ -2522,7 +2522,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_overlay(struct file *file, void *priv, +static int bttv_try_fmt_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2532,7 +2532,7 @@ static int vidioc_try_fmt_overlay(struct file *file, void *priv, /* adjust_crop */ 0); } -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int bttv_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { int retval; @@ -2544,7 +2544,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, if (0 != retval) return retval; - retval = vidioc_try_fmt_cap(file, priv, f); + retval = bttv_try_fmt_cap(file, priv, f); if (0 != retval) return retval; @@ -2565,7 +2565,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_overlay(struct file *file, void *priv, +static int bttv_s_fmt_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct bttv_fh *fh = priv; @@ -2605,7 +2605,7 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) } #endif -static int vidioc_querycap(struct file *file, void *priv, +static int bttv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct bttv_fh *fh = priv; @@ -2633,7 +2633,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, +static int bttv_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= FORMATS) @@ -2645,7 +2645,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_overlay(struct file *file, void *priv, +static int bttv_enum_fmt_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (no_overlay > 0) { @@ -2664,7 +2664,7 @@ static int vidioc_enum_fmt_overlay(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_vbi(struct file *file, void *priv, +static int bttv_enum_fmt_vbi(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (0 != f->index) @@ -2676,7 +2676,7 @@ static int vidioc_enum_fmt_vbi(struct file *file, void *priv, return 0; } -static int vidioc_g_fbuf(struct file *file, void *f, +static int bttv_g_fbuf(struct file *file, void *f, struct v4l2_framebuffer *fb) { struct bttv_fh *fh = f; @@ -2689,7 +2689,7 @@ static int vidioc_g_fbuf(struct file *file, void *f, return 0; } -static int vidioc_overlay(struct file *file, void *f, unsigned int on) +static int bttv_overlay(struct file *file, void *f, unsigned int on) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -2724,7 +2724,7 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on) return retval; } -static int vidioc_s_fbuf(struct file *file, void *f, +static int bttv_s_fbuf(struct file *file, void *f, struct v4l2_framebuffer *fb) { struct bttv_fh *fh = f; @@ -2795,21 +2795,21 @@ static int vidioc_s_fbuf(struct file *file, void *f, return retval; } -static int vidioc_reqbufs(struct file *file, void *priv, +static int bttv_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { struct bttv_fh *fh = priv; return videobuf_reqbufs(bttv_queue(fh), p); } -static int vidioc_querybuf(struct file *file, void *priv, +static int bttv_querybuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct bttv_fh *fh = priv; return videobuf_querybuf(bttv_queue(fh), b); } -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -2821,14 +2821,14 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) return videobuf_qbuf(bttv_queue(fh), b); } -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct bttv_fh *fh = priv; return videobuf_dqbuf(bttv_queue(fh), b, file->f_flags & O_NONBLOCK); } -static int vidioc_streamon(struct file *file, void *priv, +static int bttv_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct bttv_fh *fh = priv; @@ -2841,7 +2841,7 @@ static int vidioc_streamon(struct file *file, void *priv, } -static int vidioc_streamoff(struct file *file, void *priv, +static int bttv_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { struct bttv_fh *fh = priv; @@ -2857,7 +2857,7 @@ static int vidioc_streamoff(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, +static int bttv_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { struct bttv_fh *fh = priv; @@ -2880,7 +2880,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, return 0; } -static int vidioc_g_parm(struct file *file, void *f, +static int bttv_g_parm(struct file *file, void *f, struct v4l2_streamparm *parm) { struct bttv_fh *fh = f; @@ -2895,7 +2895,7 @@ static int vidioc_g_parm(struct file *file, void *f, return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, +static int bttv_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct bttv_fh *fh = priv; @@ -2923,7 +2923,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, return 0; } -static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -2933,7 +2933,7 @@ static int vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) return 0; } -static int vidioc_s_priority(struct file *file, void *f, +static int bttv_s_priority(struct file *file, void *f, enum v4l2_priority prio) { struct bttv_fh *fh = f; @@ -2942,7 +2942,7 @@ static int vidioc_s_priority(struct file *file, void *f, return v4l2_prio_change(&btv->prio, &fh->prio, prio); } -static int vidioc_cropcap(struct file *file, void *priv, +static int bttv_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap) { struct bttv_fh *fh = priv; @@ -2957,7 +2957,7 @@ static int vidioc_cropcap(struct file *file, void *priv, return 0; } -static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -2975,7 +2975,7 @@ static int vidioc_g_crop(struct file *file, void *f, struct v4l2_crop *crop) return 0; } -static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -3065,13 +3065,13 @@ static int vidioc_s_crop(struct file *file, void *f, struct v4l2_crop *crop) return 0; } -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { strcpy(a->name, "audio"); return 0; } -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { return 0; } @@ -3310,55 +3310,55 @@ static struct video_device bttv_video_template = VID_TYPE_CLIPPING|VID_TYPE_SCALES, .fops = &bttv_fops, .minor = -1, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, - .vidioc_enum_fmt_overlay = vidioc_enum_fmt_overlay, - .vidioc_g_fmt_overlay = vidioc_g_fmt_overlay, - .vidioc_try_fmt_overlay = vidioc_try_fmt_overlay, - .vidioc_s_fmt_overlay = vidioc_s_fmt_overlay, - .vidioc_enum_fmt_vbi = vidioc_enum_fmt_vbi, - .vidioc_g_fmt_vbi = vidioc_g_fmt_vbi, - .vidioc_try_fmt_vbi = vidioc_try_fmt_vbi, - .vidioc_s_fmt_vbi = vidioc_s_fmt_vbi, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_querycap = bttv_querycap, + .vidioc_enum_fmt_cap = bttv_enum_fmt_cap, + .vidioc_g_fmt_cap = bttv_g_fmt_cap, + .vidioc_try_fmt_cap = bttv_try_fmt_cap, + .vidioc_s_fmt_cap = bttv_s_fmt_cap, + .vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay, + .vidioc_g_fmt_overlay = bttv_g_fmt_overlay, + .vidioc_try_fmt_overlay = bttv_try_fmt_overlay, + .vidioc_s_fmt_overlay = bttv_s_fmt_overlay, + .vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi, + .vidioc_g_fmt_vbi = bttv_g_fmt_vbi, + .vidioc_try_fmt_vbi = bttv_try_fmt_vbi, + .vidioc_s_fmt_vbi = bttv_s_fmt_vbi, + .vidioc_g_audio = bttv_g_audio, + .vidioc_s_audio = bttv_s_audio, + .vidioc_cropcap = bttv_cropcap, + .vidioc_reqbufs = bttv_reqbufs, + .vidioc_querybuf = bttv_querybuf, + .vidioc_qbuf = bttv_qbuf, + .vidioc_dqbuf = bttv_dqbuf, + .vidioc_s_std = bttv_s_std, + .vidioc_enum_input = bttv_enum_input, + .vidioc_g_input = bttv_g_input, + .vidioc_s_input = bttv_s_input, + .vidioc_queryctrl = bttv_queryctrl, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_streamon = bttv_streamon, + .vidioc_streamoff = bttv_streamoff, + .vidioc_g_tuner = bttv_g_tuner, + .vidioc_s_tuner = bttv_s_tuner, #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif - .vidioc_g_crop = vidioc_g_crop, - .vidioc_g_crop = vidioc_g_crop, - .vidioc_s_crop = vidioc_s_crop, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_fbuf = vidioc_s_fbuf, - .vidioc_overlay = vidioc_overlay, - .vidioc_g_priority = vidioc_g_priority, - .vidioc_s_priority = vidioc_s_priority, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_log_status = vidioc_log_status, - .vidioc_querystd = vidioc_querystd, - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, + .vidioc_g_crop = bttv_g_crop, + .vidioc_g_crop = bttv_g_crop, + .vidioc_s_crop = bttv_s_crop, + .vidioc_g_fbuf = bttv_g_fbuf, + .vidioc_s_fbuf = bttv_s_fbuf, + .vidioc_overlay = bttv_overlay, + .vidioc_g_priority = bttv_g_priority, + .vidioc_s_priority = bttv_s_priority, + .vidioc_g_parm = bttv_g_parm, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, + .vidioc_log_status = bttv_log_status, + .vidioc_querystd = bttv_querystd, + .vidioc_g_register = bttv_g_register, + .vidioc_s_register = bttv_s_register, .tvnorms = BTTV_NORMS, .current_norm = V4L2_STD_PAL, }; @@ -3583,10 +3583,10 @@ static struct video_device radio_template = .vidioc_s_std = radio_s_std, .vidioc_queryctrl = radio_queryctrl, .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index da2708176aa..1f0cc79e2a3 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -303,7 +303,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, return 0; } -int vidioc_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -321,7 +321,7 @@ int vidioc_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) } -int vidioc_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -369,7 +369,7 @@ int vidioc_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) } -int vidioc_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { struct bttv_fh *fh = f; const struct bttv_tvnorm *tvnorm; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 260303065c1..1305d315cfc 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -257,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -int vidioc_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); extern struct videobuf_queue_ops bttv_vbi_qops; -- cgit v1.2.3 From 04a94d3ca25030d7c1fa27f3db3b90eb5a7985b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Dec 2007 22:23:34 -0300 Subject: V4L/DVB (6913): Preserve the previous order to make easier to check the conversion Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 355 ++++++++++++++++---------------- 1 file changed, 178 insertions(+), 177 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 30cc2d3ba52..c8f95815167 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1442,6 +1442,170 @@ static void bttv_reinit_bt848(struct bttv *btv) set_input(btv, btv->input, btv->tvnorm); } +static int bttv_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = btv->bright; + break; + case V4L2_CID_HUE: + c->value = btv->hue; + break; + case V4L2_CID_CONTRAST: + c->value = btv->contrast; + break; + case V4L2_CID_SATURATION: + c->value = btv->saturation; + break; + + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + c->value = btv->opt_chroma_agc; + break; + case V4L2_CID_PRIVATE_COMBFILTER: + c->value = btv->opt_combfilter; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + c->value = btv->opt_lumafilter; + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + c->value = btv->opt_automute; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + c->value = btv->opt_adc_crush; + break; + case V4L2_CID_PRIVATE_VCR_HACK: + c->value = btv->opt_vcr_hack; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + c->value = btv->opt_whitecrush_upper; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + c->value = btv->opt_whitecrush_lower; + break; + case V4L2_CID_PRIVATE_UV_RATIO: + c->value = btv->opt_uv_ratio; + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + c->value = btv->opt_full_luma_range; + break; + case V4L2_CID_PRIVATE_CORING: + c->value = btv->opt_coring; + break; + default: + return -EINVAL; + } + return 0; +} + +static int bttv_s_ctrl(struct file *file, void *f, + struct v4l2_control *c) +{ + int err; + int val; + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + bt848_bright(btv, c->value); + break; + case V4L2_CID_HUE: + bt848_hue(btv, c->value); + break; + case V4L2_CID_CONTRAST: + bt848_contrast(btv, c->value); + break; + case V4L2_CID_SATURATION: + bt848_sat(btv, c->value); + break; + case V4L2_CID_AUDIO_MUTE: + audio_mute(btv, c->value); + /* fall through */ + case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) + btv->volume_gpio(btv, c->value); + + bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); + break; + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + btv->opt_chroma_agc = c->value; + val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); + break; + case V4L2_CID_PRIVATE_COMBFILTER: + btv->opt_combfilter = c->value; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + btv->opt_lumafilter = c->value; + if (btv->opt_lumafilter) { + btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); + btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); + } else { + btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + btv->opt_automute = c->value; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + btv->opt_adc_crush = c->value; + btwrite(BT848_ADC_RESERVED | + (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); + break; + case V4L2_CID_PRIVATE_VCR_HACK: + btv->opt_vcr_hack = c->value; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + btv->opt_whitecrush_upper = c->value; + btwrite(c->value, BT848_WC_UP); + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + btv->opt_whitecrush_lower = c->value; + btwrite(c->value, BT848_WC_DOWN); + break; + case V4L2_CID_PRIVATE_UV_RATIO: + btv->opt_uv_ratio = c->value; + bt848_sat(btv, btv->saturation); + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + btv->opt_full_luma_range = c->value; + btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + break; + case V4L2_CID_PRIVATE_CORING: + btv->opt_coring = c->value; + btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + break; + default: + return -EINVAL; + } + return 0; +} + /* ----------------------------------------------------------------------- */ void bttv_gpio_tracking(struct bttv *btv, char *comment) @@ -1869,170 +2033,6 @@ static int bttv_log_status(struct file *file, void *f) return 0; } -static int bttv_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = btv->bright; - break; - case V4L2_CID_HUE: - c->value = btv->hue; - break; - case V4L2_CID_CONTRAST: - c->value = btv->contrast; - break; - case V4L2_CID_SATURATION: - c->value = btv->saturation; - break; - - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - c->value = btv->opt_chroma_agc; - break; - case V4L2_CID_PRIVATE_COMBFILTER: - c->value = btv->opt_combfilter; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - c->value = btv->opt_lumafilter; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = btv->opt_automute; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - c->value = btv->opt_adc_crush; - break; - case V4L2_CID_PRIVATE_VCR_HACK: - c->value = btv->opt_vcr_hack; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - c->value = btv->opt_whitecrush_upper; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - c->value = btv->opt_whitecrush_lower; - break; - case V4L2_CID_PRIVATE_UV_RATIO: - c->value = btv->opt_uv_ratio; - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - c->value = btv->opt_full_luma_range; - break; - case V4L2_CID_PRIVATE_CORING: - c->value = btv->opt_coring; - break; - default: - return -EINVAL; - } - return 0; -} - -static int bttv_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) -{ - int err; - int val; - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - bt848_bright(btv, c->value); - break; - case V4L2_CID_HUE: - bt848_hue(btv, c->value); - break; - case V4L2_CID_CONTRAST: - bt848_contrast(btv, c->value); - break; - case V4L2_CID_SATURATION: - bt848_sat(btv, c->value); - break; - case V4L2_CID_AUDIO_MUTE: - audio_mute(btv, c->value); - /* fall through */ - case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) - btv->volume_gpio(btv, c->value); - - bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); - break; - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - break; - case V4L2_CID_PRIVATE_COMBFILTER: - btv->opt_combfilter = c->value; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - btv->opt_lumafilter = c->value; - if (btv->opt_lumafilter) { - btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); - btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); - } else { - btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - btv->opt_automute = c->value; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - btv->opt_adc_crush = c->value; - btwrite(BT848_ADC_RESERVED | - (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - break; - case V4L2_CID_PRIVATE_VCR_HACK: - btv->opt_vcr_hack = c->value; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - btv->opt_whitecrush_upper = c->value; - btwrite(c->value, BT848_WC_UP); - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - btv->opt_whitecrush_lower = c->value; - btwrite(c->value, BT848_WC_DOWN); - break; - case V4L2_CID_PRIVATE_UV_RATIO: - btv->opt_uv_ratio = c->value; - bt848_sat(btv, btv->saturation); - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - btv->opt_full_luma_range = c->value; - btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); - break; - case V4L2_CID_PRIVATE_CORING: - btv->opt_coring = c->value; - btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); - break; - default: - return -EINVAL; - } - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int bttv_g_register(struct file *file, void *f, struct v4l2_register *reg) @@ -2633,13 +2633,26 @@ static int bttv_querycap(struct file *file, void *priv, return 0; } +static int bttv_enum_fmt_vbi(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (0 != f->index) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); + + return 0; +} + static int bttv_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= FORMATS) return -EINVAL; - strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; @@ -2664,18 +2677,6 @@ static int bttv_enum_fmt_overlay(struct file *file, void *priv, return 0; } -static int bttv_enum_fmt_vbi(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (0 != f->index) - return -EINVAL; - - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description, "vbi data"); - - return 0; -} - static int bttv_g_fbuf(struct file *file, void *f, struct v4l2_framebuffer *fb) { -- cgit v1.2.3 From 9134be0376e7527afa4f2574253ff02ca80d5b47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 27 Dec 2007 22:28:31 -0300 Subject: V4L/DVB (6914): Fix a few issues at the bttv conversion bttv driver is working as previously. An additional gain of about 1,5Kb were obtained with the driver conversion to vidioc_ioctl2: text data bss dec hex filename 89208 40244 57556 187008 2da80 old/bttv.ko 88960 38740 57556 185256 2d3a8 new/bttv.ko (measured on a x86_64) Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 120 ++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index c8f95815167..ddca21d9c94 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -785,15 +785,15 @@ static const struct v4l2_queryctrl bttv_ctls[] = { }; -static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); static const struct v4l2_queryctrl *ctrl_by_id(int id) { int i; - for (i = 0; i < BTTV_CTLS; i++) + for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) if (bttv_ctls[i].id == id) return bttv_ctls+i; + return NULL; } @@ -2479,6 +2479,7 @@ static int bttv_try_fmt_cap(struct file *file, void *priv, struct bttv *btv = fh->btv; enum v4l2_field field; __s32 width, height; + int rc; fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) @@ -2515,6 +2516,14 @@ static int bttv_try_fmt_cap(struct file *file, void *priv, width = f->fmt.pix.width; height = f->fmt.pix.height; + rc = limit_scaled_size(fh, &width, &height, field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 0); + if (0 != rc) + return rc; + /* update data for the application */ f->fmt.pix.field = field; pix_format_set_size(&f->fmt.pix, fmt, width, height); @@ -2539,6 +2548,8 @@ static int bttv_s_fmt_cap(struct file *file, void *priv, const struct bttv_format *fmt; struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; + __s32 width, height; + enum v4l2_field field; retval = bttv_switch_type(fh, f->type); if (0 != retval) @@ -2548,6 +2559,20 @@ static int bttv_s_fmt_cap(struct file *file, void *priv, if (0 != retval) return retval; + width = f->fmt.pix.width; + height = f->fmt.pix.height; + field = f->fmt.pix.field; + + retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 1); + if (0 != retval) + return retval; + + f->fmt.pix.field = field; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ @@ -2571,8 +2596,10 @@ static int bttv_s_fmt_overlay(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - if (no_overlay > 0) + if (no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; + } return setup_window(fh, btv, &f->fmt.win, 1); } @@ -2645,15 +2672,32 @@ static int bttv_enum_fmt_vbi(struct file *file, void *priv, return 0; } +static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) +{ + int index = -1, i; + + for (i = 0; i < FORMATS; i++) { + if (formats[i].fourcc != -1) + index++; + if ((unsigned int)index == f->index) + break; + } + if (FORMATS == i) + return -EINVAL; + + f->pixelformat = formats[i].fourcc; + strlcpy(f->description, formats[i].name, sizeof(f->description)); + + return i; +} + static int bttv_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index >= FORMATS) - return -EINVAL; + int rc = bttv_enum_fmt_cap_ovr(f); - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; + if (rc < 0) + return rc; return 0; } @@ -2661,18 +2705,20 @@ static int bttv_enum_fmt_cap(struct file *file, void *priv, static int bttv_enum_fmt_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { + int rc; + if (no_overlay > 0) { printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } - if (f->index >= FORMATS) - return -EINVAL; + rc = bttv_enum_fmt_cap_ovr(f); - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); + if (rc < 0) + return rc; - f->pixelformat = formats[f->index].fourcc; + if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; return 0; } @@ -2871,12 +2917,13 @@ static int bttv_queryctrl(struct file *file, void *priv, c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; - ctrl = ctrl_by_id(c->id); - *c = (NULL != ctrl) ? *ctrl : no_ctl; + if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) + *c = no_ctl; + else { + ctrl = ctrl_by_id(c->id); - if (!btv->volume_gpio && - (ctrl->id == V4L2_CID_AUDIO_VOLUME)) - * c = no_ctl; + *c = (NULL != ctrl) ? *ctrl : no_ctl; + } return 0; } @@ -3306,9 +3353,6 @@ static const struct file_operations bttv_fops = static struct video_device bttv_video_template = { - .name = "UNSET", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| - VID_TYPE_CLIPPING|VID_TYPE_SCALES, .fops = &bttv_fops, .minor = -1, .vidioc_querycap = bttv_querycap, @@ -3364,14 +3408,6 @@ static struct video_device bttv_video_template = .current_norm = V4L2_STD_PAL, }; -static struct video_device bttv_vbi_template = -{ - .name = "bt848/878 vbi", - .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, - .fops = &bttv_fops, - .minor = -1, -}; - /* ----------------------------------------------------------------------- */ /* radio interface */ @@ -3570,8 +3606,6 @@ static const struct file_operations radio_fops = static struct video_device radio_template = { - .name = "bt848/878 radio", - .type = VID_TYPE_TUNER, .fops = &radio_fops, .minor = -1, .vidioc_querycap = radio_querycap, @@ -4109,8 +4143,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) /* initialitation */ static struct video_device *vdev_init(struct bttv *btv, - struct video_device *template, - char *type) + const struct video_device *template, + const char *type_name, + const int type) { struct video_device *vfd; @@ -4121,9 +4156,10 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->minor = -1; vfd->dev = &btv->c.pci->dev; vfd->release = video_device_release; + vfd->type = type; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", - type, bttv_tvcards[btv->c.type].name); + type_name, bttv_tvcards[btv->c.type].name); return vfd; } @@ -4155,6 +4191,11 @@ static void bttv_unregister_video(struct bttv *btv) /* register video4linux devices */ static int __devinit bttv_register_video(struct bttv *btv) { + int video_type = VID_TYPE_CAPTURE | + VID_TYPE_TUNER | + VID_TYPE_CLIPPING| + VID_TYPE_SCALES; + if (no_overlay <= 0) { bttv_video_template.type |= VID_TYPE_OVERLAY; } else { @@ -4162,7 +4203,9 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); + btv->video_dev = vdev_init(btv, &bttv_video_template, + "video", video_type); + if (NULL == btv->video_dev) goto err; if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) @@ -4177,7 +4220,9 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi"); + btv->vbi_dev = vdev_init(btv, &bttv_video_template, + "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT); + if (NULL == btv->vbi_dev) goto err; if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) @@ -4188,7 +4233,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (!btv->has_radio) return 0; /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, "radio"); + btv->radio_dev = vdev_init(btv, &radio_template, + "radio", VID_TYPE_TUNER); if (NULL == btv->radio_dev) goto err; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) -- cgit v1.2.3 From d998cc6a6d8e7da19ecadded55e373a84b1b4463 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 22 Dec 2007 18:28:22 -0300 Subject: V4L/DVB (6915): ivtv: drop an incorrect comment Signed-off-by: Jean Delvare Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index efd4a1324dc..fa5ab1eb180 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -580,7 +580,7 @@ static int ivtv_getsda_old(void *data) /* template for i2c-bit-algo */ static struct i2c_adapter ivtv_i2c_adap_template = { .name = "ivtv i2c driver", - .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ + .id = I2C_HW_B_CX2341X, .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ .client_register = attach_inform, -- cgit v1.2.3 From 3e509c76047781525c38fde1e0fa244470c7663c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 24 Dec 2007 10:41:47 -0300 Subject: V4L/DVB (6917): ivtv: small textual update Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 0cb832a2135..d42f120354e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -640,7 +640,7 @@ done: IVTV_ERR("Defaulting to %s card\n", itv->card->name); IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n"); + IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n"); } itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; -- cgit v1.2.3 From de7234bb05a8498c5092385d3f1dd9e73cd332d0 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 26 Dec 2007 13:04:08 -0300 Subject: V4L/DVB (6919): Kconfig: VIDEO_CX23885 must select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE Everybody forgets to add the Kconfig stuff after they add new card support :-/ Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 3393dd6153e..1fd326fe411 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -15,6 +15,7 @@ config VIDEO_CX23885 select TUNER_XC2028 if !DVB_FE_CUSTOMIZE select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE select DVB_TDA18271 if !DVB_FE_CUSTOMIZE + select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. -- cgit v1.2.3 From 67d52e29032dd2f21d4080331f47a21205f337f6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 16:05:39 -0300 Subject: V4L/DVB (6920): tuner: fix backwards logic in check for set_config tuner-core was checking if analog_ops->set_config is set. If set, it would complain that it isn't. Fix this backwards logic to the proper behavior. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f792871582f..67b9ed1ac71 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -855,12 +855,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; if (analog_ops->set_config) { - tuner_warn("Tuner frontend module has no way to " - "set config\n"); + analog_ops->set_config(&t->fe, cfg->priv); break; } - analog_ops->set_config(&t->fe, cfg->priv); + tuner_dbg("Tuner frontend module has no way to set config\n"); break; } /* --- v4l ioctls --- */ -- cgit v1.2.3 From 8574ac690eab730a3ff735177af1d52e45e36c8b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 15:49:33 -0300 Subject: V4L/DVB (6921): include/media/v4l2-i2c-drv.h must #include Fix the following compiler error: v4l2-i2c-drv.h:72: error: implicit declaration of function 'v4l2_i2c_attach' Also, prevent multiple inclusions of v4l2-i2c-drv.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-i2c-drv.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h index d758b765e0f..9e4bab27691 100644 --- a/include/media/v4l2-i2c-drv.h +++ b/include/media/v4l2-i2c-drv.h @@ -21,6 +21,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef __V4L2_I2C_DRV_H__ +#define __V4L2_I2C_DRV_H__ + +#include + struct v4l2_i2c_driver_data { const char * const name; int driverid; @@ -59,3 +64,5 @@ static void __exit v4l2_i2c_drv_cleanup(void) module_init(v4l2_i2c_drv_init); module_exit(v4l2_i2c_drv_cleanup); + +#endif /* __V4L2_I2C_DRV_H__ */ -- cgit v1.2.3 From 926bf3ca937461123b98ff2ba8c3409f5b4c05b5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 14:14:03 -0300 Subject: V4L/DVB (6923): tda18271: remove extraneous debug We don't need to do a dbg_info during tda18271_attach anymore, since the tda18271_get_id function will call dbg_info with the same information and more. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 19c9be92de5..da22b24190c 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -783,7 +783,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, { struct tda18271_priv *priv = NULL; - dbg_info("@ %d-%04x\n", i2c_adapter_id(i2c), addr); priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); if (priv == NULL) return NULL; -- cgit v1.2.3 From 7686b574a1507ecf5fd7c419b43f26222668aa4d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 21:03:52 -0300 Subject: V4L/DVB (6924): tda18271: fix whitespace in tda18271_ir_measure Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-tables.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index cce0e0d8223..02b6d2cb957 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -258,11 +258,11 @@ static struct tda18271_map tda18271_rf_cal[] = { }; static struct tda18271_map tda18271_ir_measure[] = { - { .rfmax = 30000, .val = 4}, - { .rfmax = 200000, .val = 5}, - { .rfmax = 600000, .val = 6}, - { .rfmax = 865000, .val = 7}, - { .rfmax = 0, .val = 0}, /* end */ + { .rfmax = 30000, .val = 4 }, + { .rfmax = 200000, .val = 5 }, + { .rfmax = 600000, .val = 6 }, + { .rfmax = 865000, .val = 7 }, + { .rfmax = 0, .val = 0 }, /* end */ }; /*---------------------------------------------------------------------*/ -- cgit v1.2.3 From d37142102a2adaa3391a384ea6a780afb5804789 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 24 Dec 2007 14:38:41 -0300 Subject: V4L/DVB (6925): tda18271: move state structures to tda18271-priv.h Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 19 ------------------- drivers/media/dvb/frontends/tda18271-priv.h | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index da22b24190c..4526def2d42 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -20,8 +20,6 @@ #include #include - -#include "tda18271.h" #include "tda18271-priv.h" int tda18271_debug; @@ -30,23 +28,6 @@ MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); /*---------------------------------------------------------------------*/ -enum tda18271_mode { - TDA18271_ANALOG, - TDA18271_DIGITAL, -}; - -struct tda18271_priv { - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - unsigned char tda18271_regs[TDA18271_NUM_REGS]; - - enum tda18271_mode mode; - enum tda18271_i2c_gate gate; - - u32 frequency; - u32 bandwidth; -}; - static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct tda18271_priv *priv = fe->tuner_priv; diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index e1fa9a46793..7b9aa9ad53f 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -23,6 +23,7 @@ #include #include +#include "tda18271.h" #define R_ID 0x00 /* ID byte */ #define R_TM 0x01 /* Thermo byte */ @@ -66,6 +67,27 @@ #define TDA18271_NUM_REGS 39 +/*---------------------------------------------------------------------*/ + +enum tda18271_mode { + TDA18271_ANALOG, + TDA18271_DIGITAL, +}; + +struct tda18271_priv { + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + + enum tda18271_mode mode; + enum tda18271_i2c_gate gate; + + u32 frequency; + u32 bandwidth; +}; + +/*---------------------------------------------------------------------*/ + extern int tda18271_debug; #define dprintk(level, fmt, arg...) do {\ -- cgit v1.2.3 From 2f27dfc98cc0a183be9e3c2fc0da0450b85e5fde Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 25 Dec 2007 00:39:37 -0300 Subject: V4L/DVB (6926): tda18271: consolidate table lookup functions Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 28 +++--- drivers/media/dvb/frontends/tda18271-priv.h | 26 ++++-- drivers/media/dvb/frontends/tda18271-tables.c | 126 +++++++++++++++----------- 3 files changed, 106 insertions(+), 74 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 4526def2d42..72e256ebeb0 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -360,7 +360,9 @@ static int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) u8 d, pd; u32 div; - tda18271_lookup_main_pll(&freq, &pd, &d); + int ret = tda18271_lookup_pll_map(MAIN_PLL, &freq, &pd, &d); + if (ret < 0) + goto fail; regs[R_MPD] = (0x77 & pd); @@ -378,8 +380,8 @@ static int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) regs[R_MD1] = 0x7f & (div >> 16); regs[R_MD2] = 0xff & (div >> 8); regs[R_MD3] = 0xff & div; - - return 0; +fail: + return ret; } static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) @@ -390,7 +392,9 @@ static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) u8 d, pd; u32 div; - tda18271_lookup_cal_pll(&freq, &pd, &d); + int ret = tda18271_lookup_pll_map(CAL_PLL, &freq, &pd, &d); + if (ret < 0) + goto fail; regs[R_CPD] = pd; @@ -399,8 +403,8 @@ static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) regs[R_CD1] = 0x7f & (div >> 16); regs[R_CD2] = 0xff & (div >> 8); regs[R_CD3] = 0xff & div; - - return 0; +fail: + return ret; } static int tda18271_tune(struct dvb_frontend *fe, @@ -418,7 +422,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* RF tracking filter calibration */ /* calculate BP_Filter */ - tda18271_lookup_bp_filter(&freq, &val); + tda18271_lookup_map(BP_FILTER, &freq, &val); regs[R_EP1] &= ~0x07; /* clear bp filter bits */ regs[R_EP1] |= val; @@ -470,20 +474,20 @@ static int tda18271_tune(struct dvb_frontend *fe, msleep(5); /* RF tracking filter calibration initialization */ /* search for K,M,CO for RF Calibration */ - tda18271_lookup_km(&freq, &val); + tda18271_lookup_map(RF_CAL_KMCO, &freq, &val); regs[R_EB13] &= 0x83; regs[R_EB13] |= val; tda18271_write_regs(fe, R_EB13, 1); /* search for RF_BAND */ - tda18271_lookup_rf_band(&freq, &val); + tda18271_lookup_map(RF_BAND, &freq, &val); regs[R_EP2] &= ~0xe0; /* clear rf band bits */ regs[R_EP2] |= (val << 5); /* search for Gain_Taper */ - tda18271_lookup_gain_taper(&freq, &val); + tda18271_lookup_map(GAIN_TAPER, &freq, &val); regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ regs[R_EP2] |= val; @@ -511,7 +515,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP1, 1); /* RF tracking filer correction for VHF_Low band */ - tda18271_lookup_rf_cal(&freq, &val); + tda18271_lookup_map(RF_CAL, &freq, &val); /* VHF_Low band only */ if (val != 0) { @@ -555,7 +559,7 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ /* image rejection validity EP5[2:0] */ - tda18271_lookup_ir_measure(&freq, &val); + tda18271_lookup_map(IR_MEASURE, &freq, &val); regs[R_EP5] &= ~0x07; regs[R_EP5] |= val; diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 7b9aa9ad53f..b08bf08aa88 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -104,15 +104,23 @@ extern int tda18271_debug; /*---------------------------------------------------------------------*/ -extern void tda18271_lookup_cal_pll(u32 *freq, u8 *post_div, u8 *div); -extern void tda18271_lookup_main_pll(u32 *freq, u8 *post_div, u8 *div); - -extern void tda18271_lookup_bp_filter(u32 *freq, u8 *val); -extern void tda18271_lookup_km(u32 *freq, u8 *val); -extern void tda18271_lookup_rf_band(u32 *freq, u8 *val); -extern void tda18271_lookup_gain_taper(u32 *freq, u8 *val); -extern void tda18271_lookup_rf_cal(u32 *freq, u8 *val); -extern void tda18271_lookup_ir_measure(u32 *freq, u8 *val); +enum tda18271_map_type { + /* tda18271_pll_map */ + MAIN_PLL, + CAL_PLL, + /* tda18271_map */ + RF_CAL, + RF_CAL_KMCO, + BP_FILTER, + RF_BAND, + GAIN_TAPER, + IR_MEASURE, +}; + +extern int tda18271_lookup_pll_map(enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div); +extern int tda18271_lookup_map(enum tda18271_map_type map_type, + u32 *freq, u8 *val); #endif /* __TDA18271_PRIV_H__ */ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 02b6d2cb957..8990bef0cf7 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -267,22 +267,33 @@ static struct tda18271_map tda18271_ir_measure[] = { /*---------------------------------------------------------------------*/ -static void tda18271_lookup_map(struct tda18271_map *map, - u32 *freq, u8 *val) +int tda18271_lookup_pll_map(enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div) { - int i = 0; - while ((map[i].rfmax * 1000) < *freq) { - if (map[i + 1].rfmax == 0) - break; - i++; + struct tda18271_pll_map *map = NULL; + unsigned int i = 0; + char *map_name; + + switch (map_type) { + case MAIN_PLL: + map = tda18271_main_pll; + map_name = "main_pll"; + break; + case CAL_PLL: + map = tda18271_cal_pll; + map_name = "cal_pll"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + dbg_info("%s map is not set!\n", map_name); + return -EINVAL; } - *val = map[i].val; -} -static void tda18271_lookup_pll_map(struct tda18271_pll_map *map, - u32 *freq, u8 *post_div, u8 *div) -{ - int i = 0; while ((map[i].lomax * 1000) < *freq) { if (map[i + 1].lomax == 0) break; @@ -290,56 +301,65 @@ static void tda18271_lookup_pll_map(struct tda18271_pll_map *map, } *post_div = map[i].pd; *div = map[i].d; -} - -/*---------------------------------------------------------------------*/ -void tda18271_lookup_cal_pll(u32 *freq, u8 *post_div, u8 *div) -{ - tda18271_lookup_pll_map(tda18271_cal_pll, freq, post_div, div); - dbg_map("post div = 0x%02x, div = 0x%02x\n", *post_div, *div); -} + dbg_map("%s: post div = 0x%02x, div = 0x%02x\n", + map_name, *post_div, *div); -void tda18271_lookup_main_pll(u32 *freq, u8 *post_div, u8 *div) -{ - tda18271_lookup_pll_map(tda18271_main_pll, freq, post_div, div); - dbg_map("post div = 0x%02x, div = 0x%02x\n", *post_div, *div); + return 0; } -void tda18271_lookup_bp_filter(u32 *freq, u8 *val) +int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) { - tda18271_lookup_map(tda18271_bp_filter, freq, val); - dbg_map("0x%02x\n", *val); -} + struct tda18271_map *map = NULL; + unsigned int i = 0; + char *map_name; -void tda18271_lookup_km(u32 *freq, u8 *val) -{ - tda18271_lookup_map(tda18271_km, freq, val); - dbg_map("0x%02x\n", *val); -} + switch (map_type) { + case BP_FILTER: + map = tda18271_bp_filter; + map_name = "bp_filter"; + break; + case RF_CAL_KMCO: + map = tda18271_km; + map_name = "km"; + break; + case RF_BAND: + map = tda18271_rf_band; + map_name = "rf_band"; + break; + case GAIN_TAPER: + map = tda18271_gain_taper; + map_name = "gain_taper"; + break; + case RF_CAL: + map = tda18271_rf_cal; + map_name = "rf_cal"; + break; + case IR_MEASURE: + map = tda18271_ir_measure; + map_name = "ir_measure"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } -void tda18271_lookup_rf_band(u32 *freq, u8 *val) -{ - tda18271_lookup_map(tda18271_rf_band, freq, val); - dbg_map("0x%02x\n", *val); -} + if (!map) { + dbg_info("%s map is not set!\n", map_name); + return -EINVAL; + } -void tda18271_lookup_gain_taper(u32 *freq, u8 *val) -{ - tda18271_lookup_map(tda18271_gain_taper, freq, val); - dbg_map("0x%02x\n", *val); -} + while ((map[i].rfmax * 1000) < *freq) { + if (map[i + 1].rfmax == 0) + break; + i++; + } + *val = map[i].val; -void tda18271_lookup_rf_cal(u32 *freq, u8 *val) -{ - tda18271_lookup_map(tda18271_rf_cal, freq, val); - dbg_map("0x%02x\n", *val); -} + dbg_map("%s: 0x%02x\n", map_name, *val); -void tda18271_lookup_ir_measure(u32 *freq, u8 *val) -{ - tda18271_lookup_map(tda18271_ir_measure, freq, val); - dbg_map("0x%02x\n", *val); + return 0; } /* -- cgit v1.2.3 From 182519f4c99f73f376323580dda494d986b4760b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 25 Dec 2007 15:10:11 -0300 Subject: V4L/DVB (6927): tda18271: improve printk macros Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 58 +++++++++++++-------------- drivers/media/dvb/frontends/tda18271-priv.h | 20 +++++---- drivers/media/dvb/frontends/tda18271-tables.c | 8 ++-- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 72e256ebeb0..8146c4e7ee7 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -76,23 +76,23 @@ static void tda18271_dump_regs(struct dvb_frontend *fe) struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - dbg_reg("=== TDA18271 REG DUMP ===\n"); - dbg_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); - dbg_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); - dbg_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); - dbg_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); - dbg_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); - dbg_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); - dbg_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); - dbg_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); - dbg_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); - dbg_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); - dbg_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); - dbg_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); - dbg_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); - dbg_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); - dbg_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); - dbg_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); + tda_reg("=== TDA18271 REG DUMP ===\n"); + tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); + tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); + tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); + tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); + tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); + tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); + tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); + tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); + tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); + tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); + tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); + tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); + tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); + tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); + tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); + tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); } static void tda18271_read_regs(struct dvb_frontend *fe) @@ -116,8 +116,7 @@ static void tda18271_read_regs(struct dvb_frontend *fe) tda18271_i2c_gate_ctrl(fe, 0); if (ret != 2) - printk("ERROR: %s: i2c_transfer returned: %d\n", - __FUNCTION__, ret); + tda_err("ERROR: i2c_transfer returned: %d\n", ret); if (tda18271_debug & DBG_REG) tda18271_dump_regs(fe); @@ -147,8 +146,7 @@ static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) tda18271_i2c_gate_ctrl(fe, 0); if (ret != 1) - printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", - __FUNCTION__, ret); + tda_err("ERROR: i2c_transfer returned: %d\n", ret); } /*---------------------------------------------------------------------*/ @@ -158,7 +156,8 @@ static int tda18271_init_regs(struct dvb_frontend *fe) struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - printk(KERN_INFO "tda18271: initializing registers\n"); + tda_dbg("initializing registers for device @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), priv->i2c_addr); /* initialize registers */ regs[R_ID] = 0x83; @@ -417,7 +416,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_init(fe); - dbg_info("freq = %d, ifc = %d\n", freq, ifc); + tda_dbg("freq = %d, ifc = %d\n", freq, ifc); /* RF tracking filter calibration */ @@ -602,8 +601,7 @@ static int tda18271_set_params(struct dvb_frontend *fe, sgIF = 4000000; break; default: - printk(KERN_WARNING "%s: modulation not set!\n", - __FUNCTION__); + tda_warn("modulation not set!\n"); return -EINVAL; } #if 0 @@ -629,13 +627,11 @@ static int tda18271_set_params(struct dvb_frontend *fe, sgIF = 4300000; break; default: - printk(KERN_WARNING "%s: bandwidth not set!\n", - __FUNCTION__); + tda_warn("bandwidth not set!\n"); return -EINVAL; } } else { - printk(KERN_WARNING "%s: modulation type not supported!\n", - __FUNCTION__); + tda_warn("modulation type not supported!\n"); return -EINVAL; } @@ -690,7 +686,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, if (params->mode == V4L2_TUNER_RADIO) sgIF = 88; /* if frequency is 5.5 MHz */ - dbg_info("setting tda18271 to system %s\n", mode); + tda_dbg("setting tda18271 to system %s\n", mode); return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, 0, std); @@ -740,7 +736,7 @@ static int tda18271_get_id(struct dvb_frontend *fe) break; } - dbg_info("%s detected @ %d-%04x%s\n", name, + tda_info("%s detected @ %d-%04x%s\n", name, i2c_adapter_id(priv->i2c_adap), priv->i2c_addr, (0 == ret) ? "" : ", device not supported."); diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index b08bf08aa88..912b81e0c76 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -90,17 +90,23 @@ struct tda18271_priv { extern int tda18271_debug; -#define dprintk(level, fmt, arg...) do {\ - if (tda18271_debug & level) \ - printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ##arg); } while (0) - #define DBG_INFO 1 #define DBG_MAP 2 #define DBG_REG 4 -#define dbg_info(fmt, arg...) dprintk(DBG_INFO, fmt, ##arg) -#define dbg_map(fmt, arg...) dprintk(DBG_MAP, fmt, ##arg) -#define dbg_reg(fmt, arg...) dprintk(DBG_REG, fmt, ##arg) +#define tda_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt, __FUNCTION__, ##arg) + +#define dprintk(kern, lvl, fmt, arg...) do {\ + if (tda18271_debug & lvl) \ + tda_printk(kern, fmt, ##arg); } while (0) + +#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) +#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg) +#define tda_err(fmt, arg...) tda_printk(KERN_ERR, fmt, ##arg) +#define tda_dbg(fmt, arg...) dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg) +#define tda_map(fmt, arg...) dprintk(KERN_DEBUG, DBG_MAP, fmt, ##arg) +#define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg) /*---------------------------------------------------------------------*/ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 8990bef0cf7..e10a93bf12c 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -290,7 +290,7 @@ int tda18271_lookup_pll_map(enum tda18271_map_type map_type, } if (!map) { - dbg_info("%s map is not set!\n", map_name); + tda_warn("%s map is not set!\n", map_name); return -EINVAL; } @@ -302,7 +302,7 @@ int tda18271_lookup_pll_map(enum tda18271_map_type map_type, *post_div = map[i].pd; *div = map[i].d; - dbg_map("%s: post div = 0x%02x, div = 0x%02x\n", + tda_map("%s: post div = 0x%02x, div = 0x%02x\n", map_name, *post_div, *div); return 0; @@ -346,7 +346,7 @@ int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) } if (!map) { - dbg_info("%s map is not set!\n", map_name); + tda_warn("%s map is not set!\n", map_name); return -EINVAL; } @@ -357,7 +357,7 @@ int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) } *val = map[i].val; - dbg_map("%s: 0x%02x\n", map_name, *val); + tda_map("%s: 0x%02x\n", map_name, *val); return 0; } -- cgit v1.2.3 From b92bf0f6a94b73a1b8bd0023b1fa642d13b01a76 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 25 Dec 2007 18:54:22 -0300 Subject: V4L/DVB (6928): tda18271: break calculation functions out of tda18271_tune Break out the following new functions from tda18271_tune: tda18271_calc_bp_filter tda18271_calc_km tda18271_calc_rf_band tda18271_calc_gain_taper tda18271_calc_ir_measure tda18271_calc_rf_cal Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 143 ++++++++++++++++++++++++------ 1 file changed, 114 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 8146c4e7ee7..d5807c98afc 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -406,13 +406,118 @@ fail: return ret; } +static int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) +{ + /* Sets BP filter bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(BP_FILTER, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= (0x07 & val); +fail: + return ret; +} + +static int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) +{ + /* Sets K & M bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(RF_CAL_KMCO, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EB13] &= ~0x7c; /* clear k & m bits */ + regs[R_EB13] |= (0x7c & val); +fail: + return ret; +} + +static int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) +{ + /* Sets RF Band bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(RF_BAND, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (0xe0 & (val << 5)); +fail: + return ret; +} + +static int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) +{ + /* Sets Gain Taper bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(GAIN_TAPER, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= (0x1f & val); +fail: + return ret; +} + +static int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) +{ + /* Sets IR Meas bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(IR_MEASURE, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP5] &= ~0x07; + regs[R_EP5] |= (0x07 & val); +fail: + return ret; +} + +static int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) +{ + /* Sets RF Cal bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(RF_CAL, freq, &val); + if (ret < 0) + goto fail; + + /* VHF_Low band only */ + if (0 == val) { + ret = -ERANGE; + goto fail; + } + regs[R_EB14] = val; +fail: + return ret; +} + static int tda18271_tune(struct dvb_frontend *fe, u32 ifc, u32 freq, u32 bw, u8 std) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; u32 N = 0; - u8 val; tda18271_init(fe); @@ -421,10 +526,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* RF tracking filter calibration */ /* calculate BP_Filter */ - tda18271_lookup_map(BP_FILTER, &freq, &val); - - regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= val; + tda18271_calc_bp_filter(fe, &freq); tda18271_write_regs(fe, R_EP1, 1); regs[R_EB4] &= 0x07; @@ -473,23 +575,14 @@ static int tda18271_tune(struct dvb_frontend *fe, msleep(5); /* RF tracking filter calibration initialization */ /* search for K,M,CO for RF Calibration */ - tda18271_lookup_map(RF_CAL_KMCO, &freq, &val); - - regs[R_EB13] &= 0x83; - regs[R_EB13] |= val; + tda18271_calc_km(fe, &freq); tda18271_write_regs(fe, R_EB13, 1); /* search for RF_BAND */ - tda18271_lookup_map(RF_BAND, &freq, &val); - - regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (val << 5); + tda18271_calc_rf_band(fe, &freq); /* search for Gain_Taper */ - tda18271_lookup_map(GAIN_TAPER, &freq, &val); - - regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= val; + tda18271_calc_gain_taper(fe, &freq); tda18271_write_regs(fe, R_EP2, 1); tda18271_write_regs(fe, R_EP1, 1); @@ -513,14 +606,9 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP1, 1); - /* RF tracking filer correction for VHF_Low band */ - tda18271_lookup_map(RF_CAL, &freq, &val); - - /* VHF_Low band only */ - if (val != 0) { - regs[R_EB14] = val; + /* RF tracking filter correction for VHF_Low band */ + if (0 == tda18271_calc_rf_cal(fe, &freq)) tda18271_write_regs(fe, R_EB14, 1); - } /* Channel Configuration */ @@ -557,11 +645,8 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ - /* image rejection validity EP5[2:0] */ - tda18271_lookup_map(IR_MEASURE, &freq, &val); - - regs[R_EP5] &= ~0x07; - regs[R_EP5] |= val; + /* image rejection validity */ + tda18271_calc_ir_measure(fe, &freq); /* calculate MAIN PLL */ N = freq + ifc; -- cgit v1.2.3 From 71bc9bd96b342cd29bbeaa4c83b8d37759ff22d7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 27 Dec 2007 14:33:30 -0300 Subject: V4L/DVB (6930): xc5000: Removed erroneous defines Basic cleanup. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index 106004e1245..a036530ee4b 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" -#define XC5000_DEFAULT_FIRMWARE_SIZE 12400 +#define XC5000_DEFAULT_FIRMWARE_SIZE 12332 /* Misc Defines */ #define MAX_TV_STANDARD 23 -- cgit v1.2.3 From 6ccb8cfbb94cc82144a92a6a28a754d9772b3aa8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Dec 2007 21:46:34 -0300 Subject: V4L/DVB (6932): cx23885: add missing subsystem ID for Hauppauge HVR1800 Retail Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 2 +- drivers/media/video/cx23885/cx23885-cards.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 698971d23f4..302c84f45ed 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -1,6 +1,6 @@ 0 -> UNKNOWN/GENERIC [0070:3400] 1 -> Hauppauge WinTV-HVR1800lp [0070:7600] - 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801] + 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801,0070:7809] 3 -> Hauppauge WinTV-HVR1250 [0070:7911] 4 -> DViCO FusionHDTV5 Express [18ac:d500] 5 -> Hauppauge WinTV-HVR1500Q [0070:7797] diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index fbf93c63dca..3ddcab30577 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -144,6 +144,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7801, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, + .subdevice = 0x7809, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, },{ .subvendor = 0x0070, .subdevice = 0x7911, -- cgit v1.2.3 From 6a0a962cbc2c52fad556692eabda563a01c9966c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Dec 2007 21:47:50 -0300 Subject: V4L/DVB (6933): cx23885: update model matrix for Hauppauge HVR1800 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 3ddcab30577..ea1259846c2 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -206,8 +206,11 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ case 77041: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */ - case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ - case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ break; default: printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); -- cgit v1.2.3 From 68370cf94e2511aeda3b7cb8490692570a8c9dab Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Dec 2007 22:02:38 -0300 Subject: V4L/DVB (6934): cx23885: update model matrix for Hauppauge HVR1250 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index ea1259846c2..4068695383e 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -211,6 +211,10 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */ + case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */ + case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */ + case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */ break; default: printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); -- cgit v1.2.3 From b00fff0be5655614bb18a4b1d6e33b27c56c6f7e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Dec 2007 22:19:31 -0300 Subject: V4L/DVB (6935): cx23885: add missing subsystem IDs for Hauppauge HVR1500 Retail Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 4 ++-- drivers/media/video/cx23885/cx23885-cards.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 302c84f45ed..0924e6e142c 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -3,5 +3,5 @@ 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801,0070:7809] 3 -> Hauppauge WinTV-HVR1250 [0070:7911] 4 -> DViCO FusionHDTV5 Express [18ac:d500] - 5 -> Hauppauge WinTV-HVR1500Q [0070:7797] - 6 -> Hauppauge WinTV-HVR1500 [0070:7717] + 5 -> Hauppauge WinTV-HVR1500Q [0070:7790,0070:7797] + 6 -> Hauppauge WinTV-HVR1500 [0070:7710,0070:7717] diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 4068695383e..82af44884f0 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -156,10 +156,18 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xd500, .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, + },{ + .subvendor = 0x0070, + .subdevice = 0x7790, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, },{ .subvendor = 0x0070, .subdevice = 0x7797, .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, + },{ + .subvendor = 0x0070, + .subdevice = 0x7710, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500, },{ .subvendor = 0x0070, .subdevice = 0x7717, -- cgit v1.2.3 From 29a7b4cb44336a8ef85cb1d283dc6efd4cf0fa12 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 27 Dec 2007 22:22:16 -0300 Subject: V4L/DVB (6936): cx23885: update model matrix for Hauppauge HVR1500 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 82af44884f0..aa0ddf2ea22 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -212,8 +212,10 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) switch (tv.model) { case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ - case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ - case 77041: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */ + case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */ + case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */ + case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */ case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ -- cgit v1.2.3 From a594dcba943a2edc484ed83f694c27306bf5e28e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 31 Dec 2007 02:29:46 -0300 Subject: V4L/DVB (6938): Add a tool for extracting xc3028 version 2.7 firmware This tool allows the extraction of xc3028 v2.7 firmware from HVR 12x0 file. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/extract_xc3028.pl | 926 ++++++++++++++++++++++++++++ 1 file changed, 926 insertions(+) create mode 100644 Documentation/video4linux/extract_xc3028.pl diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl new file mode 100644 index 00000000000..cced8ac5c54 --- /dev/null +++ b/Documentation/video4linux/extract_xc3028.pl @@ -0,0 +1,926 @@ +#!/usr/bin/perl + +# Copyright (c) Mauro Carvalho Chehab +# Released under GPLv2 +# +# In order to use, you need to: +# 1) Download the windows driver with something like: +# wget http://www.steventoth.net/linux/xc5000/HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip +# 2) Extract the file hcw85bda.sys from the zip into the current dir: +# unzip -j HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip Driver85/hcw85bda.sys +# 3) run the script: +# ./extract_xc3028.pl +# 4) copy the generated file: +# cp xc3028-v27.fw /lib/firmware + +#use strict; +use IO::Handle; + +my $debug=0; + +sub verify ($$) +{ + my ($filename, $hash) = @_; + my ($testhash); + + if (system("which md5sum > /dev/null 2>&1")) { + die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n"; + } + + open(CMD, "md5sum ".$filename."|"); + $testhash = ; + $testhash =~ /([a-zA-Z0-9]*)/; + $testhash = $1; + close CMD; + die "Hash of extracted file does not match (found $testhash, expected $hash!\n" if ($testhash ne $hash); +} + +sub get_hunk ($$) +{ + my ($offset, $length) = @_; + my ($chunklength, $buf, $rcount, $out); + + sysseek(INFILE, $offset, SEEK_SET); + while ($length > 0) { + # Calc chunk size + $chunklength = 2048; + $chunklength = $length if ($chunklength > $length); + + $rcount = sysread(INFILE, $buf, $chunklength); + die "Ran out of data\n" if ($rcount != $chunklength); + $out .= $buf; + $length -= $rcount; + } + return $out; +} + +sub write_le16($) +{ + my $val = shift; + my $msb = ($val >> 8) &0xff; + my $lsb = $val & 0xff; + + syswrite(OUTFILE, chr($lsb).chr($msb)); +} + +sub write_le32($) +{ + my $val = shift; + my $l3 = ($val >> 24) & 0xff; + my $l2 = ($val >> 16) & 0xff; + my $l1 = ($val >> 8) & 0xff; + my $l0 = $val & 0xff; + + syswrite(OUTFILE, chr($l0).chr($l1).chr($l2).chr($l3)); +} + +sub write_le64($$) +{ + my $msb_val = shift; + my $lsb_val = shift; + my $l7 = ($msb_val >> 24) & 0xff; + my $l6 = ($msb_val >> 16) & 0xff; + my $l5 = ($msb_val >> 8) & 0xff; + my $l4 = $msb_val & 0xff; + + my $l3 = ($lsb_val >> 24) & 0xff; + my $l2 = ($lsb_val >> 16) & 0xff; + my $l1 = ($lsb_val >> 8) & 0xff; + my $l0 = $lsb_val & 0xff; + + syswrite(OUTFILE, + chr($l0).chr($l1).chr($l2).chr($l3). + chr($l4).chr($l5).chr($l6).chr($l7)); +} + +sub write_hunk($$) +{ + my ($offset, $length) = @_; + my $out = get_hunk($offset, $length); + + printf "(len %d) ",$length if ($debug); + + for (my $i=0;$i<$length;$i++) { + printf "%02x ",ord(substr($out,$i,1)) if ($debug); + } + printf "\n" if ($debug); + + syswrite(OUTFILE, $out); +} + +sub write_hunk_fix_endian($$) +{ + my ($offset, $length) = @_; + my $out = get_hunk($offset, $length); + + printf "(len_fix %d) ",$length if ($debug); + + for (my $i=0;$i<$length;$i++) { + printf "%02x ",ord(substr($out,$i,1)) if ($debug); + } + printf "\n" if ($debug); + + my $i=0; + while ($i<$length) { + my $size = ord(substr($out,$i,1))*256+ord(substr($out,$i+1,1)); + syswrite(OUTFILE, substr($out,$i+1,1)); + syswrite(OUTFILE, substr($out,$i,1)); + $i+=2; + if ($size>0 && $size <0x8000) { + for (my $j=0;$j<$size;$j++) { + syswrite(OUTFILE, substr($out,$j+$i,1)); + } + $i+=$size; + } + } +} + +sub main_firmware($$$$) +{ + my $out; + my $j=0; + my $outfile = shift; + my $name = shift; + my $version = shift; + my $nr_desc = shift; + + for ($j = length($name); $j <32; $j++) { + $name = $name.chr(0); +} + + open OUTFILE, ">$outfile"; + syswrite(OUTFILE, $name); + write_le16($version); + write_le16($nr_desc); + + # + # Firmware 0, type: BASE FW F8MHZ (0x00000003), id: (0000000000000000), size: 8718 + # + + write_le32(0x00000003); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(8718); # Size + write_hunk_fix_endian(813432, 8718); + + # + # Firmware 1, type: BASE FW F8MHZ MTS (0x00000007), id: (0000000000000000), size: 8712 + # + + write_le32(0x00000007); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(8712); # Size + write_hunk_fix_endian(822152, 8712); + + # + # Firmware 2, type: BASE FW FM (0x00000401), id: (0000000000000000), size: 8562 + # + + write_le32(0x00000401); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(8562); # Size + write_hunk_fix_endian(830872, 8562); + + # + # Firmware 3, type: BASE FW FM INPUT1 (0x00000c01), id: (0000000000000000), size: 8576 + # + + write_le32(0x00000c01); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(8576); # Size + write_hunk_fix_endian(839440, 8576); + + # + # Firmware 4, type: BASE FW (0x00000001), id: (0000000000000000), size: 8706 + # + + write_le32(0x00000001); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(8706); # Size + write_hunk_fix_endian(848024, 8706); + + # + # Firmware 5, type: BASE FW MTS (0x00000005), id: (0000000000000000), size: 8682 + # + + write_le32(0x00000005); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(8682); # Size + write_hunk_fix_endian(856736, 8682); + + # + # Firmware 6, type: STD FW (0x00000000), id: PAL/BG A2/A (0000000100000007), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000001, 0x00000007); # ID + write_le32(161); # Size + write_hunk_fix_endian(865424, 161); + + # + # Firmware 7, type: STD FW MTS (0x00000004), id: PAL/BG A2/A (0000000100000007), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000001, 0x00000007); # ID + write_le32(169); # Size + write_hunk_fix_endian(865592, 169); + + # + # Firmware 8, type: STD FW (0x00000000), id: PAL/BG A2/B (0000000200000007), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000002, 0x00000007); # ID + write_le32(161); # Size + write_hunk_fix_endian(865424, 161); + + # + # Firmware 9, type: STD FW MTS (0x00000004), id: PAL/BG A2/B (0000000200000007), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000002, 0x00000007); # ID + write_le32(169); # Size + write_hunk_fix_endian(865592, 169); + + # + # Firmware 10, type: STD FW (0x00000000), id: PAL/BG NICAM/A (0000000400000007), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000004, 0x00000007); # ID + write_le32(161); # Size + write_hunk_fix_endian(866112, 161); + + # + # Firmware 11, type: STD FW MTS (0x00000004), id: PAL/BG NICAM/A (0000000400000007), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000004, 0x00000007); # ID + write_le32(169); # Size + write_hunk_fix_endian(866280, 169); + + # + # Firmware 12, type: STD FW (0x00000000), id: PAL/BG NICAM/B (0000000800000007), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000008, 0x00000007); # ID + write_le32(161); # Size + write_hunk_fix_endian(866112, 161); + + # + # Firmware 13, type: STD FW MTS (0x00000004), id: PAL/BG NICAM/B (0000000800000007), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000008, 0x00000007); # ID + write_le32(169); # Size + write_hunk_fix_endian(866280, 169); + + # + # Firmware 14, type: STD FW (0x00000000), id: PAL/DK A2 (00000003000000e0), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000003, 0x000000e0); # ID + write_le32(161); # Size + write_hunk_fix_endian(866800, 161); + + # + # Firmware 15, type: STD FW MTS (0x00000004), id: PAL/DK A2 (00000003000000e0), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000003, 0x000000e0); # ID + write_le32(169); # Size + write_hunk_fix_endian(866968, 169); + + # + # Firmware 16, type: STD FW (0x00000000), id: PAL/DK NICAM (0000000c000000e0), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x0000000c, 0x000000e0); # ID + write_le32(161); # Size + write_hunk_fix_endian(867144, 161); + + # + # Firmware 17, type: STD FW MTS (0x00000004), id: PAL/DK NICAM (0000000c000000e0), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x0000000c, 0x000000e0); # ID + write_le32(169); # Size + write_hunk_fix_endian(867312, 169); + + # + # Firmware 18, type: STD FW (0x00000000), id: SECAM/K1 (0000000000200000), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x00200000); # ID + write_le32(161); # Size + write_hunk_fix_endian(867488, 161); + + # + # Firmware 19, type: STD FW MTS (0x00000004), id: SECAM/K1 (0000000000200000), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000000, 0x00200000); # ID + write_le32(169); # Size + write_hunk_fix_endian(867656, 169); + + # + # Firmware 20, type: STD FW (0x00000000), id: SECAM/K3 (0000000004000000), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x04000000); # ID + write_le32(161); # Size + write_hunk_fix_endian(867832, 161); + + # + # Firmware 21, type: STD FW MTS (0x00000004), id: SECAM/K3 (0000000004000000), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000000, 0x04000000); # ID + write_le32(169); # Size + write_hunk_fix_endian(868000, 169); + + # + # Firmware 22, type: STD FW D2633 DTV6 ATSC (0x00010030), id: (0000000000000000), size: 149 + # + + write_le32(0x00010030); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868176, 149); + + # + # Firmware 23, type: STD FW D2620 DTV6 QAM (0x00000068), id: (0000000000000000), size: 149 + # + + write_le32(0x00000068); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868336, 149); + + # + # Firmware 24, type: STD FW D2633 DTV6 QAM (0x00000070), id: (0000000000000000), size: 149 + # + + write_le32(0x00000070); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868488, 149); + + # + # Firmware 25, type: STD FW D2620 DTV7 (0x00000088), id: (0000000000000000), size: 149 + # + + write_le32(0x00000088); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868648, 149); + + # + # Firmware 26, type: STD FW D2633 DTV7 (0x00000090), id: (0000000000000000), size: 149 + # + + write_le32(0x00000090); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868800, 149); + + # + # Firmware 27, type: STD FW D2620 DTV78 (0x00000108), id: (0000000000000000), size: 149 + # + + write_le32(0x00000108); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868960, 149); + + # + # Firmware 28, type: STD FW D2633 DTV78 (0x00000110), id: (0000000000000000), size: 149 + # + + write_le32(0x00000110); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(869112, 149); + + # + # Firmware 29, type: STD FW D2620 DTV8 (0x00000208), id: (0000000000000000), size: 149 + # + + write_le32(0x00000208); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868648, 149); + + # + # Firmware 30, type: STD FW D2633 DTV8 (0x00000210), id: (0000000000000000), size: 149 + # + + write_le32(0x00000210); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(149); # Size + write_hunk_fix_endian(868800, 149); + + # + # Firmware 31, type: STD FW FM (0x00000400), id: (0000000000000000), size: 135 + # + + write_le32(0x00000400); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le32(135); # Size + write_hunk_fix_endian(869584, 135); + + # + # Firmware 32, type: STD FW (0x00000000), id: PAL/I (0000000000000010), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x00000010); # ID + write_le32(161); # Size + write_hunk_fix_endian(869728, 161); + + # + # Firmware 33, type: STD FW MTS (0x00000004), id: PAL/I (0000000000000010), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000000, 0x00000010); # ID + write_le32(169); # Size + write_hunk_fix_endian(869896, 169); + + # + # Firmware 34, type: STD FW (0x00000000), id: SECAM/L AM (0000001000400000), size: 169 + # + + write_le32(0x00000000); # Type + write_le64(0x00000010, 0x00400000); # ID + write_le32(169); # Size + write_hunk_fix_endian(870072, 169); + + # + # Firmware 35, type: STD FW (0x00000000), id: SECAM/L NICAM (0000000c00400000), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x0000000c, 0x00400000); # ID + write_le32(161); # Size + write_hunk_fix_endian(870248, 161); + + # + # Firmware 36, type: STD FW (0x00000000), id: SECAM/Lc (0000000000800000), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x00800000); # ID + write_le32(161); # Size + write_hunk_fix_endian(870416, 161); + + # + # Firmware 37, type: STD FW (0x00000000), id: NTSC/M Kr (0000000000008000), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x00008000); # ID + write_le32(161); # Size + write_hunk_fix_endian(870584, 161); + + # + # Firmware 38, type: STD FW LCD (0x00001000), id: NTSC/M Kr (0000000000008000), size: 161 + # + + write_le32(0x00001000); # Type + write_le64(0x00000000, 0x00008000); # ID + write_le32(161); # Size + write_hunk_fix_endian(870752, 161); + + # + # Firmware 39, type: STD FW LCD NOGD (0x00003000), id: NTSC/M Kr (0000000000008000), size: 161 + # + + write_le32(0x00003000); # Type + write_le64(0x00000000, 0x00008000); # ID + write_le32(161); # Size + write_hunk_fix_endian(870920, 161); + + # + # Firmware 40, type: STD FW MTS (0x00000004), id: NTSC/M Kr (0000000000008000), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000000, 0x00008000); # ID + write_le32(169); # Size + write_hunk_fix_endian(871088, 169); + + # + # Firmware 41, type: STD FW (0x00000000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x0000b700); # ID + write_le32(161); # Size + write_hunk_fix_endian(871264, 161); + + # + # Firmware 42, type: STD FW LCD (0x00001000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161 + # + + write_le32(0x00001000); # Type + write_le64(0x00000000, 0x0000b700); # ID + write_le32(161); # Size + write_hunk_fix_endian(871432, 161); + + # + # Firmware 43, type: STD FW LCD NOGD (0x00003000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161 + # + + write_le32(0x00003000); # Type + write_le64(0x00000000, 0x0000b700); # ID + write_le32(161); # Size + write_hunk_fix_endian(871600, 161); + + # + # Firmware 44, type: STD FW (0x00000000), id: NTSC/M Jp (0000000000002000), size: 161 + # + + write_le32(0x00000000); # Type + write_le64(0x00000000, 0x00002000); # ID + write_le32(161); # Size + write_hunk_fix_endian(871264, 161); + + # + # Firmware 45, type: STD FW MTS (0x00000004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169 + # + + write_le32(0x00000004); # Type + write_le64(0x00000000, 0x0000b700); # ID + write_le32(169); # Size + write_hunk_fix_endian(871936, 169); + + # + # Firmware 46, type: STD FW MTS LCD (0x00001004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169 + # + + write_le32(0x00001004); # Type + write_le64(0x00000000, 0x0000b700); # ID + write_le32(169); # Size + write_hunk_fix_endian(872112, 169); + + # + # Firmware 47, type: STD FW MTS LCD NOGD (0x00003004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169 + # + + write_le32(0x00003004); # Type + write_le64(0x00000000, 0x0000b700); # ID + write_le32(169); # Size + write_hunk_fix_endian(872288, 169); + + # + # Firmware 48, type: SCODE FW HAS IF (0x60000000), IF = 3.28 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(3280); # IF + write_le32(192); # Size + write_hunk(811896, 192); + + # + # Firmware 49, type: SCODE FW HAS IF (0x60000000), IF = 3.30 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(3300); # IF + write_le32(192); # Size + write_hunk(813048, 192); + + # + # Firmware 50, type: SCODE FW HAS IF (0x60000000), IF = 3.44 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(3440); # IF + write_le32(192); # Size + write_hunk(812280, 192); + + # + # Firmware 51, type: SCODE FW HAS IF (0x60000000), IF = 3.46 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(3460); # IF + write_le32(192); # Size + write_hunk(812472, 192); + + # + # Firmware 52, type: SCODE FW DTV6 ATSC OREN36 HAS IF (0x60210020), IF = 3.80 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60210020); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(3800); # IF + write_le32(192); # Size + write_hunk(809784, 192); + + # + # Firmware 53, type: SCODE FW HAS IF (0x60000000), IF = 4.00 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(4000); # IF + write_le32(192); # Size + write_hunk(812088, 192); + + # + # Firmware 54, type: SCODE FW DTV6 ATSC TOYOTA388 HAS IF (0x60410020), IF = 4.08 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60410020); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(4080); # IF + write_le32(192); # Size + write_hunk(809976, 192); + + # + # Firmware 55, type: SCODE FW HAS IF (0x60000000), IF = 4.20 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(4200); # IF + write_le32(192); # Size + write_hunk(811704, 192); + + # + # Firmware 56, type: SCODE FW MONO HAS IF (0x60008000), IF = 4.32 MHz id: NTSC/M Kr (0000000000008000), size: 192 + # + + write_le32(0x60008000); # Type + write_le64(0x00000000, 0x00008000); # ID + write_le16(4320); # IF + write_le32(192); # Size + write_hunk(808056, 192); + + # + # Firmware 57, type: SCODE FW HAS IF (0x60000000), IF = 4.45 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(4450); # IF + write_le32(192); # Size + write_hunk(812664, 192); + + # + # Firmware 58, type: SCODE FW HAS IF (0x60000000), IF = 4.50 MHz id: NTSC/M Jp (0000000000002000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00002000); # ID + write_le16(4500); # IF + write_le32(192); # Size + write_hunk(807672, 192); + + # + # Firmware 59, type: SCODE FW LCD NOGD IF HAS IF (0x60023000), IF = 4.60 MHz id: NTSC/M Kr (0000000000008000), size: 192 + # + + write_le32(0x60023000); # Type + write_le64(0x00000000, 0x00008000); # ID + write_le16(4600); # IF + write_le32(192); # Size + write_hunk(807864, 192); + + # + # Firmware 60, type: SCODE FW DTV78 ZARLINK456 HAS IF (0x62000100), IF = 4.76 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x62000100); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(4760); # IF + write_le32(192); # Size + write_hunk(807288, 192); + + # + # Firmware 61, type: SCODE FW HAS IF (0x60000000), IF = 4.94 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(4940); # IF + write_le32(192); # Size + write_hunk(811512, 192); + + # + # Firmware 62, type: SCODE FW DTV7 ZARLINK456 HAS IF (0x62000080), IF = 5.26 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x62000080); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(5260); # IF + write_le32(192); # Size + write_hunk(810552, 192); + + # + # Firmware 63, type: SCODE FW MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192 + # + + write_le32(0x60008000); # Type + write_le64(0x00000008, 0x00000007); # ID + write_le16(5320); # IF + write_le32(192); # Size + write_hunk(810744, 192); + + # + # Firmware 64, type: SCODE FW DTV8 CHINA HAS IF (0x64000200), IF = 5.40 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x64000200); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(5400); # IF + write_le32(192); # Size + write_hunk(807096, 192); + + # + # Firmware 65, type: SCODE FW DTV6 ATSC OREN538 HAS IF (0x60110020), IF = 5.58 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60110020); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(5580); # IF + write_le32(192); # Size + write_hunk(809592, 192); + + # + # Firmware 66, type: SCODE FW HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2/B (0000000200000007), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000002, 0x00000007); # ID + write_le16(5640); # IF + write_le32(192); # Size + write_hunk(808440, 192); + + # + # Firmware 67, type: SCODE FW HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000008, 0x00000007); # ID + write_le16(5740); # IF + write_le32(192); # Size + write_hunk(808632, 192); + + # + # Firmware 68, type: SCODE FW DTV7 DIBCOM52 HAS IF (0x61000080), IF = 5.90 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x61000080); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(5900); # IF + write_le32(192); # Size + write_hunk(810360, 192); + + # + # Firmware 69, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/I (0000000000000010), size: 192 + # + + write_le32(0x60008000); # Type + write_le64(0x00000000, 0x00000010); # ID + write_le16(6000); # IF + write_le32(192); # Size + write_hunk(808824, 192); + + # + # Firmware 70, type: SCODE FW DTV6 QAM F6MHZ HAS IF (0x68000060), IF = 6.20 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x68000060); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(6200); # IF + write_le32(192); # Size + write_hunk(809400, 192); + + # + # Firmware 71, type: SCODE FW HAS IF (0x60000000), IF = 6.24 MHz id: PAL/I (0000000000000010), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000010); # ID + write_le16(6240); # IF + write_le32(192); # Size + write_hunk(808248, 192); + + # + # Firmware 72, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.32 MHz id: SECAM/K1 (0000000000200000), size: 192 + # + + write_le32(0x60008000); # Type + write_le64(0x00000000, 0x00200000); # ID + write_le16(6320); # IF + write_le32(192); # Size + write_hunk(811320, 192); + + # + # Firmware 73, type: SCODE FW HAS IF (0x60000000), IF = 6.34 MHz id: SECAM/K1 (0000000000200000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00200000); # ID + write_le16(6340); # IF + write_le32(192); # Size + write_hunk(809208, 192); + + # + # Firmware 74, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.50 MHz id: SECAM/K3 (0000000004000000), size: 192 + # + + write_le32(0x60008000); # Type + write_le64(0x00000000, 0x04000000); # ID + write_le16(6500); # IF + write_le32(192); # Size + write_hunk(811128, 192); + + # + # Firmware 75, type: SCODE FW DTV6 ATSC ATI638 HAS IF (0x60090020), IF = 6.58 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60090020); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(6580); # IF + write_le32(192); # Size + write_hunk(807480, 192); + + # + # Firmware 76, type: SCODE FW HAS IF (0x60000000), IF = 6.60 MHz id: PAL/DK A2 (00000003000000e0), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000003, 0x000000e0); # ID + write_le16(6600); # IF + write_le32(192); # Size + write_hunk(809016, 192); + + # + # Firmware 77, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.68 MHz id: PAL/DK A2 (00000003000000e0), size: 192 + # + + write_le32(0x60008000); # Type + write_le64(0x00000003, 0x000000e0); # ID + write_le16(6680); # IF + write_le32(192); # Size + write_hunk(810936, 192); + + # + # Firmware 78, type: SCODE FW DTV6 ATSC TOYOTA794 HAS IF (0x60810020), IF = 8.14 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60810020); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(8140); # IF + write_le32(192); # Size + write_hunk(810168, 192); + + # + # Firmware 79, type: SCODE FW HAS IF (0x60000000), IF = 8.20 MHz id: (0000000000000000), size: 192 + # + + write_le32(0x60000000); # Type + write_le64(0x00000000, 0x00000000); # ID + write_le16(8200); # IF + write_le32(192); # Size + write_hunk(812856, 192); +} + +sub extract_firmware { + my $sourcefile = "hcw85bda.sys"; + my $hash = "0e44dbf63bb0169d57446aec21881ff2"; + my $outfile = "xc3028-v27.fw"; + my $name = "xc2028 firmware"; + my $version = 519; + my $nr_desc = 80; + my $out; + + verify($sourcefile, $hash); + + open INFILE, "<$sourcefile"; + main_firmware($outfile, $name, $version, $nr_desc); + close INFILE; +} + +extract_firmware; +printf "Firmwares generated.\n"; -- cgit v1.2.3 From 6596a4f6032f13f1bef47550fcf1d4134cd978a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 1 Jan 2008 14:43:02 -0300 Subject: V4L/DVB (6944): Fix in-kernel ivtv compilation Due to tuner-xc2028.h, some extra directories should be added at .h search. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index e8eefd96d89..a0389014fa8 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -6,3 +6,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + -- cgit v1.2.3 From 539c96d0fd86bfdcfac75c88b74aa5798439293d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 09:53:54 -0300 Subject: V4L/DVB (6947): Improve audio setup handling It is possible to select audio inputs via em28xx or via ac97 functions. This patch allows configuring a board to use either one way. It also do some cleanups at audio setup configurations. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-core.c | 81 +++++++++++++++++++++++++++++-- drivers/media/video/em28xx/em28xx-video.c | 21 +++----- drivers/media/video/em28xx/em28xx.h | 35 +++++-------- 3 files changed, 95 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index d56484f2046..70c5ec268f6 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, * em28xx_write_ac97() * write a 16 bit value to the specified AC97 address (LSB first!) */ -int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val) +static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) { int ret; u8 addr = reg & 0x7f; @@ -268,16 +268,91 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val) return 0; } +int em28xx_set_audio_source(struct em28xx *dev) +{ + static char *enable = "\x08\x08"; + static char *disable = "\x08\x88"; + char *video = enable, *line = disable; + int ret, no_ac97; + u8 input; + + if (dev->is_em2800) { + if (dev->ctl_ainput) + input = EM2800_AUDIO_SRC_LINE; + else + input = EM2800_AUDIO_SRC_TUNER; + + ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1); + if (ret < 0) + return ret; + } + + if (dev->has_msp34xx) + input = EM28XX_AUDIO_SRC_TUNER; + else { + switch (dev->ctl_ainput) { + case EM28XX_AMUX_VIDEO: + input = EM28XX_AUDIO_SRC_TUNER; + no_ac97 = 1; + break; + case EM28XX_AMUX_LINE_IN: + input = EM28XX_AUDIO_SRC_LINE; + no_ac97 = 1; + break; + case EM28XX_AMUX_AC97_VIDEO: + input = EM28XX_AUDIO_SRC_LINE; + break; + case EM28XX_AMUX_AC97_LINE_IN: + input = EM28XX_AUDIO_SRC_LINE; + video = disable; + line = enable; + break; + } + } + + ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); + if (ret < 0) + return ret; + + if (no_ac97) + return 0; + + /* Sets AC97 mixer registers */ + + ret = em28xx_write_ac97(dev, VIDEO_AC97, video); + if (ret < 0) + return ret; + + ret = em28xx_write_ac97(dev, LINE_IN_AC97, line); + + return ret; +} + int em28xx_audio_analog_set(struct em28xx *dev) { + int ret; char s[2] = { 0x00, 0x00 }; + s[0] |= 0x1f - dev->volume; s[1] |= 0x1f - dev->volume; + if (dev->mute) s[1] |= 0x80; - return em28xx_write_ac97(dev, MASTER_AC97, s); -} + ret = em28xx_write_ac97(dev, MASTER_AC97, s); + if (ret < 0) + return ret; + ret = em28xx_write_reg_bits(dev, XCLK_REG, + dev->mute ? 0x00 : 0x80, 0x80); + if (ret < 0) + return ret; + + /* Selects the proper audio input */ + ret = em28xx_set_audio_source(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); int em28xx_colorlevels_set_default(struct em28xx *dev) { diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index c2901f13eb2..1a284cb18c2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -122,11 +122,13 @@ static int em28xx_config(struct em28xx *dev) /* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */ em28xx_write_regs_req(dev,0x00,0x11,"\x51",1); - em28xx_audio_usb_mute(dev, 1); dev->mute = 1; /* maybe not the right place... */ dev->volume = 0x1f; + + /* Init XCLK_REG, audio muted */ + dev->em28xx_write_regs(dev, XCLK_REG, "\x87", 1); + em28xx_audio_analog_set(dev); - em28xx_audio_analog_setup(dev); em28xx_outfmt_set_yuv422(dev); em28xx_colorlevels_set_default(dev); em28xx_compression_disable(dev); @@ -168,7 +170,6 @@ static void em28xx_empty_framequeues(struct em28xx *dev) static void video_mux(struct em28xx *dev, int index) { - int ainput; struct v4l2_routing route; route.input = INPUT(index)->vmux; @@ -185,18 +186,9 @@ static void video_mux(struct em28xx *dev, int index) route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); /* Note: this is msp3400 specific */ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route); - ainput = EM28XX_AUDIO_SRC_TUNER; - em28xx_audio_source(dev, ainput); - } else { - switch (dev->ctl_ainput) { - case 0: - ainput = EM28XX_AUDIO_SRC_TUNER; - break; - default: - ainput = EM28XX_AUDIO_SRC_LINE; - } - em28xx_audio_source(dev, ainput); } + + em28xx_set_audio_source(dev); } /* Usage lock check functions */ @@ -292,7 +284,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) case V4L2_CID_AUDIO_MUTE: if (ctrl->value != dev->mute) { dev->mute = ctrl->value; - em28xx_audio_usb_mute(dev, ctrl->value); return em28xx_audio_analog_set(dev); } return 0; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 93007cc72f4..abde13ecb4a 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -151,10 +151,17 @@ enum enum28xx_itype { EM28XX_RADIO, }; +enum em28xx_amux { + EM28XX_AMUX_VIDEO, + EM28XX_AMUX_LINE_IN, + EM28XX_AMUX_AC97_VIDEO, + EM28XX_AMUX_AC97_LINE_IN, +}; + struct em28xx_input { enum enum28xx_itype type; unsigned int vmux; - unsigned int amux; + enum em28xx_amux amux; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -321,8 +328,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 bitmask); -int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val); +int em28xx_set_audio_source(struct em28xx *dev); int em28xx_audio_analog_set(struct em28xx *dev); + int em28xx_colorlevels_set_default(struct em28xx *dev); int em28xx_capture_start(struct em28xx *dev, int start); int em28xx_outfmt_set_yuv422(struct em28xx *dev); @@ -394,6 +402,7 @@ extern const unsigned int em28xx_bcount; /* em202 registers */ #define MASTER_AC97 0x02 +#define LINE_IN_AC97 0x10 #define VIDEO_AC97 0x14 /* register settings */ @@ -418,28 +427,6 @@ extern const unsigned int em28xx_bcount; printk(KERN_WARNING "%s: "fmt,\ dev->name , ##arg); } while (0) -inline static int em28xx_audio_source(struct em28xx *dev, int input) -{ - if(dev->is_em2800){ - u8 tmp = EM2800_AUDIO_SRC_TUNER; - if(input == EM28XX_AUDIO_SRC_LINE) - tmp = EM2800_AUDIO_SRC_LINE; - em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &tmp, 1); - } - return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); -} - -inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute) -{ - return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80); -} - -inline static int em28xx_audio_analog_setup(struct em28xx *dev) -{ - /* unmute video mixer with default volume level */ - return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08"); -} - inline static int em28xx_compression_disable(struct em28xx *dev) { /* side effect of disabling scaler and mixer */ -- cgit v1.2.3 From 74f38a82376fb1b289d0957429ba45349f0cad62 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 09:54:58 -0300 Subject: V4L/DVB (6948): HVR950 requires additional settings for audio to properly work Thanks to Markus Rechberger for retriving those commands. Also, MTS firmware is required for audio to work on HVR950. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 45 +++++++++++++++++++++++++++---- drivers/media/video/em28xx/em28xx.h | 13 +++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index e00de328605..78be0dc2572 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -179,6 +179,7 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .has_tuner = 1, + .mts_firmware = 1, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -193,6 +194,9 @@ struct em28xx_board em28xx_boards[] = { .vmux = TVP5150_SVIDEO, .amux = 1, } }, + + /* gpio's 4, 1, 0 */ + .analog_gpio = 0x003d2d, }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", @@ -453,8 +457,18 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_TERRATEC_HYBRID_XS: - /* reset through GPIO? */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); + em28xx_write_regs(dev, XCLK_REG, "\x27", 1); + em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1); + em28xx_write_regs(dev, 0x08, "\xff", 1); + em28xx_write_regs(dev, 0x04, "\x00", 1); + msleep(100); + em28xx_write_regs(dev, 0x04, "\x08", 1); + msleep(100); + em28xx_write_regs(dev, 0x08, "\xff", 1); + msleep(50); + em28xx_write_regs(dev, 0x08, "\x2d", 1); + msleep(50); + em28xx_write_regs(dev, 0x08, "\x3d", 1); break; } } @@ -469,13 +483,31 @@ static int em28xx_tuner_callback(void *ptr, int command, int arg) switch (command) { case XC2028_TUNER_RESET: - /* FIXME: This is device-dependent */ + { + char gpio0, gpio1, gpio4; + + /* GPIO and initialization codes for analog TV */ + gpio0 = dev->analog_gpio & 0xff; + gpio1 = (dev->analog_gpio >> 8) & 0xff; + gpio4 = dev->analog_gpio >> 24; + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); - msleep(140); + if (gpio4) { + dev->em28xx_write_regs(dev, 0x04, &gpio4, 1); + msleep(140); + } + + msleep(6); + dev->em28xx_write_regs(dev, 0x08, &gpio0, 1); + msleep(10); + dev->em28xx_write_regs(dev, 0x08, &gpio1, 1); + msleep(5); + break; } + } return rc; } @@ -608,6 +640,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; dev->decoder = em28xx_boards[dev->model].decoder; dev->video_inputs = em28xx_boards[dev->model].vchannels; + dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; if (!em28xx_boards[dev->model].has_tuner) dev->tuner_type = UNSET; @@ -643,7 +676,9 @@ void em28xx_card_setup(struct em28xx *dev) if (tv.has_ir) request_module("ir-kbd-i2c"); #endif - /* FIXME: Should also retrieve decoder processor type */ + /* enable audio 12 mhz i2s */ + em28xx_write_regs(dev, XCLK_REG, "\xa7", 1); + msleep(10); break; } diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index abde13ecb4a..1fb3c230e23 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -178,12 +178,13 @@ struct em28xx_board { int tuner_type; /* i2c flags */ - unsigned int is_em2800; unsigned int tda9887_conf; + unsigned int is_em2800:1; unsigned int has_tuner:1; unsigned int has_msp34xx:1; unsigned int mts_firmware:1; + unsigned int analog_gpio; enum em28xx_decoder decoder; @@ -217,15 +218,16 @@ struct em28xx { char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ - unsigned int is_em2800; - int video_inputs; /* number of video inputs */ - struct list_head devlist; + unsigned int analog_gpio; + unsigned int is_em2800:1; unsigned int has_tuner:1; unsigned int has_msp34xx:1; unsigned int has_tda9887:1; - unsigned int stream_on:1; /* Locks streams */ + int video_inputs; /* number of video inputs */ + struct list_head devlist; + u32 i2s_speed; /* I2S speed for audio digital stream */ enum em28xx_decoder decoder; @@ -351,6 +353,7 @@ extern const unsigned int em28xx_bcount; #define EM2800_AUDIOSRC_REG 0x08 /* em28xx registers */ +#define I2C_CLK_REG 0x06 #define CHIPID_REG 0x0a #define USBSUSP_REG 0x0c /* */ -- cgit v1.2.3 From a52932b405f23082f78ff12f4dd3e1741fcaab6f Mon Sep 17 00:00:00 2001 From: Markus Rechberger Date: Sat, 5 Jan 2008 09:55:47 -0300 Subject: V4L/DVB (6949): Adds em28xx-audio module em28xx-audio module exports em28xx Vendor Class audio as an -alsa driver. This module were written based on usbaudio driver by Markus Rechberger. Recently, he acked to allow us to merge it on kernel: http://lists-archives.org/video4linux/20408-supporting-prolink-pixelview-405-dvd-maker.html Thanks to Markus Rechberger Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 474 ++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 drivers/media/video/em28xx/em28xx-audio.c diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c new file mode 100644 index 00000000000..e1e1eda517a --- /dev/null +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -0,0 +1,474 @@ +/* + * Empiatech em28x1 audio extension + * + * Copyright (C) 2006 Markus Rechberger + * + * This driver is based on my previous au600 usb pstn audio driver + * and inherits all the copyrights + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include "em28xx.h" + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static int em28xx_cmd(struct em28xx *dev, int cmd,int arg); + + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + if(runtime->dma_area){ + if(runtime->dma_bytes > size) + return 0; + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if(!runtime ->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 0; +} + +static struct snd_pcm_hardware snd_em28xx_hw_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 62720*8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, //12544/2, + .period_bytes_max = 12544, + .periods_min = 2, + .periods_max = 98, //12544, +}; + +static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) +{ + int ret = 0; + int mode; + struct em28xx *dev = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + printk("opening radio device and trying to acquire exclusive lock\n"); + switch(dev->mode){ + case TUNER_STUB_DVBC_TV: + case TUNER_STUB_DVBT_TV: + case TUNER_STUB_ATSC_TV: + /* digital has no support for analog audio */ + if (ret != 0 ) { + printk("device is already in use by DVB-T\n"); + return -EINVAL; + } else { + struct v4l2_tuner tuner; + printk("switching device to FM mode\n"); + + mode = TUNER_STUB_RADIO; + memset(&tuner, 0x0, sizeof(struct v4l2_tuner)); + tuner.type = V4L2_TUNER_RADIO; + + /* enable GPIO for analog TV */ + dev->em28xx_gpio_control(dev, EM28XX_MODE, (void*)mode); + dev->mode = mode; + /* upload firmware */ + tuner_run_cmd(dev->tobj, TUNER_CMD_INIT, (void*)mode); + + /* required for devices which have kerneldriver dependencies */ +// em28xx_config(dev); +// em28xx_config_i2c(dev); + + /* this is moreover to switch the decoder to FM */ + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, &tuner); + + dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); + ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0); + /* TODO switch to FM mode */ + + printk("em28xx-audio: %d mode\n", mode); + tuner_run_cmd(dev->tobj, TUNER_CMD_G_MODE, &mode); + printk("retrieved mode from tuner: %d\n",mode); + } + break; + + case TUNER_STUB_ANALOG_TV: + printk("em28xx-audio: device is currently in analog TV mode\n"); + /* unmute by default */ + dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); + break; + case TUNER_STUB_RADIO: + /* check current mode and put a hard lock onto it */ + printk("em28xx-audio: device is currently in analogue FM mode\n"); + /* unmute by default here */ + dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); + ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); + if ( ret == 0 ) + printk("device is locked in fmradio mode now\n"); + break; + default: + printk("em28xx-audio: unhandled mode %d\n", dev->mode); + } + + runtime->hw = snd_em28xx_hw_capture; + if(dev->alt == 0 && dev->adev->users == 0 ) { + int errCode; + dev->alt = 7; + errCode = usb_set_interface(dev->udev, 0, 7); + printk("changing alternate number to 7\n"); + } + dev->adev->users++; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + dev->adev->capture_pcm_substream = substream; + runtime->private_data = dev; + return 0; +} + +static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + int amode = 0; + dev->adev->users--; + + /* decrease audio reference */ + switch(dev->mode) { + case TUNER_STUB_ANALOG_TV: + amode = EM28XX_VIDEO; + break; + case TUNER_STUB_RADIO: + amode = EM28XX_RADIO; + break; + default: + printk("invalid mode: %d\n",dev->mode); + break; + } + + dev->em28xx_acquire(dev, amode, 0); + + if(dev->adev->users == 0 && dev->adev->shutdown == 1) { + printk("audio users: %d\n",dev->adev->users); + printk("disabling audio stream!\n"); + dev->adev->shutdown = 0; + printk("released lock\n"); + em28xx_cmd(dev,EM28XX_CAPTURE_STREAM_EN,0); + } + return 0; +} + +static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) +{ + unsigned int channels, rate, format; + int ret; + ret = snd_pcm_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); + format = params_format(hw_params); + rate = params_rate(hw_params); + channels = params_channels(hw_params); + /* TODO: set up em28xx audio chip to deliver the correct audio format, current default is 48000hz multiplexed => 96000hz mono + which shouldn't matter since analogue TV only supports mono*/ + return 0; +} + +static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + if(dev->adev->capture_stream==STREAM_ON){ + em28xx_cmd(dev,EM28XX_CAPTURE_STREAM_EN,0); + } + return 0; +} + +static int snd_em28xx_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + switch(cmd){ + case SNDRV_PCM_TRIGGER_START: + em28xx_cmd(dev,EM28XX_CAPTURE_STREAM_EN,1); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + dev->adev->shutdown=1; + return 0; + default: + return -EINVAL; + } +} + +static void em28xx_audio_isocirq(struct urb *urb) +{ + struct em28xx *dev=urb->context; + int i; + unsigned int oldptr; + unsigned long flags; + int period_elapsed = 0; + int status; + unsigned char *cp; + unsigned int stride; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + if(dev->adev->capture_pcm_substream){ + substream=dev->adev->capture_pcm_substream; + runtime=substream->runtime; + + stride = runtime->frame_bits >> 3; + for(i=0;inumber_of_packets;i++){ + int length=urb->iso_frame_desc[i].actual_length/stride; + cp=(unsigned char *) urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if(!length) + continue; + + spin_lock_irqsave(&dev->adev->slock, flags); + oldptr = dev->adev->hwptr_done_capture; + dev->adev->hwptr_done_capture +=length; + if(dev->adev->hwptr_done_capture >= runtime->buffer_size) + dev->adev->hwptr_done_capture -= runtime->buffer_size; + + dev->adev->capture_transfer_done += length; + if(dev->adev->capture_transfer_done >= runtime->period_size){ + dev->adev->capture_transfer_done -= runtime->period_size; + period_elapsed=1; + } + spin_unlock_irqrestore(&dev->adev->slock, flags); + + if(oldptr + length >= runtime->buffer_size){ + unsigned int cnt = runtime->buffer_size-oldptr-1; + memcpy(runtime->dma_area+oldptr*stride, cp , cnt*stride); + memcpy(runtime->dma_area, cp + cnt, length*stride - cnt*stride); + } else { + memcpy(runtime->dma_area+oldptr*stride, cp, length*stride); + } + } + if(period_elapsed){ + snd_pcm_period_elapsed(substream); + } + } + urb->status = 0; + + if(dev->adev->shutdown) + return; + + if((status = usb_submit_urb(urb, GFP_ATOMIC))){ + em28xx_errdev("resubmit of audio urb failed (error=%i)\n", status); + } + return; +} + +static int em28xx_isoc_audio_deinit(struct em28xx *dev) +{ + int i; + for(i=0;iadev->urb[i]); + usb_free_urb(dev->adev->urb[i]); + dev->adev->urb[i]=NULL; + } + return 0; +} + +static int em28xx_init_audio_isoc(struct em28xx *dev) +{ + int i; + int errCode; + const int sb_size=EM28XX_NUM_AUDIO_PACKETS * EM28XX_AUDIO_MAX_PACKET_SIZE; + + + for(i=0;iadev->transfer_buffer[i]=kmalloc(sb_size,GFP_ATOMIC); + if(!dev->adev->transfer_buffer[i]){ + return -ENOMEM; + } + memset(dev->adev->transfer_buffer[i],0x80,sb_size); + urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS,GFP_ATOMIC); + if(urb){ + urb->dev=dev->udev; + urb->context=dev; + urb->pipe=usb_rcvisocpipe(dev->udev,0x83); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->adev->transfer_buffer[i]; + urb->interval=1; + urb->complete = em28xx_audio_isocirq; + urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; + urb->transfer_buffer_length = sb_size; + for(j=k=0; jiso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length=EM28XX_AUDIO_MAX_PACKET_SIZE; + } + dev->adev->urb[i]=urb; + } else { + return -ENOMEM; + } + } + for(i=0;iadev->urb[i], GFP_ATOMIC); + if (errCode){ + em28xx_isoc_audio_deinit(dev); + return errCode; + } + } + return 0; +} + + +static int em28xx_cmd(struct em28xx *dev, int cmd,int arg) +{ + switch(cmd){ + case EM28XX_CAPTURE_STREAM_EN: + if(dev->adev->capture_stream == STREAM_OFF && arg==1){ + dev->adev->capture_stream=STREAM_ON; + em28xx_init_audio_isoc(dev); + } else if (dev->adev->capture_stream==STREAM_ON && arg==0){ + dev->adev->capture_stream=STREAM_OFF; + em28xx_isoc_audio_deinit(dev); + } else { + printk("An underrun occured very likely... ignoring it\n"); + } + return 0; + default: + return -EINVAL; + } +} + +static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream *substream) +{ + struct em28xx *dev; + snd_pcm_uframes_t hwptr_done; + dev = snd_pcm_substream_chip(substream); + hwptr_done = dev->adev->hwptr_done_capture; + return hwptr_done; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +static struct snd_pcm_ops snd_em28xx_pcm_capture = { + .open = snd_em28xx_capture_open, + .close = snd_em28xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_em28xx_hw_capture_params, + .hw_free = snd_em28xx_hw_capture_free, + .prepare = snd_em28xx_prepare, + .trigger = snd_em28xx_capture_trigger, + .pointer = snd_em28xx_capture_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + + +static int em28xx_audio_init(struct em28xx *dev) +{ + struct em28xx_audio *adev; + struct snd_pcm *pcm; + struct snd_card *card; + static int devnr; + int ret; + int err; + printk("em28xx-audio.c: probing for em28x1 non standard usbaudio\n"); + printk("em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); + adev=kzalloc(sizeof(*adev),GFP_KERNEL); + if(!adev){ + printk("em28xx-audio.c: out of memory\n"); + return -1; + } + card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE,0); + if(card==NULL){ + kfree(adev); + return -ENOMEM; + } + + spin_lock_init(&adev->slock); + ret=snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); + pcm->info_flags = 0; + pcm->private_data = dev; + strcpy(pcm->name,"Empia 28xx Capture"); + strcpy(card->driver, "Empia Em28xx Audio"); + strcpy(card->shortname, "Em28xx Audio"); + strcpy(card->longname,"Empia Em28xx Audio"); + + if((err = snd_card_register(card))<0){ + snd_card_free(card); + return -ENOMEM; + } + adev->sndcard=card; + adev->udev=dev->udev; + dev->adev=adev; + return 0; +} + +static int em28xx_audio_fini(struct em28xx *dev) +{ + if(dev==NULL) + return 0; + if(dev->adev){ + snd_card_free(dev->adev->sndcard); + kfree(dev->adev); + dev->adev=NULL; + } + return 0; +} + +static struct em28xx_ops audio_ops = { + .id = EM28XX_AUDIO, + .name = "Em28xx Audio Extension", + .init = em28xx_audio_init, + .fini = em28xx_audio_fini, +}; + +static int __init em28xx_alsa_register(void) +{ + request_module("em28xx"); + request_module("tuner"); + return em28xx_register_extension(&audio_ops); +} + +static void __exit em28xx_alsa_unregister(void) +{ + em28xx_unregister_extension(&audio_ops); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Markus Rechberger "); +MODULE_DESCRIPTION("Em28xx Audio driver"); + +module_init(em28xx_alsa_register); +module_exit(em28xx_alsa_unregister); -- cgit v1.2.3 From 1a6f11e0e8db9e76ef34bc6731d5291e4df1ba37 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 09:56:24 -0300 Subject: V4L/DVB (6950): Lindent em28xx-audio.c Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 373 ++++++++++++++++-------------- 1 file changed, 197 insertions(+), 176 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index e1e1eda517a..c631cac4c5d 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -44,37 +44,39 @@ #include "em28xx.h" static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static int em28xx_cmd(struct em28xx *dev, int cmd,int arg); +static int em28xx_cmd(struct em28xx *dev, int cmd, int arg); - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) { struct snd_pcm_runtime *runtime = subs->runtime; - if(runtime->dma_area){ - if(runtime->dma_bytes > size) + if (runtime->dma_area) { + if (runtime->dma_bytes > size) return 0; vfree(runtime->dma_area); } runtime->dma_area = vmalloc(size); - if(!runtime ->dma_area) + if (!runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; return 0; } static struct snd_pcm_hardware snd_em28xx_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID, + .info = + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, .rate_min = 48000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = 62720*8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, //12544/2, + .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, //12544/2, .period_bytes_max = 12544, .periods_min = 2, - .periods_max = 98, //12544, + .periods_max = 98, //12544, }; static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) @@ -84,66 +86,68 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) struct em28xx *dev = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; printk("opening radio device and trying to acquire exclusive lock\n"); - switch(dev->mode){ - case TUNER_STUB_DVBC_TV: - case TUNER_STUB_DVBT_TV: - case TUNER_STUB_ATSC_TV: - /* digital has no support for analog audio */ - if (ret != 0 ) { - printk("device is already in use by DVB-T\n"); - return -EINVAL; - } else { - struct v4l2_tuner tuner; - printk("switching device to FM mode\n"); - - mode = TUNER_STUB_RADIO; - memset(&tuner, 0x0, sizeof(struct v4l2_tuner)); - tuner.type = V4L2_TUNER_RADIO; - - /* enable GPIO for analog TV */ - dev->em28xx_gpio_control(dev, EM28XX_MODE, (void*)mode); - dev->mode = mode; - /* upload firmware */ - tuner_run_cmd(dev->tobj, TUNER_CMD_INIT, (void*)mode); - - /* required for devices which have kerneldriver dependencies */ -// em28xx_config(dev); -// em28xx_config_i2c(dev); - - /* this is moreover to switch the decoder to FM */ - em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, &tuner); - - dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); - ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0); - /* TODO switch to FM mode */ - - printk("em28xx-audio: %d mode\n", mode); - tuner_run_cmd(dev->tobj, TUNER_CMD_G_MODE, &mode); - printk("retrieved mode from tuner: %d\n",mode); - } - break; - - case TUNER_STUB_ANALOG_TV: - printk("em28xx-audio: device is currently in analog TV mode\n"); - /* unmute by default */ - dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); - break; - case TUNER_STUB_RADIO: - /* check current mode and put a hard lock onto it */ - printk("em28xx-audio: device is currently in analogue FM mode\n"); - /* unmute by default here */ - dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); - ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); - if ( ret == 0 ) - printk("device is locked in fmradio mode now\n"); - break; - default: - printk("em28xx-audio: unhandled mode %d\n", dev->mode); + switch (dev->mode) { + case TUNER_STUB_DVBC_TV: + case TUNER_STUB_DVBT_TV: + case TUNER_STUB_ATSC_TV: + /* digital has no support for analog audio */ + if (ret != 0) { + printk("device is already in use by DVB-T\n"); + return -EINVAL; + } else { + struct v4l2_tuner tuner; + printk("switching device to FM mode\n"); + + mode = TUNER_STUB_RADIO; + memset(&tuner, 0x0, sizeof(struct v4l2_tuner)); + tuner.type = V4L2_TUNER_RADIO; + + /* enable GPIO for analog TV */ + dev->em28xx_gpio_control(dev, EM28XX_MODE, + (void *)mode); + dev->mode = mode; + /* upload firmware */ + tuner_run_cmd(dev->tobj, TUNER_CMD_INIT, (void *)mode); + + /* required for devices which have kerneldriver dependencies */ +// em28xx_config(dev); +// em28xx_config_i2c(dev); + + /* this is moreover to switch the decoder to FM */ + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, &tuner); + + dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); + ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0); + /* TODO switch to FM mode */ + + printk("em28xx-audio: %d mode\n", mode); + tuner_run_cmd(dev->tobj, TUNER_CMD_G_MODE, &mode); + printk("retrieved mode from tuner: %d\n", mode); + } + break; + + case TUNER_STUB_ANALOG_TV: + printk("em28xx-audio: device is currently in analog TV mode\n"); + /* unmute by default */ + dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); + break; + case TUNER_STUB_RADIO: + /* check current mode and put a hard lock onto it */ + printk + ("em28xx-audio: device is currently in analogue FM mode\n"); + /* unmute by default here */ + dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); + ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); + if (ret == 0) + printk("device is locked in fmradio mode now\n"); + break; + default: + printk("em28xx-audio: unhandled mode %d\n", dev->mode); } runtime->hw = snd_em28xx_hw_capture; - if(dev->alt == 0 && dev->adev->users == 0 ) { + if (dev->alt == 0 && dev->adev->users == 0) { int errCode; dev->alt = 7; errCode = usb_set_interface(dev->udev, 0, 7); @@ -163,48 +167,51 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) dev->adev->users--; /* decrease audio reference */ - switch(dev->mode) { - case TUNER_STUB_ANALOG_TV: - amode = EM28XX_VIDEO; - break; - case TUNER_STUB_RADIO: - amode = EM28XX_RADIO; - break; - default: - printk("invalid mode: %d\n",dev->mode); - break; + switch (dev->mode) { + case TUNER_STUB_ANALOG_TV: + amode = EM28XX_VIDEO; + break; + case TUNER_STUB_RADIO: + amode = EM28XX_RADIO; + break; + default: + printk("invalid mode: %d\n", dev->mode); + break; } - dev->em28xx_acquire(dev, amode, 0); + dev->em28xx_acquire(dev, amode, 0); - if(dev->adev->users == 0 && dev->adev->shutdown == 1) { - printk("audio users: %d\n",dev->adev->users); + if (dev->adev->users == 0 && dev->adev->shutdown == 1) { + printk("audio users: %d\n", dev->adev->users); printk("disabling audio stream!\n"); dev->adev->shutdown = 0; printk("released lock\n"); - em28xx_cmd(dev,EM28XX_CAPTURE_STREAM_EN,0); + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); } return 0; } -static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) +static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { unsigned int channels, rate, format; int ret; - ret = snd_pcm_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); + ret = + snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); format = params_format(hw_params); rate = params_rate(hw_params); channels = params_channels(hw_params); /* TODO: set up em28xx audio chip to deliver the correct audio format, current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono*/ + which shouldn't matter since analogue TV only supports mono */ return 0; } static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) { struct em28xx *dev = snd_pcm_substream_chip(substream); - if(dev->adev->capture_stream==STREAM_ON){ - em28xx_cmd(dev,EM28XX_CAPTURE_STREAM_EN,0); + if (dev->adev->capture_stream == STREAM_ON) { + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); } return 0; } @@ -214,24 +221,25 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream) return 0; } -static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, int cmd) +static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, + int cmd) { struct em28xx *dev = snd_pcm_substream_chip(substream); - switch(cmd){ - case SNDRV_PCM_TRIGGER_START: - em28xx_cmd(dev,EM28XX_CAPTURE_STREAM_EN,1); - return 0; - case SNDRV_PCM_TRIGGER_STOP: - dev->adev->shutdown=1; - return 0; - default: - return -EINVAL; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + dev->adev->shutdown = 1; + return 0; + default: + return -EINVAL; } } static void em28xx_audio_isocirq(struct urb *urb) { - struct em28xx *dev=urb->context; + struct em28xx *dev = urb->context; int i; unsigned int oldptr; unsigned long flags; @@ -241,50 +249,61 @@ static void em28xx_audio_isocirq(struct urb *urb) unsigned int stride; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; - if(dev->adev->capture_pcm_substream){ - substream=dev->adev->capture_pcm_substream; - runtime=substream->runtime; + if (dev->adev->capture_pcm_substream) { + substream = dev->adev->capture_pcm_substream; + runtime = substream->runtime; stride = runtime->frame_bits >> 3; - for(i=0;inumber_of_packets;i++){ - int length=urb->iso_frame_desc[i].actual_length/stride; - cp=(unsigned char *) urb->transfer_buffer + urb->iso_frame_desc[i].offset; + for (i = 0; i < urb->number_of_packets; i++) { + int length = + urb->iso_frame_desc[i].actual_length / stride; + cp = (unsigned char *)urb->transfer_buffer + + urb->iso_frame_desc[i].offset; - if(!length) + if (!length) continue; spin_lock_irqsave(&dev->adev->slock, flags); oldptr = dev->adev->hwptr_done_capture; - dev->adev->hwptr_done_capture +=length; - if(dev->adev->hwptr_done_capture >= runtime->buffer_size) - dev->adev->hwptr_done_capture -= runtime->buffer_size; + dev->adev->hwptr_done_capture += length; + if (dev->adev->hwptr_done_capture >= + runtime->buffer_size) + dev->adev->hwptr_done_capture -= + runtime->buffer_size; dev->adev->capture_transfer_done += length; - if(dev->adev->capture_transfer_done >= runtime->period_size){ - dev->adev->capture_transfer_done -= runtime->period_size; - period_elapsed=1; + if (dev->adev->capture_transfer_done >= + runtime->period_size) { + dev->adev->capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; } spin_unlock_irqrestore(&dev->adev->slock, flags); - if(oldptr + length >= runtime->buffer_size){ - unsigned int cnt = runtime->buffer_size-oldptr-1; - memcpy(runtime->dma_area+oldptr*stride, cp , cnt*stride); - memcpy(runtime->dma_area, cp + cnt, length*stride - cnt*stride); + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = + runtime->buffer_size - oldptr - 1; + memcpy(runtime->dma_area + oldptr * stride, cp, + cnt * stride); + memcpy(runtime->dma_area, cp + cnt, + length * stride - cnt * stride); } else { - memcpy(runtime->dma_area+oldptr*stride, cp, length*stride); + memcpy(runtime->dma_area + oldptr * stride, cp, + length * stride); } } - if(period_elapsed){ + if (period_elapsed) { snd_pcm_period_elapsed(substream); } } urb->status = 0; - - if(dev->adev->shutdown) + + if (dev->adev->shutdown) return; - if((status = usb_submit_urb(urb, GFP_ATOMIC))){ - em28xx_errdev("resubmit of audio urb failed (error=%i)\n", status); + if ((status = usb_submit_urb(urb, GFP_ATOMIC))) { + em28xx_errdev("resubmit of audio urb failed (error=%i)\n", + status); } return; } @@ -292,10 +311,10 @@ static void em28xx_audio_isocirq(struct urb *urb) static int em28xx_isoc_audio_deinit(struct em28xx *dev) { int i; - for(i=0;iadev->urb[i]); usb_free_urb(dev->adev->urb[i]); - dev->adev->urb[i]=NULL; + dev->adev->urb[i] = NULL; } return 0; } @@ -304,40 +323,42 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) { int i; int errCode; - const int sb_size=EM28XX_NUM_AUDIO_PACKETS * EM28XX_AUDIO_MAX_PACKET_SIZE; + const int sb_size = + EM28XX_NUM_AUDIO_PACKETS * EM28XX_AUDIO_MAX_PACKET_SIZE; - - for(i=0;iadev->transfer_buffer[i]=kmalloc(sb_size,GFP_ATOMIC); - if(!dev->adev->transfer_buffer[i]){ + int j, k; + dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); + if (!dev->adev->transfer_buffer[i]) { return -ENOMEM; } - memset(dev->adev->transfer_buffer[i],0x80,sb_size); - urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS,GFP_ATOMIC); - if(urb){ - urb->dev=dev->udev; - urb->context=dev; - urb->pipe=usb_rcvisocpipe(dev->udev,0x83); + memset(dev->adev->transfer_buffer[i], 0x80, sb_size); + urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); + if (urb) { + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->adev->transfer_buffer[i]; - urb->interval=1; + urb->interval = 1; urb->complete = em28xx_audio_isocirq; urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; urb->transfer_buffer_length = sb_size; - for(j=k=0; jiso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length=EM28XX_AUDIO_MAX_PACKET_SIZE; + urb->iso_frame_desc[j].length = + EM28XX_AUDIO_MAX_PACKET_SIZE; } - dev->adev->urb[i]=urb; + dev->adev->urb[i] = urb; } else { return -ENOMEM; } } - for(i=0;iadev->urb[i], GFP_ATOMIC); - if (errCode){ + if (errCode) { em28xx_isoc_audio_deinit(dev); return errCode; } @@ -345,27 +366,28 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) return 0; } - -static int em28xx_cmd(struct em28xx *dev, int cmd,int arg) +static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) { - switch(cmd){ - case EM28XX_CAPTURE_STREAM_EN: - if(dev->adev->capture_stream == STREAM_OFF && arg==1){ - dev->adev->capture_stream=STREAM_ON; - em28xx_init_audio_isoc(dev); - } else if (dev->adev->capture_stream==STREAM_ON && arg==0){ - dev->adev->capture_stream=STREAM_OFF; - em28xx_isoc_audio_deinit(dev); - } else { - printk("An underrun occured very likely... ignoring it\n"); - } - return 0; - default: - return -EINVAL; + switch (cmd) { + case EM28XX_CAPTURE_STREAM_EN: + if (dev->adev->capture_stream == STREAM_OFF && arg == 1) { + dev->adev->capture_stream = STREAM_ON; + em28xx_init_audio_isoc(dev); + } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) { + dev->adev->capture_stream = STREAM_OFF; + em28xx_isoc_audio_deinit(dev); + } else { + printk + ("An underrun occured very likely... ignoring it\n"); + } + return 0; + default: + return -EINVAL; } } -static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream + *substream) { struct em28xx *dev; snd_pcm_uframes_t hwptr_done; @@ -393,7 +415,6 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = { .page = snd_pcm_get_vmalloc_page, }; - static int em28xx_audio_init(struct em28xx *dev) { struct em28xx_audio *adev; @@ -404,54 +425,54 @@ static int em28xx_audio_init(struct em28xx *dev) int err; printk("em28xx-audio.c: probing for em28x1 non standard usbaudio\n"); printk("em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); - adev=kzalloc(sizeof(*adev),GFP_KERNEL); - if(!adev){ + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) { printk("em28xx-audio.c: out of memory\n"); return -1; } - card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE,0); - if(card==NULL){ + card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0); + if (card == NULL) { kfree(adev); return -ENOMEM; } spin_lock_init(&adev->slock); - ret=snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); + ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); pcm->info_flags = 0; pcm->private_data = dev; - strcpy(pcm->name,"Empia 28xx Capture"); + strcpy(pcm->name, "Empia 28xx Capture"); strcpy(card->driver, "Empia Em28xx Audio"); strcpy(card->shortname, "Em28xx Audio"); - strcpy(card->longname,"Empia Em28xx Audio"); + strcpy(card->longname, "Empia Em28xx Audio"); - if((err = snd_card_register(card))<0){ + if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return -ENOMEM; } - adev->sndcard=card; - adev->udev=dev->udev; - dev->adev=adev; + adev->sndcard = card; + adev->udev = dev->udev; + dev->adev = adev; return 0; } static int em28xx_audio_fini(struct em28xx *dev) { - if(dev==NULL) + if (dev == NULL) return 0; - if(dev->adev){ + if (dev->adev) { snd_card_free(dev->adev->sndcard); kfree(dev->adev); - dev->adev=NULL; + dev->adev = NULL; } return 0; } static struct em28xx_ops audio_ops = { - .id = EM28XX_AUDIO, - .name = "Em28xx Audio Extension", - .init = em28xx_audio_init, - .fini = em28xx_audio_fini, + .id = EM28XX_AUDIO, + .name = "Em28xx Audio Extension", + .init = em28xx_audio_init, + .fini = em28xx_audio_fini, }; static int __init em28xx_alsa_register(void) -- cgit v1.2.3 From 6d79468dd8537530f4150e76ed9b4b63f80571c6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 09:57:31 -0300 Subject: V4L/DVB (6951): Integrates em28xx-audio.c into em28xx kernel module Also fixes the remaining CodingStyle issues that Lindent didn't fix. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/Kconfig | 15 + drivers/media/video/em28xx/Makefile | 3 + drivers/media/video/em28xx/em28xx-audio.c | 507 +++++++++++++++--------------- drivers/media/video/em28xx/em28xx-video.c | 63 +++- drivers/media/video/em28xx/em28xx.h | 37 +++ 5 files changed, 365 insertions(+), 260 deletions(-) diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 813077b6ef7..abbd38c1ebb 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -11,3 +11,18 @@ config VIDEO_EM28XX To compile this driver as a module, choose M here: the module will be called em28xx + +config VIDEO_EM28XX_ALSA + depends on VIDEO_EM28XX + tristate "Empia EM28xx ALSA audio module" + ---help--- + This is an ALSA driver for some Empia 28xx based TV cards. + + This is not required for em2800/em2820/em2821 boards. However, + newer em28xx devices uses Vendor Class for audio, instead of + implementing the USB Audio Class. For those chips, this module + will enable digital audio. + + To compile this driver as a module, choose M here: the + module will be called em28xx-alsa + diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 7e7a93d75c3..0924550992d 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -1,7 +1,10 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ em28xx-input.o +em28xx-alsa-objs := em28xx-audio.o + obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o +obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o EXTRA_CFLAGS += -Idrivers/media/video EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index c631cac4c5d..c91ff52aefa 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -3,6 +3,10 @@ * * Copyright (C) 2006 Markus Rechberger * + * Copyright (C) 2007 Mauro Carvalho Chehab + * - Port to work with the in-kernel driver + * - Several cleanups + * * This driver is based on my previous au600 usb pstn audio driver * and inherits all the copyrights * @@ -30,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,222 +42,52 @@ #include #include #include -//#include -//#include #include #include "em28xx.h" -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static int em28xx_cmd(struct em28xx *dev, int cmd, int arg); - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); -static struct snd_pcm_hardware snd_em28xx_hw_capture = { - .info = - SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, //12544/2, - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, //12544, -}; +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_INFO "em28xx-audio %s: " fmt, \ + __FUNCTION__, ##arg); \ + } while (0) -static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) -{ - int ret = 0; - int mode; - struct em28xx *dev = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - printk("opening radio device and trying to acquire exclusive lock\n"); - switch (dev->mode) { - case TUNER_STUB_DVBC_TV: - case TUNER_STUB_DVBT_TV: - case TUNER_STUB_ATSC_TV: - /* digital has no support for analog audio */ - if (ret != 0) { - printk("device is already in use by DVB-T\n"); - return -EINVAL; - } else { - struct v4l2_tuner tuner; - printk("switching device to FM mode\n"); - - mode = TUNER_STUB_RADIO; - memset(&tuner, 0x0, sizeof(struct v4l2_tuner)); - tuner.type = V4L2_TUNER_RADIO; - - /* enable GPIO for analog TV */ - dev->em28xx_gpio_control(dev, EM28XX_MODE, - (void *)mode); - dev->mode = mode; - /* upload firmware */ - tuner_run_cmd(dev->tobj, TUNER_CMD_INIT, (void *)mode); - - /* required for devices which have kerneldriver dependencies */ -// em28xx_config(dev); -// em28xx_config_i2c(dev); - - /* this is moreover to switch the decoder to FM */ - em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, &tuner); - - dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); - ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, 0); - /* TODO switch to FM mode */ - - printk("em28xx-audio: %d mode\n", mode); - tuner_run_cmd(dev->tobj, TUNER_CMD_G_MODE, &mode); - printk("retrieved mode from tuner: %d\n", mode); - } - break; - - case TUNER_STUB_ANALOG_TV: - printk("em28xx-audio: device is currently in analog TV mode\n"); - /* unmute by default */ - dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); - break; - case TUNER_STUB_RADIO: - /* check current mode and put a hard lock onto it */ - printk - ("em28xx-audio: device is currently in analogue FM mode\n"); - /* unmute by default here */ - dev->em28xx_write_regs(dev, 0x0f, "\x87", 1); - ret = dev->em28xx_acquire(dev, EM28XX_RADIO, 1); - if (ret == 0) - printk("device is locked in fmradio mode now\n"); - break; - default: - printk("em28xx-audio: unhandled mode %d\n", dev->mode); - } - - runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev->users == 0) { - int errCode; - dev->alt = 7; - errCode = usb_set_interface(dev->udev, 0, 7); - printk("changing alternate number to 7\n"); - } - dev->adev->users++; - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - dev->adev->capture_pcm_substream = substream; - runtime->private_data = dev; - return 0; -} - -static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - int amode = 0; - dev->adev->users--; - - /* decrease audio reference */ - switch (dev->mode) { - case TUNER_STUB_ANALOG_TV: - amode = EM28XX_VIDEO; - break; - case TUNER_STUB_RADIO: - amode = EM28XX_RADIO; - break; - default: - printk("invalid mode: %d\n", dev->mode); - break; - } - - dev->em28xx_acquire(dev, amode, 0); - - if (dev->adev->users == 0 && dev->adev->shutdown == 1) { - printk("audio users: %d\n", dev->adev->users); - printk("disabling audio stream!\n"); - dev->adev->shutdown = 0; - printk("released lock\n"); - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); - } - return 0; -} +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int em28xx_isoc_audio_deinit(struct em28xx *dev) { - unsigned int channels, rate, format; - int ret; - ret = - snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - format = params_format(hw_params); - rate = params_rate(hw_params); - channels = params_channels(hw_params); - /* TODO: set up em28xx audio chip to deliver the correct audio format, current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ - return 0; -} + int i; -static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - if (dev->adev->capture_stream == STREAM_ON) { - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); + dprintk("Stopping isoc\n"); + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + usb_kill_urb(dev->adev->urb[i]); + usb_free_urb(dev->adev->urb[i]); + dev->adev->urb[i] = NULL; } - return 0; -} -static int snd_em28xx_prepare(struct snd_pcm_substream *substream) -{ return 0; } -static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); - return 0; - case SNDRV_PCM_TRIGGER_STOP: - dev->adev->shutdown = 1; - return 0; - default: - return -EINVAL; - } -} - static void em28xx_audio_isocirq(struct urb *urb) { - struct em28xx *dev = urb->context; - int i; - unsigned int oldptr; - unsigned long flags; - int period_elapsed = 0; - int status; - unsigned char *cp; - unsigned int stride; + struct em28xx *dev = urb->context; + int i; + unsigned int oldptr; + unsigned long flags; + int period_elapsed = 0; + int status; + unsigned char *cp; + unsigned int stride; struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; + struct snd_pcm_runtime *runtime; if (dev->adev->capture_pcm_substream) { substream = dev->adev->capture_pcm_substream; runtime = substream->runtime; - stride = runtime->frame_bits >> 3; + for (i = 0; i < urb->number_of_packets; i++) { int length = urb->iso_frame_desc[i].actual_length / stride; @@ -264,6 +98,7 @@ static void em28xx_audio_isocirq(struct urb *urb) continue; spin_lock_irqsave(&dev->adev->slock, flags); + oldptr = dev->adev->hwptr_done_capture; dev->adev->hwptr_done_capture += length; if (dev->adev->hwptr_done_capture >= @@ -278,6 +113,7 @@ static void em28xx_audio_isocirq(struct urb *urb) runtime->period_size; period_elapsed = 1; } + spin_unlock_irqrestore(&dev->adev->slock, flags); if (oldptr + length >= runtime->buffer_size) { @@ -292,82 +128,79 @@ static void em28xx_audio_isocirq(struct urb *urb) length * stride); } } - if (period_elapsed) { + if (period_elapsed) snd_pcm_period_elapsed(substream); - } } urb->status = 0; if (dev->adev->shutdown) return; - if ((status = usb_submit_urb(urb, GFP_ATOMIC))) { + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { em28xx_errdev("resubmit of audio urb failed (error=%i)\n", status); } return; } -static int em28xx_isoc_audio_deinit(struct em28xx *dev) -{ - int i; - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_kill_urb(dev->adev->urb[i]); - usb_free_urb(dev->adev->urb[i]); - dev->adev->urb[i] = NULL; - } - return 0; -} - static int em28xx_init_audio_isoc(struct em28xx *dev) { - int i; - int errCode; - const int sb_size = - EM28XX_NUM_AUDIO_PACKETS * EM28XX_AUDIO_MAX_PACKET_SIZE; + int i, errCode; + const int sb_size = EM28XX_NUM_AUDIO_PACKETS * + EM28XX_AUDIO_MAX_PACKET_SIZE; + + dprintk("Starting isoc transfers\n"); for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { struct urb *urb; int j, k; + dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev->transfer_buffer[i]) { + if (!dev->adev->transfer_buffer[i]) return -ENOMEM; - } + memset(dev->adev->transfer_buffer[i], 0x80, sb_size); urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (urb) { - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev->transfer_buffer[i]; - urb->interval = 1; - urb->complete = em28xx_audio_isocirq; - urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; - urb->transfer_buffer_length = sb_size; - for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; - j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - EM28XX_AUDIO_MAX_PACKET_SIZE; - } - dev->adev->urb[i] = urb; - } else { + if (!urb) return -ENOMEM; + + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->adev->transfer_buffer[i]; + urb->interval = 1; + urb->complete = em28xx_audio_isocirq; + urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; + urb->transfer_buffer_length = sb_size; + + for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; + j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + EM28XX_AUDIO_MAX_PACKET_SIZE; } + dev->adev->urb[i] = urb; } + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC); if (errCode) { em28xx_isoc_audio_deinit(dev); + return errCode; } } + return 0; } static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) { + dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)? + "stop" : "start"); + switch (cmd) { case EM28XX_CAPTURE_STREAM_EN: if (dev->adev->capture_stream == STREAM_OFF && arg == 1) { @@ -377,8 +210,8 @@ static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) dev->adev->capture_stream = STREAM_OFF; em28xx_isoc_audio_deinit(dev); } else { - printk - ("An underrun occured very likely... ignoring it\n"); + printk(KERN_ERR "An underrun very likely occurred. " + "Ignoring it.\n"); } return 0; default: @@ -386,13 +219,167 @@ static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) } } +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Alocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static struct snd_pcm_hardware snd_em28xx_hw_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, /* 12544/2, */ + .period_bytes_max = 12544, + .periods_min = 2, + .periods_max = 98, /* 12544, */ +}; + +static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + dprintk("opening device and trying to acquire exclusive lock\n"); + + /* Sets volume, mute, etc */ + dev->mute = 0; + ret = em28xx_audio_analog_set(dev); + if (ret < 0) + goto err; + + runtime->hw = snd_em28xx_hw_capture; + if (dev->alt == 0 && dev->adev->users == 0) { + int errCode; + dev->alt = 7; + errCode = usb_set_interface(dev->udev, 0, 7); + dprintk("changing alternate number to 7\n"); + } + + dev->adev->users++; + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + dev->adev->capture_pcm_substream = substream; + runtime->private_data = dev; + + return 0; +err: + printk(KERN_ERR "Error while configuring em28xx mixer\n"); + return ret; +} + +static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + dev->adev->users--; + + dprintk("closing device\n"); + + dev->mute = 1; + em28xx_audio_analog_set(dev); + + if (dev->adev->users == 0 && dev->adev->shutdown == 1) { + dprintk("audio users: %d\n", dev->adev->users); + dprintk("disabling audio stream!\n"); + dev->adev->shutdown = 0; + dprintk("released lock\n"); + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); + } + return 0; +} + +static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + unsigned int channels, rate, format; + int ret; + + dprintk("Setting capture parameters\n"); + + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + format = params_format(hw_params); + rate = params_rate(hw_params); + channels = params_channels(hw_params); + + /* TODO: set up em28xx audio chip to deliver the correct audio format, + current default is 48000hz multiplexed => 96000hz mono + which shouldn't matter since analogue TV only supports mono */ + return 0; +} + +static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dprintk("Stop capture, if needed\n"); + + if (dev->adev->capture_stream == STREAM_ON) + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); + + return 0; +} + +static int snd_em28xx_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)? + "start": "stop"); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + dev->adev->shutdown = 1; + return 0; + default: + return -EINVAL; + } +} + static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream *substream) { struct em28xx *dev; + snd_pcm_uframes_t hwptr_done; dev = snd_pcm_substream_chip(substream); hwptr_done = dev->adev->hwptr_done_capture; + return hwptr_done; } @@ -400,34 +387,38 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset) { void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); } static struct snd_pcm_ops snd_em28xx_pcm_capture = { - .open = snd_em28xx_capture_open, - .close = snd_em28xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, + .open = snd_em28xx_capture_open, + .close = snd_em28xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_em28xx_hw_capture_params, - .hw_free = snd_em28xx_hw_capture_free, - .prepare = snd_em28xx_prepare, - .trigger = snd_em28xx_capture_trigger, - .pointer = snd_em28xx_capture_pointer, - .page = snd_pcm_get_vmalloc_page, + .hw_free = snd_em28xx_hw_capture_free, + .prepare = snd_em28xx_prepare, + .trigger = snd_em28xx_capture_trigger, + .pointer = snd_em28xx_capture_pointer, + .page = snd_pcm_get_vmalloc_page, }; static int em28xx_audio_init(struct em28xx *dev) { struct em28xx_audio *adev; - struct snd_pcm *pcm; - struct snd_card *card; - static int devnr; - int ret; - int err; - printk("em28xx-audio.c: probing for em28x1 non standard usbaudio\n"); - printk("em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); + struct snd_pcm *pcm; + struct snd_card *card; + static int devnr; + int ret, err; + + printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " + "non standard usbaudio\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " + "Rechberger\n"); + adev = kzalloc(sizeof(*adev), GFP_KERNEL); if (!adev) { - printk("em28xx-audio.c: out of memory\n"); + printk(KERN_ERR "em28xx-audio.c: out of memory\n"); return -1; } card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0); @@ -446,13 +437,15 @@ static int em28xx_audio_init(struct em28xx *dev) strcpy(card->shortname, "Em28xx Audio"); strcpy(card->longname, "Empia Em28xx Audio"); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return -ENOMEM; } adev->sndcard = card; adev->udev = dev->udev; dev->adev = adev; + return 0; } @@ -460,16 +453,18 @@ static int em28xx_audio_fini(struct em28xx *dev) { if (dev == NULL) return 0; + if (dev->adev) { snd_card_free(dev->adev->sndcard); kfree(dev->adev); dev->adev = NULL; } + return 0; } static struct em28xx_ops audio_ops = { - .id = EM28XX_AUDIO, + .id = EM28XX_AUDIO, .name = "Em28xx Audio Extension", .init = em28xx_audio_init, .fini = em28xx_audio_fini, @@ -478,7 +473,6 @@ static struct em28xx_ops audio_ops = { static int __init em28xx_alsa_register(void) { request_module("em28xx"); - request_module("tuner"); return em28xx_register_extension(&audio_ops); } @@ -489,6 +483,7 @@ static void __exit em28xx_alsa_unregister(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Markus Rechberger "); +MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_DESCRIPTION("Em28xx Audio driver"); module_init(em28xx_alsa_register); diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 1a284cb18c2..caa4757b7eb 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1599,9 +1599,48 @@ static const struct video_device em28xx_video_template = { .current_norm = V4L2_STD_PAL, }; - /******************************** usb interface *****************************************/ + +static LIST_HEAD(em28xx_extension_devlist); +static DEFINE_MUTEX(em28xx_extension_devlist_lock); + +int em28xx_register_extension(struct em28xx_ops *ops) +{ + struct em28xx *h, *dev = NULL; + + list_for_each_entry(h, &em28xx_devlist, devlist) + dev = h; + + mutex_lock(&em28xx_extension_devlist_lock); + list_add_tail(&ops->next, &em28xx_extension_devlist); + if (dev) + ops->init(dev); + + printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); + mutex_unlock(&em28xx_extension_devlist_lock); + + return 0; +} +EXPORT_SYMBOL(em28xx_register_extension); + +void em28xx_unregister_extension(struct em28xx_ops *ops) +{ + struct em28xx *h, *dev = NULL; + + list_for_each_entry(h, &em28xx_devlist, devlist) + dev = h; + + if (dev) + ops->fini(dev); + + mutex_lock(&em28xx_extension_devlist_lock); + printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&em28xx_extension_devlist_lock); +} +EXPORT_SYMBOL(em28xx_unregister_extension); + /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -1609,6 +1648,7 @@ static const struct video_device em28xx_video_template = { static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, int minor) { + struct em28xx_ops *ops = NULL; struct em28xx *dev = *devhandle; int retval = -ENOMEM; int errCode; @@ -1742,6 +1782,15 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); + mutex_lock(&em28xx_extension_devlist_lock); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->id) + ops->init(dev); + } + } + mutex_unlock(&em28xx_extension_devlist_lock); + return 0; } @@ -1862,6 +1911,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, static void em28xx_usb_disconnect(struct usb_interface *interface) { struct em28xx *dev; + struct em28xx_ops *ops = NULL; dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); @@ -1891,15 +1941,20 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->state |= DEV_DISCONNECTED; em28xx_release_resources(dev); } - - mutex_unlock(&dev->lock); + mutex_lock(&em28xx_extension_devlist_lock); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + ops->fini(dev); + } + } + mutex_unlock(&em28xx_extension_devlist_lock); + if (!dev->users) { kfree(dev->alt_max_pkt_size); kfree(dev); } - } static struct usb_driver em28xx_usb_driver = { diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 1fb3c230e23..c2d9ae0ac61 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -212,6 +212,28 @@ enum em28xx_dev_state { DEV_MISCONFIGURED = 0x04, }; +#define EM28XX_AUDIO_BUFS 5 +#define EM28XX_NUM_AUDIO_PACKETS 64 +#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ +#define EM28XX_CAPTURE_STREAM_EN 1 +#define EM28XX_AUDIO 0x10 + +struct em28xx_audio { + char name[50]; + char *transfer_buffer[EM28XX_AUDIO_BUFS]; + struct urb *urb[EM28XX_AUDIO_BUFS]; + struct usb_device *udev; + unsigned int capture_transfer_done; + struct snd_pcm_substream *capture_pcm_substream; + + unsigned int hwptr_done_capture; + struct snd_card *sndcard; + + int users, shutdown; + enum em28xx_stream_state capture_stream; + spinlock_t slock; +}; + /* main device struct */ struct em28xx { /* generic device properties */ @@ -266,6 +288,8 @@ struct em28xx { unsigned long hash; /* eeprom hash - for boards with generic ID */ unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ + struct em28xx_audio *adev; + /* states */ enum em28xx_dev_state state; enum em28xx_stream_state stream; @@ -302,6 +326,15 @@ struct em28xx { struct em28xx_fh { struct em28xx *dev; unsigned int stream_on:1; /* Locks streams */ + int radio; +}; + +struct em28xx_ops { + struct list_head next; + char *name; + int id; + int (*init)(struct em28xx *); + int (*fini)(struct em28xx *); }; /* Provided by em28xx-i2c.c */ @@ -341,6 +374,10 @@ int em28xx_init_isoc(struct em28xx *dev); void em28xx_uninit_isoc(struct em28xx *dev); int em28xx_set_alternate(struct em28xx *dev); +/* Provided by em28xx-video.c */ +int em28xx_register_extension(struct em28xx_ops *dev); +void em28xx_unregister_extension(struct em28xx_ops *dev); + /* Provided by em28xx-cards.c */ extern int em2800_variant_detect(struct usb_device* udev,int model); extern void em28xx_pre_card_setup(struct em28xx *dev); -- cgit v1.2.3 From d7448a8d9d06ca2ca4fd1f17404450ecba8bea3a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 09:59:03 -0300 Subject: V4L/DVB (6952): Add code for autoloading em28xx-alsa, if needed Older em28xx devices does implement standard Audio Class. However, on newer devices, this were replaced by a Vendor Class. This patch autodetects that an em28xx lacks Audio Class and auto-loads em28xx-alsa, for the devices that implements only a Vendor Class. For devices with Audio Class, snd-usb-audio module will provide an ALSA interface. This patch uses the request_module_async function as defined on cx88-mpeg.c, originally wrote by Markus Rechberger. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 1 - drivers/media/video/em28xx/em28xx-video.c | 38 +++++++++++++++++++++++++++++++ drivers/media/video/em28xx/em28xx.h | 3 +++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index c91ff52aefa..941357c4f3f 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -472,7 +472,6 @@ static struct em28xx_ops audio_ops = { static int __init em28xx_alsa_register(void) { - request_module("em28xx"); return em28xx_register_extension(&audio_ops); } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index caa4757b7eb..a03e9d724b5 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1668,6 +1668,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req = em28xx_read_reg_req; dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + errCode = em28xx_read_reg(dev, CHIPID_REG); + if (errCode >= 0) + em28xx_info("em28xx chip ID = %d\n", errCode); + em28xx_pre_card_setup(dev); errCode = em28xx_config(dev); @@ -1794,6 +1798,25 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, return 0; } +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct em28xx *dev = container_of(work, + struct em28xx, request_module_wk); + + if (!dev->has_audio_class) + request_module("em28xx-alsa"); +} + +static void request_modules(struct em28xx *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#endif /* CONFIG_MODULES */ + /* * em28xx_usb_probe() * checks for supported devices @@ -1864,6 +1887,18 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->devno = nr; dev->model = id->driver_info; + /* Checks if audio is provided by some interface */ + for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { + uif = udev->config->interface[i]; + if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + dev->has_audio_class = 1; + break; + } + } + + printk(KERN_INFO DRIVER_NAME " %s usb audio class\n", + dev->has_audio_class ? "Has" : "Doesn't have"); + /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; @@ -1900,6 +1935,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); + + request_modules(dev); + return 0; } diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index c2d9ae0ac61..9eb213132da 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -246,6 +246,7 @@ struct em28xx { unsigned int has_msp34xx:1; unsigned int has_tda9887:1; unsigned int stream_on:1; /* Locks streams */ + unsigned int has_audio_class:1; int video_inputs; /* number of video inputs */ struct list_head devlist; @@ -295,6 +296,8 @@ struct em28xx { enum em28xx_stream_state stream; enum em28xx_io_method io; + struct work_struct request_module_wk; + /* locks */ struct mutex lock; spinlock_t queue_lock; -- cgit v1.2.3 From e545d6e2760b51163da141caffd288572c2db08d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 16:37:04 -0300 Subject: V4L/DVB (6953): Fix radio set frequency logic Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 67b9ed1ac71..35976e6cb1b 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -247,7 +247,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_warn ("tuner type not set\n"); return; } - if (analog_ops->set_params) { + if (NULL == analog_ops->set_params) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } -- cgit v1.2.3 From 0f6dac18ccc6fb0c95f3e0269e60239661c9b4c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 16:47:16 -0300 Subject: V4L/DVB (6954): There isn't a MTS radio firmware Try to load non-MTS firmware instead. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-xc2028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 1817bf67dad..f191f6a4807 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -663,7 +663,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, return rc; } - if (priv->ctrl.mts) + if (priv->ctrl.mts && !(type & FM)) type |= MTS; retry: -- cgit v1.2.3 From 3abee53e4402b6ae39e1e610f9ef94eb74097138 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 17:01:41 -0300 Subject: V4L/DVB (6955): Properly implement 12MHz I2S support Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 20 +++++++++----------- drivers/media/video/em28xx/em28xx-core.c | 11 +++++++++-- drivers/media/video/em28xx/em28xx-video.c | 7 +++---- drivers/media/video/em28xx/em28xx.h | 3 +++ 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 78be0dc2572..1011813ad7c 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -174,13 +174,14 @@ struct em28xx_board em28xx_boards[] = { } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { - .name = "Hauppauge WinTV HVR 950", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .has_tuner = 1, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, + .name = "Hauppauge WinTV HVR 950", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .has_tuner = 1, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -641,6 +642,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->decoder = em28xx_boards[dev->model].decoder; dev->video_inputs = em28xx_boards[dev->model].vchannels; dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; + dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; if (!em28xx_boards[dev->model].has_tuner) dev->tuner_type = UNSET; @@ -676,10 +678,6 @@ void em28xx_card_setup(struct em28xx *dev) if (tv.has_ir) request_module("ir-kbd-i2c"); #endif - /* enable audio 12 mhz i2s */ - em28xx_write_regs(dev, XCLK_REG, "\xa7", 1); - msleep(10); - break; } case EM2820_BOARD_KWORLD_PVRTV2800RF: diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 70c5ec268f6..f6b78357f0e 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -332,6 +332,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) { int ret; char s[2] = { 0x00, 0x00 }; + u8 xclk = 0x07; s[0] |= 0x1f - dev->volume; s[1] |= 0x1f - dev->volume; @@ -342,10 +343,16 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (ret < 0) return ret; - ret = em28xx_write_reg_bits(dev, XCLK_REG, - dev->mute ? 0x00 : 0x80, 0x80); + if (dev->has_12mhz_i2s) + xclk |= 0x20; + + if (!dev->mute) + xclk |= 0x80; + + ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7); if (ret < 0) return ret; + msleep(10); /* Selects the proper audio input */ ret = em28xx_set_audio_source(dev); diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index a03e9d724b5..0f075f532ea 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -125,10 +125,6 @@ static int em28xx_config(struct em28xx *dev) dev->mute = 1; /* maybe not the right place... */ dev->volume = 0x1f; - /* Init XCLK_REG, audio muted */ - dev->em28xx_write_regs(dev, XCLK_REG, "\x87", 1); - - em28xx_audio_analog_set(dev); em28xx_outfmt_set_yuv422(dev); em28xx_colorlevels_set_default(dev); em28xx_compression_disable(dev); @@ -1688,6 +1684,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, /* Do board specific init and eeprom reading */ em28xx_card_setup(dev); + /* Configure audio */ + em28xx_audio_analog_set(dev); + /* configure the device */ em28xx_config_i2c(dev); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 9eb213132da..2d57330c453 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -184,6 +184,8 @@ struct em28xx_board { unsigned int has_tuner:1; unsigned int has_msp34xx:1; unsigned int mts_firmware:1; + unsigned int has_12mhz_i2s:1; + unsigned int analog_gpio; enum em28xx_decoder decoder; @@ -247,6 +249,7 @@ struct em28xx { unsigned int has_tda9887:1; unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; + unsigned int has_12mhz_i2s:1; int video_inputs; /* number of video inputs */ struct list_head devlist; -- cgit v1.2.3 From 0be4375410f1ecc917f3c0caf8f98908d357c93f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Jan 2008 17:22:01 -0300 Subject: V4L/DVB (6956): Add Radio support for em28xx Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 296 ++++++++++++++++++++++++------ drivers/media/video/em28xx/em28xx.h | 2 + 2 files changed, 238 insertions(+), 60 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 0f075f532ea..5a90462d82e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -61,13 +61,17 @@ static LIST_HEAD(em28xx_devlist); static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; + module_param_array(card, int, NULL, 0444); module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -MODULE_PARM_DESC(card,"card type"); -MODULE_PARM_DESC(video_nr,"video device numbers"); -MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); +module_param_array(radio_nr, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug = 0; module_param(video_debug,int,0644); @@ -791,7 +795,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - f->type = V4L2_TUNER_ANALOG_TV; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; return 0; @@ -811,7 +815,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (0 != f->tuner) return -EINVAL; - if (V4L2_TUNER_ANALOG_TV != f->type) + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) return -EINVAL; mutex_lock(&dev->lock); @@ -1148,6 +1154,102 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) return 0; } +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ +/* ----------------------------------------------------------- */ + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); + + cap->version = EM28XX_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + if (unlikely(t->index > 0)) + return -EINVAL; + + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + if (0 != t->index) + return -EINVAL; + + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + + return 0; +} + +static int radio_s_audio(struct file *file, void *fh, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *file, void *fh, unsigned int i) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + if (qc->id < V4L2_CID_BASE || + qc->id >= V4L2_CID_LASTP1) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); + return 0; + } + } + + return -EINVAL; +} + /* * em28xx_v4l2_open() * inits the device and starts isoc transfer @@ -1155,7 +1257,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) static int em28xx_v4l2_open(struct inode *inode, struct file *filp) { int minor = iminor(inode); - int errCode = 0; + int errCode = 0, radio = 0; struct em28xx *h,*dev = NULL; struct em28xx_fh *fh; @@ -1168,6 +1270,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev = h; dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; } + if (h->radio_dev && + h->radio_dev->minor == minor) { + radio = 1; + dev = h; + } } if (NULL == dev) return -ENODEV; @@ -1183,6 +1290,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) } mutex_lock(&dev->lock); fh->dev = dev; + fh->radio = radio; filp->private_data = fh; if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { @@ -1207,6 +1315,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_empty_framequeues(dev); } + if (fh->radio) { + em28xx_videodbg("video_open: setting radio device\n"); + em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL); + } dev->users++; @@ -1229,12 +1341,30 @@ static void em28xx_release_resources(struct em28xx *dev) dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); list_del(&dev->devlist); - video_unregister_device(dev->vdev); - video_unregister_device(dev->vbi_dev); + if (dev->radio_dev) { + if (-1 != dev->radio_dev->minor) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + if (dev->vbi_dev) { + if (-1 != dev->vbi_dev->minor) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->vdev) { + if (-1 != dev->vdev->minor) + video_unregister_device(dev->vdev); + else + video_device_release(dev->vdev); + dev->vdev = NULL; + } em28xx_i2c_unregister(dev); usb_put_dev(dev->udev); - /* Mark device as unused */ em28xx_devused&=~(1<devno); } @@ -1555,6 +1685,15 @@ static const struct file_operations em28xx_v4l_fops = { .compat_ioctl = v4l_compat_ioctl32, }; +static const struct file_operations radio_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + static const struct video_device em28xx_video_template = { .fops = &em28xx_v4l_fops, .release = video_device_release, @@ -1595,6 +1734,25 @@ static const struct video_device em28xx_video_template = { .current_norm = V4L2_STD_PAL, }; +static struct video_device em28xx_radio_template = { + .name = "em28xx-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +}; + /******************************** usb interface *****************************************/ @@ -1637,6 +1795,29 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) } EXPORT_SYMBOL(em28xx_unregister_extension); +struct video_device *em28xx_vdev_init(struct em28xx *dev, + const struct video_device *template, + const int type, + const char *type_name) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + vfd->dev = &dev->udev->dev; + vfd->release = video_device_release; + vfd->type = type; + + snprintf(vfd->name, sizeof(vfd->name), "%s %s", + dev->name, type_name); + + return vfd; +} + + /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -1710,40 +1891,55 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, errCode = em28xx_config(dev); + list_add_tail(&dev->devlist, &em28xx_devlist); + /* allocate and fill video video_device struct */ - dev->vdev = video_device_alloc(); + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, + VID_TYPE_CAPTURE, "video"); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); - em28xx_devused&=~(1<devno); - kfree(dev); - return -ENOMEM; + goto fail_unreg; } - memcpy(dev->vdev, &em28xx_video_template, - sizeof(em28xx_video_template)); - dev->vdev->type = VID_TYPE_CAPTURE; if (dev->has_tuner) dev->vdev->type |= VID_TYPE_TUNER; - dev->vdev->dev = &dev->udev->dev; - snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), - "%s#%d %s", "em28xx", dev->devno, "video"); + + /* register v4l2 video video_device */ + retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]); + if (retval) { + em28xx_errdev("unable to register video device (error=%i).\n", + retval); + goto fail_unreg; + } /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = video_device_alloc(); - if (NULL == dev->vbi_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - kfree(dev->vdev); - em28xx_devused&=~(1<devno); - kfree(dev); - return -ENOMEM; + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, + VFL_TYPE_VBI, "vbi"); + /* register v4l2 vbi video_device */ + if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->devno]) < 0) { + em28xx_errdev("unable to register vbi device\n"); + retval = -ENODEV; + goto fail_unreg; + } + + if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, + VFL_TYPE_RADIO, "radio"); + if (NULL == dev->radio_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + goto fail_unreg; + } + retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->devno]); + if (retval < 0) { + em28xx_errdev("can't register radio device\n"); + goto fail_unreg; + } + em28xx_info("Registered radio device as /dev/radio%d\n", + dev->radio_dev->minor & 0x1f); } - memcpy(dev->vbi_dev, &em28xx_video_template, - sizeof(em28xx_video_template)); - dev->vbi_dev->type = VFL_TYPE_VBI; - dev->vbi_dev->dev = &dev->udev->dev; - snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), - "%s#%d %s", "em28xx", dev->devno, "vbi"); - list_add_tail(&dev->devlist,&em28xx_devlist); if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ @@ -1755,32 +1951,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, video_mux(dev, 0); - /* register v4l2 video video_device */ - if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]))) { - em28xx_errdev("unable to register video device (error=%i).\n", - retval); - mutex_unlock(&dev->lock); - list_del(&dev->devlist); - video_device_release(dev->vdev); - em28xx_devused&=~(1<devno); - kfree(dev); - return -ENODEV; - } - - /* register v4l2 vbi video_device */ - if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->devno]) < 0) { - printk("unable to register vbi device\n"); - mutex_unlock(&dev->lock); - list_del(&dev->devlist); - video_device_release(dev->vbi_dev); - video_device_release(dev->vdev); - em28xx_devused&=~(1<devno); - kfree(dev); - return -ENODEV; - } - em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); @@ -1795,6 +1965,12 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, mutex_unlock(&em28xx_extension_devlist_lock); return 0; + +fail_unreg: + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); + return retval; } #if defined(CONFIG_MODULES) && defined(MODULE) diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 2d57330c453..2ba34e5b4cc 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -191,6 +191,7 @@ struct em28xx_board { enum em28xx_decoder decoder; struct em28xx_input input[MAX_EM28XX_INPUT]; + struct em28xx_input radio; }; struct em28xx_eeprom { @@ -307,6 +308,7 @@ struct em28xx { struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; struct video_device *vbi_dev; + struct video_device *radio_dev; unsigned char eedata[256]; -- cgit v1.2.3 From 33f25b42753f464c5927e8b828352333780c14bd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 29 Dec 2007 21:46:01 -0300 Subject: V4L/DVB (6957): tda18271: fail table lookups if frequency is out of range Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 5 ----- drivers/media/dvb/frontends/tda18271-tables.c | 28 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index d5807c98afc..739ecfe0438 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -502,11 +502,6 @@ static int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) if (ret < 0) goto fail; - /* VHF_Low band only */ - if (0 == val) { - ret = -ERANGE; - goto fail; - } regs[R_EB14] = val; fail: return ret; diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index e10a93bf12c..f8202c40b04 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -273,6 +273,7 @@ int tda18271_lookup_pll_map(enum tda18271_map_type map_type, struct tda18271_pll_map *map = NULL; unsigned int i = 0; char *map_name; + int ret = 0; switch (map_type) { case MAIN_PLL: @@ -291,12 +292,17 @@ int tda18271_lookup_pll_map(enum tda18271_map_type map_type, if (!map) { tda_warn("%s map is not set!\n", map_name); - return -EINVAL; + ret = -EINVAL; + goto fail; } while ((map[i].lomax * 1000) < *freq) { - if (map[i + 1].lomax == 0) + if (map[i].lomax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; break; + } i++; } *post_div = map[i].pd; @@ -304,8 +310,8 @@ int tda18271_lookup_pll_map(enum tda18271_map_type map_type, tda_map("%s: post div = 0x%02x, div = 0x%02x\n", map_name, *post_div, *div); - - return 0; +fail: + return ret; } int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) @@ -313,6 +319,7 @@ int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) struct tda18271_map *map = NULL; unsigned int i = 0; char *map_name; + int ret = 0; switch (map_type) { case BP_FILTER: @@ -347,19 +354,24 @@ int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) if (!map) { tda_warn("%s map is not set!\n", map_name); - return -EINVAL; + ret = -EINVAL; + goto fail; } while ((map[i].rfmax * 1000) < *freq) { - if (map[i + 1].rfmax == 0) + if (map[i].rfmax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; break; + } i++; } *val = map[i].val; tda_map("%s: 0x%02x\n", map_name, *val); - - return 0; +fail: + return ret; } /* -- cgit v1.2.3 From 95af8a26cba55222d6a1beda7970431b4fbbbdd6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 1 Jan 2008 18:31:34 -0300 Subject: V4L/DVB (6958): tda18271: clean up function tda18271_set_analog_params make set_analog_params function look consistent with set_params function Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 739ecfe0438..98ee6b1ff8a 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -662,7 +662,6 @@ static int tda18271_set_params(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; u8 std; u32 bw, sgIF = 0; - u32 freq = params->frequency; priv->mode = TDA18271_DIGITAL; @@ -722,54 +721,50 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda18271_priv *priv = fe->tuner_priv; - u8 std; - unsigned int sgIF; char *mode; + u8 std; + u32 sgIF, freq = params->frequency * 62500; priv->mode = TDA18271_ANALOG; /* see table 22 */ if (params->std & V4L2_STD_MN) { std = 0x0d; - sgIF = 92; + sgIF = 5750000; mode = "MN"; } else if (params->std & V4L2_STD_B) { std = 0x0e; - sgIF = 108; + sgIF = 6750000; mode = "B"; } else if (params->std & V4L2_STD_GH) { std = 0x0f; - sgIF = 124; + sgIF = 7750000; mode = "GH"; } else if (params->std & V4L2_STD_PAL_I) { std = 0x0f; - sgIF = 124; + sgIF = 7750000; mode = "I"; } else if (params->std & V4L2_STD_DK) { std = 0x0f; - sgIF = 124; + sgIF = 7750000; mode = "DK"; } else if (params->std & V4L2_STD_SECAM_L) { std = 0x0f; - sgIF = 124; + sgIF = 7750000; mode = "L"; } else if (params->std & V4L2_STD_SECAM_LC) { std = 0x0f; - sgIF = 20; - mode = "LC"; + sgIF = 1250000; + mode = "L'"; } else { std = 0x0f; - sgIF = 124; + sgIF = 7750000; mode = "xx"; } - if (params->mode == V4L2_TUNER_RADIO) - sgIF = 88; /* if frequency is 5.5 MHz */ - tda_dbg("setting tda18271 to system %s\n", mode); - return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, - 0, std); + return tda18271_tune(fe, sgIF, freq, 0, std); } static int tda18271_release(struct dvb_frontend *fe) -- cgit v1.2.3 From dec9ccceef9bfd5f3cccc79e90b09f6c31ed3279 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 2 Jan 2008 01:35:46 -0300 Subject: V4L/DVB (6959): tda18271: add MODULE_VERSION version 0.1 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 98ee6b1ff8a..2c873ae6e8c 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -866,6 +866,7 @@ EXPORT_SYMBOL_GPL(tda18271_attach); MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); /* * Overrides for Emacs so that we follow Linus's tabbing style. -- cgit v1.2.3 From 255b5113b4ed683898a24e381155c081f03411f7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 1 Jan 2008 22:52:09 -0300 Subject: V4L/DVB (6960): tda18271: add support for NXP TDA18271HD/C2 Tested successfully with QAM256 digital cable. Analog television is limping, needs more work. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 885 +++++++++++++++++++++--- drivers/media/dvb/frontends/tda18271-priv.h | 72 +- drivers/media/dvb/frontends/tda18271-tables.c | 932 +++++++++++++++++++++++++- drivers/media/video/tda8290.c | 2 +- 4 files changed, 1779 insertions(+), 112 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 2c873ae6e8c..4b53baf12ef 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -71,7 +71,7 @@ static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) /*---------------------------------------------------------------------*/ -static void tda18271_dump_regs(struct dvb_frontend *fe) +static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -93,6 +93,37 @@ static void tda18271_dump_regs(struct dvb_frontend *fe) tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); + + /* only dump extended regs if DBG_ADV is set */ + if (!(tda18271_debug & DBG_ADV)) + return; + + /* W indicates write-only registers. + * Register dump for write-only registers shows last value written. */ + + tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); + tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); + tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); + tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); + tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); + tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); + tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); + tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); + tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); + tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); + tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); + tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); + tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); + tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); + tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); + tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); + tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); + tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); + tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); + tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); + tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); + tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); + tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); } static void tda18271_read_regs(struct dvb_frontend *fe) @@ -119,7 +150,45 @@ static void tda18271_read_regs(struct dvb_frontend *fe) tda_err("ERROR: i2c_transfer returned: %d\n", ret); if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe); + tda18271_dump_regs(fe, 0); +} + +static void tda18271_read_extended(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char regdump[TDA18271_NUM_REGS]; + unsigned char buf = 0x00; + int ret, i; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regdump, .len = TDA18271_NUM_REGS } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + for (i = 0; i <= TDA18271_NUM_REGS; i++) { + /* don't update write-only registers */ + if ((i != R_EB9) && + (i != R_EB16) && + (i != R_EB17) && + (i != R_EB19) && + (i != R_EB20)) + regs[i] = regdump[i]; + } + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 1); } static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) @@ -160,7 +229,15 @@ static int tda18271_init_regs(struct dvb_frontend *fe) i2c_adapter_id(priv->i2c_adap), priv->i2c_addr); /* initialize registers */ - regs[R_ID] = 0x83; + switch (priv->id) { + case TDA18271HDC1: + regs[R_ID] = 0x83; + break; + case TDA18271HDC2: + regs[R_ID] = 0x84; + break; + }; + regs[R_TM] = 0x08; regs[R_PL] = 0x80; regs[R_EP1] = 0xc6; @@ -176,7 +253,16 @@ static int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x00; regs[R_MD2] = 0x00; regs[R_MD3] = 0x00; - regs[R_EB1] = 0xff; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB1] = 0xff; + break; + case TDA18271HDC2: + regs[R_EB1] = 0xfc; + break; + }; + regs[R_EB2] = 0x01; regs[R_EB3] = 0x84; regs[R_EB4] = 0x41; @@ -187,21 +273,49 @@ static int tda18271_init_regs(struct dvb_frontend *fe) regs[R_EB9] = 0x00; regs[R_EB10] = 0x00; regs[R_EB11] = 0x96; - regs[R_EB12] = 0x0f; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB12] = 0x0f; + break; + case TDA18271HDC2: + regs[R_EB12] = 0x33; + break; + }; + regs[R_EB13] = 0xc1; regs[R_EB14] = 0x00; regs[R_EB15] = 0x8f; regs[R_EB16] = 0x00; regs[R_EB17] = 0x00; - regs[R_EB18] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB18] = 0x00; + break; + case TDA18271HDC2: + regs[R_EB18] = 0x8c; + break; + }; + regs[R_EB19] = 0x00; regs[R_EB20] = 0x20; - regs[R_EB21] = 0x33; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB21] = 0x33; + break; + case TDA18271HDC2: + regs[R_EB21] = 0xb3; + break; + }; + regs[R_EB22] = 0x48; regs[R_EB23] = 0xb0; tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); - /* setup AGC1 & AGC2 */ + + /* setup agc1 gain */ regs[R_EB17] = 0x00; tda18271_write_regs(fe, R_EB17, 1); regs[R_EB17] = 0x03; @@ -211,14 +325,17 @@ static int tda18271_init_regs(struct dvb_frontend *fe) regs[R_EB17] = 0x4c; tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); + /* setup agc2 gain */ + if ((priv->id) == TDA18271HDC1) { + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + } /* image rejection calibration */ @@ -235,103 +352,102 @@ static int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD2] = 0x08; regs[R_MD3] = 0x00; - tda18271_write_regs(fe, R_EP3, 11); + switch (priv->id) { + case TDA18271HDC1: + tda18271_write_regs(fe, R_EP3, 11); + break; + case TDA18271HDC2: + tda18271_write_regs(fe, R_EP3, 12); + break; + }; + + if ((priv->id) == TDA18271HDC2) { + /* main pll cp source on */ + regs[R_EB4] = 0x61; + tda18271_write_regs(fe, R_EB4, 1); + msleep(1); + + /* main pll cp source off */ + regs[R_EB4] = 0x41; + tda18271_write_regs(fe, R_EB4, 1); + } + msleep(5); /* pll locking */ - regs[R_EP1] = 0xc6; + /* launch detector */ tda18271_write_regs(fe, R_EP1, 1); msleep(5); /* wanted low measurement */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; regs[R_EP5] = 0x85; regs[R_CPD] = 0xcb; regs[R_CD1] = 0x66; regs[R_CD2] = 0x70; - regs[R_CD3] = 0x00; tda18271_write_regs(fe, R_EP3, 7); msleep(5); /* pll locking */ - regs[R_EP2] = 0xdf; + /* launch optimization algorithm */ tda18271_write_regs(fe, R_EP2, 1); msleep(30); /* image low optimization completion */ /* mid-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; regs[R_EP5] = 0x82; regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; regs[R_MPD] = 0xa9; regs[R_MD1] = 0x73; regs[R_MD2] = 0x1a; - regs[R_MD3] = 0x00; tda18271_write_regs(fe, R_EP3, 11); msleep(5); /* pll locking */ - regs[R_EP1] = 0xc6; tda18271_write_regs(fe, R_EP1, 1); msleep(5); /* wanted mid measurement */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; regs[R_EP5] = 0x86; regs[R_CPD] = 0xa8; regs[R_CD1] = 0x66; regs[R_CD2] = 0xa0; - regs[R_CD3] = 0x00; tda18271_write_regs(fe, R_EP3, 7); msleep(5); /* pll locking */ - regs[R_EP2] = 0xdf; + /* launch optimization algorithm */ tda18271_write_regs(fe, R_EP2, 1); msleep(30); /* image mid optimization completion */ /* high-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; regs[R_EP5] = 0x83; regs[R_CPD] = 0x98; regs[R_CD1] = 0x65; regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; regs[R_MPD] = 0x99; regs[R_MD1] = 0x71; regs[R_MD2] = 0xcd; - regs[R_MD3] = 0x00; tda18271_write_regs(fe, R_EP3, 11); msleep(5); /* pll locking */ - regs[R_EP1] = 0xc6; + /* launch detector */ tda18271_write_regs(fe, R_EP1, 1); msleep(5); /* wanted high measurement */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; regs[R_EP5] = 0x87; - regs[R_CPD] = 0x98; regs[R_CD1] = 0x65; regs[R_CD2] = 0x50; - regs[R_CD3] = 0x00; tda18271_write_regs(fe, R_EP3, 7); msleep(5); /* pll locking */ - regs[R_EP2] = 0xdf; - + /* launch optimization algorithm */ tda18271_write_regs(fe, R_EP2, 1); msleep(30); /* image high optimization completion */ + /* return to normal mode */ regs[R_EP4] = 0x64; tda18271_write_regs(fe, R_EP4, 1); - regs[R_EP1] = 0xc6; + /* synchronize */ tda18271_write_regs(fe, R_EP1, 1); return 0; @@ -359,7 +475,7 @@ static int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) u8 d, pd; u32 div; - int ret = tda18271_lookup_pll_map(MAIN_PLL, &freq, &pd, &d); + int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); if (ret < 0) goto fail; @@ -391,7 +507,7 @@ static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) u8 d, pd; u32 div; - int ret = tda18271_lookup_pll_map(CAL_PLL, &freq, &pd, &d); + int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); if (ret < 0) goto fail; @@ -413,7 +529,7 @@ static int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(BP_FILTER, freq, &val); + int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); if (ret < 0) goto fail; @@ -430,7 +546,7 @@ static int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(RF_CAL_KMCO, freq, &val); + int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); if (ret < 0) goto fail; @@ -447,7 +563,7 @@ static int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(RF_BAND, freq, &val); + int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); if (ret < 0) goto fail; @@ -464,7 +580,7 @@ static int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(GAIN_TAPER, freq, &val); + int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); if (ret < 0) goto fail; @@ -481,7 +597,7 @@ static int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(IR_MEASURE, freq, &val); + int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); if (ret < 0) goto fail; @@ -498,7 +614,7 @@ static int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(RF_CAL, freq, &val); + int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); if (ret < 0) goto fail; @@ -507,8 +623,581 @@ fail: return ret; } -static int tda18271_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) +/* ------------------------------------------------------------------ */ + +static int tda18271_channel_configuration(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N; + + /* update TV broadcast parameters */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= std; + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level & IF notch frequency */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_EP4] |= 0x04; /* IF level = 1 */ + regs[R_MPD] |= 0x80; /* IF notch = 1 */ + break; + } + regs[R_EP4] &= ~0x80; /* FM_RFn: turn this bit on only for fm radio */ + + /* update RF_TOP / IF_TOP */ + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_EB22] = 0x2c; + break; + case TDA18271_DIGITAL: + regs[R_EB22] = 0x37; + break; + } + tda18271_write_regs(fe, R_EB22, 1); + + /* --------------------------------------------------------------- */ + + /* disable Power Level Indicator */ + regs[R_EP1] |= 0x40; + + /* frequency dependent parameters */ + + tda18271_calc_ir_measure(fe, &freq); + + tda18271_calc_bp_filter(fe, &freq); + + tda18271_calc_rf_band(fe, &freq); + + tda18271_calc_gain_taper(fe, &freq); + + /* --------------------------------------------------------------- */ + + /* dual tuner and agc1 extra configuration */ + + /* main vco when Master, cal vco when slave */ + regs[R_EB1] |= 0x04; /* FIXME: assumes master */ + + /* agc1 always active */ + regs[R_EB1] &= ~0x02; + + /* agc1 has priority on agc2 */ + regs[R_EB1] &= ~0x01; + + tda18271_write_regs(fe, R_EB1, 1); + + /* --------------------------------------------------------------- */ + + N = freq + ifc; + + /* FIXME: assumes master */ + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + tda18271_write_regs(fe, R_TM, 7); + + /* main pll charge pump source */ + regs[R_EB4] |= 0x20; + tda18271_write_regs(fe, R_EB4, 1); + + msleep(1); + + /* normal operation for the main pll */ + regs[R_EB4] &= ~0x20; + tda18271_write_regs(fe, R_EB4, 1); + + msleep(5); + + return 0; +} + +static int tda18271_read_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int tm; + + /* switch thermometer on */ + regs[R_TM] |= 0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* read thermometer info */ + tda18271_read_regs(fe); + + if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || + (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { + + if ((regs[R_TM] & 0x20) == 0x20) + regs[R_TM] &= ~0x20; + else + regs[R_TM] |= 0x20; + + tda18271_write_regs(fe, R_TM, 1); + + msleep(10); /* temperature sensing */ + + /* read thermometer info */ + tda18271_read_regs(fe); + } + + tm = tda18271_lookup_thermometer(fe); + + /* switch thermometer off */ + regs[R_TM] &= ~0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + return tm; +} + +static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe, + u32 freq, int tm_rfcal) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int tm_current, rfcal_comp, approx, i; + u8 dc_over_dt, rf_tab; + + /* power up */ + regs[R_EP3] &= ~0xe0; /* sm = 0, sm_lt = 0, sm_xt = 0 */ + tda18271_write_regs(fe, R_EP3, 1); + + /* read die current temperature */ + tm_current = tda18271_read_thermometer(fe); + + /* frequency dependent parameters */ + + tda18271_calc_rf_cal(fe, &freq); + rf_tab = regs[R_EB14]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + if (i < 0) + return -EINVAL; + + if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { + approx = map[i].rf_a1 * + (freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab; + } else { + approx = map[i].rf_a2 * + (freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab; + } + + if (approx < 0) + approx = 0; + if (approx > 255) + approx = 255; + + tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + + /* calculate temperature compensation */ + rfcal_comp = dc_over_dt * (tm_current - tm_rfcal); + + regs[R_EB14] = approx + rfcal_comp; + tda18271_write_regs(fe, R_EB14, 1); + + return 0; +} + +static int tda18271_por(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + /* power up detector 1 */ + regs[R_EB12] &= ~0x20; + tda18271_write_regs(fe, R_EB12, 1); + + regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ + + /* POR mode */ + regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ + regs[R_EP3] |= 0x80; /* sm = 1, sm_lt = 0, sm_xt = 0 */ + tda18271_write_regs(fe, R_EP3, 1); + + /* disable 1.5 MHz low pass filter */ + regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ + regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ + tda18271_write_regs(fe, R_EB21, 3); + + return 0; +} + +static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N; + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + /* switch off agc1 */ + regs[R_EP3] |= 0x40; /* sm_lt = 1 */ + + regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + /* frequency dependent parameters */ + + tda18271_calc_bp_filter(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_km(fe, &freq); + + tda18271_write_regs(fe, R_EP1, 3); + tda18271_write_regs(fe, R_EB13, 1); + + /* main pll charge pump source */ + regs[R_EB4] |= 0x20; + tda18271_write_regs(fe, R_EB4, 1); + + /* cal pll charge pump source */ + regs[R_EB7] |= 0x20; + tda18271_write_regs(fe, R_EB7, 1); + + /* force dcdc converter to 0 V */ + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + /* disable plls lock */ + regs[R_EB20] &= ~0x20; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + tda18271_write_regs(fe, R_EP4, 2); + + /* --------------------------------------------------------------- */ + + /* set the internal calibration signal */ + N = freq; + + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + /* downconvert internal calibration */ + N += 1000000; + + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + /* --------------------------------------------------------------- */ + + /* normal operation for the main pll */ + regs[R_EB4] &= ~0x20; + tda18271_write_regs(fe, R_EB4, 1); + + /* normal operation for the cal pll */ + regs[R_EB7] &= ~0x20; + tda18271_write_regs(fe, R_EB7, 1); + + msleep(5); /* plls locking */ + + /* launch the rf tracking filters calibration */ + regs[R_EB20] |= 0x20; + tda18271_write_regs(fe, R_EB20, 1); + + msleep(60); /* calibration */ + + /* --------------------------------------------------------------- */ + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + + /* switch on agc1 */ + regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + tda18271_write_regs(fe, R_EP3, 2); + + /* synchronization */ + tda18271_write_regs(fe, R_EP1, 1); + + /* get calibration result */ + tda18271_read_extended(fe); + + return regs[R_EB14]; +} + +static int tda18271_powerscan(struct dvb_frontend *fe, + u32 *freq_in, u32 *freq_out) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int sgn, bcal, count, wait; + u8 cid_target; + u16 count_limit; + u32 freq; + + freq = *freq_in; + + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_rf_cal(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EB14, 1); + + /* downconvert frequency */ + freq += 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); /* pll locking */ + + /* detection mode */ + regs[R_EP4] &= ~0x03; + regs[R_EP4] |= 0x01; + tda18271_write_regs(fe, R_EP4, 1); + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + tda18271_read_extended(fe); + + /* algorithm initialization */ + sgn = 1; + *freq_out = *freq_in; + bcal = 0; + count = 0; + wait = false; + + while ((regs[R_EB10] & 0x3f) < cid_target) { + /* downconvert updated freq to 1 MHz */ + freq = *freq_in + (sgn * count) + 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + if (wait) { + msleep(5); /* pll locking */ + wait = false; + } else + udelay(100); /* pll locking */ + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + tda18271_read_extended(fe); + + count += 200; + + if (count < count_limit) + continue; + + if (sgn <= 0) + break; + + sgn = -1 * sgn; + count = 200; + wait = true; + } + + if ((regs[R_EB10] & 0x3f) >= cid_target) { + bcal = 1; + *freq_out = freq - 1000000; + } else + bcal = 0; + + tda_dbg("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", + bcal, *freq_in, *freq_out, freq); + + return bcal; +} + +static int tda18271_powerscan_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + /* set standard to digital */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= 0x12; + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level & IF notch frequency */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + + tda18271_write_regs(fe, R_EP3, 2); + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ + + /* 1.5 MHz low pass filter */ + regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ + regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ + + tda18271_write_regs(fe, R_EB21, 3); + + return 0; +} + +static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int bcal, rf, i; +#define RF1 0 +#define RF2 1 +#define RF3 2 + u32 rf_default[3]; + u32 rf_freq[3]; + u8 prog_cal[3]; + u8 prog_tab[3]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + + if (i < 0) + return i; + + rf_default[RF1] = 1000 * map[i].rf1_def; + rf_default[RF2] = 1000 * map[i].rf2_def; + rf_default[RF3] = 1000 * map[i].rf3_def; + + for (rf = RF1; rf <= RF3; rf++) { + if (0 == rf_default[rf]) + return 0; + tda_dbg("freq = %d, rf = %d\n", freq, rf); + + /* look for optimized calibration frequency */ + bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); + + tda18271_calc_rf_cal(fe, &rf_freq[rf]); + prog_tab[rf] = regs[R_EB14]; + + if (1 == bcal) + prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); + else + prog_cal[rf] = prog_tab[rf]; + + switch (rf) { + case RF1: + map[i].rf_a1 = 0; + map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1]; + map[i].rf1 = rf_freq[RF1] / 1000; + break; + case RF2: + map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]) / + ((rf_freq[RF2] - rf_freq[RF1]) / 1000); + map[i].rf2 = rf_freq[RF2] / 1000; + break; + case RF3: + map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]) / + ((rf_freq[RF3] - rf_freq[RF2]) / 1000); + map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2]; + map[i].rf3 = rf_freq[RF3] / 1000; + break; + default: + BUG(); + } + } + + return 0; +} + +static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe, + int *tm_rfcal) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned int i; + + tda_info("tda18271: performing RF tracking filter calibration\n"); + + /* wait for die temperature stabilization */ + msleep(200); + + tda18271_powerscan_init(fe); + + /* rf band calibration */ + for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) + tda18271_rf_tracking_filters_init(fe, 1000 * + priv->rf_cal_state[i].rfmax); + + *tm_rfcal = tda18271_read_thermometer(fe); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_init_cal(struct dvb_frontend *fe, int *tm) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + if (priv->cal_initialized) + return 0; + + /* initialization */ + tda18271_init(fe); + + tda18271_calc_rf_filter_curve(fe, tm); + + tda18271_por(fe); + + priv->cal_initialized = true; + + return 0; +} + +static int tda18271c2_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) +{ + int tm = 0; + + tda_dbg("freq = %d, ifc = %d\n", freq, ifc); + + tda18271_init_cal(fe, &tm); + + tda18271_rf_tracking_filters_correction(fe, freq, tm); + + tda18271_channel_configuration(fe, ifc, freq, bw, std); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271c1_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -520,7 +1209,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* RF tracking filter calibration */ - /* calculate BP_Filter */ + /* calculate bp filter */ tda18271_calc_bp_filter(fe, &freq); tda18271_write_regs(fe, R_EP1, 1); @@ -537,10 +1226,10 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EB20] = 0xcc; tda18271_write_regs(fe, R_EB20, 1); - /* set CAL mode to RF tracking filter calibration */ + /* set cal mode to RF tracking filter calibration */ regs[R_EP4] |= 0x03; - /* calculate CAL PLL */ + /* calculate cal pll */ switch (priv->mode) { case TDA18271_ANALOG: @@ -553,7 +1242,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_calc_cal_pll(fe, N); - /* calculate MAIN PLL */ + /* calculate main pll */ switch (priv->mode) { case TDA18271_ANALOG: @@ -569,14 +1258,14 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP3, 11); msleep(5); /* RF tracking filter calibration initialization */ - /* search for K,M,CO for RF Calibration */ + /* search for K,M,CO for RF calibration */ tda18271_calc_km(fe, &freq); tda18271_write_regs(fe, R_EB13, 1); - /* search for RF_BAND */ + /* search for rf band */ tda18271_calc_rf_band(fe, &freq); - /* search for Gain_Taper */ + /* search for gain taper */ tda18271_calc_gain_taper(fe, &freq); tda18271_write_regs(fe, R_EP2, 1); @@ -660,10 +1349,13 @@ static int tda18271_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = priv->std; u8 std; u32 bw, sgIF = 0; u32 freq = params->frequency; + BUG_ON(!priv->tune || !priv->std); + priv->mode = TDA18271_DIGITAL; /* see table 22 */ @@ -671,13 +1363,13 @@ static int tda18271_set_params(struct dvb_frontend *fe, switch (params->u.vsb.modulation) { case VSB_8: case VSB_16: - std = 0x1b; /* device-specific (spec says 0x1c) */ - sgIF = 5380000; + std = std_map->atsc_6.std_bits; + sgIF = std_map->atsc_6.if_freq; break; case QAM_64: case QAM_256: - std = 0x18; /* device-specific (spec says 0x1d) */ - sgIF = 4000000; + std = std_map->qam_6.std_bits; + sgIF = std_map->qam_6.if_freq; break; default: tda_warn("modulation not set!\n"); @@ -691,19 +1383,19 @@ static int tda18271_set_params(struct dvb_frontend *fe, } else if (fe->ops.info.type == FE_OFDM) { switch (params->u.ofdm.bandwidth) { case BANDWIDTH_6_MHZ: - std = 0x1b; /* device-specific (spec says 0x1c) */ bw = 6000000; - sgIF = 3300000; + std = std_map->dvbt_6.std_bits; + sgIF = std_map->dvbt_6.if_freq; break; case BANDWIDTH_7_MHZ: - std = 0x19; /* device-specific (spec says 0x1d) */ bw = 7000000; - sgIF = 3800000; + std = std_map->dvbt_7.std_bits; + sgIF = std_map->dvbt_7.if_freq; break; case BANDWIDTH_8_MHZ: - std = 0x1a; /* device-specific (spec says 0x1e) */ bw = 8000000; - sgIF = 4300000; + std = std_map->dvbt_8.std_bits; + sgIF = std_map->dvbt_8.if_freq; break; default: tda_warn("bandwidth not set!\n"); @@ -714,57 +1406,59 @@ static int tda18271_set_params(struct dvb_frontend *fe, return -EINVAL; } - return tda18271_tune(fe, sgIF, freq, bw, std); + return priv->tune(fe, sgIF, freq, bw, std); } static int tda18271_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = priv->std; char *mode; u8 std; u32 sgIF, freq = params->frequency * 62500; + BUG_ON(!priv->tune || !priv->std); + priv->mode = TDA18271_ANALOG; - /* see table 22 */ if (params->std & V4L2_STD_MN) { - std = 0x0d; - sgIF = 5750000; + std = std_map->atv_mn.std_bits; + sgIF = std_map->atv_mn.if_freq; mode = "MN"; } else if (params->std & V4L2_STD_B) { - std = 0x0e; - sgIF = 6750000; + std = std_map->atv_b.std_bits; + sgIF = std_map->atv_b.if_freq; mode = "B"; } else if (params->std & V4L2_STD_GH) { - std = 0x0f; - sgIF = 7750000; + std = std_map->atv_gh.std_bits; + sgIF = std_map->atv_gh.if_freq; mode = "GH"; } else if (params->std & V4L2_STD_PAL_I) { - std = 0x0f; - sgIF = 7750000; + std = std_map->atv_i.std_bits; + sgIF = std_map->atv_i.if_freq; mode = "I"; } else if (params->std & V4L2_STD_DK) { - std = 0x0f; - sgIF = 7750000; + std = std_map->atv_dk.std_bits; + sgIF = std_map->atv_dk.if_freq; mode = "DK"; } else if (params->std & V4L2_STD_SECAM_L) { - std = 0x0f; - sgIF = 7750000; + std = std_map->atv_l.std_bits; + sgIF = std_map->atv_l.if_freq; mode = "L"; } else if (params->std & V4L2_STD_SECAM_LC) { - std = 0x0f; - sgIF = 1250000; + std = std_map->atv_lc.std_bits; + sgIF = std_map->atv_lc.if_freq; mode = "L'"; } else { - std = 0x0f; - sgIF = 7750000; + std = std_map->atv_i.std_bits; + sgIF = std_map->atv_i.if_freq; mode = "xx"; } tda_dbg("setting tda18271 to system %s\n", mode); - return tda18271_tune(fe, sgIF, freq, 0, std); + return priv->tune(fe, sgIF, freq, 0, std); } static int tda18271_release(struct dvb_frontend *fe) @@ -800,10 +1494,13 @@ static int tda18271_get_id(struct dvb_frontend *fe) switch (regs[R_ID] & 0x7f) { case 3: name = "TDA18271HD/C1"; + priv->id = TDA18271HDC1; + priv->tune = tda18271c1_tune; break; case 4: name = "TDA18271HD/C2"; - ret = -EPROTONOSUPPORT; + priv->id = TDA18271HDC2; + priv->tune = tda18271c2_tune; break; default: name = "Unknown device"; @@ -846,12 +1543,16 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, priv->i2c_addr = addr; priv->i2c_adap = i2c; priv->gate = gate; + priv->cal_initialized = false; fe->tuner_priv = priv; if (tda18271_get_id(fe) < 0) goto fail; + if (tda18271_assign_map_layout(fe) < 0) + goto fail; + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -866,7 +1567,7 @@ EXPORT_SYMBOL_GPL(tda18271_attach); MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); +MODULE_VERSION("0.2"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 912b81e0c76..8552c6ae0d1 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -69,11 +69,54 @@ /*---------------------------------------------------------------------*/ +struct tda18271_rf_tracking_filter_cal { + u32 rfmax; + u8 rfband; + u32 rf1_def; + u32 rf2_def; + u32 rf3_def; + u32 rf1; + u32 rf2; + u32 rf3; + int rf_a1; + int rf_b1; + int rf_a2; + int rf_b2; +}; + +struct tda18271_std_map_item { + u32 if_freq; + u8 std_bits; +}; + +struct tda18271_std_map { + struct tda18271_std_map_item atv_b; + struct tda18271_std_map_item atv_dk; + struct tda18271_std_map_item atv_gh; + struct tda18271_std_map_item atv_i; + struct tda18271_std_map_item atv_l; + struct tda18271_std_map_item atv_lc; + struct tda18271_std_map_item atv_mn; + struct tda18271_std_map_item atsc_6; + struct tda18271_std_map_item dvbt_6; + struct tda18271_std_map_item dvbt_7; + struct tda18271_std_map_item dvbt_8; + struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_8; +}; + enum tda18271_mode { TDA18271_ANALOG, TDA18271_DIGITAL, }; +struct tda18271_map_layout; + +enum tda18271_ver { + TDA18271HDC1, + TDA18271HDC2, +}; + struct tda18271_priv { u8 i2c_addr; struct i2c_adapter *i2c_adap; @@ -81,6 +124,16 @@ struct tda18271_priv { enum tda18271_mode mode; enum tda18271_i2c_gate gate; + enum tda18271_ver id; + + unsigned int cal_initialized:1; + + struct tda18271_std_map *std; + struct tda18271_map_layout *maps; + struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; + + int (*tune) (struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std); u32 frequency; u32 bandwidth; @@ -93,6 +146,7 @@ extern int tda18271_debug; #define DBG_INFO 1 #define DBG_MAP 2 #define DBG_REG 4 +#define DBG_ADV 8 #define tda_printk(kern, fmt, arg...) \ printk(kern "%s: " fmt, __FUNCTION__, ##arg) @@ -117,17 +171,31 @@ enum tda18271_map_type { /* tda18271_map */ RF_CAL, RF_CAL_KMCO, + RF_CAL_DC_OVER_DT, BP_FILTER, RF_BAND, GAIN_TAPER, IR_MEASURE, }; -extern int tda18271_lookup_pll_map(enum tda18271_map_type map_type, +extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, u32 *freq, u8 *post_div, u8 *div); -extern int tda18271_lookup_map(enum tda18271_map_type map_type, +extern int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, u32 *freq, u8 *val); +extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); + +extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, + u32 *freq, u8 *rf_band); + +extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, + u16 *count_limit); + +extern int tda18271_assign_map_layout(struct dvb_frontend *fe); + #endif /* __TDA18271_PRIV_H__ */ /* diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index f8202c40b04..3042e5c873e 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -33,7 +33,7 @@ struct tda18271_map { /*---------------------------------------------------------------------*/ -static struct tda18271_pll_map tda18271_main_pll[] = { +static struct tda18271_pll_map tda18271c1_main_pll[] = { { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, @@ -77,7 +77,51 @@ static struct tda18271_pll_map tda18271_main_pll[] = { { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ }; -static struct tda18271_pll_map tda18271_cal_pll[] = { +static struct tda18271_pll_map tda18271c2_main_pll[] = { + { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, + { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, + { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, + { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, + { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, + { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, + { .lomax = 55188, .pd = 0x51, .d = 0x90 }, + { .lomax = 62125, .pd = 0x50, .d = 0x80 }, + { .lomax = 66250, .pd = 0x47, .d = 0x78 }, + { .lomax = 71000, .pd = 0x46, .d = 0x70 }, + { .lomax = 76375, .pd = 0x45, .d = 0x68 }, + { .lomax = 82750, .pd = 0x44, .d = 0x60 }, + { .lomax = 90250, .pd = 0x43, .d = 0x58 }, + { .lomax = 99375, .pd = 0x42, .d = 0x50 }, + { .lomax = 110375, .pd = 0x41, .d = 0x48 }, + { .lomax = 124250, .pd = 0x40, .d = 0x40 }, + { .lomax = 132500, .pd = 0x37, .d = 0x3c }, + { .lomax = 142000, .pd = 0x36, .d = 0x38 }, + { .lomax = 152750, .pd = 0x35, .d = 0x34 }, + { .lomax = 165500, .pd = 0x34, .d = 0x30 }, + { .lomax = 180500, .pd = 0x33, .d = 0x2c }, + { .lomax = 198750, .pd = 0x32, .d = 0x28 }, + { .lomax = 220750, .pd = 0x31, .d = 0x24 }, + { .lomax = 248500, .pd = 0x30, .d = 0x20 }, + { .lomax = 265000, .pd = 0x27, .d = 0x1e }, + { .lomax = 284000, .pd = 0x26, .d = 0x1c }, + { .lomax = 305500, .pd = 0x25, .d = 0x1a }, + { .lomax = 331000, .pd = 0x24, .d = 0x18 }, + { .lomax = 361000, .pd = 0x23, .d = 0x16 }, + { .lomax = 397500, .pd = 0x22, .d = 0x14 }, + { .lomax = 441500, .pd = 0x21, .d = 0x12 }, + { .lomax = 497000, .pd = 0x20, .d = 0x10 }, + { .lomax = 530000, .pd = 0x17, .d = 0x0f }, + { .lomax = 568000, .pd = 0x16, .d = 0x0e }, + { .lomax = 611000, .pd = 0x15, .d = 0x0d }, + { .lomax = 662000, .pd = 0x14, .d = 0x0c }, + { .lomax = 722000, .pd = 0x13, .d = 0x0b }, + { .lomax = 795000, .pd = 0x12, .d = 0x0a }, + { .lomax = 883000, .pd = 0x11, .d = 0x09 }, + { .lomax = 994000, .pd = 0x10, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c1_cal_pll[] = { { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, @@ -116,6 +160,44 @@ static struct tda18271_pll_map tda18271_cal_pll[] = { { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ }; +static struct tda18271_pll_map tda18271c2_cal_pll[] = { + { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, + { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, + { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, + { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, + { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, + { .lomax = 87875, .pd = 0xca, .d = 0x50 }, + { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, + { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, + { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, + { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, + { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, + { .lomax = 175750, .pd = 0xba, .d = 0x28 }, + { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, + { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, + { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, + { .lomax = 270500, .pd = 0xad, .d = 0x1a }, + { .lomax = 293000, .pd = 0xac, .d = 0x18 }, + { .lomax = 319500, .pd = 0xab, .d = 0x16 }, + { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, + { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, + { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, + { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, + { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 781000, .pd = 0x99, .d = 0x09 }, + { .lomax = 879000, .pd = 0x98, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + static struct tda18271_map tda18271_bp_filter[] = { { .rfmax = 62000, .val = 0x00 }, { .rfmax = 84000, .val = 0x01 }, @@ -127,7 +209,7 @@ static struct tda18271_map tda18271_bp_filter[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -static struct tda18271_map tda18271_km[] = { +static struct tda18271_map tda18271c1_km[] = { { .rfmax = 61100, .val = 0x74 }, { .rfmax = 350000, .val = 0x40 }, { .rfmax = 720000, .val = 0x30 }, @@ -135,6 +217,15 @@ static struct tda18271_map tda18271_km[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; +static struct tda18271_map tda18271c2_km[] = { + { .rfmax = 47900, .val = 0x38 }, + { .rfmax = 61100, .val = 0x44 }, + { .rfmax = 350000, .val = 0x30 }, + { .rfmax = 720000, .val = 0x24 }, + { .rfmax = 865000, .val = 0x3c }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + static struct tda18271_map tda18271_rf_band[] = { { .rfmax = 47900, .val = 0x00 }, { .rfmax = 61100, .val = 0x01 }, @@ -236,7 +327,7 @@ static struct tda18271_map tda18271_gain_taper[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; -static struct tda18271_map tda18271_rf_cal[] = { +static struct tda18271_map tda18271c1_rf_cal[] = { { .rfmax = 41000, .val = 0x1e }, { .rfmax = 43000, .val = 0x30 }, { .rfmax = 45000, .val = 0x43 }, @@ -257,6 +348,446 @@ static struct tda18271_map tda18271_rf_cal[] = { { .rfmax = 0, .val = 0x00 }, /* end */ }; +static struct tda18271_map tda18271c2_rf_cal[] = { + { .rfmax = 41000, .val = 0x0f }, + { .rfmax = 43000, .val = 0x1c }, + { .rfmax = 45000, .val = 0x2f }, + { .rfmax = 46000, .val = 0x39 }, + { .rfmax = 47000, .val = 0x40 }, + { .rfmax = 47900, .val = 0x50 }, + { .rfmax = 49100, .val = 0x16 }, + { .rfmax = 50000, .val = 0x18 }, + { .rfmax = 51000, .val = 0x20 }, + { .rfmax = 53000, .val = 0x28 }, + { .rfmax = 55000, .val = 0x2b }, + { .rfmax = 56000, .val = 0x32 }, + { .rfmax = 57000, .val = 0x35 }, + { .rfmax = 58000, .val = 0x3e }, + { .rfmax = 59000, .val = 0x43 }, + { .rfmax = 60000, .val = 0x4e }, + { .rfmax = 61100, .val = 0x55 }, + { .rfmax = 63000, .val = 0x0f }, + { .rfmax = 64000, .val = 0x11 }, + { .rfmax = 65000, .val = 0x12 }, + { .rfmax = 66000, .val = 0x15 }, + { .rfmax = 67000, .val = 0x16 }, + { .rfmax = 68000, .val = 0x17 }, + { .rfmax = 70000, .val = 0x19 }, + { .rfmax = 71000, .val = 0x1c }, + { .rfmax = 72000, .val = 0x1d }, + { .rfmax = 73000, .val = 0x1f }, + { .rfmax = 74000, .val = 0x20 }, + { .rfmax = 75000, .val = 0x21 }, + { .rfmax = 76000, .val = 0x24 }, + { .rfmax = 77000, .val = 0x25 }, + { .rfmax = 78000, .val = 0x27 }, + { .rfmax = 80000, .val = 0x28 }, + { .rfmax = 81000, .val = 0x29 }, + { .rfmax = 82000, .val = 0x2d }, + { .rfmax = 83000, .val = 0x2e }, + { .rfmax = 84000, .val = 0x2f }, + { .rfmax = 85000, .val = 0x31 }, + { .rfmax = 86000, .val = 0x33 }, + { .rfmax = 87000, .val = 0x34 }, + { .rfmax = 88000, .val = 0x35 }, + { .rfmax = 89000, .val = 0x37 }, + { .rfmax = 90000, .val = 0x38 }, + { .rfmax = 91000, .val = 0x39 }, + { .rfmax = 93000, .val = 0x3c }, + { .rfmax = 94000, .val = 0x3e }, + { .rfmax = 95000, .val = 0x3f }, + { .rfmax = 96000, .val = 0x40 }, + { .rfmax = 97000, .val = 0x42 }, + { .rfmax = 99000, .val = 0x45 }, + { .rfmax = 100000, .val = 0x46 }, + { .rfmax = 102000, .val = 0x48 }, + { .rfmax = 103000, .val = 0x4a }, + { .rfmax = 105000, .val = 0x4d }, + { .rfmax = 106000, .val = 0x4e }, + { .rfmax = 107000, .val = 0x50 }, + { .rfmax = 108000, .val = 0x51 }, + { .rfmax = 110000, .val = 0x54 }, + { .rfmax = 111000, .val = 0x56 }, + { .rfmax = 112000, .val = 0x57 }, + { .rfmax = 113000, .val = 0x58 }, + { .rfmax = 114000, .val = 0x59 }, + { .rfmax = 115000, .val = 0x5c }, + { .rfmax = 116000, .val = 0x5d }, + { .rfmax = 117000, .val = 0x5f }, + { .rfmax = 119000, .val = 0x60 }, + { .rfmax = 120000, .val = 0x64 }, + { .rfmax = 121000, .val = 0x65 }, + { .rfmax = 122000, .val = 0x66 }, + { .rfmax = 123000, .val = 0x68 }, + { .rfmax = 124000, .val = 0x69 }, + { .rfmax = 125000, .val = 0x6c }, + { .rfmax = 126000, .val = 0x6d }, + { .rfmax = 127000, .val = 0x6e }, + { .rfmax = 128000, .val = 0x70 }, + { .rfmax = 129000, .val = 0x71 }, + { .rfmax = 130000, .val = 0x75 }, + { .rfmax = 131000, .val = 0x77 }, + { .rfmax = 132000, .val = 0x78 }, + { .rfmax = 133000, .val = 0x7b }, + { .rfmax = 134000, .val = 0x7e }, + { .rfmax = 135000, .val = 0x81 }, + { .rfmax = 136000, .val = 0x82 }, + { .rfmax = 137000, .val = 0x87 }, + { .rfmax = 138000, .val = 0x88 }, + { .rfmax = 139000, .val = 0x8d }, + { .rfmax = 140000, .val = 0x8e }, + { .rfmax = 141000, .val = 0x91 }, + { .rfmax = 142000, .val = 0x95 }, + { .rfmax = 143000, .val = 0x9a }, + { .rfmax = 144000, .val = 0x9d }, + { .rfmax = 145000, .val = 0xa1 }, + { .rfmax = 146000, .val = 0xa2 }, + { .rfmax = 147000, .val = 0xa4 }, + { .rfmax = 148000, .val = 0xa9 }, + { .rfmax = 149000, .val = 0xae }, + { .rfmax = 150000, .val = 0xb0 }, + { .rfmax = 151000, .val = 0xb1 }, + { .rfmax = 152000, .val = 0xb7 }, + { .rfmax = 153000, .val = 0xbd }, + { .rfmax = 154000, .val = 0x20 }, + { .rfmax = 155000, .val = 0x22 }, + { .rfmax = 156000, .val = 0x24 }, + { .rfmax = 157000, .val = 0x25 }, + { .rfmax = 158000, .val = 0x27 }, + { .rfmax = 159000, .val = 0x29 }, + { .rfmax = 160000, .val = 0x2c }, + { .rfmax = 161000, .val = 0x2d }, + { .rfmax = 163000, .val = 0x2e }, + { .rfmax = 164000, .val = 0x2f }, + { .rfmax = 165000, .val = 0x30 }, + { .rfmax = 166000, .val = 0x11 }, + { .rfmax = 167000, .val = 0x12 }, + { .rfmax = 168000, .val = 0x13 }, + { .rfmax = 169000, .val = 0x14 }, + { .rfmax = 170000, .val = 0x15 }, + { .rfmax = 172000, .val = 0x16 }, + { .rfmax = 173000, .val = 0x17 }, + { .rfmax = 174000, .val = 0x18 }, + { .rfmax = 175000, .val = 0x1a }, + { .rfmax = 176000, .val = 0x1b }, + { .rfmax = 178000, .val = 0x1d }, + { .rfmax = 179000, .val = 0x1e }, + { .rfmax = 180000, .val = 0x1f }, + { .rfmax = 181000, .val = 0x20 }, + { .rfmax = 182000, .val = 0x21 }, + { .rfmax = 183000, .val = 0x22 }, + { .rfmax = 184000, .val = 0x24 }, + { .rfmax = 185000, .val = 0x25 }, + { .rfmax = 186000, .val = 0x26 }, + { .rfmax = 187000, .val = 0x27 }, + { .rfmax = 188000, .val = 0x29 }, + { .rfmax = 189000, .val = 0x2a }, + { .rfmax = 190000, .val = 0x2c }, + { .rfmax = 191000, .val = 0x2d }, + { .rfmax = 192000, .val = 0x2e }, + { .rfmax = 193000, .val = 0x2f }, + { .rfmax = 194000, .val = 0x30 }, + { .rfmax = 195000, .val = 0x33 }, + { .rfmax = 196000, .val = 0x35 }, + { .rfmax = 198000, .val = 0x36 }, + { .rfmax = 200000, .val = 0x38 }, + { .rfmax = 201000, .val = 0x3c }, + { .rfmax = 202000, .val = 0x3d }, + { .rfmax = 203500, .val = 0x3e }, + { .rfmax = 206000, .val = 0x0e }, + { .rfmax = 208000, .val = 0x0f }, + { .rfmax = 212000, .val = 0x10 }, + { .rfmax = 216000, .val = 0x11 }, + { .rfmax = 217000, .val = 0x12 }, + { .rfmax = 218000, .val = 0x13 }, + { .rfmax = 220000, .val = 0x14 }, + { .rfmax = 222000, .val = 0x15 }, + { .rfmax = 225000, .val = 0x16 }, + { .rfmax = 228000, .val = 0x17 }, + { .rfmax = 231000, .val = 0x18 }, + { .rfmax = 234000, .val = 0x19 }, + { .rfmax = 235000, .val = 0x1a }, + { .rfmax = 236000, .val = 0x1b }, + { .rfmax = 237000, .val = 0x1c }, + { .rfmax = 240000, .val = 0x1d }, + { .rfmax = 242000, .val = 0x1f }, + { .rfmax = 247000, .val = 0x20 }, + { .rfmax = 249000, .val = 0x21 }, + { .rfmax = 252000, .val = 0x22 }, + { .rfmax = 253000, .val = 0x23 }, + { .rfmax = 254000, .val = 0x24 }, + { .rfmax = 256000, .val = 0x25 }, + { .rfmax = 259000, .val = 0x26 }, + { .rfmax = 262000, .val = 0x27 }, + { .rfmax = 264000, .val = 0x28 }, + { .rfmax = 267000, .val = 0x29 }, + { .rfmax = 269000, .val = 0x2a }, + { .rfmax = 271000, .val = 0x2b }, + { .rfmax = 273000, .val = 0x2c }, + { .rfmax = 275000, .val = 0x2d }, + { .rfmax = 277000, .val = 0x2e }, + { .rfmax = 279000, .val = 0x2f }, + { .rfmax = 282000, .val = 0x30 }, + { .rfmax = 284000, .val = 0x31 }, + { .rfmax = 286000, .val = 0x32 }, + { .rfmax = 287000, .val = 0x33 }, + { .rfmax = 290000, .val = 0x34 }, + { .rfmax = 293000, .val = 0x35 }, + { .rfmax = 295000, .val = 0x36 }, + { .rfmax = 297000, .val = 0x37 }, + { .rfmax = 300000, .val = 0x38 }, + { .rfmax = 303000, .val = 0x39 }, + { .rfmax = 305000, .val = 0x3a }, + { .rfmax = 306000, .val = 0x3b }, + { .rfmax = 307000, .val = 0x3c }, + { .rfmax = 310000, .val = 0x3d }, + { .rfmax = 312000, .val = 0x3e }, + { .rfmax = 315000, .val = 0x3f }, + { .rfmax = 318000, .val = 0x40 }, + { .rfmax = 320000, .val = 0x41 }, + { .rfmax = 323000, .val = 0x42 }, + { .rfmax = 324000, .val = 0x43 }, + { .rfmax = 325000, .val = 0x44 }, + { .rfmax = 327000, .val = 0x45 }, + { .rfmax = 331000, .val = 0x46 }, + { .rfmax = 334000, .val = 0x47 }, + { .rfmax = 337000, .val = 0x48 }, + { .rfmax = 339000, .val = 0x49 }, + { .rfmax = 340000, .val = 0x4a }, + { .rfmax = 341000, .val = 0x4b }, + { .rfmax = 343000, .val = 0x4c }, + { .rfmax = 345000, .val = 0x4d }, + { .rfmax = 349000, .val = 0x4e }, + { .rfmax = 352000, .val = 0x4f }, + { .rfmax = 353000, .val = 0x50 }, + { .rfmax = 355000, .val = 0x51 }, + { .rfmax = 357000, .val = 0x52 }, + { .rfmax = 359000, .val = 0x53 }, + { .rfmax = 361000, .val = 0x54 }, + { .rfmax = 362000, .val = 0x55 }, + { .rfmax = 364000, .val = 0x56 }, + { .rfmax = 368000, .val = 0x57 }, + { .rfmax = 370000, .val = 0x58 }, + { .rfmax = 372000, .val = 0x59 }, + { .rfmax = 375000, .val = 0x5a }, + { .rfmax = 376000, .val = 0x5b }, + { .rfmax = 377000, .val = 0x5c }, + { .rfmax = 379000, .val = 0x5d }, + { .rfmax = 382000, .val = 0x5e }, + { .rfmax = 384000, .val = 0x5f }, + { .rfmax = 385000, .val = 0x60 }, + { .rfmax = 386000, .val = 0x61 }, + { .rfmax = 388000, .val = 0x62 }, + { .rfmax = 390000, .val = 0x63 }, + { .rfmax = 393000, .val = 0x64 }, + { .rfmax = 394000, .val = 0x65 }, + { .rfmax = 396000, .val = 0x66 }, + { .rfmax = 397000, .val = 0x67 }, + { .rfmax = 398000, .val = 0x68 }, + { .rfmax = 400000, .val = 0x69 }, + { .rfmax = 402000, .val = 0x6a }, + { .rfmax = 403000, .val = 0x6b }, + { .rfmax = 407000, .val = 0x6c }, + { .rfmax = 408000, .val = 0x6d }, + { .rfmax = 409000, .val = 0x6e }, + { .rfmax = 410000, .val = 0x6f }, + { .rfmax = 411000, .val = 0x70 }, + { .rfmax = 412000, .val = 0x71 }, + { .rfmax = 413000, .val = 0x72 }, + { .rfmax = 414000, .val = 0x73 }, + { .rfmax = 417000, .val = 0x74 }, + { .rfmax = 418000, .val = 0x75 }, + { .rfmax = 420000, .val = 0x76 }, + { .rfmax = 422000, .val = 0x77 }, + { .rfmax = 423000, .val = 0x78 }, + { .rfmax = 424000, .val = 0x79 }, + { .rfmax = 427000, .val = 0x7a }, + { .rfmax = 428000, .val = 0x7b }, + { .rfmax = 429000, .val = 0x7d }, + { .rfmax = 432000, .val = 0x7f }, + { .rfmax = 434000, .val = 0x80 }, + { .rfmax = 435000, .val = 0x81 }, + { .rfmax = 436000, .val = 0x83 }, + { .rfmax = 437000, .val = 0x84 }, + { .rfmax = 438000, .val = 0x85 }, + { .rfmax = 439000, .val = 0x86 }, + { .rfmax = 440000, .val = 0x87 }, + { .rfmax = 441000, .val = 0x88 }, + { .rfmax = 442000, .val = 0x89 }, + { .rfmax = 445000, .val = 0x8a }, + { .rfmax = 446000, .val = 0x8b }, + { .rfmax = 447000, .val = 0x8c }, + { .rfmax = 448000, .val = 0x8e }, + { .rfmax = 449000, .val = 0x8f }, + { .rfmax = 450000, .val = 0x90 }, + { .rfmax = 452000, .val = 0x91 }, + { .rfmax = 453000, .val = 0x93 }, + { .rfmax = 454000, .val = 0x94 }, + { .rfmax = 456000, .val = 0x96 }, + { .rfmax = 457000, .val = 0x98 }, + { .rfmax = 461000, .val = 0x11 }, + { .rfmax = 468000, .val = 0x12 }, + { .rfmax = 472000, .val = 0x13 }, + { .rfmax = 473000, .val = 0x14 }, + { .rfmax = 474000, .val = 0x15 }, + { .rfmax = 481000, .val = 0x16 }, + { .rfmax = 486000, .val = 0x17 }, + { .rfmax = 491000, .val = 0x18 }, + { .rfmax = 498000, .val = 0x19 }, + { .rfmax = 499000, .val = 0x1a }, + { .rfmax = 501000, .val = 0x1b }, + { .rfmax = 506000, .val = 0x1c }, + { .rfmax = 511000, .val = 0x1d }, + { .rfmax = 516000, .val = 0x1e }, + { .rfmax = 520000, .val = 0x1f }, + { .rfmax = 521000, .val = 0x20 }, + { .rfmax = 525000, .val = 0x21 }, + { .rfmax = 529000, .val = 0x22 }, + { .rfmax = 533000, .val = 0x23 }, + { .rfmax = 539000, .val = 0x24 }, + { .rfmax = 541000, .val = 0x25 }, + { .rfmax = 547000, .val = 0x26 }, + { .rfmax = 549000, .val = 0x27 }, + { .rfmax = 551000, .val = 0x28 }, + { .rfmax = 556000, .val = 0x29 }, + { .rfmax = 561000, .val = 0x2a }, + { .rfmax = 563000, .val = 0x2b }, + { .rfmax = 565000, .val = 0x2c }, + { .rfmax = 569000, .val = 0x2d }, + { .rfmax = 571000, .val = 0x2e }, + { .rfmax = 577000, .val = 0x2f }, + { .rfmax = 580000, .val = 0x30 }, + { .rfmax = 582000, .val = 0x31 }, + { .rfmax = 584000, .val = 0x32 }, + { .rfmax = 588000, .val = 0x33 }, + { .rfmax = 591000, .val = 0x34 }, + { .rfmax = 596000, .val = 0x35 }, + { .rfmax = 598000, .val = 0x36 }, + { .rfmax = 603000, .val = 0x37 }, + { .rfmax = 604000, .val = 0x38 }, + { .rfmax = 606000, .val = 0x39 }, + { .rfmax = 612000, .val = 0x3a }, + { .rfmax = 615000, .val = 0x3b }, + { .rfmax = 617000, .val = 0x3c }, + { .rfmax = 621000, .val = 0x3d }, + { .rfmax = 622000, .val = 0x3e }, + { .rfmax = 625000, .val = 0x3f }, + { .rfmax = 632000, .val = 0x40 }, + { .rfmax = 633000, .val = 0x41 }, + { .rfmax = 634000, .val = 0x42 }, + { .rfmax = 642000, .val = 0x43 }, + { .rfmax = 643000, .val = 0x44 }, + { .rfmax = 647000, .val = 0x45 }, + { .rfmax = 650000, .val = 0x46 }, + { .rfmax = 652000, .val = 0x47 }, + { .rfmax = 657000, .val = 0x48 }, + { .rfmax = 661000, .val = 0x49 }, + { .rfmax = 662000, .val = 0x4a }, + { .rfmax = 665000, .val = 0x4b }, + { .rfmax = 667000, .val = 0x4c }, + { .rfmax = 670000, .val = 0x4d }, + { .rfmax = 673000, .val = 0x4e }, + { .rfmax = 676000, .val = 0x4f }, + { .rfmax = 677000, .val = 0x50 }, + { .rfmax = 681000, .val = 0x51 }, + { .rfmax = 683000, .val = 0x52 }, + { .rfmax = 686000, .val = 0x53 }, + { .rfmax = 688000, .val = 0x54 }, + { .rfmax = 689000, .val = 0x55 }, + { .rfmax = 691000, .val = 0x56 }, + { .rfmax = 695000, .val = 0x57 }, + { .rfmax = 698000, .val = 0x58 }, + { .rfmax = 703000, .val = 0x59 }, + { .rfmax = 704000, .val = 0x5a }, + { .rfmax = 705000, .val = 0x5b }, + { .rfmax = 707000, .val = 0x5c }, + { .rfmax = 710000, .val = 0x5d }, + { .rfmax = 712000, .val = 0x5e }, + { .rfmax = 717000, .val = 0x5f }, + { .rfmax = 718000, .val = 0x60 }, + { .rfmax = 721000, .val = 0x61 }, + { .rfmax = 722000, .val = 0x62 }, + { .rfmax = 723000, .val = 0x63 }, + { .rfmax = 725000, .val = 0x64 }, + { .rfmax = 727000, .val = 0x65 }, + { .rfmax = 730000, .val = 0x66 }, + { .rfmax = 732000, .val = 0x67 }, + { .rfmax = 735000, .val = 0x68 }, + { .rfmax = 740000, .val = 0x69 }, + { .rfmax = 741000, .val = 0x6a }, + { .rfmax = 742000, .val = 0x6b }, + { .rfmax = 743000, .val = 0x6c }, + { .rfmax = 745000, .val = 0x6d }, + { .rfmax = 747000, .val = 0x6e }, + { .rfmax = 748000, .val = 0x6f }, + { .rfmax = 750000, .val = 0x70 }, + { .rfmax = 752000, .val = 0x71 }, + { .rfmax = 754000, .val = 0x72 }, + { .rfmax = 757000, .val = 0x73 }, + { .rfmax = 758000, .val = 0x74 }, + { .rfmax = 760000, .val = 0x75 }, + { .rfmax = 763000, .val = 0x76 }, + { .rfmax = 764000, .val = 0x77 }, + { .rfmax = 766000, .val = 0x78 }, + { .rfmax = 767000, .val = 0x79 }, + { .rfmax = 768000, .val = 0x7a }, + { .rfmax = 773000, .val = 0x7b }, + { .rfmax = 774000, .val = 0x7c }, + { .rfmax = 776000, .val = 0x7d }, + { .rfmax = 777000, .val = 0x7e }, + { .rfmax = 778000, .val = 0x7f }, + { .rfmax = 779000, .val = 0x80 }, + { .rfmax = 781000, .val = 0x81 }, + { .rfmax = 783000, .val = 0x82 }, + { .rfmax = 784000, .val = 0x83 }, + { .rfmax = 785000, .val = 0x84 }, + { .rfmax = 786000, .val = 0x85 }, + { .rfmax = 793000, .val = 0x86 }, + { .rfmax = 794000, .val = 0x87 }, + { .rfmax = 795000, .val = 0x88 }, + { .rfmax = 797000, .val = 0x89 }, + { .rfmax = 799000, .val = 0x8a }, + { .rfmax = 801000, .val = 0x8b }, + { .rfmax = 802000, .val = 0x8c }, + { .rfmax = 803000, .val = 0x8d }, + { .rfmax = 804000, .val = 0x8e }, + { .rfmax = 810000, .val = 0x90 }, + { .rfmax = 811000, .val = 0x91 }, + { .rfmax = 812000, .val = 0x92 }, + { .rfmax = 814000, .val = 0x93 }, + { .rfmax = 816000, .val = 0x94 }, + { .rfmax = 817000, .val = 0x96 }, + { .rfmax = 818000, .val = 0x97 }, + { .rfmax = 820000, .val = 0x98 }, + { .rfmax = 821000, .val = 0x99 }, + { .rfmax = 822000, .val = 0x9a }, + { .rfmax = 828000, .val = 0x9b }, + { .rfmax = 829000, .val = 0x9d }, + { .rfmax = 830000, .val = 0x9f }, + { .rfmax = 831000, .val = 0xa0 }, + { .rfmax = 833000, .val = 0xa1 }, + { .rfmax = 835000, .val = 0xa2 }, + { .rfmax = 836000, .val = 0xa3 }, + { .rfmax = 837000, .val = 0xa4 }, + { .rfmax = 838000, .val = 0xa6 }, + { .rfmax = 840000, .val = 0xa8 }, + { .rfmax = 842000, .val = 0xa9 }, + { .rfmax = 845000, .val = 0xaa }, + { .rfmax = 846000, .val = 0xab }, + { .rfmax = 847000, .val = 0xad }, + { .rfmax = 848000, .val = 0xae }, + { .rfmax = 852000, .val = 0xaf }, + { .rfmax = 853000, .val = 0xb0 }, + { .rfmax = 858000, .val = 0xb1 }, + { .rfmax = 860000, .val = 0xb2 }, + { .rfmax = 861000, .val = 0xb3 }, + { .rfmax = 862000, .val = 0xb4 }, + { .rfmax = 863000, .val = 0xb6 }, + { .rfmax = 864000, .val = 0xb8 }, + { .rfmax = 865000, .val = 0xb9 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + static struct tda18271_map tda18271_ir_measure[] = { { .rfmax = 30000, .val = 4 }, { .rfmax = 200000, .val = 5 }, @@ -265,23 +796,293 @@ static struct tda18271_map tda18271_ir_measure[] = { { .rfmax = 0, .val = 0 }, /* end */ }; +static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 55000, .val = 0x00 }, + { .rfmax = 61100, .val = 0x0a }, + { .rfmax = 64000, .val = 0x0a }, + { .rfmax = 82000, .val = 0x14 }, + { .rfmax = 84000, .val = 0x19 }, + { .rfmax = 119000, .val = 0x1c }, + { .rfmax = 124000, .val = 0x20 }, + { .rfmax = 129000, .val = 0x2a }, + { .rfmax = 134000, .val = 0x32 }, + { .rfmax = 139000, .val = 0x39 }, + { .rfmax = 144000, .val = 0x3e }, + { .rfmax = 149000, .val = 0x3f }, + { .rfmax = 152600, .val = 0x40 }, + { .rfmax = 154000, .val = 0x40 }, + { .rfmax = 164700, .val = 0x41 }, + { .rfmax = 203500, .val = 0x32 }, + { .rfmax = 353000, .val = 0x19 }, + { .rfmax = 356000, .val = 0x1a }, + { .rfmax = 359000, .val = 0x1b }, + { .rfmax = 363000, .val = 0x1c }, + { .rfmax = 366000, .val = 0x1d }, + { .rfmax = 369000, .val = 0x1e }, + { .rfmax = 373000, .val = 0x1f }, + { .rfmax = 376000, .val = 0x20 }, + { .rfmax = 379000, .val = 0x21 }, + { .rfmax = 383000, .val = 0x22 }, + { .rfmax = 386000, .val = 0x23 }, + { .rfmax = 389000, .val = 0x24 }, + { .rfmax = 393000, .val = 0x25 }, + { .rfmax = 396000, .val = 0x26 }, + { .rfmax = 399000, .val = 0x27 }, + { .rfmax = 402000, .val = 0x28 }, + { .rfmax = 404000, .val = 0x29 }, + { .rfmax = 407000, .val = 0x2a }, + { .rfmax = 409000, .val = 0x2b }, + { .rfmax = 412000, .val = 0x2c }, + { .rfmax = 414000, .val = 0x2d }, + { .rfmax = 417000, .val = 0x2e }, + { .rfmax = 419000, .val = 0x2f }, + { .rfmax = 422000, .val = 0x30 }, + { .rfmax = 424000, .val = 0x31 }, + { .rfmax = 427000, .val = 0x32 }, + { .rfmax = 429000, .val = 0x33 }, + { .rfmax = 432000, .val = 0x34 }, + { .rfmax = 434000, .val = 0x35 }, + { .rfmax = 437000, .val = 0x36 }, + { .rfmax = 439000, .val = 0x37 }, + { .rfmax = 442000, .val = 0x38 }, + { .rfmax = 444000, .val = 0x39 }, + { .rfmax = 447000, .val = 0x3a }, + { .rfmax = 449000, .val = 0x3b }, + { .rfmax = 457800, .val = 0x3c }, + { .rfmax = 465000, .val = 0x0f }, + { .rfmax = 477000, .val = 0x12 }, + { .rfmax = 483000, .val = 0x14 }, + { .rfmax = 502000, .val = 0x19 }, + { .rfmax = 508000, .val = 0x1b }, + { .rfmax = 519000, .val = 0x1c }, + { .rfmax = 522000, .val = 0x1d }, + { .rfmax = 524000, .val = 0x1e }, + { .rfmax = 534000, .val = 0x1f }, + { .rfmax = 549000, .val = 0x20 }, + { .rfmax = 554000, .val = 0x22 }, + { .rfmax = 584000, .val = 0x24 }, + { .rfmax = 589000, .val = 0x26 }, + { .rfmax = 658000, .val = 0x27 }, + { .rfmax = 664000, .val = 0x2c }, + { .rfmax = 669000, .val = 0x2d }, + { .rfmax = 699000, .val = 0x2e }, + { .rfmax = 704000, .val = 0x30 }, + { .rfmax = 709000, .val = 0x31 }, + { .rfmax = 714000, .val = 0x32 }, + { .rfmax = 724000, .val = 0x33 }, + { .rfmax = 729000, .val = 0x36 }, + { .rfmax = 739000, .val = 0x38 }, + { .rfmax = 744000, .val = 0x39 }, + { .rfmax = 749000, .val = 0x3b }, + { .rfmax = 754000, .val = 0x3c }, + { .rfmax = 759000, .val = 0x3d }, + { .rfmax = 764000, .val = 0x3e }, + { .rfmax = 769000, .val = 0x3f }, + { .rfmax = 774000, .val = 0x40 }, + { .rfmax = 779000, .val = 0x41 }, + { .rfmax = 784000, .val = 0x43 }, + { .rfmax = 789000, .val = 0x46 }, + { .rfmax = 794000, .val = 0x48 }, + { .rfmax = 799000, .val = 0x4b }, + { .rfmax = 804000, .val = 0x4f }, + { .rfmax = 809000, .val = 0x54 }, + { .rfmax = 814000, .val = 0x59 }, + { .rfmax = 819000, .val = 0x5d }, + { .rfmax = 824000, .val = 0x61 }, + { .rfmax = 829000, .val = 0x68 }, + { .rfmax = 834000, .val = 0x6e }, + { .rfmax = 839000, .val = 0x75 }, + { .rfmax = 844000, .val = 0x7e }, + { .rfmax = 849000, .val = 0x82 }, + { .rfmax = 854000, .val = 0x84 }, + { .rfmax = 859000, .val = 0x8f }, + { .rfmax = 865000, .val = 0x9a }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/*---------------------------------------------------------------------*/ + +struct tda18271_thermo_map { + u8 d; + u8 r0; + u8 r1; +}; + +static struct tda18271_thermo_map tda18271_thermometer[] = { + { .d = 0x00, .r0 = 60, .r1 = 92 }, + { .d = 0x01, .r0 = 62, .r1 = 94 }, + { .d = 0x02, .r0 = 66, .r1 = 98 }, + { .d = 0x03, .r0 = 64, .r1 = 96 }, + { .d = 0x04, .r0 = 74, .r1 = 106 }, + { .d = 0x05, .r0 = 72, .r1 = 104 }, + { .d = 0x06, .r0 = 68, .r1 = 100 }, + { .d = 0x07, .r0 = 70, .r1 = 102 }, + { .d = 0x08, .r0 = 90, .r1 = 122 }, + { .d = 0x09, .r0 = 88, .r1 = 120 }, + { .d = 0x0a, .r0 = 84, .r1 = 116 }, + { .d = 0x0b, .r0 = 86, .r1 = 118 }, + { .d = 0x0c, .r0 = 76, .r1 = 108 }, + { .d = 0x0d, .r0 = 78, .r1 = 110 }, + { .d = 0x0e, .r0 = 82, .r1 = 114 }, + { .d = 0x0f, .r0 = 80, .r1 = 112 }, + { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ +}; + +int tda18271_lookup_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int val, i = 0; + + while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { + if (tda18271_thermometer[i + 1].d == 0) + break; + i++; + } + + if ((regs[R_TM] & 0x20) == 0x20) + val = tda18271_thermometer[i].r1; + else + val = tda18271_thermometer[i].r0; + + tda_map("(%d) tm = %d\n", i, val); + + return val; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_cid_target_map { + u32 rfmax; + u8 target; + u16 limit; +}; + +static struct tda18271_cid_target_map tda18271_cid_target[] = { + { .rfmax = 46000, .target = 0x04, .limit = 1800 }, + { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, + { .rfmax = 79100, .target = 0x01, .limit = 4000 }, + { .rfmax = 136800, .target = 0x18, .limit = 4000 }, + { .rfmax = 156700, .target = 0x18, .limit = 4000 }, + { .rfmax = 156700, .target = 0x18, .limit = 4000 }, + { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, + { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, + { .rfmax = 345000, .target = 0x18, .limit = 4000 }, + { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, + { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, + { .rfmax = 697500, .target = 0x32, .limit = 4000 }, + { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, + { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ +}; + +int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, u16 *count_limit) +{ + int i = 0; + + while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { + if (tda18271_cid_target[i + 1].rfmax == 0) + break; + i++; + } + *cid_target = tda18271_cid_target[i].target; + *count_limit = tda18271_cid_target[i].limit; + + tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, + tda18271_cid_target[i].target, tda18271_cid_target[i].limit); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { + { .rfmax = 47900, .rfband = 0x00, + .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 61100, .rfband = 0x01, + .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 152600, .rfband = 0x02, + .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, + { .rfmax = 164700, .rfband = 0x03, + .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 203500, .rfband = 0x04, + .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 457800, .rfband = 0x05, + .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, + { .rfmax = 865000, .rfband = 0x06, + .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, + { .rfmax = 0, .rfband = 0x00, + .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ +}; + +int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + int i = 0; + + while ((map[i].rfmax * 1000) < *freq) { + if (tda18271_debug & DBG_ADV) + tda_map("(%d) rfmax = %d < freq = %d, " + "rf1_def = %d, rf2_def = %d, rf3_def = %d, " + "rf1 = %d, rf2 = %d, rf3 = %d, " + "rf_a1 = %d, rf_a2 = %d, " + "rf_b1 = %d, rf_b2 = %d\n", + i, map[i].rfmax * 1000, *freq, + map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, + map[i].rf1, map[i].rf2, map[i].rf3, + map[i].rf_a1, map[i].rf_a2, + map[i].rf_b1, map[i].rf_b2); + if (map[i].rfmax == 0) + return -EINVAL; + i++; + } + if (rf_band) + *rf_band = map[i].rfband; + + tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); + + return i; +} + /*---------------------------------------------------------------------*/ -int tda18271_lookup_pll_map(enum tda18271_map_type map_type, +struct tda18271_map_layout { + struct tda18271_pll_map *main_pll; + struct tda18271_pll_map *cal_pll; + + struct tda18271_map *rf_cal; + struct tda18271_map *rf_cal_kmco; + struct tda18271_map *rf_cal_dc_over_dt; + + struct tda18271_map *bp_filter; + struct tda18271_map *rf_band; + struct tda18271_map *gain_taper; + struct tda18271_map *ir_measure; +}; + +/*---------------------------------------------------------------------*/ + +int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, u32 *freq, u8 *post_div, u8 *div) { + struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_pll_map *map = NULL; unsigned int i = 0; char *map_name; int ret = 0; + BUG_ON(!priv->maps); + switch (map_type) { case MAIN_PLL: - map = tda18271_main_pll; + map = priv->maps->main_pll; map_name = "main_pll"; break; case CAL_PLL: - map = tda18271_cal_pll; + map = priv->maps->cal_pll; map_name = "cal_pll"; break; default: @@ -308,44 +1109,53 @@ int tda18271_lookup_pll_map(enum tda18271_map_type map_type, *post_div = map[i].pd; *div = map[i].d; - tda_map("%s: post div = 0x%02x, div = 0x%02x\n", - map_name, *post_div, *div); + tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", + i, map_name, *post_div, *div); fail: return ret; } -int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) +int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val) { + struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_map *map = NULL; unsigned int i = 0; char *map_name; int ret = 0; + BUG_ON(!priv->maps); + switch (map_type) { case BP_FILTER: - map = tda18271_bp_filter; + map = priv->maps->bp_filter; map_name = "bp_filter"; break; case RF_CAL_KMCO: - map = tda18271_km; + map = priv->maps->rf_cal_kmco; map_name = "km"; break; case RF_BAND: - map = tda18271_rf_band; + map = priv->maps->rf_band; map_name = "rf_band"; break; case GAIN_TAPER: - map = tda18271_gain_taper; + map = priv->maps->gain_taper; map_name = "gain_taper"; break; case RF_CAL: - map = tda18271_rf_cal; + map = priv->maps->rf_cal; map_name = "rf_cal"; break; case IR_MEASURE: - map = tda18271_ir_measure; + map = priv->maps->ir_measure; map_name = "ir_measure"; break; + case RF_CAL_DC_OVER_DT: + map = priv->maps->rf_cal_dc_over_dt; + map_name = "rf_cal_dc_over_dt"; + break; default: /* we should never get here */ map_name = "undefined"; @@ -369,11 +1179,99 @@ int tda18271_lookup_map(enum tda18271_map_type map_type, u32 *freq, u8 *val) } *val = map[i].val; - tda_map("%s: 0x%02x\n", map_name, *val); + tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); fail: return ret; } +/*---------------------------------------------------------------------*/ + +static struct tda18271_std_map tda18271c1_std_map = { + .atv_b = { .if_freq = 6750000, .std_bits = 0x0e }, + .atv_dk = { .if_freq = 7750000, .std_bits = 0x0f }, + .atv_gh = { .if_freq = 7750000, .std_bits = 0x0f }, + .atv_i = { .if_freq = 7750000, .std_bits = 0x0f }, + .atv_l = { .if_freq = 7750000, .std_bits = 0x0f }, + .atv_lc = { .if_freq = 1250000, .std_bits = 0x0f }, + .atv_mn = { .if_freq = 5750000, .std_bits = 0x0d }, + .atsc_6 = { .if_freq = 5380000, .std_bits = 0x1b }, + .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1b }, + .dvbt_7 = { .if_freq = 3800000, .std_bits = 0x19 }, + .dvbt_8 = { .if_freq = 4300000, .std_bits = 0x1a }, + .qam_6 = { .if_freq = 4000000, .std_bits = 0x18 }, + .qam_8 = { .if_freq = 5000000, .std_bits = 0x1f }, +}; + +static struct tda18271_std_map tda18271c2_std_map = { + .atv_b = { .if_freq = 6000000, .std_bits = 0x0d }, + .atv_dk = { .if_freq = 6900000, .std_bits = 0x0e }, + .atv_gh = { .if_freq = 7100000, .std_bits = 0x0e }, + .atv_i = { .if_freq = 7250000, .std_bits = 0x0e }, + .atv_l = { .if_freq = 6900000, .std_bits = 0x0e }, + .atv_lc = { .if_freq = 1250000, .std_bits = 0x0e }, + .atv_mn = { .if_freq = 5400000, .std_bits = 0x0c }, + .atsc_6 = { .if_freq = 5380000, .std_bits = 0x1b }, + .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1c }, + .dvbt_7 = { .if_freq = 3500000, .std_bits = 0x1c }, + .dvbt_8 = { .if_freq = 4000000, .std_bits = 0x1d }, + .qam_6 = { .if_freq = 4000000, .std_bits = 0x1d }, + .qam_8 = { .if_freq = 5000000, .std_bits = 0x1f }, +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_map_layout tda18271c1_map_layout = { + .main_pll = tda18271c1_main_pll, + .cal_pll = tda18271c1_cal_pll, + + .rf_cal = tda18271c1_rf_cal, + .rf_cal_kmco = tda18271c1_km, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +static struct tda18271_map_layout tda18271c2_map_layout = { + .main_pll = tda18271c2_main_pll, + .cal_pll = tda18271c2_cal_pll, + + .rf_cal = tda18271c2_rf_cal, + .rf_cal_kmco = tda18271c2_km, + + .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +int tda18271_assign_map_layout(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = 0; + + switch (priv->id) { + case TDA18271HDC1: + priv->maps = &tda18271c1_map_layout; + priv->std = &tda18271c1_std_map; + break; + case TDA18271HDC2: + priv->maps = &tda18271c2_map_layout; + priv->std = &tda18271c2_std_map; + break; + default: + ret = -EINVAL; + break; + } + memcpy(priv->rf_cal_state, &tda18271_rf_band_template, + sizeof(tda18271_rf_band_template)); + + return ret; +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index bb62d5629af..54d261a2f25 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -570,7 +570,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) return -EREMOTEIO; } - if (data == 0x83) { + if ((data == 0x83) || (data == 0x84)) { priv->ver |= TDA18271; tda18271_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, -- cgit v1.2.3 From 59067f7ed491ec95e6e9033e35e1ae726cff3cee Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 2 Jan 2008 01:58:26 -0300 Subject: V4L/DVB (6961): tda18271: move common code to tda18271-common.c Move some common code to a new file to make this easier to look at. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Makefile | 2 +- drivers/media/dvb/frontends/tda18271-common.c | 619 ++++++++++++++++++++++++++ drivers/media/dvb/frontends/tda18271-fe.c | 583 +----------------------- drivers/media/dvb/frontends/tda18271-priv.h | 19 +- drivers/media/dvb/frontends/tda18271-tables.c | 2 +- drivers/media/dvb/frontends/tda18271.h | 2 +- 6 files changed, 641 insertions(+), 586 deletions(-) create mode 100644 drivers/media/dvb/frontends/tda18271-common.c diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 1c082a6a949..16bd107ebd3 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -5,7 +5,7 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/video/ -tda18271-objs := tda18271-tables.o tda18271-fe.o +tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c new file mode 100644 index 00000000000..4adc7390ba0 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-common.c @@ -0,0 +1,619 @@ +/* + tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky + + 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 + (at your option) any later version. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tda18271-priv.h" + +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + enum tda18271_i2c_gate gate; + int ret = 0; + + switch (priv->gate) { + case TDA18271_GATE_DIGITAL: + case TDA18271_GATE_ANALOG: + gate = priv->gate; + break; + case TDA18271_GATE_AUTO: + default: + switch (priv->mode) { + case TDA18271_DIGITAL: + gate = TDA18271_GATE_DIGITAL; + break; + case TDA18271_ANALOG: + default: + gate = TDA18271_GATE_ANALOG; + break; + } + } + + switch (gate) { + case TDA18271_GATE_ANALOG: + if (fe->ops.analog_ops.i2c_gate_ctrl) + ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); + break; + case TDA18271_GATE_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_reg("=== TDA18271 REG DUMP ===\n"); + tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); + tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); + tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); + tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); + tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); + tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); + tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); + tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); + tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); + tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); + tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); + tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); + tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); + tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); + tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); + tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); + + /* only dump extended regs if DBG_ADV is set */ + if (!(tda18271_debug & DBG_ADV)) + return; + + /* W indicates write-only registers. + * Register dump for write-only registers shows last value written. */ + + tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); + tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); + tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); + tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); + tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); + tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); + tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); + tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); + tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); + tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); + tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); + tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); + tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); + tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); + tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); + tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); + tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); + tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); + tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); + tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); + tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); + tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); + tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); +} + +int tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 0); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_read_extended(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char regdump[TDA18271_NUM_REGS]; + unsigned char buf = 0x00; + int ret, i; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regdump, .len = TDA18271_NUM_REGS } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + for (i = 0; i <= TDA18271_NUM_REGS; i++) { + /* don't update write-only registers */ + if ((i != R_EB9) && + (i != R_EB16) && + (i != R_EB17) && + (i != R_EB19) && + (i != R_EB20)) + regs[i] = regdump[i]; + } + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 1); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS + 1]; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = len + 1 }; + int i, ret; + + BUG_ON((len == 0) || (idx + len > sizeof(buf))); + + buf[0] = idx; + for (i = 1; i <= len; i++) + buf[i] = regs[idx - 1 + i]; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* write registers */ + ret = i2c_transfer(priv->i2c_adap, &msg, 1); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 1) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + return (ret == 1 ? 0 : ret); +} + +/*---------------------------------------------------------------------*/ + +int tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_dbg("initializing registers for device @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), priv->i2c_addr); + + /* initialize registers */ + switch (priv->id) { + case TDA18271HDC1: + regs[R_ID] = 0x83; + break; + case TDA18271HDC2: + regs[R_ID] = 0x84; + break; + }; + + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB1] = 0xff; + break; + case TDA18271HDC2: + regs[R_EB1] = 0xfc; + break; + }; + + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB12] = 0x0f; + break; + case TDA18271HDC2: + regs[R_EB12] = 0x33; + break; + }; + + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB18] = 0x00; + break; + case TDA18271HDC2: + regs[R_EB18] = 0x8c; + break; + }; + + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB21] = 0x33; + break; + case TDA18271HDC2: + regs[R_EB21] = 0xb3; + break; + }; + + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + + /* setup agc1 gain */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + /* setup agc2 gain */ + if ((priv->id) == TDA18271HDC1) { + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + } + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + tda18271_write_regs(fe, R_EP3, 11); + break; + case TDA18271HDC2: + tda18271_write_regs(fe, R_EP3, 12); + break; + }; + + if ((priv->id) == TDA18271HDC2) { + /* main pll cp source on */ + regs[R_EB4] = 0x61; + tda18271_write_regs(fe, R_EB4, 1); + msleep(1); + + /* main pll cp source off */ + regs[R_EB4] = 0x41; + tda18271_write_regs(fe, R_EB4, 1); + } + + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP5] = 0x87; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + /* return to normal mode */ + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + /* synchronize */ + tda18271_write_regs(fe, R_EP1, 1); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets main post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); + if (ret < 0) + goto fail; + + regs[R_MPD] = (0x77 & pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_MD1] = 0x7f & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; +fail: + return ret; +} + +int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets cal post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); + if (ret < 0) + goto fail; + + regs[R_CPD] = pd; + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_CD1] = 0x7f & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) +{ + /* sets bp filter bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) +{ + /* sets K & M bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EB13] &= ~0x7c; /* clear k & m bits */ + regs[R_EB13] |= (0x7c & val); +fail: + return ret; +} + +int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf band bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (0xe0 & (val << 5)); +fail: + return ret; +} + +int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) +{ + /* sets gain taper bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= (0x1f & val); +fail: + return ret; +} + +int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) +{ + /* sets IR Meas bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP5] &= ~0x07; + regs[R_EP5] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf cal byte (RFC_Cprog), but does not write it */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EB14] = val; +fail: + return ret; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 4b53baf12ef..537d520de22 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -1,7 +1,7 @@ /* tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner - Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + Copyright (C) 2007, 2008 Michael Krufky 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 @@ -28,431 +28,6 @@ MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); /*---------------------------------------------------------------------*/ -static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct tda18271_priv *priv = fe->tuner_priv; - enum tda18271_i2c_gate gate; - int ret = 0; - - switch (priv->gate) { - case TDA18271_GATE_DIGITAL: - case TDA18271_GATE_ANALOG: - gate = priv->gate; - break; - case TDA18271_GATE_AUTO: - default: - switch (priv->mode) { - case TDA18271_DIGITAL: - gate = TDA18271_GATE_DIGITAL; - break; - case TDA18271_ANALOG: - default: - gate = TDA18271_GATE_ANALOG; - break; - } - } - - switch (gate) { - case TDA18271_GATE_ANALOG: - if (fe->ops.analog_ops.i2c_gate_ctrl) - ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); - break; - case TDA18271_GATE_DIGITAL: - if (fe->ops.i2c_gate_ctrl) - ret = fe->ops.i2c_gate_ctrl(fe, enable); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -}; - -/*---------------------------------------------------------------------*/ - -static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_reg("=== TDA18271 REG DUMP ===\n"); - tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); - tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); - tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); - tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); - tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); - tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); - tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); - tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); - tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); - tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); - tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); - tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); - tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); - tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); - tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); - tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); - - /* only dump extended regs if DBG_ADV is set */ - if (!(tda18271_debug & DBG_ADV)) - return; - - /* W indicates write-only registers. - * Register dump for write-only registers shows last value written. */ - - tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); - tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); - tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); - tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); - tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); - tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); - tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); - tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); - tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); - tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); - tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); - tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); - tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); - tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); - tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); - tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); - tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); - tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); - tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); - tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); - tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); - tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); - tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); -} - -static void tda18271_read_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf = 0x00; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->i2c_addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = regs, .len = 16 } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 0); -} - -static void tda18271_read_extended(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char regdump[TDA18271_NUM_REGS]; - unsigned char buf = 0x00; - int ret, i; - struct i2c_msg msg[] = { - { .addr = priv->i2c_addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = regdump, .len = TDA18271_NUM_REGS } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - for (i = 0; i <= TDA18271_NUM_REGS; i++) { - /* don't update write-only registers */ - if ((i != R_EB9) && - (i != R_EB16) && - (i != R_EB17) && - (i != R_EB19) && - (i != R_EB20)) - regs[i] = regdump[i]; - } - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 1); -} - -static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf[TDA18271_NUM_REGS+1]; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = len+1 }; - int i, ret; - - BUG_ON((len == 0) || (idx+len > sizeof(buf))); - - buf[0] = idx; - for (i = 1; i <= len; i++) { - buf[i] = regs[idx-1+i]; - } - - tda18271_i2c_gate_ctrl(fe, 1); - - /* write registers */ - ret = i2c_transfer(priv->i2c_adap, &msg, 1); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 1) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); -} - -/*---------------------------------------------------------------------*/ - -static int tda18271_init_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_dbg("initializing registers for device @ %d-%04x\n", - i2c_adapter_id(priv->i2c_adap), priv->i2c_addr); - - /* initialize registers */ - switch (priv->id) { - case TDA18271HDC1: - regs[R_ID] = 0x83; - break; - case TDA18271HDC2: - regs[R_ID] = 0x84; - break; - }; - - regs[R_TM] = 0x08; - regs[R_PL] = 0x80; - regs[R_EP1] = 0xc6; - regs[R_EP2] = 0xdf; - regs[R_EP3] = 0x16; - regs[R_EP4] = 0x60; - regs[R_EP5] = 0x80; - regs[R_CPD] = 0x80; - regs[R_CD1] = 0x00; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0x00; - regs[R_MD1] = 0x00; - regs[R_MD2] = 0x00; - regs[R_MD3] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB1] = 0xff; - break; - case TDA18271HDC2: - regs[R_EB1] = 0xfc; - break; - }; - - regs[R_EB2] = 0x01; - regs[R_EB3] = 0x84; - regs[R_EB4] = 0x41; - regs[R_EB5] = 0x01; - regs[R_EB6] = 0x84; - regs[R_EB7] = 0x40; - regs[R_EB8] = 0x07; - regs[R_EB9] = 0x00; - regs[R_EB10] = 0x00; - regs[R_EB11] = 0x96; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB12] = 0x0f; - break; - case TDA18271HDC2: - regs[R_EB12] = 0x33; - break; - }; - - regs[R_EB13] = 0xc1; - regs[R_EB14] = 0x00; - regs[R_EB15] = 0x8f; - regs[R_EB16] = 0x00; - regs[R_EB17] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB18] = 0x00; - break; - case TDA18271HDC2: - regs[R_EB18] = 0x8c; - break; - }; - - regs[R_EB19] = 0x00; - regs[R_EB20] = 0x20; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB21] = 0x33; - break; - case TDA18271HDC2: - regs[R_EB21] = 0xb3; - break; - }; - - regs[R_EB22] = 0x48; - regs[R_EB23] = 0xb0; - - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); - - /* setup agc1 gain */ - regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); - - /* setup agc2 gain */ - if ((priv->id) == TDA18271HDC1) { - regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - } - - /* image rejection calibration */ - - /* low-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x81; - regs[R_CPD] = 0xcc; - regs[R_CD1] = 0x6c; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0xcd; - regs[R_MD1] = 0x77; - regs[R_MD2] = 0x08; - regs[R_MD3] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - tda18271_write_regs(fe, R_EP3, 11); - break; - case TDA18271HDC2: - tda18271_write_regs(fe, R_EP3, 12); - break; - }; - - if ((priv->id) == TDA18271HDC2) { - /* main pll cp source on */ - regs[R_EB4] = 0x61; - tda18271_write_regs(fe, R_EB4, 1); - msleep(1); - - /* main pll cp source off */ - regs[R_EB4] = 0x41; - tda18271_write_regs(fe, R_EB4, 1); - } - - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted low measurement */ - - regs[R_EP5] = 0x85; - regs[R_CPD] = 0xcb; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0x70; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image low optimization completion */ - - /* mid-band */ - regs[R_EP5] = 0x82; - regs[R_CPD] = 0xa8; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0xa9; - regs[R_MD1] = 0x73; - regs[R_MD2] = 0x1a; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted mid measurement */ - - regs[R_EP5] = 0x86; - regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0xa0; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image mid optimization completion */ - - /* high-band */ - regs[R_EP5] = 0x83; - regs[R_CPD] = 0x98; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0x99; - regs[R_MD1] = 0x71; - regs[R_MD2] = 0xcd; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted high measurement */ - - regs[R_EP5] = 0x87; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x50; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image high optimization completion */ - - /* return to normal mode */ - regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); - - /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); - - return 0; -} - static int tda18271_init(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -467,162 +42,6 @@ static int tda18271_init(struct dvb_frontend *fe) return 0; } -static int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) -{ - /* Sets Main Post-Divider & Divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); - if (ret < 0) - goto fail; - - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_MD1] = 0x7f & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; -fail: - return ret; -} - -static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) -{ - /* Sets Cal Post-Divider & Divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); - if (ret < 0) - goto fail; - - regs[R_CPD] = pd; - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_CD1] = 0x7f & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; -fail: - return ret; -} - -static int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) -{ - /* Sets BP filter bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= (0x07 & val); -fail: - return ret; -} - -static int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) -{ - /* Sets K & M bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EB13] &= ~0x7c; /* clear k & m bits */ - regs[R_EB13] |= (0x7c & val); -fail: - return ret; -} - -static int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) -{ - /* Sets RF Band bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (0xe0 & (val << 5)); -fail: - return ret; -} - -static int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) -{ - /* Sets Gain Taper bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= (0x1f & val); -fail: - return ret; -} - -static int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) -{ - /* Sets IR Meas bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP5] &= ~0x07; - regs[R_EP5] |= (0x07 & val); -fail: - return ret; -} - -static int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) -{ - /* Sets RF Cal bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EB14] = val; -fail: - return ret; -} - /* ------------------------------------------------------------------ */ static int tda18271_channel_configuration(struct dvb_frontend *fe, diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 8552c6ae0d1..deb375ea253 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -1,7 +1,7 @@ /* tda18271-priv.h - private header for the NXP TDA18271 silicon tuner - Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + Copyright (C) 2007, 2008 Michael Krufky 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 @@ -196,6 +196,23 @@ extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, extern int tda18271_assign_map_layout(struct dvb_frontend *fe); +/*---------------------------------------------------------------------*/ + +extern int tda18271_read_regs(struct dvb_frontend *fe); +extern int tda18271_read_extended(struct dvb_frontend *fe); +extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); +extern int tda18271_init_regs(struct dvb_frontend *fe); + +extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); +extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); + +extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); + #endif /* __TDA18271_PRIV_H__ */ /* diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 3042e5c873e..46f1d4ddda3 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -1,7 +1,7 @@ /* tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner - Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + Copyright (C) 2007, 2008 Michael Krufky 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 diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index b98a9331c59..f5356810331 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -1,7 +1,7 @@ /* tda18271.h - header for the Philips / NXP TDA18271 silicon tuner - Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) + Copyright (C) 2007, 2008 Michael Krufky 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 -- cgit v1.2.3 From f21e0d7f0513e743b14df3197fdeeb9a9b7edbb2 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 2 Jan 2008 03:01:54 -0300 Subject: V4L/DVB (6962): tda18271: allow device-specific configuration of IF frequency and std bits Allow drivers to pass device-specific configuration parameters during attach. If these parameters are omitted, default values will be used. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 82 +++++++++++++++++++++++++-- drivers/media/dvb/frontends/tda18271-priv.h | 23 +------- drivers/media/dvb/frontends/tda18271-tables.c | 18 +++--- drivers/media/dvb/frontends/tda18271.h | 30 +++++++++- drivers/media/video/cx23885/cx23885-dvb.c | 12 +++- drivers/media/video/tda8290.c | 6 +- 6 files changed, 131 insertions(+), 40 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 537d520de22..b17ab4ace08 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -768,12 +768,12 @@ static int tda18271_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = priv->std; + struct tda18271_std_map *std_map = &priv->std; u8 std; u32 bw, sgIF = 0; u32 freq = params->frequency; - BUG_ON(!priv->tune || !priv->std); + BUG_ON(!priv->tune); priv->mode = TDA18271_DIGITAL; @@ -832,12 +832,12 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = priv->std; + struct tda18271_std_map *std_map = &priv->std; char *mode; u8 std; u32 sgIF, freq = params->frequency * 62500; - BUG_ON(!priv->tune || !priv->std); + BUG_ON(!priv->tune); priv->mode = TDA18271_ANALOG; @@ -901,6 +901,69 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +/* ------------------------------------------------------------------ */ + +#define tda18271_update_std(std_cfg, name) do { \ + if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) { \ + tda_dbg("Using custom std config for %s\n", name); \ + memcpy(&std->std_cfg, &map->std_cfg, \ + sizeof(struct tda18271_std_map_item)); \ + } } while (0) + +#define tda18271_dump_std_item(std_cfg, name) do { \ + tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n", \ + name, std->std_cfg.if_freq, std->std_cfg.std_bits); \ + } while (0) + +static int tda18271_dump_std_map(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); + tda18271_dump_std_item(atv_b, "pal b"); + tda18271_dump_std_item(atv_dk, "pal dk"); + tda18271_dump_std_item(atv_gh, "pal gh"); + tda18271_dump_std_item(atv_i, "pal i"); + tda18271_dump_std_item(atv_l, "pal l"); + tda18271_dump_std_item(atv_lc, "pal l'"); + tda18271_dump_std_item(atv_mn, "atv mn"); + tda18271_dump_std_item(atsc_6, "atsc 6"); + tda18271_dump_std_item(dvbt_6, "dvbt 6"); + tda18271_dump_std_item(dvbt_7, "dvbt 7"); + tda18271_dump_std_item(dvbt_8, "dvbt 8"); + tda18271_dump_std_item(qam_6, "qam 6"); + tda18271_dump_std_item(qam_8, "qam 8"); + + return 0; +} + +static int tda18271_update_std_map(struct dvb_frontend *fe, + struct tda18271_std_map *map) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + if (!map) + return -EINVAL; + + tda18271_update_std(atv_b, "atv b"); + tda18271_update_std(atv_dk, "atv dk"); + tda18271_update_std(atv_gh, "atv gh"); + tda18271_update_std(atv_i, "atv i"); + tda18271_update_std(atv_l, "atv l"); + tda18271_update_std(atv_lc, "atv l'"); + tda18271_update_std(atv_mn, "atv mn"); + tda18271_update_std(atsc_6, "atsc 6"); + tda18271_update_std(dvbt_6, "dvbt 6"); + tda18271_update_std(dvbt_7, "dvbt 7"); + tda18271_update_std(dvbt_8, "dvbt 8"); + tda18271_update_std(qam_6, "qam 6"); + tda18271_update_std(qam_8, "qam 8"); + + return 0; +} + static int tda18271_get_id(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -951,7 +1014,7 @@ static struct dvb_tuner_ops tda18271_tuner_ops = { struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, - enum tda18271_i2c_gate gate) + struct tda18271_config *cfg) { struct tda18271_priv *priv = NULL; @@ -961,7 +1024,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, priv->i2c_addr = addr; priv->i2c_adap = i2c; - priv->gate = gate; + priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; priv->cal_initialized = false; fe->tuner_priv = priv; @@ -975,6 +1038,13 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, sizeof(struct dvb_tuner_ops)); + /* override default std map with values in config struct */ + if ((cfg) && (cfg->std_map)) + tda18271_update_std_map(fe, cfg->std_map); + + if (tda18271_debug & DBG_MAP) + tda18271_dump_std_map(fe); + tda18271_init_regs(fe); return fe; diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index deb375ea253..6e04258ca6f 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -84,27 +84,6 @@ struct tda18271_rf_tracking_filter_cal { int rf_b2; }; -struct tda18271_std_map_item { - u32 if_freq; - u8 std_bits; -}; - -struct tda18271_std_map { - struct tda18271_std_map_item atv_b; - struct tda18271_std_map_item atv_dk; - struct tda18271_std_map_item atv_gh; - struct tda18271_std_map_item atv_i; - struct tda18271_std_map_item atv_l; - struct tda18271_std_map_item atv_lc; - struct tda18271_std_map_item atv_mn; - struct tda18271_std_map_item atsc_6; - struct tda18271_std_map_item dvbt_6; - struct tda18271_std_map_item dvbt_7; - struct tda18271_std_map_item dvbt_8; - struct tda18271_std_map_item qam_6; - struct tda18271_std_map_item qam_8; -}; - enum tda18271_mode { TDA18271_ANALOG, TDA18271_DIGITAL, @@ -128,8 +107,8 @@ struct tda18271_priv { unsigned int cal_initialized:1; - struct tda18271_std_map *std; struct tda18271_map_layout *maps; + struct tda18271_std_map std; struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; int (*tune) (struct dvb_frontend *fe, diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 46f1d4ddda3..2f8ea72bcab 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -1194,11 +1194,11 @@ static struct tda18271_std_map tda18271c1_std_map = { .atv_l = { .if_freq = 7750000, .std_bits = 0x0f }, .atv_lc = { .if_freq = 1250000, .std_bits = 0x0f }, .atv_mn = { .if_freq = 5750000, .std_bits = 0x0d }, - .atsc_6 = { .if_freq = 5380000, .std_bits = 0x1b }, - .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1b }, - .dvbt_7 = { .if_freq = 3800000, .std_bits = 0x19 }, - .dvbt_8 = { .if_freq = 4300000, .std_bits = 0x1a }, - .qam_6 = { .if_freq = 4000000, .std_bits = 0x18 }, + .atsc_6 = { .if_freq = 3250000, .std_bits = 0x1c }, + .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1c }, + .dvbt_7 = { .if_freq = 3800000, .std_bits = 0x1d }, + .dvbt_8 = { .if_freq = 4300000, .std_bits = 0x1e }, + .qam_6 = { .if_freq = 4000000, .std_bits = 0x1d }, .qam_8 = { .if_freq = 5000000, .std_bits = 0x1f }, }; @@ -1210,7 +1210,7 @@ static struct tda18271_std_map tda18271c2_std_map = { .atv_l = { .if_freq = 6900000, .std_bits = 0x0e }, .atv_lc = { .if_freq = 1250000, .std_bits = 0x0e }, .atv_mn = { .if_freq = 5400000, .std_bits = 0x0c }, - .atsc_6 = { .if_freq = 5380000, .std_bits = 0x1b }, + .atsc_6 = { .if_freq = 3250000, .std_bits = 0x1c }, .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1c }, .dvbt_7 = { .if_freq = 3500000, .std_bits = 0x1c }, .dvbt_8 = { .if_freq = 4000000, .std_bits = 0x1d }, @@ -1256,11 +1256,13 @@ int tda18271_assign_map_layout(struct dvb_frontend *fe) switch (priv->id) { case TDA18271HDC1: priv->maps = &tda18271c1_map_layout; - priv->std = &tda18271c1_std_map; + memcpy(&priv->std, &tda18271c1_std_map, + sizeof(struct tda18271_std_map)); break; case TDA18271HDC2: priv->maps = &tda18271c2_map_layout; - priv->std = &tda18271c2_std_map; + memcpy(&priv->std, &tda18271c2_std_map, + sizeof(struct tda18271_std_map)); break; default: ret = -EINVAL; diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index f5356810331..36a3a548a6f 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -24,21 +24,47 @@ #include #include "dvb_frontend.h" +struct tda18271_std_map_item { + u32 if_freq; + u8 std_bits; +}; + +struct tda18271_std_map { + struct tda18271_std_map_item atv_b; + struct tda18271_std_map_item atv_dk; + struct tda18271_std_map_item atv_gh; + struct tda18271_std_map_item atv_i; + struct tda18271_std_map_item atv_l; + struct tda18271_std_map_item atv_lc; + struct tda18271_std_map_item atv_mn; + struct tda18271_std_map_item atsc_6; + struct tda18271_std_map_item dvbt_6; + struct tda18271_std_map_item dvbt_7; + struct tda18271_std_map_item dvbt_8; + struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_8; +}; + enum tda18271_i2c_gate { TDA18271_GATE_AUTO = 0, TDA18271_GATE_ANALOG, TDA18271_GATE_DIGITAL, }; +struct tda18271_config { + struct tda18271_std_map *std_map; + enum tda18271_i2c_gate gate; +}; + #if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, - enum tda18271_i2c_gate gate); + struct tda18271_config *cfg); #else static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, - enum tda18271_i2c_gate gate) + struct tda18271_config *cfg) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 81dd47f6f65..948a7fb7ed0 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -183,6 +183,16 @@ static struct tda829x_config tda829x_no_probe = { .probe_tuner = TDA829X_DONT_PROBE, }; +static struct tda18271_std_map hauppauge_tda18271_std_map = { + .atsc_6 = { .if_freq = 5380000, .std_bits = 0x1b }, + .qam_6 = { .if_freq = 4000000, .std_bits = 0x18 }, +}; + +static struct tda18271_config hauppauge_tda18271_config = { + .std_map = &hauppauge_tda18271_std_map, + .gate = TDA18271_GATE_ANALOG, +}; + static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) { struct cx23885_tsport *port = ptr; @@ -248,7 +258,7 @@ static int dvb_register(struct cx23885_tsport *port) &tda829x_no_probe); dvb_attach(tda18271_attach, port->dvb.frontend, 0x60, &dev->i2c_bus[1].i2c_adap, - TDA18271_GATE_ANALOG); + &hauppauge_tda18271_config); } break; case 0: diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 54d261a2f25..eab530708a4 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -509,6 +509,10 @@ static void tda829x_release(struct dvb_frontend *fe) fe->analog_demod_priv = NULL; } +static struct tda18271_config tda829x_tda18271_config = { + .gate = TDA18271_GATE_ANALOG, +}; + static int tda829x_find_tuner(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; @@ -574,7 +578,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) priv->ver |= TDA18271; tda18271_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, - TDA18271_GATE_ANALOG); + &tda829x_tda18271_config); } else { if ((data & 0x3c) == 0) priv->ver |= TDA8275; -- cgit v1.2.3 From 2ba65d517b91ebb30f4f2a88f1e1beeabd8d8ee6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 3 Jan 2008 01:17:45 -0300 Subject: V4L/DVB (6963): tda18271: store IF frequency in a u16 instead of u32 Store IF Frequency in a u16 instead of a u32. Multiply by 1000 before use. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 11 +++--- drivers/media/dvb/frontends/tda18271-tables.c | 52 +++++++++++++-------------- drivers/media/dvb/frontends/tda18271.h | 2 +- drivers/media/video/cx23885/cx23885-dvb.c | 4 +-- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index b17ab4ace08..a02d6404f75 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -770,8 +770,8 @@ static int tda18271_set_params(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; u8 std; - u32 bw, sgIF = 0; - u32 freq = params->frequency; + u16 sgIF; + u32 bw, freq = params->frequency; BUG_ON(!priv->tune); @@ -825,7 +825,7 @@ static int tda18271_set_params(struct dvb_frontend *fe, return -EINVAL; } - return priv->tune(fe, sgIF, freq, bw, std); + return priv->tune(fe, sgIF * 1000, freq, bw, std); } static int tda18271_set_analog_params(struct dvb_frontend *fe, @@ -835,7 +835,8 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, struct tda18271_std_map *std_map = &priv->std; char *mode; u8 std; - u32 sgIF, freq = params->frequency * 62500; + u16 sgIF; + u32 freq = params->frequency * 62500; BUG_ON(!priv->tune); @@ -877,7 +878,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, tda_dbg("setting tda18271 to system %s\n", mode); - return priv->tune(fe, sgIF, freq, 0, std); + return priv->tune(fe, sgIF * 1000, freq, 0, std); } static int tda18271_release(struct dvb_frontend *fe) diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 2f8ea72bcab..528a2ec9e96 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -1187,35 +1187,35 @@ fail: /*---------------------------------------------------------------------*/ static struct tda18271_std_map tda18271c1_std_map = { - .atv_b = { .if_freq = 6750000, .std_bits = 0x0e }, - .atv_dk = { .if_freq = 7750000, .std_bits = 0x0f }, - .atv_gh = { .if_freq = 7750000, .std_bits = 0x0f }, - .atv_i = { .if_freq = 7750000, .std_bits = 0x0f }, - .atv_l = { .if_freq = 7750000, .std_bits = 0x0f }, - .atv_lc = { .if_freq = 1250000, .std_bits = 0x0f }, - .atv_mn = { .if_freq = 5750000, .std_bits = 0x0d }, - .atsc_6 = { .if_freq = 3250000, .std_bits = 0x1c }, - .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1c }, - .dvbt_7 = { .if_freq = 3800000, .std_bits = 0x1d }, - .dvbt_8 = { .if_freq = 4300000, .std_bits = 0x1e }, - .qam_6 = { .if_freq = 4000000, .std_bits = 0x1d }, - .qam_8 = { .if_freq = 5000000, .std_bits = 0x1f }, + .atv_b = { .if_freq = 6750, .std_bits = 0x0e }, + .atv_dk = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_gh = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_i = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_l = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_lc = { .if_freq = 1250, .std_bits = 0x0f }, + .atv_mn = { .if_freq = 5750, .std_bits = 0x0d }, + .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c }, + .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c }, + .dvbt_7 = { .if_freq = 3800, .std_bits = 0x1d }, + .dvbt_8 = { .if_freq = 4300, .std_bits = 0x1e }, + .qam_6 = { .if_freq = 4000, .std_bits = 0x1d }, + .qam_8 = { .if_freq = 5000, .std_bits = 0x1f }, }; static struct tda18271_std_map tda18271c2_std_map = { - .atv_b = { .if_freq = 6000000, .std_bits = 0x0d }, - .atv_dk = { .if_freq = 6900000, .std_bits = 0x0e }, - .atv_gh = { .if_freq = 7100000, .std_bits = 0x0e }, - .atv_i = { .if_freq = 7250000, .std_bits = 0x0e }, - .atv_l = { .if_freq = 6900000, .std_bits = 0x0e }, - .atv_lc = { .if_freq = 1250000, .std_bits = 0x0e }, - .atv_mn = { .if_freq = 5400000, .std_bits = 0x0c }, - .atsc_6 = { .if_freq = 3250000, .std_bits = 0x1c }, - .dvbt_6 = { .if_freq = 3300000, .std_bits = 0x1c }, - .dvbt_7 = { .if_freq = 3500000, .std_bits = 0x1c }, - .dvbt_8 = { .if_freq = 4000000, .std_bits = 0x1d }, - .qam_6 = { .if_freq = 4000000, .std_bits = 0x1d }, - .qam_8 = { .if_freq = 5000000, .std_bits = 0x1f }, + .atv_b = { .if_freq = 6000, .std_bits = 0x0d }, + .atv_dk = { .if_freq = 6900, .std_bits = 0x0e }, + .atv_gh = { .if_freq = 7100, .std_bits = 0x0e }, + .atv_i = { .if_freq = 7250, .std_bits = 0x0e }, + .atv_l = { .if_freq = 6900, .std_bits = 0x0e }, + .atv_lc = { .if_freq = 1250, .std_bits = 0x0e }, + .atv_mn = { .if_freq = 5400, .std_bits = 0x0c }, + .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c }, + .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c }, + .dvbt_7 = { .if_freq = 3500, .std_bits = 0x1c }, + .dvbt_8 = { .if_freq = 4000, .std_bits = 0x1d }, + .qam_6 = { .if_freq = 4000, .std_bits = 0x1d }, + .qam_8 = { .if_freq = 5000, .std_bits = 0x1f }, }; /*---------------------------------------------------------------------*/ diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index 36a3a548a6f..4fa3d6ab621 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -25,7 +25,7 @@ #include "dvb_frontend.h" struct tda18271_std_map_item { - u32 if_freq; + u16 if_freq; u8 std_bits; }; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 948a7fb7ed0..1b669ee962d 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -184,8 +184,8 @@ static struct tda829x_config tda829x_no_probe = { }; static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 5380000, .std_bits = 0x1b }, - .qam_6 = { .if_freq = 4000000, .std_bits = 0x18 }, + .atsc_6 = { .if_freq = 5380, .std_bits = 0x1b }, + .qam_6 = { .if_freq = 4000, .std_bits = 0x18 }, }; static struct tda18271_config hauppauge_tda18271_config = { -- cgit v1.2.3 From 0e1fab90a8a76e09b669d3159ec910eab7ee97d6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 3 Jan 2008 01:40:47 -0300 Subject: V4L/DVB (6964): tda18271: document debug level and configuration parameters Document debug level module options and tda18271_config attach-time parameters. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 3 ++- drivers/media/dvb/frontends/tda18271.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index a02d6404f75..55c17fc2227 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -24,7 +24,8 @@ int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); +MODULE_PARM_DESC(debug, "set debug level " + "(info=1, map=2, reg=4, adv=8 (or-able))"); /*---------------------------------------------------------------------*/ diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index 4fa3d6ab621..9ccfa6e8b5a 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -52,7 +52,10 @@ enum tda18271_i2c_gate { }; struct tda18271_config { + /* override default if freq / std settings (optional) */ struct tda18271_std_map *std_map; + + /* use i2c gate provided by analog or digital demod */ enum tda18271_i2c_gate gate; }; -- cgit v1.2.3 From d2c932a1f7aca16727ce6670c5eccb0a4e2b47a5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 5 Jan 2008 15:42:54 -0300 Subject: V4L/DVB (6965): tda18271: fix analog tuning regression caused by earlier changeset An earlier patch, "tda18271: fail table lookups if frequency is out of range" broke analog support on certain hardware. This patch fixes that problem, by allowing the RF_CAL byte to be set to the maximum value, in cases of the frequency being out of range. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-common.c | 8 +++----- drivers/media/dvb/frontends/tda18271-tables.c | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c index 4adc7390ba0..d7a33565947 100644 --- a/drivers/media/dvb/frontends/tda18271-common.c +++ b/drivers/media/dvb/frontends/tda18271-common.c @@ -601,13 +601,11 @@ int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) unsigned char *regs = priv->tda18271_regs; u8 val; - int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); - if (ret < 0) - goto fail; + tda18271_lookup_map(fe, RF_CAL, freq, &val); regs[R_EB14] = val; -fail: - return ret; + + return 0; } /* diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 528a2ec9e96..0402c7dab19 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -1098,7 +1098,7 @@ int tda18271_lookup_pll_map(struct dvb_frontend *fe, } while ((map[i].lomax * 1000) < *freq) { - if (map[i].lomax == 0) { + if (map[i + 1].lomax == 0) { tda_map("%s: frequency (%d) out of range\n", map_name, *freq); ret = -ERANGE; @@ -1169,7 +1169,7 @@ int tda18271_lookup_map(struct dvb_frontend *fe, } while ((map[i].rfmax * 1000) < *freq) { - if (map[i].rfmax == 0) { + if (map[i + 1].rfmax == 0) { tda_map("%s: frequency (%d) out of range\n", map_name, *freq); ret = -ERANGE; -- cgit v1.2.3 From 11fcd4703004fc8c9030ba45dda8ad74a431d235 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 25 Oct 2007 02:01:10 -0300 Subject: V4L/DVB (6967): pvrusb2: add support for Hauppauge WinTV PVR-USB2 Model 75xxx Create a device description and enable autodetection for Hauppauge WinTV PVR-USB2 Model 75xxx Signed-off-by: Michael Krufky Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 9a08670d406..4df6d6d936f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -154,6 +154,33 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = { +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 75xxx */ + +static const char *pvr2_client_75xxx[] = { + "cx25840", + "tuner", +}; + +static const char *pvr2_fw1_names_75xxx[] = { + "v4l-pvrusb2-73xxx-01.fw", +}; + +static const struct pvr2_device_desc pvr2_device_75xxx = { + .description = "WinTV PVR USB2 Model Category 75xxxx", + .shortname = "75xxx", + .client_modules.lst = pvr2_client_75xxx, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), + .fx2_firmware.lst = pvr2_fw1_names_75xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx), + .flag_has_cx25840 = !0, + .flag_has_hauppauge_rom = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + .default_std_mask = V4L2_STD_NTSC_M, +}; + + + /*------------------------------------------------------------------------*/ struct usb_device_id pvr2_device_table[] = { @@ -171,6 +198,8 @@ struct usb_device_id pvr2_device_table[] = { { USB_DEVICE(0x11ba, 0x1001), .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, #endif + { USB_DEVICE(0x2040, 0x7500), + .driver_info = (kernel_ulong_t)&pvr2_device_75xxx}, { } }; -- cgit v1.2.3 From a4950134d46f0b83745f05ea37987785a3905eba Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 6 Jan 2008 09:45:44 -0300 Subject: V4L/DVB (6969): Avoid causing regressions for non-HVR950 boards Only HVR950 has analog_gpio configured. It makes no sense to set gpio to 0 for other boards. Better to add a test, while this var is not set for all xc3028 devices. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 34 +++++++++++++++++-------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 1011813ad7c..5ffdbaab3ad 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -485,27 +485,31 @@ static int em28xx_tuner_callback(void *ptr, int command, int arg) switch (command) { case XC2028_TUNER_RESET: { - char gpio0, gpio1, gpio4; - - /* GPIO and initialization codes for analog TV */ - gpio0 = dev->analog_gpio & 0xff; - gpio1 = (dev->analog_gpio >> 8) & 0xff; - gpio4 = dev->analog_gpio >> 24; + /* GPIO and initialization codes for analog TV and radio + This code should be complemented for DTV, since reset + codes are different. + */ dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); - if (gpio4) { - dev->em28xx_write_regs(dev, 0x04, &gpio4, 1); - msleep(140); + if (dev->analog_gpio) { + char gpio0 = dev->analog_gpio & 0xff; + char gpio1 = (dev->analog_gpio >> 8) & 0xff; + char gpio4 = dev->analog_gpio >> 24; + + if (gpio4) { + dev->em28xx_write_regs(dev, 0x04, &gpio4, 1); + msleep(140); + } + + msleep(6); + dev->em28xx_write_regs(dev, 0x08, &gpio0, 1); + msleep(10); + dev->em28xx_write_regs(dev, 0x08, &gpio1, 1); + msleep(5); } - msleep(6); - dev->em28xx_write_regs(dev, 0x08, &gpio0, 1); - msleep(10); - dev->em28xx_write_regs(dev, 0x08, &gpio1, 1); - msleep(5); - break; } } -- cgit v1.2.3 From 3f4dfe2acf4ffed48395e69166531d8925eb106a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 6 Jan 2008 09:54:17 -0300 Subject: V4L/DVB (6970): Request snd-usb-audio for devices with Audio Class support Before this patch, only Vendor Class audio support were loaded. This means that older em28xx devices won't have digital audio support loaded. This patch changes the logic to auto load eighter snd-usb-audio, for devices with USB Audio Class or em28xx-alsa, for devices with USB Vendor Class. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 5a90462d82e..de95ca87424 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1979,7 +1979,9 @@ static void request_module_async(struct work_struct *work) struct em28xx *dev = container_of(work, struct em28xx, request_module_wk); - if (!dev->has_audio_class) + if (dev->has_audio_class) + request_module("snd-usb-audio"); + else request_module("em28xx-alsa"); } -- cgit v1.2.3 From e8018c9e78b0ff4bb0290e46f4045fb4ea589ae8 Mon Sep 17 00:00:00 2001 From: "Andrey J. Melnikoff (TEMHOTA)" Date: Mon, 7 Jan 2008 05:17:39 -0300 Subject: V4L/DVB (6973): Add Beholder TV 401/405/407/409/505/507/609/M6 support This patch updates cardlist for Beholder TV tuners: old models (with GPIO ir) 401, 403, 405, 407, 409, 505, 507 and add support for 607, 609, M6 cards with new i2c-ir. Signed-off-by: Igor Kuznetsov Signed-off-by: Andrey J. Melnikov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 13 + drivers/media/common/ir-keymaps.c | 104 ++++++ drivers/media/video/ir-kbd-i2c.c | 3 +- drivers/media/video/saa7134/saa7134-cards.c | 504 ++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-i2c.c | 2 + drivers/media/video/saa7134/saa7134-input.c | 60 ++++ drivers/media/video/saa7134/saa7134.h | 13 + include/media/ir-common.h | 1 + 8 files changed, 699 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 29ca16cdb71..387c35f2ecd 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -116,3 +116,16 @@ 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] 116 -> 10MOONS TM300 TV Card [1131:2304] 117 -> Avermedia Super 007 [1461:f01d] +118 -> Beholder BeholdTV 401 [1131:0000,0000:4016] +119 -> Beholder BeholdTV 403 [0000:4036] +120 -> Beholder BeholdTV 403 FM [1131:0000,0000:4037] +121 -> Beholder BeholdTV 405 [0000:4050] +122 -> Beholder BeholdTV 405 FM [0000:4051] +123 -> [0000:4070] +124 -> Beholder BeholdTV 407 FM [0000:4071] +125 -> Beholder BeholdTV 409 [0000:4090] +126 -> Beholder BeholdTV 505 FM/RDS [0000:5051,0000:505B,5ace:5050] +127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090] +128 -> Beholder BeholdTV Columbus TVFM [0000:5201] +129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093] +130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193] diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 42762dfb738..ee2c69e3152 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1848,3 +1848,107 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); + +/* + * Igor Kuznetsov + * Andrey J. Melnikov + * + * Keytable is used by BeholdTV 60x series, M6 series at + * least, and probably other cards too. + * The "ascii-art picture" below (in comments, first row + * is the keycode in hex, and subsequent row(s) shows + * the button labels (several variants when appropriate) + * helps to descide which keycodes to assign to the buttons. + */ +IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = { + + /* 0x1c 0x12 * + * TV/FM POWER * + * */ + [ 0x1c ] = KEY_TUNER, /*XXX KEY_TV KEY_RADIO */ + [ 0x12 ] = KEY_POWER, + + /* 0x01 0x02 0x03 * + * 1 2 3 * + * * + * 0x04 0x05 0x06 * + * 4 5 6 * + * * + * 0x07 0x08 0x09 * + * 7 8 9 * + * */ + [ 0x01 ] = KEY_1, + [ 0x02 ] = KEY_2, + [ 0x03 ] = KEY_3, + [ 0x04 ] = KEY_4, + [ 0x05 ] = KEY_5, + [ 0x06 ] = KEY_6, + [ 0x07 ] = KEY_7, + [ 0x08 ] = KEY_8, + [ 0x09 ] = KEY_9, + + /* 0x0a 0x00 0x17 * + * RECALL 0 MODE * + * */ + [ 0x0a ] = KEY_AGAIN, + [ 0x00 ] = KEY_0, + [ 0x17 ] = KEY_MODE, + + /* 0x14 0x10 * + * ASPECT FULLSCREEN * + * */ + [ 0x14 ] = KEY_SCREEN, + [ 0x10 ] = KEY_ZOOM, + + /* 0x0b * + * Up * + * * + * 0x18 0x16 0x0c * + * Left Ok Right * + * * + * 0x015 * + * Down * + * */ + [ 0x0b ] = KEY_CHANNELUP, /*XXX KEY_UP */ + [ 0x18 ] = KEY_VOLUMEDOWN, /*XXX KEY_LEFT */ + [ 0x16 ] = KEY_OK, /*XXX KEY_ENTER */ + [ 0x0c ] = KEY_VOLUMEUP, /*XXX KEY_RIGHT */ + [ 0x15 ] = KEY_CHANNELDOWN, /*XXX KEY_DOWN */ + + /* 0x11 0x0d * + * MUTE INFO * + * */ + [ 0x11 ] = KEY_MUTE, + [ 0x0d ] = KEY_INFO, + + /* 0x0f 0x1b 0x1a * + * RECORD PLAY/PAUSE STOP * + * * + * 0x0e 0x1f 0x1e * + *TELETEXT AUDIO SOURCE * + * RED YELLOW * + * */ + [ 0x0f ] = KEY_RECORD, + [ 0x1b ] = KEY_PLAYPAUSE, + [ 0x1a ] = KEY_STOP, + [ 0x0e ] = KEY_TEXT, + [ 0x1f ] = KEY_RED, /*XXX KEY_AUDIO */ + [ 0x1e ] = KEY_YELLOW, /*XXX KEY_SOURCE */ + + /* 0x1d 0x13 0x19 * + * SLEEP PREVIEW DVB * + * GREEN BLUE * + * */ + [ 0x1d ] = KEY_SLEEP, + [ 0x13 ] = KEY_GREEN, + [ 0x19 ] = KEY_BLUE, /*XXX KEY_SAT */ + + /* 0x58 0x5c * + * FREEZE SNAPSHOT * + * */ + [ 0x58 ] = KEY_SLOW, + [ 0x5c ] = KEY_SAVE, + +}; + +EXPORT_SYMBOL_GPL(ir_codes_behold); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 29779d8bf7f..9851987b95f 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -398,6 +398,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr, case 0x7a: case 0x47: case 0x71: + case 0x2d: if (adap->id == I2C_HW_B_CX2388x) { /* Handled by cx88-input */ name = "CX2388x remote"; @@ -504,7 +505,7 @@ static int ir_probe(struct i2c_adapter *adap) */ static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; + static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; static const int probe_cx23885[] = { 0x6b, -1 }; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index b29427aaa88..6a35d88fdbb 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3562,6 +3562,329 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, }}, }, + [SAA7134_BOARD_BEHOLD_401] = { + .name = "Beholder BeholdTV 401", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_BEHOLD_403] = { + .name = "Beholder BeholdTV 403", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + }, + [SAA7134_BOARD_BEHOLD_403FM] = { + .name = "Beholder BeholdTV 403 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_405] = { + .name = "Beholder BeholdTV 405", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + }, + [SAA7134_BOARD_BEHOLD_405FM] = { + /* Sergey */ + .name = "Beholder BeholdTV 405 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_407FM] = { + .name = "Beholder BeholdTV 407 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xc0c000, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + .gpio = 0xc0c000, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0xc0c000, + }, + }, + [SAA7134_BOARD_BEHOLD_409] = { + .name = "Beholder BeholdTV 409", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_BEHOLD_505FM] = { + .name = "Beholder BeholdTV 505 FM/RDS", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_507_9FM] = { + .name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = { + .name = "Beholder BeholdTV Columbus TVFM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_ALPS_TSBE5_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_607_9FM] = { + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV 607 / BeholdTV 609", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_M6] = { + /* Igor Kuznetsov */ + /* Andrey Melnikoff */ + .name = "Beholder BeholdTV M6 / BeholdTV M6 Extra", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mpeg = SAA7134_MPEG_EMPRESS, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4326,6 +4649,174 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1131, + .subdevice = 0x0000, + .driver_data = SAA7134_BOARD_BEHOLD_401, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x4016, + .driver_data = SAA7134_BOARD_BEHOLD_401, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1131, + .subdevice = 0x0000, + .driver_data = SAA7134_BOARD_BEHOLD_403FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4036, + .driver_data = SAA7134_BOARD_BEHOLD_403, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4037, + .driver_data = SAA7134_BOARD_BEHOLD_403FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x4050, + .driver_data = SAA7134_BOARD_BEHOLD_405, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x4051, + .driver_data = SAA7134_BOARD_BEHOLD_405FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4070, + .driver_data = SAA7134_BOARD_BEHOLD_407, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4071, + .driver_data = SAA7134_BOARD_BEHOLD_407FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x4090, + .driver_data = SAA7134_BOARD_BEHOLD_409, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x5051, + .driver_data = SAA7134_BOARD_BEHOLD_505FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x505B, + .driver_data = SAA7134_BOARD_BEHOLD_505FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x5ace, + .subdevice = 0x5050, + .driver_data = SAA7134_BOARD_BEHOLD_505FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x5071, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x507B, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x5070, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x5090, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x5201, + .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6070, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6071, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6072, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6073, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6090, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6091, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6092, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6093, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6190, + .driver_data = SAA7134_BOARD_BEHOLD_M6, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6193, + .driver_data = SAA7134_BOARD_BEHOLD_M6, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -4473,6 +4964,16 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ENCORE_ENLTV: case SAA7134_BOARD_ENCORE_ENLTV_FM: case SAA7134_BOARD_10MOONSTVMASTER3: + case SAA7134_BOARD_BEHOLD_401: + case SAA7134_BOARD_BEHOLD_403: + case SAA7134_BOARD_BEHOLD_403FM: + case SAA7134_BOARD_BEHOLD_405: + case SAA7134_BOARD_BEHOLD_405FM: + case SAA7134_BOARD_BEHOLD_407: + case SAA7134_BOARD_BEHOLD_407FM: + case SAA7134_BOARD_BEHOLD_409: + case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_507_9FM: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -4512,6 +5013,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); break; case SAA7134_BOARD_AVERMEDIA_CARDBUS: + case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); @@ -4533,6 +5035,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_UPMOST_PURPLE_TV: case SAA7134_BOARD_HAUPPAUGE_HVR1110: + case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_M6: dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 800b397f8f1..d3322c3018f 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -334,6 +334,7 @@ static int attach_inform(struct i2c_client *client) case 0x7a: case 0x47: case 0x71: + case 0x2d: { struct IR_i2c *ir = i2c_get_clientdata(client); d1printk("%s i2c IR detected (%s).\n", @@ -439,6 +440,7 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0x86 >> 1 ] = "tda9887", + [ 0x5a >> 1 ] = "remote control", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 8cfeb2bde90..7f4212928e9 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -52,6 +52,11 @@ module_param(repeat_period, int, 0644); MODULE_PARM_DESC(repeat_period, "repeat period between " "keypresses when key is down"); +static unsigned int disable_other_ir; +module_param(disable_other_ir, int, 0644); +MODULE_PARM_DESC(disable_other_ir, "disable full codes of " + "alternative remotes from other manufacturers"); + #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) #define i2cdprintk(fmt, arg...) if (ir_debug) \ @@ -154,6 +159,45 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } + +static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char data[12]; + u32 gpio; + + struct saa7134_dev *dev = ir->c.adapter->algo_data; + + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); + + if (0x400000 &~ gpio) + return 0; /* No button press */ + + ir->c.addr = 0x5a >> 1; + + if (12 != i2c_master_recv(&ir->c, data, 12)) { + i2cdprintk("read error\n"); + return -EIO; + } + /* IR of this card normally decode signals NEC-standard from + * - Sven IHOO MT 5.1R remote. xxyye718 + * - Sven DVD HD-10xx remote. xxyyf708 + * - BBK ... + * - mayby others + * So, skip not our, if disable full codes mode. + */ + if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir) + return 0; + + *ir_key = data[9]; + *ir_raw = data[9]; + + return 1; +} + void saa7134_input_irq(struct saa7134_dev *dev) { struct card_ir *ir = dev->remote; @@ -288,6 +332,16 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: + case SAA7134_BOARD_BEHOLD_401: + case SAA7134_BOARD_BEHOLD_403: + case SAA7134_BOARD_BEHOLD_403FM: + case SAA7134_BOARD_BEHOLD_405: + case SAA7134_BOARD_BEHOLD_405FM: + case SAA7134_BOARD_BEHOLD_407: + case SAA7134_BOARD_BEHOLD_407FM: + case SAA7134_BOARD_BEHOLD_409: + case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_507_9FM: ir_codes = ir_codes_manli; mask_keycode = 0x001f00; mask_keyup = 0x004000; @@ -458,6 +512,12 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) ir->get_key = get_key_hvr1110; ir->ir_codes = ir_codes_hauppauge_new; break; + case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_M6: + snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); + ir->get_key = get_key_beholdm6xx; + ir->ir_codes = ir_codes_behold; + break; default: dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 3e77aeb7974..ce450304fb5 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -240,6 +240,19 @@ struct saa7134_format { #define SAA7134_BOARD_SABRENT_TV_PCB05 115 #define SAA7134_BOARD_10MOONSTVMASTER3 116 #define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 +#define SAA7134_BOARD_BEHOLD_401 118 +#define SAA7134_BOARD_BEHOLD_403 119 +#define SAA7134_BOARD_BEHOLD_403FM 120 +#define SAA7134_BOARD_BEHOLD_405 121 +#define SAA7134_BOARD_BEHOLD_405FM 122 +#define SAA7134_BOARD_BEHOLD_407 123 +#define SAA7134_BOARD_BEHOLD_407FM 124 +#define SAA7134_BOARD_BEHOLD_409 125 +#define SAA7134_BOARD_BEHOLD_505FM 126 +#define SAA7134_BOARD_BEHOLD_507_9FM 127 +#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 +#define SAA7134_BOARD_BEHOLD_607_9FM 129 +#define SAA7134_BOARD_BEHOLD_M6 130 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 diff --git a/include/media/ir-common.h b/include/media/ir-common.h index b904d325726..9c2fc09a713 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -140,6 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3 From 616f8878bc5b5b2276f1941643d9ca7c88690305 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 Jan 2008 05:18:36 -0300 Subject: V4L/DVB (6974): Fix codingStyle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 7f4212928e9..0db955c2d9b 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -173,7 +173,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - if (0x400000 &~ gpio) + if (0x400000 & ~gpio) return 0; /* No button press */ ir->c.addr = 0x5a >> 1; -- cgit v1.2.3 From 1434bc0cbb842ed71eada244ac46185e3b17e4e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 Jan 2008 05:20:04 -0300 Subject: V4L/DVB (6975): Add missing entry for Beholder BeholdTV 407 Acked-by: Andrey J. Melnikov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 387c35f2ecd..fda570e50fa 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -121,7 +121,7 @@ 120 -> Beholder BeholdTV 403 FM [1131:0000,0000:4037] 121 -> Beholder BeholdTV 405 [0000:4050] 122 -> Beholder BeholdTV 405 FM [0000:4051] -123 -> [0000:4070] +123 -> Beholder BeholdTV 407 [0000:4070] 124 -> Beholder BeholdTV 407 FM [0000:4071] 125 -> Beholder BeholdTV 409 [0000:4090] 126 -> Beholder BeholdTV 505 FM/RDS [0000:5051,0000:505B,5ace:5050] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 6a35d88fdbb..46b6ac4b310 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3687,6 +3687,33 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }, }, + [SAA7134_BOARD_BEHOLD_407] = { + .name = "Beholder BeholdTV 407", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xc0c000, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + .gpio = 0xc0c000, + }}, + }, [SAA7134_BOARD_BEHOLD_407FM] = { .name = "Beholder BeholdTV 407 FM", .audio_clock = 0x00187de7, -- cgit v1.2.3 From 98512f7b36ec412ea0461e9aab8f16c882df055d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 7 Jan 2008 05:24:51 -0300 Subject: V4L/DVB (6976): drivers/media/radio/radio-sf16fmr2.c: fix error handling video_register_device() returns -EFOO on errr, not -1. Addresses http://bugzilla.kernel.org/show_bug.cgi?id=9699 Reported-By: Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-sf16fmr2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index c432c44bd63..f7c8b000404 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -476,8 +476,7 @@ static int __init fmr2_init(void) return -EBUSY; } - if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } -- cgit v1.2.3 From 09f83c4fc06b02597ad4458c2a6675b0872f0b5c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 5 Jan 2008 20:00:09 -0300 Subject: V4L/DVB (6977): tda18271: clean up calibration initialization procedures Always initialize registers during attach. Perform IR Calibration during init if needed. Perform RF Calibration during init if needed for C2, only. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 37 +++++++++++++++++------------ drivers/media/dvb/frontends/tda18271-priv.h | 1 + 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 55c17fc2227..1a86c9f7a7e 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -29,7 +29,7 @@ MODULE_PARM_DESC(debug, "set debug level " /*---------------------------------------------------------------------*/ -static int tda18271_init(struct dvb_frontend *fe) +static int tda18271_ir_cal_init(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -184,7 +184,7 @@ static int tda18271_read_thermometer(struct dvb_frontend *fe) } static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe, - u32 freq, int tm_rfcal) + u32 freq) { struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; @@ -224,7 +224,7 @@ static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe, tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); /* calculate temperature compensation */ - rfcal_comp = dc_over_dt * (tm_current - tm_rfcal); + rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal); regs[R_EB14] = approx + rfcal_comp; tda18271_write_regs(fe, R_EB14, 1); @@ -554,8 +554,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) return 0; } -static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe, - int *tm_rfcal) +static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; unsigned int i; @@ -572,24 +571,21 @@ static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe, tda18271_rf_tracking_filters_init(fe, 1000 * priv->rf_cal_state[i].rfmax); - *tm_rfcal = tda18271_read_thermometer(fe); + priv->tm_rfcal = tda18271_read_thermometer(fe); return 0; } /* ------------------------------------------------------------------ */ -static int tda18271_init_cal(struct dvb_frontend *fe, int *tm) +static int tda18271_rf_cal_init(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; if (priv->cal_initialized) return 0; - /* initialization */ - tda18271_init(fe); - - tda18271_calc_rf_filter_curve(fe, tm); + tda18271_calc_rf_filter_curve(fe); tda18271_por(fe); @@ -598,16 +594,27 @@ static int tda18271_init_cal(struct dvb_frontend *fe, int *tm) return 0; } +static int tda18271_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + /* initialization */ + tda18271_ir_cal_init(fe); + + if (priv->id == TDA18271HDC2) + tda18271_rf_cal_init(fe); + + return 0; +} + static int tda18271c2_tune(struct dvb_frontend *fe, u32 ifc, u32 freq, u32 bw, u8 std) { - int tm = 0; - tda_dbg("freq = %d, ifc = %d\n", freq, ifc); - tda18271_init_cal(fe, &tm); + tda18271_init(fe); - tda18271_rf_tracking_filters_correction(fe, freq, tm); + tda18271_rf_tracking_filters_correction(fe, freq); tda18271_channel_configuration(fe, ifc, freq, bw, std); diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 6e04258ca6f..7b06e0599dc 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -105,6 +105,7 @@ struct tda18271_priv { enum tda18271_i2c_gate gate; enum tda18271_ver id; + unsigned int tm_rfcal; unsigned int cal_initialized:1; struct tda18271_map_layout *maps; -- cgit v1.2.3 From ccbac9bb174db457181f5f58fecf9cbc3020ea1d Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 6 Jan 2008 00:55:21 -0300 Subject: V4L/DVB (6978): tda18271: store frequency and bandwidth after successful tune Store last tuned frequency & bandwidth after successful tune. Clean up tune functions -- remove pointer to tune function in state structure, instead call tune function based on priv->id. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 46 ++++++++++++++++++++++++----- drivers/media/dvb/frontends/tda18271-priv.h | 3 -- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 1a86c9f7a7e..c1da16ad07e 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -770,6 +770,23 @@ static int tda18271c1_tune(struct dvb_frontend *fe, return 0; } +static inline int tda18271_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (priv->id) { + case TDA18271HDC1: + ret = tda18271c1_tune(fe, ifc, freq, bw, std); + break; + case TDA18271HDC2: + ret = tda18271c2_tune(fe, ifc, freq, bw, std); + break; + } + return ret; +} + /* ------------------------------------------------------------------ */ static int tda18271_set_params(struct dvb_frontend *fe, @@ -777,12 +794,11 @@ static int tda18271_set_params(struct dvb_frontend *fe, { struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; + int ret; u8 std; u16 sgIF; u32 bw, freq = params->frequency; - BUG_ON(!priv->tune); - priv->mode = TDA18271_DIGITAL; /* see table 22 */ @@ -833,7 +849,16 @@ static int tda18271_set_params(struct dvb_frontend *fe, return -EINVAL; } - return priv->tune(fe, sgIF * 1000, freq, bw, std); + ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std); + + if (ret < 0) + goto fail; + + priv->frequency = freq; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + return ret; } static int tda18271_set_analog_params(struct dvb_frontend *fe, @@ -842,12 +867,11 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; char *mode; + int ret; u8 std; u16 sgIF; u32 freq = params->frequency * 62500; - BUG_ON(!priv->tune); - priv->mode = TDA18271_ANALOG; if (params->std & V4L2_STD_MN) { @@ -886,7 +910,15 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, tda_dbg("setting tda18271 to system %s\n", mode); - return priv->tune(fe, sgIF * 1000, freq, 0, std); + ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std); + + if (ret < 0) + goto fail; + + priv->frequency = freq; + priv->bandwidth = 0; +fail: + return ret; } static int tda18271_release(struct dvb_frontend *fe) @@ -986,12 +1018,10 @@ static int tda18271_get_id(struct dvb_frontend *fe) case 3: name = "TDA18271HD/C1"; priv->id = TDA18271HDC1; - priv->tune = tda18271c1_tune; break; case 4: name = "TDA18271HD/C2"; priv->id = TDA18271HDC2; - priv->tune = tda18271c2_tune; break; default: name = "Unknown device"; diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 7b06e0599dc..b4d1ab770ca 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -112,9 +112,6 @@ struct tda18271_priv { struct tda18271_std_map std; struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; - int (*tune) (struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std); - u32 frequency; u32 bandwidth; }; -- cgit v1.2.3 From 8d316bf54b2a1965f9460d0ad9d80850d2c7afb3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 6 Jan 2008 15:31:35 -0300 Subject: V4L/DVB (6979): tda18271: use a mutex to protect state in critical sections Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 20 ++++++++++++++++++++ drivers/media/dvb/frontends/tda18271-priv.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index c1da16ad07e..e860f4c009c 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -598,26 +598,36 @@ static int tda18271_init(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; + mutex_lock(&priv->lock); + /* initialization */ tda18271_ir_cal_init(fe); if (priv->id == TDA18271HDC2) tda18271_rf_cal_init(fe); + mutex_unlock(&priv->lock); + return 0; } static int tda18271c2_tune(struct dvb_frontend *fe, u32 ifc, u32 freq, u32 bw, u8 std) { + struct tda18271_priv *priv = fe->tuner_priv; + tda_dbg("freq = %d, ifc = %d\n", freq, ifc); tda18271_init(fe); + mutex_lock(&priv->lock); + tda18271_rf_tracking_filters_correction(fe, freq); tda18271_channel_configuration(fe, ifc, freq, bw, std); + mutex_unlock(&priv->lock); + return 0; } @@ -632,6 +642,8 @@ static int tda18271c1_tune(struct dvb_frontend *fe, tda18271_init(fe); + mutex_lock(&priv->lock); + tda_dbg("freq = %d, ifc = %d\n", freq, ifc); /* RF tracking filter calibration */ @@ -766,6 +778,7 @@ static int tda18271c1_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_TM, 15); msleep(5); + mutex_unlock(&priv->lock); return 0; } @@ -1012,7 +1025,9 @@ static int tda18271_get_id(struct dvb_frontend *fe) char *name; int ret = 0; + mutex_lock(&priv->lock); tda18271_read_regs(fe); + mutex_unlock(&priv->lock); switch (regs[R_ID] & 0x7f) { case 3: @@ -1065,6 +1080,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, priv->i2c_adap = i2c; priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; priv->cal_initialized = false; + mutex_init(&priv->lock); fe->tuner_priv = priv; @@ -1084,8 +1100,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, if (tda18271_debug & DBG_MAP) tda18271_dump_std_map(fe); + mutex_lock(&priv->lock); + tda18271_init_regs(fe); + mutex_unlock(&priv->lock); + return fe; fail: tda18271_release(fe); diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index b4d1ab770ca..af89cfab006 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -23,6 +23,7 @@ #include #include +#include #include "tda18271.h" #define R_ID 0x00 /* ID byte */ @@ -112,6 +113,8 @@ struct tda18271_priv { struct tda18271_std_map std; struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; + struct mutex lock; + u32 frequency; u32 bandwidth; }; -- cgit v1.2.3 From b3d98135aa6e462d7e3f42a86d12483a9003a4da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 Jan 2008 09:30:31 -0300 Subject: V4L/DVB (6981): Fix bugzillas 9686 and 9691 IR were not working for Winfast XP 2000 TV. Gabor Nyekhelyi wrote a hack some time ago: http://marc.info/?l=linux-video&m=116362609323281&w=2 This patch fixes CodingStyle and commits the hack. I suspect that the proper solution would be to find the proper mask_keydown for this IR. Anyway, better to have this patch as a workaround. Thanks to Stafan Talpalaru for pointing the issue. CC: Gabor Nyekhelyi CC: Stafan Talpalaru Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-input.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index e7c521b8444..fc9ecb21eec 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv) (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { ir_input_keydown(ir->dev,&ir->ir,data,data); } else { + /* HACK: Probably, ir->mask_keydown is missing + for this board */ + if (btv->c.type == BTTV_BOARD_WINFAST2000) + ir_input_keydown(ir->dev, &ir->ir, data, data); + ir_input_nokey(ir->dev,&ir->ir); } -- cgit v1.2.3 From a4f263b587573f47cc6bc7ad85e5f650169d48f6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 6 Jan 2008 15:52:56 -0300 Subject: V4L/DVB (6986): tda18271: share state between analog and digital tuner instances Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 93 ++++++++++++++++++++++------- drivers/media/dvb/frontends/tda18271-priv.h | 3 + drivers/media/video/tda8290.c | 9 ++- 3 files changed, 81 insertions(+), 24 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index e860f4c009c..aa93e155062 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -27,6 +27,9 @@ module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level " "(info=1, map=2, reg=4, adv=8 (or-able))"); +static LIST_HEAD(tda18271_list); +static DEFINE_MUTEX(tda18271_list_mutex); + /*---------------------------------------------------------------------*/ static int tda18271_ir_cal_init(struct dvb_frontend *fe) @@ -936,8 +939,24 @@ fail: static int tda18271_release(struct dvb_frontend *fe) { - kfree(fe->tuner_priv); + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&tda18271_list_mutex); + + priv->count--; + + if (!priv->count) { + tda_dbg("destroying instance @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), + priv->i2c_addr); + list_del(&priv->tda18271_list); + + kfree(priv); + } + mutex_unlock(&tda18271_list_mutex); + fe->tuner_priv = NULL; + return 0; } @@ -1071,43 +1090,73 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct tda18271_config *cfg) { struct tda18271_priv *priv = NULL; + int state_found = 0; + + mutex_lock(&tda18271_list_mutex); + + list_for_each_entry(priv, &tda18271_list, tda18271_list) { + if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) && + (priv->i2c_addr == addr)) { + tda_dbg("attaching existing tuner @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), + priv->i2c_addr); + priv->count++; + fe->tuner_priv = priv; + state_found = 1; + /* allow dvb driver to override i2c gate setting */ + if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG)) + priv->gate = cfg->gate; + break; + } + } + if (state_found == 0) { + tda_dbg("creating new tuner instance @ %d-%04x\n", + i2c_adapter_id(i2c), addr); + + priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); + if (priv == NULL) { + mutex_unlock(&tda18271_list_mutex); + return NULL; + } - priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; + priv->cal_initialized = false; + mutex_init(&priv->lock); + priv->count++; - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; - priv->cal_initialized = false; - mutex_init(&priv->lock); + fe->tuner_priv = priv; - fe->tuner_priv = priv; + list_add_tail(&priv->tda18271_list, &tda18271_list); - if (tda18271_get_id(fe) < 0) - goto fail; + if (tda18271_get_id(fe) < 0) + goto fail; - if (tda18271_assign_map_layout(fe) < 0) - goto fail; + if (tda18271_assign_map_layout(fe) < 0) + goto fail; - memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, - sizeof(struct dvb_tuner_ops)); + mutex_lock(&priv->lock); + tda18271_init_regs(fe); + mutex_unlock(&priv->lock); + } /* override default std map with values in config struct */ if ((cfg) && (cfg->std_map)) tda18271_update_std_map(fe, cfg->std_map); - if (tda18271_debug & DBG_MAP) - tda18271_dump_std_map(fe); - - mutex_lock(&priv->lock); + mutex_unlock(&tda18271_list_mutex); - tda18271_init_regs(fe); + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); - mutex_unlock(&priv->lock); + if (tda18271_debug & DBG_MAP) + tda18271_dump_std_map(fe); return fe; fail: + mutex_unlock(&tda18271_list_mutex); + tda18271_release(fe); return NULL; } diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index af89cfab006..5c04d63ae84 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -102,10 +102,13 @@ struct tda18271_priv { struct i2c_adapter *i2c_adap; unsigned char tda18271_regs[TDA18271_NUM_REGS]; + struct list_head tda18271_list; + enum tda18271_mode mode; enum tda18271_i2c_gate gate; enum tda18271_ver id; + unsigned int count; unsigned int tm_rfcal; unsigned int cal_initialized:1; diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index eab530708a4..4ac7c043889 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -502,8 +502,13 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) static void tda829x_release(struct dvb_frontend *fe) { - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); + struct tda8290_priv *priv = fe->analog_demod_priv; + + /* dont try to release the tuner + * if we didn't attach it from this module */ + if ((priv->ver > TDA8290) && (priv->ver > TDA8295)) + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); kfree(fe->analog_demod_priv); fe->analog_demod_priv = NULL; -- cgit v1.2.3 From c353f42f752d9b47661ff83b947986f6de948b61 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 8 Jan 2008 10:38:10 -0300 Subject: V4L/DVB (6987): tda18271: add support for fm radio Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 42 ++++++++++++++++++--------- drivers/media/dvb/frontends/tda18271-tables.c | 2 ++ drivers/media/dvb/frontends/tda18271.h | 1 + 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index aa93e155062..7d218819b28 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -49,7 +49,8 @@ static int tda18271_ir_cal_init(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ static int tda18271_channel_configuration(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, + int radio) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -76,7 +77,11 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe, regs[R_MPD] |= 0x80; /* IF notch = 1 */ break; } - regs[R_EP4] &= ~0x80; /* FM_RFn: turn this bit on only for fm radio */ + + if (radio) + regs[R_EP4] |= 0x80; + else + regs[R_EP4] &= ~0x80; /* update RF_TOP / IF_TOP */ switch (priv->mode) { @@ -615,7 +620,7 @@ static int tda18271_init(struct dvb_frontend *fe) } static int tda18271c2_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, int radio) { struct tda18271_priv *priv = fe->tuner_priv; @@ -627,7 +632,7 @@ static int tda18271c2_tune(struct dvb_frontend *fe, tda18271_rf_tracking_filters_correction(fe, freq); - tda18271_channel_configuration(fe, ifc, freq, bw, std); + tda18271_channel_configuration(fe, ifc, freq, bw, std, radio); mutex_unlock(&priv->lock); @@ -637,7 +642,7 @@ static int tda18271c2_tune(struct dvb_frontend *fe, /* ------------------------------------------------------------------ */ static int tda18271c1_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, int radio) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -769,7 +774,10 @@ static int tda18271c1_tune(struct dvb_frontend *fe, break; } - regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ + if (radio) + regs[R_EP4] |= 0x80; + else + regs[R_EP4] &= ~0x80; /* image rejection validity */ tda18271_calc_ir_measure(fe, &freq); @@ -787,17 +795,17 @@ static int tda18271c1_tune(struct dvb_frontend *fe, } static inline int tda18271_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std) + u32 ifc, u32 freq, u32 bw, u8 std, int radio) { struct tda18271_priv *priv = fe->tuner_priv; int ret = -EINVAL; switch (priv->id) { case TDA18271HDC1: - ret = tda18271c1_tune(fe, ifc, freq, bw, std); + ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio); break; case TDA18271HDC2: - ret = tda18271c2_tune(fe, ifc, freq, bw, std); + ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio); break; } return ret; @@ -865,7 +873,7 @@ static int tda18271_set_params(struct dvb_frontend *fe, return -EINVAL; } - ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std); + ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0); if (ret < 0) goto fail; @@ -883,14 +891,20 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; char *mode; - int ret; + int ret, radio = 0; u8 std; u16 sgIF; u32 freq = params->frequency * 62500; priv->mode = TDA18271_ANALOG; - if (params->std & V4L2_STD_MN) { + if (params->mode == V4L2_TUNER_RADIO) { + radio = 1; + freq = freq / 1000; + std = std_map->fm_radio.std_bits; + sgIF = std_map->fm_radio.if_freq; + mode = "fm"; + } else if (params->std & V4L2_STD_MN) { std = std_map->atv_mn.std_bits; sgIF = std_map->atv_mn.if_freq; mode = "MN"; @@ -926,7 +940,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, tda_dbg("setting tda18271 to system %s\n", mode); - ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std); + ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio); if (ret < 0) goto fail; @@ -994,6 +1008,7 @@ static int tda18271_dump_std_map(struct dvb_frontend *fe) struct tda18271_std_map *std = &priv->std; tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); + tda18271_dump_std_item(fm_radio, "fm"); tda18271_dump_std_item(atv_b, "pal b"); tda18271_dump_std_item(atv_dk, "pal dk"); tda18271_dump_std_item(atv_gh, "pal gh"); @@ -1020,6 +1035,7 @@ static int tda18271_update_std_map(struct dvb_frontend *fe, if (!map) return -EINVAL; + tda18271_update_std(fm_radio, "fm"); tda18271_update_std(atv_b, "atv b"); tda18271_update_std(atv_dk, "atv dk"); tda18271_update_std(atv_gh, "atv gh"); diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c index 0402c7dab19..e94afcfdc5b 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -1187,6 +1187,7 @@ fail: /*---------------------------------------------------------------------*/ static struct tda18271_std_map tda18271c1_std_map = { + .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, .atv_b = { .if_freq = 6750, .std_bits = 0x0e }, .atv_dk = { .if_freq = 7750, .std_bits = 0x0f }, .atv_gh = { .if_freq = 7750, .std_bits = 0x0f }, @@ -1203,6 +1204,7 @@ static struct tda18271_std_map tda18271c1_std_map = { }; static struct tda18271_std_map tda18271c2_std_map = { + .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, .atv_b = { .if_freq = 6000, .std_bits = 0x0d }, .atv_dk = { .if_freq = 6900, .std_bits = 0x0e }, .atv_gh = { .if_freq = 7100, .std_bits = 0x0e }, diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h index 9ccfa6e8b5a..24b0e35a2ab 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/dvb/frontends/tda18271.h @@ -30,6 +30,7 @@ struct tda18271_std_map_item { }; struct tda18271_std_map { + struct tda18271_std_map_item fm_radio; struct tda18271_std_map_item atv_b; struct tda18271_std_map_item atv_dk; struct tda18271_std_map_item atv_gh; -- cgit v1.2.3 From cf04d29c4868a783b3e994e4a19f78ce22ba2d93 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 9 Jan 2008 00:34:30 -0300 Subject: V4L/DVB (6988): tda18271: give calibration debug a separate debug mask We don't usually want to see the calibration debug messages, but sometimes it is useful. Assign it to a separate debug mask. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 6 +++--- drivers/media/dvb/frontends/tda18271-priv.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 7d218819b28..0b41b951394 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -25,7 +25,7 @@ int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level " - "(info=1, map=2, reg=4, adv=8 (or-able))"); + "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); static LIST_HEAD(tda18271_list); static DEFINE_MUTEX(tda18271_list_mutex); @@ -459,7 +459,7 @@ static int tda18271_powerscan(struct dvb_frontend *fe, } else bcal = 0; - tda_dbg("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", + tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", bcal, *freq_in, *freq_out, freq); return bcal; @@ -522,7 +522,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) for (rf = RF1; rf <= RF3; rf++) { if (0 == rf_default[rf]) return 0; - tda_dbg("freq = %d, rf = %d\n", freq, rf); + tda_cal("freq = %d, rf = %d\n", freq, rf); /* look for optimized calibration frequency */ bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 5c04d63ae84..080efb3991e 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -130,6 +130,7 @@ extern int tda18271_debug; #define DBG_MAP 2 #define DBG_REG 4 #define DBG_ADV 8 +#define DBG_CAL 16 #define tda_printk(kern, fmt, arg...) \ printk(kern "%s: " fmt, __FUNCTION__, ##arg) @@ -144,6 +145,7 @@ extern int tda18271_debug; #define tda_dbg(fmt, arg...) dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg) #define tda_map(fmt, arg...) dprintk(KERN_DEBUG, DBG_MAP, fmt, ##arg) #define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg) +#define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg) /*---------------------------------------------------------------------*/ -- cgit v1.2.3 From 006ed1ecf2c62659e5dd902350a7eb209b8a5257 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 9 Jan 2008 10:44:27 -0300 Subject: V4L/DVB (6989): tda18271: clean up chip id logic in tda829x_release This test is easier to read. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 4ac7c043889..3e593a3d903 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -504,9 +504,9 @@ static void tda829x_release(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; - /* dont try to release the tuner - * if we didn't attach it from this module */ - if ((priv->ver > TDA8290) && (priv->ver > TDA8295)) + /* only try to release the tuner if we've + * attached it from within this module */ + if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) if (fe->ops.tuner_ops.release) fe->ops.tuner_ops.release(fe); -- cgit v1.2.3 From 6d8ea8621f49a1cc486de4bf893db9743d0577bf Mon Sep 17 00:00:00 2001 From: hermann pitton Date: Mon, 7 Jan 2008 22:36:09 -0300 Subject: V4L/DVB (6992): saa7134: remove Beholder devices without eeprom from auto detection As in the past, we should not allow to auto detect like this, since all saa7130 and saa7134 cards without eeprom will be detected as such Beholder cards then. Signed-off-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 46b6ac4b310..0e3d2a73932 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -4676,24 +4676,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x0000, - .driver_data = SAA7134_BOARD_BEHOLD_401, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x0000, .subdevice = 0x4016, .driver_data = SAA7134_BOARD_BEHOLD_401, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x0000, - .driver_data = SAA7134_BOARD_BEHOLD_403FM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -- cgit v1.2.3 From e9ca1c79f2868d26c3e74ff3f20d5fa7d30724c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 9 Jan 2008 21:35:56 -0300 Subject: V4L/DVB (6993): Fix CARDLIST.saa7134 Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index fda570e50fa..fe8514e06d2 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -116,9 +116,9 @@ 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] 116 -> 10MOONS TM300 TV Card [1131:2304] 117 -> Avermedia Super 007 [1461:f01d] -118 -> Beholder BeholdTV 401 [1131:0000,0000:4016] +118 -> Beholder BeholdTV 401 [0000:4016] 119 -> Beholder BeholdTV 403 [0000:4036] -120 -> Beholder BeholdTV 403 FM [1131:0000,0000:4037] +120 -> Beholder BeholdTV 403 FM [0000:4037] 121 -> Beholder BeholdTV 405 [0000:4050] 122 -> Beholder BeholdTV 405 FM [0000:4051] 123 -> Beholder BeholdTV 407 [0000:4070] -- cgit v1.2.3 From eeec4b3853a8af0cd2b42af24b9e8fd0e0ef1f8a Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Wed, 9 Jan 2008 17:33:53 -0300 Subject: V4L/DVB (6994): usbvision: add Pinnacle Studio PCTV USB (NTSC) FM V3 Add the "Pinnacle Studio PCTV USB (NTSC) FM" device. This is the third occurrence of the same device designation... Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.usbvision | 1 + drivers/media/video/usbvision/usbvision-cards.c | 18 +++++++++++++++++- drivers/media/video/usbvision/usbvision-cards.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.usbvision b/Documentation/video4linux/CARDLIST.usbvision index 3d6850ef024..0b72d3fee17 100644 --- a/Documentation/video4linux/CARDLIST.usbvision +++ b/Documentation/video4linux/CARDLIST.usbvision @@ -62,3 +62,4 @@ 61 -> Pinnacle Studio Linx Video input cable (PAL) [2304:0301] 62 -> Pinnacle PCTV Bungee USB (PAL) FM [2304:0419] 63 -> Hauppauge WinTv-USB [2400:4200] + 64 -> Pinnacle Studio PCTV USB (NTSC) FM V3 [2304:0113] diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index f09eb102731..503b13beb92 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -901,6 +901,20 @@ struct usbvision_device_data_st usbvision_device_data[] = { .Y_Offset = -1, .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM", }, + [PINNA_PCTV_USB_NTSC_FM_V3] = { + .Interface = -1, + .Codec = CODEC_SAA7111, + .VideoChannels = 3, + .VideoNorm = V4L2_STD_NTSC, + .AudioChannels = 1, + .Radio = 1, + .vbi = 1, + .Tuner = 1, + .TunerType = TUNER_PHILIPS_NTSC_M, + .X_Offset = -1, + .Y_Offset = -1, + .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V3", + }, [PINNA_PCTV_USB_PAL_FM_V2] = { .Interface = -1, .Codec = CODEC_SAA7113, @@ -1044,7 +1058,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN }, { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 }, { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL }, - { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 }, + { USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 }, { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG }, { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I }, { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L }, @@ -1074,6 +1088,8 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM }, { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB }, { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM }, + { USB_DEVICE(0x2304, 0x0113), + .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 }, { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 }, { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 }, { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 }, diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h index 512c5cee414..9c6ad22960d 100644 --- a/drivers/media/video/usbvision/usbvision-cards.h +++ b/drivers/media/video/usbvision/usbvision-cards.h @@ -62,5 +62,6 @@ #define PINNA_LINX_VD_IN_CAB_PAL 61 #define PINNA_PCTV_BUNGEE_PAL_FM 62 #define HPG_WINTV 63 +#define PINNA_PCTV_USB_NTSC_FM_V3 64 extern const int usbvision_device_data_size; -- cgit v1.2.3 From c6243d9c3de82e46467c88898db45ca14b6843a0 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Wed, 9 Jan 2008 17:34:53 -0300 Subject: V4L/DVB (6995): ubvision: add adjust_X_Offset/adjust_Y_Offset parms Add adjust_X_Offset/adjust_Y_Offset module parameters to allow users to tune X and Y picture offsets for their almost-working tuners without repetitive recompilation. Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 9e404b87d00..1e52a0387aa 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -69,6 +69,15 @@ static int SwitchSVideoInput = 0; // To help people with Black and White outpu module_param(SwitchSVideoInput, int, 0444); MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); +static unsigned int adjust_X_Offset = -1; +module_param(adjust_X_Offset, int, 0644); +MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]"); + +static unsigned int adjust_Y_Offset = -1; +module_param(adjust_Y_Offset, int, 0644); +MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]"); + + #define ENABLE_HEXDUMP 0 /* Enable if you need it */ @@ -2097,11 +2106,21 @@ int usbvision_set_input(struct usb_usbvision *usbvision) value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8; } + if (adjust_X_Offset != -1) { + value[4] = adjust_X_Offset & 0xff; + value[5] = (adjust_X_Offset & 0x0300) >> 8; + } + if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) { value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff; value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8; } + if (adjust_Y_Offset != -1) { + value[6] = adjust_Y_Offset & 0xff; + value[7] = (adjust_Y_Offset & 0x0300) >> 8; + } + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), USBVISION_OP_CODE, /* USBVISION specific code */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0, -- cgit v1.2.3 From d05051c82e0e8ff748e9c9a06a061bda3ad656e5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 10 Jan 2008 07:33:03 -0300 Subject: V4L/DVB (6997): Replace a very dirty hack on videobuf for a clean wait_event In order to videobuf_iolock to work, mmap_mapper should be called first. Otherwise, an OOPS is generated. On some cases, .mmap file handler used to took some time to be called. On those situations, mmap_mmapper() were called after iolock. This patch properly waits for mmap_mapper to be called, otherwise generating an error. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 15 +++++++++++---- include/media/videobuf-core.h | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 43fe3f78c8d..c3adbd686ff 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -98,13 +98,15 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, MAGIC_CHECK(vb->magic, MAGIC_BUFFER); MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - /* FIXME: This is required to avoid OOPS on some cases, + /* This is required to avoid OOPS on some cases, since mmap_mapper() method should be called before _iolock. On some cases, the mmap_mapper() is called only after scheduling. - - However, this way is just too dirty! Better to wait for some event. */ - schedule_timeout(HZ); + wait_event_timeout(vb->done, q->is_mmapped, msecs_to_jiffies(100)); + if (!q->is_mmapped) { + printk(KERN_ERR "Error: mmap_mapper() never called!\n"); + return -EINVAL; + } return CALL(q, iolock, q, vb, fbuf); } @@ -300,7 +302,11 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + rc = CALL(q, mmap_free, q); + + q->is_mmapped = 0; + if (rc < 0) return rc; @@ -1022,6 +1028,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, mutex_lock(&q->lock); retval = CALL(q, mmap_mapper, q, vma); + q->is_mmapped = 1; mutex_unlock(&q->lock); return retval; diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 7aa7a7b64c1..97f14d46959 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -164,6 +164,8 @@ struct videobuf_queue { unsigned int streaming:1; unsigned int reading:1; + unsigned int is_mmapped:1; + /* capture via mmap() + ioctl(QBUF/DQBUF) */ struct list_head stream; -- cgit v1.2.3 From f234081bc564c69eb0e2cd4e957ad1cbae4a6144 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 01:22:39 -0300 Subject: V4L/DVB (7002): cx25840: Add basic CX23885 AVCore support The cx23885/7/8 PCIe bridge has an internal AVCore modelled on the cx2584x family. Many of the registers positions are identical but some moved. The register values are also different because the different bridges run at different clock rates. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 65 ++++++-- drivers/media/video/cx25840/cx25840-core.c | 219 ++++++++++++++++++++++--- drivers/media/video/cx25840/cx25840-core.h | 1 + drivers/media/video/cx25840/cx25840-firmware.c | 5 + include/media/cx25840.h | 19 +++ 5 files changed, 272 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 51fc0af0157..d6421e1e8f6 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -32,11 +32,17 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) /* common for all inputs and rates */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ - cx25840_write(client, 0x127, 0x50); + if (!state->is_cx23885) + cx25840_write(client, 0x127, 0x50); if (state->aud_input != CX25840_AUDIO_SERIAL) { switch (freq) { case 32000: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x1006040f); @@ -53,6 +59,11 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) break; case 44100: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x1009040f); @@ -69,6 +80,11 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) break; case 48000: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x100a040f); @@ -87,6 +103,11 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) } else { switch (freq) { case 32000: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x1e08040f); @@ -109,6 +130,12 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) break; case 44100: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } + /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x1809040f); @@ -128,22 +155,33 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) break; case 48000: - /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x180a040f); + if (!state->is_cx23885) { + /* VID_PLL and AUX_PLL */ + cx25840_write4(client, 0x108, 0x180a040f); - /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x0098d6e5); + /* AUX_PLL_FRAC */ + cx25840_write4(client, 0x110, 0x0098d6e5); + } if (state->is_cx25836) break; - /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x08018000); + if (!state->is_cx23885) { + /* src1_ctl */ + cx25840_write4(client, 0x8f8, 0x08018000); - /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x08015555); - cx25840_write4(client, 0x904, 0x08015555); - cx25840_write4(client, 0x90c, 0x08015555); + /* src3/4/6_ctl */ + cx25840_write4(client, 0x900, 0x08015555); + cx25840_write4(client, 0x904, 0x08015555); + cx25840_write4(client, 0x90c, 0x08015555); + } else { + + cx25840_write4(client, 0x8f8, 0x0801867c); + + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); + } break; } } @@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client) /* deassert soft reset */ cx25840_and_or(client, 0x810, ~0x1, 0x00); + + if (state->is_cx23885) { + /* Ensure the controller is running when we exit */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); + } } static int get_volume(struct i2c_client *client) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 0d3d24aff50..756a1eeb274 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -13,6 +13,8 @@ * NTSC sliced VBI support by Christopher Neufeld * with additional fixes by Hans Verkuil . * + * CX23885 support by Steven Toth . + * * 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 @@ -255,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_and_or(client, 0x803, ~0x10, 0x10); } +static void cx23885_initialize(struct i2c_client *client) +{ + DEFINE_WAIT(wait); + struct cx25840_state *state = i2c_get_clientdata(client); + struct workqueue_struct *q; + + /* Internal Reset */ + cx25840_and_or(client, 0x102, ~0x01, 0x01); + cx25840_and_or(client, 0x102, ~0x01, 0x00); + + /* Stop microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + + /* DIF in reset? */ + cx25840_write(client, 0x398, 0); + + /* Trust the default xtal, no division */ + /* This changes for the cx23888 products */ + cx25840_write(client, 0x2, 0x76); + + /* Bring down the regulator for AUX clk */ + cx25840_write(client, 0x1, 0x40); + + /* Sys PLL frac */ + cx25840_write4(client, 0x11c, 0x01d1744c); + + /* Sys PLL int */ + cx25840_write4(client, 0x118, 0x00000416); + + /* Disable DIF bypass */ + cx25840_write4(client, 0x33c, 0x00000001); + + /* DIF Src phase inc */ + cx25840_write4(client, 0x340, 0x0df7df83); + + /* Vid PLL frac */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + + /* Vid PLL int */ + cx25840_write4(client, 0x108, 0x00000512); + + /* Luma */ + cx25840_write4(client, 0x414, 0x00107d12); + + /* Chroma */ + cx25840_write4(client, 0x420, 0x3d008282); + + /* Aux PLL frac */ + cx25840_write4(client, 0x114, 0x017dbf48); + + /* Aux PLL int */ + cx25840_write4(client, 0x110, 0x000a030e); + + /* ADC2 input select */ + cx25840_write(client, 0x102, 0x10); + + /* VIN1 & VIN5 */ + cx25840_write(client, 0x103, 0x11); + + /* Enable format auto detect */ + cx25840_write(client, 0x400, 0); + /* Fast subchroma lock */ + /* White crush, Chroma AGC & Chroma Killer enabled */ + cx25840_write(client, 0x401, 0xe8); + + /* Select AFE clock pad output source */ + cx25840_write(client, 0x144, 0x05); + + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + + cx25840_vbi_setup(client); + + /* (re)set input */ + set_input(client, state->vid_input, state->aud_input); + + /* start microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); +} + /* ----------------------------------------------------------------------- */ static void input_change(struct i2c_client *client) @@ -318,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input <= CX25840_COMPOSITE8); u8 reg; - v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n", - vid_input, aud_input); + v4l_dbg(1, cx25840_debug, client, + "decoder set video input %d, audio input %d\n", + vid_input, aud_input); + if (vid_input >= CX25840_VIN1_CH1) { + v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", + vid_input); + reg = vid_input & 0xff; + if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) + is_composite = 0; + else + is_composite = 1; + + v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", + reg, is_composite); + } else if (is_composite) { reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); } else { @@ -330,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp if ((vid_input & ~0xff0) || luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { - v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); + v4l_err(client, "0x%04x is not a valid video input!\n", + vid_input); return -EINVAL; } reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); @@ -343,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp } } - switch (aud_input) { - case CX25840_AUDIO_SERIAL: - /* do nothing, use serial audio input */ - break; - case CX25840_AUDIO4: reg &= ~0x30; break; - case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX25840_AUDIO7: reg &= ~0xc0; break; - case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + /* The caller has previously prepared the correct routing + * configuration in reg (for the cx23885) so we have no + * need to attempt to flip bits for earlier av decoders. + */ + if (!state->is_cx23885) { + switch (aud_input) { + case CX25840_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX25840_AUDIO4: reg &= ~0x30; break; + case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX25840_AUDIO7: reg &= ~0xc0; break; + case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; - default: - v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); - return -EINVAL; + default: + v4l_err(client, "0x%04x is not a valid audio input!\n", + aud_input); + return -EINVAL; + } } cx25840_write(client, 0x103, reg); + /* Set INPUT_MODE to Composite (0) or S-Video (1) */ cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); - /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ - if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) - cx25840_and_or(client, 0x102, ~0x4, 4); - else - cx25840_and_or(client, 0x102, ~0x4, 0); + + if (!state->is_cx23885) { + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx25840_and_or(client, 0x102, ~0x4, 4); + else + cx25840_and_or(client, 0x102, ~0x4, 0); + } else { + if (is_composite) + /* ADC2 input select channel 2 */ + cx25840_and_or(client, 0x102, ~0x2, 0); + else + /* ADC2 input select channel 3 */ + cx25840_and_or(client, 0x102, ~0x2, 2); + } state->vid_input = vid_input; state->aud_input = aud_input; @@ -375,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_audio_set_path(client); input_change(client); } + + if (state->is_cx23885) { + /* Audio channel 1 src : Parallel 1 */ + cx25840_write(client, 0x124, 0x03); + + /* Select AFE clock pad output source */ + cx25840_write(client, 0x144, 0x05); + + /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ + cx25840_write(client, 0x914, 0xa0); + + /* I2S_OUT_CTL: + * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 + * I2S_OUT_MASTER_MODE = Master + */ + cx25840_write(client, 0x918, 0xa0); + cx25840_write(client, 0x919, 0x01); + } + return 0; } @@ -853,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, state->is_initialized = 1; if (state->is_cx25836) cx25836_initialize(client); + else if (state->is_cx23885) + cx23885_initialize(client); else cx25840_initialize(client); } @@ -870,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = cx25840_read(client, reg->reg & 0x0fff); else @@ -886,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_STREAMON: v4l_dbg(1, cx25840_debug, client, "enable output\n"); - cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c); - cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07); + if (state->is_cx23885) { + u8 v = (cx25840_read(client, 0x421) | 0x0b); + cx25840_write(client, 0x421, v); + } else { + cx25840_write(client, 0x115, + state->is_cx25836 ? 0x0c : 0x8c); + cx25840_write(client, 0x116, + state->is_cx25836 ? 0x04 : 0x07); + } break; case VIDIOC_STREAMOFF: v4l_dbg(1, cx25840_debug, client, "disable output\n"); - cx25840_write(client, 0x115, 0x00); - cx25840_write(client, 0x116, 0x00); + if (state->is_cx23885) { + u8 v = cx25840_read(client, 0x421) & ~(0x0b); + cx25840_write(client, 0x421, v); + } else { + cx25840_write(client, 0x115, 0x00); + cx25840_write(client, 0x116, 0x00); + } break; case VIDIOC_LOG_STATUS: @@ -1056,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_INT_RESET: if (state->is_cx25836) cx25836_initialize(client); + else if (state->is_cx23885) + cx23885_initialize(client); else cx25840_initialize(client); break; @@ -1086,6 +1246,7 @@ static int cx25840_probe(struct i2c_client *client) device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); + v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); /* The high byte of the device ID should be * 0x83 for the cx2583x and 0x84 for the cx2584x */ @@ -1094,6 +1255,10 @@ static int cx25840_probe(struct i2c_client *client) } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); + } else if (device_id == 0x0000) { + id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; + } else if (device_id == 0x1313) { + id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); @@ -1115,6 +1280,7 @@ static int cx25840_probe(struct i2c_client *client) i2c_set_clientdata(client, state); state->c = client; state->is_cx25836 = ((device_id & 0xff00) == 0x8300); + state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; @@ -1124,6 +1290,7 @@ static int cx25840_probe(struct i2c_client *client) state->vbi_line_offset = 8; state->id = id; state->rev = device_id; + return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index ea669b1f084..95093edc918 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -47,6 +47,7 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; + int is_cx23885; int is_initialized; wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ struct work_struct fw_work; /* work entry for fw load */ diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index e852024a5ea..1ddf724a2c7 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -24,6 +24,7 @@ #include "cx25840-core.h" #define FWFILE "v4l-cx25840.fw" +#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw" /* * Mike Isely - The FWSEND parameter controls the @@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size) int cx25840_loadfw(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); const struct firmware *fw = NULL; u8 buffer[4], *ptr; int size, send, retval; + if (state->is_cx23885) + firmware = FWFILE_CX23885; + if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { v4l_err(client, "unable to open firmware %s\n", firmware); return -EINVAL; diff --git a/include/media/cx25840.h b/include/media/cx25840.h index 8e7e52d659a..cd599ad29fb 100644 --- a/include/media/cx25840.h +++ b/include/media/cx25840.h @@ -49,6 +49,25 @@ enum cx25840_video_input { CX25840_SVIDEO2 = 0x620, CX25840_SVIDEO3 = 0x730, CX25840_SVIDEO4 = 0x840, + + /* Allow frames to specify specific input configurations */ + CX25840_VIN1_CH1 = 0x80000000, + CX25840_VIN2_CH1 = 0x80000001, + CX25840_VIN3_CH1 = 0x80000002, + CX25840_VIN4_CH1 = 0x80000003, + CX25840_VIN5_CH1 = 0x80000004, + CX25840_VIN6_CH1 = 0x80000005, + CX25840_VIN7_CH1 = 0x80000006, + CX25840_VIN8_CH1 = 0x80000007, + CX25840_VIN4_CH2 = 0x80000000, + CX25840_VIN5_CH2 = 0x80000010, + CX25840_VIN6_CH2 = 0x80000020, + CX25840_NONE_CH2 = 0x80000030, + CX25840_VIN7_CH3 = 0x80000000, + CX25840_VIN8_CH3 = 0x80000040, + CX25840_NONE0_CH3 = 0x80000080, + CX25840_NONE1_CH3 = 0x800000c0, + CX25840_SVIDEO_ON = 0x80000100, }; enum cx25840_audio_input { -- cgit v1.2.3 From 0ac5881aefc2dab8b3535c2e44fee6628acaf787 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 02:06:35 -0300 Subject: V4L/DVB (7003): cx23885: Add support for device revision detection Each version of the cx23885/7/8 silicon has different build revs. We'll use this internal revision to work around bugs and known issues in the video and encoder related patches. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 40 ++++++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-reg.h | 1 + drivers/media/video/cx23885/cx23885.h | 1 + 3 files changed, 42 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index f205ad6354e..a602ac800a4 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -702,6 +702,44 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p return 0; } +static void cx23885_dev_checkrevision(struct cx23885_dev *dev) +{ + switch (cx_read(RDR_CFG2) & 0xff) { + case 0x00: + /* cx23885 */ + dev->hwrevision = 0xa0; + break; + case 0x01: + /* CX23885-12Z */ + dev->hwrevision = 0xa1; + break; + case 0x02: + /* CX23885-13Z */ + dev->hwrevision = 0xb0; + break; + case 0x03: + /* CX23888-22Z */ + dev->hwrevision = 0xc0; + break; + case 0x0e: + /* CX23887-15Z */ + dev->hwrevision = 0xc0; + case 0x0f: + /* CX23887-14Z */ + dev->hwrevision = 0xb1; + break; + default: + printk(KERN_ERR "%s() New hardware revision found 0x%x\n", + __FUNCTION__, dev->hwrevision); + } + if (dev->hwrevision) + printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", + __FUNCTION__, dev->hwrevision); + else + printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", + __FUNCTION__, dev->hwrevision); +} + static int cx23885_dev_setup(struct cx23885_dev *dev) { int i; @@ -832,6 +870,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) } } + cx23885_dev_checkrevision(dev); + return 0; } diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 162169f9091..38abf49b63a 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -276,6 +276,7 @@ Channel manager Data Structure entry = 20 DWORD #define RDR_CFG0 0x00050000 #define RDR_CFG1 0x00050004 +#define RDR_CFG2 0x00050008 #define RDR_TLCTL0 0x00050318 /* APB DMAC Current Buffer Pointer */ diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 974ec14782d..48d0c87ddbc 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -191,6 +191,7 @@ struct cx23885_dev { u32 __iomem *lmmio; u8 __iomem *bmmio; int pci_irqmask; + int hwrevision; /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; -- cgit v1.2.3 From 5206d6ec36e2c66090c3c02c95b8d70c356a9ad3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 02:09:27 -0300 Subject: V4L/DVB (7004): cx23885: Ensure HVR1800 TDA8295A is reset fully on module load Failure to do this means that a full system reboot is required if the part hangs. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index aa0ddf2ea22..901bebcca7c 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -268,7 +268,13 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-15-18 cx23417 READY, CS, RD, WR */ /* GPIO-19 IR_RX */ - cx_set(GP0_IO, 0x00040004); /* Bring the tuner out of reset */ + /* Force the TDA8295A into reset and back */ + cx_set(GP0_IO, 0x00040004); + mdelay(20); + cx_clear(GP0_IO, 0x00000004); + mdelay(20); + cx_set(GP0_IO, 0x00040004); + mdelay(20); break; } } -- cgit v1.2.3 From 69ad6e56bade948793957a295b3bf1376cffdf65 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 02:16:41 -0300 Subject: V4L/DVB (7005): cx23885: SRAM reallocation prior to analog video implementation We need to clear space large enough for the video and encoder fifos. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index a602ac800a4..31723dd7cbd 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -75,12 +75,12 @@ static LIST_HEAD(cx23885_devlist); static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH01] = { - .name = "test ch1", + .name = "VID A", .cmds_start = 0x10000, - .ctrl_start = 0x10500, - .cdt = 0x10900, - .fifo_start = 0x3000, - .fifo_size = 0x1000, + .ctrl_start = 0x105b0, + .cdt = 0x107b0, + .fifo_start = 0x40, + .fifo_size = 0x2800, .ptr1_reg = DMA1_PTR1, .ptr2_reg = DMA1_PTR2, .cnt1_reg = DMA1_CNT1, @@ -102,8 +102,8 @@ static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH03] = { .name = "TS1 B", .cmds_start = 0x100A0, - .ctrl_start = 0x10780, - .cdt = 0x10400, + .ctrl_start = 0x10630, + .cdt = 0x10870, .fifo_start = 0x5000, .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, @@ -139,7 +139,7 @@ static struct sram_channel cx23885_sram_channels[] = { .name = "TS2 C", .cmds_start = 0x10140, .ctrl_start = 0x10680, - .cdt = 0x10480, + .cdt = 0x108d0, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -207,12 +207,12 @@ static struct sram_channel cx23885_sram_channels[] = { static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { - .name = "test ch1", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "VID A", + .cmds_start = 0x10000, + .ctrl_start = 0x105b0, + .cdt = 0x107b0, + .fifo_start = 0x40, + .fifo_size = 0x2800, .ptr1_reg = DMA1_PTR1, .ptr2_reg = DMA1_PTR2, .cnt1_reg = DMA1_CNT1, @@ -231,12 +231,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA2_CNT2, }, [SRAM_CH03] = { - .name = "ch3", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10780, + .cdt = 0x10400, + .fifo_start = 0x5000, + .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, .ptr2_reg = DMA3_PTR2, .cnt1_reg = DMA3_CNT1, -- cgit v1.2.3 From c771261330c90b7c77f686a1aa0fb4f756e07b5f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 02:24:27 -0300 Subject: V4L/DVB (7006): cx23885: Track the board clock frequency and allow overrides The cx23885/6/8 all have different clock rates, this patch allows the core to compensate, and developers to allow vendor specific overrides. This patches will be used by future analog video and encoder patches. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 2 ++ drivers/media/video/cx23885/cx23885-core.c | 8 ++++++++ drivers/media/video/cx23885/cx23885.h | 15 +++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 901bebcca7c..a4bac43cf9f 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -32,6 +32,8 @@ struct cx23885_board cx23885_boards[] = { [CX23885_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", + /* Ensure safe default for unknown boards */ + .clk_freq = 0, .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 31723dd7cbd..8616a26895d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -759,10 +759,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; dev->sram_channels = cx23887_sram_channels; + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 25000000; } else if(dev->pci->device == 0x8852) { dev->bridge = CX23885_BRIDGE_885; dev->sram_channels = cx23885_sram_channels; + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 28000000; } else BUG(); @@ -782,6 +786,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } + /* If the user specific a clk freq override, apply it */ + if (cx23885_boards[dev->board].clk_freq > 0) + dev->clk_freq = cx23885_boards[dev->board].clk_freq; + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); dev->pci_irqmask = 0x001f00; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 48d0c87ddbc..b957242dcd5 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -100,6 +100,17 @@ typedef enum { struct cx23885_board { char *name; port_t portb, portc; + + /* Vendors can and do run the PCIe bridge at different + * clock rates, driven physically by crystals on the PCBs. + * The core has to accomodate this. This allows the user + * to add new boards with new frequencys. The value is + * expressed in Hz. + * + * The core framework will default this value based on + * current designs, but it can vary. + */ + u32 clk_freq; struct cx23885_input input[MAX_CX23885_INPUT]; }; @@ -193,6 +204,10 @@ struct cx23885_dev { int pci_irqmask; int hwrevision; + /* This valud is board specific and is used to configure the + * AV core so we see nice clean and stable video and audio. */ + u32 clk_freq; + /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; -- cgit v1.2.3 From 7b8880140ff6aec6a5bec7929b03ce0b96a7c79a Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 03:40:49 -0300 Subject: V4L/DVB (7007): cx23885: Add basic video support for the HVR1800 This enabled basic preview NTSC and PAL support for the HVR1800. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Makefile | 2 +- drivers/media/video/cx23885/cx23885-cards.c | 27 ++-- drivers/media/video/cx23885/cx23885-core.c | 185 ++++++++++++++++++++++++---- drivers/media/video/cx23885/cx23885-i2c.c | 31 ++++- drivers/media/video/cx23885/cx23885-reg.h | 12 ++ drivers/media/video/cx23885/cx23885.h | 151 ++++++++++++++++++++++- 6 files changed, 366 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index 665067022d2..32c90be5060 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -1,4 +1,4 @@ -cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o +cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index a4bac43cf9f..c2d5a4d7228 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "cx23885.h" @@ -71,23 +72,29 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x42, /* 0x84 >> 1 */ .input = {{ .type = CX23885_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xff00, - },{ - .type = CX23885_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1, + .gpio0 = 0, },{ .type = CX23885_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xff02, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .gpio0 = 0, },{ .type = CX23885_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xff02, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .gpio0 = 0, }}, }, [CX23885_BOARD_HAUPPAUGE_HVR1250] = { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 8616a26895d..e1b06d79e9b 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -50,7 +50,7 @@ MODULE_PARM_DESC(card,"card type"); static unsigned int cx23885_devcount; static DEFINE_MUTEX(devlist); -static LIST_HEAD(cx23885_devlist); +LIST_HEAD(cx23885_devlist); #define NO_SYNC_LINE (-1U) @@ -356,7 +356,7 @@ static int cx23885_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -static void cx23885_wakeup(struct cx23885_tsport *port, +void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; @@ -392,7 +392,7 @@ static void cx23885_wakeup(struct cx23885_tsport *port, __FUNCTION__, bc); } -static int cx23885_sram_channel_setup(struct cx23885_dev *dev, +int cx23885_sram_channel_setup(struct cx23885_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc) { @@ -465,7 +465,7 @@ static int cx23885_sram_channel_setup(struct cx23885_dev *dev, return 0; } -static void cx23885_sram_channel_dump(struct cx23885_dev *dev, +void cx23885_sram_channel_dump(struct cx23885_dev *dev, struct sram_channel *ch) { static char *name[] = { @@ -592,15 +592,18 @@ static void cx23885_reset(struct cx23885_dev *dev) mdelay(100); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], + 720*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03], + 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06], + 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); cx23885_gpio_setup(dev); } @@ -634,7 +637,7 @@ static int get_resources(struct cx23885_dev *dev) } static void cx23885_timeout(unsigned long data); -static int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) @@ -854,6 +857,17 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_pci_quirks(dev); + /* Assume some sensible defaults */ + dev->tuner_type = cx23885_boards[dev->board].tuner_type; + dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; + dev->radio_type = cx23885_boards[dev->board].radio_type; + dev->radio_addr = cx23885_boards[dev->board].radio_addr; + + dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n", + __FUNCTION__, dev->tuner_type, dev->tuner_addr); + dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", + __FUNCTION__, dev->radio_type, dev->radio_addr); + /* init hardware */ cx23885_reset(dev); @@ -864,14 +878,21 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_setup(dev); cx23885_ir_init(dev); - if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { + if (cx23885_video_register(dev) < 0) { + printk(KERN_ERR "%s() Failed to register analog " + "video adapters on VID_A\n", __FUNCTION__); + } + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { if (cx23885_dvb_register(&dev->ts1) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", __FUNCTION__); } } - if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n", __FUNCTION__); @@ -891,6 +912,9 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) + cx23885_video_unregister(dev); + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) cx23885_dvb_unregister(&dev->ts1); @@ -958,6 +982,45 @@ static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist, return rp; } +int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines) +{ + u32 instructions, fields; + u32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + syncs + jump (all 2 dwords). Padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + /* write and jump need and extra dword */ + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions += 2; + if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) + rp = cx23885_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines); + if (UNSET != bottom_offset) + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + return 0; +} static int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, @@ -990,7 +1053,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, return 0; } -static int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value) { u32 *rp; @@ -1023,6 +1086,57 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) buf->vb.state = VIDEOBUF_NEEDS_INIT; } +static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s() Register Dump\n", __FUNCTION__); + dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __FUNCTION__, + cx_read(DEV_CNTRL2)); + dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __FUNCTION__, + cx_read(PCI_INT_MSK)); + dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __FUNCTION__, + cx_read(AUDIO_INT_INT_MSK)); + dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __FUNCTION__, + cx_read(AUD_INT_DMA_CTL)); + dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __FUNCTION__, + cx_read(AUDIO_EXT_INT_MSK)); + dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __FUNCTION__, + cx_read(AUD_EXT_DMA_CTL)); + dprintk(1, "%s() PAD_CTRL 0x%08X\n", __FUNCTION__, + cx_read(PAD_CTRL)); + dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __FUNCTION__, + cx_read(ALT_PIN_OUT_SEL)); + dprintk(1, "%s() GPIO2 0x%08X\n", __FUNCTION__, + cx_read(GPIO2)); + dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __FUNCTION__, + port->reg_gpcnt, cx_read(port->reg_gpcnt)); + dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); + dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); + dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_src_sel, cx_read(port->reg_src_sel)); + dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_lngth, cx_read(port->reg_lngth)); + dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); + dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); + dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); + dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_sop_status, cx_read(port->reg_sop_status)); + dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); + dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_vld_misc, cx_read(port->reg_vld_misc)); + dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); + dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); +} + static int cx23885_start_dma(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) @@ -1085,6 +1199,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ + if (debug > 4) + cx23885_tsport_reg_dump(port); + return 0; } @@ -1100,7 +1217,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) return 0; } -static int cx23885_restart_queue(struct cx23885_tsport *port, +int cx23885_restart_queue(struct cx23885_tsport *port, struct cx23885_dmaqueue *q) { struct cx23885_dev *dev = port->dev; @@ -1324,12 +1441,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_tsport *ts1 = &dev->ts1; struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; + u32 vida_status, vida_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; - int ts1_count = 0, ts2_count = 0, handled = 0; + int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); + vida_status = cx_read(VID_A_INT_STAT); + vida_mask = cx_read(VID_A_INT_MSK); ts1_status = cx_read(VID_B_INT_STAT); ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); @@ -1338,11 +1458,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; + vida_count = cx_read(VID_A_GPCNT); ts1_count = cx_read(ts1->reg_gpcnt); ts2_count = cx_read(ts2->reg_gpcnt); - dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count ); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count ); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", + pci_status, pci_mask); + dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", + vida_status, vida_mask, vida_count); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", + ts1_status, ts1_mask, ts1_count); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", + ts2_status, ts2_mask, ts2_count); if ( (pci_status & PCI_MSK_RISC_RD) || (pci_status & PCI_MSK_RISC_WR) || @@ -1379,11 +1505,18 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - if (ts1_status) - handled += cx23885_irq_ts(ts1, ts1_status); + if (ts1_status) { + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts1, ts1_status); + } + + if (ts2_status) { + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts2, ts2_status); + } - if (ts2_status) - handled += cx23885_irq_ts(ts2, ts2_status); + if (vida_status) + handled += cx23885_video_irq(dev, vida_status); if (handled) cx_write(PCI_INT_STAT, pci_status); diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index b2ffbf04ef2..fbc4a57a236 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -270,7 +270,9 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, static int attach_inform(struct i2c_client *client) { - struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter); + struct cx23885_dev *dev = bus->dev; + struct tuner_setup tun_setup; dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -278,6 +280,31 @@ static int attach_inform(struct i2c_client *client) if (!client->driver->command) return 0; + if (dev->tuner_type != UNSET) { + + dprintk(1, "%s (tuner) i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, + client->name); + + if ((dev->tuner_addr == ADDR_UNSET) || + (dev->tuner_addr == client->addr)) { + + dprintk(1, "%s (tuner || addr UNSET)\n", + client->driver->driver.name); + + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, + client->addr, client->name); + + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + + client->driver->command(client, TUNER_SET_TYPE_ADDR, + &tun_setup); + } + } + return 0; } @@ -316,6 +343,7 @@ static struct i2c_adapter cx23885_i2c_adap_template = { .owner = THIS_MODULE, .id = I2C_HW_B_CX23885, .algo = &cx23885_i2c_algo_template, + .class = I2C_CLASS_TV_ANALOG, .client_register = attach_inform, .client_unregister = detach_inform, }; @@ -371,6 +399,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; + i2c_set_adapdata(&bus->i2c_adap, bus); i2c_add_adapter(&bus->i2c_adap); bus->i2c_client.adapter = &bus->i2c_adap; diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 38abf49b63a..bdd11bc513a 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -233,6 +233,17 @@ Channel manager Data Structure entry = 20 DWORD #define VID_A_INT_SSTAT 0x0004002C #define VID_B_INT_MSK 0x00040030 +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_VBI_OPC_ERR (1 << 17) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_VBI_SYNC (1 << 13) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_VBI_OF (1 << 9) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_VBI_RISCI2 (1 << 5) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_VBI_RISCI1 (1 << 1) +#define VID_B_MSK_RISCI1 1 #define VID_B_INT_STAT 0x00040034 #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C @@ -336,6 +347,7 @@ Channel manager Data Structure entry = 20 DWORD /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ #define MC417_OEN 0x00110024 #define MC417_CTL 0x00110028 +#define ALT_PIN_OUT_SEL 0x0011002C #define CLK_DELAY 0x00110048 #define PAD_CTRL 0x0011004C diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b957242dcd5..390f9335bdc 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -44,6 +44,10 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 +#define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -56,6 +60,60 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 #define CX23885_BOARD_HAUPPAUGE_HVR1500 6 +/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ +#define CX23885_NORMS (\ + V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ + V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) + +struct cx23885_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +struct cx23885_ctrl { + struct v4l2_queryctrl v; + u32 off; + u32 reg; + u32 mask; + u32 shift; +}; + +struct cx23885_tvnorm { + char *name; + v4l2_std_id id; + u32 cxiformat; + u32 cxoformat; +}; + +struct cx23885_fh { + struct cx23885_dev *dev; + enum v4l2_buf_type type; + int radio; + u32 resources; + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip *clips; + unsigned int nclips; + + /* video capture */ + struct cx23885_fmt *fmt; + unsigned int width, height; + + /* vbi capture */ + struct videobuf_queue vidq; + struct videobuf_queue vbiq; + + /* MPEG Encoder specifics ONLY */ + struct videobuf_queue mpegq; + atomic_t v4l_reading; +}; + enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, CX23885_VMUX_COMPOSITE2, @@ -94,12 +152,17 @@ struct cx23885_input { typedef enum { CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB + CX23885_MPEG_DVB, + CX23885_ANALOG_VIDEO, } port_t; struct cx23885_board { char *name; - port_t portb, portc; + port_t porta, portb, portc; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; /* Vendors can and do run the PCIe bridge at different * clock rates, driven physically by crystals on the PCBs. @@ -228,8 +291,31 @@ struct cx23885_dev { CX23885_BRIDGE_885 = 885, CX23885_BRIDGE_887 = 887, } bridge; + + /* Analog video */ + u32 resources; + unsigned int input; + u32 tvaudio; + v4l2_std_id tvnorm; + unsigned int tuner_type; + unsigned char tuner_addr; + unsigned int radio_type; + unsigned char radio_addr; + unsigned int has_radio; + + /* V4l */ + u32 freq; + struct video_device *video_dev; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + struct cx23885_dmaqueue vidq; + struct cx23885_dmaqueue vbiq; + spinlock_t slock; }; +extern struct list_head cx23885_devlist; + #define SRAM_CH01 0 /* Video A */ #define SRAM_CH02 1 /* VBI A */ #define SRAM_CH03 2 /* Video B */ @@ -273,8 +359,34 @@ struct sram_channel { #define cx_clear(reg,bit) cx_andor((reg),(bit),0) /* ----------------------------------------------------------- */ -/* cx23885-cards.c */ +/* cx23885-core.c */ + +extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, + struct sram_channel *ch, + unsigned int bpl, u32 risc); + +extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); +extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines); + +void cx23885_cancel_buffers(struct cx23885_tsport *port); + +extern int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q); + +extern void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count); + + +/* ----------------------------------------------------------- */ +/* cx23885-cards.c */ extern struct cx23885_board cx23885_boards[]; extern const unsigned int cx23885_bcount; @@ -294,19 +406,50 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, struct cx23885_buffer *buf, enum v4l2_field field); - extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ +/* cx23885-video.c */ +/* Video */ +extern int cx23885_video_register(struct cx23885_dev *dev); +extern void cx23885_video_unregister(struct cx23885_dev *dev); +extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); + +/* ----------------------------------------------------------- */ +/* cx23885-vbi.c */ +extern int cx23885_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f); +extern void cx23885_vbi_timeout(unsigned long data); +extern struct videobuf_queue_ops cx23885_vbi_qops; + /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); +/* ----------------------------------------------------------- */ +/* tv norms */ + +static inline unsigned int norm_maxw(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; +} + +static inline unsigned int norm_maxh(v4l2_std_id norm) +{ + return (norm & V4L2_STD_625_50) ? 576 : 480; +} + +static inline unsigned int norm_swidth(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; +} + + /* * Local variables: * c-basic-offset: 8 -- cgit v1.2.3 From a57ed8a1f7381aa7e1bec6c55d5f119706f2982d Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 03:43:11 -0300 Subject: V4L/DVB (7008): s5h1409: Ensure the silicon is initialized during attach If not it impacts on analog tuner quality. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index d3b148ddad2..3391777e0b2 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -750,6 +750,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c) { struct s5h1409_state* state = NULL; + u16 reg; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); @@ -763,7 +764,8 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, state->if_freq = S5H1409_VSB_IF_FREQ; /* check if the demod exists */ - if (s5h1409_readreg(state, 0x04) != 0x0066) + reg = s5h1409_readreg(state, 0x04); + if ((reg != 0x0066) && (reg != 0x007f)) goto error; /* create dvb_frontend */ @@ -771,8 +773,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + if (s5h1409_init(&state->frontend) != 0) { + printk(KERN_ERR "%s: Failed to initialize correctly\n", + __FUNCTION__); + goto error; + } + /* Note: Leaving the I2C gate open here. */ - s5h1409_writereg(state, 0xf3, 1); + s5h1409_i2c_gate_ctrl(&state->frontend, 1); return &state->frontend; -- cgit v1.2.3 From e47f30b140333525ea682ec672641b470da1e599 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 04:25:59 -0300 Subject: V4L/DVB (7009): cx23885: Video and VBI related files cx23885: Video and VBI related files. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-vbi.c | 256 +++++ drivers/media/video/cx23885/cx23885-video.c | 1658 +++++++++++++++++++++++++++ 2 files changed, 1914 insertions(+) create mode 100644 drivers/media/video/cx23885/cx23885-vbi.c create mode 100644 drivers/media/video/cx23885/cx23885-video.c diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c new file mode 100644 index 00000000000..32ec9d5bdbd --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -0,0 +1,256 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2007 Steven Toth + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "cx23885.h" + +static unsigned int vbibufs = 4; +module_param(vbibufs, int, 0644); +MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); + +static unsigned int vbi_debug = 0; +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); + +#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) + +/* ------------------------------------------------------------------ */ + +int cx23885_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (dev->tvnorm & V4L2_STD_525_60) { + /* ntsc */ + f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.start[0] = 10; + f->fmt.vbi.start[1] = 273; + + } else if (dev->tvnorm & V4L2_STD_625_50) { + /* pal */ + f->fmt.vbi.sampling_rate = 35468950; + f->fmt.vbi.start[0] = 7 - 1; + f->fmt.vbi.start[1] = 319 - 1; + } + return 0; +} + +static int cx23885_start_vbi_dma(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], + buf->vb.width, buf->risc.dma); + + /* reset counter */ + q->count = 1; + + /* enable irqs */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); + cx_set(VID_A_INT_MSK, 0x000022); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); + cx_set(VID_A_DMA_CTL, 0x00000022); + + return 0; +} + +int cx23885_stop_vbi_dma(struct cx23885_dev *dev) +{ + /* stop dma */ + cx_clear(VID_A_DMA_CTL, 0x00000022); + + /* disable irqs */ + cx_clear(PCI_INT_MSK, 0x000001); + cx_clear(VID_A_INT_MSK, 0x00000022); + return 0; +} + +int cx23885_restart_vbi_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q) +{ + struct cx23885_buffer *buf; + struct list_head *item; + + if (list_empty(&q->active)) + return 0; + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_vbi_dma(dev, q, buf); + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx23885_buffer, vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +void cx23885_vbi_timeout(unsigned long data) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)data; + struct cx23885_dmaqueue *q = &dev->vbiq; + struct cx23885_buffer *buf; + unsigned long flags; + + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); + + cx_clear(VID_A_DMA_CTL, 0x22); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, + buf, buf->vb.i, (unsigned long)buf->risc.dma); + } + cx23885_restart_vbi_queue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +/* ------------------------------------------------------------------ */ +#define VBI_LINE_LENGTH 2048 +#define VBI_LINE_COUNT 17 + +static int +vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 == *count) + *count = vbibufs; + if (*count < 2) + *count = 2; + if (*count > 32) + *count = 32; + return 0; +} + +static int +vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + unsigned int size; + int rc; + + size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + buf->vb.width = VBI_LINE_LENGTH; + buf->vb.height = VBI_LINE_COUNT; + buf->vb.size = size; + buf->vb.field = V4L2_FIELD_SEQ_TB; + + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->vb.width * buf->vb.height, + buf->vb.width, 0, + buf->vb.height); + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +static void +vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_fh *fh = vq->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_dmaqueue *q = &dev->vbiq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_vbi_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] vbi_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + } +} + +static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + cx23885_free_buffer(q, buf); +} + +struct videobuf_queue_ops cx23885_vbi_qops = { + .buf_setup = vbi_setup, + .buf_prepare = vbi_prepare, + .buf_queue = vbi_queue, + .buf_release = vbi_release, +}; + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c new file mode 100644 index 00000000000..8eaebdb76b1 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -0,0 +1,1658 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2007 Steven Toth + * + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx23885.h" +#include + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +/* Include V4L1 specific functions. Should be removed soon */ +#include +#endif + +MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth "); +MODULE_LICENSE("GPL"); + +/* ------------------------------------------------------------------ */ + +static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +static unsigned int video_debug = 0; +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); + +static unsigned int irq_debug = 0; +module_param(irq_debug, int, 0644); +MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); + +static unsigned int vid_limit = 16; +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); + +#define dprintk(level, fmt, arg...)\ + if (video_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------- */ +/* static data */ + +#define FORMAT_FLAGS_PACKED 0x01 + +static struct cx23885_fmt formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, +}; + +static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].fourcc == fourcc) + return formats+i; + + printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc); + return NULL; +} + +/* ------------------------------------------------------------------- */ + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +static struct cx23885_ctrl cx23885_ctls[] = { + /* --- video --- */ + { + .v = { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = LUMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + .v = { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = LUMA_CTRL, + .mask = 0xff00, + .shift = 8, + }, { + .v = { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = CHROMA_CTRL, + .mask = 0xff0000, + .shift = 16, + }, { + /* strictly, this only describes only U saturation. + * V saturation is handled specially through code. + */ + .v = { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = CHROMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + /* --- audio --- */ + .v = { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = PATH1_CTL1, + .mask = (0x1f << 24), + .shift = 24, + }, { + .v = { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .reg = PATH1_VOL_CTL, + .mask = 0xff, + .shift = 0, + } +}; +static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); + +const u32 cx23885_user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_MUTE, + 0 +}; +EXPORT_SYMBOL(cx23885_user_ctrls); + +static const u32 *ctrl_classes[] = { + cx23885_user_ctrls, + NULL +}; + +void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + do_gettimeofday(&buf->vb.ts); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, + count, buf->count); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) { + del_timer(&q->timeout); + } else { + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + } + if (bc != 1) + printk(KERN_WARN "%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); +} + +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +{ + dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", + __FUNCTION__, + (unsigned int)norm, + v4l2_norm_to_name(norm)); + + dev->tvnorm = norm; + + + /* Tell the analog tuner/demods */ + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); + + /* Tell the internal A/V decoder */ + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm); + + return 0; +} + +struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, + struct pci_dev *pci, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + dprintk(1, "%s()\n", __FUNCTION__); + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + vfd->dev = &pci->dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + dev->name, type, cx23885_boards[dev->board].name); + return vfd; +} + +int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) +{ + int i; + + if (qctrl->id < V4L2_CID_BASE || + qctrl->id >= V4L2_CID_LASTP1) + return -EINVAL; + for (i = 0; i < CX23885_CTLS; i++) + if (cx23885_ctls[i].v.id == qctrl->id) + break; + if (i == CX23885_CTLS) { + *qctrl = no_ctl; + return 0; + } + *qctrl = cx23885_ctls[i].v; + return 0; +} +EXPORT_SYMBOL(cx23885_ctrl_query); + +/* ------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, + unsigned int bit) +{ + dprintk(1, "%s()\n", __FUNCTION__); + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(1, "res: get %d\n", bit); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_check(struct cx23885_fh *fh, unsigned int bit) +{ + return (fh->resources & bit); +} + +static int res_locked(struct cx23885_dev *dev, unsigned int bit) +{ + return (dev->resources & bit); +} + +static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, + unsigned int bits) +{ + BUG_ON((fh->resources & bits) != bits); + dprintk(1, "%s()\n", __FUNCTION__); + + mutex_lock(&dev->lock); + fh->resources &= ~bits; + dev->resources &= ~bits; + dprintk(1, "res: put %d\n", bits); + mutex_unlock(&dev->lock); +} + +int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) +{ + struct v4l2_routing route; + memset(&route, 0, sizeof(route)); + + dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", + __FUNCTION__, + input, INPUT(input)->vmux, + INPUT(input)->gpio0, INPUT(input)->gpio1, + INPUT(input)->gpio2, INPUT(input)->gpio3); + dev->input = input; + + route.input = INPUT(input)->vmux; + + /* Tell the internal A/V decoder */ + cx23885_call_i2c_clients(&dev->i2c_bus[2], + VIDIOC_INT_S_VIDEO_ROUTING, &route); + + return 0; +} +EXPORT_SYMBOL(cx23885_video_mux); + +/* ------------------------------------------------------------------ */ +int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, + unsigned int height, enum v4l2_field field) +{ + dprintk(1, "%s()\n", __FUNCTION__); + return 0; +} + +static int cx23885_start_video_dma(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], + buf->bpl, buf->risc.dma); + cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + + /* reset counter */ + cx_write(VID_A_GPCNT_CTL, 3); + q->count = 1; + + /* enable irq */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); + cx_set(VID_A_INT_MSK, 0x000011); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); + cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ + + return 0; +} + +#ifdef CONFIG_PM +static int cx23885_stop_video_dma(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + /* stop dma */ + cx_clear(VID_A_DMA_CTL, 0x11); + + /* disable irqs */ + cx_clear(PCI_INT_MSK, 0x000001); + cx_clear(VID_A_INT_MSK, 0x000011); + + return 0; +} +#endif + +static int cx23885_restart_video_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q) +{ + struct cx23885_buffer *buf, *prev; + struct list_head *item; + dprintk(1, "%s()\n", __FUNCTION__); + + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_video_dma(dev, q, buf); + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx23885_buffer, + vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + cx23885_start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_move_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ + dprintk(2, "[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } +} + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct cx23885_fh *fh = q->priv_data; + + *size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 == *count) + *count = 32; + while (*size * *count > vid_limit * 1024 * 1024) + (*count)--; + return 0; +} + +static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + int rc, init_buffer = 0; + u32 line0_offset, line1_offset; + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + BUG_ON(NULL == fh->fmt); + if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || + fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) + return -EINVAL; + buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + init_buffer = 1; + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + } + + if (init_buffer) { + buf->bpl = buf->vb.width * buf->fmt->depth >> 3; + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, 0, UNSET, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, UNSET, 0, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_NTSC) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating NTSC risc\n", + __FUNCTION__); + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating PAL/SECAM risc\n", + __FUNCTION__); + line0_offset = 0; + line1_offset = buf->bpl; + } + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, + buf->vb.height >> 1); + break; + default: + BUG(); + } + } + dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.i, + fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_fh *fh = vq->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_dmaqueue *q = &dev->vidq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - append to queued\n", + buf, buf->vb.i); + + } else if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] buffer_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx23885_buffer, + vb.queue); + if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + /* 64 bit bits 63-32 */ + prev->risc.jmp[2] = cpu_to_le32(0); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + + } else { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - first queued\n", + buf, buf->vb.i); + } + } +} + +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_free_buffer(q, buf); +} + +static struct videobuf_queue_ops cx23885_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +static struct videobuf_queue *get_queue(struct cx23885_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &fh->vidq; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return &fh->vbiq; + default: + BUG(); + return NULL; + } +} + +static int get_resource(struct cx23885_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return RESOURCE_VIDEO; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return RESOURCE_VBI; + default: + BUG(); + return 0; + } +} + +static int video_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct cx23885_dev *h, *dev = NULL; + struct cx23885_fh *fh; + struct list_head *list; + enum v4l2_buf_type type = 0; + int radio = 0; + + list_for_each(list, &cx23885_devlist) { + h = list_entry(list, struct cx23885_dev, devlist); + if (h->video_dev->minor == minor) { + dev = h; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + if (h->vbi_dev && + h->vbi_dev->minor == minor) { + dev = h; + type = V4L2_BUF_TYPE_VBI_CAPTURE; + } + if (h->radio_dev && + h->radio_dev->minor == minor) { + radio = 1; + dev = h; + } + } + if (NULL == dev) + return -ENODEV; + + dprintk(1, "open minor=%d radio=%d type=%s\n", + minor, radio, v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + fh->width = 320; + fh->height = 240; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + + videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops, + dev->pci, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx23885_buffer), + fh); + + dprintk(1, "post videobuf_queue_init()\n"); + + + return 0; +} + +static ssize_t video_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct cx23885_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + return videobuf_read_one(&fh->vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!res_get(fh->dev, fh, RESOURCE_VBI)) + return -EBUSY; + return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + default: + BUG(); + return 0; + } +} + +static unsigned int video_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_buffer *buf; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (!res_get(fh->dev, fh, RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(file, &fh->vbiq, wait); + } + + if (res_check(fh, RESOURCE_VIDEO)) { + /* streaming capture */ + if (list_empty(&fh->vidq.stream)) + return POLLERR; + buf = list_entry(fh->vidq.stream.next, + struct cx23885_buffer, vb.stream); + } else { + /* read() capture */ + buf = (struct cx23885_buffer *)fh->vidq.read_buf; + if (NULL == buf) + return POLLERR; + } + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + return POLLIN|POLLRDNORM; + return 0; +} + +static int video_release(struct inode *inode, struct file *file) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + /* turn off overlay */ + if (res_check(fh, RESOURCE_OVERLAY)) { + /* FIXME */ + res_free(dev, fh, RESOURCE_OVERLAY); + } + + /* stop video capture */ + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_queue_cancel(&fh->vidq); + res_free(dev, fh, RESOURCE_VIDEO); + } + if (fh->vidq.read_buf) { + buffer_release(&fh->vidq, fh->vidq.read_buf); + kfree(fh->vidq.read_buf); + } + + /* stop vbi capture */ + if (res_check(fh, RESOURCE_VBI)) { + if (fh->vbiq.streaming) + videobuf_streamoff(&fh->vbiq); + if (fh->vbiq.reading) + videobuf_read_stop(&fh->vbiq); + res_free(dev, fh, RESOURCE_VBI); + } + + videobuf_mmap_free(&fh->vidq); + file->private_data = NULL; + kfree(fh); + + + return 0; +} + +static int video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_mmap_mapper(get_queue(fh), vma); +} + +/* ------------------------------------------------------------------ */ +/* VIDEO CTRL IOCTLS */ + +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +{ + dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__); + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); + return 0; +} +EXPORT_SYMBOL(cx23885_get_control); + +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +{ + dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" + " (disabled - no action)\n", __FUNCTION__); + return 0; +} +EXPORT_SYMBOL(cx23885_set_control); + +static void init_controls(struct cx23885_dev *dev) +{ + struct v4l2_control ctrl; + int i; + + for (i = 0; i < CX23885_CTLS; i++) { + ctrl.id = cx23885_ctls[i].v.id; + ctrl.value = cx23885_ctls[i].v.default_value; + + cx23885_set_control(dev, &ctrl); + } +} + +/* ------------------------------------------------------------------ */ +/* VIDEO IOCTLS */ + +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = norm_maxw(dev->tvnorm); + maxh = norm_maxh(dev->tvnorm); + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + int err; + + dprintk(2, "%s()\n", __FUNCTION__); + err = vidioc_try_fmt_cap(file, priv, f); + + if (0 != err) + return err; + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vidq.field = f->fmt.pix.field; + dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__, + fh->width, fh->height, fh->vidq.field); + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + strcpy(cap->driver, "cx23885"); + strlcpy(cap->card, cx23885_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); + cap->version = CX23885_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (UNSET != dev->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, + struct video_mbuf *mbuf) +{ + struct cx23885_fh *fh = priv; + struct videobuf_queue *q; + struct v4l2_requestbuffers req; + unsigned int i; + int err; + + q = get_queue(fh); + memset(&req, 0, sizeof(req)); + req.type = q->type; + req.count = 8; + req.memory = V4L2_MEMORY_MMAP; + err = videobuf_reqbufs(q, &req); + if (err < 0) + return err; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + return 0; +} +#endif + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_reqbufs(get_queue(fh), p)); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_querybuf(get_queue(fh), p)); +} + +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_qbuf(get_queue(fh), p)); +} + +static int vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_dqbuf(get_queue(fh), p, + file->f_flags & O_NONBLOCK)); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + if (unlikely(i != fh->type)) + return -EINVAL; + + if (unlikely(!res_get(dev, fh, get_resource(fh)))) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + int err, res; + dprintk(1, "%s()\n", __FUNCTION__); + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (i != fh->type) + return -EINVAL; + + res = get_resource(fh); + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev, fh, res); + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, *tvnorms); + mutex_unlock(&dev->lock); + + return 0; +} + +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +{ + static const char *iname[] = { + [CX23885_VMUX_COMPOSITE1] = "Composite1", + [CX23885_VMUX_COMPOSITE2] = "Composite2", + [CX23885_VMUX_COMPOSITE3] = "Composite3", + [CX23885_VMUX_COMPOSITE4] = "Composite4", + [CX23885_VMUX_SVIDEO] = "S-Video", + [CX23885_VMUX_TELEVISION] = "Television", + [CX23885_VMUX_CABLE] = "Cable TV", + [CX23885_VMUX_DVB] = "DVB", + [CX23885_VMUX_DEBUG] = "for debug only", + }; + unsigned int n; + dprintk(1, "%s()\n", __FUNCTION__); + + n = i->index; + if (n >= 4) + return -EINVAL; + + if (0 == INPUT(n)->type) + return -EINVAL; + + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, iname[INPUT(n)->type]); + if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || + (CX23885_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + i->std = CX23885_NORMS; + return 0; +} +EXPORT_SYMBOL(cx23885_enum_input); + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __FUNCTION__); + return cx23885_enum_input(dev, i); +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + *i = dev->input; + dprintk(1, "%s() returns %d\n", __FUNCTION__, *i); + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + dprintk(1, "%s(%d)\n", __FUNCTION__, i); + + if (i >= 4) { + dprintk(1, "%s() -EINVAL\n", __FUNCTION__); + return -EINVAL; + } + + mutex_lock(&dev->lock); + cx23885_video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (unlikely(qctrl->id == 0)) + return -EINVAL; + return cx23885_ctrl_query(qctrl); +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + return cx23885_get_control(dev, ctl); +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + return cx23885_set_control(dev, ctl); +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + t->signal = 0xffff ; /* LOCKED */ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->freq; + + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f); + + return 0; +} + +int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) +{ + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(10); + + mutex_unlock(&dev->lock); + + return 0; +} +EXPORT_SYMBOL(cx23885_set_freq); + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + return + cx23885_set_freq(dev, f); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg); + + return 0; +} + +static int vidioc_s_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); + return 0; +} +#endif + +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ +/* ----------------------------------------------------------- */ + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + strcpy(cap->driver, "cx23885"); + strlcpy(cap->card, cx23885_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); + cap->version = CX23885_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (unlikely(t->index > 0)) + return -EINVAL; + + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t); + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} + +/* FIXME: Should add a standard for radio */ + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (0 != t->index) + return -EINVAL; + + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_TUNER, t); + + return 0; +} + +static int radio_s_audio(struct file *file, void *fh, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *file, void *fh, unsigned int i) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + int i; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + for (i = 0; i < CX23885_CTLS; i++) + if (cx23885_ctls[i].v.id == c->id) + break; + *c = cx23885_ctls[i].v; + } else + *c = no_ctl; + return 0; +} + +/* ----------------------------------------------------------- */ + +static void cx23885_vid_timeout(unsigned long data) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)data; + struct cx23885_dmaqueue *q = &dev->vidq; + struct cx23885_buffer *buf; + unsigned long flags; + + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + + cx_clear(VID_A_DMA_CTL, 0x11); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + dev->name, buf, buf->vb.i, + (unsigned long)buf->risc.dma); + } + cx23885_restart_video_queue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +int cx23885_video_irq(struct cx23885_dev *dev, u32 status) +{ + u32 mask, count; + int handled = 0; + + mask = cx_read(VID_A_INT_MSK); + if (0 == (status & mask)) + return handled; + cx_write(VID_A_INT_STAT, status); + + dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status); + /* risc op code error */ + if (status & (1 << 16)) { + printk(KERN_WARNING "%s/0: video risc op code error\n", + dev->name); + cx_clear(VID_A_DMA_CTL, 0x11); + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + } + + /* risc1 y */ + if (status & 0x01) { + spin_lock(&dev->slock); + count = cx_read(VID_A_GPCNT); + cx23885_video_wakeup(dev, &dev->vidq, count); + spin_unlock(&dev->slock); + handled++; + } + /* risc2 y */ + if (status & 0x10) { + dprintk(2, "stopper video\n"); + spin_lock(&dev->slock); + cx23885_restart_video_queue(dev, &dev->vidq); + spin_unlock(&dev->slock); + handled++; + } + + return handled; +} + + +/* ----------------------------------------------------------- */ +/* exported stuff */ + +static const struct file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + +static struct video_device cx23885_vbi_template; +static struct video_device cx23885_video_template = { + .name = "cx23885-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_fmt_vbi = cx23885_vbi_fmt, + .vidioc_try_fmt_vbi = cx23885_vbi_fmt, + .vidioc_s_fmt_vbi = cx23885_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif + .tvnorms = CX23885_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +static const struct file_operations radio_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + + +void cx23885_video_unregister(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + cx_clear(PCI_INT_MSK, 1); + + if (dev->video_dev) { + if (-1 != dev->video_dev->minor) + video_unregister_device(dev->video_dev); + else + video_device_release(dev->video_dev); + dev->video_dev = NULL; + + btcx_riscmem_free(dev->pci, &dev->vidq.stopper); + } +} + +int cx23885_video_register(struct cx23885_dev *dev) +{ + int err; + + dprintk(1, "%s()\n", __FUNCTION__); + spin_lock_init(&dev->slock); + + /* Initialize VBI template */ + memcpy(&cx23885_vbi_template, &cx23885_video_template, + sizeof(cx23885_vbi_template)); + strcpy(cx23885_vbi_template.name, "cx23885-vbi"); + cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; + + dev->tvnorm = cx23885_video_template.current_norm; + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + dev->vidq.timeout.function = cx23885_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); + cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, + VID_A_DMA_CTL, 0x11, 0x00); + + cx_set(PCI_INT_MSK, 1); + + + /* register v4l devices */ + dev->video_dev = cx23885_vdev_init(dev, dev->pci, + &cx23885_video_template, "video"); + err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, + video_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail_unreg; + } + printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", + dev->name, dev->video_dev->minor & 0x1f); + /* initial device configuration */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, dev->tvnorm); + init_controls(dev); + cx23885_video_mux(dev, 0); + mutex_unlock(&dev->lock); + + /* FIXME start tvaudio thread */ + + return 0; + +fail_unreg: + cx23885_video_unregister(dev); + return err; +} + -- cgit v1.2.3 From 21a78091921915cd1afd0edb2940dd726edefe9b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 04:38:59 -0300 Subject: V4L/DVB (7010): cx23885: Small cleanup cx23885: Small cleanup Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 8eaebdb76b1..40d5e778aa2 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -288,7 +288,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); } if (bc != 1) - printk(KERN_WARN "%s: %d buffers handled (should be 1)\n", + printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); } -- cgit v1.2.3 From a19602f26a24c32e491108b49790b106a6351f24 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 10 Jan 2008 11:43:18 -0300 Subject: V4L/DVB (7011): cx23885: Cleanup of compiler defines and warnings Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-video.c | 128 +++------------------------- 1 file changed, 13 insertions(+), 115 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 40d5e778aa2..44c809474ba 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -270,11 +270,13 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, break; buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; + do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); @@ -301,7 +303,6 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) dev->tvnorm = norm; - /* Tell the analog tuner/demods */ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); @@ -455,20 +456,6 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, return 0; } -#ifdef CONFIG_PM -static int cx23885_stop_video_dma(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __FUNCTION__); - /* stop dma */ - cx_clear(VID_A_DMA_CTL, 0x11); - - /* disable irqs */ - cx_clear(PCI_INT_MSK, 0x000001); - cx_clear(VID_A_INT_MSK, 0x000011); - - return 0; -} -#endif static int cx23885_restart_video_queue(struct cx23885_dev *dev, struct cx23885_dmaqueue *q) @@ -877,6 +864,10 @@ static int video_release(struct inode *inode, struct file *file) file->private_data = NULL; kfree(fh); + /* We are not putting the tuner to sleep here on exit, because + * we want to use the mpeg encoder in another session to capture + * tuner video. Closing this will result in no video to the encoder. + */ return 0; } @@ -1337,6 +1328,9 @@ static int vidioc_g_register(struct file *file, void *fh, { struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg); return 0; @@ -1347,108 +1341,14 @@ static int vidioc_s_register(struct file *file, void *fh, { struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); - return 0; -} -#endif - -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - strcpy(cap->driver, "cx23885"); - strlcpy(cap->card, cx23885_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - if (unlikely(t->index > 0)) - return -EINVAL; - - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t); - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} - -/* FIXME: Should add a standard for radio */ - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - if (0 != t->index) + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_TUNER, t); - - return 0; -} - -static int radio_s_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *file, void *fh, unsigned int i) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - int i; + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - for (i = 0; i < CX23885_CTLS; i++) - if (cx23885_ctls[i].v.id == c->id) - break; - *c = cx23885_ctls[i].v; - } else - *c = no_ctl; return 0; } +#endif /* ----------------------------------------------------------- */ @@ -1517,7 +1417,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) return handled; } - /* ----------------------------------------------------------- */ /* exported stuff */ @@ -1625,6 +1524,7 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, VID_A_DMA_CTL, 0x11, 0x00); + /* Don't enable VBI yet */ cx_set(PCI_INT_MSK, 1); @@ -1647,8 +1547,6 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_video_mux(dev, 0); mutex_unlock(&dev->lock); - /* FIXME start tvaudio thread */ - return 0; fail_unreg: -- cgit v1.2.3 From d685a483b8c92e3d0580b6c28e2ed531391c8c46 Mon Sep 17 00:00:00 2001 From: "Brett T. Warden" Date: Thu, 10 Jan 2008 04:33:31 -0300 Subject: V4L/DVB (7013): bw-qcam: add module parameter 'force_init' to skip polite auto-detection prior to direct initialization Setting force_init=1 bypasses the friendly auto-detection by polling the status register, and instead attempts to initialize the qcam directly. Not friendly to other parallel devices, but much more reliable than the auto-detection. Signed-off-by: Brett T. Warden Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bw-qcam.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 58423525591..032265383df 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -82,11 +82,16 @@ OTHER DEALINGS IN THE SOFTWARE. static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ static unsigned int yieldlines=4; /* Yield after this many during capture */ static int video_nr = -1; +static unsigned int force_init; /* Whether to probe aggressively */ module_param(maxpoll, int, 0); module_param(yieldlines, int, 0); module_param(video_nr, int, 0); +/* Set force_init=1 to avoid detection by polling status register and + * immediately attempt to initialize qcam */ +module_param(force_init, int, 0); + static inline int read_lpstatus(struct qcam_device *q) { return parport_read_status(q->pport); @@ -331,6 +336,9 @@ static int qc_detect(struct qcam_device *q) int count = 0; int i; + if (force_init) + return 1; + lastreg = reg = read_lpstatus(q) & 0xf0; for (i = 0; i < 500; i++) @@ -354,12 +362,12 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ -/* if (count > 30 && count < 200) */ if (count > 20 && count < 400) { return 1; /* found */ } else { printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); + printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); return 0; /* not found */ } } -- cgit v1.2.3 From 4513fc696e273d64ea32f2366748aed810316ecc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 12 Jan 2008 11:36:36 -0300 Subject: V4L/DVB (7014): cx23885: dprintk macro cleanup Added missing do { } while (0) Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 8 +++++--- drivers/media/video/cx23885/cx23885-dvb.c | 8 +++++--- drivers/media/video/cx23885/cx23885-i2c.c | 8 ++++---- drivers/media/video/cx23885/cx23885-vbi.c | 8 +++++--- drivers/media/video/cx23885/cx23885-video.c | 9 +++++---- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index e1b06d79e9b..8e40c7bcc06 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth "); MODULE_LICENSE("GPL"); -static unsigned int debug = 0; +static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages"); @@ -44,8 +44,10 @@ static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card,"card type"); -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) static unsigned int cx23885_devcount; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 1b669ee962d..34910368049 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -40,10 +40,12 @@ #include "tuner-xc2028.h" #include "tuner-xc2028-types.h" -static unsigned int debug = 0; +static unsigned int debug; -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index fbc4a57a236..92fe0bd37c8 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -29,7 +29,7 @@ #include -static unsigned int i2c_debug = 0; +static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); @@ -37,9 +37,9 @@ static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); -#define dprintk(level, fmt, arg...) do { \ - if (i2c_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg); \ +#define dprintk(level, fmt, arg...)\ + do { if (i2c_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ } while (0) #define I2C_WAIT_DELAY 32 diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c index 32ec9d5bdbd..e36e3fcae2f 100644 --- a/drivers/media/video/cx23885/cx23885-vbi.c +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -31,12 +31,14 @@ static unsigned int vbibufs = 4; module_param(vbibufs, int, 0644); MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); -static unsigned int vbi_debug = 0; +static unsigned int vbi_debug; module_param(vbi_debug, int, 0644); MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); -#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) +#define dprintk(level, fmt, arg...)\ + do { if (vbi_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) /* ------------------------------------------------------------------ */ diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 44c809474ba..d3c4d2c5cbe 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -57,11 +57,11 @@ MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); MODULE_PARM_DESC(radio_nr, "radio device numbers"); -static unsigned int video_debug = 0; +static unsigned int video_debug; module_param(video_debug, int, 0644); MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); -static unsigned int irq_debug = 0; +static unsigned int irq_debug; module_param(irq_debug, int, 0644); MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); @@ -70,8 +70,9 @@ module_param(vid_limit, int, 0644); MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); #define dprintk(level, fmt, arg...)\ - if (video_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg) + do { if (video_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) /* ------------------------------------------------------------------- */ /* static data */ -- cgit v1.2.3 From a28cb828ef9ba6669be738dd9affbaba65cc07fb Mon Sep 17 00:00:00 2001 From: Hermann Pitton Date: Sat, 12 Jan 2008 14:31:03 -0300 Subject: V4L/DVB (7016): saa7134: remove the Avermedia Super 007 from eeprom detection saa7134: remove the Avermedia Super 007 from eeprom detection The card made it into the Philips' Tigers eeprom detection and falls through. Since it has attracted already others to follow, which are wrongly identified as TIGER_S then, move it to the usual analog initialization. Signed-off-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 0e3d2a73932..4a5a1459f02 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5197,7 +5197,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: - case SAA7134_BOARD_AVERMEDIA_SUPER_007: { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; @@ -5227,6 +5226,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ -- cgit v1.2.3 From b6667e5fb8c478e65768fdb18fa6576ac1634068 Mon Sep 17 00:00:00 2001 From: Hermann Pitton Date: Sat, 12 Jan 2008 14:43:48 -0300 Subject: V4L/DVB (7017): saa7134: add MSI TV@nywhere Plus with the older tda8275 tuner Thanks go to Mark Schultz for the initial contribution and to Dean Hilkewich for testing it again. Signed-off-by: Hermann Pitton Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index fe8514e06d2..5d3b6b4d251 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -80,7 +80,7 @@ 79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B) 80 -> ASUS Digimatrix TV [1043:0210] 81 -> Philips Tiger reference design [1131:2018] - 82 -> MSI TV@Anywhere plus [1462:6231] + 82 -> MSI TV@Anywhere plus [1462:6231,1462:8624] 83 -> Terratec Cinergy 250 PCI TV [153b:1160] 84 -> LifeView FlyDVB Trio [5168:0319] 85 -> AverTV DVB-T 777 [1461:2c05,1461:2c05] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 4a5a1459f02..7d7f383b404 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -4392,7 +4392,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1462, - .subdevice = 0x6231, + .subdevice = 0x6231, /* tda8275a, ks003 IR */ + .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1462, + .subdevice = 0x8624, /* tda8275, ks003 IR */ .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, -- cgit v1.2.3 From ec16dae5453eafd1586f35c4ec1ef854e5a808e0 Mon Sep 17 00:00:00 2001 From: Jaime Velasco Juan Date: Sat, 12 Jan 2008 06:48:14 -0300 Subject: V4L/DVB (7019): V4L: add support for Syntek DC1125 webcams This driver supports cameras with USB ID 174f:a311 or 05e1:0501, and the ov965x sensors. These devices are found in some Asus laptops and probably somewhere else. It is based on the stk11xx driver written by Nicolas Vivien Signed-off-by: Jaime Velasco Juan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 13 + drivers/media/video/Makefile | 3 + drivers/media/video/stk-sensor.c | 578 +++++++++++++++ drivers/media/video/stk-webcam.c | 1465 ++++++++++++++++++++++++++++++++++++++ drivers/media/video/stk-webcam.h | 138 ++++ 5 files changed, 2197 insertions(+) create mode 100644 drivers/media/video/stk-sensor.c create mode 100644 drivers/media/video/stk-webcam.c create mode 100644 drivers/media/video/stk-webcam.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 7431f6da5ca..a2e8987a619 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -821,6 +821,19 @@ config USB_ZR364XX To compile this driver as a module, choose M here: the module will be called zr364xx. +config USB_STKWEBCAM + tristate "USB Syntek DC1125 Camera support" + depends on VIDEO_V4L2 && EXPERIMENTAL + ---help--- + Say Y here if you want to use this type of camera. + Supported devices are typically found in some Asus laptops, + with USB id 174f:a311 and 05e1:0501. Other Syntek cameras + may be supported by the stk11xx driver, from which this is + derived, see http://stk11xx.sourceforge.net + + To compile this driver as a module, choose M here: the + module will be called stkwebcam. + endif # V4L_USB_DRIVERS endif # VIDEO_CAPTURE_DRIVERS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 74a2a1c45fe..28ddd146c1c 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -8,6 +8,8 @@ tuner-objs := tuner-core.o tuner-types.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o +stkwebcam-objs := stk-webcam.o stk-sensor.o + obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ v4l2-int-device.o @@ -116,6 +118,7 @@ obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o obj-$(CONFIG_USB_ZR364XX) += zr364xx.o +obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_USB_ET61X251) += et61x251/ diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c new file mode 100644 index 00000000000..4a9a0b62efa --- /dev/null +++ b/drivers/media/video/stk-sensor.c @@ -0,0 +1,578 @@ +/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams) + * + * Copyright 2007-2008 Jaime Velasco Juan + * + * Some parts derived from ov7670.c: + * Copyright 2006 One Laptop Per Child Association, Inc. Written + * by Jonathan Corbet with substantial inspiration from Mark + * McClelland's ovcamchip code. + * + * Copyright 2006-7 Jonathan Corbet + * + * This file may be distributed under the terms of the GNU General + * 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 + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Controlling the sensor via the STK1125 vendor specific control interface: + * The camera uses an OmniVision sensor and the stk1125 provides an + * SCCB(i2c)-USB bridge which let us program the sensor. + * In my case the sensor id is 0x9652, it can be read from sensor's register + * 0x0A and 0x0B as follows: + * - read register #R: + * output #R to index 0x0208 + * output 0x0070 to index 0x0200 + * input 1 byte from index 0x0201 (some kind of status register) + * until its value is 0x01 + * input 1 byte from index 0x0209. This is the value of #R + * - write value V to register #R + * output #R to index 0x0204 + * output V to index 0x0205 + * output 0x0005 to index 0x0200 + * input 1 byte from index 0x0201 until its value becomes 0x04 + */ + +/* It seems the i2c bus is controlled with these registers */ + +#include "stk-webcam.h" + +#define STK_IIC_BASE (0x0200) +# define STK_IIC_OP (STK_IIC_BASE) +# define STK_IIC_OP_TX (0x05) +# define STK_IIC_OP_RX (0x70) +# define STK_IIC_STAT (STK_IIC_BASE+1) +# define STK_IIC_STAT_TX_OK (0x04) +# define STK_IIC_STAT_RX_OK (0x01) +/* I don't know what does this register. + * when it is 0x00 or 0x01, we cannot talk to the sensor, + * other values work */ +# define STK_IIC_ENABLE (STK_IIC_BASE+2) +# define STK_IIC_ENABLE_NO (0x00) +/* This is what the driver writes in windows */ +# define STK_IIC_ENABLE_YES (0x1e) +/* + * Address of the slave. Seems like the binary driver look for the + * sensor in multiple places, attempting a reset sequence. + * We only know about the ov9650 + */ +# define STK_IIC_ADDR (STK_IIC_BASE+3) +# define STK_IIC_TX_INDEX (STK_IIC_BASE+4) +# define STK_IIC_TX_VALUE (STK_IIC_BASE+5) +# define STK_IIC_RX_INDEX (STK_IIC_BASE+8) +# define STK_IIC_RX_VALUE (STK_IIC_BASE+9) + +#define MAX_RETRIES (50) + +#define SENSOR_ADDRESS (0x60) + +/* From ov7670.c (These registers aren't fully accurate) */ + +/* Registers */ +#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ +#define REG_BLUE 0x01 /* blue gain */ +#define REG_RED 0x02 /* red gain */ +#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ +#define REG_COM1 0x04 /* Control 1 */ +#define COM1_CCIR656 0x40 /* CCIR656 enable */ +#define COM1_QFMT 0x20 /* QVGA/QCIF format */ +#define COM1_SKIP_0 0x00 /* Do not skip any row */ +#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */ +#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */ +#define REG_BAVE 0x05 /* U/B Average level */ +#define REG_GbAVE 0x06 /* Y/Gb Average level */ +#define REG_AECHH 0x07 /* AEC MS 5 bits */ +#define REG_RAVE 0x08 /* V/R Average level */ +#define REG_COM2 0x09 /* Control 2 */ +#define COM2_SSLEEP 0x10 /* Soft sleep mode */ +#define REG_PID 0x0a /* Product ID MSB */ +#define REG_VER 0x0b /* Product ID LSB */ +#define REG_COM3 0x0c /* Control 3 */ +#define COM3_SWAP 0x40 /* Byte swap */ +#define COM3_SCALEEN 0x08 /* Enable scaling */ +#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ +#define REG_COM4 0x0d /* Control 4 */ +#define REG_COM5 0x0e /* All "reserved" */ +#define REG_COM6 0x0f /* Control 6 */ +#define REG_AECH 0x10 /* More bits of AEC value */ +#define REG_CLKRC 0x11 /* Clock control */ +#define CLK_PLL 0x80 /* Enable internal PLL */ +#define CLK_EXT 0x40 /* Use external clock directly */ +#define CLK_SCALE 0x3f /* Mask for internal clock scale */ +#define REG_COM7 0x12 /* Control 7 */ +#define COM7_RESET 0x80 /* Register reset */ +#define COM7_FMT_MASK 0x38 +#define COM7_FMT_SXGA 0x00 +#define COM7_FMT_VGA 0x40 +#define COM7_FMT_CIF 0x20 /* CIF format */ +#define COM7_FMT_QVGA 0x10 /* QVGA format */ +#define COM7_FMT_QCIF 0x08 /* QCIF format */ +#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ +#define COM7_YUV 0x00 /* YUV */ +#define COM7_BAYER 0x01 /* Bayer format */ +#define COM7_PBAYER 0x05 /* "Processed bayer" */ +#define REG_COM8 0x13 /* Control 8 */ +#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ +#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ +#define COM8_BFILT 0x20 /* Band filter enable */ +#define COM8_AGC 0x04 /* Auto gain enable */ +#define COM8_AWB 0x02 /* White balance enable */ +#define COM8_AEC 0x01 /* Auto exposure enable */ +#define REG_COM9 0x14 /* Control 9 - gain ceiling */ +#define REG_COM10 0x15 /* Control 10 */ +#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ +#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ +#define COM10_HREF_REV 0x08 /* Reverse HREF */ +#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ +#define COM10_VS_NEG 0x02 /* VSYNC negative */ +#define COM10_HS_NEG 0x01 /* HSYNC negative */ +#define REG_HSTART 0x17 /* Horiz start high bits */ +#define REG_HSTOP 0x18 /* Horiz stop high bits */ +#define REG_VSTART 0x19 /* Vert start high bits */ +#define REG_VSTOP 0x1a /* Vert stop high bits */ +#define REG_PSHFT 0x1b /* Pixel delay after HREF */ +#define REG_MIDH 0x1c /* Manuf. ID high */ +#define REG_MIDL 0x1d /* Manuf. ID low */ +#define REG_MVFP 0x1e /* Mirror / vflip */ +#define MVFP_MIRROR 0x20 /* Mirror image */ +#define MVFP_FLIP 0x10 /* Vertical flip */ + +#define REG_AEW 0x24 /* AGC upper limit */ +#define REG_AEB 0x25 /* AGC lower limit */ +#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ +#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */ +#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */ +#define REG_HSYST 0x30 /* HSYNC rising edge delay */ +#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ +#define REG_HREF 0x32 /* HREF pieces */ +#define REG_TSLB 0x3a /* lots of stuff */ +#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ +#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */ +#define REG_COM11 0x3b /* Control 11 */ +#define COM11_NIGHT 0x80 /* NIght mode enable */ +#define COM11_NMFR 0x60 /* Two bit NM frame rate */ +#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ +#define COM11_50HZ 0x08 /* Manual 50Hz select */ +#define COM11_EXP 0x02 +#define REG_COM12 0x3c /* Control 12 */ +#define COM12_HREF 0x80 /* HREF always */ +#define REG_COM13 0x3d /* Control 13 */ +#define COM13_GAMMA 0x80 /* Gamma enable */ +#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ +#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */ +#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ +#define REG_COM14 0x3e /* Control 14 */ +#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ +#define REG_EDGE 0x3f /* Edge enhancement factor */ +#define REG_COM15 0x40 /* Control 15 */ +#define COM15_R10F0 0x00 /* Data range 10 to F0 */ +#define COM15_R01FE 0x80 /* 01 to FE */ +#define COM15_R00FF 0xc0 /* 00 to FF */ +#define COM15_RGB565 0x10 /* RGB565 output */ +#define COM15_RGBFIXME 0x20 /* FIXME */ +#define COM15_RGB555 0x30 /* RGB555 output */ +#define REG_COM16 0x41 /* Control 16 */ +#define COM16_AWBGAIN 0x08 /* AWB gain enable */ +#define REG_COM17 0x42 /* Control 17 */ +#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ +#define COM17_CBAR 0x08 /* DSP Color bar */ + +/* + * This matrix defines how the colors are generated, must be + * tweaked to adjust hue and saturation. + * + * Order: v-red, v-green, v-blue, u-red, u-green, u-blue + * + * They are nine-bit signed quantities, with the sign bit + * stored in 0x58. Sign for v-red is bit 0, and up from there. + */ +#define REG_CMATRIX_BASE 0x4f +#define CMATRIX_LEN 6 +#define REG_CMATRIX_SIGN 0x58 + + +#define REG_BRIGHT 0x55 /* Brightness */ +#define REG_CONTRAS 0x56 /* Contrast control */ + +#define REG_GFIX 0x69 /* Fix gain control */ + +#define REG_RGB444 0x8c /* RGB 444 control */ +#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ +#define R444_RGBX 0x01 /* Empty nibble at end */ + +#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ +#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ + +#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ +#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ +#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ +#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ +#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ +#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ +#define REG_BD60MAX 0xab /* 60hz banding step limit */ + + + + +/* Returns 0 if OK */ +int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) +{ + int i = 0; + int tmpval = 0; + + if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) + return 1; + if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val)) + return 1; + if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX)) + return 1; + do { + if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) + return 1; + i++; + } while (tmpval == 0 && i < MAX_RETRIES); + if (tmpval != STK_IIC_STAT_TX_OK) { + if (tmpval) + STK_ERROR("stk_sensor_outb failed, status=0x%02x\n", + tmpval); + return 1; + } else + return 0; +} + +int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) +{ + int i = 0; + int tmpval = 0; + + if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) + return 1; + if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX)) + return 1; + do { + if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) + return 1; + i++; + } while (tmpval == 0 && i < MAX_RETRIES); + if (tmpval != STK_IIC_STAT_RX_OK) { + if (tmpval) + STK_ERROR("stk_sensor_inb failed, status=0x%02x\n", + tmpval); + return 1; + } + + if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) + return 1; + + *val = (u8) tmpval; + return 0; +} + +static int stk_sensor_write_regvals(struct stk_camera *dev, + struct regval *rv) +{ + int ret; + if (rv == NULL) + return 0; + while (rv->reg != 0xff || rv->val != 0xff) { + ret = stk_sensor_outb(dev, rv->reg, rv->val); + if (ret != 0) + return ret; + rv++; + } + return 0; +} + +int stk_sensor_sleep(struct stk_camera *dev) +{ + u8 tmp; + return stk_sensor_inb(dev, REG_COM2, &tmp) + || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP); +} + +int stk_sensor_wakeup(struct stk_camera *dev) +{ + u8 tmp; + return stk_sensor_inb(dev, REG_COM2, &tmp) + || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP); +} + +static struct regval ov_initvals[] = { + {REG_CLKRC, CLK_PLL}, + {REG_COM11, 0x01}, + {0x6a, 0x7d}, + {REG_AECH, 0x40}, + {REG_GAIN, 0x00}, + {REG_BLUE, 0x80}, + {REG_RED, 0x80}, + /* Do not enable fast AEC for now */ + /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/ + {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC}, + {0x39, 0x50}, {0x38, 0x93}, + {0x37, 0x00}, {0x35, 0x81}, + {REG_COM5, 0x20}, + {REG_COM1, 0x00}, + {REG_COM3, 0x00}, + {REG_COM4, 0x00}, + {REG_PSHFT, 0x00}, + {0x16, 0x07}, + {0x33, 0xe2}, {0x34, 0xbf}, + {REG_COM16, 0x00}, + {0x96, 0x04}, + /* Gamma curve values */ +/* { 0x7a, 0x20 }, { 0x7b, 0x10 }, + { 0x7c, 0x1e }, { 0x7d, 0x35 }, + { 0x7e, 0x5a }, { 0x7f, 0x69 }, + { 0x80, 0x76 }, { 0x81, 0x80 }, + { 0x82, 0x88 }, { 0x83, 0x8f }, + { 0x84, 0x96 }, { 0x85, 0xa3 }, + { 0x86, 0xaf }, { 0x87, 0xc4 }, + { 0x88, 0xd7 }, { 0x89, 0xe8 }, +*/ + {REG_GFIX, 0x40}, + {0x8e, 0x00}, + {REG_COM12, 0x73}, + {0x8f, 0xdf}, {0x8b, 0x06}, + {0x8c, 0x20}, + {0x94, 0x88}, {0x95, 0x88}, +/* {REG_COM15, 0xc1}, TODO */ + {0x29, 0x3f}, + {REG_COM6, 0x42}, + {REG_BD50MAX, 0x80}, + {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92}, + {REG_BD60MAX, 0x0a}, + {0x90, 0x00}, {0x91, 0x00}, + {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00}, + {REG_AEW, 0x68}, {REG_AEB, 0x5c}, + {REG_VPT, 0xc3}, + {REG_COM9, 0x2e}, + {0x2a, 0x00}, {0x2b, 0x00}, + + {0xff, 0xff}, /* END MARKER */ +}; + +/* Probe the I2C bus and initialise the sensor chip */ +int stk_sensor_init(struct stk_camera *dev) +{ + u8 idl = 0; + u8 idh = 0; + + if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES) + || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS) + || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) { + STK_ERROR("Sensor resetting failed\n"); + return -ENODEV; + } + msleep(10); + /* Read the manufacturer ID: ov = 0x7FA2 */ + if (stk_sensor_inb(dev, REG_MIDH, &idh) + || stk_sensor_inb(dev, REG_MIDL, &idl)) { + STK_ERROR("Strange error reading sensor ID\n"); + return -ENODEV; + } + if (idh != 0x7F || idl != 0xA2) { + STK_ERROR("Huh? you don't have a sensor from ovt\n"); + return -ENODEV; + } + if (stk_sensor_inb(dev, REG_PID, &idh) + || stk_sensor_inb(dev, REG_VER, &idl)) { + STK_ERROR("Could not read sensor model\n"); + return -ENODEV; + } + stk_sensor_write_regvals(dev, ov_initvals); + msleep(10); + STK_INFO("OmniVision sensor detected, id %02X%02X" + " at address %x\n", idh, idl, SENSOR_ADDRESS); + return 0; +} + +/* V4L2_PIX_FMT_UYVY */ +static struct regval ov_fmt_uyvy[] = { + {REG_TSLB, TSLB_YLAST|0x08 }, + { 0x4f, 0x80 }, /* "matrix coefficient 1" */ + { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x22 }, /* "matrix coefficient 4" */ + { 0x53, 0x5e }, /* "matrix coefficient 5" */ + { 0x54, 0x80 }, /* "matrix coefficient 6" */ + {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, + {REG_COM15, COM15_R00FF }, + {0xff, 0xff}, /* END MARKER */ +}; + +/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */ +static struct regval ov_fmt_rgbr[] = { + { REG_RGB444, 0 }, /* No RGB444 please */ + {REG_TSLB, 0x00}, + { REG_COM1, 0x0 }, + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { REG_COM13, COM13_GAMMA }, + { REG_COM15, COM15_RGB565|COM15_R00FF }, + { 0xff, 0xff }, +}; + +/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */ +static struct regval ov_fmt_rgbp[] = { + { REG_RGB444, 0 }, /* No RGB444 please */ + {REG_TSLB, TSLB_BYTEORD }, + { REG_COM1, 0x0 }, + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { REG_COM13, COM13_GAMMA }, + { REG_COM15, COM15_RGB565|COM15_R00FF }, + { 0xff, 0xff }, +}; + +/* V4L2_PIX_FMT_SRGGB8 */ +static struct regval ov_fmt_bayer[] = { + /* This changes color order */ + {REG_TSLB, 0x40}, /* BGGR */ + /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */ + {REG_COM15, COM15_R00FF }, + {0xff, 0xff}, /* END MARKER */ +}; +/* + * Store a set of start/stop values into the camera. + */ +static int stk_sensor_set_hw(struct stk_camera *dev, + int hstart, int hstop, int vstart, int vstop) +{ + int ret; + unsigned char v; +/* + * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of + * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is + * a mystery "edge offset" value in the top two bits of href. + */ + ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff); + ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff); + ret += stk_sensor_inb(dev, REG_HREF, &v); + v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); + msleep(10); + ret += stk_sensor_outb(dev, REG_HREF, v); +/* + * Vertical: similar arrangement (note: this is different from ov7670.c) + */ + ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff); + ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff); + ret += stk_sensor_inb(dev, REG_VREF, &v); + v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7); + msleep(10); + ret += stk_sensor_outb(dev, REG_VREF, v); + return ret; +} + + +int stk_sensor_configure(struct stk_camera *dev) +{ + int com7; + /* + * We setup the sensor to output dummy lines in low-res modes, + * so we don't get absurdly hight framerates. + */ + unsigned dummylines; + int flip; + struct regval *rv; + + switch (dev->vsettings.mode) { + case MODE_QCIF: com7 = COM7_FMT_QCIF; + dummylines = 604; + break; + case MODE_QVGA: com7 = COM7_FMT_QVGA; + dummylines = 267; + break; + case MODE_CIF: com7 = COM7_FMT_CIF; + dummylines = 412; + break; + case MODE_VGA: com7 = COM7_FMT_VGA; + dummylines = 11; + break; + case MODE_SXGA: com7 = COM7_FMT_SXGA; + dummylines = 0; + break; + default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode); + return -EFAULT; + } + switch (dev->vsettings.palette) { + case V4L2_PIX_FMT_UYVY: + com7 |= COM7_YUV; + rv = ov_fmt_uyvy; + break; + case V4L2_PIX_FMT_RGB565: + com7 |= COM7_RGB; + rv = ov_fmt_rgbp; + break; + case V4L2_PIX_FMT_RGB565X: + com7 |= COM7_RGB; + rv = ov_fmt_rgbr; + break; + case V4L2_PIX_FMT_SBGGR8: + com7 |= COM7_PBAYER; + rv = ov_fmt_bayer; + break; + default: STK_ERROR("Unsupported colorspace\n"); + return -EFAULT; + } + /*FIXME sometimes the sensor go to a bad state + stk_sensor_write_regvals(dev, ov_initvals); */ + stk_sensor_outb(dev, REG_COM7, com7); + msleep(50); + stk_sensor_write_regvals(dev, rv); + flip = (dev->vsettings.vflip?MVFP_FLIP:0) + | (dev->vsettings.hflip?MVFP_MIRROR:0); + stk_sensor_outb(dev, REG_MVFP, flip); + if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8 + && !dev->vsettings.vflip) + stk_sensor_outb(dev, REG_TSLB, 0x08); + stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8); + stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff); + msleep(50); + switch (dev->vsettings.mode) { + case MODE_VGA: + if (stk_sensor_set_hw(dev, 302, 1582, 6, 486)) + STK_ERROR("stk_sensor_set_hw failed (VGA)\n"); + break; + case MODE_SXGA: + case MODE_CIF: + case MODE_QVGA: + case MODE_QCIF: + /*FIXME These settings seem ignored by the sensor + if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034)) + STK_ERROR("stk_sensor_set_hw failed (SXGA)\n"); + */ + break; + } + msleep(10); + return 0; +} + +int stk_sensor_set_brightness(struct stk_camera *dev, int br) +{ + if (br < 0 || br > 0xff) + return -EINVAL; + stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6)); + stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6)); + return 0; +} + diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c new file mode 100644 index 00000000000..f300eca3c47 --- /dev/null +++ b/drivers/media/video/stk-webcam.c @@ -0,0 +1,1465 @@ +/* + * stk-webcam.c : Driver for Syntek 1125 USB webcam controller + * + * Copyright (C) 2006 Nicolas VIVIEN + * Copyright 2007-2008 Jaime Velasco Juan + * + * Some parts are inspired from cafe_ccic.c + * Copyright 2006-2007 Jonathan Corbet + * + * 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 + * any later version. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "stk-webcam.h" + + +static int hflip = 1; +module_param(hflip, bool, 0444); +MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1"); + +static int vflip = 1; +module_param(vflip, bool, 0444); +MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1"); + +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jaime Velasco Juan and Nicolas VIVIEN"); +MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); + + + +/* Some cameras have audio interfaces, we aren't interested in those */ +static struct usb_device_id stkwebcam_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) }, + { } +}; +MODULE_DEVICE_TABLE(usb, stkwebcam_table); + +void stk_camera_cleanup(struct kref *kref) +{ + struct stk_camera *dev = to_stk_camera(kref); + + STK_INFO("Syntek USB2.0 Camera release resources" + " video device /dev/video%d\n", dev->vdev.minor); + video_unregister_device(&dev->vdev); + dev->vdev.priv = NULL; + + if (dev->sio_bufs != NULL || dev->isobufs != NULL) + STK_ERROR("We are leaking memory\n"); + usb_put_intf(dev->interface); + kfree(dev); +} + + +/* + * Basic stuff + */ +int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) +{ + struct usb_device *udev = dev->udev; + int ret; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + 500); + if (ret < 0) + return ret; + else + return 0; +} + +int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) +{ + struct usb_device *udev = dev->udev; + int ret; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, + index, + (u8 *) value, + sizeof(u8), + 500); + if (ret < 0) + return ret; + else + return 0; +} + +static int stk_start_stream(struct stk_camera *dev) +{ + int value; + int i, ret; + int value_116, value_117; + + if (!is_present(dev)) + return -ENODEV; + if (!is_memallocd(dev) || !is_initialised(dev)) { + STK_ERROR("FIXME: Buffers are not allocated\n"); + return -EFAULT; + } + ret = usb_set_interface(dev->udev, 0, 5); + + if (ret < 0) + STK_ERROR("usb_set_interface failed !\n"); + if (stk_sensor_wakeup(dev)) + STK_ERROR("error awaking the sensor\n"); + + stk_camera_read_reg(dev, 0x0116, &value_116); + stk_camera_read_reg(dev, 0x0117, &value_117); + + stk_camera_write_reg(dev, 0x0116, 0x0000); + stk_camera_write_reg(dev, 0x0117, 0x0000); + + stk_camera_read_reg(dev, 0x0100, &value); + stk_camera_write_reg(dev, 0x0100, value | 0x80); + + stk_camera_write_reg(dev, 0x0116, value_116); + stk_camera_write_reg(dev, 0x0117, value_117); + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (dev->isobufs[i].urb) { + ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL); + atomic_inc(&dev->urbs_used); + if (ret) + return ret; + } + } + set_streaming(dev); + return 0; +} + +static int stk_stop_stream(struct stk_camera *dev) +{ + int value; + int i; + if (is_present(dev)) { + stk_camera_read_reg(dev, 0x0100, &value); + stk_camera_write_reg(dev, 0x0100, value & ~0x80); + if (dev->isobufs != NULL) { + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (dev->isobufs[i].urb) + usb_kill_urb(dev->isobufs[i].urb); + } + } + unset_streaming(dev); + + if (usb_set_interface(dev->udev, 0, 0)) + STK_ERROR("usb_set_interface failed !\n"); + if (stk_sensor_sleep(dev)) + STK_ERROR("error suspending the sensor\n"); + } + return 0; +} + +/* + * This seems to be the shortest init sequence we + * must do in order to find the sensor + * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor + * is also reset. Maybe powers down it? + * Rest of values don't make a difference + */ + +static struct regval stk1125_initvals[] = { + /*TODO: What means this sequence? */ + {0x0000, 0x24}, + {0x0100, 0x21}, + {0x0002, 0x68}, + {0x0003, 0x80}, + {0x0005, 0x00}, + {0x0007, 0x03}, + {0x000d, 0x00}, + {0x000f, 0x02}, + {0x0300, 0x12}, + {0x0350, 0x41}, + {0x0351, 0x00}, + {0x0352, 0x00}, + {0x0353, 0x00}, + {0x0018, 0x10}, + {0x0019, 0x00}, + {0x001b, 0x0e}, + {0x001c, 0x46}, + {0x0300, 0x80}, + {0x001a, 0x04}, + {0x0110, 0x00}, + {0x0111, 0x00}, + {0x0112, 0x00}, + {0x0113, 0x00}, + + {0xffff, 0xff}, +}; + + +static int stk_initialise(struct stk_camera *dev) +{ + struct regval *rv; + int ret; + if (!is_present(dev)) + return -ENODEV; + if (is_initialised(dev)) + return 0; + rv = stk1125_initvals; + while (rv->reg != 0xffff) { + ret = stk_camera_write_reg(dev, rv->reg, rv->val); + if (ret) + return ret; + rv++; + } + if (stk_sensor_init(dev) == 0) { + set_initialised(dev); + return 0; + } else + return -1; +} + +/* sysfs functions */ +/*FIXME cleanup this */ + +static ssize_t show_brightness(struct device *class, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + return sprintf(buf, "%X\n", dev->vsettings.brightness); +} + +static ssize_t store_brightness(struct device *class, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *endp; + unsigned long value; + int ret; + + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + value = simple_strtoul(buf, &endp, 16); + + dev->vsettings.brightness = (int) value; + + ret = stk_sensor_set_brightness(dev, value >> 8); + if (ret) + return ret; + else + return count; +} + +static ssize_t show_hflip(struct device *class, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + return sprintf(buf, "%d\n", dev->vsettings.hflip); +} + +static ssize_t store_hflip(struct device *class, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + if (strncmp(buf, "1", 1) == 0) + dev->vsettings.hflip = 1; + else if (strncmp(buf, "0", 1) == 0) + dev->vsettings.hflip = 0; + else + return -EINVAL; + + return strlen(buf); +} + +static ssize_t show_vflip(struct device *class, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + return sprintf(buf, "%d\n", dev->vsettings.vflip); +} + +static ssize_t store_vflip(struct device *class, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + if (strncmp(buf, "1", 1) == 0) + dev->vsettings.vflip = 1; + else if (strncmp(buf, "0", 1) == 0) + dev->vsettings.vflip = 0; + else + return -EINVAL; + + return strlen(buf); +} + +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO, + show_brightness, store_brightness); +static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip); +static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip); + +static int stk_create_sysfs_files(struct video_device *vdev) +{ + int ret; + + ret = video_device_create_file(vdev, &dev_attr_brightness); + ret += video_device_create_file(vdev, &dev_attr_hflip); + ret += video_device_create_file(vdev, &dev_attr_vflip); + return ret; +} + +static void stk_remove_sysfs_files(struct video_device *vdev) +{ + video_device_remove_file(vdev, &dev_attr_brightness); + video_device_remove_file(vdev, &dev_attr_hflip); + video_device_remove_file(vdev, &dev_attr_vflip); +} + + +/* *********************************************** */ +/* + * This function is called as an URB transfert is complete (Isochronous pipe). + * So, the traitement is done in interrupt time, so it has be fast, not crash, + * and not stall. Neat. + */ +static void stk_isoc_handler(struct urb *urb) +{ + int i; + int ret; + int framelen; + unsigned long flags; + + unsigned char *fill = NULL; + unsigned char *iso_buf = NULL; + + struct stk_camera *dev; + struct stk_sio_buffer *fb; + + dev = (struct stk_camera *) urb->context; + + if (dev == NULL) { + STK_ERROR("isoc_handler called with NULL device !\n"); + return; + } + + if (urb->status == -ENOENT || urb->status == -ECONNRESET + || urb->status == -ESHUTDOWN) { + atomic_dec(&dev->urbs_used); + return; + } + + spin_lock_irqsave(&dev->spinlock, flags); + + if (urb->status != -EINPROGRESS && urb->status != 0) { + STK_ERROR("isoc_handler: urb->status == %d\n", urb->status); + goto resubmit; + } + + if (list_empty(&dev->sio_avail)) { + /*FIXME Stop streaming after a while */ + (void) (printk_ratelimit() && + STK_ERROR("isoc_handler without available buffer!\n")); + goto resubmit; + } + fb = list_first_entry(&dev->sio_avail, + struct stk_sio_buffer, list); + fill = fb->buffer + fb->v4lbuf.bytesused; + + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status != 0) { + if (urb->iso_frame_desc[i].status != -EXDEV) + STK_ERROR("Frame %d has error %d\n", i, + urb->iso_frame_desc[i].status); + continue; + } + framelen = urb->iso_frame_desc[i].actual_length; + iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (framelen <= 4) + continue; /* no data */ + + /* + * we found something informational from there + * the isoc frames have to type of headers + * type1: 00 xx 00 00 or 20 xx 00 00 + * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00 + * xx is a sequencer which has never been seen over 0x3f + * imho data written down looks like bayer, i see similarities + * after every 640 bytes + */ + if (*iso_buf & 0x80) { + framelen -= 8; + iso_buf += 8; + /* This marks a new frame */ + if (fb->v4lbuf.bytesused != 0 + && fb->v4lbuf.bytesused != dev->frame_size) { + (void) (printk_ratelimit() && + STK_ERROR("frame %d, " + "bytesused=%d, skipping\n", + i, fb->v4lbuf.bytesused)); + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; + } else if (fb->v4lbuf.bytesused == dev->frame_size) { + list_move_tail(dev->sio_avail.next, + &dev->sio_full); + wake_up(&dev->wait_frame); + if (list_empty(&dev->sio_avail)) { + (void) (printk_ratelimit() && + STK_ERROR("No buffer available\n")); + goto resubmit; + } + fb = list_first_entry(&dev->sio_avail, + struct stk_sio_buffer, list); + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; + } + } else { + framelen -= 4; + iso_buf += 4; + } + + /* Our buffer is full !!! */ + if (framelen + fb->v4lbuf.bytesused > dev->frame_size) { + (void) (printk_ratelimit() && + STK_ERROR("Frame buffer overflow, lost sync\n")); + /*FIXME Do something here? */ + continue; + } + spin_unlock_irqrestore(&dev->spinlock, flags); + memcpy(fill, iso_buf, framelen); + spin_lock_irqsave(&dev->spinlock, flags); + fill += framelen; + + /* New size of our buffer */ + fb->v4lbuf.bytesused += framelen; + } + +resubmit: + spin_unlock_irqrestore(&dev->spinlock, flags); + urb->dev = dev->udev; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret != 0) { + STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n", + ret); + } +} + +/* -------------------------------------------- */ + +static int stk_prepare_iso(struct stk_camera *dev) +{ + void *kbuf; + int i, j; + struct urb *urb; + struct usb_device *udev; + + if (dev == NULL) + return -ENXIO; + udev = dev->udev; + + if (dev->isobufs) + STK_ERROR("isobufs already allocated. Bad\n"); + else + dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs), + GFP_KERNEL); + if (dev->isobufs == NULL) { + STK_ERROR("Unable to allocate iso buffers\n"); + return -ENOMEM; + } + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (dev->isobufs[i].data == NULL) { + kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); + if (kbuf == NULL) { + STK_ERROR("Failed to allocate iso buffer %d\n", + i); + goto isobufs_out; + } + dev->isobufs[i].data = kbuf; + } else + STK_ERROR("isobuf data already allocated\n"); + if (dev->isobufs[i].urb == NULL) { + urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); + if (urb == NULL) { + STK_ERROR("Failed to allocate URB %d\n", i); + goto isobufs_out; + } + dev->isobufs[i].urb = urb; + } else { + STK_ERROR("Killing URB\n"); + usb_kill_urb(dev->isobufs[i].urb); + urb = dev->isobufs[i].urb; + } + urb->interval = 1; + urb->dev = udev; + urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->isobufs[i].data; + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = stk_isoc_handler; + urb->context = dev; + urb->start_frame = 0; + urb->number_of_packets = ISO_FRAMES_PER_DESC; + + for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; + } + } + set_memallocd(dev); + return 0; + +isobufs_out: + for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++) + kfree(dev->isobufs[i].data); + for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++) + usb_free_urb(dev->isobufs[i].urb); + kfree(dev->isobufs); + dev->isobufs = NULL; + return -ENOMEM; +} + +static void stk_clean_iso(struct stk_camera *dev) +{ + int i; + + if (dev == NULL || dev->isobufs == NULL) + return; + + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = dev->isobufs[i].urb; + if (urb) { + if (atomic_read(&dev->urbs_used)) + usb_kill_urb(urb); + usb_free_urb(urb); + } + kfree(dev->isobufs[i].data); + } + kfree(dev->isobufs); + dev->isobufs = NULL; + unset_memallocd(dev); +} + +static int stk_setup_siobuf(struct stk_camera *dev, int index) +{ + struct stk_sio_buffer *buf = dev->sio_bufs + index; + INIT_LIST_HEAD(&buf->list); + buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size); + buf->buffer = vmalloc_user(buf->v4lbuf.length); + if (buf->buffer == NULL) + return -ENOMEM; + buf->mapcount = 0; + buf->dev = dev; + buf->v4lbuf.index = index; + buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf->v4lbuf.field = V4L2_FIELD_NONE; + buf->v4lbuf.memory = V4L2_MEMORY_MMAP; + buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; + return 0; +} + +static int stk_free_sio_buffers(struct stk_camera *dev) +{ + int i; + int nbufs; + unsigned long flags; + if (dev->n_sbufs == 0 || dev->sio_bufs == NULL) + return 0; + /* + * If any buffers are mapped, we cannot free them at all. + */ + for (i = 0; i < dev->n_sbufs; i++) { + if (dev->sio_bufs[i].mapcount > 0) + return -EBUSY; + } + /* + * OK, let's do it. + */ + spin_lock_irqsave(&dev->spinlock, flags); + INIT_LIST_HEAD(&dev->sio_avail); + INIT_LIST_HEAD(&dev->sio_full); + nbufs = dev->n_sbufs; + dev->n_sbufs = 0; + spin_unlock_irqrestore(&dev->spinlock, flags); + for (i = 0; i < nbufs; i++) { + if (dev->sio_bufs[i].buffer != NULL) + vfree(dev->sio_bufs[i].buffer); + } + kfree(dev->sio_bufs); + dev->sio_bufs = NULL; + return 0; +} + +static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) +{ + int i; + if (dev->sio_bufs != NULL) + STK_ERROR("sio_bufs already allocated\n"); + else { + dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer), + GFP_KERNEL); + if (dev->sio_bufs == NULL) + return -ENOMEM; + for (i = 0; i < n_sbufs; i++) { + if (stk_setup_siobuf(dev, i)) + return (dev->n_sbufs > 1)? 0 : -ENOMEM; + dev->n_sbufs = i+1; + } + } + return 0; +} + +static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs) +{ + int err; + err = stk_prepare_iso(dev); + if (err) { + stk_clean_iso(dev); + return err; + } + err = stk_prepare_sio_buffers(dev, n_sbufs); + if (err) { + stk_free_sio_buffers(dev); + return err; + } + return 0; +} + +static void stk_free_buffers(struct stk_camera *dev) +{ + stk_clean_iso(dev); + stk_free_sio_buffers(dev); +} +/* -------------------------------------------- */ + +/* v4l file operations */ + +static int v4l_stk_open(struct inode *inode, struct file *fp) +{ + struct stk_camera *dev; + struct video_device *vdev; + + vdev = video_devdata(fp); + dev = vdev_to_camera(vdev); + + if (dev == NULL || !is_present(dev)) + return -ENXIO; + fp->private_data = vdev; + kref_get(&dev->kref); + + return 0; +} + +static int v4l_stk_release(struct inode *inode, struct file *fp) +{ + struct stk_camera *dev; + struct video_device *vdev; + + vdev = video_devdata(fp); + if (vdev == NULL) { + STK_ERROR("v4l_release called w/o video devdata\n"); + return -EFAULT; + } + dev = vdev_to_camera(vdev); + if (dev == NULL) { + STK_ERROR("v4l_release called on removed device\n"); + return -ENODEV; + } + + if (dev->owner != fp) { + kref_put(&dev->kref, stk_camera_cleanup); + return 0; + } + + stk_stop_stream(dev); + + stk_free_buffers(dev); + + dev->owner = NULL; + + kref_put(&dev->kref, stk_camera_cleanup); + + return 0; +} + +static ssize_t v4l_stk_read(struct file *fp, char __user *buf, + size_t count, loff_t *f_pos) +{ + int i; + int ret; + unsigned long flags; + struct stk_camera *dev; + struct video_device *vdev; + struct stk_sio_buffer *sbuf; + + vdev = video_devdata(fp); + if (vdev == NULL) + return -EFAULT; + dev = vdev_to_camera(vdev); + + if (dev == NULL) + return -EIO; + + if (!is_present(dev)) + return -EIO; + if (dev->owner && dev->owner != fp) + return -EBUSY; + dev->owner = fp; + if (!is_streaming(dev)) { + if (stk_initialise(dev) + || stk_allocate_buffers(dev, 3) + || stk_start_stream(dev)) + return -ENOMEM; + spin_lock_irqsave(&dev->spinlock, flags); + for (i = 0; i < dev->n_sbufs; i++) { + list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); + dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED; + } + spin_unlock_irqrestore(&dev->spinlock, flags); + } + if (*f_pos == 0) { + if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) + return -EWOULDBLOCK; + ret = wait_event_interruptible(dev->wait_frame, + !list_empty(&dev->sio_full) || !is_present(dev)); + if (ret) + return ret; + if (!is_present(dev)) + return -EIO; + } + if (count + *f_pos > dev->frame_size) + count = dev->frame_size - *f_pos; + spin_lock_irqsave(&dev->spinlock, flags); + if (list_empty(&dev->sio_full)) { + spin_unlock_irqrestore(&dev->spinlock, flags); + STK_ERROR("BUG: No siobufs ready\n"); + return 0; + } + sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); + spin_unlock_irqrestore(&dev->spinlock, flags); + + if (copy_to_user(buf, sbuf->buffer + *f_pos, count)) + return -EFAULT; + + *f_pos += count; + + if (*f_pos >= dev->frame_size) { + *f_pos = 0; + spin_lock_irqsave(&dev->spinlock, flags); + list_move_tail(&sbuf->list, &dev->sio_avail); + spin_unlock_irqrestore(&dev->spinlock, flags); + } + return count; +} + +static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) +{ + struct stk_camera *dev; + struct video_device *vdev; + + vdev = video_devdata(fp); + + if (vdev == NULL) + return -EFAULT; + + dev = vdev_to_camera(vdev); + if (dev == NULL) + return -ENODEV; + + poll_wait(fp, &dev->wait_frame, wait); + + if (!is_present(dev)) + return POLLERR; + + if (!list_empty(&dev->sio_full)) + return (POLLIN | POLLRDNORM); + + return 0; +} + + +static void stk_v4l_vm_open(struct vm_area_struct *vma) +{ + struct stk_sio_buffer *sbuf = vma->vm_private_data; + sbuf->mapcount++; +} +static void stk_v4l_vm_close(struct vm_area_struct *vma) +{ + struct stk_sio_buffer *sbuf = vma->vm_private_data; + sbuf->mapcount--; + if (sbuf->mapcount == 0) + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; +} +static struct vm_operations_struct stk_v4l_vm_ops = { + .open = stk_v4l_vm_open, + .close = stk_v4l_vm_close +}; + +static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) +{ + unsigned int i; + int ret; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + struct stk_camera *dev; + struct video_device *vdev; + struct stk_sio_buffer *sbuf = NULL; + + if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vdev = video_devdata(fp); + dev = vdev_to_camera(vdev); + + for (i = 0; i < dev->n_sbufs; i++) { + if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { + sbuf = dev->sio_bufs + i; + break; + } + } + if (sbuf == NULL) + return -EINVAL; + ret = remap_vmalloc_range(vma, sbuf->buffer, 0); + if (ret) + return ret; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = sbuf; + vma->vm_ops = &stk_v4l_vm_ops; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; + stk_v4l_vm_open(vma); + return 0; +} + +/* v4l ioctl handlers */ + +static int stk_vidioc_querycap(struct file *filp, + void *priv, struct v4l2_capability *cap) +{ + strcpy(cap->driver, "stk"); + strcpy(cap->card, "stk"); + cap->version = DRIVER_VERSION_NUM; + + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + return 0; +} + +static int stk_vidioc_enum_input(struct file *filp, + void *priv, struct v4l2_input *input) +{ + if (input->index != 0) + return -EINVAL; + + strcpy(input->name, "Syntek USB Camera"); + input->type = V4L2_INPUT_TYPE_CAMERA; + return 0; +} + + +static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + else + return 0; +} + +/* from vivi.c */ +static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) +{ + return 0; +} + +/* List of all V4Lv2 controls supported by the driver */ +static struct v4l2_queryctrl stk_controls[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xffff, + .step = 0x0100, + .default_value = 0x6000, + }, + /*TODO: get more controls to work */ +}; + +static int stk_vidioc_queryctrl(struct file *filp, + void *priv, struct v4l2_queryctrl *c) +{ + int i; + int nbr; + nbr = ARRAY_SIZE(stk_controls); + + for (i = 0; i < nbr; i++) { + if (stk_controls[i].id == c->id) { + memcpy(c, &stk_controls[i], + sizeof(struct v4l2_queryctrl)); + return 0; + } + } + return -EINVAL; +} + +static int stk_vidioc_g_ctrl(struct file *filp, + void *priv, struct v4l2_control *c) +{ + struct stk_camera *dev = priv; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = dev->vsettings.brightness; + break; + default: + return -EINVAL; + } + return 0; +} + +static int stk_vidioc_s_ctrl(struct file *filp, + void *priv, struct v4l2_control *c) +{ + struct stk_camera *dev = priv; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + dev->vsettings.brightness = c->value; + return stk_sensor_set_brightness(dev, c->value >> 8); + default: + return -EINVAL; + } + return 0; +} + + +static int stk_vidioc_enum_fmt_cap(struct file *filp, + void *priv, struct v4l2_fmtdesc *fmtd) +{ + fmtd->flags = 0; + + switch (fmtd->index) { + case 0: + fmtd->pixelformat = V4L2_PIX_FMT_RGB565; + strcpy(fmtd->description, "r5g6b5"); + break; + case 1: + fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; + strcpy(fmtd->description, "r5g6b5BE"); + break; + case 2: + fmtd->pixelformat = V4L2_PIX_FMT_UYVY; + strcpy(fmtd->description, "yuv4:2:2"); + break; + case 3: + fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; + strcpy(fmtd->description, "Raw bayer"); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct stk_size { + unsigned w; + unsigned h; + enum stk_mode m; +} stk_sizes[] = { + { .w = 1280, .h = 1024, .m = MODE_SXGA, }, + { .w = 640, .h = 480, .m = MODE_VGA, }, + { .w = 352, .h = 288, .m = MODE_CIF, }, + { .w = 320, .h = 240, .m = MODE_QVGA, }, + { .w = 176, .h = 144, .m = MODE_QCIF, }, +}; + +static int stk_vidioc_g_fmt_cap(struct file *filp, + void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix_format = &f->fmt.pix; + struct stk_camera *dev = priv; + int i; + + for (i = 0; i < ARRAY_SIZE(stk_sizes) + && stk_sizes[i].m != dev->vsettings.mode; + i++); + if (i == ARRAY_SIZE(stk_sizes)) { + STK_ERROR("ERROR: mode invalid\n"); + return -EINVAL; + } + pix_format->width = stk_sizes[i].w; + pix_format->height = stk_sizes[i].h; + pix_format->field = V4L2_FIELD_NONE; + pix_format->colorspace = V4L2_COLORSPACE_SRGB; + pix_format->priv = 0; + pix_format->pixelformat = dev->vsettings.palette; + if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) + pix_format->bytesperline = pix_format->width; + else + pix_format->bytesperline = 2 * pix_format->width; + pix_format->sizeimage = pix_format->bytesperline + * pix_format->height; + return 0; +} + +static int stk_vidioc_try_fmt_cap(struct file *filp, + void *priv, struct v4l2_format *fmtd) +{ + int i; + switch (fmtd->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_SBGGR8: + break; + default: + return -EINVAL; + } + for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) { + if (fmtd->fmt.pix.width > stk_sizes[i].w) + break; + } + if (i == ARRAY_SIZE(stk_sizes) + || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w) + < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { + fmtd->fmt.pix.height = stk_sizes[i-1].h; + fmtd->fmt.pix.width = stk_sizes[i-1].w; + fmtd->fmt.pix.priv = i - 1; + } else { + fmtd->fmt.pix.height = stk_sizes[i].h; + fmtd->fmt.pix.width = stk_sizes[i].w; + fmtd->fmt.pix.priv = i; + } + + fmtd->fmt.pix.field = V4L2_FIELD_NONE; + fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) + fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width; + else + fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; + fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline + * fmtd->fmt.pix.height; + return 0; +} + +static int stk_vidioc_s_fmt_cap(struct file *filp, + void *priv, struct v4l2_format *fmtd) +{ + int ret; + struct stk_camera *dev = priv; + + if (dev == NULL) + return -ENODEV; + if (!is_present(dev)) + return -ENODEV; + if (is_streaming(dev)) + return -EBUSY; + if (dev->owner && dev->owner != filp) + return -EBUSY; + dev->owner = filp; + ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd); + if (ret) + return ret; + + dev->vsettings.palette = fmtd->fmt.pix.pixelformat; + stk_free_buffers(dev); + dev->frame_size = fmtd->fmt.pix.sizeimage; + dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; + + stk_initialise(dev); + /* This registers controls some timings, not sure of what. */ + stk_camera_write_reg(dev, 0x001b, 0x0e); + if (dev->vsettings.mode == MODE_SXGA) + stk_camera_write_reg(dev, 0x001c, 0x0e); + else + stk_camera_write_reg(dev, 0x001c, 0x46); + /* + * Registers 0x0115 0x0114 are the size of each line (bytes), + * regs 0x0117 0x0116 are the heigth of the image. + */ + stk_camera_write_reg(dev, 0x0115, + (fmtd->fmt.pix.bytesperline >> 8) & 0xff); + stk_camera_write_reg(dev, 0x0114, + fmtd->fmt.pix.bytesperline & 0xff); + stk_camera_write_reg(dev, 0x0117, + (fmtd->fmt.pix.height >> 8) & 0xff); + stk_camera_write_reg(dev, 0x0116, + fmtd->fmt.pix.height & 0xff); + return stk_sensor_configure(dev); +} + +static int stk_vidioc_reqbufs(struct file *filp, + void *priv, struct v4l2_requestbuffers *rb) +{ + struct stk_camera *dev = priv; + + if (dev == NULL) + return -ENODEV; + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + if (is_streaming(dev) + || (dev->owner && dev->owner != filp)) + return -EBUSY; + dev->owner = filp; + + /*FIXME If they ask for zero, we must stop streaming and free */ + if (rb->count < 3) + rb->count = 3; + /* Arbitrary limit */ + else if (rb->count > 5) + rb->count = 5; + + stk_allocate_buffers(dev, rb->count); + rb->count = dev->n_sbufs; + return 0; +} + +static int stk_vidioc_querybuf(struct file *filp, + void *priv, struct v4l2_buffer *buf) +{ + int index; + struct stk_camera *dev = priv; + struct stk_sio_buffer *sbuf; + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + index = buf->index; + + if (index < 0 || index >= dev->n_sbufs) + return -EINVAL; + sbuf = dev->sio_bufs + buf->index; + *buf = sbuf->v4lbuf; + return 0; +} + +static int stk_vidioc_qbuf(struct file *filp, + void *priv, struct v4l2_buffer *buf) +{ + struct stk_camera *dev = priv; + struct stk_sio_buffer *sbuf; + unsigned long flags; + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (buf->index < 0 || buf->index >= dev->n_sbufs) + return -EINVAL; + sbuf = dev->sio_bufs + buf->index; + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) + return 0; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; + spin_lock_irqsave(&dev->spinlock, flags); + list_add_tail(&sbuf->list, &dev->sio_avail); + *buf = sbuf->v4lbuf; + spin_unlock_irqrestore(&dev->spinlock, flags); + return 0; +} + +static int stk_vidioc_dqbuf(struct file *filp, + void *priv, struct v4l2_buffer *buf) +{ + struct stk_camera *dev = priv; + struct stk_sio_buffer *sbuf; + unsigned long flags; + int ret; + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || !is_streaming(dev)) + return -EINVAL; + + if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) + return -EWOULDBLOCK; + ret = wait_event_interruptible(dev->wait_frame, + !list_empty(&dev->sio_full) || !is_present(dev)); + if (ret) + return ret; + if (!is_present(dev)) + return -EIO; + + spin_lock_irqsave(&dev->spinlock, flags); + sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); + list_del_init(&sbuf->list); + spin_unlock_irqrestore(&dev->spinlock, flags); + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; + sbuf->v4lbuf.sequence = ++dev->sequence; + do_gettimeofday(&sbuf->v4lbuf.timestamp); + + *buf = sbuf->v4lbuf; + return 0; +} + +static int stk_vidioc_streamon(struct file *filp, + void *priv, enum v4l2_buf_type type) +{ + struct stk_camera *dev = priv; + if (is_streaming(dev)) + return 0; + if (dev->sio_bufs == NULL) + return -EINVAL; + dev->sequence = 0; + return stk_start_stream(dev); +} + +static int stk_vidioc_streamoff(struct file *filp, + void *priv, enum v4l2_buf_type type) +{ + struct stk_camera *dev = priv; + unsigned long flags; + int i; + stk_stop_stream(dev); + spin_lock_irqsave(&dev->spinlock, flags); + INIT_LIST_HEAD(&dev->sio_avail); + INIT_LIST_HEAD(&dev->sio_full); + for (i = 0; i < dev->n_sbufs; i++) { + INIT_LIST_HEAD(&dev->sio_bufs[i].list); + dev->sio_bufs[i].v4lbuf.flags = 0; + } + spin_unlock_irqrestore(&dev->spinlock, flags); + return 0; +} + + +static int stk_vidioc_g_parm(struct file *filp, + void *priv, struct v4l2_streamparm *sp) +{ + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + sp->parm.capture.capability = 0; + sp->parm.capture.capturemode = 0; + /*FIXME This is not correct */ + sp->parm.capture.timeperframe.numerator = 1; + sp->parm.capture.timeperframe.denominator = 30; + sp->parm.capture.readbuffers = 2; + sp->parm.capture.extendedmode = 0; + return 0; +} + +static struct file_operations v4l_stk_fops = { + .owner = THIS_MODULE, + .open = v4l_stk_open, + .release = v4l_stk_release, + .read = v4l_stk_read, + .poll = v4l_stk_poll, + .mmap = v4l_stk_mmap, + .ioctl = video_ioctl2, + .llseek = no_llseek +}; + +static void stk_v4l_dev_release(struct video_device *vd) +{ +} + +static struct video_device stk_v4l_data = { + .name = "stkwebcam", + .type = VFL_TYPE_GRABBER, + .type2 = VID_TYPE_CAPTURE, + .minor = -1, + .tvnorms = V4L2_STD_UNKNOWN, + .current_norm = V4L2_STD_UNKNOWN, + .fops = &v4l_stk_fops, + .release = stk_v4l_dev_release, + + .vidioc_querycap = stk_vidioc_querycap, + .vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap, + .vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap, + .vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap, + .vidioc_enum_input = stk_vidioc_enum_input, + .vidioc_s_input = stk_vidioc_s_input, + .vidioc_g_input = stk_vidioc_g_input, + .vidioc_s_std = stk_vidioc_s_std, + .vidioc_reqbufs = stk_vidioc_reqbufs, + .vidioc_querybuf = stk_vidioc_querybuf, + .vidioc_qbuf = stk_vidioc_qbuf, + .vidioc_dqbuf = stk_vidioc_dqbuf, + .vidioc_streamon = stk_vidioc_streamon, + .vidioc_streamoff = stk_vidioc_streamoff, + .vidioc_queryctrl = stk_vidioc_queryctrl, + .vidioc_g_ctrl = stk_vidioc_g_ctrl, + .vidioc_s_ctrl = stk_vidioc_s_ctrl, + .vidioc_g_parm = stk_vidioc_g_parm, +}; + + +static int stk_register_video_device(struct stk_camera *dev) +{ + int err; + + dev->vdev = stk_v4l_data; + dev->vdev.debug = debug; + dev->vdev.dev = &dev->interface->dev; + dev->vdev.priv = dev; + err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); + if (err) + STK_ERROR("v4l registration failed\n"); + else + STK_INFO("Syntek USB2.0 Camera is now controlling video device" + " /dev/video%d\n", dev->vdev.minor); + return err; +} + + +/* USB Stuff */ + +static int stk_camera_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int i; + int err; + + struct stk_camera *dev = NULL; + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + + dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL); + if (dev == NULL) { + STK_ERROR("Out of memory !\n"); + return -ENOMEM; + } + + kref_init(&dev->kref); + spin_lock_init(&dev->spinlock); + init_waitqueue_head(&dev->wait_frame); + + dev->udev = udev; + dev->interface = interface; + usb_get_intf(interface); + + dev->vsettings.vflip = vflip; + dev->vsettings.hflip = hflip; + dev->n_sbufs = 0; + set_present(dev); + + /* Set up the endpoint information + * use only the first isoc-in endpoint + * for the current alternate setting */ + iface_desc = interface->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!dev->isoc_ep + && ((endpoint->bEndpointAddress + & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + && ((endpoint->bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) { + /* we found an isoc in endpoint */ + dev->isoc_ep = (endpoint->bEndpointAddress & 0xF); + break; + } + } + if (!dev->isoc_ep) { + STK_ERROR("Could not find isoc-in endpoint"); + kref_put(&dev->kref, stk_camera_cleanup); + return -ENODEV; + } + dev->vsettings.brightness = 0x7fff; + dev->vsettings.palette = V4L2_PIX_FMT_RGB565; + dev->vsettings.mode = MODE_VGA; + dev->frame_size = 640*480*2; + + INIT_LIST_HEAD(&dev->sio_avail); + INIT_LIST_HEAD(&dev->sio_full); + + usb_set_intfdata(interface, dev); + + err = stk_register_video_device(dev); + if (err) { + kref_put(&dev->kref, stk_camera_cleanup); + return err; + } + + stk_create_sysfs_files(&dev->vdev); + + return 0; +} + +static void stk_camera_disconnect(struct usb_interface *interface) +{ + struct stk_camera *dev = usb_get_intfdata(interface); + + usb_set_intfdata(interface, NULL); + unset_present(dev); + + wake_up_interruptible(&dev->wait_frame); + stk_remove_sysfs_files(&dev->vdev); + + kref_put(&dev->kref, stk_camera_cleanup); +} + +static struct usb_driver stk_camera_driver = { + .name = "stkwebcam", + .probe = stk_camera_probe, + .disconnect = stk_camera_disconnect, + .id_table = stkwebcam_table, +}; + + +static int __init stk_camera_init(void) +{ + int result; + + result = usb_register(&stk_camera_driver); + if (result) + STK_ERROR("usb_register failed ! Error number %d\n", result); + + + return result; +} + +static void __exit stk_camera_exit(void) +{ + usb_deregister(&stk_camera_driver); +} + +module_init(stk_camera_init); +module_exit(stk_camera_exit); + + diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h new file mode 100644 index 00000000000..7e989d1ac1e --- /dev/null +++ b/drivers/media/video/stk-webcam.h @@ -0,0 +1,138 @@ +/* + * stk-webcam.h : Driver for Syntek 1125 USB webcam controller + * + * Copyright (C) 2006 Nicolas VIVIEN + * Copyright 2007-2008 Jaime Velasco Juan + * + * 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 + * any later version. + * + * 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 STKWEBCAM_H +#define STKWEBCAM_H + +#include +#include + +#define DRIVER_VERSION "v0.0.1" +#define DRIVER_VERSION_NUM 0x000001 + +#define MAX_ISO_BUFS 3 +#define ISO_FRAMES_PER_DESC 16 +#define ISO_MAX_FRAME_SIZE 3 * 1024 +#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) + + +#define PREFIX "stkwebcam: " +#define STK_INFO(str, args...) printk(KERN_INFO PREFIX str, ##args) +#define STK_ERROR(str, args...) printk(KERN_ERR PREFIX str, ##args) +#define STK_WARNING(str, args...) printk(KERN_WARNING PREFIX str, ##args) + +struct stk_iso_buf { + void *data; + int length; + int read; + struct urb *urb; +}; + +/* Streaming IO buffers */ +struct stk_sio_buffer { + struct v4l2_buffer v4lbuf; + char *buffer; + int mapcount; + struct stk_camera *dev; + struct list_head list; +}; + +enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF}; + +struct stk_video { + enum stk_mode mode; + int brightness; + __u32 palette; + int hflip; + int vflip; +}; + +enum stk_status { + S_PRESENT = 1, + S_INITIALISED = 2, + S_MEMALLOCD = 4, + S_STREAMING = 8, +}; +#define is_present(dev) ((dev)->status & S_PRESENT) +#define is_initialised(dev) ((dev)->status & S_INITIALISED) +#define is_streaming(dev) ((dev)->status & S_STREAMING) +#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD) +#define set_present(dev) ((dev)->status = S_PRESENT) +#define unset_present(dev) ((dev)->status &= \ + ~(S_PRESENT|S_INITIALISED|S_STREAMING)) +#define set_initialised(dev) ((dev)->status |= S_INITIALISED) +#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD) +#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD) +#define set_streaming(dev) ((dev)->status |= S_STREAMING) +#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING) + +struct regval { + unsigned reg; + unsigned val; +}; + +struct stk_camera { + struct video_device vdev; + struct usb_device *udev; + struct usb_interface *interface; + int webcam_model; + struct file *owner; + + u8 isoc_ep; + + struct kref kref; + /* Not sure if this is right */ + atomic_t urbs_used; + + struct stk_video vsettings; + + enum stk_status status; + + spinlock_t spinlock; + wait_queue_head_t wait_frame; + + struct stk_iso_buf *isobufs; + + int frame_size; + /* Streaming buffers */ + unsigned int n_sbufs; + struct stk_sio_buffer *sio_bufs; + struct list_head sio_avail; + struct list_head sio_full; + unsigned sequence; +}; + +#define to_stk_camera(d) container_of(d, struct stk_camera, kref) +#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) + +void stk_camera_delete(struct kref *); +int stk_camera_write_reg(struct stk_camera *, u16, u8); +int stk_camera_read_reg(struct stk_camera *, u16, int *); + +int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val); +int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val); +int stk_sensor_init(struct stk_camera *); +int stk_sensor_configure(struct stk_camera *); +int stk_sensor_sleep(struct stk_camera *dev); +int stk_sensor_wakeup(struct stk_camera *dev); +int stk_sensor_set_brightness(struct stk_camera *dev, int br); + +#endif -- cgit v1.2.3 From 15b9becc68793209a2afd6c580bf71a71fee90a6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Jan 2008 12:02:20 -0300 Subject: V4L/DVB (7020): Add USB ID for a newer variant of Hauppauge WinTV USB2 Thanks to Jeroen Janssen Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index dbc19ca9e48..6a8469f2bca 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -2,7 +2,7 @@ 1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2750,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883] 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036] 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208] - 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200] + 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200,2040:4201] 5 -> MSI VOX USB 2.0 (em2820/em2840) 6 -> Terratec Cinergy 200 USB (em2800) 7 -> Leadtek Winfast USB II (em2800) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 5ffdbaab3ad..fe0ee451847 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -419,6 +419,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, + { USB_DEVICE(0x2040, 0x4201), + .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x2304, 0x021a), -- cgit v1.2.3 From c8793b035df7b18997d1cf34254064dac166f009 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Jan 2008 15:42:17 -0300 Subject: V4L/DVB (7021): Move all board specific configuration to em28xx-cards.c This cleanup moves the board-specific configurations to em28xx-cards.c. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 105 +++++++++++++++++++++++++----- drivers/media/video/em28xx/em28xx-input.c | 52 ++------------- drivers/media/video/em28xx/em28xx.h | 46 ++++--------- 3 files changed, 106 insertions(+), 97 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index fe0ee451847..368a766eb80 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -42,12 +42,36 @@ static int tuner = -1; module_param(tuner, int, 0444); MODULE_PARM_DESC(tuner, "tuner type"); +static unsigned int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); + struct em28xx_hash_table { unsigned long hash; unsigned int model; unsigned int tuner; }; +/* Boards supported by driver */ + +#define EM2800_BOARD_UNKNOWN 0 +#define EM2820_BOARD_UNKNOWN 1 +#define EM2820_BOARD_TERRATEC_CINERGY_250 2 +#define EM2820_BOARD_PINNACLE_USB_2 3 +#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 +#define EM2820_BOARD_MSI_VOX_USB_2 5 +#define EM2800_BOARD_TERRATEC_CINERGY_200 6 +#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 +#define EM2800_BOARD_KWORLD_USB2800 8 +#define EM2820_BOARD_PINNACLE_DVC_90 9 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 +#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 +#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 +#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 +#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 +#define EM2800_BOARD_VGEAR_POCKETTV 15 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 + struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", @@ -245,26 +269,28 @@ struct em28xx_board em28xx_boards[] = { } }, }, [EM2820_BOARD_MSI_VOX_USB_2] = { - .name = "MSI VOX USB 2.0", - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .has_tuner = 1, - .decoder = EM28XX_SAA7114, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, - .amux = 0, + .name = "MSI VOX USB 2.0", + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .has_tuner = 1, + .max_range_640_480 = 1, + + .decoder = EM28XX_SAA7114, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE4, + .amux = 0, }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, } }, }, [EM2800_BOARD_TERRATEC_CINERGY_200] = { @@ -649,11 +675,54 @@ static void em28xx_set_model(struct em28xx *dev) dev->video_inputs = em28xx_boards[dev->model].vchannels; dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; + dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; if (!em28xx_boards[dev->model].has_tuner) dev->tuner_type = UNSET; } +/* ----------------------------------------------------------------------- */ +void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) +{ + if (disable_ir) { + ir->get_key = NULL; + return ; + } + + /* detect & configure */ + switch (dev->model) { + case (EM2800_BOARD_UNKNOWN): + break; + case (EM2820_BOARD_UNKNOWN): + break; + case (EM2800_BOARD_TERRATEC_CINERGY_200): + case (EM2820_BOARD_TERRATEC_CINERGY_250): + ir->ir_codes = ir_codes_em_terratec; + ir->get_key = em28xx_get_key_terratec; + snprintf(ir->c.name, sizeof(ir->c.name), + "i2c IR (EM28XX Terratec)"); + break; + case (EM2820_BOARD_PINNACLE_USB_2): + ir->ir_codes = ir_codes_pinnacle_grey; + ir->get_key = em28xx_get_key_pinnacle_usb_grey; + snprintf(ir->c.name, sizeof(ir->c.name), + "i2c IR (EM28XX Pinnacle PCTV)"); + break; + case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): + ir->ir_codes = ir_codes_hauppauge_new; + ir->get_key = em28xx_get_key_em_haup; + snprintf(ir->c.name, sizeof(ir->c.name), + "i2c IR (EM2840 Hauppauge)"); + break; + case (EM2820_BOARD_MSI_VOX_USB_2): + break; + case (EM2800_BOARD_LEADTEK_WINFAST_USBII): + break; + case (EM2800_BOARD_KWORLD_USB2800): + break; + } +} + void em28xx_card_setup(struct em28xx *dev) { em28xx_set_model(dev); diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index e3894b68c4e..10da2fd8d98 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -30,11 +30,7 @@ #include "em28xx.h" -static unsigned int disable_ir = 0; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir,"disable infrared remote support"); - -static unsigned int ir_debug = 0; +static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); @@ -43,7 +39,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); /* ----------------------------------------------------------------------- */ -static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -72,7 +68,7 @@ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } -static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[2]; unsigned char code; @@ -103,7 +99,8 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw) { unsigned char buf[3]; @@ -125,45 +122,6 @@ static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw return 1; } -/* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir) -{ - if (disable_ir) { - ir->get_key=NULL; - return ; - } - - /* detect & configure */ - switch (dev->model) { - case (EM2800_BOARD_UNKNOWN): - break; - case (EM2820_BOARD_UNKNOWN): - break; - case (EM2800_BOARD_TERRATEC_CINERGY_200): - case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)"); - break; - case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)"); - break; - case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)"); - break; - case (EM2820_BOARD_MSI_VOX_USB_2): - break; - case (EM2800_BOARD_LEADTEK_WINFAST_USBII): - break; - case (EM2800_BOARD_KWORLD_USB2800): - break; - } -} - /* ---------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 2ba34e5b4cc..3ef80d8b566 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -30,26 +30,6 @@ #include #include -/* Boards supported by driver */ - -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 -#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 -#define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 - #define UNSET -1 /* maximum number of em28xx boards */ @@ -185,6 +165,7 @@ struct em28xx_board { unsigned int has_msp34xx:1; unsigned int mts_firmware:1; unsigned int has_12mhz_i2s:1; + unsigned int max_range_640_480:1; unsigned int analog_gpio; @@ -251,6 +232,7 @@ struct em28xx { unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; unsigned int has_12mhz_i2s:1; + unsigned int max_range_640_480:1; int video_inputs; /* number of video inputs */ struct list_head devlist; @@ -352,10 +334,6 @@ void em28xx_do_i2c_scan(struct em28xx *dev); int em28xx_i2c_register(struct em28xx *dev); int em28xx_i2c_unregister(struct em28xx *dev); -/* Provided by em28xx-input.c */ - -void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir); - /* Provided by em28xx-core.c */ u32 em28xx_request_buffers(struct em28xx *dev, u32 count); @@ -393,6 +371,14 @@ extern void em28xx_card_setup(struct em28xx *dev); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; +void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); + +/* Provided by em28xx-input.c */ +/* TODO: Check if the standard get_key handlers on ir-common can be used */ +int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw); /* em2800 registers */ #define EM2800_AUDIOSRC_REG 0x08 @@ -550,21 +536,17 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val) /*FIXME: maxw should be dependent of alt mode */ inline static unsigned int norm_maxw(struct em28xx *dev) { - switch (dev->model) { - case EM2820_BOARD_MSI_VOX_USB_2: + if (dev->max_range_640_480) return 640; - default: + else return 720; - } } inline static unsigned int norm_maxh(struct em28xx *dev) { - switch (dev->model) { - case EM2820_BOARD_MSI_VOX_USB_2: + if (dev->max_range_640_480) return 480; - default: + else return (dev->norm & V4L2_STD_625_50) ? 576 : 480; - } } #endif -- cgit v1.2.3 From dfd8c04ec14b88bc2849e62d6ff9e36f31352b60 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Jan 2008 19:36:11 -0300 Subject: V4L/DVB (7022): Fix timestamp presentation on vivi driver Due to date overflow, vivi were not working fine anymore. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c9d23633fe4..1db067c0281 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -173,7 +173,8 @@ struct vivi_dev { struct vivi_dmaqueue vidq; /* Several counters */ - int h, m, s, us, jiffies; + int h, m, s, ms; + unsigned long jiffies; char timestr[13]; int mv_count; /* Controls bars movement */ @@ -348,10 +349,10 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) /* Updates stream time */ - dev->us += jiffies_to_usecs(jiffies-dev->jiffies); + dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); dev->jiffies = jiffies; - if (dev->us >= 1000000) { - dev->us -= 1000000; + if (dev->ms >= 1000) { + dev->ms -= 1000; dev->s++; if (dev->s >= 60) { dev->s -= 60; @@ -365,7 +366,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) } } sprintf(dev->timestr, "%02d:%02d:%02d:%03d", - dev->h, dev->m, dev->s, (dev->us + 500) / 1000); + dev->h, dev->m, dev->s, dev->ms); dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", dev->timestr, (unsigned long)tmpbuf, pos); @@ -1073,11 +1074,11 @@ found: dev->h = 0; dev->m = 0; dev->s = 0; - dev->us = 0; + dev->ms = 0; dev->mv_count = 0; dev->jiffies = jiffies; sprintf(dev->timestr, "%02d:%02d:%02d:%03d", - dev->h, dev->m, dev->s, (dev->us + 500) / 1000); + dev->h, dev->m, dev->s, dev->ms); videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, -- cgit v1.2.3 From 1f8d30083abc17897b897787c39d446eb9d99fe0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Jan 2008 19:40:30 -0300 Subject: V4L/DVB (7023): Fix a regresion left by changeset 7e65d6e8f6df Changeset 7e65d6e8f6df removed a very bad hack on mmap(). However, the fixes weren't considering usermap and overlay memory models. This were breaking direct reading from /dev/video?, used mostly by mpeg aware drivers. Thanks to Steven Toth for reporting the issue and bissecting it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index c3adbd686ff..80a14da9ace 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -102,10 +102,14 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, since mmap_mapper() method should be called before _iolock. On some cases, the mmap_mapper() is called only after scheduling. */ - wait_event_timeout(vb->done, q->is_mmapped, msecs_to_jiffies(100)); - if (!q->is_mmapped) { - printk(KERN_ERR "Error: mmap_mapper() never called!\n"); - return -EINVAL; + if (vb->memory == V4L2_MEMORY_MMAP) { + wait_event_timeout(vb->done, q->is_mmapped, + msecs_to_jiffies(100)); + if (!q->is_mmapped) { + printk(KERN_ERR + "Error: mmap_mapper() never called!\n"); + return -EINVAL; + } } return CALL(q, iolock, q, vb, fbuf); -- cgit v1.2.3 From 6200bbaa5bd8b6751931364dfa4aa1cdd5efa686 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Thu, 10 Jan 2008 18:20:34 -0300 Subject: V4L/DVB (7024): usbvision: YUV to RGB conversion fixes All YUV to RGB conversions in usbvision were reverted (conversion to BGR but saying RGB to the application) Signed-off-by: Thierry MERLE Acked-by: Dwaine Garden Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 300 ++++++++++++++----------- 1 file changed, 166 insertions(+), 134 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 1e52a0387aa..56775ab8b75 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -633,25 +633,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv); switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); - *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = bv; - *f++ = gv; - *f++ = rv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = bv; - *f++ = gv; - *f++ = rv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); - *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x07 & (gv >> 3)) | + (0xF8 & bv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = rv; + *f++ = gv; + *f++ = bv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = rv; + *f++ = gv; + *f++ = bv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x03 & (gv >> 3)) | + (0x7C & (bv << 2)); + break; } } clipmask_index += clipmask_add; @@ -665,25 +669,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv); switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); - *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = bv; - *f++ = gv; - *f++ = rv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = bv; - *f++ = gv; - *f++ = rv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); - *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x07 & (gv >> 3)) | + (0xF8 & bv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = rv; + *f++ = gv; + *f++ = bv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = rv; + *f++ = gv; + *f++ = bv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x03 & (gv >> 3)) | + (0x7C & (bv << 2)); + break; } } clipmask_index += clipmask_add; @@ -951,22 +959,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, *f++ = Y[Idx]; break; case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); - *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x03 & (gv >> 3)) | + (0x7C & (bv << 2)); break; case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); - *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x07 & (gv >> 3)) | + (0xF8 & bv); break; case V4L2_PIX_FMT_RGB24: - *f++ = bv; - *f++ = gv; *f++ = rv; + *f++ = gv; + *f++ = bv; break; case V4L2_PIX_FMT_RGB32: - *f++ = bv; - *f++ = gv; *f++ = rv; + *f++ = gv; + *f++ = bv; f++; break; } @@ -1080,28 +1092,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_even++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_even_index += clipmask_add; @@ -1119,28 +1136,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_even++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_even_index += clipmask_add; @@ -1160,28 +1182,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_odd++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_odd_index += clipmask_add; @@ -1199,28 +1226,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_odd++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_odd_index += clipmask_add; -- cgit v1.2.3 From 6bfa6657246013bf999fecda0874105441f6ecb5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 7 Jan 2008 00:51:48 -0300 Subject: V4L/DVB (7026): tda18271: report when the RF tracking filter calibration has completed Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 0b41b951394..c254ac367e7 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -597,6 +597,8 @@ static int tda18271_rf_cal_init(struct dvb_frontend *fe) tda18271_por(fe); + tda_info("tda18271: RF tracking filter calibration complete\n"); + priv->cal_initialized = true; return 0; -- cgit v1.2.3 From 518d87399baee908b0353bc0ef7d41c3c46295ec Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 13 Jan 2008 17:01:01 -0300 Subject: V4L/DVB (7027): tda18271: put the device in standby mode during sleep() Add function, tda18271_set_standby_mode. During sleep, enter standby mode with slave tuner output enabled, loop through on and xtal oscillator on. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-common.c | 36 +++++++++++++++++++++++++++ drivers/media/dvb/frontends/tda18271-fe.c | 26 +++++++++++++++---- drivers/media/dvb/frontends/tda18271-priv.h | 3 +++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c index d7a33565947..cebb6b90b7e 100644 --- a/drivers/media/dvb/frontends/tda18271-common.c +++ b/drivers/media/dvb/frontends/tda18271-common.c @@ -452,6 +452,42 @@ int tda18271_init_regs(struct dvb_frontend *fe) /*---------------------------------------------------------------------*/ +/* + * Standby modes, EP3 [7:5] + * + * | SM || SM_LT || SM_XT || mode description + * |=====\\=======\\=======\\=================================== + * | 0 || 0 || 0 || normal mode + * |-----||-------||-------||----------------------------------- + * | || || || standby mode w/ slave tuner output + * | 1 || 0 || 0 || & loop thru & xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 0 || standby mode w/ xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 1 || power off + * + */ + +int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); + + regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ + regs[R_EP3] |= sm ? (1 << 7) : 0 | + sm_lt ? (1 << 6) : 0 | + sm_xt ? (1 << 5) : 0; + + tda18271_write_regs(fe, R_EP3, 1); + + return 0; +} + +/*---------------------------------------------------------------------*/ + int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) { /* sets main post divider & divider bytes, but does not write them */ diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index c254ac367e7..c8ab1fda1de 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -201,8 +201,7 @@ static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe, u8 dc_over_dt, rf_tab; /* power up */ - regs[R_EP3] &= ~0xe0; /* sm = 0, sm_lt = 0, sm_xt = 0 */ - tda18271_write_regs(fe, R_EP3, 1); + tda18271_set_standby_mode(fe, 0, 0, 0); /* read die current temperature */ tm_current = tda18271_read_thermometer(fe); @@ -256,9 +255,7 @@ static int tda18271_por(struct dvb_frontend *fe) regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ /* POR mode */ - regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ - regs[R_EP3] |= 0x80; /* sm = 1, sm_lt = 0, sm_xt = 0 */ - tda18271_write_regs(fe, R_EP3, 1); + tda18271_set_standby_mode(fe, 1, 0, 0); /* disable 1.5 MHz low pass filter */ regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ @@ -610,6 +607,9 @@ static int tda18271_init(struct dvb_frontend *fe) mutex_lock(&priv->lock); + /* power up */ + tda18271_set_standby_mode(fe, 0, 0, 0); + /* initialization */ tda18271_ir_cal_init(fe); @@ -953,6 +953,21 @@ fail: return ret; } +static int tda18271_sleep(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&priv->lock); + + /* standby mode w/ slave tuner output + * & loop thru & xtal oscillator on */ + tda18271_set_standby_mode(fe, 1, 0, 0); + + mutex_unlock(&priv->lock); + + return 0; +} + static int tda18271_release(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -1096,6 +1111,7 @@ static struct dvb_tuner_ops tda18271_tuner_ops = { .frequency_step = 62500 }, .init = tda18271_init, + .sleep = tda18271_sleep, .set_params = tda18271_set_params, .set_analog_params = tda18271_set_analog_params, .release = tda18271_release, diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h index 080efb3991e..7b939a5325f 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -188,6 +188,9 @@ extern int tda18271_read_extended(struct dvb_frontend *fe); extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); extern int tda18271_init_regs(struct dvb_frontend *fe); +extern int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt); + extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); -- cgit v1.2.3 From 839c6c96d05894815b7af0dff22b710ce5a4373a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 13 Jan 2008 18:29:44 -0300 Subject: V4L/DVB (7028): tda18271: test RF_CAL_OK to see if we need additional RF calibration Test RF_CAL_OK to see if we need to perform the RF tracking filter calibration after returning from standby. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index c8ab1fda1de..8eb9a537970 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -586,6 +586,11 @@ static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) static int tda18271_rf_cal_init(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + /* test RF_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x10) == 0) + priv->cal_initialized = false; if (priv->cal_initialized) return 0; -- cgit v1.2.3 From 0f96251e7bfb2b2798f35e70efaa54bae65bfb9c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 13 Jan 2008 22:01:07 -0300 Subject: V4L/DVB (7029): tda18271: provide a choice whether to perform rf cal on init or on first tune If module option "cal" is set to 1, the ~22 sec rf tracking filter calibration sequence will be invoked on startup. Otherwise, the calibration will take place during the first tune. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 8eb9a537970..7c80516a448 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -27,6 +27,10 @@ module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level " "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); +int tda18271_cal_on_startup; +module_param_named(cal, tda18271_cal_on_startup, int, 0644); +MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); + static LIST_HEAD(tda18271_list); static DEFINE_MUTEX(tda18271_list_mutex); @@ -1177,6 +1181,10 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, mutex_lock(&priv->lock); tda18271_init_regs(fe); + + if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2)) + tda18271_rf_cal_init(fe); + mutex_unlock(&priv->lock); } -- cgit v1.2.3 From 99beeee9e927bf0c8d62e462a2fda86fa2c1450b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 13 Jan 2008 20:02:52 -0300 Subject: V4L/DVB (7030): Kconfig: add missing selections for VIDEO_PVRUSB2 VIDEO_PVRUSB2 must select: VIDEO_SAA711X, VIDEO_CX25840, VIDEO_MSP3400, and VIDEO_WM8775 Signed-off-by: Michael Krufky Acked-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 95e4396011c..6fc1b8be1a1 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -5,6 +5,10 @@ config VIDEO_PVRUSB2 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X + select VIDEO_SAA711X + select VIDEO_CX25840 + select VIDEO_MSP3400 + select VIDEO_WM8775 ---help--- This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. -- cgit v1.2.3 From bc835d80d9cd912cfa8beb6ad4549cd8160d3601 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 14 Jan 2008 11:10:54 -0300 Subject: V4L/DVB (7032): tda18271: tda18271_cal_on_startup should be declared static This module option variable is only handled within the file tda18271-fe.c - Declare this variable as static. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index 7c80516a448..dd3657e459b 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -27,7 +27,7 @@ module_param_named(debug, tda18271_debug, int, 0644); MODULE_PARM_DESC(debug, "set debug level " "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); -int tda18271_cal_on_startup; +static int tda18271_cal_on_startup; module_param_named(cal, tda18271_cal_on_startup, int, 0644); MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); -- cgit v1.2.3 From a2a9b1eceb50993ef9e126dffc2f678fd6602158 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Jan 2008 22:03:42 -0300 Subject: V4L/DVB (7035): drivers/media/common: Add missing video_device_release Video_device_alloc returns the result of a kzalloc. In this case, the value is stored in a local variable which is not copied elsewhere before the point of the error return (video_register_device does not save its first argument anywhere if it returns a negative value). Thus, a video_device_release it needed before the error return. The problem was found using the following semantic match. (http://www.emn.fr/x-info/coccinelle/) // @@ type T,T1,T2; identifier E; statement S; expression x1,x2,x3; int ret; @@ T E; ... * E = video_device_alloc(...); if (E == NULL) S ... when != video_device_release(...,(T1)E,...) when != if (E != NULL) { ... video_device_release(...,(T1)E,...); ...} when != x1 = (T1)E when != E = x3; when any if (...) { ... when != video_device_release(...,(T2)E,...) when != if (E != NULL) { ... video_device_release(...,(T2)E,...); ...} when != x2 = (T2)E ( * return; | * return ret; ) } // Signed-off-by: Julia Lawall Signed-off-by: Andrew Morton CC: Oliver Endriss CC: Michael Hunold Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_fops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index b40bf2306fb..f0703d8bc3e 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); if (video_register_device(vfd, type, -1) < 0) { ERR(("cannot register v4l2 device. skipping.\n")); + video_device_release(vfd); return -1; } -- cgit v1.2.3 From f37fdf3ff744bffc35a8f1b9d7d655d8d88a0404 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 1 Jan 2008 18:08:10 -0300 Subject: V4L/DVB (7036): radio: Use video_device_release rather than kfree The file drivers/media/video/videodev.c defines both video_device_alloc and video_device_release. These are essentially just kzmalloc and kfree, respectively, but it seems better to use video_device_release, as done in the other media files, rather than kfree, in case the implementation some day changes. The problem was found using the following semantic match. (http://www.emn.fr/x-info/coccinelle/) // @@ type T,T1,T2; identifier E; statement S; expression x1,x2,x3; int ret; @@ T E; ... * E = video_device_alloc(...); if (E == NULL) S ... when != video_device_release(...,(T1)E,...) when != if (E != NULL) { ... video_device_release(...,(T1)E,...); ...} when != x1 = (T1)E when != E = x3; when any if (...) { ... when != video_device_release(...,(T2)E,...) when != if (E != NULL) { ... video_device_release(...,(T2)E,...); ...} when != x2 = (T2)E ( * return; | * return ret; ) } // Signed-off-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-maestro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 8e33a19a22a..bc51f4d23a5 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev, errunr: video_unregister_device(maestro_radio_inst); errfr1: - kfree(maestro_radio_inst); + video_device_release(maestro_radio_inst); errfr: kfree(radio_unit); err: -- cgit v1.2.3 From 438468359e1db16a7d1925fc4f2519a044bbf7dd Mon Sep 17 00:00:00 2001 From: Zoltan Devai Date: Mon, 14 Jan 2008 13:24:38 -0300 Subject: V4L/DVB (7037): Fix build breakage of the bttv driver, when advanced debugging is not enabled Signed-off-by: Zoltan Devai Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index ddca21d9c94..907dc62c178 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3402,8 +3402,10 @@ static struct video_device bttv_video_template = .vidioc_s_frequency = bttv_s_frequency, .vidioc_log_status = bttv_log_status, .vidioc_querystd = bttv_querystd, +#ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = bttv_g_register, .vidioc_s_register = bttv_s_register, +#endif .tvnorms = BTTV_NORMS, .current_norm = V4L2_STD_PAL, }; -- cgit v1.2.3 From 78656acdcf4852547a29e929a1b7a98d5ac65f17 Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Mon, 14 Jan 2008 21:55:27 -0300 Subject: V4L/DVB (7038): USB radio driver for Silicon Labs Si470x FM Radio Receivers this patch adds a new driver for the Silicon Labs Si470x FM Radio Receiver. It should also work for the identical ADS/Tech FM Radio Receiver (formerly Instant FM Music) as soon as I find out the USB Vendor and Product ID. The driver is inspired by several other USB and radio drivers, but mainly from the D-Link DSB-R100 USB radio (dsbr100.c). The USB stick currently has an Si4701 FM RDS radio receiver. But the other Si470x devices are pin and register compatible, so that in the future the driver can easily be patched to support these too. Therefore I named the driver radio-si470x and the configuration option usb-si470x. The driver itself just provides the control function over the radio. For getting audio back, the device support the USB audio class, which is implemented in the already existing driver. I tested the driver in the last days, until it now satisfies all my functionality and robustness requirements. The application I used for testing was kradio. Signed-off-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 10 + drivers/media/radio/Makefile | 1 + drivers/media/radio/radio-si470x.c | 1440 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1451 insertions(+) create mode 100644 drivers/media/radio/radio-si470x.c diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 11e962f1a97..8d5214f18cf 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -351,4 +351,14 @@ config USB_DSBR To compile this driver as a module, choose M here: the module will be called dsbr100. +config USB_SI470X + tristate "Silicon Labs Si470x FM Radio Receiver support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called radio-silabs. + endif # RADIO_ADAPTERS diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index cf55a18e3dd..f36cf4e63b6 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o obj-$(CONFIG_USB_DSBR) += dsbr100.o +obj-$(CONFIG_USB_SI470X) := radio-si470x.o EXTRA_CFLAGS += -Isound diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c new file mode 100644 index 00000000000..eccbc750e14 --- /dev/null +++ b/drivers/media/radio/radio-si470x.c @@ -0,0 +1,1440 @@ +/* + * drivers/media/radio/radio-si470x.c + * + * Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers: + * - Silicon Labs USB FM Radio Reference Design + * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) + * + * Copyright (c) 2007 Tobias Lorenz + * + * 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 + * (at your option) any later version. + * + * 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 + */ + + +/* + * History: + * 2008-01-12 Tobias Lorenz + * Version 1.0.0 + * - First working version + * 2008-01-13 Tobias Lorenz + * Version 1.0.1 + * - Improved error handling, every function now returns errno + * - Improved multi user access (start/mute/stop) + * - Channel doesn't get lost anymore after start/mute/stop + * - RDS support added (polling mode via interrupt EP 1) + * - marked default module parameters with *value* + * - switched from bit structs to bit masks + * - header file cleaned and integrated + * 2008-01-14 Tobias Lorenz + * Version 1.0.2 + * - hex values are now lower case + * - commented USB ID for ADS/Tech moved on todo list + * - blacklisted si470x in hid-quirks.c + * - rds buffer handling functions integrated into *_work, *_read + * - rds_command in si470x_poll exchanged against simple retval + * - check for firmware version 15 + * - code order and prototypes still remain the same + * - spacing and bottom of band codes remain the same + * + * ToDo: + * - check USB Vendor/Product ID for ADS/Tech FM Radio Receiver + * (formerly Instant FM Music) (RDX-155-EF) is 06e1:a155 + * - add seeking support + * - add firmware download/update support + * - add possibility to switch off RDS + * - RDS support: interrupt mode, instead of polling + * - add LED status output + */ + +/* driver definitions */ +#define DRIVER_AUTHOR "Tobias Lorenz " +#define DRIVER_NAME "radio-si470x" +#define DRIVER_VERSION KERNEL_VERSION(1, 0, 2) +#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" +#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" + + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Radio Nr */ +static int radio_nr = -1; +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* Spacing (kHz) */ +/* 0: 200 kHz (USA, Australia) */ +/* 1: 100 kHz (Europe, Japan) */ +/* 2: 50 kHz */ +static int space = 2; +module_param(space, int, 0); +MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); + +/* Bottom of Band (MHz) */ +/* 0: 87.5 - 108 MHz (USA, Europe)*/ +/* 1: 76 - 108 MHz (Japan wide band) */ +/* 2: 76 - 90 MHz (Japan) */ +static int band = 1; +module_param(band, int, 0); +MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); + +/* De-emphasis */ +/* 0: 75 us (USA) */ +/* 1: 50 us (Europe, Australia, Japan) */ +static int de = 1; +module_param(de, int, 0); +MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*"); + +/* USB timeout */ +static int usb_timeout = 500; +module_param(usb_timeout, int, 0); +MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); + +/* Seek retries */ +static int seek_retries = 100; +module_param(seek_retries, int, 0); +MODULE_PARM_DESC(seek_retries, "Seek retries: *100*"); + +/* RDS buffer blocks */ +static int rds_buf = 100; +module_param(rds_buf, int, 0); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +/* RDS maximum block errors */ +static int max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, int, 0); +MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); + +/* RDS poll frequency */ +static int rds_poll_time = 40; +/* 40 is used by the original USBRadio.exe */ +/* 75 should be okay */ +/* 80 is the usual RDS receive interval */ +module_param(rds_poll_time, int, 0); +MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); + + + +/************************************************************************** + * Register Definitions + **************************************************************************/ +#define FMRADIO_REGISTER_SIZE 2 /* 16 register bit width */ +#define FMRADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ +#define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ + +#define DEVICEID 0 /* Device ID */ +#define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ +#define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ + +#define CHIPID 1 /* Chip ID */ +#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ +#define CHIPID_DEV 0x0200 /* bits 09..09: Device */ +#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ + +#define POWERCFG 2 /* Power Configuration */ +#define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ +#define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */ +#define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */ +#define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */ +#define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */ +#define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */ +#define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */ +#define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */ +#define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */ + +#define CHANNEL 3 /* Channel */ +#define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */ +#define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */ + +#define SYSCONFIG1 4 /* System Configuration 1 */ +#define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */ +#define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */ +#define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */ +#define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */ +#define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */ +#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ +#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ +#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ +#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ + +#define SYSCONFIG2 5 /* System Configuration 2 */ +#define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ +#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ +#define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ +#define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ + +#define SYSCONFIG3 6 /* System Configuration 3 */ +#define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */ +#define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */ +#define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */ +#define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */ + +#define TEST1 7 /* Test 1 */ +#define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */ + +#define TEST2 8 /* Test 2 */ +/* TEST2 only contains reserved bits */ + +#define BOOTCONFIG 9 /* Boot Configuration */ +/* BOOTCONFIG only contains reserved bits */ + +#define STATUSRSSI 10 /* Status RSSI */ +#define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */ +#define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */ +#define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */ +#define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */ +#define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */ +#define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */ +#define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */ +#define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */ + +#define READCHAN 11 /* Read Channel */ +#define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */ +#define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */ +#define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */ +#define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */ + +#define RDSA 12 /* RDSA */ +#define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */ + +#define RDSB 13 /* RDSB */ +#define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */ + +#define RDSC 14 /* RDSC */ +#define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */ + +#define RDSD 15 /* RDSD */ +#define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */ + + + +/************************************************************************** + * USB HID reports + **************************************************************************/ + +/* Reports 1-16 give direct read/write access to the 16 Si470x registers */ +/* with the (REPORT_ID - 1) corresponding to the register address across USB */ +/* endpoint 0 using GET_REPORT and SET_REPORT */ +#define REGISTER_REPORT_SIZE (FMRADIO_REGISTER_SIZE + 1) +#define REGISTER_REPORT(reg) ((reg) + 1) + +/* Report 17 gives direct read/write access to the entire Si470x register */ +/* map across endpoint 0 using GET_REPORT and SET_REPORT */ +#define ENTIRE_REPORT_SIZE (FMRADIO_REGISTER_NUM * FMRADIO_REGISTER_SIZE + 1) +#define ENTIRE_REPORT 17 + +/* Report 18 is used to send the lowest 6 Si470x registers up the HID */ +/* interrupt endpoint 1 to Windows every 20 milliseconds for status */ +#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * FMRADIO_REGISTER_SIZE + 1) +#define RDS_REPORT 18 + +/* Report 19: LED state */ +#define LED_REPORT_SIZE 3 +#define LED_REPORT 19 + +/* Report 19: stream */ +#define STREAM_REPORT_SIZE 3 +#define STREAM_REPORT 19 + +/* Report 20: scratch */ +#define SCRATCH_PAGE_SIZE 63 +#define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1) +#define SCRATCH_REPORT 20 + +/* Reports 19-22: flash upgrade of the C8051F321 */ +#define WRITE_REPORT 19 +#define FLASH_REPORT 20 +#define CRC_REPORT 21 +#define RESPONSE_REPORT 22 + +/* Report 23: currently unused, but can accept 60 byte reports on the HID */ +/* interrupt out endpoint 2 every 1 millisecond */ +#define UNUSED_REPORT 23 + + + +/************************************************************************** + * software/hardware versions + **************************************************************************/ +#define FMRADIO_SW_VERSION_NOT_BOOTLOADABLE 6 +#define FMRADIO_SW_VERSION 7 +#define FMRADIO_SW_VERSION_CURRENT 15 +#define FMRADIO_HW_VERSION 1 + +#define SCRATCH_PAGE_SW_VERSION 1 +#define SCRATCH_PAGE_HW_VERSION 2 + + + +/************************************************************************** + * LED State definitions + **************************************************************************/ +#define LED_COMMAND 0x35 + +#define NO_CHANGE_LED 0x00 +#define ALL_COLOR_LED 0x01 /* streaming state */ +#define BLINK_GREEN_LED 0x02 /* connect state */ +#define BLINK_RED_LED 0x04 +#define BLINK_ORANGE_LED 0x10 /* disconnect state */ +#define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ +#define SOLID_RED_LED 0x40 /* bootload state */ +#define SOLID_ORANGE_LED 0x80 + + + +/************************************************************************** + * Stream State definitions + **************************************************************************/ +#define STREAM_COMMAND 0x36 +#define STREAM_VIDPID 0x00 +#define STREAM_AUDIO 0xff + + + +/************************************************************************** + * bootloader / flash commands + **************************************************************************/ + +/* Unique ID sent to bootloader and required to put into a bootload state */ +#define UNIQUE_BL_ID 0x34 + +/* Mask for the flash data */ +#define FLASH_DATA_MASK 0x55 + +/* Bootloader commands */ +#define GET_SW_VERSION_COMMAND 0x00 +#define SET_PAGE_COMMAND 0x01 +#define ERASE_PAGE_COMMAND 0x02 +#define WRITE_PAGE_COMMAND 0x03 +#define CRC_ON_PAGE_COMMAND 0x04 +#define READ_FLASH_BYTE_COMMAND 0x05 +#define RESET_DEVICE_COMMAND 0x06 +#define GET_HW_VERSION_COMMAND 0x07 +#define BLANK 0xff + +/* Bootloader command responses */ +#define COMMAND_OK 0x01 +#define COMMAND_FAILED 0x02 +#define COMMAND_PENDING 0x03 + +/* Buffer sizes */ +#define COMMAND_BUFFER_SIZE 4 +#define RESPONSE_BUFFER_SIZE 2 +#define FLASH_BUFFER_SIZE 64 +#define CRC_BUFFER_SIZE 3 + + + +/************************************************************************** + * Driver private definitions + **************************************************************************/ + +/* private data */ +struct si470x_device { + /* reference to USB and video device */ + struct usb_device *usbdev; + struct video_device *videodev; + + /* are these really necessary ? */ + int users; + + /* report buffer (maximum 64 bytes) */ + unsigned char buf[64]; + + /* Silabs internal registers (0..15) */ + unsigned short registers[FMRADIO_REGISTER_NUM]; + + /* RDS receive buffer */ + struct work_struct work; + struct timer_list timer; + spinlock_t lock; + unsigned char *buffer; + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + unsigned int block_count; + unsigned char last_blocknum; + wait_queue_head_t read_queue; + int data_available_for_read; +}; + +/* register acccess functions */ +static int si470x_get_report(struct si470x_device *radio, int size); +static int si470x_set_report(struct si470x_device *radio, int size); +static int si470x_get_register(struct si470x_device *radio, int regnr); +static int si470x_set_register(struct si470x_device *radio, int regnr); +static int si470x_get_all_registers(struct si470x_device *radio); +static int si470x_get_rds_registers(struct si470x_device *radio); + +/* high-level functions */ +static int si470x_start(struct si470x_device *radio); +static int si470x_stop(struct si470x_device *radio); +static int si470x_set_chan(struct si470x_device *radio, int chan); +static int si470x_get_freq(struct si470x_device *radio); +static int si470x_set_freq(struct si470x_device *radio, int freq); + +/* RDS functions */ +static void si470x_rds(struct si470x_device *radio); +static void si470x_timer(unsigned long data); +static void si470x_work(struct work_struct *work); + + + +/************************************************************************** + * USB interface definitions + **************************************************************************/ + +/* USB device ID list (Vendor, Product, Class, SubClass, Protocol) */ +static struct usb_device_id si470x_usb_driver_id_table[] = { + /* Silicon Labs USB FM Radio Reference Design */ + { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE (usb, si470x_usb_driver_id_table); + +/* USB driver functions */ +static int si470x_usb_driver_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void si470x_usb_driver_disconnect(struct usb_interface *intf); + +/* USB driver interface */ +static struct usb_driver si470x_usb_driver = { + .name = DRIVER_NAME, + .probe = si470x_usb_driver_probe, + .disconnect = si470x_usb_driver_disconnect, + .id_table = si470x_usb_driver_id_table, +}; + + + +/************************************************************************** + * Video4Linux interface definitions + **************************************************************************/ + +/* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, */ +/* 62.5 kHz otherwise. */ +/* The tuner is able to have a channel spacing of 50, 100 or 200 kHz. */ +/* tuner->capability is therefore set to V4L2_TUNER_CAP_LOW */ +/* The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 */ +#define FREQ_MUL (1000000 / 62.5) + +/* File operations functions */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos); +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts); +static int si470x_fops_open(struct inode *inode, struct file *file); +static int si470x_fops_release(struct inode *inode, struct file *file); + +/* File operations interface */ +static const struct file_operations si470x_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .open = si470x_fops_open, + .release = si470x_fops_release, +}; + +/* Video device functions */ +static int si470x_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability); +static int si470x_vidioc_g_input(struct file *file, void *priv, + unsigned int *i); +static int si470x_vidioc_s_input(struct file *file, void *priv, + unsigned int i); +static int si470x_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc); +static int si470x_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl); +static int si470x_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl); +static int si470x_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio); +static int si470x_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio); +static int si470x_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner); +static int si470x_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner); +static int si470x_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq); +static int si470x_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq); + +/* Video device interface */ +static struct video_device si470x_viddev_template = { + .fops = &si470x_fops, + .name = DRIVER_NAME, + .type = VID_TYPE_TUNER, + .release = video_device_release, + .vidioc_querycap = si470x_vidioc_querycap, + .vidioc_g_input = si470x_vidioc_g_input, + .vidioc_s_input = si470x_vidioc_s_input, + .vidioc_queryctrl = si470x_vidioc_queryctrl, + .vidioc_g_ctrl = si470x_vidioc_g_ctrl, + .vidioc_s_ctrl = si470x_vidioc_s_ctrl, + .vidioc_g_audio = si470x_vidioc_g_audio, + .vidioc_s_audio = si470x_vidioc_s_audio, + .vidioc_g_tuner = si470x_vidioc_g_tuner, + .vidioc_s_tuner = si470x_vidioc_s_tuner, + .vidioc_g_frequency = si470x_vidioc_g_frequency, + .vidioc_s_frequency = si470x_vidioc_s_frequency, + .owner = THIS_MODULE, +}; + +/* Query control */ +static struct v4l2_queryctrl radio_queryctrl[] = { +/* HINT: the disabled controls are only here to satify kradio and such apps */ + { + .id = V4L2_CID_AUDIO_VOLUME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Volume", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 15, + }, + { + .id = V4L2_CID_AUDIO_BALANCE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_BASS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_TREBLE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_MUTE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_AUDIO_LOUDNESS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, +}; + + + +/************************************************************************** + * Driver private functions + **************************************************************************/ + +/* + * si470x_get_report - receive a HID report + */ +static int si470x_get_report(struct si470x_device *radio, int size) +{ + return usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + HID_REQ_GET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + radio->buf[0], 2, + radio->buf, size, usb_timeout); +} + + +/* + * si470x_set_report - send a HID report + */ +static int si470x_set_report(struct si470x_device *radio, int size) +{ + return usb_control_msg(radio->usbdev, + usb_sndctrlpipe(radio->usbdev, 0), + HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + radio->buf[0], 2, + radio->buf, size, usb_timeout); +} + + +/* + * si470x_get_register - read register + */ +static int si470x_get_register(struct si470x_device *radio, int regnr) +{ + int retval; + + radio->buf[0] = REGISTER_REPORT(regnr); + + retval = si470x_get_report(radio, REGISTER_REPORT_SIZE); + if (retval >= 0) + radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2]; + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_set_register - write register + */ +static int si470x_set_register(struct si470x_device *radio, int regnr) +{ + int retval; + + radio->buf[0] = REGISTER_REPORT(regnr); + radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8; + radio->buf[2] = (radio->registers[regnr] & 0x00ff); + + retval = si470x_set_report(radio, REGISTER_REPORT_SIZE); + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_get_all_registers - read entire registers + */ +static int si470x_get_all_registers(struct si470x_device *radio) +{ + int retval; + int regnr; + + radio->buf[0] = ENTIRE_REPORT; + + retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); + + if (retval >= 0) + for (regnr = 0; regnr < FMRADIO_REGISTER_NUM; regnr++) + radio->registers[regnr] = + (radio->buf[regnr * FMRADIO_REGISTER_SIZE + 1] << 8) | + radio->buf[regnr * FMRADIO_REGISTER_SIZE + 2]; + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_get_rds_registers - read rds registers + */ +static int si470x_get_rds_registers(struct si470x_device *radio) +{ + int retval; + int regnr; + int size; + + radio->buf[0] = RDS_REPORT; + + retval = usb_interrupt_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 1), + radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); + + if (retval >= 0) { + for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { + radio->registers[STATUSRSSI + regnr] = + (radio->buf[regnr * FMRADIO_REGISTER_SIZE + 1] << 8) | + radio->buf[regnr * FMRADIO_REGISTER_SIZE + 2]; + } + } + + return (retval < 0) ? - EINVAL : 0; +} + + +/* + * si470x_start - switch on radio + */ +static int si470x_start(struct si470x_device *radio) +{ + int retval; + + /* powercfg */ + radio->registers[POWERCFG] = + POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + return retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] = + SYSCONFIG1_DE | SYSCONFIG1_RDS; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + return retval; + + /* sysconfig 2 */ + radio->registers[SYSCONFIG2] = + (0x3f << 8) | /* SEEKTH */ + (band << 6) | /* BAND */ + (space << 4) | /* SPACE */ + 15; /* VOLUME (max) */ + retval = si470x_set_register(radio, SYSCONFIG2); + if (retval < 0) + return retval; + + /* reset last channel */ + return si470x_set_chan(radio, + radio->registers[CHANNEL] & CHANNEL_CHAN); +} + + +/* + * si470x_stop - switch off radio + */ +static int si470x_stop(struct si470x_device *radio) +{ + /* powercfg */ + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + /* POWERCFG_ENABLE has to automatically go low */ + radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; + return si470x_set_register(radio, POWERCFG); +} + + +/* + * si470x_set_chan - set the channel + */ +static int si470x_set_chan(struct si470x_device *radio, int chan) +{ + int retval, i; + + /* start tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_CHAN; + radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; + retval = si470x_set_register(radio, CHANNEL); + if (retval < 0) + return retval; + + /* wait till seek operation has completed */ + i = 0; + do { + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + return retval; + } while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) && + (++i < seek_retries)); + if (i >= seek_retries) + printk(KERN_WARNING DRIVER_NAME + ": seek does not finish after %d tries\n", i); + + /* stop tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_TUNE; + return si470x_set_register(radio, CHANNEL); +} + + +/* + * si470x_get_freq - get the frequency + */ +static int si470x_get_freq(struct si470x_device *radio) +{ + int spacing, band_bottom, chan, freq; + int retval; + + /* Spacing (kHz) */ + switch (space) { + /* 0: 200 kHz (USA, Australia) */ + default: spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1 : spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + case 2 : spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch (band) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + default: band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1 : band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : band_bottom = 76 * FREQ_MUL; break; + }; + + /* read channel */ + retval = si470x_get_register(radio, READCHAN); + if (retval < 0) + return retval; + chan = radio->registers[READCHAN] & READCHAN_READCHAN; + + /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ + freq = chan * spacing + band_bottom; + + return freq; +} + + +/* + * si470x_set_freq - set the frequency + */ +static int si470x_set_freq(struct si470x_device *radio, int freq) +{ + int spacing, band_bottom, chan; + + /* Spacing (kHz) */ + switch (space) { + /* 0: 200 kHz (USA, Australia) */ + default: spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1 : spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + case 2 : spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch (band) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + default: band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1 : band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : band_bottom = 76 * FREQ_MUL; break; + }; + + /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ + chan = (freq - band_bottom) / spacing; + + return si470x_set_chan(radio, chan); +} + + + +/* + * si470x_rds - rds processing function + */ +static void si470x_rds(struct si470x_device *radio) +{ + unsigned long flags; + unsigned char tmpbuf[3]; + unsigned char blocknum; + unsigned char bler; /* RDS block errors */ + unsigned short rds; + unsigned int i; + + if (radio->users == 0) + return; + if (si470x_get_rds_registers(radio) < 0) + return; + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { + /* No RDS group ready */ + return; + } + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) { + /* RDS decoder not synchronized */ + return; + } + + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + tmpbuf[0] = rds & 0x00ff; /* LSB */ + tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + spin_lock_irqsave(&radio->lock, flags); + + /* copy RDS block to internal buffer */ + for (i = 0; i < 3; i++) { + radio->buffer[radio->wr_index] = tmpbuf[i]; + radio->wr_index++; + } + + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + if (radio->wr_index == radio->rd_index) { + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } else + radio->block_count++; + + spin_unlock_irqrestore(&radio->lock, flags); + } + + radio->data_available_for_read = 1; + wake_up_interruptible(&radio->read_queue); +} + + +/* + * si470x_timer - rds timer function + */ +static void si470x_timer(unsigned long data) +{ + struct si470x_device *radio = (struct si470x_device *) data; + + schedule_work(&radio->work); +} + + +/* + * si470x_timer - rds work function + */ +static void si470x_work(struct work_struct *work) +{ + struct si470x_device *radio = container_of(work, struct si470x_device, + work); + + if (radio->users == 0) + return; + + si470x_rds(radio); + mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time)); +} + + + +/************************************************************************** + * USB interface functions + **************************************************************************/ + +/* + * si470x_usb_driver_probe - probe for the device + */ +static int si470x_usb_driver_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct si470x_device *radio; + + if (!(radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL))) + return -ENOMEM; + if (!(radio->videodev = video_device_alloc())) { + kfree(radio); + return -ENOMEM; + } + memcpy(radio->videodev, &si470x_viddev_template, + sizeof(si470x_viddev_template)); + radio->users = 0; + radio->usbdev = interface_to_usbdev(intf); + video_set_drvdata(radio->videodev, radio); + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { + printk(KERN_WARNING DRIVER_NAME + ": Could not register video device\n"); + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + usb_set_intfdata(intf, radio); + + /* show some infos about the specific device */ + if (si470x_get_all_registers(radio) < 0) { + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + + /* check if firmware is current */ + if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) + < FMRADIO_SW_VERSION_CURRENT) { + printk(KERN_WARNING DRIVER_NAME + ": This driver is known to work with chip version %d, " + "but the device has firmware %d. If you have some " + "trouble using this driver, please report to V4L ML " + "at video4linux-list@redhat.com\n", + radio->registers[CHIPID] & CHIPID_FIRMWARE, + FMRADIO_SW_VERSION_CURRENT); + } + + /* set initial frequency */ + si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + + /* rds initialization */ + radio->buf_size = rds_buf * 3; + if (NULL == (radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL))) { + video_device_release(radio->videodev); + kfree(radio); + return -ENOMEM; + } + radio->block_count = 0; + radio->wr_index = 0; + radio->rd_index = 0; + radio->last_blocknum = 0xff; + init_waitqueue_head(&radio->read_queue); + radio->data_available_for_read = 0; + + /* prepare polling via eventd */ + INIT_WORK(&radio->work, si470x_work); + init_timer(&radio->timer); + radio->timer.function = si470x_timer; + radio->timer.data = (unsigned long) radio; + + return 0; +} + + +/* + * si470x_usb_driver_disconnect - disconnect the device + */ +static void si470x_usb_driver_disconnect(struct usb_interface *intf) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + del_timer_sync(&radio->timer); + flush_scheduled_work(); + + usb_set_intfdata(intf, NULL); + if (radio) { + video_unregister_device(radio->videodev); + kfree(radio->buffer); + kfree(radio); + } +} + + + +/************************************************************************** + * Video4Linux interface functions + **************************************************************************/ + +/* + * si470x_fops_read - read RDS data + */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct rds_command cmd; + unsigned long flags; + unsigned int i; + unsigned int rd_blocks; + + cmd.block_count = count / 3; /* each RDS block needs 3 bytes */ + cmd.result = 0; + cmd.buffer = buf; + cmd.instance = file; + + /* copy RDS block out of internal buffer */ + while (!radio->data_available_for_read) { + if (wait_event_interruptible(radio->read_queue, + radio->data_available_for_read) < 0) + return -EINTR; + } + + spin_lock_irqsave(&radio->lock, flags); + rd_blocks = cmd.block_count; + if (rd_blocks > radio->block_count) + rd_blocks = radio->block_count; + + if (!rd_blocks) { + spin_unlock_irqrestore(&radio->lock, flags); + return cmd.result; + } + + for (i = 0; i < rd_blocks; i++) { + /* copy RDS block to user buffer */ + if (radio->rd_index == radio->wr_index) + break; + + if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) + break; + + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + radio->block_count--; + + buf += 3; + cmd.result += 3; + } + radio->data_available_for_read = (radio->block_count > 0); + spin_unlock_irqrestore(&radio->lock, flags); + + return cmd.result; +} + + +/* + * si470x_fops_poll - poll RDS data + */ +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; + + retval = 0; + if (radio->data_available_for_read) + retval = POLLIN | POLLRDNORM; + poll_wait(file, &radio->read_queue, pts); + + return retval; +} + + +/* + * si470x_fops_open - file open + */ +static int si470x_fops_open(struct inode *inode, struct file *file) +{ + int retval; + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + radio->users++; + if (radio->users == 1) { + retval = si470x_start(radio); + if (retval < 0) + return retval; + + schedule_work(&radio->work); + } + + return 0; +} + + +/* + * si470x_fops_release - file release + */ +static int si470x_fops_release(struct inode *inode, struct file *file) +{ + int retval; + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (!radio) + return -ENODEV; + + radio->users--; + if (radio->users == 0) { + radio->data_available_for_read = 1; /* ? */ + wake_up_interruptible(&radio->read_queue); /* ? */ + + retval = si470x_stop(radio); + if (retval < 0) + return retval; + } + + return 0; +} + + +/* + * si470x_vidioc_querycap - query device capabilities + */ +static int si470x_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + sprintf(capability->bus_info, "USB"); + capability->version = DRIVER_VERSION; + capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + + return 0; +} + + +/* + * si470x_vidioc_g_input - get input + */ +static int si470x_vidioc_g_input(struct file *filp, void *priv, + unsigned int *i) +{ + *i = 0; + + return 0; +} + + +/* + * si470x_vidioc_s_input - set input + */ +static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + + return 0; +} + + +/* + * si470x_vidioc_queryctrl - enumerate control items + */ +static int si470x_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(radio_queryctrl); i++) { + if (qc->id && qc->id == radio_queryctrl[i].id) { + memcpy(qc, &(radio_queryctrl[i]), sizeof(*qc)); + return 0; + } + } + + return -EINVAL; +} + + +/* + * si470x_vidioc_g_ctrl - get the value of a control + */ +static int si470x_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = radio->registers[SYSCONFIG2] & + SYSCONFIG2_VOLUME; + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = ((radio->registers[POWERCFG] & + POWERCFG_DMUTE) == 0) ? 1 : 0; + break; + } + + return 0; +} + + +/* + * si470x_vidioc_s_ctrl - set the value of a control + */ +static int si470x_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; + radio->registers[SYSCONFIG2] |= ctrl->value; + return si470x_set_register(radio, SYSCONFIG2); + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value == 1) + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + else + radio->registers[POWERCFG] |= POWERCFG_DMUTE; + return si470x_set_register(radio, POWERCFG); + } + + return -EINVAL; +} + + +/* + * si470x_vidioc_g_audio - get audio attributes + */ +static int si470x_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index > 1) + return -EINVAL; + + strcpy(audio->name, "Radio"); + audio->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + + +/* + * si470x_vidioc_s_audio - set audio attributes + */ +static int si470x_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index != 0) + return -EINVAL; + + return 0; +} + + +/* + * si470x_vidioc_g_tuner - get tuner attributes + */ +static int si470x_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + int retval; + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (tuner->index > 0) + return -EINVAL; + + /* read status rssi */ + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + return retval; + + strcpy(tuner->name, "FM"); + tuner->type = V4L2_TUNER_RADIO; + switch(band) { + /* 0: 87.5 - 108 MHz (USA, Europe, default) */ + default: + tuner->rangelow = 87.5 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1 : + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 90 * FREQ_MUL; + break; + }; + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + tuner->capability = V4L2_TUNER_CAP_LOW; + + /* Stereo indicator == Stereo (instead of Mono) */ + if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1) + tuner->audmode = V4L2_TUNER_MODE_STEREO; + else + tuner->audmode = V4L2_TUNER_MODE_MONO; + + /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ + tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI) + * 0x0101; + + /* automatic frequency control: -1: freq to low, 1 freq to high */ + tuner->afc = 0; + + return 0; +} + + +/* + * si470x_vidioc_s_tuner - set tuner attributes + */ +static int si470x_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (tuner->index > 0) + return -EINVAL; + + if (tuner->audmode == V4L2_TUNER_MODE_MONO) + radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ + else + radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ + + return si470x_set_register(radio, POWERCFG); +} + + +/* + * si470x_vidioc_g_frequency - get tuner or modulator radio frequency + */ +static int si470x_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + freq->type = V4L2_TUNER_RADIO; + freq->frequency = si470x_get_freq(radio); + + return 0; +} + + +/* + * si470x_vidioc_s_frequency - set tuner or modulator radio frequency + */ +static int si470x_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (freq->type != V4L2_TUNER_RADIO) + return -EINVAL; + + return si470x_set_freq(radio, freq->frequency); +} + + + +/************************************************************************** + * Module interface definitions and functions + **************************************************************************/ + +/* + * si470x_module_init - module init + */ +static int __init si470x_module_init(void) +{ + printk(KERN_INFO DRIVER_DESC "\n"); + return usb_register(&si470x_usb_driver); +} + + +/* + * si470x_module_exit - module exit + */ +static void __exit si470x_module_exit(void) +{ + usb_deregister(&si470x_usb_driver); +} + + +module_init(si470x_module_init); +module_exit(si470x_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION("1.0.2"); -- cgit v1.2.3 From 387d447776484b6e1d08973337aa4c834ea7c6bc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Jan 2008 11:25:10 -0300 Subject: V4L/DVB (7039): Reorder headers The backports weren't tested, but compile fine. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si470x.c | 4 ++-- drivers/media/video/stk-webcam.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index eccbc750e14..ccb167a1acd 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -72,11 +72,11 @@ #include #include #include -#include -#include #include #include #include +#include +#include #include diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index f300eca3c47..d37e5e2594b 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -30,9 +30,9 @@ #include #include +#include #include #include -#include #include "stk-webcam.h" -- cgit v1.2.3 From dfc1c08aab447d49230dacb390d3f2263584d28f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 15 Jan 2008 21:35:22 -0300 Subject: V4L/DVB (7041): s5h1409: Bug fix for parallel support Parallel support was not working with the s5h1409 and the Pinnacle HD800i. This patch fixes the demodulator driver and ensures that all existing s5h1409 based products configure the demodulator correctly. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 51 ++++++++++++++++++++++++++----- drivers/media/dvb/frontends/s5h1409.h | 7 +++++ drivers/media/video/cx23885/cx23885-dvb.c | 15 ++++++--- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 3391777e0b2..819433485d3 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -98,7 +98,7 @@ static struct init_tab { { 0xac, 0x1003, }, { 0xad, 0x103f, }, { 0xe2, 0x0100, }, - { 0xe3, 0x0000, }, + { 0xe3, 0x1000, }, { 0x28, 0x1010, }, { 0xb1, 0x000e, }, }; @@ -441,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) dprintk("%s(%d)\n", __FUNCTION__, enable); if (enable) - return s5h1409_writereg(state, 0xe3, 0x1100); + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) | 0x1100); else - return s5h1409_writereg(state, 0xe3, 0x1000); + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) & 0xeeff); } static int s5h1409_sleep(struct dvb_frontend* fe, int enable) @@ -513,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) s5h1409_writereg(state, 0x96, 0x20); s5h1409_writereg(state, 0xad, ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); - s5h1409_writereg(state, 0xab, 0x1100); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xeffe); } } else { if (state->qam_state != 1) { state->qam_state = 1; s5h1409_writereg(state, 0x96, 0x08); - s5h1409_writereg(state, 0xab, 0x1101); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x1001); } } } @@ -556,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, return 0; } +static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __FUNCTION__, mode); + + val = s5h1409_readreg(state, 0xac) & 0xcfff; + switch (mode) { + case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + val |= 0x0000; + break; + case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode); + val |= 0x1000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + val |= 0x2000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + val |= 0x3000; + break; + default: + return -EINVAL; + } + + /* Configure MPEG Signal Timing charactistics */ + return s5h1409_writereg(state, 0xac, val); +} + /* Reset the demod hardware and reset all of the configuration registers to a default state. */ static int s5h1409_init (struct dvb_frontend* fe) @@ -575,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe) state->current_modulation = VSB_8; if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) - s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ else - s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ s5h1409_set_spectralinversion(fe, state->config->inversion); s5h1409_set_if_freq(fe, state->if_freq); s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); s5h1409_softreset(fe); /* Note: Leaving the I2C gate closed. */ diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index b1f43390666..f0bb13fe808 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -51,6 +51,13 @@ struct s5h1409_config #define S5H1409_TUNERLOCKING 0 #define S5H1409_DEMODLOCKING 1 u8 status_mode; + + /* MPEG signal timing */ +#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 +#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 +#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 +#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 + u16 mpeg_timing; }; #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 34910368049..21937d5cbb1 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -126,7 +126,8 @@ static struct s5h1409_config hauppauge_generic_config = { .gpio = S5H1409_GPIO_ON, .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_ezqam_config = { @@ -135,7 +136,8 @@ static struct s5h1409_config hauppauge_ezqam_config = { .gpio = S5H1409_GPIO_OFF, .qam_if = 4000, .inversion = S5H1409_INVERSION_ON, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1800lp_config = { @@ -144,7 +146,8 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = { .gpio = S5H1409_GPIO_OFF, .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1500_config = { @@ -152,7 +155,8 @@ static struct s5h1409_config hauppauge_hvr1500_config = { .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct mt2131_config hauppauge_generic_tunerconfig = { @@ -171,7 +175,8 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { .gpio = S5H1409_GPIO_ON, .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { -- cgit v1.2.3 From 27c685a4b09b5e391023d769cddb97e4fcb3b9e1 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 16:50:14 -0300 Subject: V4L/DVB (7042): xc5000: Tuner analog support From Zhang: This an updated patch that adds analog support for the xc5000 tuner driver. it was tested on a Pinnacle PCTV HD 800i card (patches to follow). Patch commited as-is, cleanup to follow ... Steve. Signed-off-by: Chaogui Zhang Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 1 + drivers/media/dvb/frontends/xc5000.c | 213 ++++++++++++++++++++++++++----- drivers/media/dvb/frontends/xc5000.h | 12 +- drivers/media/video/tuner-core.c | 20 +++ drivers/media/video/tuner-types.c | 4 + include/media/tuner.h | 1 + 6 files changed, 213 insertions(+), 38 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 2211c8eac64..0e2394695bb 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -73,3 +73,4 @@ tuner=71 - Xceive xc2028/xc3028 tuner tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio +tuner=76 - Xceive 5000 tuner diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index a036530ee4b..28048d5307a 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,10 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define XC_RESULT_I2C_READ_FAILURE 3 #define XC_RESULT_OUT_OF_RANGE 5 +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_FW_LOADED 0x1388 + /* Registers */ #define XREG_INIT 0x00 #define XREG_VIDEO_MODE 0x01 @@ -122,7 +127,29 @@ typedef struct { } XC_TV_STANDARD; /* Tuner standards */ -#define DTV6 17 +#define MN_NTSC_PAL_BTSC 0 +#define MN_NTSC_PAL_A2 1 +#define MN_NTSC_PAL_EIAJ 2 +#define MN_NTSC_PAL_Mono 3 +#define BG_PAL_A2 4 +#define BG_PAL_NICAM 5 +#define BG_PAL_MONO 6 +#define I_PAL_NICAM 7 +#define I_PAL_NICAM_MONO 8 +#define DK_PAL_A2 9 +#define DK_PAL_NICAM 10 +#define DK_PAL_MONO 11 +#define DK_SECAM_A2DK1 12 +#define DK_SECAM_A2LDK3 13 +#define DK_SECAM_A2MONO 14 +#define L_SECAM_NICAM 15 +#define LC_SECAM_NICAM 16 +#define DTV6 17 +#define DTV8 18 +#define DTV7_8 19 +#define DTV7 20 +#define FM_Radio_INPUT2 21 +#define FM_Radio_INPUT1 22 XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, @@ -184,12 +211,13 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) dprintk(1, "%s()\n", __FUNCTION__); - if (priv->cfg->tuner_reset) { - ret = priv->cfg->tuner_reset(fe); + if (priv->cfg->tuner_callback) { + ret = priv->cfg->tuner_callback(priv->cfg->video_dev, + XC5000_TUNER_RESET, 0); if (ret) printk(KERN_ERR "xc5000: reset failed\n"); } else - printk(KERN_ERR "xc5000: no tuner reset function, fatal\n"); + printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); } static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) @@ -259,7 +287,6 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[]) index=0; while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { - len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; if (len == 0x0000) { /* RESET command */ @@ -311,7 +338,7 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, u16 VideoMode, u16 AudioMode) { int ret; - dprintk(1, "%s(%d,%d)\n", __FUNCTION__, VideoMode, AudioMode); + dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode); dprintk(1, "%s() Standard = %s\n", __FUNCTION__, XC5000_Standard[priv->video_standard].Name); @@ -325,7 +352,11 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, static int xc_shutdown(struct xc5000_priv *priv) { - return xc_write_reg(priv, XREG_POWER_DOWN, 0); + return 0; + /* Fixme: cannot bring tuner back alive once shutdown + * without reloading the driver modules. + * return xc_write_reg(priv, XREG_POWER_DOWN, 0); + */ } static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) @@ -349,7 +380,7 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) { u16 freq_code; - dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); + dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || (freq_hz < xc5000_tuner_ops.info.frequency_min)) @@ -457,7 +488,7 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) { int found = 0; - dprintk(1, "%s(%d)\n", __FUNCTION__, freq_hz); + dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) return 0; @@ -480,7 +511,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) }; if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "xc5000 I2C read failed\n"); + printk(KERN_WARNING "xc5000: I2C read failed\n"); return -EREMOTEIO; } @@ -494,7 +525,7 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) .flags = 0, .buf = buf, .len = len }; if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C write failed (len=%i)\n", + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", (int)len); return -EREMOTEIO; } @@ -519,16 +550,11 @@ static int xc5000_fwupload(struct dvb_frontend* fe) const struct firmware *fw; int ret; - if (!priv->cfg->request_firmware) { - printk(KERN_ERR "xc5000: no firmware callback, fatal\n"); - return -EIO; - } - /* request the firmware, this will block and timeout */ printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", XC5000_DEFAULT_FIRMWARE); - ret = priv->cfg->request_firmware(fe, &fw, XC5000_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; @@ -601,7 +627,6 @@ static int xc5000_set_params(struct dvb_frontend *fe, dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); - switch(params->u.vsb.modulation) { case VSB_8: case VSB_16: @@ -658,6 +683,93 @@ static int xc5000_set_params(struct dvb_frontend *fe, return 0; } +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); + +static int xc5000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + if(priv->fwloaded == 0) + xc_load_fw_and_init_tuner(fe); + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __FUNCTION__, params->frequency); + + priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */ + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + /* FIX ME: Some video standards may have several possible audio + standards. We simply default to one of them here. + */ + if(params->std & V4L2_STD_MN) { + /* default to BTSC audio standard */ + priv->video_standard = MN_NTSC_PAL_BTSC; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_BG) { + /* default to NICAM audio standard */ + priv->video_standard = BG_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + priv->video_standard = I_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_DK) { + /* default to NICAM audio standard */ + priv->video_standard = DK_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_DK) { + /* default to A2 DK1 audio standard */ + priv->video_standard = DK_SECAM_A2DK1; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_L) { + priv->video_standard = L_SECAM_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_LC) { + priv->video_standard = LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + xc_tune_channel(priv, priv->freq_hz); + + if (debug) + xc_debug_dump(priv); + + return 0; +} + static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; @@ -670,6 +782,7 @@ static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) { struct xc5000_priv *priv = fe->tuner_priv; dprintk(1, "%s()\n", __FUNCTION__); + *bw = priv->bandwidth; return 0; } @@ -691,13 +804,12 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; - int ret; + int ret = 0; if (priv->fwloaded == 0) { ret = xc5000_fwupload(fe); if (ret != XC_RESULT_SUCCESS) return ret; - priv->fwloaded = 1; } @@ -720,9 +832,27 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) static int xc5000_sleep(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; + int ret; + dprintk(1, "%s()\n", __FUNCTION__); - return xc_shutdown(priv); + /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized + * once shutdown without reloading the driver. Maybe I am not + * doing something right. + * + */ + + ret = xc_shutdown(priv); + if(ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __FUNCTION__); + return -EREMOTEIO; + } + else { + /* priv->fwloaded = 0; */ + return XC_RESULT_SUCCESS; + } } static int xc5000_init(struct dvb_frontend *fe) @@ -757,14 +887,15 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .frequency_step = 50000, }, - .release = xc5000_release, - .init = xc5000_init, - .sleep = xc5000_sleep, + .release = xc5000_release, + .init = xc5000_init, + .sleep = xc5000_sleep, - .set_params = xc5000_set_params, - .get_frequency = xc5000_get_frequency, - .get_bandwidth = xc5000_get_bandwidth, - .get_status = xc5000_get_status + .set_params = xc5000_set_params, + .set_analog_params = xc5000_set_analog_params, + .get_frequency = xc5000_get_frequency, + .get_bandwidth = xc5000_get_bandwidth, + .get_status = xc5000_get_status }; struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, @@ -783,14 +914,33 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, priv->cfg = cfg; priv->bandwidth = BANDWIDTH_6_MHZ; priv->i2c = i2c; - priv->fwloaded = 0; + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { kfree(priv); return NULL; } - if ((id != 0x2000) && (id != 0x1388)) { + switch(id) { + case XC_PRODUCT_ID_FW_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has been loaded previously\n"); + priv->fwloaded = 1; + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has not been loaded previously\n"); + priv->fwloaded = 0; + break; + default: printk(KERN_ERR "xc5000: Device not found at addr 0x%02x (0x%x)\n", cfg->i2c_address, id); @@ -798,9 +948,6 @@ struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, return NULL; } - printk(KERN_INFO "xc5000: successfully identified at address 0x%02x\n", - cfg->i2c_address); - memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, sizeof(struct dvb_tuner_ops)); diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h index 941b3194813..85b2d438fa4 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/dvb/frontends/xc5000.h @@ -28,13 +28,15 @@ struct dvb_frontend; struct i2c_adapter; struct xc5000_config { - u8 i2c_address; - u32 if_khz; - int (*request_firmware)(struct dvb_frontend *fe, - const struct firmware **fw, char *name); - int (*tuner_reset)(struct dvb_frontend* fe); + u8 i2c_address; + u32 if_khz; + void *video_dev; + int (*tuner_callback) (void *dev, int command, int arg); }; +/* xc5000 callback command */ +#define XC5000_TUNER_RESET 0 + #if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 35976e6cb1b..16cdeeafeb6 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -27,6 +27,7 @@ #include "tuner-xc2028.h" #include "tuner-simple.h" #include "tda9887.h" +#include "xc5000.h" #define UNSET (-1U) @@ -329,6 +330,8 @@ static void attach_tda829x(struct tuner *t) tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } +static struct xc5000_config xc5000_cfg; + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) @@ -428,6 +431,23 @@ static void set_type(struct i2c_client *c, unsigned int type, case TUNER_TDA9887: tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); break; + case TUNER_XC5000: + xc5000_cfg.i2c_address = t->i2c->addr; + xc5000_cfg.if_khz = 5380; + xc5000_cfg.video_dev = c->adapter->algo_data; + xc5000_cfg.tuner_callback = t->tuner_callback; + if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + { + struct dvb_tuner_ops *xc_tuner_ops; + xc_tuner_ops = &t->fe.ops.tuner_ops; + if(xc_tuner_ops->init != NULL) + xc_tuner_ops->init(&t->fe); + } + break; default: attach_simple_tuner(t); break; diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index e2cd05a0580..883047f9c28 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1475,6 +1475,10 @@ struct tunertype tuners[] = { .name = "Philips TEA5761 FM Radio", /* see tea5767.c for details */ }, + [TUNER_XC5000] = { /* Xceive 5000 */ + .name = "Xceive 5000 tuner", + /* see xc5000.c for details */ + }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/include/media/tuner.h b/include/media/tuner.h index 97be269afbe..1bf24a6ed8f 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -121,6 +121,7 @@ #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ #define TUNER_TDA9887 74 /* This tuner should be used only internally */ #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ +#define TUNER_XC5000 76 /* Xceive Silicon Tuner */ /* tv card specific */ #define TDA9887_PRESENT (1<<0) -- cgit v1.2.3 From 60464da8b1ed8d7c19563f58cadb0ca990448a36 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 16:53:01 -0300 Subject: V4L/DVB (7043): New card supported(partially): Pinnacle 800i From Zhang: This patch continues the support for the Pinnacle HD 800i. Patch committed as-is, cleanups to follow ... Steve Signed-off-by: Chaogui Zhang Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 1 + drivers/media/video/cx88/cx88-cards.c | 63 +++++++++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-dvb.c | 36 +++++++++++++++++++ drivers/media/video/cx88/cx88-i2c.c | 17 ++++----- drivers/media/video/cx88/cx88-mpeg.c | 7 +++- drivers/media/video/cx88/cx88.h | 2 ++ 6 files changed, 117 insertions(+), 9 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 82ac8250e97..bc5593bd970 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -56,3 +56,4 @@ 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980] 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602] 57 -> ADS Tech Instant Video PCI [1421:0390] + 58 -> Pinnacle PCTV HD 800i [11bd:0051] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index d484e5ce579..3ba31572c65 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1375,6 +1375,32 @@ static const struct cx88_board cx88_boards[] = { .gpio0 = 0x07fa, }}, }, + [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { + .name = "Pinnacle PCTV HD 800i", + .tuner_type = TUNER_XC5000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x04fb, + .gpio1 = 0x10ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + }}, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -1684,6 +1710,10 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x1421, .subdevice = 0x0390, .card = CX88_BOARD_ADSTECH_PTV_390, + },{ + .subvendor = 0x11bd, + .subdevice = 0x0051, + .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, }, }; @@ -1850,6 +1880,39 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) } } +/* ----------------------------------------------------------------------- */ +/* Tuner callback function. Currently only needed for the Pinnacle * + * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * + * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ + +int cx88_tuner_callback(void *i2c_algo, int command, int arg) +{ + struct i2c_algo_bit_data *algo = i2c_algo; + struct cx88_core *core = algo->data; + + switch(core->boardnr) { + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + if(command == 0) { /* This is the reset command from xc5000 */ + /* Reset XC5000 tuner via GPIO pin #2 */ + cx_set(MO_GP0_IO, 0x00000400); + cx_clear(MO_GP0_IO, 0x00000004); + mdelay(200); + cx_set(MO_GP0_IO, 0x00000004); + printk(KERN_ERR "xc5000: in reset for xc5000\n"); + mdelay(200); + return 0; + } + else { + printk(KERN_ERR + "xc5000: unknown tuner callback command.\n"); + return -EINVAL; + } + break; + } + return 0; /* Should never be here */ +} +EXPORT_SYMBOL(cx88_tuner_callback); + /* ----------------------------------------------------------------------- */ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index fce19caf9d0..0246f97a998 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -40,6 +40,8 @@ #include "cx22702.h" #include "or51132.h" #include "lgdt330x.h" +#include "s5h1409.h" +#include "xc5000.h" #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" @@ -371,6 +373,22 @@ static struct cx24123_config kworld_dvbs_100_config = { .lnb_polarity = 1, }; +static struct s5h1409_config pinnacle_pctv_hd_800i_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, +}; + +static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { + .i2c_address = 0x64, + .if_khz = 5380, + /* cannot set .video_dev here, do it right before attach */ + .tuner_callback = cx88_tuner_callback, +}; + static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ @@ -625,6 +643,24 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + /* Parallel mpeg data port and punctured clock mode */ + dev->ts_gen_cntrl = 0x04; + + dev->dvb.frontend = dvb_attach(s5h1409_attach, + &pinnacle_pctv_hd_800i_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + /* tuner_config.video_dev must point to + * i2c_adap.algo_data + */ + pinnacle_pctv_hd_800i_tuner_config.video_dev = + dev->core->i2c_adap.algo_data; + dvb_attach(xc5000_attach, dev->dvb.frontend, + &dev->core->i2c_adap, + &pinnacle_pctv_hd_800i_tuner_config); + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 937497c8624..566b26af523 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -109,20 +109,20 @@ static int attach_inform(struct i2c_client *client) if (core->board.radio_type != UNSET) { if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } if (core->board.tuner_type != UNSET) { if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } @@ -182,6 +182,7 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0xc2 >> 1 ] = "tuner (analog/dvb)", + [ 0xc8 >> 1 ] = "xc5000", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 339a88a64f5..a21b50357a8 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); + cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: @@ -117,6 +117,11 @@ static int cx8802_start_dma(struct cx8802_dev *dev, break; case CX88_BOARD_HAUPPAUGE_HVR1300: break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + /* Enable MPEG parallel port */ + cx_write(MO_PINMUX_IO, 0x80); + udelay(100); + break; default: cx_write(TS_SOP_STAT, 0x00); break; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0cd2946a278..4e823f2a539 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -210,6 +210,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 #define CX88_BOARD_HAUPPAUGE_HVR1300 56 #define CX88_BOARD_ADSTECH_PTV_390 57 +#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -589,6 +590,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ +extern int cx88_tuner_callback(void *dev, int command, int arg); extern int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci); extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); -- cgit v1.2.3 From 8c70017f5793e68ea48085a65008d713c9a85dde Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 16:55:45 -0300 Subject: V4L/DVB (7044): XC5000: Fix support for HVR1500Q broken by patch 1 From Zhang: This patch fixes support for the HVR1500Q which was broken when the xc5000 analog patch was added. Patch committed as-is, cleanups to follows .... Steve Signed-off-by: Chaogui Zhang Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 28 +++++++++++++++++++++++ drivers/media/video/cx23885/cx23885-dvb.c | 35 ++++++----------------------- drivers/media/video/cx23885/cx23885.h | 1 + 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index c2d5a4d7228..ee3f1b09914 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -244,6 +244,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } +/* Tuner callback function for cx23885 boards. Currently only needed + * for HVR1500Q, which has an xc5000 tuner. + */ +int cx23885_tuner_callback(void *i2c_bus, int command, int arg) +{ + struct cx23885_i2c *bus = i2c_bus; + struct cx23885_dev *dev = bus->dev; + + switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + if(command == 0) { /* Tuner Reset Command from xc5000 */ + /* Drive the tuner into reset and out */ + cx_clear(GP0_IO, 0x00000004); + mdelay(200); + cx_set(GP0_IO, 0x00000004); + return 0; + } + else { + printk(KERN_ERR + "%s(): Unknow command.\n", __FUNCTION__); + return -EINVAL; + } + break; + } + + return 0; /* Should never be here */ +} +EXPORT_SYMBOL(cx23885_tuner_callback); void cx23885_gpio_setup(struct cx23885_dev *dev) { switch(dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 21937d5cbb1..61d75d04db8 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -87,32 +87,6 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer*)vb); } -static int cx23885_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct cx23885_tsport *port = fe->dvb->priv; - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s(?,?,%s)\n", __FUNCTION__, name); - - return request_firmware(fw, name, &dev->pci->dev); -} - -static int hauppauge_hvr1500q_tuner_reset(struct dvb_frontend *fe) -{ - struct cx23885_tsport *port = fe->dvb->priv; - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s()\n", __FUNCTION__); - - /* Drive the tuner into reset back back */ - cx_clear(GP0_IO, 0x00000004); - mdelay(200); - cx_set(GP0_IO, 0x00000004); - - return 0; -} - static struct videobuf_queue_ops dvb_qops = { .buf_setup = dvb_buf_setup, .buf_prepare = dvb_buf_prepare, @@ -182,8 +156,8 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, - .request_firmware = cx23885_request_firmware, - .tuner_reset = hauppauge_hvr1500q_tuner_reset + /* cannot set .video_dev here, do it before attach. */ + .tuner_callback = cx23885_tuner_callback }; static struct tda829x_config tda829x_no_probe = { @@ -308,6 +282,11 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1500q_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { + /* tunerconfig.video_dev must point to + * i2c_adap.algo_data + */ + hauppauge_hvr1500q_tunerconfig.video_dev = + i2c_bus->i2c_adap.algo_data; dvb_attach(xc5000_attach, port->dvb.frontend, &i2c_bus->i2c_adap, &hauppauge_hvr1500q_tunerconfig); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 390f9335bdc..ac9a76624e9 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -393,6 +393,7 @@ extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; +extern int cx23885_tuner_callback(void *i2c_bus, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); -- cgit v1.2.3 From 73c993a8294077ae1b724286da8ac323c25d90db Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 5 Jan 2008 17:08:05 -0300 Subject: V4L/DVB (7045): xc5000: Small amount of cleanup and commenting xc5000: Small amount of cleanup and commenting, just for clarification. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.c | 4 ++-- drivers/media/dvb/frontends/xc5000.h | 12 ++++++++++-- drivers/media/video/cx23885/cx23885-cards.c | 6 +++--- drivers/media/video/cx23885/cx23885-dvb.c | 7 +------ drivers/media/video/cx23885/cx23885.h | 2 +- drivers/media/video/cx88/cx88-cards.c | 7 +++---- drivers/media/video/cx88/cx88-dvb.c | 3 +-- drivers/media/video/tuner-core.c | 2 +- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index 28048d5307a..a0705a640ba 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include @@ -212,7 +212,7 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) dprintk(1, "%s()\n", __FUNCTION__); if (priv->cfg->tuner_callback) { - ret = priv->cfg->tuner_callback(priv->cfg->video_dev, + ret = priv->cfg->tuner_callback(priv->cfg->priv, XC5000_TUNER_RESET, 0); if (ret) printk(KERN_ERR "xc5000: reset failed\n"); diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h index 85b2d438fa4..e0e84562aed 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/dvb/frontends/xc5000.h @@ -30,8 +30,16 @@ struct i2c_adapter; struct xc5000_config { u8 i2c_address; u32 if_khz; - void *video_dev; - int (*tuner_callback) (void *dev, int command, int arg); + + /* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast priv accordingly. + * The xc5000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + void *priv; + int (*tuner_callback) (void *priv, int command, int arg); }; /* xc5000 callback command */ diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index ee3f1b09914..2d414dad5c3 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -247,9 +247,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) /* Tuner callback function for cx23885 boards. Currently only needed * for HVR1500Q, which has an xc5000 tuner. */ -int cx23885_tuner_callback(void *i2c_bus, int command, int arg) +int cx23885_tuner_callback(void *priv, int command, int arg) { - struct cx23885_i2c *bus = i2c_bus; + struct cx23885_i2c *bus = priv; struct cx23885_dev *dev = bus->dev; switch(dev->board) { @@ -271,7 +271,7 @@ int cx23885_tuner_callback(void *i2c_bus, int command, int arg) return 0; /* Should never be here */ } -EXPORT_SYMBOL(cx23885_tuner_callback); + void cx23885_gpio_setup(struct cx23885_dev *dev) { switch(dev->board) { diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 61d75d04db8..ed465c007ce 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -156,7 +156,6 @@ static struct s5h1409_config hauppauge_hvr1500q_config = { static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, - /* cannot set .video_dev here, do it before attach. */ .tuner_callback = cx23885_tuner_callback }; @@ -282,11 +281,7 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1500q_config, &dev->i2c_bus[0].i2c_adap); if (port->dvb.frontend != NULL) { - /* tunerconfig.video_dev must point to - * i2c_adap.algo_data - */ - hauppauge_hvr1500q_tunerconfig.video_dev = - i2c_bus->i2c_adap.algo_data; + hauppauge_hvr1500q_tunerconfig.priv = i2c_bus; dvb_attach(xc5000_attach, port->dvb.frontend, &i2c_bus->i2c_adap, &hauppauge_hvr1500q_tunerconfig); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index ac9a76624e9..7cb2179f262 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -393,7 +393,7 @@ extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; -extern int cx23885_tuner_callback(void *i2c_bus, int command, int arg); +extern int cx23885_tuner_callback(void *priv, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 3ba31572c65..254290975cd 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1885,10 +1885,10 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ -int cx88_tuner_callback(void *i2c_algo, int command, int arg) +int cx88_tuner_callback(void *priv, int command, int arg) { - struct i2c_algo_bit_data *algo = i2c_algo; - struct cx88_core *core = algo->data; + struct i2c_algo_bit_data *i2c_algo = priv; + struct cx88_core *core = i2c_algo->data; switch(core->boardnr) { case CX88_BOARD_PINNACLE_PCTV_HD_800i: @@ -1898,7 +1898,6 @@ int cx88_tuner_callback(void *i2c_algo, int command, int arg) cx_clear(MO_GP0_IO, 0x00000004); mdelay(200); cx_set(MO_GP0_IO, 0x00000004); - printk(KERN_ERR "xc5000: in reset for xc5000\n"); mdelay(200); return 0; } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 0246f97a998..c852efca159 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -385,7 +385,6 @@ static struct s5h1409_config pinnacle_pctv_hd_800i_config = { static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { .i2c_address = 0x64, .if_khz = 5380, - /* cannot set .video_dev here, do it right before attach */ .tuner_callback = cx88_tuner_callback, }; @@ -654,7 +653,7 @@ static int dvb_register(struct cx8802_dev *dev) /* tuner_config.video_dev must point to * i2c_adap.algo_data */ - pinnacle_pctv_hd_800i_tuner_config.video_dev = + pinnacle_pctv_hd_800i_tuner_config.priv = dev->core->i2c_adap.algo_data; dvb_attach(xc5000_attach, dev->dvb.frontend, &dev->core->i2c_adap, diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 16cdeeafeb6..8e406b168d7 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -434,7 +434,7 @@ static void set_type(struct i2c_client *c, unsigned int type, case TUNER_XC5000: xc5000_cfg.i2c_address = t->i2c->addr; xc5000_cfg.if_khz = 5380; - xc5000_cfg.video_dev = c->adapter->algo_data; + xc5000_cfg.priv = c->adapter->algo_data; xc5000_cfg.tuner_callback = t->tuner_callback; if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { t->type = TUNER_ABSENT; -- cgit v1.2.3 From 4917019d190d9809287308c4866cbc47d6c1000b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 15 Jan 2008 21:57:14 -0300 Subject: V4L/DVB (7046): Finalise support for the Pinnacle HD 8000i Correctly set the atatch structures, enable IR, configure the xc5000 tuner includes. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.c | 2 +- drivers/media/video/cx88/cx88-dvb.c | 4 +--- drivers/media/video/cx88/cx88-input.c | 2 ++ drivers/media/video/cx88/cx88-mpeg.c | 8 ++++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index a0705a640ba..a13027e09cd 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c852efca159..f7b41eb1bb5 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -380,6 +380,7 @@ static struct s5h1409_config pinnacle_pctv_hd_800i_config = { .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, }; static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { @@ -643,9 +644,6 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: - /* Parallel mpeg data port and punctured clock mode */ - dev->ts_gen_cntrl = 0x04; - dev->dvb.frontend = dvb_attach(s5h1409_attach, &pinnacle_pctv_hd_800i_config, &dev->core->i2c_adap); diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index e52de3968c6..f79a1c77414 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -224,6 +224,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_PINNACLE_PCTV_HD_800i: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; @@ -443,6 +444,7 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_PINNACLE_PCTV_HD_800i: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index a21b50357a8..0aedbeaf94c 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -118,8 +118,12 @@ static int cx8802_start_dma(struct cx8802_dev *dev, case CX88_BOARD_HAUPPAUGE_HVR1300: break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: - /* Enable MPEG parallel port */ - cx_write(MO_PINMUX_IO, 0x80); + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); + cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4)); + dev->ts_gen_cntrl = 5; + cx_write(TS_SOP_STAT, 0); + cx_write(TS_VALERR_CNTRL, 0); udelay(100); break; default: -- cgit v1.2.3 From 4e8a23ea3c1333561f8d0f5daee53feee3e85b8a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 17 Jan 2008 14:54:53 -0300 Subject: V4L/DVB (7047): fix broken build when CONFIG_USB_SI470X is set Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index f36cf4e63b6..a30159f6fa4 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -21,6 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o obj-$(CONFIG_USB_DSBR) += dsbr100.o -obj-$(CONFIG_USB_SI470X) := radio-si470x.o +obj-$(CONFIG_USB_SI470X) += radio-si470x.o EXTRA_CFLAGS += -Isound -- cgit v1.2.3 From 3473e342d79be938497a31caedd3c4e8d562485f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 Jan 2008 10:45:47 -0300 Subject: V4L/DVB (7051): Cleans up error handling on or51xxx_attach state is already NULL. Reviewed-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/or51132.c | 6 +----- drivers/media/dvb/frontends/or51211.c | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index b314a1f2dee..1d2d28ce823 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, /* Allocate memory for the internal state */ state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL); if (state == NULL) - goto error; + return NULL; /* Setup the state */ state->config = config; @@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops or51132_ops = { diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index f02bd944595..6a6b0d727c6 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, /* Allocate memory for the internal state */ state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL); if (state == NULL) - goto error; + return NULL; /* Setup the state */ state->config = config; @@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops or51211_ops = { -- cgit v1.2.3 From ed73683f06475531fb39e7ae9afe3011e4c5f8c1 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 19 Jan 2008 17:41:04 -0300 Subject: V4L/DVB (7052): tda18271: when tuning digital, the analog demod must be tri-stated Call analog_ops.standby during tda18271_set_params, to put the tda8295 in tri-state when tuning digital channels. Otherwise the tda8295 will interfere with the signal coming from the tda18271 into the digital demodulator. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda18271-fe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c index dd3657e459b..dfe72aaec38 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -836,7 +836,6 @@ static int tda18271_set_params(struct dvb_frontend *fe, priv->mode = TDA18271_DIGITAL; - /* see table 22 */ if (fe->ops.info.type == FE_ATSC) { switch (params->u.vsb.modulation) { case VSB_8: @@ -884,6 +883,10 @@ static int tda18271_set_params(struct dvb_frontend *fe, return -EINVAL; } + /* When tuning digital, the analog demod must be tri-stated */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0); if (ret < 0) -- cgit v1.2.3 From 8cb9329309cfc6c922f46bfe05ed6f40d5b1cb56 Mon Sep 17 00:00:00 2001 From: Luca Olivetti Date: Sun, 20 Jan 2008 17:56:43 -0300 Subject: V4L/DVB (7054): ansonic branded dvb-t usb stick support in the af9005 driver Marcos Melero (marcosmelero at gmail.com) reported he could make his dvb-t usb stick work with the af9005 driver by changing the device ids (10b9:6000). The stick is branded "Ansonic" (one of the brands of a spanish chain of supermarkets) with no other identification of the model. Since neither Marcos nor me know the OEM for the stick, in the attached patch I used Ansonic for the ids/description. Signed-off-by: Luca Olivetti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9005.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index 7db6eee50e3..e7f76f515b4 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf, static struct usb_device_id af9005_usb_table[] = { {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, {0}, }; @@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = { .rc_key_map_size = 0, .rc_query = af9005_rc_query, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { {.name = "Afatech DVB-T USB1.1 stick", .cold_ids = {&af9005_usb_table[0], NULL}, @@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = { .cold_ids = {&af9005_usb_table[1], NULL}, .warm_ids = {NULL}, }, + {.name = "Ansonic DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[2], NULL}, + .warm_ids = {NULL}, + }, {NULL}, } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index c94d993a6ef..aee5a6ef821 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -15,6 +15,7 @@ #define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 +#define USB_VID_ANSONIC 0x10b9 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b @@ -53,6 +54,7 @@ #define USB_PID_ADSTECH_USB2_WARM 0xa334 #define USB_PID_AFATECH_AF9005 0x9020 #define USB_VID_ALINK_DTU 0xf170 +#define USB_PID_ANSONIC_DVBT_USB 0x6000 #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 -- cgit v1.2.3 From 0f2ce9834246519e483e89dbc7225fe1fcbd30a8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 21 Jan 2008 10:55:37 -0300 Subject: V4L/DVB (7055): make tuner names consistent with standard cases Change TDA9887 to tda9887. TDA8290 shall reflect the actual hardware present in its name, ie: tda8295+18271 tda8290+8275a Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 8 ++------ drivers/media/video/tda9887.c | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 3e593a3d903..55bc89a6f06 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -645,9 +645,6 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) } static struct analog_demod_ops tda8290_ops = { - .info = { - .name = "TDA8290", - }, .set_params = tda8290_set_params, .has_signal = tda8290_has_signal, .standby = tda8290_standby, @@ -656,9 +653,6 @@ static struct analog_demod_ops tda8290_ops = { }; static struct analog_demod_ops tda8295_ops = { - .info = { - .name = "TDA8295", - }, .set_params = tda8295_set_params, .has_signal = tda8295_has_signal, .standby = tda8295_standby, @@ -731,6 +725,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, } tuner_info("type set to %s\n", name); + fe->ops.analog_ops.info.name = name; + if (priv->ver & TDA8290) { tda8290_init_tuner(fe); tda8290_init_if(fe); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d3aabe2d146..106c93b8203 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -650,7 +650,7 @@ static void tda9887_release(struct dvb_frontend *fe) static struct analog_demod_ops tda9887_ops = { .info = { - .name = "TDA9887", + .name = "tda9887", }, .set_params = tda9887_set_params, .standby = tda9887_standby, -- cgit v1.2.3 From 1641002bf56c1da265f2c49ea1c29baba997e63b Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 21 Jan 2008 12:01:34 -0300 Subject: V4L/DVB (7056): tuner: suppress obsolete tuner i2c address warning for XC5000 tuners We already know that the XC5000 tuner can only be located at i2c address 0x61, 0x62, 0x63 or 0x64 We shouldn't display this warning if the XC5000 tuner is present. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 8e406b168d7..ba538f6fbcc 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -297,6 +297,12 @@ static void tuner_i2c_address_check(struct tuner *t) ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f))) return; + /* We already know that the XC5000 can only be located at + * i2c address 0x61, 0x62, 0x63 or 0x64 */ + if ((t->type == TUNER_XC5000) && + ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61)) + return; + tuner_warn("====================== WARNING! ======================\n"); tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); tuner_warn("will soon be dropped. This message indicates that your\n"); -- cgit v1.2.3 From 9121106a7f149f9702ed7c2ac0d86e9feb54ede8 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 22 Jan 2008 01:00:33 -0300 Subject: V4L/DVB (7058): IR corrections for the Pinnacle 800i IR corrections for the Pinnacle 800i Signed-off-by: Steven Toth Signed-off-by: Chaogui Zhang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/ir-keymaps.c | 35 +++++++++++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-input.c | 6 +++++- include/media/ir-common.h | 1 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index ee2c69e3152..a4a937c9053 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1849,6 +1849,41 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); +/* Pinnacle PCTV HD 800i mini remote */ +IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = { + + [0x0f] = KEY_1, + [0x15] = KEY_2, + [0x10] = KEY_3, + [0x18] = KEY_4, + [0x1b] = KEY_5, + [0x1e] = KEY_6, + [0x11] = KEY_7, + [0x21] = KEY_8, + [0x12] = KEY_9, + [0x27] = KEY_0, + + [0x24] = KEY_ZOOM, + [0x2a] = KEY_SUBTITLE, + + [0x00] = KEY_MUTE, + [0x01] = KEY_ENTER, /* Pinnacle Logo */ + [0x39] = KEY_POWER, + + [0x03] = KEY_VOLUMEUP, + [0x09] = KEY_VOLUMEDOWN, + [0x06] = KEY_CHANNELUP, + [0x0c] = KEY_CHANNELDOWN, + + [0x2d] = KEY_REWIND, + [0x30] = KEY_PLAYPAUSE, + [0x33] = KEY_FASTFORWARD, + [0x3c] = KEY_STOP, + [0x36] = KEY_RECORD, + [0x3f] = KEY_EPG, /* Labeled "?" */ +}; +EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd); + /* * Igor Kuznetsov * Andrey J. Melnikov diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index f79a1c77414..bb0911b4d2f 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -224,7 +224,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_PINNACLE_PCTV_HD_800i: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; @@ -306,6 +305,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keycode = 0xfa; ir->polling = 50; /* ms */ break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + ir_codes = ir_codes_pinnacle_pctv_hd; + ir_type = IR_TYPE_RC5; + ir->sampling = 1; + break; } if (NULL == ir_codes) { diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 9c2fc09a713..831547d7968 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -141,6 +141,7 @@ extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3 From 72e04f720f23cfa8d4400d832784f3a424379227 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 22 Jan 2008 01:03:10 -0300 Subject: V4L/DVB (7059): cx88: Ensure the tuner is reset correctly Previous patches assume the tuner was on a different gpio. This patch corrects this. Signed-off-by: Steven Toth Signed-off-by: Chaogui Zhang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 254290975cd..e6b7f518c56 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1893,12 +1893,10 @@ int cx88_tuner_callback(void *priv, int command, int arg) switch(core->boardnr) { case CX88_BOARD_PINNACLE_PCTV_HD_800i: if(command == 0) { /* This is the reset command from xc5000 */ - /* Reset XC5000 tuner via GPIO pin #2 */ - cx_set(MO_GP0_IO, 0x00000400); - cx_clear(MO_GP0_IO, 0x00000004); - mdelay(200); - cx_set(MO_GP0_IO, 0x00000004); - mdelay(200); + /* Reset XC5000 tuner via SYS_RSTO_pin */ + cx_write(MO_SRST_IO, 0); + msleep(10); + cx_write(MO_SRST_IO, 1); return 0; } else { -- cgit v1.2.3 From ed086314f4e41eb90a9107c7fb2737230686f668 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 24 Jan 2008 06:59:20 -0300 Subject: V4L/DVB (7060): em28xx: remove has_tuner has_tuner flag doesn't make much sense, since tuner_type=TUNER_ABSENT means the same thing. Having two ways to say that a tuner is not present is not nice, since it may lead to bad setups. In fact, with the previous code, if a device were using has_tuner=0, but the user forces a tuner, with modprobe option tuner=type, the modprobe option won't work. Also, tveeprom returns TUNER_ABSENT, when tuner is unknown or absent. So, with the previous logic, in this case, the driver should set has_tuner=0, or has_tuner=1 otherwise. Instead of adding several additional tests and setups, better just to remove .has_tuner. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 29 +++++++---------------------- drivers/media/video/em28xx/em28xx-video.c | 5 +++-- drivers/media/video/em28xx/em28xx.h | 2 -- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 368a766eb80..2159d0160df 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -78,7 +78,6 @@ struct em28xx_board em28xx_boards[] = { .is_em2800 = 1, .vchannels = 2, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_COMPOSITE1, @@ -93,13 +92,14 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_UNKNOWN] = { .name = "Unknown EM2750/28xx video grabber", .is_em2800 = 0, + .tuner_type = TUNER_ABSENT, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, .vchannels = 2, + .tuner_type = TUNER_TEMIC_PAL, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_COMPOSITE1, @@ -116,7 +116,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -137,7 +136,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -160,7 +158,6 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE| TDA9887_PORT2_ACTIVE, - .has_tuner = 1, .decoder = EM28XX_TVP5150, .has_msp34xx = 1, /*FIXME: S-Video not tested */ @@ -180,7 +177,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, - .has_tuner = 1, .mts_firmware = 1, .decoder = EM28XX_TVP5150, .input = { { @@ -202,7 +198,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, - .has_tuner = 1, .mts_firmware = 1, .has_12mhz_i2s = 1, .decoder = EM28XX_TVP5150, @@ -227,7 +222,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Hybrid XS", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .input = { { @@ -251,7 +245,6 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Prodigy XS", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, .input = { { @@ -275,7 +268,6 @@ struct em28xx_board em28xx_boards[] = { .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .has_tuner = 1, .max_range_640_480 = 1, .decoder = EM28XX_SAA7114, @@ -299,7 +291,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -321,7 +312,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -343,7 +333,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tuner_type = TUNER_PHILIPS_ATSC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -362,7 +351,7 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90/DVC 100", .vchannels = 3, - .has_tuner = 0, + .tuner_type = TUNER_ABSENT, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_COMPOSITE1, @@ -380,7 +369,6 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -400,7 +388,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Pixelview Prolink PlayTV USB 2.0", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, + .tuner_type = TUNER_YMEC_TVF_5533MF, .decoder = EM28XX_SAA7113, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -551,7 +539,7 @@ static void em28xx_config_tuner(struct em28xx *dev) struct tuner_setup tun_setup; struct v4l2_frequency f; - if (!dev->has_tuner) + if (dev->tuner_type == TUNER_ABSENT) return; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; @@ -668,7 +656,6 @@ static int em28xx_hint_board(struct em28xx *dev) static void em28xx_set_model(struct em28xx *dev) { dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->has_tuner = em28xx_boards[dev->model].has_tuner; dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; dev->decoder = em28xx_boards[dev->model].decoder; @@ -676,9 +663,6 @@ static void em28xx_set_model(struct em28xx *dev) dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; - - if (!em28xx_boards[dev->model].has_tuner) - dev->tuner_type = UNSET; } /* ----------------------------------------------------------------------- */ @@ -745,6 +729,7 @@ void em28xx_card_setup(struct em28xx *dev) tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); dev->tuner_type = tv.tuner_type; + if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { dev->i2s_speed = 2048000; dev->has_msp34xx = 1; @@ -777,7 +762,7 @@ void em28xx_card_setup(struct em28xx *dev) request_module("saa7115"); if (dev->decoder == EM28XX_TVP5150) request_module("tvp5150"); - if (dev->has_tuner) + if (dev->tuner_type != TUNER_ABSENT) request_module("tuner"); #endif diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index de95ca87424..a0c33467248 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -38,6 +38,7 @@ #include "em28xx.h" #include #include +#include #define DRIVER_AUTHOR "Ludovico Cavedon , " \ "Markus Rechberger , " \ @@ -928,7 +929,7 @@ static int vidioc_querycap(struct file *file, void *priv, V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (dev->has_tuner) + if (dev->tuner_type != TUNER_ABSENT) cap->capabilities |= V4L2_CAP_TUNER; return 0; @@ -1900,7 +1901,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, em28xx_errdev("cannot allocate video_device.\n"); goto fail_unreg; } - if (dev->has_tuner) + if (dev->tuner_type != TUNER_ABSENT) dev->vdev->type |= VID_TYPE_TUNER; /* register v4l2 video video_device */ diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 3ef80d8b566..f3bad0c1c51 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -161,7 +161,6 @@ struct em28xx_board { unsigned int tda9887_conf; unsigned int is_em2800:1; - unsigned int has_tuner:1; unsigned int has_msp34xx:1; unsigned int mts_firmware:1; unsigned int has_12mhz_i2s:1; @@ -226,7 +225,6 @@ struct em28xx { int devno; /* marks the number of this device */ unsigned int analog_gpio; unsigned int is_em2800:1; - unsigned int has_tuner:1; unsigned int has_msp34xx:1; unsigned int has_tda9887:1; unsigned int stream_on:1; /* Locks streams */ -- cgit v1.2.3 From 8bf5e5ca394441e56f68300dc4e7b26b79ddfe0b Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Fri, 25 Jan 2008 04:19:48 -0300 Subject: V4L/DVB (7061): radio-si470x: Some cleanups - code reordered to avoid function prototypes - switch/case defaults are now more user-friendly - unified comment style - applied all checkpatch.pl v1.12 suggestions except the warning about the too long lines with bit comments - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) Signed-off-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si470x.c | 859 ++++++++++++++++++------------------- 1 file changed, 415 insertions(+), 444 deletions(-) diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index ccb167a1acd..d54fe640535 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -5,7 +5,7 @@ * - Silicon Labs USB FM Radio Reference Design * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) * - * Copyright (c) 2007 Tobias Lorenz + * Copyright (c) 2008 Tobias Lorenz * * 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 @@ -29,7 +29,7 @@ * Version 1.0.0 * - First working version * 2008-01-13 Tobias Lorenz - * Version 1.0.1 + * Version 1.0.1 * - Improved error handling, every function now returns errno * - Improved multi user access (start/mute/stop) * - Channel doesn't get lost anymore after start/mute/stop @@ -47,6 +47,14 @@ * - check for firmware version 15 * - code order and prototypes still remain the same * - spacing and bottom of band codes remain the same + * 2008-01-16 Tobias Lorenz + * Version 1.0.3 + * - code reordered to avoid function prototypes + * - switch/case defaults are now more user-friendly + * - unified comment style + * - applied all checkpatch.pl v1.12 suggestions + * except the warning about the too long lines with bit comments + * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) * * ToDo: * - check USB Vendor/Product ID for ADS/Tech FM Radio Receiver @@ -55,13 +63,14 @@ * - add firmware download/update support * - add possibility to switch off RDS * - RDS support: interrupt mode, instead of polling - * - add LED status output + * - add LED status output (check if that's not already done in firmware) */ + /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz " #define DRIVER_NAME "radio-si470x" -#define DRIVER_VERSION KERNEL_VERSION(1, 0, 2) +#define DRIVER_VERSION KERNEL_VERSION(1, 0, 3) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" @@ -80,6 +89,21 @@ #include +/* USB Device ID List */ +static struct usb_device_id si470x_usb_driver_id_table[] = { + /* Silicon Labs USB FM Radio Reference Design */ + { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); + + + +/************************************************************************** + * Module Parameters + **************************************************************************/ + /* Radio Nr */ static int radio_nr = -1; module_param(radio_nr, int, 0); @@ -145,8 +169,8 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** * Register Definitions **************************************************************************/ -#define FMRADIO_REGISTER_SIZE 2 /* 16 register bit width */ -#define FMRADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ +#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ +#define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ #define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ #define DEVICEID 0 /* Device ID */ @@ -236,23 +260,23 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** - * USB HID reports + * USB HID Reports **************************************************************************/ /* Reports 1-16 give direct read/write access to the 16 Si470x registers */ /* with the (REPORT_ID - 1) corresponding to the register address across USB */ /* endpoint 0 using GET_REPORT and SET_REPORT */ -#define REGISTER_REPORT_SIZE (FMRADIO_REGISTER_SIZE + 1) +#define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) #define REGISTER_REPORT(reg) ((reg) + 1) /* Report 17 gives direct read/write access to the entire Si470x register */ /* map across endpoint 0 using GET_REPORT and SET_REPORT */ -#define ENTIRE_REPORT_SIZE (FMRADIO_REGISTER_NUM * FMRADIO_REGISTER_SIZE + 1) +#define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) #define ENTIRE_REPORT 17 /* Report 18 is used to send the lowest 6 Si470x registers up the HID */ /* interrupt endpoint 1 to Windows every 20 milliseconds for status */ -#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * FMRADIO_REGISTER_SIZE + 1) +#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) #define RDS_REPORT 18 /* Report 19: LED state */ @@ -281,12 +305,12 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** - * software/hardware versions + * Software/Hardware Versions **************************************************************************/ -#define FMRADIO_SW_VERSION_NOT_BOOTLOADABLE 6 -#define FMRADIO_SW_VERSION 7 -#define FMRADIO_SW_VERSION_CURRENT 15 -#define FMRADIO_HW_VERSION 1 +#define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 +#define RADIO_SW_VERSION 7 +#define RADIO_SW_VERSION_CURRENT 15 +#define RADIO_HW_VERSION 1 #define SCRATCH_PAGE_SW_VERSION 1 #define SCRATCH_PAGE_HW_VERSION 2 @@ -294,7 +318,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** - * LED State definitions + * LED State Definitions **************************************************************************/ #define LED_COMMAND 0x35 @@ -310,7 +334,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** - * Stream State definitions + * Stream State Definitions **************************************************************************/ #define STREAM_COMMAND 0x36 #define STREAM_VIDPID 0x00 @@ -319,16 +343,16 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** - * bootloader / flash commands + * Bootloader / Flash Commands **************************************************************************/ -/* Unique ID sent to bootloader and required to put into a bootload state */ +/* unique id sent to bootloader and required to put into a bootload state */ #define UNIQUE_BL_ID 0x34 -/* Mask for the flash data */ +/* mask for the flash data */ #define FLASH_DATA_MASK 0x55 -/* Bootloader commands */ +/* bootloader commands */ #define GET_SW_VERSION_COMMAND 0x00 #define SET_PAGE_COMMAND 0x01 #define ERASE_PAGE_COMMAND 0x02 @@ -339,12 +363,12 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); #define GET_HW_VERSION_COMMAND 0x07 #define BLANK 0xff -/* Bootloader command responses */ +/* bootloader command responses */ #define COMMAND_OK 0x01 #define COMMAND_FAILED 0x02 #define COMMAND_PENDING 0x03 -/* Buffer sizes */ +/* buffer sizes */ #define COMMAND_BUFFER_SIZE 4 #define RESPONSE_BUFFER_SIZE 2 #define FLASH_BUFFER_SIZE 64 @@ -353,10 +377,12 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /************************************************************************** - * Driver private definitions + * General Driver Definitions **************************************************************************/ -/* private data */ +/* + * si470x_device - private data + */ struct si470x_device { /* reference to USB and video device */ struct usb_device *usbdev; @@ -369,12 +395,12 @@ struct si470x_device { unsigned char buf[64]; /* Silabs internal registers (0..15) */ - unsigned short registers[FMRADIO_REGISTER_NUM]; + unsigned short registers[RADIO_REGISTER_NUM]; /* RDS receive buffer */ struct work_struct work; struct timer_list timer; - spinlock_t lock; + spinlock_t lock; /* buffer locking */ unsigned char *buffer; unsigned int buf_size; unsigned int rd_index; @@ -385,177 +411,20 @@ struct si470x_device { int data_available_for_read; }; -/* register acccess functions */ -static int si470x_get_report(struct si470x_device *radio, int size); -static int si470x_set_report(struct si470x_device *radio, int size); -static int si470x_get_register(struct si470x_device *radio, int regnr); -static int si470x_set_register(struct si470x_device *radio, int regnr); -static int si470x_get_all_registers(struct si470x_device *radio); -static int si470x_get_rds_registers(struct si470x_device *radio); - -/* high-level functions */ -static int si470x_start(struct si470x_device *radio); -static int si470x_stop(struct si470x_device *radio); -static int si470x_set_chan(struct si470x_device *radio, int chan); -static int si470x_get_freq(struct si470x_device *radio); -static int si470x_set_freq(struct si470x_device *radio, int freq); - -/* RDS functions */ -static void si470x_rds(struct si470x_device *radio); -static void si470x_timer(unsigned long data); -static void si470x_work(struct work_struct *work); - - - -/************************************************************************** - * USB interface definitions - **************************************************************************/ - -/* USB device ID list (Vendor, Product, Class, SubClass, Protocol) */ -static struct usb_device_id si470x_usb_driver_id_table[] = { - /* Silicon Labs USB FM Radio Reference Design */ - { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, - /* Terminating entry */ - { } -}; -MODULE_DEVICE_TABLE (usb, si470x_usb_driver_id_table); - -/* USB driver functions */ -static int si470x_usb_driver_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void si470x_usb_driver_disconnect(struct usb_interface *intf); - -/* USB driver interface */ -static struct usb_driver si470x_usb_driver = { - .name = DRIVER_NAME, - .probe = si470x_usb_driver_probe, - .disconnect = si470x_usb_driver_disconnect, - .id_table = si470x_usb_driver_id_table, -}; - - - -/************************************************************************** - * Video4Linux interface definitions - **************************************************************************/ -/* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, */ -/* 62.5 kHz otherwise. */ -/* The tuner is able to have a channel spacing of 50, 100 or 200 kHz. */ -/* tuner->capability is therefore set to V4L2_TUNER_CAP_LOW */ -/* The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 */ +/* + * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, + * 62.5 kHz otherwise. + * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. + * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW + * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 + */ #define FREQ_MUL (1000000 / 62.5) -/* File operations functions */ -static ssize_t si470x_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); -static unsigned int si470x_fops_poll(struct file *file, - struct poll_table_struct *pts); -static int si470x_fops_open(struct inode *inode, struct file *file); -static int si470x_fops_release(struct inode *inode, struct file *file); - -/* File operations interface */ -static const struct file_operations si470x_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = si470x_fops_read, - .poll = si470x_fops_poll, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .open = si470x_fops_open, - .release = si470x_fops_release, -}; - -/* Video device functions */ -static int si470x_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability); -static int si470x_vidioc_g_input(struct file *file, void *priv, - unsigned int *i); -static int si470x_vidioc_s_input(struct file *file, void *priv, - unsigned int i); -static int si470x_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc); -static int si470x_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl); -static int si470x_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl); -static int si470x_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio); -static int si470x_vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio); -static int si470x_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner); -static int si470x_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner); -static int si470x_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq); -static int si470x_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq); - -/* Video device interface */ -static struct video_device si470x_viddev_template = { - .fops = &si470x_fops, - .name = DRIVER_NAME, - .type = VID_TYPE_TUNER, - .release = video_device_release, - .vidioc_querycap = si470x_vidioc_querycap, - .vidioc_g_input = si470x_vidioc_g_input, - .vidioc_s_input = si470x_vidioc_s_input, - .vidioc_queryctrl = si470x_vidioc_queryctrl, - .vidioc_g_ctrl = si470x_vidioc_g_ctrl, - .vidioc_s_ctrl = si470x_vidioc_s_ctrl, - .vidioc_g_audio = si470x_vidioc_g_audio, - .vidioc_s_audio = si470x_vidioc_s_audio, - .vidioc_g_tuner = si470x_vidioc_g_tuner, - .vidioc_s_tuner = si470x_vidioc_s_tuner, - .vidioc_g_frequency = si470x_vidioc_g_frequency, - .vidioc_s_frequency = si470x_vidioc_s_frequency, - .owner = THIS_MODULE, -}; - -/* Query control */ -static struct v4l2_queryctrl radio_queryctrl[] = { -/* HINT: the disabled controls are only here to satify kradio and such apps */ - { - .id = V4L2_CID_AUDIO_VOLUME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Volume", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 15, - }, - { - .id = V4L2_CID_AUDIO_BALANCE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BASS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_TREBLE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_AUDIO_LOUDNESS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, -}; - /************************************************************************** - * Driver private functions + * General Driver Functions **************************************************************************/ /* @@ -633,10 +502,10 @@ static int si470x_get_all_registers(struct si470x_device *radio) retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); if (retval >= 0) - for (regnr = 0; regnr < FMRADIO_REGISTER_NUM; regnr++) + for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) radio->registers[regnr] = - (radio->buf[regnr * FMRADIO_REGISTER_SIZE + 1] << 8) | - radio->buf[regnr * FMRADIO_REGISTER_SIZE + 2]; + (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | + radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; return (retval < 0) ? -EINVAL : 0; } @@ -657,65 +526,13 @@ static int si470x_get_rds_registers(struct si470x_device *radio) usb_rcvctrlpipe(radio->usbdev, 1), radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); - if (retval >= 0) { - for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { + if (retval >= 0) + for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) radio->registers[STATUSRSSI + regnr] = - (radio->buf[regnr * FMRADIO_REGISTER_SIZE + 1] << 8) | - radio->buf[regnr * FMRADIO_REGISTER_SIZE + 2]; - } - } + (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | + radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; - return (retval < 0) ? - EINVAL : 0; -} - - -/* - * si470x_start - switch on radio - */ -static int si470x_start(struct si470x_device *radio) -{ - int retval; - - /* powercfg */ - radio->registers[POWERCFG] = - POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; - retval = si470x_set_register(radio, POWERCFG); - if (retval < 0) - return retval; - - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = - SYSCONFIG1_DE | SYSCONFIG1_RDS; - retval = si470x_set_register(radio, SYSCONFIG1); - if (retval < 0) - return retval; - - /* sysconfig 2 */ - radio->registers[SYSCONFIG2] = - (0x3f << 8) | /* SEEKTH */ - (band << 6) | /* BAND */ - (space << 4) | /* SPACE */ - 15; /* VOLUME (max) */ - retval = si470x_set_register(radio, SYSCONFIG2); - if (retval < 0) - return retval; - - /* reset last channel */ - return si470x_set_chan(radio, - radio->registers[CHANNEL] & CHANNEL_CHAN); -} - - -/* - * si470x_stop - switch off radio - */ -static int si470x_stop(struct si470x_device *radio) -{ - /* powercfg */ - radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; - /* POWERCFG_ENABLE has to automatically go low */ - radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; - return si470x_set_register(radio, POWERCFG); + return (retval < 0) ? -EINVAL : 0; } @@ -761,22 +578,22 @@ static int si470x_get_freq(struct si470x_device *radio) /* Spacing (kHz) */ switch (space) { - /* 0: 200 kHz (USA, Australia) */ - default: spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1 : spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - case 2 : spacing = 0.050 * FREQ_MUL; break; + /* 0: 200 kHz (USA, Australia) */ + case 0 : spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1 : spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: spacing = 0.050 * FREQ_MUL; break; }; /* Bottom of Band (MHz) */ switch (band) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - default: band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - case 1 : band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2 : band_bottom = 76 * FREQ_MUL; break; + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0 : band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : band_bottom = 76 * FREQ_MUL; break; }; /* read channel */ @@ -801,22 +618,22 @@ static int si470x_set_freq(struct si470x_device *radio, int freq) /* Spacing (kHz) */ switch (space) { - /* 0: 200 kHz (USA, Australia) */ - default: spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1 : spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - case 2 : spacing = 0.050 * FREQ_MUL; break; + /* 0: 200 kHz (USA, Australia) */ + case 0 : spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1 : spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: spacing = 0.050 * FREQ_MUL; break; }; /* Bottom of Band (MHz) */ switch (band) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - default: band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - case 1 : band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2 : band_bottom = 76 * FREQ_MUL; break; + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0 : band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : band_bottom = 76 * FREQ_MUL; break; }; /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ @@ -826,6 +643,60 @@ static int si470x_set_freq(struct si470x_device *radio, int freq) } +/* + * si470x_start - switch on radio + */ +static int si470x_start(struct si470x_device *radio) +{ + int retval; + + /* powercfg */ + radio->registers[POWERCFG] = + POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + return retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] = + SYSCONFIG1_DE | SYSCONFIG1_RDS; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + return retval; + + /* sysconfig 2 */ + radio->registers[SYSCONFIG2] = + (0x3f << 8) | /* SEEKTH */ + (band << 6) | /* BAND */ + (space << 4) | /* SPACE */ + 15; /* VOLUME (max) */ + retval = si470x_set_register(radio, SYSCONFIG2); + if (retval < 0) + return retval; + + /* reset last channel */ + return si470x_set_chan(radio, + radio->registers[CHANNEL] & CHANNEL_CHAN); +} + + +/* + * si470x_stop - switch off radio + */ +static int si470x_stop(struct si470x_device *radio) +{ + /* powercfg */ + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + /* POWERCFG_ENABLE has to automatically go low */ + radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; + return si470x_set_register(radio, POWERCFG); +} + + + +/************************************************************************** + * RDS Driver Functions + **************************************************************************/ /* * si470x_rds - rds processing function @@ -854,26 +725,26 @@ static void si470x_rds(struct si470x_device *radio) for (blocknum = 0; blocknum < 4; blocknum++) { switch (blocknum) { - default: - bler = (radio->registers[STATUSRSSI] & - STATUSRSSI_BLERA) >> 9; - rds = radio->registers[RDSA]; - break; - case 1: - bler = (radio->registers[READCHAN] & - READCHAN_BLERB) >> 14; - rds = radio->registers[RDSB]; - break; - case 2: - bler = (radio->registers[READCHAN] & - READCHAN_BLERC) >> 12; - rds = radio->registers[RDSC]; - break; - case 3: - bler = (radio->registers[READCHAN] & - READCHAN_BLERD) >> 10; - rds = radio->registers[RDSD]; - break; + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; }; /* Fill the V4L2 RDS buffer */ @@ -941,120 +812,20 @@ static void si470x_work(struct work_struct *work) /************************************************************************** - * USB interface functions + * File Operations Interface **************************************************************************/ /* - * si470x_usb_driver_probe - probe for the device + * si470x_fops_read - read RDS data */ -static int si470x_usb_driver_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { - struct si470x_device *radio; - - if (!(radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL))) - return -ENOMEM; - if (!(radio->videodev = video_device_alloc())) { - kfree(radio); - return -ENOMEM; - } - memcpy(radio->videodev, &si470x_viddev_template, - sizeof(si470x_viddev_template)); - radio->users = 0; - radio->usbdev = interface_to_usbdev(intf); - video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - printk(KERN_WARNING DRIVER_NAME - ": Could not register video device\n"); - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - usb_set_intfdata(intf, radio); - - /* show some infos about the specific device */ - if (si470x_get_all_registers(radio) < 0) { - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", - radio->registers[DEVICEID], radio->registers[CHIPID]); - - /* check if firmware is current */ - if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) - < FMRADIO_SW_VERSION_CURRENT) { - printk(KERN_WARNING DRIVER_NAME - ": This driver is known to work with chip version %d, " - "but the device has firmware %d. If you have some " - "trouble using this driver, please report to V4L ML " - "at video4linux-list@redhat.com\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE, - FMRADIO_SW_VERSION_CURRENT); - } - - /* set initial frequency */ - si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ - - /* rds initialization */ - radio->buf_size = rds_buf * 3; - if (NULL == (radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL))) { - video_device_release(radio->videodev); - kfree(radio); - return -ENOMEM; - } - radio->block_count = 0; - radio->wr_index = 0; - radio->rd_index = 0; - radio->last_blocknum = 0xff; - init_waitqueue_head(&radio->read_queue); - radio->data_available_for_read = 0; - - /* prepare polling via eventd */ - INIT_WORK(&radio->work, si470x_work); - init_timer(&radio->timer); - radio->timer.function = si470x_timer; - radio->timer.data = (unsigned long) radio; - - return 0; -} - - -/* - * si470x_usb_driver_disconnect - disconnect the device - */ -static void si470x_usb_driver_disconnect(struct usb_interface *intf) -{ - struct si470x_device *radio = usb_get_intfdata(intf); - - del_timer_sync(&radio->timer); - flush_scheduled_work(); - - usb_set_intfdata(intf, NULL); - if (radio) { - video_unregister_device(radio->videodev); - kfree(radio->buffer); - kfree(radio); - } -} - - - -/************************************************************************** - * Video4Linux interface functions - **************************************************************************/ - -/* - * si470x_fops_read - read RDS data - */ -static ssize_t si470x_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - struct rds_command cmd; - unsigned long flags; - unsigned int i; - unsigned int rd_blocks; + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct rds_command cmd; + unsigned long flags; + unsigned int i; + unsigned int rd_blocks; cmd.block_count = count / 3; /* each RDS block needs 3 bytes */ cmd.result = 0; @@ -1165,6 +936,68 @@ static int si470x_fops_release(struct inode *inode, struct file *file) } +/* + * si470x_fops - file operations interface + */ +static const struct file_operations si470x_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .open = si470x_fops_open, + .release = si470x_fops_release, +}; + + + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ + +/* + * si470x_v4l2_queryctrl - query control + */ +static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = { +/* HINT: the disabled controls are only here to satify kradio and such apps */ + { + .id = V4L2_CID_AUDIO_VOLUME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Volume", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 15, + }, + { + .id = V4L2_CID_AUDIO_BALANCE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_BASS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_TREBLE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_MUTE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_AUDIO_LOUDNESS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, +}; + + /* * si470x_vidioc_querycap - query device capabilities */ @@ -1213,9 +1046,9 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv, { int i; - for (i = 0; i < ARRAY_SIZE(radio_queryctrl); i++) { - if (qc->id && qc->id == radio_queryctrl[i].id) { - memcpy(qc, &(radio_queryctrl[i]), sizeof(*qc)); + for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { + if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) { + memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); return 0; } } @@ -1233,14 +1066,14 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv, struct si470x_device *radio = video_get_drvdata(video_devdata(file)); switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = radio->registers[SYSCONFIG2] & - SYSCONFIG2_VOLUME; - break; - case V4L2_CID_AUDIO_MUTE: - ctrl->value = ((radio->registers[POWERCFG] & - POWERCFG_DMUTE) == 0) ? 1 : 0; - break; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = radio->registers[SYSCONFIG2] & + SYSCONFIG2_VOLUME; + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = ((radio->registers[POWERCFG] & + POWERCFG_DMUTE) == 0) ? 1 : 0; + break; } return 0; @@ -1256,16 +1089,16 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, struct si470x_device *radio = video_get_drvdata(video_devdata(file)); switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; - radio->registers[SYSCONFIG2] |= ctrl->value; - return si470x_set_register(radio, SYSCONFIG2); - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value == 1) - radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; - else - radio->registers[POWERCFG] |= POWERCFG_DMUTE; - return si470x_set_register(radio, POWERCFG); + case V4L2_CID_AUDIO_VOLUME: + radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; + radio->registers[SYSCONFIG2] |= ctrl->value; + return si470x_set_register(radio, SYSCONFIG2); + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value == 1) + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + else + radio->registers[POWERCFG] |= POWERCFG_DMUTE; + return si470x_set_register(radio, POWERCFG); } return -EINVAL; @@ -1320,22 +1153,22 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, strcpy(tuner->name, "FM"); tuner->type = V4L2_TUNER_RADIO; - switch(band) { - /* 0: 87.5 - 108 MHz (USA, Europe, default) */ - default: - tuner->rangelow = 87.5 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 1: 76 - 108 MHz (Japan wide band) */ - case 1 : - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 2: 76 - 90 MHz (Japan) */ - case 2 : - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 90 * FREQ_MUL; - break; + switch (band) { + /* 0: 87.5 - 108 MHz (USA, Europe, default) */ + default: + tuner->rangelow = 87.5 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1 : + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 90 * FREQ_MUL; + break; }; tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; tuner->capability = V4L2_TUNER_CAP_LOW; @@ -1407,9 +1240,147 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, } +/* + * si470x_viddev_tamples - video device interface + */ +static struct video_device si470x_viddev_template = { + .fops = &si470x_fops, + .name = DRIVER_NAME, + .type = VID_TYPE_TUNER, + .release = video_device_release, + .vidioc_querycap = si470x_vidioc_querycap, + .vidioc_g_input = si470x_vidioc_g_input, + .vidioc_s_input = si470x_vidioc_s_input, + .vidioc_queryctrl = si470x_vidioc_queryctrl, + .vidioc_g_ctrl = si470x_vidioc_g_ctrl, + .vidioc_s_ctrl = si470x_vidioc_s_ctrl, + .vidioc_g_audio = si470x_vidioc_g_audio, + .vidioc_s_audio = si470x_vidioc_s_audio, + .vidioc_g_tuner = si470x_vidioc_g_tuner, + .vidioc_s_tuner = si470x_vidioc_s_tuner, + .vidioc_g_frequency = si470x_vidioc_g_frequency, + .vidioc_s_frequency = si470x_vidioc_s_frequency, + .owner = THIS_MODULE, +}; + + + +/************************************************************************** + * USB Interface + **************************************************************************/ + +/* + * si470x_usb_driver_probe - probe for the device + */ +static int si470x_usb_driver_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct si470x_device *radio; + + /* memory and interface allocations */ + radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL); + if (!radio) + return -ENOMEM; + radio->videodev = video_device_alloc(); + if (!radio->videodev) { + kfree(radio); + return -ENOMEM; + } + memcpy(radio->videodev, &si470x_viddev_template, + sizeof(si470x_viddev_template)); + radio->users = 0; + radio->usbdev = interface_to_usbdev(intf); + video_set_drvdata(radio->videodev, radio); + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { + printk(KERN_WARNING DRIVER_NAME + ": Could not register video device\n"); + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + usb_set_intfdata(intf, radio); + + /* show some infos about the specific device */ + if (si470x_get_all_registers(radio) < 0) { + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + + /* check if firmware is current */ + if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) + < RADIO_SW_VERSION_CURRENT) + printk(KERN_WARNING DRIVER_NAME + ": This driver is known to work with chip version %d, " + "but the device has firmware %d. If you have some " + "trouble using this driver, please report to V4L ML " + "at video4linux-list@redhat.com\n", + radio->registers[CHIPID] & CHIPID_FIRMWARE, + RADIO_SW_VERSION_CURRENT); + + /* set initial frequency */ + si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + + /* rds initialization */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + video_device_release(radio->videodev); + kfree(radio); + return -ENOMEM; + } + radio->block_count = 0; + radio->wr_index = 0; + radio->rd_index = 0; + radio->last_blocknum = 0xff; + init_waitqueue_head(&radio->read_queue); + radio->data_available_for_read = 0; + + /* prepare polling via eventd */ + INIT_WORK(&radio->work, si470x_work); + init_timer(&radio->timer); + radio->timer.function = si470x_timer; + radio->timer.data = (unsigned long) radio; + + return 0; +} + + +/* + * si470x_usb_driver_disconnect - disconnect the device + */ +static void si470x_usb_driver_disconnect(struct usb_interface *intf) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + del_timer_sync(&radio->timer); + flush_scheduled_work(); + + usb_set_intfdata(intf, NULL); + if (radio) { + video_unregister_device(radio->videodev); + kfree(radio->buffer); + kfree(radio); + } +} + + +/* + * si470x_usb_driver - usb driver interface + */ +static struct usb_driver si470x_usb_driver = { + .name = DRIVER_NAME, + .probe = si470x_usb_driver_probe, + .disconnect = si470x_usb_driver_disconnect, + .id_table = si470x_usb_driver_id_table, +}; + + /************************************************************************** - * Module interface definitions and functions + * Module Interface **************************************************************************/ /* @@ -1437,4 +1408,4 @@ module_exit(si470x_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION("1.0.2"); +MODULE_VERSION("1.0.3"); -- cgit v1.2.3 From 2fb8840663cf0e476549104a2c09caa0fb3b4bc9 Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Fri, 25 Jan 2008 05:14:57 -0300 Subject: V4L/DVB (7062): radio-si570x: Some fixes and new USB ID addition - avoid poss. locking when doing copy_to_user which may sleep - RDS is automatically activated on read now - code cleaned of unnecessary rds_commands - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified (thanks to Guillaume RAMOUSSE) Signed-off-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si470x.c | 291 ++++++++++++++++++++----------------- 1 file changed, 156 insertions(+), 135 deletions(-) diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index d54fe640535..8e4bd476904 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -55,13 +55,17 @@ * - applied all checkpatch.pl v1.12 suggestions * except the warning about the too long lines with bit comments * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) + * 2008-01-22 Tobias Lorenz + * Version 1.0.4 + * - avoid poss. locking when doing copy_to_user which may sleep + * - RDS is automatically activated on read now + * - code cleaned of unnecessary rds_commands + * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified + * (thanks to Guillaume RAMOUSSE) * * ToDo: - * - check USB Vendor/Product ID for ADS/Tech FM Radio Receiver - * (formerly Instant FM Music) (RDX-155-EF) is 06e1:a155 * - add seeking support * - add firmware download/update support - * - add possibility to switch off RDS * - RDS support: interrupt mode, instead of polling * - add LED status output (check if that's not already done in firmware) */ @@ -70,7 +74,7 @@ /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz " #define DRIVER_NAME "radio-si470x" -#define DRIVER_VERSION KERNEL_VERSION(1, 0, 3) +#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" @@ -93,6 +97,8 @@ static struct usb_device_id si470x_usb_driver_id_table[] = { /* Silicon Labs USB FM Radio Reference Design */ { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, + /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, /* Terminating entry */ { } }; @@ -159,6 +165,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); /* RDS poll frequency */ static int rds_poll_time = 40; /* 40 is used by the original USBRadio.exe */ +/* 50 is used by radio-cadet */ /* 75 should be okay */ /* 80 is the usual RDS receive interval */ module_param(rds_poll_time, int, 0); @@ -399,16 +406,13 @@ struct si470x_device { /* RDS receive buffer */ struct work_struct work; + wait_queue_head_t read_queue; struct timer_list timer; spinlock_t lock; /* buffer locking */ - unsigned char *buffer; + unsigned char *buffer; /* size is always multiple of three */ unsigned int buf_size; unsigned int rd_index; unsigned int wr_index; - unsigned int block_count; - unsigned char last_blocknum; - wait_queue_head_t read_queue; - int data_available_for_read; }; @@ -658,8 +662,7 @@ static int si470x_start(struct si470x_device *radio) return retval; /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = - SYSCONFIG1_DE | SYSCONFIG1_RDS; + radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; retval = si470x_set_register(radio, SYSCONFIG1); if (retval < 0) return retval; @@ -685,6 +688,14 @@ static int si470x_start(struct si470x_device *radio) */ static int si470x_stop(struct si470x_device *radio) { + int retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + return retval; + /* powercfg */ radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; /* POWERCFG_ENABLE has to automatically go low */ @@ -693,6 +704,17 @@ static int si470x_stop(struct si470x_device *radio) } +/* + * si470x_rds_on - switch on rds reception + */ +static int si470x_rds_on(struct si470x_device *radio) +{ + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; + return si470x_set_register(radio, SYSCONFIG1); +} + + /************************************************************************** * RDS Driver Functions @@ -703,15 +725,13 @@ static int si470x_stop(struct si470x_device *radio) */ static void si470x_rds(struct si470x_device *radio) { - unsigned long flags; unsigned char tmpbuf[3]; unsigned char blocknum; - unsigned char bler; /* RDS block errors */ + unsigned char bler; /* rds block errors */ unsigned short rds; unsigned int i; - if (radio->users == 0) - return; + /* get rds blocks */ if (si470x_get_rds_registers(radio) < 0) return; if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { @@ -723,63 +743,67 @@ static void si470x_rds(struct si470x_device *radio) return; } - for (blocknum = 0; blocknum < 4; blocknum++) { - switch (blocknum) { - default: - bler = (radio->registers[STATUSRSSI] & - STATUSRSSI_BLERA) >> 9; - rds = radio->registers[RDSA]; - break; - case 1: - bler = (radio->registers[READCHAN] & - READCHAN_BLERB) >> 14; - rds = radio->registers[RDSB]; - break; - case 2: - bler = (radio->registers[READCHAN] & - READCHAN_BLERC) >> 12; - rds = radio->registers[RDSC]; - break; - case 3: - bler = (radio->registers[READCHAN] & - READCHAN_BLERD) >> 10; - rds = radio->registers[RDSD]; - break; - }; - - /* Fill the V4L2 RDS buffer */ - tmpbuf[0] = rds & 0x00ff; /* LSB */ - tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ - tmpbuf[2] = blocknum; /* offset name */ - tmpbuf[2] |= blocknum << 3; /* received offset */ - if (bler > max_rds_errors) - tmpbuf[2] |= 0x80; /* uncorrectable errors */ - else if (bler > 0) - tmpbuf[2] |= 0x40; /* corrected error(s) */ - - spin_lock_irqsave(&radio->lock, flags); - - /* copy RDS block to internal buffer */ - for (i = 0; i < 3; i++) { - radio->buffer[radio->wr_index] = tmpbuf[i]; - radio->wr_index++; + /* copy four RDS blocks to internal buffer */ + if (spin_trylock(&radio->lock)) { + /* process each rds block */ + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + tmpbuf[0] = rds & 0x00ff; /* LSB */ + tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + /* copy RDS block to internal buffer */ + for (i = 0; i < 3; i++) { + radio->buffer[radio->wr_index] = tmpbuf[i]; + radio->wr_index++; + } + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } } - - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - if (radio->wr_index == radio->rd_index) { - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - } else - radio->block_count++; - - spin_unlock_irqrestore(&radio->lock, flags); + spin_unlock(&radio->lock); } - radio->data_available_for_read = 1; - wake_up_interruptible(&radio->read_queue); + /* wake up read queue */ + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); } @@ -795,14 +819,14 @@ static void si470x_timer(unsigned long data) /* - * si470x_timer - rds work function + * si470x_work - rds work function */ static void si470x_work(struct work_struct *work) { struct si470x_device *radio = container_of(work, struct si470x_device, work); - if (radio->users == 0) + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) return; si470x_rds(radio); @@ -822,53 +846,52 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - struct rds_command cmd; - unsigned long flags; - unsigned int i; - unsigned int rd_blocks; - - cmd.block_count = count / 3; /* each RDS block needs 3 bytes */ - cmd.result = 0; - cmd.buffer = buf; - cmd.instance = file; - - /* copy RDS block out of internal buffer */ - while (!radio->data_available_for_read) { - if (wait_event_interruptible(radio->read_queue, - radio->data_available_for_read) < 0) - return -EINTR; - } + int retval = 0; + unsigned int block_count = 0; - spin_lock_irqsave(&radio->lock, flags); - rd_blocks = cmd.block_count; - if (rd_blocks > radio->block_count) - rd_blocks = radio->block_count; + /* switch on rds reception */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { + si470x_rds_on(radio); + schedule_work(&radio->work); + } - if (!rd_blocks) { - spin_unlock_irqrestore(&radio->lock, flags); - return cmd.result; + /* block if no new data available */ + while (radio->wr_index == radio->rd_index) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + interruptible_sleep_on(&radio->read_queue); } - for (i = 0; i < rd_blocks; i++) { - /* copy RDS block to user buffer */ - if (radio->rd_index == radio->wr_index) - break; + /* calculate block count from byte count */ + count /= 3; + + /* copy RDS block out of internal buffer and to user buffer */ + if (spin_trylock(&radio->lock)) { + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; - if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) - break; + /* always transfer rds complete blocks */ + if (copy_to_user(buf, + &radio->buffer[radio->rd_index], 3)) + /* retval = -EFAULT; */ + break; - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - radio->block_count--; + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + } - buf += 3; - cmd.result += 3; + spin_unlock(&radio->lock); } - radio->data_available_for_read = (radio->block_count > 0); - spin_unlock_irqrestore(&radio->lock, flags); - return cmd.result; + return retval; } @@ -879,14 +902,19 @@ static unsigned int si470x_fops_poll(struct file *file, struct poll_table_struct *pts) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval; - retval = 0; - if (radio->data_available_for_read) - retval = POLLIN | POLLRDNORM; + /* switch on rds reception */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { + si470x_rds_on(radio); + schedule_work(&radio->work); + } + poll_wait(file, &radio->read_queue, pts); - return retval; + if (radio->rd_index != radio->wr_index) + return POLLIN | POLLRDNORM; + + return 0; } @@ -895,17 +923,11 @@ static unsigned int si470x_fops_poll(struct file *file, */ static int si470x_fops_open(struct inode *inode, struct file *file) { - int retval; struct si470x_device *radio = video_get_drvdata(video_devdata(file)); radio->users++; - if (radio->users == 1) { - retval = si470x_start(radio); - if (retval < 0) - return retval; - - schedule_work(&radio->work); - } + if (radio->users == 1) + return si470x_start(radio); return 0; } @@ -916,7 +938,6 @@ static int si470x_fops_open(struct inode *inode, struct file *file) */ static int si470x_fops_release(struct inode *inode, struct file *file) { - int retval; struct si470x_device *radio = video_get_drvdata(video_devdata(file)); if (!radio) @@ -924,12 +945,14 @@ static int si470x_fops_release(struct inode *inode, struct file *file) radio->users--; if (radio->users == 0) { - radio->data_available_for_read = 1; /* ? */ - wake_up_interruptible(&radio->read_queue); /* ? */ + /* stop rds reception */ + del_timer_sync(&radio->timer); + flush_scheduled_work(); - retval = si470x_stop(radio); - if (retval < 0) - return retval; + /* cancel read processes */ + wake_up_interruptible(&radio->read_queue); + + return si470x_stop(radio); } return 0; @@ -1314,9 +1337,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, < RADIO_SW_VERSION_CURRENT) printk(KERN_WARNING DRIVER_NAME ": This driver is known to work with chip version %d, " - "but the device has firmware %d. If you have some " - "trouble using this driver, please report to V4L ML " - "at video4linux-list@redhat.com\n", + "but the device has firmware %d.\n" + DRIVER_NAME + "If you have some trouble using this driver, please " + "report to V4L ML at video4linux-list@redhat.com\n", radio->registers[CHIPID] & CHIPID_FIRMWARE, RADIO_SW_VERSION_CURRENT); @@ -1331,12 +1355,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, kfree(radio); return -ENOMEM; } - radio->block_count = 0; radio->wr_index = 0; radio->rd_index = 0; - radio->last_blocknum = 0xff; init_waitqueue_head(&radio->read_queue); - radio->data_available_for_read = 0; /* prepare polling via eventd */ INIT_WORK(&radio->work, si470x_work); @@ -1408,4 +1429,4 @@ module_exit(si470x_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION("1.0.3"); +MODULE_VERSION("1.0.4"); -- cgit v1.2.3 From 5ea60531c1c6164788ea7d6efecdf575adc543ff Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 24 Jan 2008 22:29:46 -0300 Subject: V4L/DVB (7063): xc5000: Fix OOPS caused by missing firmware xc5000: Fix OOPS caused by missing firmware. Signed-off-by: Chaogui Zhang Acked-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/xc5000.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c index a13027e09cd..f642ca200b5 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/dvb/frontends/xc5000.c @@ -558,6 +558,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe) if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; + goto out; } else { printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n", fw->size); @@ -572,6 +573,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe) ret = xc_load_i2c_sequence(fe, fw->data ); } +out: release_firmware(fw); return ret; } -- cgit v1.2.3 From 7999a8161d06326f3c4cb797fcf0de8b2eb08253 Mon Sep 17 00:00:00 2001 From: Yousef Lamlum Date: Fri, 25 Jan 2008 05:51:48 -0300 Subject: V4L/DVB (7065): Artec T14BR patches Added Artec T14BR support Signed-off-by: Yousef Lamlum Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 1aa335d5aa9..a7088cee1ef 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -851,6 +851,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, /* 21 */{ USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, +/* 22 */{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1018,7 +1019,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -1028,6 +1029,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[16], NULL }, { NULL }, }, + { "Artec T14BR DVB-T", + { &dib0700_usb_id_table[22], NULL }, + { NULL }, + } } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index aee5a6ef821..36aeda2b171 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -105,6 +105,7 @@ #define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a #define USB_PID_ARTEC_T14_COLD 0x810b #define USB_PID_ARTEC_T14_WARM 0x810c +#define USB_PID_ARTEC_T14BR 0x810f #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 #define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e -- cgit v1.2.3 From 132c3188433bcb149ee764be1ca9a69f6d719dfe Mon Sep 17 00:00:00 2001 From: Daniel Gimpelevich Date: Fri, 25 Jan 2008 06:02:42 -0300 Subject: V4L/DVB (7066): ASUS My Cinema U3000 Mini DVBT Tuner Adding support for ASUS My Cinema U3000 Mini DVBT Tuner Signed-off-by: Daniel Gimpelevich Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 55 ++++++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 3 ++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a7088cee1ef..de36790899b 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -230,6 +230,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = { } }; +static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) { if (adap->id == 0) { @@ -850,8 +871,10 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, -/* 21 */{ USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, -/* 22 */{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -923,7 +946,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[20] }, { NULL }, }, - /* dom : pour Gigabyte U7000 */ { "Gigabyte U7000", { &dib0700_usb_id_table[21], NULL }, { NULL }, @@ -1005,6 +1027,25 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = stk7700P2_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, + }, + + .num_device_descs = 1, + .devices = { + { "ASUS My Cinema U3000 Mini DVBT Tuner", + { &dib0700_usb_id_table[23], NULL }, + { NULL }, + }, + } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 1, @@ -1019,7 +1060,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -1032,7 +1073,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Artec T14BR DVB-T", { &dib0700_usb_id_table[22], NULL }, { NULL }, - } + }, + { "ASUS My Cinema U3100 Mini DVBT Tuner", + { &dib0700_usb_id_table[24], NULL }, + { NULL }, + }, } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 36aeda2b171..a411430f827 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -17,6 +17,7 @@ #define USB_VID_ANCHOR 0x0547 #define USB_VID_ANSONIC 0x10b9 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd +#define USB_VID_ASUS 0x0b05 #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f @@ -182,5 +183,7 @@ #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 /* dom pour gigabyte u7000 */ #define USB_PID_GIGABYTE_U7000 0x7001 +#define USB_PID_ASUS_U3000 0x171f +#define USB_PID_ASUS_U3100 0x173f #endif -- cgit v1.2.3 From 3a0311c6c539bd022a65d298355471aacbd7a618 Mon Sep 17 00:00:00 2001 From: Jose Alberto Reguero Date: Fri, 25 Jan 2008 06:05:16 -0300 Subject: V4L/DVB (7067): fix autoserach in the Hauppauge NOVA-T 500 This patch fix autoserach in the Hauppauge NOVA-T 500. Signed-off-by: Jose Alberto Reguero Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index edae0be063f..3667f8e4809 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -700,7 +700,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 100, found; + int i = 1000, found; dib3000mc_autosearch_start(fe, fep); do { -- cgit v1.2.3 From c7637b1a31bb0470e1247f1923a323c90927ac37 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 25 Jan 2008 06:16:36 -0300 Subject: V4L/DVB (7068): Add support for WinTV Nova-T-CE driver Add support for WinTV Nova-T-CE driver Signed-off-by: Tim Taubert Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 15 +++++++++++++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index de36790899b..4c8c7120658 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -875,6 +875,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, +/* 25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1060,7 +1061,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 4, + .num_device_descs = 5, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -1078,7 +1079,17 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[24], NULL }, { NULL }, }, - } + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[25], NULL }, + { NULL }, + }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index a411430f827..35df40f5f7e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -128,6 +128,7 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 -- cgit v1.2.3 From 13b83b5d516abe2610ae7812267d7d322050bf68 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Fri, 25 Jan 2008 06:20:02 -0300 Subject: V4L/DVB (7069): Support for myTV.t Here's a roll-up which provides support for both this and the myTV.t. Signed-off-by: Darren Salt Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 4c8c7120658..36d29f9d2f6 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -876,6 +876,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, /* 25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1061,7 +1062,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 5, + .num_device_descs = 6, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -1083,6 +1084,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[25], NULL }, { NULL }, }, + { "Hauppauge Nova-T MyTV.t", + { &dib0700_usb_id_table[26], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 35df40f5f7e..aa4844ef875 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -129,6 +129,7 @@ #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 +#define USB_PID_HAUPPAUGE_MYTV_T 0x7080 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 -- cgit v1.2.3 From 853ea132c75ff2c4e3c3aaf61bf3ef5779774dbc Mon Sep 17 00:00:00 2001 From: Soeren Moch Date: Fri, 25 Jan 2008 06:27:06 -0300 Subject: V4L/DVB (7070): Fix some tuning problems The attached patch solves all my vdr tuning problems on a dib7000p nova-t stick as far as I could check within the last weekend. It disables streaming while tuning, like that the number of faulty TS packets is reduced. Signed-off-by: Soeren Moch Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib3000mc.c | 8 ++++++-- drivers/media/dvb/frontends/dib7000m.c | 9 ++++++--- drivers/media/dvb/frontends/dib7000p.c | 8 +++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 3667f8e4809..fa851601e7d 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; + int ret; + + dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, dib3000mc_get_frontend(fe, fep); } + ret = dib3000mc_tune(fe, fep); + /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - - return dib3000mc_tune(fe, fep); + return ret; } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index fb18441a8c5..5f1375e30df 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - int time; + int time, ret; + + dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, dib7000m_get_frontend(fe, fep); } + ret = dib7000m_tune(fe, fep); + /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - - return dib7000m_tune(fe, fep); + return ret; } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index f45bcfc51cf..0396a6f31ef 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1128,8 +1128,9 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - int time; + int time, ret; + dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -1166,10 +1167,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, dib7000p_get_frontend(fe, fep); } + ret = dib7000p_tune(fe, fep); + /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - - return dib7000p_tune(fe, fep); + return ret; } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) -- cgit v1.2.3 From a162abb06bda3f38750a208e85e27f419798aa79 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 25 Jan 2008 06:37:57 -0300 Subject: V4L/DVB (7071): DiB0700: Start streaming the right way There was a mistake in the way how to start the streaming in the dib0700. This patch fixes that. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 3ea294eb96b..c9857d5c698 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) u8 b[4]; b[0] = REQUEST_ENABLE_VIDEO; - b[1] = 0x00; + b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ b[2] = (0x01 << 4); /* Master mode */ b[3] = 0x00; @@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) b[2] |= st->channel_state; - if (st->channel_state) /* if at least one channel is active */ - b[1] = (0x01 << 4) | 0x00; - deb_info("data for streaming: %x %x\n",b[1],b[2]); return dib0700_ctrl_wr(adap->dev, b, 4); -- cgit v1.2.3 From c52344fdc49665a4eeef24236750b49637d6982f Mon Sep 17 00:00:00 2001 From: Olivier DANET Date: Fri, 25 Jan 2008 06:50:07 -0300 Subject: V4L/DVB (7072): sets the MT2060 IF1 frequency according to EEPROM Here is a patch for Hauppage Nova-T-Stick and Nova-T-500 users. It sets the MT2060 IF1 frequency according to the calibration values stored in the EEPROM. It is supposed to enhance the signal quality, but, hey, there is no guarantee. Feedbacks would be much appreciated, to know whether it deserves being applied. Signed-off-by: Olivier DANET Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 32 ++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 36d29f9d2f6..ffecb6ed819 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } +int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) +{ + struct i2c_msg msg[2] = { + { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, + }; + if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; + return 0; +} + static int bristol_tuner_attach(struct dvb_usb_adapter *adap) { - struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id], - st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE && + adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) { + if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; + } + return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], + if1) == NULL ? -ENODEV : 0; } /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ @@ -628,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = { static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) { + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; struct dib0700_state *st = adap->dev->priv; struct i2c_adapter *tun_i2c; - + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE && + adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) { + if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; + } if (st->is_dib7000pc) tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); else tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, - st->mt2060_if1[0]) == NULL ? -ENODEV : 0; + if1) == NULL ? -ENODEV : 0; } /* DIB7070 generic */ -- cgit v1.2.3 From 3cb2c39ded029b8572cf7625b8042e9984d63c2c Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 25 Jan 2008 07:25:20 -0300 Subject: V4L/DVB (7073): DiB7070: Reception quality improved Removing two bugs to improve sensitivity for DiB7070 and Dib7000P with MT2266. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 6 ++++++ drivers/media/dvb/frontends/dib0070.c | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index ffecb6ed819..1c6843c631e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -781,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -820,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -832,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 481eaa68415..fe895bf7b18 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] = 0, }; -static void dib0070_wbd_calibration(struct dib0070_state *state) +static void dib0070_wbd_calibration(struct dvb_frontend *fe) { u16 wbd_offs; + struct dib0070_state *state = fe->tuner_priv; + + if (state->cfg->sleep) + state->cfg->sleep(fe, 0); + dib0070_write_reg(state, 0x0f, 0x6d81); dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); msleep(9); @@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state) dib0070_write_reg(state, 0x20, 0); state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); + + if (state->cfg->sleep) + state->cfg->sleep(fe, 1); + } u16 dib0070_wbd_offset(struct dvb_frontend *fe) @@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter if (dib0070_reset(state) != 0) goto free_mem; - dib0070_wbd_calibration(state); + dib0070_wbd_calibration(fe); printk(KERN_INFO "DiB0070: successfully identified\n"); memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); -- cgit v1.2.3 From 904a82e3e27b57a2518f7575c0cab9b6aaddc422 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 25 Jan 2008 07:31:58 -0300 Subject: V4L/DVB (7074): DiB7000P: correct tuning problem for 7MHz channel Tuning problem for 7Mhz channels fixes Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib7000p.c | 10 ++++------ drivers/media/dvb/frontends/dibx000_common.h | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 0396a6f31ef..47c23e29753 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -35,8 +35,8 @@ struct dib7000p_state { u16 wbd_ref; - u8 current_band; - fe_bandwidth_t current_bandwidth; + u8 current_band; + u32 current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; @@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe, fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = state->current_bandwidth; + fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); switch ((tps >> 8) & 0x3) { case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; @@ -1131,10 +1131,8 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, int time, ret; dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); - /* maybe the parameter has been changed */ + /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5e17275afd2..84e4d536292 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -128,6 +128,11 @@ enum dibx000_adc_states { (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) +#define BANDWIDTH_TO_INDEX(v) ( \ + (v) == 8000 ? BANDWIDTH_8_MHZ : \ + (v) == 7000 ? BANDWIDTH_7_MHZ : \ + (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) + /* Chip output mode. */ #define OUTMODE_HIGH_Z 0 #define OUTMODE_MPEG2_PAR_GATED_CLK 1 -- cgit v1.2.3 From 4a2b108379743405bc488eaef6a75080aa1bbba4 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Fri, 25 Jan 2008 07:32:58 -0300 Subject: V4L/DVB (7075): Make a local function static Make a local function static Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 1c6843c631e..e7093826e97 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -94,7 +94,7 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } -int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) +static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) { struct i2c_msg msg[2] = { { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, -- cgit v1.2.3 From 386900781205d203c1141d3e2dae759f1b531193 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 21 Jan 2008 12:15:19 -0300 Subject: V4L/DVB (7077): bt878: remove handcrafted PCI subsystem ID check This patch moves the subsystem ID and subsystem vendor ID check from probing function to the PCI generic function by describing subsystem IDs in pci_device_id table. This enables to add new PCI IDs to a device driver pci_ids table at runtime by new_id file in sysfs pci driver tree. Signed-off-by: Akinobu Mita Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- Documentation/dvb/bt8xx.txt | 12 +++++++ drivers/media/dvb/bt8xx/bt878.c | 76 ++++++++++++++++++----------------------- drivers/media/dvb/bt8xx/bt878.h | 6 ---- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt index ecb47adda06..b7b1d1b1da4 100644 --- a/Documentation/dvb/bt8xx.txt +++ b/Documentation/dvb/bt8xx.txt @@ -78,6 +78,18 @@ Example: For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv. In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org. +2c) Probing the cards with broken PCI subsystem ID +-------------------------------------------------- +There are some TwinHan cards that the EEPROM has become corrupted for some +reason. The cards do not have correct PCI subsystem ID. But we can force +probing the cards with broken PCI subsystem ID + + $ echo 109e 0878 $subvendor $subdevice > \ + /sys/bus/pci/drivers/bt878/new_id + +109e: PCI_VENDOR_ID_BROOKTREE +0878: PCI_DEVICE_ID_BROOKTREE_878 + Authors: Richard Walker, Jamie Honan, Michael Hunold, diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 85e36a1d6d7..c7bbb40223f 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet * EXPORT_SYMBOL(bt878_device_control); +#define BROOKTREE_878_DEVICE(vend, dev, name) \ + { \ + .vendor = PCI_VENDOR_ID_BROOKTREE, \ + .device = PCI_DEVICE_ID_BROOKTREE_878, \ + .subvendor = (vend), .subdevice = (dev), \ + .driver_data = (unsigned long) name \ + } -static struct cards card_list[] __devinitdata = { - - { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, - { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, - { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, - { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, - { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, - { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, - { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, - { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, - { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, - { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, - { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" } +static struct pci_device_id bt878_pci_tbl[] __devinitdata = { + BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), + BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), + BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), + BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), + BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), + BROOKTREE_878_DEVICE(0x270f, 0xfc00, + "ChainTech digitop DST-1000 DVB-S"), + BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), + BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), + BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), + { } }; +MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); + +static const char * __devinit card_name(const struct pci_device_id *id) +{ + return id->driver_data ? (const char *)id->driver_data : "Unknown"; +} /***********************/ /* PCI device handling */ @@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = { static int __devinit bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { - int result = 0, has_dvb = 0, i; + int result = 0; unsigned char lat; struct bt878 *bt; #if defined(__powerpc__) unsigned int cmd; #endif unsigned int cardid; - unsigned short id; - struct cards *dvb_cards; printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); @@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev, if (pci_enable_device(dev)) return -EIO; - pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id); - cardid = id << 16; - pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id); - cardid |= id; - - for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) { - if (cardid == dvb_cards->pci_id) { - printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n", - __func__, cardid, dvb_cards->name); - has_dvb = 1; - } - } + cardid = dev->subsystem_device << 16; + cardid |= dev->subsystem_vendor; - if (!has_dvb) { - printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid); - result = -EINVAL; - - goto fail0; - } + printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", + __func__, cardid, card_name(pci_id)); bt = &bt878[bt878_num]; bt->dev = dev; @@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) return; } -static struct pci_device_id bt878_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); - static struct pci_driver bt878_pci_driver = { .name = "bt878", .id_table = bt878_pci_tbl, diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index d593bc14562..375fd2892a1 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -101,12 +101,6 @@ #define BTTV_BOARD_DVICO_DVBT_LITE 0x80 #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 -struct cards { - __u32 pci_id; - __u16 card_id; - char *name; -}; - extern int bt878_num; struct bt878 { -- cgit v1.2.3 From a999337b49fcdd2c4a475e97e4b8337ebdfa4abf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 23 Jan 2008 02:39:39 -0300 Subject: V4L/DVB (7078): radio: fix sf16fmi section mismatch isapnp_fmi_probe() is only called by fmi_init(), which is __init, so isapnp_fmi_probe() can also be __init. media/radio/radio-sf16fmi.c: WARNING: vmlinux.o(.text+0x994e19): Section mismatch: reference to .init.data: (between 'isapnp_fmi_probe' and 'vidioc_s_tuner') WARNING: vmlinux.o(.text+0x994e22): Section mismatch: reference to .init.data: (between 'isapnp_fmi_probe' and 'vidioc_s_tuner') WARNING: vmlinux.o(.text+0x994e3a): Section mismatch: reference to .init.data:id_table (between 'isapnp_fmi_probe' and 'vidioc_s_tuner') Signed-off-by: Randy Dunlap Acked-by: Sam Ravnborg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-sf16fmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 395165367f3..3118bdab318 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = { MODULE_DEVICE_TABLE(isapnp, id_table); -static int isapnp_fmi_probe(void) +static int __init isapnp_fmi_probe(void) { int i = 0; -- cgit v1.2.3