diff options
Diffstat (limited to 'linux/drivers')
234 files changed, 16397 insertions, 3356 deletions
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c index b58c8907f..6c0a80f45 100644 --- a/linux/drivers/media/common/ir-keymaps.c +++ b/linux/drivers/media/common/ir-keymaps.c @@ -2561,3 +2561,35 @@ IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys); + +/* ATI TV Wonder HD 600 USB + Devin Heitmueller <devin.heitmueller@gmail.com> + */ +IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = { + [0x00] = KEY_RECORD, /* Row 1 */ + [0x01] = KEY_PLAYPAUSE, + [0x02] = KEY_STOP, + [0x03] = KEY_POWER, + [0x04] = KEY_PREVIOUS, /* Row 2 */ + [0x05] = KEY_REWIND, + [0x06] = KEY_FORWARD, + [0x07] = KEY_NEXT, + [0x08] = KEY_EPG, /* Row 3 */ + [0x09] = KEY_HOME, + [0x0a] = KEY_MENU, + [0x0b] = KEY_CHANNELUP, + [0x0c] = KEY_BACK, /* Row 4 */ + [0x0d] = KEY_UP, + [0x0e] = KEY_INFO, + [0x0f] = KEY_CHANNELDOWN, + [0x10] = KEY_LEFT, /* Row 5 */ + [0x11] = KEY_SELECT, + [0x12] = KEY_RIGHT, + [0x13] = KEY_VOLUMEUP, + [0x14] = KEY_LAST, /* Row 6 */ + [0x15] = KEY_DOWN, + [0x16] = KEY_MUTE, + [0x17] = KEY_VOLUMEDOWN, +}; + +EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600); diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c index 37a227d01..cd4f95860 100644 --- a/linux/drivers/media/common/saa7146_fops.c +++ b/linux/drivers/media/common/saa7146_fops.c @@ -314,7 +314,7 @@ static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd, /* DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg)); */ - return video_usercopy(inode, file, cmd, arg, saa7146_video_do_ioctl); + return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl); } static int fops_mmap(struct file *file, struct vm_area_struct * vma) @@ -546,11 +546,11 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, if( VFL_TYPE_GRABBER == type ) { vv->video_minor = vfd->minor; INFO(("%s: registered device video%d [v4l2]\n", - dev->name, vfd->minor & 0x1f)); + dev->name, vfd->num)); } else { vv->vbi_minor = vfd->minor; INFO(("%s: registered device vbi%d [v4l2]\n", - dev->name, vfd->minor & 0x1f)); + dev->name, vfd->num)); } *vid = vfd; diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index 8804d4e78..12717058e 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -835,7 +835,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file) * copying is done already, arg is a kernel pointer. */ -int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) +int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; @@ -1216,7 +1216,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int } #endif default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, + return v4l_compat_translate_ioctl(file, cmd, arg, saa7146_video_do_ioctl); } return 0; diff --git a/linux/drivers/media/common/tuners/mxl5005s.c b/linux/drivers/media/common/tuners/mxl5005s.c index 20405506a..58418277a 100644 --- a/linux/drivers/media/common/tuners/mxl5005s.c +++ b/linux/drivers/media/common/tuners/mxl5005s.c @@ -3483,7 +3483,9 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, } ctrlVal = 0; for (k = 0; k < state->MXL_Ctrl[i].size; k++) - ctrlVal += state->MXL_Ctrl[i].val[k] * (1 << k); + ctrlVal += state-> + MXL_Ctrl[i].val[k] * + (1 << k); } else return -1; } @@ -3583,7 +3585,7 @@ static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, static u32 MXL_Ceiling(u32 value, u32 resolution) { - return (value/resolution + (value % resolution > 0 ? 1 : 0)); + return value / resolution + (value % resolution > 0 ? 1 : 0); } /* Retrieve the Initialzation Registers */ @@ -3598,7 +3600,7 @@ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, 76, 77, 91, 134, 135, 137, 147, 156, 166, 167, 168, 25 }; - *count = sizeof(RegAddr) / sizeof(u8); + *count = ARRAY_SIZE(RegAddr); status += MXL_BlockInit(fe); @@ -3630,7 +3632,7 @@ static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, */ #endif - *count = sizeof(RegAddr) / sizeof(u8); + *count = ARRAY_SIZE(RegAddr); for (i = 0 ; i < *count; i++) { RegNum[i] = RegAddr[i]; @@ -3648,7 +3650,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, u8 RegAddr[] = {43, 136}; - *count = sizeof(RegAddr) / sizeof(u8); + *count = ARRAY_SIZE(RegAddr); for (i = 0; i < *count; i++) { RegNum[i] = RegAddr[i]; @@ -3912,7 +3914,10 @@ static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, static int mxl5005s_init(struct dvb_frontend *fe) { + struct mxl5005s_state *state = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + state->current_mode = MXL_QAM; return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); } @@ -4094,7 +4099,6 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, state->frontend = fe; state->config = config; state->i2c = i2c; - state->current_mode = MXL_QAM; printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", config->i2c_address); diff --git a/linux/drivers/media/common/tuners/tda9887.c b/linux/drivers/media/common/tuners/tda9887.c index effbf31da..8df82bfab 100644 --- a/linux/drivers/media/common/tuners/tda9887.c +++ b/linux/drivers/media/common/tuners/tda9887.c @@ -181,11 +181,10 @@ static struct tvnorm tvnorms[] = { },{ .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, .name = "SECAM-BGH", - .b = ( cPositiveAmTV | + .b = ( cNegativeFmTV | cQSS ), .c = ( cTopDefault), - .e = ( cGating_36 | - cAudioIF_5_5 | + .e = ( cAudioIF_5_5 | cVideoIF_38_90 ), },{ .std = V4L2_STD_SECAM_L, diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c index 036504510..0d9fc1bb2 100644 --- a/linux/drivers/media/common/tuners/tuner-simple.c +++ b/linux/drivers/media/common/tuners/tuner-simple.c @@ -513,6 +513,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: case TUNER_LG_NTSC_TAPE: case TUNER_PHILIPS_FM1256_IH3: case TUNER_TCL_MF02GIP_5N: @@ -787,6 +788,7 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, switch (priv->type) { case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && params->frequency >= 158870000) buf[3] |= 0x08; diff --git a/linux/drivers/media/common/tuners/tuner-types.c b/linux/drivers/media/common/tuners/tuner-types.c index 861d23872..d83df3604 100644 --- a/linux/drivers/media/common/tuners/tuner-types.c +++ b/linux/drivers/media/common/tuners/tuner-types.c @@ -947,7 +947,7 @@ static struct tuner_params tuner_tena_9533_di_params[] = { }, }; -/* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */ +/* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, @@ -985,6 +985,27 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { }, }; +static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_active = 1, + .port2_fm_high_sensitivity = 1, + .port2_invert_for_secam_lc = 1, + .port1_set_for_fm_mono = 1, + .radio_if = 1, + .fm_gain_normal = 1, + }, + { + .type = TUNER_PARAM_TYPE_DIGITAL, + .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), + .iffreq = 16 * 36.125, /*MHz*/ + }, +}; /* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ @@ -1664,6 +1685,16 @@ struct tunertype tuners[] = { .params = tuner_tcl_mf02gip_5n_params, .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), }, + [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ + .name = "Philips FMD1216MEX MK3 Hybrid Tuner", + .params = tuner_philips_fmd1216mex_mk3_params, + .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), + .min = 16 * 50.87, + .max = 16 * 858.00, + .stepsize = 166667, + .initdata = tua603x_agc112, + .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, + }, }; EXPORT_SYMBOL(tuners); diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c index f3a3c47fe..8cfac7002 100644 --- a/linux/drivers/media/common/tuners/xc5000.c +++ b/linux/drivers/media/common/tuners/xc5000.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); static DEFINE_MUTEX(xc5000_list_mutex); static LIST_HEAD(hybrid_tuner_instance_list); -#define dprintk(level,fmt, arg...) if (debug >= level) \ +#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" @@ -138,11 +138,11 @@ struct xc5000_priv { immediately the length of the following transaction. */ -typedef struct { +struct XC_TV_STANDARD { char *Name; u16 AudioMode; u16 VideoMode; -} XC_TV_STANDARD; +}; /* Tuner standards */ #define MN_NTSC_PAL_BTSC 0 @@ -169,7 +169,7 @@ typedef struct { #define FM_Radio_INPUT2 21 #define FM_Radio_INPUT1 22 -static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { +static struct 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}, @@ -183,7 +183,7 @@ static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"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 L/DK3", 0x0E00, 0x8009}, {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, {"L-SECAM-NICAM", 0x8E82, 0x0009}, {"L'-SECAM-NICAM", 0x8E82, 0x4009}, @@ -307,9 +307,10 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) unsigned int len, pos, index; 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]; + 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); @@ -329,15 +330,17 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) 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 { + 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; i < nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + + i - 2]; } - for (i=2; i<nbytes_to_send; i++) { - buf[i] = i2c_sequence[index + pos + i - 2]; - } - result = xc_send_i2c_data(priv, buf, nbytes_to_send); + result = xc_send_i2c_data(priv, buf, + nbytes_to_send); if (result != XC_RESULT_SUCCESS) return result; @@ -386,8 +389,7 @@ static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) dprintk(1, "%s(%d) Source = %s\n", __func__, 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 "%s(), Invalid mode, defaulting to CABLE", @@ -579,13 +581,13 @@ static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) .flags = I2C_M_RD, .buf = buf, .len = len }; if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len); return -EREMOTEIO; } return 0; } -static int xc5000_fwupload(struct dvb_frontend* fe) +static int xc5000_fwupload(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; const struct firmware *fw; @@ -595,7 +597,8 @@ static int xc5000_fwupload(struct dvb_frontend* fe) printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", XC5000_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev); + ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, + &priv->i2c_props.adap->dev); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; @@ -611,7 +614,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe) ret = XC_RESULT_RESET_FAILURE; } else { printk(KERN_INFO "xc5000: firmware upload\n"); - ret = xc_load_i2c_sequence(fe, fw->data ); + ret = xc_load_i2c_sequence(fe, fw->data); } out: @@ -670,7 +673,7 @@ static int xc5000_set_params(struct dvb_frontend *fe, dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); - switch(params->u.vsb.modulation) { + switch (params->u.vsb.modulation) { case VSB_8: case VSB_16: dprintk(1, "%s() VSB modulation\n", __func__); @@ -767,42 +770,42 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, /* 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + if (params->std & V4L2_STD_SECAM_L) { priv->video_standard = L_SECAM_NICAM; goto tune_channel; } - if(params->std & V4L2_STD_SECAM_LC) { + if (params->std & V4L2_STD_SECAM_LC) { priv->video_standard = LC_SECAM_NICAM; goto tune_channel; } @@ -810,7 +813,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, tune_channel: ret = xc_SetSignalSource(priv, priv->rf_mode); if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR + printk(KERN_ERR "xc5000: xc_SetSignalSource(%d) failed\n", priv->rf_mode); return -EREMOTEIO; @@ -882,7 +885,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) * I2C transactions until calibration is complete. This way we * don't have to rely on clock stretching working. */ - xc_wait( 100 ); + xc_wait(100); /* Default to "CABLE" mode */ ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); @@ -904,15 +907,13 @@ static int xc5000_sleep(struct dvb_frontend *fe) */ ret = xc_shutdown(priv); - if(ret != XC_RESULT_SUCCESS) { + if (ret != XC_RESULT_SUCCESS) { printk(KERN_ERR "xc5000: %s() unable to shutdown tuner\n", __func__); return -EREMOTEIO; - } - else { + } else return XC_RESULT_SUCCESS; - } } static int xc5000_init(struct dvb_frontend *fe) @@ -1008,7 +1009,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) goto fail; - switch(id) { + switch (id) { case XC_PRODUCT_ID_FW_LOADED: printk(KERN_INFO "xc5000: Successfully identified at address 0x%02x\n", diff --git a/linux/drivers/media/common/tuners/xc5000.h b/linux/drivers/media/common/tuners/xc5000.h index cf1a558e0..f4c146698 100644 --- a/linux/drivers/media/common/tuners/xc5000.h +++ b/linux/drivers/media/common/tuners/xc5000.h @@ -45,17 +45,17 @@ struct xc5000_config { #if defined(CONFIG_MEDIA_TUNER_XC5000) || \ (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) -extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, +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, +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", __func__); return NULL; } -#endif // CONFIG_MEDIA_TUNER_XC5000 +#endif -#endif // __XC5000_H__ +#endif diff --git a/linux/drivers/media/dvb/Kconfig b/linux/drivers/media/dvb/Kconfig index 0bcd85257..40ebde53b 100644 --- a/linux/drivers/media/dvb/Kconfig +++ b/linux/drivers/media/dvb/Kconfig @@ -2,6 +2,19 @@ # DVB device configuration # +config DVB_DYNAMIC_MINORS + bool "Dynamic DVB minor allocation" + depends on DVB_CORE + default n + help + If you say Y here, the DVB subsystem will use dynamic minor + allocation for any device that uses the DVB major number. + This means that you can have more than 4 of a single type + of device (like demuxes and frontends) per adapter, but udev + will be required to manage the device nodes. + + If you are unsure about this, say N here. + menuconfig DVB_CAPTURE_DRIVERS bool "DVB/ATSC adapters" depends on DVB_CORE diff --git a/linux/drivers/media/dvb/dm1105/dm1105.c b/linux/drivers/media/dvb/dm1105/dm1105.c index 07ebe639f..100a7f661 100644 --- a/linux/drivers/media/dvb/dm1105/dm1105.c +++ b/linux/drivers/media/dvb/dm1105/dm1105.c @@ -19,7 +19,6 @@ * */ -#include <linux/version.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> @@ -368,11 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb) { dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - return pci_dma_mapping_error(dm1105dvb->dma_addr); -#else - return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr); -#endif + return !dm1105dvb->ts_buf; } static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) @@ -380,7 +375,7 @@ static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr); } -static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb) +static void dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb) { outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK)); outb(1, dm_io_mem(DM1105_CR)); @@ -603,6 +598,18 @@ static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb) dm1105dvb_dma_unmap(dm1105dvb); } +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + static struct stv0288_config earda_config = { .demod_address = 0x68, .min_delay_ms = 100, diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index 51fb82edc..e7adf9f47 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -133,6 +133,7 @@ struct dvb_frontend_private { unsigned int step_size; int quality; unsigned int check_wrapped; + enum dvbfe_search algo_status; }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); @@ -228,6 +229,8 @@ static void dvb_frontend_init(struct dvb_frontend *fe) if (fe->ops.init) fe->ops.init(fe); if (fe->ops.tuner_ops.init) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.init(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -519,6 +522,8 @@ static int dvb_frontend_thread(void *data) struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; fe_status_t s; + enum dvbfe_algo algo; + struct dvb_frontend_parameters *params; dprintk("%s\n", __func__); @@ -571,29 +576,88 @@ restart: /* do an iteration of the tuning loop */ if (fe->ops.get_frontend_algo) { - if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { - /* have we been asked to retune? */ - params = NULL; + algo = fe->ops.get_frontend_algo(fe); + switch (algo) { + case DVBFE_ALGO_HW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); + params = NULL; /* have we been asked to RETUNE ? */ + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); params = &fepriv->parameters; fepriv->state = FESTATE_TUNED; } - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + if (fe->ops.tune) + fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + if (s != fepriv->status) { + dprintk("%s: state changed, adding current state\n", __func__); dvb_frontend_add_event(fe, s); fepriv->status = s; } - } else + break; + case DVBFE_ALGO_SW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); dvb_frontend_swzigzag(fe); - } else + break; + case DVBFE_ALGO_CUSTOM: + params = NULL; /* have we been asked to RETUNE ? */ + dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); + if (fepriv->state & FESTATE_RETUNE) { + dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); + params = &fepriv->parameters; + fepriv->state = FESTATE_TUNED; + } + /* Case where we are going to search for a carrier + * User asked us to retune again for some reason, possibly + * requesting a search with a new set of parameters + */ + if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { + if (fe->ops.search) { + fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters); + /* We did do a search as was requested, the flags are + * now unset as well and has the flags wrt to search. + */ + } else { + fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; + } + } + /* Track the carrier if the search was successful */ + if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { + if (fe->ops.track) + fe->ops.track(fe, &fepriv->parameters); + } else { + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + fepriv->delay = HZ / 2; + } + fe->ops.read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); /* update event list */ + fepriv->status = s; + if (!(s & FE_HAS_LOCK)) { + fepriv->delay = HZ / 10; + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + } else { + fepriv->delay = 60 * HZ; + } + } + break; + default: + dprintk("%s: UNDEFINED ALGO !\n", __func__); + break; + } + } else { dvb_frontend_swzigzag(fe); + } } if (dvb_powerdown_on_sleep) { if (fe->ops.set_voltage) fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -973,36 +1037,37 @@ void dtv_property_dump(struct dtv_property *tvp) int i; if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n", + printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n", __func__, tvp->cmd); return; } - printk("%s() tvp.cmd = 0x%08x (%s)\n" - ,__FUNCTION__ + dprintk("%s() tvp.cmd = 0x%08x (%s)\n" + ,__func__ ,tvp->cmd ,dtv_cmds[ tvp->cmd ].name); if(dtv_cmds[ tvp->cmd ].buffer) { - printk("%s() tvp.u.buffer.len = 0x%02x\n" - ,__FUNCTION__ + dprintk("%s() tvp.u.buffer.len = 0x%02x\n" + ,__func__ ,tvp->u.buffer.len); for(i = 0; i < tvp->u.buffer.len; i++) - printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" - ,__FUNCTION__ + dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" + ,__func__ ,i ,tvp->u.buffer.data[i]); } else - printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data); + dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); } int is_legacy_delivery_system(fe_delivery_system_t s) { if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS)) + (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || + (s == SYS_ATSC)) return 1; return 0; @@ -1016,8 +1081,6 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame { struct dtv_frontend_properties *c = &fe->dtv_property_cache; - printk("%s()\n", __FUNCTION__); - c->frequency = p->frequency; c->inversion = p->inversion; @@ -1072,27 +1135,25 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe) struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_parameters *p = &fepriv->parameters; - printk("%s()\n", __FUNCTION__); - p->frequency = c->frequency; p->inversion = c->inversion; switch (fe->ops.info.type) { case FE_QPSK: - printk("%s() Preparing QPSK req\n", __FUNCTION__); + dprintk("%s() Preparing QPSK req\n", __func__); p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; c->delivery_system = SYS_DVBS; break; case FE_QAM: - printk("%s() Preparing QAM req\n", __FUNCTION__); + dprintk("%s() Preparing QAM req\n", __func__); p->u.qam.symbol_rate = c->symbol_rate; p->u.qam.fec_inner = c->fec_inner; p->u.qam.modulation = c->modulation; c->delivery_system = SYS_DVBC_ANNEX_AC; break; case FE_OFDM: - printk("%s() Preparing OFDM req\n", __FUNCTION__); + dprintk("%s() Preparing OFDM req\n", __func__); if (c->bandwidth_hz == 6000000) p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; else if (c->bandwidth_hz == 7000000) @@ -1110,7 +1171,7 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe) c->delivery_system = SYS_DVBT; break; case FE_ATSC: - printk("%s() Preparing VSB req\n", __FUNCTION__); + dprintk("%s() Preparing VSB req\n", __func__); p->u.vsb.modulation = c->modulation; if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) c->delivery_system = SYS_ATSC; @@ -1129,8 +1190,6 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe) struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_parameters *p = &fepriv->parameters; - printk("%s()\n", __FUNCTION__); - p->frequency = c->frequency; p->inversion = c->inversion; @@ -1164,19 +1223,17 @@ void dtv_property_cache_submit(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; - printk("%s()\n", __FUNCTION__); - /* For legacy delivery systems we don't need the delivery_system to * be specified, but we populate the older structures from the cache * so we can call set_frontend on older drivers. */ if(is_legacy_delivery_system(c->delivery_system)) { - printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation); + dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation); dtv_property_legacy_params_sync(fe); } else { - printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation); + dprintk("%s() adv, modulation = %d\n", __func__, c->modulation); /* For advanced delivery systems / modulation types ... * we seed the lecacy dvb_frontend_parameters structure @@ -1198,8 +1255,6 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, { int r = 0; - printk("%s()\n", __FUNCTION__); - dtv_property_dump(tvp); /* Allow the frontend to validate incoming properties */ @@ -1309,7 +1364,6 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, { int r = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; - printk("%s()\n", __FUNCTION__); dtv_property_dump(tvp); /* Allow the frontend to validate incoming properties */ @@ -1324,7 +1378,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, /* Reset a cache of data specific to the frontend here. This does * not effect hardware. */ - printk("%s() Flushing property cache\n", __FUNCTION__); + dprintk("%s() Flushing property cache\n", __func__); memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties)); fe->dtv_property_cache.state = tvp->cmd; fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; @@ -1335,9 +1389,12 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, * ioctl. */ fe->dtv_property_cache.state = tvp->cmd; - printk("%s() Finalised property cache\n", __FUNCTION__); + dprintk("%s() Finalised property cache\n", __func__); dtv_property_cache_submit(fe); + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; @@ -1455,12 +1512,10 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, dprintk("%s\n", __func__); if(cmd == FE_SET_PROPERTY) { - printk("%s() FE_SET_PROPERTY\n", __FUNCTION__); - tvps = (struct dtv_properties __user *)parg; - printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num); - printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props); + dprintk("%s() properties.num = %d\n", __func__, tvps->num); + dprintk("%s() properties.props = %p\n", __func__, tvps->props); /* Put an arbitrary limit on the number of messages that can * be sent at once */ @@ -1484,18 +1539,16 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, err |= (tvp + i)->result; } - if(fe->dtv_property_cache.state == DTV_TUNE) { - printk("%s() Property cache is full, tuning\n", __FUNCTION__); - } + if(fe->dtv_property_cache.state == DTV_TUNE) + dprintk("%s() Property cache is full, tuning\n", __func__); } else if(cmd == FE_GET_PROPERTY) { - printk("%s() FE_GET_PROPERTY\n", __FUNCTION__); tvps = (struct dtv_properties __user *)parg; - printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num); - printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props); + dprintk("%s() properties.num = %d\n", __func__, tvps->num); + dprintk("%s() properties.props = %p\n", __func__, tvps->props); /* Put an arbitrary limit on the number of messages that can * be sent at once */ @@ -1825,39 +1878,46 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_adapter *adapter = fe->dvb; - struct dvb_device *mfedev; - struct dvb_frontend *mfe; - struct dvb_frontend_private *mfepriv; - int mferetry; int ret; dprintk ("%s\n", __func__); if (adapter->mfe_shared) { mutex_lock (&adapter->mfe_lock); - if (adapter->mfe_dvbdev != dvbdev) { - if (adapter->mfe_dvbdev) { - mfedev = adapter->mfe_dvbdev; - mfe = mfedev->priv; - mfepriv = mfe->frontend_priv; - mutex_unlock (&adapter->mfe_lock); - mferetry = (dvb_mfe_wait_time << 1); - while (mferetry-- && (mfedev->users != -1 || mfepriv->thread != NULL)) { - if(msleep_interruptible(500)) { - if(signal_pending(current)) - return -EINTR; - } + + if (adapter->mfe_dvbdev == NULL) + adapter->mfe_dvbdev = dvbdev; + + else if (adapter->mfe_dvbdev != dvbdev) { + struct dvb_device + *mfedev = adapter->mfe_dvbdev; + struct dvb_frontend + *mfe = mfedev->priv; + struct dvb_frontend_private + *mfepriv = mfe->frontend_priv; + int mferetry = (dvb_mfe_wait_time << 1); + + mutex_unlock (&adapter->mfe_lock); + while (mferetry-- && (mfedev->users != -1 || + mfepriv->thread != NULL)) { + if(msleep_interruptible(500)) { + if(signal_pending(current)) + return -EINTR; } - mutex_lock (&adapter->mfe_lock); + } + + mutex_lock (&adapter->mfe_lock); + if(adapter->mfe_dvbdev != dvbdev) { mfedev = adapter->mfe_dvbdev; mfe = mfedev->priv; mfepriv = mfe->frontend_priv; - if (mfedev->users != -1 || mfepriv->thread != NULL) { - ret = -EBUSY; - goto err0; + if (mfedev->users != -1 || + mfepriv->thread != NULL) { + mutex_unlock (&adapter->mfe_lock); + return -EBUSY; } + adapter->mfe_dvbdev = dvbdev; } - adapter->mfe_dvbdev = dvbdev; } } diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h index 569b72a96..cff26dd66 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -69,6 +69,125 @@ struct analog_parameters { u64 std; }; +enum dvbfe_modcod { + DVBFE_MODCOD_DUMMY_PLFRAME = 0, + DVBFE_MODCOD_QPSK_1_4, + DVBFE_MODCOD_QPSK_1_3, + DVBFE_MODCOD_QPSK_2_5, + DVBFE_MODCOD_QPSK_1_2, + DVBFE_MODCOD_QPSK_3_5, + DVBFE_MODCOD_QPSK_2_3, + DVBFE_MODCOD_QPSK_3_4, + DVBFE_MODCOD_QPSK_4_5, + DVBFE_MODCOD_QPSK_5_6, + DVBFE_MODCOD_QPSK_8_9, + DVBFE_MODCOD_QPSK_9_10, + DVBFE_MODCOD_8PSK_3_5, + DVBFE_MODCOD_8PSK_2_3, + DVBFE_MODCOD_8PSK_3_4, + DVBFE_MODCOD_8PSK_5_6, + DVBFE_MODCOD_8PSK_8_9, + DVBFE_MODCOD_8PSK_9_10, + DVBFE_MODCOD_16APSK_2_3, + DVBFE_MODCOD_16APSK_3_4, + DVBFE_MODCOD_16APSK_4_5, + DVBFE_MODCOD_16APSK_5_6, + DVBFE_MODCOD_16APSK_8_9, + DVBFE_MODCOD_16APSK_9_10, + DVBFE_MODCOD_32APSK_3_4, + DVBFE_MODCOD_32APSK_4_5, + DVBFE_MODCOD_32APSK_5_6, + DVBFE_MODCOD_32APSK_8_9, + DVBFE_MODCOD_32APSK_9_10, + DVBFE_MODCOD_RESERVED_1, + DVBFE_MODCOD_BPSK_1_3, + DVBFE_MODCOD_BPSK_1_4, + DVBFE_MODCOD_RESERVED_2 +}; + +enum tuner_param { + DVBFE_TUNER_FREQUENCY = (1 << 0), + DVBFE_TUNER_TUNERSTEP = (1 << 1), + DVBFE_TUNER_IFFREQ = (1 << 2), + DVBFE_TUNER_BANDWIDTH = (1 << 3), + DVBFE_TUNER_REFCLOCK = (1 << 4), + DVBFE_TUNER_IQSENSE = (1 << 5), + DVBFE_TUNER_DUMMY = (1 << 31) +}; + +/* + * ALGO_HW: (Hardware Algorithm) + * ---------------------------------------------------------------- + * Devices that support this algorithm do everything in hardware + * and no software support is needed to handle them. + * Requesting these devices to LOCK is the only thing required, + * device is supposed to do everything in the hardware. + * + * ALGO_SW: (Software Algorithm) + * ---------------------------------------------------------------- + * These are dumb devices, that require software to do everything + * + * ALGO_CUSTOM: (Customizable Agorithm) + * ---------------------------------------------------------------- + * Devices having this algorithm can be customized to have specific + * algorithms in the frontend driver, rather than simply doing a + * software zig-zag. In this case the zigzag maybe hardware assisted + * or it maybe completely done in hardware. In all cases, usage of + * this algorithm, in conjunction with the search and track + * callbacks, utilizes the driver specific algorithm. + * + * ALGO_RECOVERY: (Recovery Algorithm) + * ---------------------------------------------------------------- + * These devices have AUTO recovery capabilities from LOCK failure + */ +enum dvbfe_algo { + DVBFE_ALGO_HW = (1 << 0), + DVBFE_ALGO_SW = (1 << 1), + DVBFE_ALGO_CUSTOM = (1 << 2), + DVBFE_ALGO_RECOVERY = (1 << 31) +}; + +struct tuner_state { + u32 frequency; + u32 tunerstep; + u32 ifreq; + u32 bandwidth; + u32 iqsense; + u32 refclock; +}; + +/* + * search callback possible return status + * + * DVBFE_ALGO_SEARCH_SUCCESS + * The frontend search algorithm completed and returned succesfully + * + * DVBFE_ALGO_SEARCH_ASLEEP + * The frontend search algorithm is sleeping + * + * DVBFE_ALGO_SEARCH_FAILED + * The frontend search for a signal failed + * + * DVBFE_ALGO_SEARCH_INVALID + * The frontend search algorith was probably supplied with invalid + * parameters and the search is an invalid one + * + * DVBFE_ALGO_SEARCH_ERROR + * The frontend search algorithm failed due to some error + * + * DVBFE_ALGO_SEARCH_AGAIN + * The frontend search algorithm was requested to search again + */ +enum dvbfe_search { + DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), + DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), + DVBFE_ALGO_SEARCH_FAILED = (1 << 2), + DVBFE_ALGO_SEARCH_INVALID = (1 << 3), + DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), + DVBFE_ALGO_SEARCH_ERROR = (1 << 31), +}; + + struct dvb_tuner_ops { struct dvb_tuner_info info; @@ -99,6 +218,13 @@ struct dvb_tuner_ops { * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + + /* + * These are provided seperately from set_params in order to facilitate silicon + * tuners which require sophisticated tuning loops, controlling each parameter seperately. + */ + int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); + int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); }; struct analog_demod_info { @@ -142,7 +268,7 @@ struct dvb_frontend_ops { unsigned int *delay, fe_status_t *status); /* get frontend tuning algorithm from the module */ - int (*get_frontend_algo)(struct dvb_frontend *fe); + enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); /* these two are only used for the swzigzag code */ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); @@ -167,6 +293,12 @@ struct dvb_frontend_ops { int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); + /* These callbacks are for devices that implement their own + * tuning algorithms, rather than a simple swzigzag + */ + enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c index 422af5a0d..fa1adf9dd 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.c +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c @@ -51,33 +51,27 @@ static const char * const dnames[] = { "net", "osd" }; +#ifdef CONFIG_DVB_DYNAMIC_MINORS +#define MAX_DVB_MINORS 256 +#define DVB_MAX_IDS MAX_DVB_MINORS +#else #define DVB_MAX_IDS 4 #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) +#endif static struct class *dvb_class; -static struct dvb_device* dvbdev_find_device (int minor) -{ - struct dvb_adapter *adap; - - list_for_each_entry(adap, &dvb_adapter_list, list_head) { - struct dvb_device *dev; - list_for_each_entry(dev, &adap->device_list, list_head) - if (nums2minor(adap->num, dev->type, dev->id) == minor) - return dev; - } - - return NULL; -} - +static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; +static DECLARE_RWSEM(minor_rwsem); static int dvb_device_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev; lock_kernel(); - dvbdev = dvbdev_find_device (iminor(inode)); + down_read(&minor_rwsem); + dvbdev = dvb_minors[iminor(inode)]; if (dvbdev && dvbdev->fops) { int err = 0; @@ -97,9 +91,11 @@ static int dvb_device_open(struct inode *inode, struct file *file) file->f_op = fops_get(old_fops); } fops_put(old_fops); + up_read(&minor_rwsem); unlock_kernel(); return err; } + up_read(&minor_rwsem); unlock_kernel(); return -ENODEV; } @@ -201,6 +197,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, #else struct class_device *clsdev; #endif + int minor; int id; mutex_lock(&dvbdev_register_lock); @@ -240,15 +237,39 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, list_add_tail (&dvbdev->list_head, &adap->device_list); + down_write(&minor_rwsem); +#ifdef CONFIG_DVB_DYNAMIC_MINORS + for (minor = 0; minor < MAX_DVB_MINORS; minor++) + if (dvb_minors[minor] == NULL) + break; + + if (minor == MAX_DVB_MINORS) { + kfree(dvbdevfops); + kfree(dvbdev); + mutex_unlock(&dvbdev_register_lock); + return -EINVAL; + } +#else + minor = nums2minor(adap->num, type, id); +#endif + + dvbdev->minor = minor; + dvb_minors[minor] = dvbdev; + up_write(&minor_rwsem); + mutex_unlock(&dvbdev_register_lock); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 26) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27) + clsdev = device_create(dvb_class, adap->device, + MKDEV(DVB_MAJOR, minor), + dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 27) clsdev = device_create_drvdata(dvb_class, adap->device, - MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + MKDEV(DVB_MAJOR, minor), + dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); #else clsdev = device_create(dvb_class, adap->device, - MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + MKDEV(DVB_MAJOR, minor), "dvb%d.%s%d", adap->num, dnames[type], id); #endif if (IS_ERR(clsdev)) { @@ -258,8 +279,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", - adap->num, dnames[type], id, nums2minor(adap->num, type, id), - nums2minor(adap->num, type, id)); + adap->num, dnames[type], id, minor, minor); return 0; } @@ -271,8 +291,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); + down_write(&minor_rwsem); + dvb_minors[dvbdev->minor] = NULL; + up_write(&minor_rwsem); + + device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); list_del (&dvbdev->list_head); kfree (dvbdev->fops); @@ -428,6 +451,17 @@ out: return err; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct dvb_device *dvbdev = dev_get_drvdata(dev); + + add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); + add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); + return 0; +} +#endif + static int __init init_dvbdev(void) { int retval; @@ -454,6 +488,9 @@ static int __init init_dvbdev(void) retval = PTR_ERR(dvb_class); goto error; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + dvb_class->dev_uevent = dvb_uevent; +#endif return 0; error: diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h index 574e336ba..dca49cf96 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.h +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h @@ -74,6 +74,7 @@ struct dvb_device { struct file_operations *fops; struct dvb_adapter *adapter; int type; + int minor; u32 id; /* in theory, 'users' can vanish now, diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index 3c13bcfa6..62b68c291 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -261,7 +261,7 @@ config DVB_USB_DW2102 Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers and the TeVii S650. -config DVB_USB_CINERGY_T2 +config DVB_USB_CINERGY_T2 tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" depends on DVB_USB help @@ -283,6 +283,7 @@ config DVB_USB_ANYSEE config DVB_USB_DTV5100 tristate "AME DTV-5100 USB2.0 DVB-T support" depends on DVB_USB + select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c index 64d2d0f8c..21e10fa23 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.c +++ b/linux/drivers/media/dvb/dvb-usb/af9015.c @@ -31,13 +31,13 @@ #include "mc44s80x.h" #endif -int dvb_usb_af9015_debug; +static int dvb_usb_af9015_debug; module_param_named(debug, dvb_usb_af9015_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -int dvb_usb_af9015_remote; +static int dvb_usb_af9015_remote; module_param_named(remote, dvb_usb_af9015_remote, int, 0644); MODULE_PARM_DESC(remote, "select remote"); -int dvb_usb_af9015_dual_mode; +static int dvb_usb_af9015_dual_mode; module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644); MODULE_PARM_DESC(dual_mode, "enable dual mode"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -46,7 +46,7 @@ static DEFINE_MUTEX(af9015_usb_mutex); static struct af9015_config af9015_config; static struct dvb_usb_device_properties af9015_properties[2]; -int af9015_properties_count = ARRAY_SIZE(af9015_properties); +static int af9015_properties_count = ARRAY_SIZE(af9015_properties); static struct af9013_config af9015_af9013_config[] = { { @@ -549,7 +549,7 @@ static int af9015_eeprom_dump(struct dvb_usb_device *d) return 0; } -int af9015_download_ir_table(struct dvb_usb_device *d) +static int af9015_download_ir_table(struct dvb_usb_device *d) { int i, packets = 0, ret; u16 addr = 0x9a56; /* ir-table start address */ @@ -742,7 +742,7 @@ static int af9015_read_config(struct usb_device *udev) } } else { switch (udev->descriptor.idVendor) { - case USB_VID_LEADTEK: + case cpu_to_le16(USB_VID_LEADTEK): af9015_properties[i].rc_key_map = af9015_rc_keys_leadtek; af9015_properties[i].rc_key_map_size = @@ -752,9 +752,9 @@ static int af9015_read_config(struct usb_device *udev) af9015_config.ir_table_size = ARRAY_SIZE(af9015_ir_table_leadtek); break; - case USB_VID_VISIONPLUS: + case cpu_to_le16(USB_VID_VISIONPLUS): if (udev->descriptor.idProduct == - USB_PID_AZUREWAVE_AD_TU700) { + cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) { af9015_properties[i].rc_key_map = af9015_rc_keys_twinhan; af9015_properties[i].rc_key_map_size = @@ -765,7 +765,7 @@ static int af9015_read_config(struct usb_device *udev) ARRAY_SIZE(af9015_ir_table_twinhan); } break; - case USB_VID_KWORLD_2: + case cpu_to_le16(USB_VID_KWORLD_2): /* TODO: use correct rc keys */ af9015_properties[i].rc_key_map = af9015_rc_keys_twinhan; @@ -778,7 +778,7 @@ static int af9015_read_config(struct usb_device *udev) /* Check USB manufacturer and product strings and try to determine correct remote in case of chip vendor reference IDs are used. */ - case USB_VID_AFATECH: + case cpu_to_le16(USB_VID_AFATECH): memset(manufacturer, 0, sizeof(manufacturer)); usb_string(udev, udev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer)); @@ -806,6 +806,16 @@ static int af9015_read_config(struct usb_device *udev) ARRAY_SIZE(af9015_ir_table_msi); } break; + case cpu_to_le16(USB_VID_AVERMEDIA): + af9015_properties[i].rc_key_map = + af9015_rc_keys_avermedia; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_avermedia); + af9015_config.ir_table = + af9015_ir_table_avermedia; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_avermedia); + break; } } } @@ -999,7 +1009,7 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state) } /* init 2nd I2C adapter */ -int af9015_i2c_init(struct dvb_usb_device *d) +static int af9015_i2c_init(struct dvb_usb_device *d) { int ret; struct af9015_state *state = d->priv; @@ -1197,6 +1207,7 @@ static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, /* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1347,7 +1358,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { .name = "Xtensions XD-380", @@ -1379,6 +1390,12 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[15], NULL}, .warm_ids = {NULL}, }, + { + .name = "KWorld USB DVB-T TV Stick II " \ + "(VS-DVB-T 395U)", + .cold_ids = {&af9015_usb_table[16], NULL}, + .warm_ids = {NULL}, + }, } } }; @@ -1419,7 +1436,7 @@ static int af9015_usb_probe(struct usb_interface *intf, return ret; } -void af9015_i2c_exit(struct dvb_usb_device *d) +static void af9015_i2c_exit(struct dvb_usb_device *d) { struct af9015_state *state = d->priv; deb_info("%s: \n", __func__); diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.h b/linux/drivers/media/dvb/dvb-usb/af9015.h index 882e8a4b3..1ab86cc6c 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.h +++ b/linux/drivers/media/dvb/dvb-usb/af9015.h @@ -27,7 +27,6 @@ #define DVB_USB_LOG_PREFIX "af9015" #include "dvb-usb.h" -extern int dvb_usb_af9015_debug; #define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) #define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) #define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args) @@ -521,4 +520,80 @@ static u8 af9015_ir_table_kworld[] = { 0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00, }; +/* AverMedia Volar X */ +static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = { + { 0x05, 0x3d, KEY_PROG1 }, /* SOURCE */ + { 0x05, 0x12, KEY_POWER }, /* POWER */ + { 0x05, 0x1e, KEY_1 }, /* 1 */ + { 0x05, 0x1f, KEY_2 }, /* 2 */ + { 0x05, 0x20, KEY_3 }, /* 3 */ + { 0x05, 0x21, KEY_4 }, /* 4 */ + { 0x05, 0x22, KEY_5 }, /* 5 */ + { 0x05, 0x23, KEY_6 }, /* 6 */ + { 0x05, 0x24, KEY_7 }, /* 7 */ + { 0x05, 0x25, KEY_8 }, /* 8 */ + { 0x05, 0x26, KEY_9 }, /* 9 */ + { 0x05, 0x3f, KEY_LEFT }, /* L / DISPLAY */ + { 0x05, 0x27, KEY_0 }, /* 0 */ + { 0x05, 0x0f, KEY_RIGHT }, /* R / CH RTN */ + { 0x05, 0x18, KEY_PROG2 }, /* SNAP SHOT */ + { 0x05, 0x1c, KEY_PROG3 }, /* 16-CH PREV */ + { 0x05, 0x2d, KEY_VOLUMEDOWN }, /* VOL DOWN */ + { 0x05, 0x3e, KEY_ZOOM }, /* FULL SCREEN */ + { 0x05, 0x2e, KEY_VOLUMEUP }, /* VOL UP */ + { 0x05, 0x10, KEY_MUTE }, /* MUTE */ + { 0x05, 0x04, KEY_AUDIO }, /* AUDIO */ + { 0x05, 0x15, KEY_RECORD }, /* RECORD */ + { 0x05, 0x11, KEY_PLAY }, /* PLAY */ + { 0x05, 0x16, KEY_STOP }, /* STOP */ + { 0x05, 0x0c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ + { 0x05, 0x05, KEY_BACK }, /* << / RED */ + { 0x05, 0x09, KEY_FORWARD }, /* >> / YELLOW */ + { 0x05, 0x17, KEY_TEXT }, /* TELETEXT */ + { 0x05, 0x0a, KEY_EPG }, /* EPG */ + { 0x05, 0x13, KEY_MENU }, /* MENU */ + + { 0x05, 0x0e, KEY_CHANNELUP }, /* CH UP */ + { 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */ + { 0x05, 0x19, KEY_FIRST }, /* |<< / GREEN */ + { 0x05, 0x08, KEY_LAST }, /* >>| / BLUE */ +}; + +static u8 af9015_ir_table_avermedia[] = { + 0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00, + 0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00, + 0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00, + 0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00, + 0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00, + 0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00, + 0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00, + 0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00, + 0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00, + 0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00, + 0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00, + 0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00, + 0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00, + 0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00, + 0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00, + 0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00, + 0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00, + 0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00, + 0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00, + 0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00, + 0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00, + 0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00, + 0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00, + 0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00, + 0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00, + 0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00, + 0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00, + 0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00, + 0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00, + 0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00, + 0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00, + 0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00, + 0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00, + 0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00, +}; + #endif diff --git a/linux/drivers/media/dvb/dvb-usb/anysee.c b/linux/drivers/media/dvb/dvb-usb/anysee.c index c786359fb..cd2edbcaa 100644 --- a/linux/drivers/media/dvb/dvb-usb/anysee.c +++ b/linux/drivers/media/dvb/dvb-usb/anysee.c @@ -46,7 +46,7 @@ module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644); MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static struct mutex anysee_usb_mutex; +static DEFINE_MUTEX(anysee_usb_mutex); static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen) @@ -456,8 +456,6 @@ static int anysee_probe(struct usb_interface *intf, struct usb_host_interface *alt; int ret; - mutex_init(&anysee_usb_mutex); - /* There is one interface with two alternate settings. Alternate setting 0 is for bulk transfer. Alternate setting 1 is for isochronous transfer. diff --git a/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 3ac9f74e9..80e37a0d0 100644 --- a/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -32,7 +32,6 @@ /* debug */ int dvb_usb_cinergyt2_debug; -int disable_remote; module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " @@ -45,7 +44,7 @@ struct cinergyt2_state { }; /* We are missing a release hook with usb_device data */ -struct dvb_usb_device *cinergyt2_usb_device; +static struct dvb_usb_device *cinergyt2_usb_device; static struct dvb_usb_device_properties cinergyt2_properties; diff --git a/linux/drivers/media/dvb/dvb-usb/cinergyT2.h b/linux/drivers/media/dvb/dvb-usb/cinergyT2.h index 11d79eb38..4e3247d04 100644 --- a/linux/drivers/media/dvb/dvb-usb/cinergyT2.h +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2.h @@ -30,7 +30,11 @@ #ifndef _DVB_USB_CINERGYT2_H_ #define _DVB_USB_CINERGYT2_H_ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) #include <linux/usb/input.h> +#else +#include <linux/usb_input.h> +#endif #define DVB_USB_LOG_PREFIX "cinergyT2" #include "dvb-usb.h" @@ -70,11 +74,11 @@ struct dvbt_get_status_msg { uint8_t bandwidth; uint16_t tps; uint8_t flags; - uint16_t gain; + __le16 gain; uint8_t snr; - uint32_t viterbi_error_rate; + __le32 viterbi_error_rate; uint32_t rs_error_rate; - uint32_t uncorrected_block_count; + __le32 uncorrected_block_count; uint8_t lock_bits; uint8_t prev_lock_bits; } __attribute__((packed)); @@ -82,9 +86,9 @@ struct dvbt_get_status_msg { struct dvbt_set_parameters_msg { uint8_t cmd; - uint32_t freq; + __le32 freq; uint8_t bandwidth; - uint16_t tps; + __le16 tps; uint8_t flags; } __attribute__((packed)); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700.h b/linux/drivers/media/dvb/dvb-usb/dib0700.h index 739193943..8b544fe79 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700.h +++ b/linux/drivers/media/dvb/dvb-usb/dib0700.h @@ -22,7 +22,7 @@ extern int dvb_usb_dib0700_debug; #define REQUEST_I2C_READ 0x2 #define REQUEST_I2C_WRITE 0x3 -#define REQUEST_POLL_RC 0x4 +#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ #define REQUEST_JUMPRAM 0x8 #define REQUEST_SET_CLOCK 0xB #define REQUEST_SET_GPIO 0xC @@ -40,11 +40,14 @@ struct dib0700_state { u16 mt2060_if1[2]; u8 rc_toggle; u8 rc_counter; + u8 rc_func_version; u8 is_dib7000pc; u8 fw_use_new_i2c_api; u8 disable_streaming_master_mode; }; +extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype); extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c index 3c7bdef28..2fbb7049a 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -19,6 +19,22 @@ MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (defau DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, + u32 *romversion, u32 *ramversion, u32 *fwtype) +{ + u8 b[16]; + int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + b, sizeof(b), USB_CTRL_GET_TIMEOUT); + *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; + *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; + *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; + *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; + return ret; +} + /* expecting rx buffer: request data[0] data[1] ... data[2] */ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) { diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 0cfccc24b..f28d3ae59 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -38,6 +38,7 @@ static struct mt2060_config bristol_mt2060_config[2] = { } }; + static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { .band_caps = BAND_VHF | BAND_UHF, .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), @@ -451,8 +452,13 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; /* Number of keypresses to ignore before start repeating */ #define RC_REPEAT_DELAY 2 +#define RC_REPEAT_DELAY_V1_20 5 -static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) + + +/* Used by firmware versions < 1.20 (deprecated) */ +static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event, + int *state) { u8 key[4]; int i; @@ -529,6 +535,137 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +/* This is the structure of the RC response packet starting in firmware 1.20 */ +struct dib0700_rc_response { + u8 report_id; + u8 data_state; + u8 system_msb; + u8 system_lsb; + u8 data; + u8 not_data; +}; + +/* This supports the new IR response format for firmware v1.20 */ +static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + struct dib0700_state *st = d->priv; + struct dib0700_rc_response poll_reply; + u8 buf[6]; + int i; + int status; + int actlen; + int found = 0; + + /* Set initial results in case we exit the function early */ + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + /* Firmware v1.20 provides RC data via bulk endpoint 1 */ + status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf, + sizeof(buf), &actlen, 50); + if (status < 0) { + /* No data available (meaning no key press) */ + return 0; + } + + if (actlen != sizeof(buf)) { + /* We didn't get back the 6 byte message we expected */ + err("Unexpected RC response size [%d]", actlen); + return -1; + } + + poll_reply.report_id = buf[0]; + poll_reply.data_state = buf[1]; + poll_reply.system_msb = buf[2]; + poll_reply.system_lsb = buf[3]; + poll_reply.data = buf[4]; + poll_reply.not_data = buf[5]; + + /* + info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n", + poll_reply.report_id, poll_reply.data_state, + poll_reply.system_msb, poll_reply.system_lsb, + poll_reply.data, poll_reply.not_data); + */ + + if ((poll_reply.data + poll_reply.not_data) != 0xff) { + /* Key failed integrity check */ + err("key failed integrity check: %02x %02x %02x %02x", + poll_reply.system_msb, poll_reply.system_lsb, + poll_reply.data, poll_reply.not_data); + return -1; + } + + /* Find the key in the map */ + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == poll_reply.system_lsb && + keymap[i].data == poll_reply.data) { + *event = keymap[i].event; + found = 1; + break; + } + } + + if (found == 0) { + err("Unknown remote controller key: %02x %02x %02x %02x", + poll_reply.system_msb, poll_reply.system_lsb, + poll_reply.data, poll_reply.not_data); + d->last_event = 0; + return 0; + } + + if (poll_reply.data_state == 1) { + /* New key hit */ + st->rc_counter = 0; + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + d->last_event = keymap[i].event; + } else if (poll_reply.data_state == 2) { + /* Key repeated */ + st->rc_counter++; + + /* prevents unwanted double hits */ + if (st->rc_counter > RC_REPEAT_DELAY_V1_20) { + *event = d->last_event; + *state = REMOTE_KEY_PRESSED; + st->rc_counter = RC_REPEAT_DELAY_V1_20; + } + } else { + err("Unknown data state [%d]", poll_reply.data_state); + } + + return 0; +} + +static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct dib0700_state *st = d->priv; + + /* Because some people may have improperly named firmware files, + let's figure out whether to use the new firmware call or the legacy + call based on the firmware version embedded in the file */ + if (st->rc_func_version == 0) { + u32 hwver, romver, ramver, fwtype; + int ret = dib0700_get_version(d, &hwver, &romver, &ramver, + &fwtype); + if (ret < 0) { + err("Could not determine version info"); + return -1; + } + if (ramver < 0x10200) + st->rc_func_version = 1; + else + st->rc_func_version = 2; + } + + if (st->rc_func_version == 2) + return dib0700_rc_query_v1_20(d, event, state); + else + return dib0700_rc_query_legacy(d, event, state); +} + static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* Key codes for the tiny Pinnacle remote*/ { 0x07, 0x00, KEY_MUTE }, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 7380b94b3..a4fca3fca 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -96,6 +96,7 @@ #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_KWORLD_399U 0xe399 +#define USB_PID_KWORLD_395U 0xe396 #define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 5cef12a07..6fe71c674 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -13,14 +13,14 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, { int actlen,ret = -ENOMEM; + if (!d || wbuf == NULL || wlen == 0) + return -EINVAL; + if (d->props.generic_bulk_ctrl_endpoint == 0) { err("endpoint for generic control not specified."); return -EINVAL; } - if (wbuf == NULL || wlen == 0) - return -EINVAL; - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) return ret; diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c index ca53df61c..bc5e47a2b 100644 --- a/linux/drivers/media/dvb/dvb-usb/dw2102.c +++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c @@ -9,7 +9,6 @@ * * see Documentation/dvb/README.dvb-usb for more information */ -#include <linux/version.h> #include "dw2102.h" #include "si21xx.h" #include "stv0299.h" @@ -27,6 +26,10 @@ #define USB_PID_DW2104 0x2104 #endif +#ifndef USB_PID_CINERGY_S +#define USB_PID_CINERGY_S 0x0064 +#endif + #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -422,6 +425,18 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static struct stv0299_config sharp_z0194a_config = { + .demod_address = 0x68, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + static struct cx24116_config dw2104_config = { .demod_address = 0x55, .mpg_clk_pos_pol = 0x01, @@ -566,6 +581,7 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, {USB_DEVICE(0x9022, 0xd650)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, { } }; @@ -635,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev, dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); break; + case USB_PID_CINERGY_S: case USB_PID_DW2102: dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); @@ -714,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = { }, } }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { {"DVBWorld DVB-S 2102 USB2.0", {&dw2102_table[0], NULL}, @@ -724,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = { {&dw2102_table[1], NULL}, {NULL}, }, + {"TerraTec Cinergy S USB", + {&dw2102_table[4], NULL}, + {NULL}, + }, } }; diff --git a/linux/drivers/media/dvb/dvb-usb/usb-urb.c b/linux/drivers/media/dvb/dvb-usb/usb-urb.c index 5caec2034..eb3aaaf7a 100644 --- a/linux/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/linux/drivers/media/dvb/dvb-usb/usb-urb.c @@ -139,7 +139,7 @@ stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]) static int usb_bulk_urb_init(struct usb_data_stream *stream) { - int i; + int i, j; if ((i = usb_allocate_stream_buffers(stream,stream->props.count, stream->props.u.bulk.buffersize)) < 0) @@ -147,9 +147,13 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) /* allocate the URBs */ for (i = 0; i < stream->props.count; i++) { - if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!.\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[i]); return -ENOMEM; - + } usb_fill_bulk_urb( stream->urb_list[i], stream->udev, usb_rcvbulkpipe(stream->udev,stream->props.endpoint), stream->buf_list[i], @@ -174,9 +178,14 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) for (i = 0; i < stream->props.count; i++) { struct urb *urb; int frame_offset = 0; - if ((stream->urb_list[i] = - usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) + + stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[i]); return -ENOMEM; + } urb = stream->urb_list[i]; diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index 96b93e21a..2470d88e9 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -12,6 +12,25 @@ config DVB_FE_CUSTOMISE If unsure say N. +comment "Multistandard (satellite) frontends" + depends on DVB_CORE + +config DVB_STB0899 + tristate "STB0899 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want + to support this demodulator based frontends + +config DVB_STB6100 + tristate "STB6100 based tuners" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A Silicon tuner from ST used in conjunction with the STB0899 + demodulator. Say Y when you want to support this tuner. + comment "DVB-S (satellite) frontends" depends on DVB_CORE @@ -78,6 +97,13 @@ config DVB_TDA10086 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_TDA8261 + tristate "Philips TDA8261 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + config DVB_VES1X93 tristate "VLSI VES1893 or VES1993 based" depends on DVB_CORE && I2C @@ -345,6 +371,14 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LGDT3304 + tristate "LG Electronics LGDT3304" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + config DVB_S5H1409 tristate "Samsung S5H1409 based" depends on DVB_CORE && I2C @@ -369,6 +403,17 @@ config DVB_S5H1411 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +comment "ISDB-T (terrestrial) frontends" + depends on DVB_CORE + +config DVB_S921 + tristate "Sharp S921 tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. + Say Y when you want to support this frontend. + comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index aba79f4a6..7a19c0c7b 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -5,8 +5,13 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/common/tuners/ +s921-objs := s921_module.o s921_core.o +stb0899-objs = stb0899_drv.o stb0899_algo.o + obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o +obj-$(CONFIG_DVB_STB0899) += stb0899.o +obj-$(CONFIG_DVB_STB6100) += stb6100.o obj-$(CONFIG_DVB_SP8870) += sp8870.o obj-$(CONFIG_DVB_CX22700) += cx22700.o obj-$(CONFIG_DVB_CX24110) += cx24110.o @@ -35,12 +40,14 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o +obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o obj-$(CONFIG_DVB_ISL6405) += isl6405.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o +obj-$(CONFIG_DVB_TDA8261) += tda8261.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o @@ -55,3 +62,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o obj-$(CONFIG_DVB_SI21XX) += si21xx.o obj-$(CONFIG_DVB_STV0288) += stv0288.o obj-$(CONFIG_DVB_STB6000) += stb6000.o +obj-$(CONFIG_DVB_S921) += s921.o + diff --git a/linux/drivers/media/dvb/frontends/af9013.c b/linux/drivers/media/dvb/frontends/af9013.c index 21c1060cf..692b68a9e 100644 --- a/linux/drivers/media/dvb/frontends/af9013.c +++ b/linux/drivers/media/dvb/frontends/af9013.c @@ -1187,7 +1187,7 @@ static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) if (tmp) *status |= FE_HAS_SYNC | FE_HAS_LOCK; - if (!*status & FE_HAS_SIGNAL) { + if (!(*status & FE_HAS_SIGNAL)) { /* AGC lock */ ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); if (ret) @@ -1196,7 +1196,7 @@ static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) *status |= FE_HAS_SIGNAL; } - if (!*status & FE_HAS_CARRIER) { + if (!(*status & FE_HAS_CARRIER)) { /* CFO lock */ ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); if (ret) @@ -1205,7 +1205,7 @@ static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) *status |= FE_HAS_CARRIER; } - if (!*status & FE_HAS_CARRIER) { + if (!(*status & FE_HAS_CARRIER)) { /* SFOE lock */ ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); if (ret) diff --git a/linux/drivers/media/dvb/frontends/cx22702.c b/linux/drivers/media/dvb/frontends/cx22702.c index 9430e03db..5d1abe34b 100644 --- a/linux/drivers/media/dvb/frontends/cx22702.c +++ b/linux/drivers/media/dvb/frontends/cx22702.c @@ -34,13 +34,12 @@ #include "dvb_frontend.h" #include "cx22702.h" - struct cx22702_state { - struct i2c_adapter* i2c; + struct i2c_adapter *i2c; /* configuration settings */ - const struct cx22702_config* config; + const struct cx22702_config *config; struct dvb_frontend frontend; @@ -49,10 +48,13 @@ struct cx22702_state { }; static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + #define dprintk if (debug) printk /* Register values to initialise the demod */ -static u8 init_tab [] = { +static u8 init_tab[] = { 0x00, 0x00, /* Stop aquisition */ 0x0B, 0x06, 0x09, 0x01, @@ -80,65 +82,67 @@ static u8 init_tab [] = { 0xfd, 0x00, }; -static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data) +static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data) { int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, .flags = 0, + .buf = buf, .len = 2 }; ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + printk(KERN_ERR + "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", __func__, reg, data, ret); return (ret != 1) ? -1 : 0; } -static u8 cx22702_readreg (struct cx22702_state* state, u8 reg) +static u8 cx22702_readreg(struct cx22702_state *state, u8 reg) { int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; - struct i2c_msg msg [] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __func__, ret); + printk(KERN_ERR "%s: readreg error (ret == %i)\n", + __func__, ret); return b1[0]; } -static int cx22702_set_inversion (struct cx22702_state *state, int inversion) +static int cx22702_set_inversion(struct cx22702_state *state, int inversion) { u8 val; switch (inversion) { - - case INVERSION_AUTO: - return -EOPNOTSUPP; - - case INVERSION_ON: - val = cx22702_readreg (state, 0x0C); - return cx22702_writereg (state, 0x0C, val | 0x01); - - case INVERSION_OFF: - val = cx22702_readreg (state, 0x0C); - return cx22702_writereg (state, 0x0C, val & 0xfe); - - default: - return -EINVAL; - + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val = cx22702_readreg(state, 0x0C); + return cx22702_writereg(state, 0x0C, val | 0x01); + case INVERSION_OFF: + val = cx22702_readreg(state, 0x0C); + return cx22702_writereg(state, 0x0C, val & 0xfe); + default: + return -EINVAL; } } /* Retrieve the demod settings */ -static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p) +static int cx22702_get_tps(struct cx22702_state *state, + struct dvb_ofdm_parameters *p) { u8 val; @@ -146,180 +150,281 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet if (!(cx22702_readreg(state, 0x0A) & 0x20)) return -EAGAIN; - val = cx22702_readreg (state, 0x01); - switch( (val&0x18)>>3) { - case 0: p->constellation = QPSK; break; - case 1: p->constellation = QAM_16; break; - case 2: p->constellation = QAM_64; break; + val = cx22702_readreg(state, 0x01); + switch ((val & 0x18) >> 3) { + case 0: + p->constellation = QPSK; + break; + case 1: + p->constellation = QAM_16; + break; + case 2: + p->constellation = QAM_64; + break; } - switch( val&0x07 ) { - case 0: p->hierarchy_information = HIERARCHY_NONE; break; - case 1: p->hierarchy_information = HIERARCHY_1; break; - case 2: p->hierarchy_information = HIERARCHY_2; break; - case 3: p->hierarchy_information = HIERARCHY_4; break; + switch (val & 0x07) { + case 0: + p->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + p->hierarchy_information = HIERARCHY_1; + break; + case 2: + p->hierarchy_information = HIERARCHY_2; + break; + case 3: + p->hierarchy_information = HIERARCHY_4; + break; } - val = cx22702_readreg (state, 0x02); - switch( (val&0x38)>>3 ) { - case 0: p->code_rate_HP = FEC_1_2; break; - case 1: p->code_rate_HP = FEC_2_3; break; - case 2: p->code_rate_HP = FEC_3_4; break; - case 3: p->code_rate_HP = FEC_5_6; break; - case 4: p->code_rate_HP = FEC_7_8; break; + val = cx22702_readreg(state, 0x02); + switch ((val & 0x38) >> 3) { + case 0: + p->code_rate_HP = FEC_1_2; + break; + case 1: + p->code_rate_HP = FEC_2_3; + break; + case 2: + p->code_rate_HP = FEC_3_4; + break; + case 3: + p->code_rate_HP = FEC_5_6; + break; + case 4: + p->code_rate_HP = FEC_7_8; + break; } - switch( val&0x07 ) { - case 0: p->code_rate_LP = FEC_1_2; break; - case 1: p->code_rate_LP = FEC_2_3; break; - case 2: p->code_rate_LP = FEC_3_4; break; - case 3: p->code_rate_LP = FEC_5_6; break; - case 4: p->code_rate_LP = FEC_7_8; break; + switch (val & 0x07) { + case 0: + p->code_rate_LP = FEC_1_2; + break; + case 1: + p->code_rate_LP = FEC_2_3; + break; + case 2: + p->code_rate_LP = FEC_3_4; + break; + case 3: + p->code_rate_LP = FEC_5_6; + break; + case 4: + p->code_rate_LP = FEC_7_8; + break; } - - val = cx22702_readreg (state, 0x03); - switch( (val&0x0c)>>2 ) { - case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; - case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; - case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; - case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; + val = cx22702_readreg(state, 0x03); + switch ((val & 0x0c) >> 2) { + case 0: + p->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + p->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + p->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + p->guard_interval = GUARD_INTERVAL_1_4; + break; } - switch( val&0x03 ) { - case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; + switch (val & 0x03) { + case 0: + p->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->transmission_mode = TRANSMISSION_MODE_8K; + break; } return 0; } -static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct cx22702_state* state = fe->demodulator_priv; - dprintk ("%s(%d)\n", __func__, enable); + struct cx22702_state *state = fe->demodulator_priv; + dprintk("%s(%d)\n", __func__, enable); if (enable) - return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe); + return cx22702_writereg(state, 0x0D, + cx22702_readreg(state, 0x0D) & 0xfe); else - return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1); + return cx22702_writereg(state, 0x0D, + cx22702_readreg(state, 0x0D) | 1); } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22702_set_tps(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { u8 val; - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; 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); } /* set inversion */ - cx22702_set_inversion (state, p->inversion); + cx22702_set_inversion(state, p->inversion); /* set bandwidth */ - switch(p->u.ofdm.bandwidth) { + switch (p->u.ofdm.bandwidth) { case BANDWIDTH_6_MHZ: - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 ); + cx22702_writereg(state, 0x0C, + (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20); break; case BANDWIDTH_7_MHZ: - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 ); + cx22702_writereg(state, 0x0C, + (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10); break; case BANDWIDTH_8_MHZ: - cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf ); + cx22702_writereg(state, 0x0C, + cx22702_readreg(state, 0x0C) & 0xcf); break; default: - dprintk ("%s: invalid bandwidth\n",__func__); + dprintk("%s: invalid bandwidth\n", __func__); return -EINVAL; } - - p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working + p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ /* use auto configuration? */ - if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) || - (p->u.ofdm.constellation==QAM_AUTO) || - (p->u.ofdm.code_rate_HP==FEC_AUTO) || - (p->u.ofdm.code_rate_LP==FEC_AUTO) || - (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) || - (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) { + if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) || + (p->u.ofdm.constellation == QAM_AUTO) || + (p->u.ofdm.code_rate_HP == FEC_AUTO) || + (p->u.ofdm.code_rate_LP == FEC_AUTO) || + (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) || + (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) { /* TPS Source - use hardware driven values */ cx22702_writereg(state, 0x06, 0x10); cx22702_writereg(state, 0x07, 0x9); cx22702_writereg(state, 0x08, 0xC1); - cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc ); - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); + cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) + & 0xfc); + cx22702_writereg(state, 0x0C, + (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ - dprintk("%s: Autodetecting\n",__func__); + dprintk("%s: Autodetecting\n", __func__); return 0; } /* manually programmed values */ - val=0; - switch(p->u.ofdm.constellation) { - case QPSK: val = (val&0xe7); break; - case QAM_16: val = (val&0xe7)|0x08; break; - case QAM_64: val = (val&0xe7)|0x10; break; - default: - dprintk ("%s: invalid constellation\n",__func__); - return -EINVAL; + val = 0; + switch (p->u.ofdm.constellation) { + case QPSK: + val = (val & 0xe7); + break; + case QAM_16: + val = (val & 0xe7) | 0x08; + break; + case QAM_64: + val = (val & 0xe7) | 0x10; + break; + default: + dprintk("%s: invalid constellation\n", __func__); + return -EINVAL; } - switch(p->u.ofdm.hierarchy_information) { - case HIERARCHY_NONE: val = (val&0xf8); break; - case HIERARCHY_1: val = (val&0xf8)|1; break; - case HIERARCHY_2: val = (val&0xf8)|2; break; - case HIERARCHY_4: val = (val&0xf8)|3; break; - default: - dprintk ("%s: invalid hierarchy\n",__func__); - return -EINVAL; + switch (p->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + val = (val & 0xf8); + break; + case HIERARCHY_1: + val = (val & 0xf8) | 1; + break; + case HIERARCHY_2: + val = (val & 0xf8) | 2; + break; + case HIERARCHY_4: + val = (val & 0xf8) | 3; + break; + default: + dprintk("%s: invalid hierarchy\n", __func__); + return -EINVAL; } - cx22702_writereg (state, 0x06, val); - - val=0; - switch(p->u.ofdm.code_rate_HP) { - case FEC_NONE: - case FEC_1_2: val = (val&0xc7); break; - case FEC_2_3: val = (val&0xc7)|0x08; break; - case FEC_3_4: val = (val&0xc7)|0x10; break; - case FEC_5_6: val = (val&0xc7)|0x18; break; - case FEC_7_8: val = (val&0xc7)|0x20; break; - default: - dprintk ("%s: invalid code_rate_HP\n",__func__); - return -EINVAL; + cx22702_writereg(state, 0x06, val); + + val = 0; + switch (p->u.ofdm.code_rate_HP) { + case FEC_NONE: + case FEC_1_2: + val = (val & 0xc7); + break; + case FEC_2_3: + val = (val & 0xc7) | 0x08; + break; + case FEC_3_4: + val = (val & 0xc7) | 0x10; + break; + case FEC_5_6: + val = (val & 0xc7) | 0x18; + break; + case FEC_7_8: + val = (val & 0xc7) | 0x20; + break; + default: + dprintk("%s: invalid code_rate_HP\n", __func__); + return -EINVAL; } - switch(p->u.ofdm.code_rate_LP) { - case FEC_NONE: - case FEC_1_2: val = (val&0xf8); break; - case FEC_2_3: val = (val&0xf8)|1; break; - case FEC_3_4: val = (val&0xf8)|2; break; - case FEC_5_6: val = (val&0xf8)|3; break; - case FEC_7_8: val = (val&0xf8)|4; break; - default: - dprintk ("%s: invalid code_rate_LP\n",__func__); - return -EINVAL; + switch (p->u.ofdm.code_rate_LP) { + case FEC_NONE: + case FEC_1_2: + val = (val & 0xf8); + break; + case FEC_2_3: + val = (val & 0xf8) | 1; + break; + case FEC_3_4: + val = (val & 0xf8) | 2; + break; + case FEC_5_6: + val = (val & 0xf8) | 3; + break; + case FEC_7_8: + val = (val & 0xf8) | 4; + break; + default: + dprintk("%s: invalid code_rate_LP\n", __func__); + return -EINVAL; } - cx22702_writereg (state, 0x07, val); - - val=0; - switch(p->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: val = (val&0xf3); break; - case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break; - case GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break; - case GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break; - default: - dprintk ("%s: invalid guard_interval\n",__func__); - return -EINVAL; + cx22702_writereg(state, 0x07, val); + + val = 0; + switch (p->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_32: + val = (val & 0xf3); + break; + case GUARD_INTERVAL_1_16: + val = (val & 0xf3) | 0x04; + break; + case GUARD_INTERVAL_1_8: + val = (val & 0xf3) | 0x08; + break; + case GUARD_INTERVAL_1_4: + val = (val & 0xf3) | 0x0c; + break; + default: + dprintk("%s: invalid guard_interval\n", __func__); + return -EINVAL; } - switch(p->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: val = (val&0xfc); break; - case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break; - default: - dprintk ("%s: invalid transmission_mode\n",__func__); - return -EINVAL; + switch (p->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_2K: + val = (val & 0xfc); + break; + case TRANSMISSION_MODE_8K: + val = (val & 0xfc) | 1; + break; + default: + dprintk("%s: invalid transmission_mode\n", __func__); + return -EINVAL; } cx22702_writereg(state, 0x08, val); - cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 ); - cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); + cx22702_writereg(state, 0x0B, + (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02); + cx22702_writereg(state, 0x0C, + (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); /* Begin channel aquisition */ cx22702_writereg(state, 0x00, 0x01); @@ -329,109 +434,111 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet /* Reset the demod hardware and reset all of the configuration registers to a default state. */ -static int cx22702_init (struct dvb_frontend* fe) +static int cx22702_init(struct dvb_frontend *fe) { int i; - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; - cx22702_writereg (state, 0x00, 0x02); + cx22702_writereg(state, 0x00, 0x02); msleep(10); - for (i=0; i<sizeof(init_tab); i+=2) - cx22702_writereg (state, init_tab[i], init_tab[i+1]); + for (i = 0; i < ARRAY_SIZE(init_tab); i += 2) + cx22702_writereg(state, init_tab[i], init_tab[i + 1]); - cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); + cx22702_writereg(state, 0xf8, (state->config->output_mode << 1) + & 0x02); cx22702_i2c_gate_ctrl(fe, 0); return 0; } -static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; u8 reg0A; u8 reg23; *status = 0; - reg0A = cx22702_readreg (state, 0x0A); - reg23 = cx22702_readreg (state, 0x23); + reg0A = cx22702_readreg(state, 0x0A); + reg23 = cx22702_readreg(state, 0x23); - dprintk ("%s: status demod=0x%02x agc=0x%02x\n" - ,__func__,reg0A,reg23); + dprintk("%s: status demod=0x%02x agc=0x%02x\n" + , __func__, reg0A, reg23); - if(reg0A & 0x10) { + if (reg0A & 0x10) { *status |= FE_HAS_LOCK; *status |= FE_HAS_VITERBI; *status |= FE_HAS_SYNC; } - if(reg0A & 0x20) + if (reg0A & 0x20) *status |= FE_HAS_CARRIER; - if(reg23 < 0xf0) + if (reg23 < 0xf0) *status |= FE_HAS_SIGNAL; return 0; } -static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber) +static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; - if(cx22702_readreg (state, 0xE4) & 0x02) { + if (cx22702_readreg(state, 0xE4) & 0x02) { /* Realtime statistics */ - *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 - | (cx22702_readreg (state, 0xDF)&0x7F); + *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 + | (cx22702_readreg(state, 0xDF) & 0x7F); } else { /* Averagtine statistics */ - *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 - | cx22702_readreg (state, 0xDF); + *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 + | cx22702_readreg(state, 0xDF); } return 0; } -static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +static int cx22702_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; u16 rs_ber = 0; - rs_ber = cx22702_readreg (state, 0x23); + rs_ber = cx22702_readreg(state, 0x23); *signal_strength = (rs_ber << 8) | rs_ber; return 0; } -static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr) +static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; - u16 rs_ber=0; - if(cx22702_readreg (state, 0xE4) & 0x02) { + u16 rs_ber = 0; + if (cx22702_readreg(state, 0xE4) & 0x02) { /* Realtime statistics */ - rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 - | (cx22702_readreg (state, 0xDF)& 0x7F); + rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 + | (cx22702_readreg(state, 0xDF) & 0x7F); } else { /* Averagine statistics */ - rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8 - | cx22702_readreg (state, 0xDF); + rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8 + | cx22702_readreg(state, 0xDF); } *snr = ~rs_ber; return 0; } -static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; u8 _ucblocks; /* RS Uncorrectable Packet Count then reset */ - _ucblocks = cx22702_readreg (state, 0xE3); + _ucblocks = cx22702_readreg(state, 0xE3); if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks); else @@ -441,34 +548,36 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22702_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; - u8 reg0C = cx22702_readreg (state, 0x0C); + u8 reg0C = cx22702_readreg(state, 0x0C); p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22702_get_tps (state, &p->u.ofdm); + return cx22702_get_tps(state, &p->u.ofdm); } -static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +static int cx22702_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; return 0; } -static void cx22702_release(struct dvb_frontend* fe) +static void cx22702_release(struct dvb_frontend *fe) { - struct cx22702_state* state = fe->demodulator_priv; + struct cx22702_state *state = fe->demodulator_priv; kfree(state); } static struct dvb_frontend_ops cx22702_ops; -struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, - struct i2c_adapter* i2c) +struct dvb_frontend *cx22702_attach(const struct cx22702_config *config, + struct i2c_adapter *i2c) { - struct cx22702_state* state = NULL; + struct cx22702_state *state = NULL; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); @@ -485,7 +594,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &cx22702_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -493,6 +603,7 @@ error: kfree(state); return NULL; } +EXPORT_SYMBOL(cx22702_attach); static struct dvb_frontend_ops cx22702_ops = { @@ -525,11 +636,6 @@ static struct dvb_frontend_ops cx22702_ops = { .read_ucblocks = cx22702_read_ucblocks, }; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(cx22702_attach); diff --git a/linux/drivers/media/dvb/frontends/cx22702.h b/linux/drivers/media/dvb/frontends/cx22702.h index b1e465c6c..f154e1f42 100644 --- a/linux/drivers/media/dvb/frontends/cx22702.h +++ b/linux/drivers/media/dvb/frontends/cx22702.h @@ -30,8 +30,7 @@ #include <linux/dvb/frontend.h> -struct cx22702_config -{ +struct cx22702_config { /* the demodulator's i2c address */ u8 demod_address; @@ -41,16 +40,19 @@ struct cx22702_config u8 output_mode; }; -#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) && defined(MODULE)) -extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, - struct i2c_adapter* i2c); +#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *cx22702_attach( + const struct cx22702_config *config, + struct i2c_adapter *i2c); #else -static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, - struct i2c_adapter* i2c) +static inline struct dvb_frontend *cx22702_attach( + const struct cx22702_config *config, + struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_CX22702 +#endif -#endif // CX22702_H +#endif diff --git a/linux/drivers/media/dvb/frontends/cx24116.c b/linux/drivers/media/dvb/frontends/cx24116.c index 3c58b9f57..497ea635e 100644 --- a/linux/drivers/media/dvb/frontends/cx24116.c +++ b/linux/drivers/media/dvb/frontends/cx24116.c @@ -41,10 +41,14 @@ #include "dvb_frontend.h" #include "cx24116.h" -static int debug = 0; +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + #define dprintk(args...) \ do { \ - if (debug) printk ("cx24116: " args); \ + if (debug) \ + printk(KERN_INFO "cx24116: " args); \ } while (0) #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" @@ -68,13 +72,20 @@ static int debug = 0; #define CX24116_REG_UCB8 (0xca) #define CX24116_REG_CLKDIV (0xf3) #define CX24116_REG_RATEDIV (0xf9) -#define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ + +/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ +#define CX24116_REG_FECSTATUS (0x9c) /* FECSTATUS bits */ -#define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */ -#define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */ +/* mask to determine configured fec (not tuned) or actual fec (tuned) */ +#define CX24116_FEC_FECMASK (0x1f) + +/* Select DVB-S demodulator, else DVB-S2 */ +#define CX24116_FEC_DVBS (0x20) #define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ -#define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */ + +/* Pilot mode requested when tuning else always reset when tuned */ +#define CX24116_FEC_PILOT (0x80) /* arg buffer size */ #define CX24116_ARGLEN (0x1e) @@ -116,12 +127,17 @@ static int debug = 0; /* DiSEqC tone burst */ static int toneburst = 1; +module_param(toneburst, int, 0644); +MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\ + "2=MESSAGE CACHE (default:1)"); /* SNR measurements */ -static int esno_snr = 0; +static int esno_snr; +module_param(esno_snr, int, 0644); +MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\ + "1=ESNO(db * 10) (default:0)"); -enum cmds -{ +enum cmds { CMD_SET_VCO = 0x10, CMD_TUNEREQUEST = 0x11, CMD_MPEGCONFIG = 0x13, @@ -138,8 +154,7 @@ enum cmds }; /* The Demod/Tuner can't easily provide these, we cache them */ -struct cx24116_tuning -{ +struct cx24116_tuning { u32 frequency; u32 symbol_rate; fe_spectral_inversion_t inversion; @@ -158,16 +173,14 @@ struct cx24116_tuning }; /* Basic commands that are sent to the firmware */ -struct cx24116_cmd -{ +struct cx24116_cmd { u8 len; u8 args[CX24116_ARGLEN]; }; -struct cx24116_state -{ - struct i2c_adapter* i2c; - const struct cx24116_config* config; +struct cx24116_state { + struct i2c_adapter *i2c; + const struct cx24116_config *config; struct dvb_frontend frontend; @@ -179,19 +192,20 @@ struct cx24116_state struct cx24116_cmd dsec_cmd; }; -static int cx24116_writereg(struct cx24116_state* state, int reg, int data) +static int cx24116_writereg(struct cx24116_state *state, int reg, int data) { u8 buf[] = { reg, data }; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; int err; - if (debug>1) + if (debug > 1) printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", - __func__,reg, data); + __func__, reg, data); - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk("%s: writereg error(err == %i, reg == 0x%02x," + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," " value == 0x%02x)\n", __func__, err, reg, data); return -EREMOTEIO; } @@ -200,7 +214,8 @@ static int cx24116_writereg(struct cx24116_state* state, int reg, int data) } /* Bulk byte writes to a single I2C address, for 32k firmware load */ -static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len) +static int cx24116_writeregN(struct cx24116_state *state, int reg, + const u8 *data, u16 len) { int ret = -EREMOTEIO; struct i2c_msg msg; @@ -221,12 +236,13 @@ static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 msg.buf = buf; msg.len = len + 1; - if (debug>1) - printk("cx24116: %s: write regN 0x%02x, len = %d\n", - __func__,reg, len); + if (debug > 1) + printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n", + __func__, reg, len); - if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk("%s: writereg error(err == %i, reg == 0x%02x\n", + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) { + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n", __func__, ret, reg); ret = -EREMOTEIO; } @@ -237,30 +253,35 @@ error: return ret; } -static int cx24116_readreg(struct cx24116_state* state, u8 reg) +static int cx24116_readreg(struct cx24116_state *state, u8 reg) { int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } + { .addr = state->config->demod_address, .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) { - printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret); + printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", + __func__, reg, ret); return ret; } - if (debug>1) - printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]); + if (debug > 1) + printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n", + reg, b1[0]); return b1[0]; } -static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion) +static int cx24116_set_inversion(struct cx24116_state *state, + fe_spectral_inversion_t inversion) { dprintk("%s(%d)\n", __func__, inversion); @@ -308,10 +329,10 @@ static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_invers * Eg.(2/3) szap "Zone Horror" * * mask/val = 0x04, 0x20 - * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK + * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK * * mask/val = 0x04, 0x30 - * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK + * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK * * After tuning FECSTATUS contains actual FEC * in use numbered 1 through to 8 for 1/2 .. 2/3 etc @@ -389,18 +410,16 @@ struct cx24116_modfec { */ }; -static int cx24116_lookup_fecmod(struct cx24116_state* state, +static int cx24116_lookup_fecmod(struct cx24116_state *state, fe_modulation_t m, fe_code_rate_t f) { int i, ret = -EOPNOTSUPP; dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); - for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++) - { - if( (m == CX24116_MODFEC_MODES[i].modulation) && - (f == CX24116_MODFEC_MODES[i].fec) ) - { + for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) { + if ((m == CX24116_MODFEC_MODES[i].modulation) && + (f == CX24116_MODFEC_MODES[i].fec)) { ret = i; break; } @@ -409,7 +428,8 @@ static int cx24116_lookup_fecmod(struct cx24116_state* state, return ret; } -static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec) +static int cx24116_set_fec(struct cx24116_state *state, + fe_modulation_t mod, fe_code_rate_t fec) { int ret = 0; @@ -417,7 +437,7 @@ static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_ ret = cx24116_lookup_fecmod(state, mod, fec); - if(ret < 0) + if (ret < 0) return ret; state->dnxt.fec = fec; @@ -429,7 +449,7 @@ static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_ return 0; } -static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) +static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate) { dprintk("%s(%d)\n", __func__, rate); @@ -446,42 +466,49 @@ static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) return 0; } -static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw); +static int cx24116_load_firmware(struct dvb_frontend *fe, + const struct firmware *fw); -static int cx24116_firmware_ondemand(struct dvb_frontend* fe) +static int cx24116_firmware_ondemand(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; const struct firmware *fw; int ret = 0; - dprintk("%s()\n",__func__); + dprintk("%s()\n", __func__); - if (cx24116_readreg(state, 0x20) > 0) - { + if (cx24116_readreg(state, 0x20) > 0) { if (state->skip_fw_load) return 0; /* Load firmware */ - /* request the firmware, this will block until someone uploads it */ - printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev); - printk("%s: Waiting for firmware upload(2)...\n", __func__); + /* request the firmware, this will block until loaded */ + printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", + __func__, CX24116_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, + &state->i2c->dev); + printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", + __func__); if (ret) { - printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__); + printk(KERN_ERR "%s: No firmware uploaded " + "(timeout or file not found?)\n", __func__); return ret; } - /* Make sure we don't recurse back through here during loading */ + /* Make sure we don't recurse back through here + * during loading */ state->skip_fw_load = 1; ret = cx24116_load_firmware(fe, fw); if (ret) - printk("%s: Writing firmware to device failed\n", __func__); + printk(KERN_ERR "%s: Writing firmware to device failed\n", + __func__); release_firmware(fw); - printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed"); + printk(KERN_INFO "%s: Firmware upload %s\n", __func__, + ret == 0 ? "complete" : "failed"); /* Ensure firmware is always loaded if required */ state->skip_fw_load = 0; @@ -490,8 +517,10 @@ static int cx24116_firmware_ondemand(struct dvb_frontend* fe) return ret; } -/* Take a basic firmware command structure, format it and forward it for processing */ -static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) +/* Take a basic firmware command structure, format it + * and forward it for processing + */ +static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd) { struct cx24116_state *state = fe->demodulator_priv; int i, ret; @@ -499,49 +528,49 @@ static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) dprintk("%s()\n", __func__); /* Load the firmware if required */ - if ( (ret = cx24116_firmware_ondemand(fe)) != 0) - { - printk("%s(): Unable initialise the firmware\n", __func__); + ret = cx24116_firmware_ondemand(fe); + if (ret != 0) { + printk(KERN_ERR "%s(): Unable initialise the firmware\n", + __func__); return ret; } /* Write the command */ - for(i = 0; i < cmd->len ; i++) - { + for (i = 0; i < cmd->len ; i++) { dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); cx24116_writereg(state, i, cmd->args[i]); } /* Start execution and wait for cmd to terminate */ cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); - while( cx24116_readreg(state, CX24116_REG_EXECUTE) ) - { + while (cx24116_readreg(state, CX24116_REG_EXECUTE)) { msleep(10); - if(i++ > 64) - { - /* Avoid looping forever if the firmware does no respond */ - printk("%s() Firmware not responding\n", __func__); + if (i++ > 64) { + /* Avoid looping forever if the firmware does + not respond */ + printk(KERN_WARNING "%s() Firmware not responding\n", + __func__); return -EREMOTEIO; } } return 0; } -static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +static int cx24116_load_firmware(struct dvb_frontend *fe, + const struct firmware *fw) { - struct cx24116_state* state = fe->demodulator_priv; + struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; int i, ret; unsigned char vers[4]; dprintk("%s\n", __func__); - dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n" - ,fw->size - ,fw->data[0] - ,fw->data[1] - ,fw->data[ fw->size-2 ] - ,fw->data[ fw->size-1 ] - ); + dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", + fw->size, + fw->data[0], + fw->data[1], + fw->data[fw->size-2], + fw->data[fw->size-1]); /* Toggle 88x SRST pin to reset demod */ if (state->config->reset_device) @@ -587,7 +616,7 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware cmd.args[0x07] = 0x9d; cmd.args[0x08] = 0xfc; cmd.args[0x09] = 0x06; - cmd.len= 0x0a; + cmd.len = 0x0a; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; @@ -598,7 +627,7 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware cmd.args[0x00] = CMD_TUNERINIT; cmd.args[0x01] = 0x00; cmd.args[0x02] = 0x00; - cmd.len= 0x03; + cmd.len = 0x03; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; @@ -615,36 +644,38 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware else cmd.args[0x04] = 0x02; cmd.args[0x05] = 0x00; - cmd.len= 0x06; + cmd.len = 0x06; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; /* Firmware CMD 35: Get firmware version */ cmd.args[0x00] = CMD_UPDFWVERS; - cmd.len= 0x02; - for(i=0; i<4; i++) { + cmd.len = 0x02; + for (i = 0; i < 4; i++) { cmd.args[0x01] = i; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; - vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX); + vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX); } - printk("%s: FW version %i.%i.%i.%i\n", __func__, + printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__, vers[0], vers[1], vers[2], vers[3]); return 0; } -static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int cx24116_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) { /* The isl6421 module will override this function in the fops. */ - dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__); + dprintk("%s() This should never appear if the isl6421 module " + "is loaded correctly\n", __func__); return -EOPNOTSUPP; } -static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct cx24116_state *state = fe->demodulator_priv; @@ -666,22 +697,23 @@ static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } -static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber) +static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber) { struct cx24116_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); - *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) | - ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) | - ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) | - cx24116_readreg(state, CX24116_REG_BER0 ); + *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) | + (cx24116_readreg(state, CX24116_REG_BER16) << 16) | + (cx24116_readreg(state, CX24116_REG_BER8) << 8) | + cx24116_readreg(state, CX24116_REG_BER0); return 0; } /* TODO Determine function and scale appropriately */ -static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +static int cx24116_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) { struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; @@ -692,39 +724,43 @@ static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_str /* Firmware CMD 19: Get AGC */ cmd.args[0x00] = CMD_GETAGC; - cmd.len= 0x01; + cmd.len = 0x01; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; - sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) | - ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 ); - *signal_strength= 0 - sig_reading; + sig_reading = + (cx24116_readreg(state, + CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) | + (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6); + *signal_strength = 0 - sig_reading; - dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength); + dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", + __func__, sig_reading, *signal_strength); return 0; } /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ -static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) +static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr) { struct cx24116_state *state = fe->demodulator_priv; u8 snr_reading; static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ - 0x00000,0x0199A,0x03333,0x04ccD,0x06667, - 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, - 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; + 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667, + 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667, + 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667, + 0x18000 }; dprintk("%s()\n", __func__); snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); - if(snr_reading >= 0xa0 /* 100% */) + if (snr_reading >= 0xa0 /* 100% */) *snr = 0xffff; else - *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] + - ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 ); + *snr = snr_tab[(snr_reading & 0xf0) >> 4] + + (snr_tab[(snr_reading & 0x0f)] >> 4); dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, snr_reading, *snr); @@ -736,7 +772,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) * ESNO, from 0->30db (values 0->300). We provide this value by * default. */ -static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) +static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr) { struct cx24116_state *state = fe->demodulator_priv; @@ -750,7 +786,7 @@ static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) return 0; } -static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) +static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr) { if (esno_snr == 1) return cx24116_read_snr_esno(fe, snr); @@ -758,27 +794,27 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) return cx24116_read_snr_pct(fe, snr); } -static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct cx24116_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); - *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) | + *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) | cx24116_readreg(state, CX24116_REG_UCB0); return 0; } /* Overwrite the current tuning params, we are about to tune */ -static void cx24116_clone_params(struct dvb_frontend* fe) +static void cx24116_clone_params(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); } /* Wait for LNB */ -static int cx24116_wait_for_lnb(struct dvb_frontend* fe) +static int cx24116_wait_for_lnb(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; int i; @@ -787,7 +823,7 @@ static int cx24116_wait_for_lnb(struct dvb_frontend* fe) cx24116_readreg(state, CX24116_REG_QSTATUS)); /* Wait for up to 300 ms */ - for(i = 0; i < 30 ; i++) { + for (i = 0; i < 30 ; i++) { if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) return 0; msleep(10); @@ -798,20 +834,21 @@ static int cx24116_wait_for_lnb(struct dvb_frontend* fe) return -ETIMEDOUT; /* -EBUSY ? */ } -static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int cx24116_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t tone) { struct cx24116_cmd cmd; int ret; dprintk("%s(%d)\n", __func__, tone); - if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) { - printk("%s: Invalid, tone=%d\n", __func__, tone); + if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { + printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); return -EINVAL; } /* Wait for LNB ready */ ret = cx24116_wait_for_lnb(fe); - if(ret != 0) + if (ret != 0) return ret; /* Min delay time after DiSEqC send */ @@ -820,7 +857,7 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) /* This is always done before the tone is set */ cmd.args[0x00] = CMD_SET_TONEPRE; cmd.args[0x01] = 0x00; - cmd.len= 0x02; + cmd.len = 0x02; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; @@ -836,11 +873,11 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) cmd.args[0x03] = 0x01; break; case SEC_TONE_OFF: - dprintk("%s: setting tone off\n",__func__); + dprintk("%s: setting tone off\n", __func__); cmd.args[0x03] = 0x00; break; } - cmd.len= 0x04; + cmd.len = 0x04; /* Min delay time before DiSEqC send */ msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ @@ -849,7 +886,7 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) } /* Initialise DiSEqC */ -static int cx24116_diseqc_init(struct dvb_frontend* fe) +static int cx24116_diseqc_init(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; @@ -864,7 +901,7 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe) cmd.args[0x05] = 0x28; cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; cmd.args[0x07] = 0x01; - cmd.len= 0x08; + cmd.len = 0x08; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; @@ -878,36 +915,38 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe) /* Unknown */ state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; - state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */ + /* Continuation flag? */ + state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* DiSEqC message length */ state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; /* Command length */ - state->dsec_cmd.len= CX24116_DISEQC_MSGOFS; + state->dsec_cmd.len = CX24116_DISEQC_MSGOFS; return 0; } /* Send DiSEqC message with derived burst (hack) || previous burst */ -static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d) +static int cx24116_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *d) { struct cx24116_state *state = fe->demodulator_priv; int i, ret; /* Dump DiSEqC message */ if (debug) { - printk("cx24116: %s(", __func__); - for(i = 0 ; i < d->msg_len ;) { - printk("0x%02x", d->msg[i]); - if(++i < d->msg_len) - printk(", "); - } + printk(KERN_INFO "cx24116: %s(", __func__); + for (i = 0 ; i < d->msg_len ;) { + printk(KERN_INFO "0x%02x", d->msg[i]); + if (++i < d->msg_len) + printk(KERN_INFO ", "); + } printk(") toneburst=%d\n", toneburst); } /* Validate length */ - if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) + if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) return -EINVAL; /* DiSEqC message */ @@ -918,18 +957,19 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; /* Command length */ - state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; + state->dsec_cmd.len = CX24116_DISEQC_MSGOFS + + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; /* DiSEqC toneburst */ - if(toneburst == CX24116_DISEQC_MESGCACHE) + if (toneburst == CX24116_DISEQC_MESGCACHE) /* Message is cached */ return 0; - else if(toneburst == CX24116_DISEQC_TONEOFF) + else if (toneburst == CX24116_DISEQC_TONEOFF) /* Message is sent without burst */ state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; - else if(toneburst == CX24116_DISEQC_TONECACHE) { + else if (toneburst == CX24116_DISEQC_TONECACHE) { /* * Message is sent with derived else cached burst * @@ -948,15 +988,17 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma * Y = VOLTAGE (0=13V, 1=18V) * Z = BAND (0=LOW, 1=HIGH(22K)) */ - if(d->msg_len >= 4 && d->msg[2] == 0x38) - state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2); - if(debug) - dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]); + if (d->msg_len >= 4 && d->msg[2] == 0x38) + state->dsec_cmd.args[CX24116_DISEQC_BURST] = + ((d->msg[3] & 4) >> 2); + if (debug) + dprintk("%s burst=%d\n", __func__, + state->dsec_cmd.args[CX24116_DISEQC_BURST]); } /* Wait for LNB ready */ ret = cx24116_wait_for_lnb(fe); - if(ret != 0) + if (ret != 0) return ret; /* Wait for voltage/min repeat delay */ @@ -964,7 +1006,7 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma /* Command */ ret = cx24116_cmd_execute(fe, &state->dsec_cmd); - if(ret != 0) + if (ret != 0) return ret; /* * Wait for send @@ -976,29 +1018,33 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma * 12.5ms burst + * >15ms delay (XXX determine if FW does this, see set_tone) */ - msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) ); + msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60)); return 0; } /* Send DiSEqC burst */ -static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int cx24116_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) { struct cx24116_state *state = fe->demodulator_priv; int ret; - dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst); + dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst); /* DiSEqC burst */ if (burst == SEC_MINI_A) - state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; - else if(burst == SEC_MINI_B) - state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; + state->dsec_cmd.args[CX24116_DISEQC_BURST] = + CX24116_DISEQC_MINI_A; + else if (burst == SEC_MINI_B) + state->dsec_cmd.args[CX24116_DISEQC_BURST] = + CX24116_DISEQC_MINI_B; else return -EINVAL; /* DiSEqC toneburst */ - if(toneburst != CX24116_DISEQC_MESGCACHE) + if (toneburst != CX24116_DISEQC_MESGCACHE) /* Burst is cached */ return 0; @@ -1006,7 +1052,7 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t /* Wait for LNB ready */ ret = cx24116_wait_for_lnb(fe); - if(ret != 0) + if (ret != 0) return ret; /* Wait for voltage/min repeat delay */ @@ -1014,7 +1060,7 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t /* Command */ ret = cx24116_cmd_execute(fe, &state->dsec_cmd); - if(ret != 0) + if (ret != 0) return ret; /* @@ -1027,34 +1073,32 @@ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t * 12.5ms burst + * >15ms delay (XXX determine if FW does this, see set_tone) */ - msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); + msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60); return 0; } -static void cx24116_release(struct dvb_frontend* fe) +static void cx24116_release(struct dvb_frontend *fe) { - struct cx24116_state* state = fe->demodulator_priv; - dprintk("%s\n",__func__); + struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s\n", __func__); kfree(state); } static struct dvb_frontend_ops cx24116_ops; -struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, - struct i2c_adapter* i2c) +struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, + struct i2c_adapter *i2c) { - struct cx24116_state* state = NULL; + struct cx24116_state *state = NULL; int ret; - dprintk("%s\n",__func__); + dprintk("%s\n", __func__); /* allocate memory for the internal state */ state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); - if (state == NULL) { - printk("Unable to kmalloc\n"); + if (state == NULL) goto error1; - } /* setup the state */ memset(state, 0, sizeof(struct cx24116_state)); @@ -1063,27 +1107,31 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, state->i2c = i2c; /* check if the demod is present */ - ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); + ret = (cx24116_readreg(state, 0xFF) << 8) | + cx24116_readreg(state, 0xFE); if (ret != 0x0501) { - printk("Invalid probe, probably not a CX24116 device\n"); + printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n"); goto error2; } /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &cx24116_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; error2: kfree(state); error1: return NULL; } +EXPORT_SYMBOL(cx24116_attach); + #if 0 -static int cx24116_get_params(struct dvb_frontend* fe) +static int cx24116_get_params(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; struct dtv_frontend_properties *cache = &fe->dtv_property_cache; - dprintk("%s()\n",__func__); + dprintk("%s()\n", __func__); cache->frequency = state->dcur.frequency; cache->inversion = state->dcur.inversion; @@ -1099,13 +1147,13 @@ static int cx24116_get_params(struct dvb_frontend* fe) * * Power config will reset and load initial firmware if required */ -static int cx24116_initfe(struct dvb_frontend* fe) +static int cx24116_initfe(struct dvb_frontend *fe) { - struct cx24116_state* state = fe->demodulator_priv; + struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; int ret; - dprintk("%s()\n",__func__); + dprintk("%s()\n", __func__); /* Power on */ cx24116_writereg(state, 0xe0, 0); @@ -1115,9 +1163,9 @@ static int cx24116_initfe(struct dvb_frontend* fe) /* Firmware CMD 36: Power config */ cmd.args[0x00] = CMD_TUNERSLEEP; cmd.args[0x01] = 0; - cmd.len= 0x02; + cmd.len = 0x02; ret = cx24116_cmd_execute(fe, &cmd); - if(ret != 0) + if (ret != 0) return ret; return cx24116_diseqc_init(fe); @@ -1126,20 +1174,20 @@ static int cx24116_initfe(struct dvb_frontend* fe) /* * Put device to sleep */ -static int cx24116_sleep(struct dvb_frontend* fe) +static int cx24116_sleep(struct dvb_frontend *fe) { - struct cx24116_state* state = fe->demodulator_priv; + struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; int ret; - dprintk("%s()\n",__func__); + dprintk("%s()\n", __func__); /* Firmware CMD 36: Power config */ cmd.args[0x00] = CMD_TUNERSLEEP; cmd.args[0x01] = 1; - cmd.len= 0x02; + cmd.len = 0x02; ret = cx24116_cmd_execute(fe, &cmd); - if(ret != 0) + if (ret != 0) return ret; /* Power off (Shutdown clocks) */ @@ -1150,13 +1198,15 @@ static int cx24116_sleep(struct dvb_frontend* fe) return 0; } -static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp) +static int cx24116_set_property(struct dvb_frontend *fe, + struct dtv_property *tvp) { dprintk("%s(..)\n", __func__); return 0; } -static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp) +static int cx24116_get_property(struct dvb_frontend *fe, + struct dtv_property *tvp) { dprintk("%s(..)\n", __func__); return 0; @@ -1165,7 +1215,8 @@ static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tv /* dvb-core told us to tune, the tv property cache will be complete, * it's safe for is to pull values and use them for tuning purposes. */ -static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24116_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { struct cx24116_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1173,96 +1224,102 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par fe_status_t tunerstat; int i, status, ret, retune; - dprintk("%s()\n",__func__); + dprintk("%s()\n", __func__); - switch(c->delivery_system) { - case SYS_DVBS: - dprintk("%s: DVB-S delivery system selected\n",__func__); + switch (c->delivery_system) { + case SYS_DVBS: + dprintk("%s: DVB-S delivery system selected\n", __func__); - /* Only QPSK is supported for DVB-S */ - if(c->modulation != QPSK) { - dprintk("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } + /* Only QPSK is supported for DVB-S */ + if (c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } - /* Pilot doesn't exist in DVB-S, turn bit off */ - state->dnxt.pilot_val = CX24116_PILOT_OFF; - retune = 1; + /* Pilot doesn't exist in DVB-S, turn bit off */ + state->dnxt.pilot_val = CX24116_PILOT_OFF; + retune = 1; - /* DVB-S only supports 0.35 */ - if(c->rolloff != ROLLOFF_35) { - dprintk("%s: unsupported rolloff selected (%d)\n", - __func__, c->rolloff); - return -EOPNOTSUPP; - } - state->dnxt.rolloff_val = CX24116_ROLLOFF_035; - break; + /* DVB-S only supports 0.35 */ + if (c->rolloff != ROLLOFF_35) { + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); + return -EOPNOTSUPP; + } + state->dnxt.rolloff_val = CX24116_ROLLOFF_035; + break; - case SYS_DVBS2: - dprintk("%s: DVB-S2 delivery system selected\n",__func__); - - /* - * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, - * but not hardware auto detection - */ - if(c->modulation != PSK_8 && c->modulation != QPSK) { - dprintk("%s: unsupported modulation selected (%d)\n", - __func__, c->modulation); - return -EOPNOTSUPP; - } + case SYS_DVBS2: + dprintk("%s: DVB-S2 delivery system selected\n", __func__); - switch(c->pilot) { - case PILOT_AUTO: /* Not supported but emulated */ - retune = 2; /* Fall-through */ - case PILOT_OFF: - state->dnxt.pilot_val = CX24116_PILOT_OFF; - break; - case PILOT_ON: - state->dnxt.pilot_val = CX24116_PILOT_ON; - break; - default: - dprintk("%s: unsupported pilot mode selected (%d)\n", - __func__, c->pilot); - return -EOPNOTSUPP; - } + /* + * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, + * but not hardware auto detection + */ + if (c->modulation != PSK_8 && c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } - switch(c->rolloff) { - case ROLLOFF_20: - state->dnxt.rolloff_val= CX24116_ROLLOFF_020; - break; - case ROLLOFF_25: - state->dnxt.rolloff_val= CX24116_ROLLOFF_025; - break; - case ROLLOFF_35: - state->dnxt.rolloff_val= CX24116_ROLLOFF_035; - break; - case ROLLOFF_AUTO: /* Rolloff must be explicit */ - default: - dprintk("%s: unsupported rolloff selected (%d)\n", - __func__, c->rolloff); - return -EOPNOTSUPP; - } + switch (c->pilot) { + case PILOT_AUTO: /* Not supported but emulated */ + state->dnxt.pilot_val = (c->modulation == QPSK) + ? CX24116_PILOT_OFF : CX24116_PILOT_ON; + retune = 2; + break; + case PILOT_OFF: + state->dnxt.pilot_val = CX24116_PILOT_OFF; + break; + case PILOT_ON: + state->dnxt.pilot_val = CX24116_PILOT_ON; break; + default: + dprintk("%s: unsupported pilot mode selected (%d)\n", + __func__, c->pilot); + return -EOPNOTSUPP; + } + switch (c->rolloff) { + case ROLLOFF_20: + state->dnxt.rolloff_val = CX24116_ROLLOFF_020; + break; + case ROLLOFF_25: + state->dnxt.rolloff_val = CX24116_ROLLOFF_025; + break; + case ROLLOFF_35: + state->dnxt.rolloff_val = CX24116_ROLLOFF_035; + break; + case ROLLOFF_AUTO: /* Rolloff must be explicit */ default: - dprintk("%s: unsupported delivery system selected (%d)\n", - __func__, c->delivery_system); + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); return -EOPNOTSUPP; + } + break; + + default: + dprintk("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; } state->dnxt.modulation = c->modulation; state->dnxt.frequency = c->frequency; state->dnxt.pilot = c->pilot; state->dnxt.rolloff = c->rolloff; - if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) + ret = cx24116_set_inversion(state, c->inversion); + if (ret != 0) return ret; /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ - if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) + ret = cx24116_set_fec(state, c->modulation, c->fec_inner); + if (ret != 0) return ret; - if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0) + ret = cx24116_set_symbolrate(state, c->symbol_rate); + if (ret != 0) return ret; /* discard the 'current' tuning parameters and prepare to tune */ @@ -1288,7 +1345,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* Set/Reset B/W */ cmd.args[0x00] = CMD_BANDWIDTH; cmd.args[0x01] = 0x01; - cmd.len= 0x02; + cmd.len = 0x02; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; @@ -1336,7 +1393,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); } - cmd.len= 0x13; + cmd.len = 0x13; /* We need to support pilot and non-pilot tuning in the * driver automatically. This is a workaround for because @@ -1344,12 +1401,13 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par */ do { /* Reset status register */ - status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK; + status = cx24116_readreg(state, CX24116_REG_SSTATUS) + & CX24116_SIGNAL_MASK; cx24116_writereg(state, CX24116_REG_SSTATUS, status); /* Tune */ ret = cx24116_cmd_execute(fe, &cmd); - if( ret != 0 ) + if (ret != 0) break; /* @@ -1358,28 +1416,27 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par * If we are able to tune then generally it occurs within 100ms. * If it takes longer, try a different toneburst setting. */ - for(i = 0; i < 50 ; i++) { + for (i = 0; i < 50 ; i++) { cx24116_read_status(fe, &tunerstat); status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); - if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { - dprintk("%s: Tuned\n",__func__); + if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { + dprintk("%s: Tuned\n", __func__); goto tuned; } msleep(10); } - dprintk("%s: Not tuned\n",__func__); + dprintk("%s: Not tuned\n", __func__); /* Toggle pilot bit when in auto-pilot */ - if(state->dcur.pilot == PILOT_AUTO) + if (state->dcur.pilot == PILOT_AUTO) cmd.args[0x07] ^= CX24116_PILOT_ON; - } - while(--retune); + } while (--retune); tuned: /* Set/Reset B/W */ cmd.args[0x00] = CMD_BANDWIDTH; cmd.args[0x01] = 0x00; - cmd.len= 0x02; + cmd.len = 0x02; ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret; @@ -1424,17 +1481,7 @@ static struct dvb_frontend_ops cx24116_ops = { .set_frontend = cx24116_set_frontend, }; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -module_param(toneburst, int, 0644); -MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); - -module_param(esno_snr, int, 0644); -MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)"); - MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(cx24116_attach); diff --git a/linux/drivers/media/dvb/frontends/cx24116.h b/linux/drivers/media/dvb/frontends/cx24116.h index 8dbcec268..4cb3ddd6c 100644 --- a/linux/drivers/media/dvb/frontends/cx24116.h +++ b/linux/drivers/media/dvb/frontends/cx24116.h @@ -23,31 +23,32 @@ #include <linux/dvb/frontend.h> -struct cx24116_config -{ +struct cx24116_config { /* the demodulator's i2c address */ u8 demod_address; /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); /* Need to reset device during firmware loading */ - int (*reset_device)(struct dvb_frontend* fe); + int (*reset_device)(struct dvb_frontend *fe); /* Need to set MPEG parameters */ u8 mpg_clk_pos_pol:0x02; }; #if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE) -extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, - struct i2c_adapter* i2c); +extern struct dvb_frontend *cx24116_attach( + const struct cx24116_config *config, + struct i2c_adapter *i2c); #else -static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, - struct i2c_adapter* i2c) +static inline struct dvb_frontend *cx24116_attach( + const struct cx24116_config *config, + struct i2c_adapter *i2c) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_CX24116 +#endif #endif /* CX24116_H */ diff --git a/linux/drivers/media/dvb/frontends/cx24123.c b/linux/drivers/media/dvb/frontends/cx24123.c index 970e4df08..fb559369e 100644 --- a/linux/drivers/media/dvb/frontends/cx24123.c +++ b/linux/drivers/media/dvb/frontends/cx24123.c @@ -33,7 +33,13 @@ #define XTAL 10111000 static int force_band; +module_param(force_band, int, 0644); +MODULE_PARM_DESC(force_band, "Force a specific band select "\ + "(1-9, default:off)."); + static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); #define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0) #define err(args...) do { printk(KERN_ERR "CX24123: " args); } while (0) @@ -46,10 +52,9 @@ static int debug; } \ } while (0) -struct cx24123_state -{ - struct i2c_adapter* i2c; - const struct cx24123_config* config; +struct cx24123_state { + struct i2c_adapter *i2c; + const struct cx24123_config *config; struct dvb_frontend frontend; @@ -70,8 +75,7 @@ struct cx24123_state }; /* Various tuner defaults need to be established for a given symbol rate Sps */ -static struct -{ +static struct cx24123_AGC_val { u32 symbolrate_low; u32 symbolrate_high; u32 VCAprogdata; @@ -109,8 +113,7 @@ static struct * fixme: The bounds on the bands do not match the doc in real life. * fixme: Some of them have been moved, other might need adjustment. */ -static struct -{ +static struct cx24123_bandselect_val { u32 freq_low; u32 freq_high; u32 VCOdivider; @@ -260,7 +263,8 @@ static int cx24123_i2c_writereg(struct cx24123_state *state, /* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */ - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { printk("%s: writereg error(err == %i, reg == 0x%02x," " data == 0x%02x)\n", __func__, err, reg, data); return err; @@ -295,7 +299,8 @@ static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg) #define cx24123_writereg(state, reg, val) \ cx24123_i2c_writereg(state, state->config->demod_address, reg, val) -static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) +static int cx24123_set_inversion(struct cx24123_state *state, + fe_spectral_inversion_t inversion) { u8 nom_reg = cx24123_readreg(state, 0x0e); u8 auto_reg = cx24123_readreg(state, 0x10); @@ -322,7 +327,8 @@ static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_invers return 0; } -static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion) +static int cx24123_get_inversion(struct cx24123_state *state, + fe_spectral_inversion_t *inversion) { u8 val; @@ -339,18 +345,20 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers return 0; } -static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) +static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec) { u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; - if ( (fec < FEC_NONE) || (fec > FEC_AUTO) ) + if ((fec < FEC_NONE) || (fec > FEC_AUTO)) fec = FEC_AUTO; /* Set the soft decision threshold */ - if(fec == FEC_1_2) - cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) | 0x01); + if (fec == FEC_1_2) + cx24123_writereg(state, 0x43, + cx24123_readreg(state, 0x43) | 0x01); else - cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) & ~0x01); + cx24123_writereg(state, 0x43, + cx24123_readreg(state, 0x43) & ~0x01); switch (fec) { case FEC_1_2: @@ -399,11 +407,11 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) return 0; } -static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) +static int cx24123_get_fec(struct cx24123_state *state, fe_code_rate_t *fec) { int ret; - ret = cx24123_readreg (state, 0x1b); + ret = cx24123_readreg(state, 0x1b); if (ret < 0) return ret; ret = ret & 0x07; @@ -444,16 +452,16 @@ static u32 cx24123_int_log2(u32 a, u32 b) { u32 exp, nearest = 0; u32 div = a / b; - if(a % b >= b / 2) ++div; - if(div < (1 << 31)) - { - for(exp = 1; div > exp; nearest++) + if (a % b >= b / 2) + ++div; + if (div < (1 << 31)) { + for (exp = 1; div > exp; nearest++) exp += exp; } return nearest; } -static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) +static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) { u32 tmp, sample_rate, ratio, sample_gain; u8 pll_mult; @@ -509,9 +517,9 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) cx24123_writereg(state, 0x01, pll_mult * 6); - cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f ); - cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff ); - cx24123_writereg(state, 0x0a, (ratio ) & 0xff ); + cx24123_writereg(state, 0x08, (ratio >> 16) & 0x3f); + cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff); + cx24123_writereg(state, 0x0a, ratio & 0xff); /* also set the demodulator sample gain */ sample_gain = cx24123_int_log2(sample_rate, srate); @@ -525,10 +533,12 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) } /* - * Based on the required frequency and symbolrate, the tuner AGC has to be configured - * and the correct band selected. Calculate those values + * Based on the required frequency and symbolrate, the tuner AGC has + * to be configured and the correct band selected. + * Calculate those values. */ -static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24123_pll_calculate(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { struct cx24123_state *state = fe->demodulator_priv; u32 ndiv = 0, adiv = 0, vco_div = 0; @@ -536,6 +546,8 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa int pump = 2; int band = 0; int num_bands = ARRAY_SIZE(cx24123_bandselect_vals); + struct cx24123_bandselect_val *bsv = NULL; + struct cx24123_AGC_val *agcv = NULL; /* Defaults for low freq, low rate */ state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; @@ -543,58 +555,65 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa state->bandselectarg = cx24123_bandselect_vals[0].progdata; vco_div = cx24123_bandselect_vals[0].VCOdivider; - /* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */ - for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) - { - if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) && - (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) { - state->VCAarg = cx24123_AGC_vals[i].VCAprogdata; - state->VGAarg = cx24123_AGC_vals[i].VGAprogdata; - state->FILTune = cx24123_AGC_vals[i].FILTune; + /* For the given symbol rate, determine the VCA, VGA and + * FILTUNE programming bits */ + for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) { + agcv = &cx24123_AGC_vals[i]; + if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) && + (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) { + state->VCAarg = agcv->VCAprogdata; + state->VGAarg = agcv->VGAprogdata; + state->FILTune = agcv->FILTune; } } /* determine the band to use */ - if(force_band < 1 || force_band > num_bands) - { - for (i = 0; i < num_bands; i++) - { - if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && - (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) + if (force_band < 1 || force_band > num_bands) { + for (i = 0; i < num_bands; i++) { + bsv = &cx24123_bandselect_vals[i]; + if ((bsv->freq_low <= p->frequency) && + (bsv->freq_high >= p->frequency)) band = i; } - } - else + } else band = force_band - 1; state->bandselectarg = cx24123_bandselect_vals[band].progdata; vco_div = cx24123_bandselect_vals[band].VCOdivider; /* determine the charge pump current */ - if ( p->frequency < (cx24123_bandselect_vals[band].freq_low + cx24123_bandselect_vals[band].freq_high)/2 ) + if (p->frequency < (cx24123_bandselect_vals[band].freq_low + + cx24123_bandselect_vals[band].freq_high) / 2) pump = 0x01; else pump = 0x02; /* Determine the N/A dividers for the requested lband freq (in kHz). */ - /* Note: the reference divider R=10, frequency is in KHz, XTAL is in Hz */ - ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff; - adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f; + /* Note: the reference divider R=10, frequency is in KHz, + * XTAL is in Hz */ + ndiv = (((p->frequency * vco_div * 10) / + (2 * XTAL / 1000)) / 32) & 0x1ff; + adiv = (((p->frequency * vco_div * 10) / + (2 * XTAL / 1000)) % 32) & 0x1f; if (adiv == 0 && ndiv > 0) ndiv--; - /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */ - state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv; + /* control bits 11, refdiv 11, charge pump polarity 1, + * charge pump current, ndiv, adiv */ + state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | + (pump << 14) | (ndiv << 5) | adiv; return 0; } /* * Tuner data is 21 bits long, must be left-aligned in data. - * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip. + * Tuner cx24109 is written through a dedicated 3wire interface + * on the demod chip. */ -static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data) +static int cx24123_pll_writereg(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p, u32 data) { struct cx24123_state *state = fe->demodulator_priv; unsigned long timeout; @@ -621,7 +640,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par /* send another 8 bytes, wait for the send to be completed */ timeout = jiffies + msecs_to_jiffies(40); - cx24123_writereg(state, 0x22, (data>>8) & 0xff ); + cx24123_writereg(state, 0x22, (data >> 8) & 0xff); while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { if (time_after(jiffies, timeout)) { err("%s: demodulator is not responding, "\ @@ -631,9 +650,10 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par msleep(10); } - /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */ + /* send the lower 5 bits of this byte, padded with 3 LBB, + * wait for the send to be completed */ timeout = jiffies + msecs_to_jiffies(40); - cx24123_writereg(state, 0x22, (data) & 0xff ); + cx24123_writereg(state, 0x22, (data) & 0xff); while ((cx24123_readreg(state, 0x20) & 0x80)) { if (time_after(jiffies, timeout)) { err("%s: demodulator is not responding," \ @@ -650,7 +670,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24123_pll_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { struct cx24123_state *state = fe->demodulator_priv; u8 val; @@ -701,7 +722,7 @@ static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start) return cx24123_writereg(state, 0x23, r); } -static int cx24123_initfe(struct dvb_frontend* fe) +static int cx24123_initfe(struct dvb_frontend *fe) { struct cx24123_state *state = fe->demodulator_priv; int i; @@ -710,19 +731,22 @@ static int cx24123_initfe(struct dvb_frontend* fe) /* Configure the demod to a good set of defaults */ for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++) - cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data); + cx24123_writereg(state, cx24123_regdata[i].reg, + cx24123_regdata[i].data); /* Set the LNB polarity */ - if(state->config->lnb_polarity) - cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02); + if (state->config->lnb_polarity) + cx24123_writereg(state, 0x32, + cx24123_readreg(state, 0x32) | 0x02); if (state->config->dont_use_pll) - cx24123_repeater_mode(state, 1, 0); + cx24123_repeater_mode(state, 1, 0); return 0; } -static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int cx24123_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) { struct cx24123_state *state = fe->demodulator_priv; u8 val; @@ -751,7 +775,7 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state) { unsigned long timeout = jiffies + msecs_to_jiffies(200); while (!(cx24123_readreg(state, 0x29) & 0x40)) { - if(time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout)) { err("%s: diseqc queue not ready, " \ "command may be lost.\n", __func__); break; @@ -760,7 +784,8 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state) } } -static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) +static int cx24123_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) { struct cx24123_state *state = fe->demodulator_priv; int i, val, tone; @@ -782,20 +807,21 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma cx24123_writereg(state, 0x2C + i, cmd->msg[i]); val = cx24123_readreg(state, 0x29); - cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); + cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40) | + ((cmd->msg_len-3) & 3)); /* wait for diseqc message to finish sending */ cx24123_wait_for_diseqc(state); /* restart continuous tone if enabled */ - if (tone & 0x10) { + if (tone & 0x10) cx24123_writereg(state, 0x29, tone & ~0x40); - } return 0; } -static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +static int cx24123_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) { struct cx24123_state *state = fe->demodulator_priv; int val, tone; @@ -825,13 +851,13 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); /* restart continuous tone if enabled */ - if (tone & 0x10) { + if (tone & 0x10) cx24123_writereg(state, 0x29, tone & ~0x40); - } + return 0; } -static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int cx24123_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct cx24123_state *state = fe->demodulator_priv; int sync = cx24123_readreg(state, 0x14); @@ -864,8 +890,9 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) } /* - * Configured to return the measurement of errors in blocks, because no UCBLOCKS value - * is available, so this value doubles up to satisfy both measurements + * Configured to return the measurement of errors in blocks, + * because no UCBLOCKS value is available, so this value doubles up + * to satisfy both measurements. */ static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber) { @@ -887,7 +914,8 @@ static int cx24123_read_signal_strength(struct dvb_frontend *fe, { struct cx24123_state *state = fe->demodulator_priv; - *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */ + /* larger = better */ + *signal_strength = cx24123_readreg(state, 0x3b) << 8; dprintk("Signal strength = %d\n", *signal_strength); @@ -918,7 +946,7 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); - state->currentfreq=p->frequency; + state->currentfreq = p->frequency; state->currentsymbolrate = p->u.qpsk.symbol_rate; cx24123_set_inversion(state, p->inversion); @@ -943,7 +971,8 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, return 0; } -static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24123_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { struct cx24123_state *state = fe->demodulator_priv; @@ -963,7 +992,7 @@ static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { struct cx24123_state *state = fe->demodulator_priv; u8 val; @@ -988,8 +1017,8 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return 0; } -static int cx24123_tune(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, +static int cx24123_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) @@ -1008,12 +1037,12 @@ static int cx24123_tune(struct dvb_frontend* fe, static int cx24123_get_algo(struct dvb_frontend *fe) { - return 1; //FE_ALGO_HW + return 1; /* FE_ALGO_HW */ } -static void cx24123_release(struct dvb_frontend* fe) +static void cx24123_release(struct dvb_frontend *fe) { - struct cx24123_state* state = fe->demodulator_priv; + struct cx24123_state *state = fe->demodulator_priv; dprintk("\n"); i2c_del_adapter(&state->tuner_i2c_adapter); kfree(state); @@ -1024,7 +1053,7 @@ static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, { struct cx24123_state *state = i2c_get_adapdata(i2c_adap); /* this repeater closes after the first stop */ - cx24123_repeater_mode(state, 1, 1); + cx24123_repeater_mode(state, 1, 1); return i2c_transfer(state->i2c, msg, num); } @@ -1048,8 +1077,8 @@ EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter); static struct dvb_frontend_ops cx24123_ops; -struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, - struct i2c_adapter* i2c) +struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, + struct i2c_adapter *i2c) { struct cx24123_state *state = kzalloc(sizeof(struct cx24123_state), GFP_KERNEL); @@ -1068,20 +1097,25 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, /* check if the demod is there */ state->demod_rev = cx24123_readreg(state, 0x00); switch (state->demod_rev) { - case 0xe1: info("detected CX24123C\n"); break; - case 0xd1: info("detected CX24123\n"); break; + case 0xe1: + info("detected CX24123C\n"); + break; + case 0xd1: + info("detected CX24123\n"); + break; default: err("wrong demod revision: %x\n", state->demod_rev); goto error; } /* create dvb_frontend */ - memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &cx24123_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; - /* create tuner i2c adapter */ - if (config->dont_use_pll) - cx24123_repeater_mode(state, 1, 0); + /* create tuner i2c adapter */ + if (config->dont_use_pll) + cx24123_repeater_mode(state, 1, 0); strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", sizeof(state->tuner_i2c_adapter.name)); @@ -1090,7 +1124,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, state->tuner_i2c_adapter.algo_data = NULL; i2c_set_adapdata(&state->tuner_i2c_adapter, state); if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) { - err("tuner i2c bus could not be initialized\n"); + err("tuner i2c bus could not be initialized\n"); goto error; } @@ -1101,6 +1135,7 @@ error: return NULL; } +EXPORT_SYMBOL(cx24123_attach); static struct dvb_frontend_ops cx24123_ops = { @@ -1137,15 +1172,8 @@ static struct dvb_frontend_ops cx24123_ops = { .get_frontend_algo = cx24123_get_algo, }; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - -module_param(force_band, int, 0644); -MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off)."); - MODULE_DESCRIPTION("DVB Frontend module for Conexant " \ "CX24123/CX24109/CX24113 hardware"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(cx24123_attach); diff --git a/linux/drivers/media/dvb/frontends/cx24123.h b/linux/drivers/media/dvb/frontends/cx24123.h index cc6b411d6..51ae866e9 100644 --- a/linux/drivers/media/dvb/frontends/cx24123.h +++ b/linux/drivers/media/dvb/frontends/cx24123.h @@ -23,13 +23,12 @@ #include <linux/dvb/frontend.h> -struct cx24123_config -{ +struct cx24123_config { /* the demodulator's i2c address */ u8 demod_address; /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); /* 0 = LNB voltage normal, 1 = LNB voltage inverted */ int lnb_polarity; @@ -39,7 +38,8 @@ struct cx24123_config void (*agc_callback) (struct dvb_frontend *); }; -#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE)) +#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \ + && defined(MODULE)) extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *); @@ -56,6 +56,6 @@ static struct i2c_adapter * printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_CX24123 +#endif #endif /* CX24123_H */ diff --git a/linux/drivers/media/dvb/frontends/dvb-pll.c b/linux/drivers/media/dvb/frontends/dvb-pll.c index bb3e35373..8ef5d1eff 100644 --- a/linux/drivers/media/dvb/frontends/dvb-pll.c +++ b/linux/drivers/media/dvb/frontends/dvb-pll.c @@ -312,7 +312,7 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { .count = 4, .entries = { { 1250000, 500, 0xc4, 0x00}, - { 1550000, 500, 0xc4, 0x40}, + { 1450000, 500, 0xc4, 0x40}, { 2050000, 500, 0xc4, 0x80}, { 2150000, 500, 0xc4, 0xc0}, }, diff --git a/linux/drivers/media/dvb/frontends/lgdt3304.c b/linux/drivers/media/dvb/frontends/lgdt3304.c new file mode 100644 index 000000000..724811744 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgdt3304.c @@ -0,0 +1,398 @@ +/* + * Driver for LG ATSC lgdt3304 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "lgdt3304.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)"); + +#define dprintk(fmt, args...) if (debug) do {\ + printk("lgdt3304 debug: " fmt, ##args); } while (0) + +struct lgdt3304_state +{ + struct dvb_frontend frontend; + fe_modulation_t current_modulation; + __u32 snr; + __u32 current_frequency; + __u8 addr; + struct i2c_adapter *i2c; +}; + +static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 3, + .buf = buf + }; + int i; + int err; + + for (i=0; i<len-1; i+=3){ + if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + i2cmsgs.buf += 3; + } + return 0; +} + +static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + struct i2c_msg i2cmsgs[2]; + int ret; + __u8 buf; + + __u8 regbuf[2] = { reg>>8, reg&0xff }; + + i2cmsgs[0].addr = state->addr; + i2cmsgs[0].flags = 0; + i2cmsgs[0].len = 2; + i2cmsgs[0].buf = regbuf; + + i2cmsgs[1].addr = state->addr; + i2cmsgs[1].flags = I2C_M_RD; + i2cmsgs[1].len = 1; + i2cmsgs[1].buf = &buf; + + if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, ret); + return ret; + } + + return buf; +} + +static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + char buffer[3] = { reg>>8, reg&0xff, val }; + int ret; + + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 3, + .buf=buffer + }; + ret = i2c_transfer(state->i2c, &i2cmsgs, 1); + if (ret != 1) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, ret); + return ret; + } + + return 0; +} + + +static int lgdt3304_soft_Reset(struct dvb_frontend *fe) +{ + lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a); + lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b); + mdelay(200); + return 0; +} + +static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { + int err = 0; + + static __u8 lgdt3304_vsb8_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x02, + 0x00, 0x00, 0x13, + 0x00, 0x0d, 0x02, + 0x00, 0x0e, 0x02, + 0x00, 0x12, 0x32, + 0x00, 0x13, 0xc4, + 0x01, 0x12, 0x17, + 0x01, 0x13, 0x15, + 0x01, 0x14, 0x18, + 0x01, 0x15, 0xff, + 0x01, 0x16, 0x2c, + 0x02, 0x14, 0x67, + 0x02, 0x24, 0x8d, + 0x04, 0x27, 0x12, + 0x04, 0x28, 0x4f, + 0x03, 0x08, 0x80, + 0x03, 0x09, 0x00, + 0x03, 0x0d, 0x00, + 0x03, 0x0e, 0x1c, + 0x03, 0x14, 0xe1, + 0x05, 0x0e, 0x5b, + }; + + /* not yet tested .. */ + static __u8 lgdt3304_qam64_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x18, + 0x00, 0x0d, 0x02, + //0x00, 0x0e, 0x02, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x00, + 0x03, 0x14, 0xe3, + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + 0x05, 0x0e, 0x5b, + }; + +#if 0 + /* not yet tested */ + static __u8 lgdt3304_qam256_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x19, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + 0x03, 0x0d, 0x14, + 0x05, 0x0e, 0x5b, + }; +#endif + + /* tested with KWorld a340 */ + static __u8 lgdt3304_qam256_data[] = { + /* 16bit , 8bit */ + /* regs , val */ + 0x00, 0x00, 0x01, //0x19, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + + 0x03, 0x0d, 0x14, + //0x05, 0x0e, 0x5b, + 0x01, 0x06, 0x4a, + 0x01, 0x07, 0x3d, + 0x01, 0x08, 0x70, + 0x01, 0x09, 0xa3, + + 0x05, 0x04, 0xfd, + + 0x00, 0x0d, 0x82, + + 0x05, 0x0e, 0x5b, + + 0x05, 0x0e, 0x5b, + + 0x00, 0x02, 0x9a, + + 0x00, 0x02, 0x9b, + + 0x00, 0x00, 0x01, + 0x00, 0x12, 0x2a, + 0x00, 0x13, 0x80, + 0x00, 0x0d, 0x02, + 0x03, 0x14, 0xe3, + + 0x03, 0x0e, 0x1c, + 0x03, 0x08, 0x66, + 0x03, 0x09, 0x66, + 0x03, 0x0a, 0x08, + 0x03, 0x0b, 0x9b, + + 0x03, 0x0d, 0x14, + 0x01, 0x06, 0x4a, + 0x01, 0x07, 0x3d, + 0x01, 0x08, 0x70, + 0x01, 0x09, 0xa3, + + 0x05, 0x04, 0xfd, + + 0x00, 0x0d, 0x82, + + 0x05, 0x0e, 0x5b, + }; + + struct lgdt3304_state *state = fe->demodulator_priv; + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data, + sizeof(lgdt3304_vsb8_data)); + break; + case QAM_64: + err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data, + sizeof(lgdt3304_qam64_data)); + break; + case QAM_256: + err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data, + sizeof(lgdt3304_qam256_data)); + break; + default: + break; + } + + if (err) { + printk("%s error setting modulation\n", __FUNCTION__); + } else { + state->current_modulation = param->u.vsb.modulation; + } + } + state->current_frequency = param->frequency; + + lgdt3304_soft_Reset(fe); + + + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, param); + + return 0; +} + +static int lgdt3304_init(struct dvb_frontend *fe) { + return 0; +} + +static int lgdt3304_sleep(struct dvb_frontend *fe) { + return 0; +} + + +static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgdt3304_state *state = fe->demodulator_priv; + int r011d; + int qam_lck; + + *status = 0; + dprintk("lgdt read status\n"); + + r011d = lgdt3304_i2c_read_reg(fe, 0x011d); + + dprintk("%02x\n", r011d); + + switch(state->current_modulation) { + case VSB_8: + if (r011d & 0x80) { + dprintk("VSB Locked\n"); + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + } + break; + case QAM_64: + case QAM_256: + qam_lck = r011d & 0x7; + switch(qam_lck) { + case 0x0: dprintk("Unlock\n"); + break; + case 0x4: dprintk("1st Lock in acquisition state\n"); + break; + case 0x6: dprintk("2nd Lock in acquisition state\n"); + break; + case 0x7: dprintk("Final Lock in good reception state\n"); + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + break; + } + break; + default: + printk("%s unhandled modulation\n", __FUNCTION__); + } + + + return 0; +} + +static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber) +{ + dprintk("read ber\n"); + return 0; +} + +static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr) +{ + dprintk("read snr\n"); + return 0; +} + +static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks) +{ + dprintk("read ucblocks\n"); + return 0; +} + +static void lgdt3304_release(struct dvb_frontend *fe) +{ + struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops demod_lgdt3304={ + .info = { + .name = "LG 3304", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 5056941, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt3304_init, + .sleep = lgdt3304_sleep, + .set_frontend = lgdt3304_set_parameters, + .read_snr = lgdt3304_read_snr, + .read_ber = lgdt3304_read_ber, + .read_status = lgdt3304_read_status, + .read_ucblocks = lgdt3304_read_ucblocks, + .release = lgdt3304_release, +}; + +struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c) +{ + + struct lgdt3304_state *state; + state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL); + memset(state, 0x0, sizeof(struct lgdt3304_state)); + state->addr = config->i2c_address; + state->i2c = i2c; + + memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +EXPORT_SYMBOL_GPL(lgdt3304_attach); +MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>"); +MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/lgdt3304.h b/linux/drivers/media/dvb/frontends/lgdt3304.h new file mode 100644 index 000000000..fc409fe59 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgdt3304.h @@ -0,0 +1,45 @@ +/* + * Driver for DVB-T lgdt3304 demodulator + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.com> + * + * 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 LGDT3304_H +#define LGDT3304_H + +#include <linux/dvb/frontend.h> + +struct lgdt3304_config +{ + /* demodulator's I2C address */ + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE)) +extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGDT */ + +#endif /* LGDT3304_H */ diff --git a/linux/drivers/media/dvb/frontends/s5h1409.c b/linux/drivers/media/dvb/frontends/s5h1409.c index 7500a1c53..cf4d8936b 100644 --- a/linux/drivers/media/dvb/frontends/s5h1409.c +++ b/linux/drivers/media/dvb/frontends/s5h1409.c @@ -30,10 +30,10 @@ struct s5h1409_state { - struct i2c_adapter* i2c; + struct i2c_adapter *i2c; /* configuration settings */ - const struct s5h1409_config* config; + const struct s5h1409_config *config; struct dvb_frontend frontend; @@ -48,6 +48,9 @@ struct s5h1409_state { }; static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable verbose debug messages"); + #define dprintk if (debug) printk /* Register values to initialise the demod, this will set VSB by default */ @@ -299,10 +302,10 @@ static struct qam256_snr_tab { }; /* 8 bit registers, 16 bit values */ -static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) +static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data) { int ret; - u8 buf [] = { reg, data >> 8, data & 0xff }; + u8 buf[] = { reg, data >> 8, data & 0xff }; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; @@ -310,19 +313,19 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " + printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, " "ret == %i)\n", __func__, reg, data, ret); return (ret != 1) ? -1 : 0; } -static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) +static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg) { int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0, 0 }; + u8 b0[] = { reg }; + u8 b1[] = { 0, 0 }; - struct i2c_msg msg [] = { + struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, { .addr = state->config->demod_address, .flags = I2C_M_RD, @@ -335,9 +338,9 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg) return (b1[0] << 8) | b1[1]; } -static int s5h1409_softreset(struct dvb_frontend* fe) +static int s5h1409_softreset(struct dvb_frontend *fe) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); @@ -349,11 +352,11 @@ static int s5h1409_softreset(struct dvb_frontend* fe) } #define S5H1409_VSB_IF_FREQ 5380 -#define S5H1409_QAM_IF_FREQ state->config->qam_if +#define S5H1409_QAM_IF_FREQ (state->config->qam_if) -static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) +static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(%d KHz)\n", __func__, KHz); @@ -376,26 +379,26 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) return 0; } -static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) +static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(%d)\n", __func__, inverted); - if(inverted == 1) + if (inverted == 1) return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ else return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ } -static int s5h1409_enable_modulation(struct dvb_frontend* fe, +static int s5h1409_enable_modulation(struct dvb_frontend *fe, fe_modulation_t m) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(0x%08x)\n", __func__, m); - switch(m) { + switch (m) { case VSB_8: dprintk("%s() VSB_8\n", __func__); if (state->if_freq != S5H1409_VSB_IF_FREQ) @@ -422,9 +425,9 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, return 0; } -static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(%d)\n", __func__, enable); @@ -434,9 +437,9 @@ static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) return s5h1409_writereg(state, 0xf3, 0); } -static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) +static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(%d)\n", __func__, enable); @@ -448,18 +451,18 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) s5h1409_readreg(state, 0xe3) & 0xfeff); } -static int s5h1409_sleep(struct dvb_frontend* fe, int enable) +static int s5h1409_sleep(struct dvb_frontend *fe, int enable) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(%d)\n", __func__, enable); return s5h1409_writereg(state, 0xf2, enable); } -static int s5h1409_register_reset(struct dvb_frontend* fe) +static int s5h1409_register_reset(struct dvb_frontend *fe) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); @@ -483,7 +486,7 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe) reg &= 0xff; s5h1409_writereg(state, 0x96, 0x00c); - if ((reg < 0x38) || (reg > 0x68) ) { + if ((reg < 0x38) || (reg > 0x68)) { s5h1409_writereg(state, 0x93, 0x3332); s5h1409_writereg(state, 0x9e, 0x2c37); } else { @@ -514,7 +517,7 @@ 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)) ); + (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); s5h1409_writereg(state, 0xab, s5h1409_readreg(state, 0xab) & 0xeffe); } @@ -529,10 +532,10 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend (struct dvb_frontend* fe, +static int s5h1409_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(frequency=%d)\n", __func__, p->frequency); @@ -546,9 +549,11 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, msleep(100); if (fe->ops.tuner_ops.set_params) { - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); 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); } /* Optimize the demod for QAM */ @@ -592,17 +597,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) /* Reset the demod hardware and reset all of the configuration registers to a default state. */ -static int s5h1409_init (struct dvb_frontend* fe) +static int s5h1409_init(struct dvb_frontend *fe) { int i; - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); s5h1409_sleep(fe, 0); s5h1409_register_reset(fe); - for (i=0; i < ARRAY_SIZE(init_tab); i++) + for (i = 0; i < ARRAY_SIZE(init_tab); i++) s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data); /* The datasheet says that after initialisation, VSB is default */ @@ -627,9 +632,9 @@ static int s5h1409_init (struct dvb_frontend* fe) return 0; } -static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; u16 reg; u32 tuner_status = 0; @@ -637,12 +642,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) /* Get the demodulator status */ reg = s5h1409_readreg(state, 0xf1); - if(reg & 0x1000) + if (reg & 0x1000) *status |= FE_HAS_VITERBI; - if(reg & 0x8000) + if (reg & 0x8000) *status |= FE_HAS_LOCK | FE_HAS_SYNC; - switch(state->config->status_mode) { + switch (state->config->status_mode) { case S5H1409_DEMODLOCKING: if (*status & FE_HAS_VITERBI) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; @@ -668,12 +673,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } -static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) { int i, ret = -EINVAL; dprintk("%s()\n", __func__); - for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) { + for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { if (v < qam256_snr_tab[i].val) { *snr = qam256_snr_tab[i].data; ret = 0; @@ -683,12 +688,12 @@ static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) return ret; } -static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) { int i, ret = -EINVAL; dprintk("%s()\n", __func__); - for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) { + for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { if (v < qam64_snr_tab[i].val) { *snr = qam64_snr_tab[i].data; ret = 0; @@ -698,12 +703,12 @@ static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) return ret; } -static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) +static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) { int i, ret = -EINVAL; dprintk("%s()\n", __func__); - for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) { + for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { if (v > vsb_snr_tab[i].val) { *snr = vsb_snr_tab[i].data; ret = 0; @@ -714,13 +719,13 @@ static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v) return ret; } -static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) +static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; u16 reg; dprintk("%s()\n", __func__); - switch(state->current_modulation) { + switch (state->current_modulation) { case QAM_64: reg = s5h1409_readreg(state, 0xf0) & 0xff; return s5h1409_qam64_lookup_snr(fe, snr, reg); @@ -737,30 +742,30 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr) return -EINVAL; } -static int s5h1409_read_signal_strength(struct dvb_frontend* fe, - u16* signal_strength) +static int s5h1409_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) { return s5h1409_read_snr(fe, signal_strength); } -static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; *ucblocks = s5h1409_readreg(state, 0xb5); return 0; } -static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber) +static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber) { return s5h1409_read_ucblocks(fe, ber); } -static int s5h1409_get_frontend(struct dvb_frontend* fe, +static int s5h1409_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; p->frequency = state->current_frequency; p->u.vsb.modulation = state->current_modulation; @@ -768,25 +773,25 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe, return 0; } -static int s5h1409_get_tune_settings(struct dvb_frontend* fe, +static int s5h1409_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; return 0; } -static void s5h1409_release(struct dvb_frontend* fe) +static void s5h1409_release(struct dvb_frontend *fe) { - struct s5h1409_state* state = fe->demodulator_priv; + struct s5h1409_state *state = fe->demodulator_priv; kfree(state); } static struct dvb_frontend_ops s5h1409_ops; -struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, - struct i2c_adapter* i2c) +struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, + struct i2c_adapter *i2c) { - struct s5h1409_state* state = NULL; + struct s5h1409_state *state = NULL; u16 reg; /* allocate memory for the internal state */ @@ -825,6 +830,7 @@ error: kfree(state); return NULL; } +EXPORT_SYMBOL(s5h1409_attach); static struct dvb_frontend_ops s5h1409_ops = { @@ -850,14 +856,10 @@ static struct dvb_frontend_ops s5h1409_ops = { .release = s5h1409_release, }; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Enable verbose debug messages"); - MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(s5h1409_attach); /* * Local variables: diff --git a/linux/drivers/media/dvb/frontends/s5h1409.h b/linux/drivers/media/dvb/frontends/s5h1409.h index d1a1d2eb8..070d9743e 100644 --- a/linux/drivers/media/dvb/frontends/s5h1409.h +++ b/linux/drivers/media/dvb/frontends/s5h1409.h @@ -24,8 +24,7 @@ #include <linux/dvb/frontend.h> -struct s5h1409_config -{ +struct s5h1409_config { /* the demodulator's i2c address */ u8 demod_address; @@ -60,12 +59,14 @@ struct s5h1409_config u16 mpeg_timing; }; -#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) -extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, - struct i2c_adapter* i2c); +#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, + struct i2c_adapter *i2c); #else -static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, - struct i2c_adapter* i2c) +static inline struct dvb_frontend *s5h1409_attach( + const struct s5h1409_config *config, + struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/linux/drivers/media/dvb/frontends/s5h1411.c b/linux/drivers/media/dvb/frontends/s5h1411.c index 2da1a3763..66e2dd6d6 100644 --- a/linux/drivers/media/dvb/frontends/s5h1411.c +++ b/linux/drivers/media/dvb/frontends/s5h1411.c @@ -38,6 +38,7 @@ struct s5h1411_state { struct dvb_frontend frontend; fe_modulation_t current_modulation; + unsigned int first_tune:1; u32 current_frequency; int if_freq; @@ -62,7 +63,7 @@ static struct init_tab { { S5H1411_I2C_TOP_ADDR, 0x08, 0x0047, }, { S5H1411_I2C_TOP_ADDR, 0x1c, 0x0400, }, { S5H1411_I2C_TOP_ADDR, 0x1e, 0x0370, }, - { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342a, }, + { S5H1411_I2C_TOP_ADDR, 0x1f, 0x342c, }, { S5H1411_I2C_TOP_ADDR, 0x24, 0x0231, }, { S5H1411_I2C_TOP_ADDR, 0x25, 0x1011, }, { S5H1411_I2C_TOP_ADDR, 0x26, 0x0f07, }, @@ -100,7 +101,6 @@ static struct init_tab { { S5H1411_I2C_TOP_ADDR, 0x78, 0x3141, }, { S5H1411_I2C_TOP_ADDR, 0x7a, 0x3141, }, { S5H1411_I2C_TOP_ADDR, 0xb3, 0x8003, }, - { S5H1411_I2C_TOP_ADDR, 0xb5, 0xafbb, }, { S5H1411_I2C_TOP_ADDR, 0xb5, 0xa6bb, }, { S5H1411_I2C_TOP_ADDR, 0xb6, 0x0609, }, { S5H1411_I2C_TOP_ADDR, 0xb7, 0x2f06, }, @@ -343,7 +343,7 @@ static int s5h1411_writereg(struct s5h1411_state *state, u8 addr, u8 reg, u16 data) { int ret; - u8 buf [] = { reg, data >> 8, data & 0xff }; + u8 buf[] = { reg, data >> 8, data & 0xff }; struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; @@ -359,10 +359,10 @@ static int s5h1411_writereg(struct s5h1411_state *state, static u16 s5h1411_readreg(struct s5h1411_state *state, u8 addr, u8 reg) { int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0, 0 }; + u8 b0[] = { reg }; + u8 b1[] = { 0, 0 }; - struct i2c_msg msg [] = { + struct i2c_msg msg[] = { { .addr = addr, .flags = 0, .buf = b0, .len = 1 }, { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; @@ -393,7 +393,7 @@ static int s5h1411_set_if_freq(struct dvb_frontend *fe, int KHz) switch (KHz) { case 3250: - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d9); + s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x38, 0x10d5); s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x39, 0x5342); s5h1411_writereg(state, S5H1411_I2C_QAM_ADDR, 0x2c, 0x10d9); break; @@ -464,13 +464,25 @@ static int s5h1411_set_spectralinversion(struct dvb_frontend *fe, int inversion) if (inversion == 1) val |= 0x1000; /* Inverted */ - else - val |= 0x0000; state->inversion = inversion; return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x24, val); } +static int s5h1411_set_serialmode(struct dvb_frontend *fe, int serial) +{ + struct s5h1411_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __func__, serial); + val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbd) & ~0x100; + + if (serial == 1) + val |= 0x100; + + return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, val); +} + static int s5h1411_enable_modulation(struct dvb_frontend *fe, fe_modulation_t m) { @@ -478,6 +490,12 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe, dprintk("%s(0x%08x)\n", __func__, m); + if ((state->first_tune == 0) && (m == state->current_modulation)) { + dprintk("%s() Already at desired modulation. Skipping...\n", + __func__); + return 0; + } + switch (m) { case VSB_8: dprintk("%s() VSB_8\n", __func__); @@ -502,6 +520,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe, } state->current_modulation = m; + state->first_tune = 0; s5h1411_softreset(fe); return 0; @@ -535,7 +554,7 @@ static int s5h1411_set_gpio(struct dvb_frontend *fe, int enable) return s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xe0, val); } -static int s5h1411_sleep(struct dvb_frontend *fe, int enable) +static int s5h1411_set_powerstate(struct dvb_frontend *fe, int enable) { struct s5h1411_state *state = fe->demodulator_priv; @@ -551,6 +570,11 @@ static int s5h1411_sleep(struct dvb_frontend *fe, int enable) return 0; } +static int s5h1411_sleep(struct dvb_frontend *fe) +{ + return s5h1411_set_powerstate(fe, 1); +} + static int s5h1411_register_reset(struct dvb_frontend *fe) { struct s5h1411_state *state = fe->demodulator_priv; @@ -574,9 +598,6 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe, s5h1411_enable_modulation(fe, p->u.vsb.modulation); - /* Allow the demod to settle */ - msleep(100); - if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -587,6 +608,10 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 0); } + /* Issue a reset to the demod so it knows to resync against the + newly tuned frequency */ + s5h1411_softreset(fe); + return 0; } @@ -599,7 +624,7 @@ static int s5h1411_init(struct dvb_frontend *fe) dprintk("%s()\n", __func__); - s5h1411_sleep(fe, 0); + s5h1411_set_powerstate(fe, 0); s5h1411_register_reset(fe); for (i = 0; i < ARRAY_SIZE(init_tab); i++) @@ -610,12 +635,17 @@ static int s5h1411_init(struct dvb_frontend *fe) /* The datasheet says that after initialisation, VSB is default */ state->current_modulation = VSB_8; + /* Although the datasheet says it's in VSB, empirical evidence + shows problems getting lock on the first tuning request. Make + sure we call enable_modulation the first time around */ + state->first_tune = 1; + if (state->config->output_mode == S5H1411_SERIAL_OUTPUT) /* Serial */ - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1101); + s5h1411_set_serialmode(fe, 1); else /* Parallel */ - s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xbd, 0x1001); + s5h1411_set_serialmode(fe, 0); s5h1411_set_spectralinversion(fe, state->config->inversion); s5h1411_set_if_freq(fe, state->config->vsb_if); @@ -637,28 +667,29 @@ static int s5h1411_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = 0; - /* Get the demodulator status */ - reg = (s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2) >> 15) - & 0x0001; - if (reg) - *status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_SIGNAL; + /* Register F2 bit 15 = Master Lock, removed */ switch (state->current_modulation) { case QAM_64: case QAM_256: reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf0); - if (reg & 0x100) - *status |= FE_HAS_VITERBI; - if (reg & 0x10) - *status |= FE_HAS_SYNC; + if (reg & 0x10) /* QAM FEC Lock */ + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + if (reg & 0x100) /* QAM EQ Lock */ + *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; + break; case VSB_8: - reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x5e); - if (reg & 0x0001) - *status |= FE_HAS_SYNC; reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xf2); - if (reg & 0x1000) - *status |= FE_HAS_VITERBI; + if (reg & 0x1000) /* FEC Lock */ + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + if (reg & 0x2000) /* EQ Lock */ + *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; + + reg = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0x53); + if (reg & 0x1) /* AFC Lock */ + *status |= FE_HAS_SIGNAL; + break; default: return -EINVAL; @@ -843,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, /* Note: Leaving the I2C gate open here. */ s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1); + /* Put the device into low-power mode until first use */ + s5h1411_set_powerstate(&state->frontend, 1); + return &state->frontend; error: @@ -863,6 +897,7 @@ static struct dvb_frontend_ops s5h1411_ops = { }, .init = s5h1411_init, + .sleep = s5h1411_sleep, .i2c_gate_ctrl = s5h1411_i2c_gate_ctrl, .set_frontend = s5h1411_set_frontend, .get_frontend = s5h1411_get_frontend, diff --git a/linux/drivers/media/dvb/frontends/s5h1411.h b/linux/drivers/media/dvb/frontends/s5h1411.h index 7d542bc00..45ec0f829 100644 --- a/linux/drivers/media/dvb/frontends/s5h1411.h +++ b/linux/drivers/media/dvb/frontends/s5h1411.h @@ -47,7 +47,7 @@ struct s5h1411_config { u16 mpeg_timing; /* IF Freq for QAM and VSB in KHz */ -#define S5H1411_IF_2500 2500 +#define S5H1411_IF_3250 3250 #define S5H1411_IF_3500 3500 #define S5H1411_IF_4000 4000 #define S5H1411_IF_5380 5380 diff --git a/linux/drivers/media/dvb/frontends/s921_core.c b/linux/drivers/media/dvb/frontends/s921_core.c new file mode 100644 index 000000000..5b9e6040e --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_core.c @@ -0,0 +1,587 @@ +/* + * Driver for Sharp s921 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "s921_core.h" + +static int s921_isdb_init(struct s921_isdb_t *dev); +static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params); +static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params); +static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data); + +static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01, + 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00, + 0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80, + 0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12, + 0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00, + 0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff, + 0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00, + 0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88, + 0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00, + 0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06, + 0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00, + 0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00, + 0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20, + 0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70, + 0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f, + 0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00, + 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, + 0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30, + 0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d, + 0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f, + 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00, + 0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84, + 0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e, + 0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba, + 0xf8, 0xd7 }; + +static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b, + 0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b, + 0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b, + 0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b, + 0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b, + 0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b, + 0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b, + 0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb, + 0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb, + 0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb, + 0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb, + 0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb, + 0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb, + 0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b, + 0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b, + 0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b, + 0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b }; + +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) { + switch(cmd) { + case ISDB_T_CMD_INIT: + s921_isdb_init(dev); + break; + case ISDB_T_CMD_SET_PARAM: + s921_isdb_set_parameters(dev, data); + break; + case ISDB_T_CMD_TUNE: + s921_isdb_tune(dev, data); + break; + case ISDB_T_CMD_GET_STATUS: + s921_isdb_get_status(dev, data); + break; + default: + printk("unhandled command\n"); + return -EINVAL; + } + return 0; +} + +static int s921_isdb_init(struct s921_isdb_t *dev) { + unsigned int i; + unsigned int ret; + printk("isdb_init\n"); + for (i = 0; i < sizeof(init_table); i+=2) { + ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]); + if (ret != 0) { + printk("i2c write failed\n"); + return ret; + } + } + return 0; +} + +static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) { + + int ret; + /* auto is sufficient for now, lateron this should be reflected in an extra interface */ + +#if 0 + u8 mod_b2 = 0; + u8 mod_b3 = 0; + u8 mod_b4 = 0; + u8 mod_b5 = 0; + u8 mod_b6 = 0; + u8 mod_b7 = 0; + u8 mod_b8 = 0; + /* LAYER A Setup */ + + switch (params->layer_a_carrier_modulation) { + case ISDB_T_LA_CM_DQPSK: + mod_b3 |= 0<<5; + break; + case ISDB_T_LA_CM_QPSK: + mod_b3 |= 1<<5; + break; + case ISDB_T_LA_CM_16QAM: + mod_b3 |= 2<<5; + break; + case ISDB_T_LA_CM_64QAM: + mod_b3 |= 3<<5; + break; + case ISDB_T_LA_CM_NOLAYER: + mod_b3 |= 7<<5; + break; + default: + printk("invalid carrier modulation\n"); + return -EINVAL; + } + + switch(params->layer_a_code_rate) { + case ISDB_T_LA_CR_1_2: + mod_b3 |= 0<<2; + break; + case ISDB_T_LA_CR_2_3: + mod_b3 |= 1<<2; + break; + case ISDB_T_LA_CR_3_4: + mod_b3 |= 2<<2; + break; + case ISDB_T_LA_CR_5_6: + mod_b3 |= 3<<2; + break; + case ISDB_T_LA_CR_7_8: + mod_b3 |= 4<<2; + break; + default: + printk("invalid coderate\n"); + return -EINVAL; + } + + switch (params->layer_a_mode) { + case ISDB_T_LA_MODE_1: + switch(params->layer_a_time_interleave) { + case ISDB_T_LA_TI_0: + mod_b3 |= 0; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_4: + mod_b3 |= 1; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_8: + mod_b3 |= 2; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_16: + mod_b3 |= 3; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_32: + mod_b3 |= 0; + mod_b4 |= 1<<7; + break; + default: + printk("invalid layer a time interleave\n"); + return -EINVAL; + } + break; + case ISDB_T_LA_MODE_2: + switch(params->layer_a_time_interleave) { + case ISDB_T_LA_TI_0: + mod_b3 |= 0; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_2: + mod_b3 |= 1; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_4: + mod_b3 |= 2; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_8: + mod_b3 |= 3; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_16: + mod_b3 |= 0; + mod_b4 |= 1<<7; + break; + default: + + printk("invalid layer a time interleave\n"); + return -EINVAL; + } + break; + case ISDB_T_LA_MODE_3: + switch(params->layer_a_time_interleave) { + case ISDB_T_LA_TI_0: + mod_b3 |= 0; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_1: + mod_b3 |= 1; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_2: + mod_b3 |= 2; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_4: + mod_b3 |= 3; + mod_b4 |= 0; + break; + case ISDB_T_LA_TI_8: + mod_b3 |= 0; + mod_b4 |= 1<<7; + break; + default: + printk("invalid layer a time interleave\n"); + return -EINVAL; + } + break; + default: + printk("invalid layer mode\n"); + return -EINVAL; + } + + + /* LAYER B Setup */ + switch (params->layer_b_carrier_modulation) { + case ISDB_T_LB_CM_DQPSK: + mod_b4 |= 0; + break; + case ISDB_T_LB_CM_QPSK: + mod_b4 |= 1; + break; + case ISDB_T_LB_CM_16QAM: + mod_b4 |= 2; + break; + case ISDB_T_LB_CM_64QAM: + mod_b4 |= 3; + break; + case ISDB_T_LB_CM_NOLAYER: + mod_b4 |= 7; + break; + default: + return -EINVAL; + } + + switch(params->layer_b_code_rate) { + case ISDB_T_LB_CR_1_2: + mod_b5 |= 0<<5; + break; + case ISDB_T_LB_CR_2_3: + mod_b5 |= 1<<5; + break; + case ISDB_T_LB_CR_3_4: + mod_b5 |= 2<<5; + break; + case ISDB_T_LB_CR_5_6: + mod_b5 |= 3<<5; + break; + case ISDB_T_LB_CR_7_8: + mod_b5 |= 4<<5; + break; + case ISDB_T_LB_CR_NOLAYER: + mod_b5 |= 7<<5; + break; + default: + return -EINVAL; + } + + switch (params->layer_b_mode) { + case ISDB_T_LB_MODE_1: + switch(params->layer_b_time_interleave) { + case ISDB_T_LB_TI_0: + mod_b5 |= 0; + break; + case ISDB_T_LB_TI_4: + mod_b5 |= 1<<2; + break; + case ISDB_T_LB_TI_8: + mod_b5 |= 2<<2; + break; + case ISDB_T_LB_TI_16: + mod_b5 |= 3<<2; + break; + case ISDB_T_LB_TI_32: + mod_b5 |= 4<<2; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LB_MODE_2: + switch(params->layer_b_time_interleave) { + case ISDB_T_LB_TI_0: + mod_b5 |= 0; + break; + case ISDB_T_LB_TI_2: + mod_b5 |= 1<<2; + break; + case ISDB_T_LB_TI_4: + mod_b5 |= 2<<2; + break; + case ISDB_T_LB_TI_8: + mod_b5 |= 3<<2; + break; + case ISDB_T_LB_TI_16: + mod_b5 |= 4<<2; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LB_MODE_3: + switch(params->layer_b_time_interleave) { + case ISDB_T_LB_TI_0: + mod_b5 |= 0; + break; + case ISDB_T_LB_TI_1: + mod_b5 |= 1<<2; + break; + case ISDB_T_LB_TI_2: + mod_b5 |= 2<<2; + break; + case ISDB_T_LB_TI_4: + mod_b5 |= 3<<2; + break; + case ISDB_T_LB_TI_8: + mod_b5 |= 4<<2; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + /* LAYER C Setup */ + switch (params->layer_c_carrier_modulation) { + case ISDB_T_LC_CM_DQPSK: + mod_b5 |= 0<<3; + break; + case ISDB_T_LC_CM_QPSK: + mod_b5 |= 1<<3; + break; + case ISDB_T_LC_CM_16QAM: + mod_b5 |= 2<<3; + break; + case ISDB_T_LC_CM_64QAM: + mod_b5 |= 3<<3; + break; + case ISDB_T_LC_CM_NOLAYER: + mod_b5 |= 7<<3; + break; + default: + return -EINVAL; + } + + switch(params->layer_c_code_rate) { + case ISDB_T_LC_CR_1_2: + mod_b5 |= 0<<0; + break; + case ISDB_T_LC_CR_2_3: + mod_b5 |= 1<<0; + break; + case ISDB_T_LC_CR_3_4: + mod_b5 |= 2<<0; + break; + case ISDB_T_LC_CR_5_6: + mod_b5 |= 3<<0; + break; + case ISDB_T_LC_CR_7_8: + mod_b5 |= 4<<0; + break; + default: + return -EINVAL; + } + + switch (params->layer_c_mode) { + case ISDB_T_LC_MODE_1: + switch(params->layer_c_time_interleave) { + case ISDB_T_LC_TI_0: + mod_b7 |= 0<<5; + break; + case ISDB_T_LC_TI_4: + mod_b7 |= 1<<5; + break; + case ISDB_T_LC_TI_8: + mod_b7 |= 2<<5; + break; + case ISDB_T_LC_TI_16: + mod_b7 |= 3<<5; + break; + case ISDB_T_LC_TI_32: + mod_b7 |= 4<<5; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LC_MODE_2: + switch(params->layer_c_time_interleave) { + case ISDB_T_LC_TI_0: + mod_b7 |= 0<<5; + break; + case ISDB_T_LC_TI_2: + mod_b7 |= 1<<5; + break; + case ISDB_T_LC_TI_4: + mod_b7 |= 2<<5; + break; + case ISDB_T_LC_TI_8: + mod_b7 |= 3<<5; + break; + case ISDB_T_LC_TI_16: + mod_b7 |= 4<<5; + break; + default: + return -EINVAL; + } + break; + case ISDB_T_LC_MODE_3: + switch(params->layer_c_time_interleave) { + case ISDB_T_LC_TI_0: + mod_b7 |= 0<<5; + break; + case ISDB_T_LC_TI_1: + mod_b7 |= 1<<5; + break; + case ISDB_T_LC_TI_2: + mod_b7 |= 2<<5; + break; + case ISDB_T_LC_TI_4: + mod_b7 |= 3<<5; + break; + case ISDB_T_LC_TI_8: + mod_b7 |= 4<<5; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } +#endif + + + ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2); + ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2); + + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7); + if (ret < 0) + return -EINVAL; + + return E_OK; +} + +static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) { + + int ret; + int index; + + index = (params->frequency - 473143000)/6000000; + + if (index > 48) { + return -EINVAL; + } + + dev->i2c_write(dev->priv_dev, 0x47, 0x60); + + ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a); + if (ret < 0) + return -EINVAL; + + ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09); + if (ret < 0) + return -EINVAL; + + dev->i2c_write(dev->priv_dev, 0x01, 0x40); + return 0; +} + +static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) { + unsigned int *ret = (unsigned int*)data; + u8 ifagc_dt; + u8 rfagc_dt; + + mdelay(10); + ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81); + rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82); +#if 0 + *ret = dev->i2c_read(dev->priv_dev, 0x82); + printk("status 83: %02x\n", *ret); + *ret = dev->i2c_read(dev->priv_dev, 0x80); + mdelay(10); + *ret = dev->i2c_read(dev->priv_dev, 0x80); + mdelay(10); + *ret = dev->i2c_read(dev->priv_dev, 0x80); +#endif + if (rfagc_dt == 0x40) { + *ret = 1; + } + return 0; +} diff --git a/linux/drivers/media/dvb/frontends/s921_core.h b/linux/drivers/media/dvb/frontends/s921_core.h new file mode 100644 index 000000000..de2f10a44 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_core.h @@ -0,0 +1,114 @@ +#ifndef _S921_CORE_H +#define _S921_CORE_H +//#define u8 unsigned int +//#define u32 unsigned int + + + +//#define EINVAL -1 +#define E_OK 0 + +struct s921_isdb_t { + void *priv_dev; + int (*i2c_write)(void *dev, u8 reg, u8 val); + int (*i2c_read)(void *dev, u8 reg); +}; + +#define ISDB_T_CMD_INIT 0 +#define ISDB_T_CMD_SET_PARAM 1 +#define ISDB_T_CMD_TUNE 2 +#define ISDB_T_CMD_GET_STATUS 3 + +struct s921_isdb_t_tune_params { + u32 frequency; +}; + +struct s921_isdb_t_status { +}; + +struct s921_isdb_t_transmission_mode_params { + u8 mode; + u8 layer_a_mode; +#define ISDB_T_LA_MODE_1 0 +#define ISDB_T_LA_MODE_2 1 +#define ISDB_T_LA_MODE_3 2 + u8 layer_a_carrier_modulation; +#define ISDB_T_LA_CM_DQPSK 0 +#define ISDB_T_LA_CM_QPSK 1 +#define ISDB_T_LA_CM_16QAM 2 +#define ISDB_T_LA_CM_64QAM 3 +#define ISDB_T_LA_CM_NOLAYER 4 + u8 layer_a_code_rate; +#define ISDB_T_LA_CR_1_2 0 +#define ISDB_T_LA_CR_2_3 1 +#define ISDB_T_LA_CR_3_4 2 +#define ISDB_T_LA_CR_5_6 4 +#define ISDB_T_LA_CR_7_8 8 +#define ISDB_T_LA_CR_NOLAYER 16 + u8 layer_a_time_interleave; +#define ISDB_T_LA_TI_0 0 +#define ISDB_T_LA_TI_1 1 +#define ISDB_T_LA_TI_2 2 +#define ISDB_T_LA_TI_4 4 +#define ISDB_T_LA_TI_8 8 +#define ISDB_T_LA_TI_16 16 +#define ISDB_T_LA_TI_32 32 + u8 layer_a_nseg; + + u8 layer_b_mode; +#define ISDB_T_LB_MODE_1 0 +#define ISDB_T_LB_MODE_2 1 +#define ISDB_T_LB_MODE_3 2 + u8 layer_b_carrier_modulation; +#define ISDB_T_LB_CM_DQPSK 0 +#define ISDB_T_LB_CM_QPSK 1 +#define ISDB_T_LB_CM_16QAM 2 +#define ISDB_T_LB_CM_64QAM 3 +#define ISDB_T_LB_CM_NOLAYER 4 + u8 layer_b_code_rate; +#define ISDB_T_LB_CR_1_2 0 +#define ISDB_T_LB_CR_2_3 1 +#define ISDB_T_LB_CR_3_4 2 +#define ISDB_T_LB_CR_5_6 4 +#define ISDB_T_LB_CR_7_8 8 +#define ISDB_T_LB_CR_NOLAYER 16 + u8 layer_b_time_interleave; +#define ISDB_T_LB_TI_0 0 +#define ISDB_T_LB_TI_1 1 +#define ISDB_T_LB_TI_2 2 +#define ISDB_T_LB_TI_4 4 +#define ISDB_T_LB_TI_8 8 +#define ISDB_T_LB_TI_16 16 +#define ISDB_T_LB_TI_32 32 + u8 layer_b_nseg; + + u8 layer_c_mode; +#define ISDB_T_LC_MODE_1 0 +#define ISDB_T_LC_MODE_2 1 +#define ISDB_T_LC_MODE_3 2 + u8 layer_c_carrier_modulation; +#define ISDB_T_LC_CM_DQPSK 0 +#define ISDB_T_LC_CM_QPSK 1 +#define ISDB_T_LC_CM_16QAM 2 +#define ISDB_T_LC_CM_64QAM 3 +#define ISDB_T_LC_CM_NOLAYER 4 + u8 layer_c_code_rate; +#define ISDB_T_LC_CR_1_2 0 +#define ISDB_T_LC_CR_2_3 1 +#define ISDB_T_LC_CR_3_4 2 +#define ISDB_T_LC_CR_5_6 4 +#define ISDB_T_LC_CR_7_8 8 +#define ISDB_T_LC_CR_NOLAYER 16 + u8 layer_c_time_interleave; +#define ISDB_T_LC_TI_0 0 +#define ISDB_T_LC_TI_1 1 +#define ISDB_T_LC_TI_2 2 +#define ISDB_T_LC_TI_4 4 +#define ISDB_T_LC_TI_8 8 +#define ISDB_T_LC_TI_16 16 +#define ISDB_T_LC_TI_32 32 + u8 layer_c_nseg; +}; + +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data); +#endif diff --git a/linux/drivers/media/dvb/frontends/s921_module.c b/linux/drivers/media/dvb/frontends/s921_module.c new file mode 100644 index 000000000..6018ec505 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_module.c @@ -0,0 +1,254 @@ +/* + * Driver for Sharp s921 driver + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de> + * + * All rights reserved. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include "dvb_frontend.h" +#include "s921_module.h" +#include "s921_core.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"s921 debugging (default off)"); + +#define dprintk(fmt, args...) if (debug) do {\ + printk("s921 debug: " fmt, ##args); } while (0) + +struct s921_state +{ + struct dvb_frontend frontend; + fe_modulation_t current_modulation; + __u32 snr; + __u32 current_frequency; + __u8 addr; + struct s921_isdb_t dev; + struct i2c_adapter *i2c; +}; + +static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + struct s921_isdb_t_transmission_mode_params params; + struct s921_isdb_t_tune_params tune_params; + + tune_params.frequency = param->frequency; +#if 0 + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + case BANDWIDTH_7_MHZ: + case BANDWIDTH_8_MHZ: + default: + break; + } + + switch (op->code_rate_HP) { + case FEC_2_3: + case FEC_3_4: + case FEC_5_6: + case FEC_7_8: + case FEC_1_2: + case FEC_AUTO: + break; + default: + break; + } + + switch(op->code_rate_LP) { + case FEC_2_3: + case FEC_3_4: + case FEC_5_6: + case FEC_7_8: + case FEC_1_2: + case FEC_AUTO: + case FEC_NONE: + default: + break; + } + + switch (op->constellation) { + case QPSK: + case QAM_AUTO: + case QAM_16: + default: + break; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + case GUARD_INTERVAL_1_16: + case GUARD_INTERVAL_1_8: + case GUARD_INTERVAL_1_4: + default: + break; + } + + switch (op->hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + case HIERARCHY_1: + case HIERARCHY_2: + case HIERARCHY_4: + default: + break; + } + +#endif + s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, ¶ms); + s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params); + mdelay(100); + return 0; +} + +static int s921_init(struct dvb_frontend *fe) { + printk("s921 init\n"); + return 0; +} + +static int s921_sleep(struct dvb_frontend *fe) { + printk("s921 sleep\n"); + return 0; +} + +static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + unsigned int ret; + mdelay(5); + s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret); + *status = 0; + + printk("status: %02x\n", ret); + if (ret == 1) { + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_LOCK; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_SIGNAL; + } + + return 0; +} + +static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber) +{ + dprintk("read ber\n"); + return 0; +} + +static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr) +{ + dprintk("read snr\n"); + return 0; +} + +static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks) +{ + dprintk("read ucblocks\n"); + return 0; +} + +static void s921_release(struct dvb_frontend *fe) +{ + struct s921_state *state = (struct s921_state *)fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops demod_s921={ + .info = { + .name = "SHARP S921", + .type = FE_OFDM, + .frequency_min = 473143000, + .frequency_max = 767143000, + .frequency_stepsize = 6000000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + .init = s921_init, + .sleep = s921_sleep, + .set_frontend = s921_set_parameters, + .read_snr = s921_read_snr, + .read_ber = s921_read_ber, + .read_status = s921_read_status, + .read_ucblocks = s921_read_ucblocks, + .release = s921_release, +}; + +static int s921_write(void *dev, u8 reg, u8 val) { + struct s921_state *state = dev; + char buf[2]={reg,val}; + int err; + struct i2c_msg i2cmsgs = { + .addr = state->addr, + .flags = 0, + .len = 2, + .buf = buf + }; + + if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) { + printk("%s i2c_transfer error %d\n", __FUNCTION__, err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static int s921_read(void *dev, u8 reg) { + struct s921_state *state = dev; + u8 b1; + int ret; + struct i2c_msg msg[2] = { { .addr = state->addr, + .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->addr, + .flags = I2C_M_RD, + .buf = &b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + return ret; + return b1; +} + +struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + + struct s921_state *state; + state = kzalloc(sizeof(struct s921_state), GFP_KERNEL); + memset(state, 0x0, sizeof(struct s921_state)); + + state->addr = config->i2c_address; + state->i2c = i2c; + state->dev.i2c_write = &s921_write; + state->dev.i2c_read = &s921_read; + state->dev.priv_dev = state; + + s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL); + + memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; +} + +EXPORT_SYMBOL_GPL(s921_attach); +MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>"); +MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/s921_module.h b/linux/drivers/media/dvb/frontends/s921_module.h new file mode 100644 index 000000000..78660424b --- /dev/null +++ b/linux/drivers/media/dvb/frontends/s921_module.h @@ -0,0 +1,49 @@ +/* + * Driver for DVB-T s921 demodulator + * + * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.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 S921_MODULE_H +#define S921_MODULE_H + +#include <linux/dvb/frontend.h> +#include "s921_core.h" + +int s921_isdb_init(struct s921_isdb_t *dev); +int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data); + +struct s921_config +{ + /* demodulator's I2C address */ + u8 i2c_address; +}; + +#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE)) +extern struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend* s921_attach(const struct s921_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_S921 */ + +#endif /* S921_H */ diff --git a/linux/drivers/media/dvb/frontends/si21xx.c b/linux/drivers/media/dvb/frontends/si21xx.c index 2f69a173d..216a532ab 100644 --- a/linux/drivers/media/dvb/frontends/si21xx.c +++ b/linux/drivers/media/dvb/frontends/si21xx.c @@ -8,7 +8,6 @@ * (at your option) any later version. * */ -#include <linux/version.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/linux/drivers/media/dvb/frontends/stb0899_algo.c b/linux/drivers/media/dvb/frontends/stb0899_algo.c new file mode 100644 index 000000000..156906f5d --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb0899_algo.c @@ -0,0 +1,1532 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 "stb0899_drv.h" +#include "stb0899_priv.h" +#include "stb0899_reg.h" + +inline u32 stb0899_do_div(u64 n, u32 d) +{ + /* wrap do_div() for ease of use */ + + do_div(n, d); + return n; +} + +/* + * stb0899_calc_srate + * Compute symbol rate + */ +static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr) +{ + u64 tmp; + + /* srate = (SFR * master_clk) >> 20 */ + + /* sfr is of size 20 bit, stored with an offset of 4 bit */ + tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2]; + tmp &= ~0xf; + tmp *= master_clk; + tmp >>= 24; + + return tmp; +} + +/* + * stb0899_get_srate + * Get the current symbol rate + */ +u32 stb0899_get_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u8 sfr[3]; + + stb0899_read_regs(state, STB0899_SFRH, sfr, 3); + + return stb0899_calc_srate(internal->master_clk, sfr); +} + +/* + * stb0899_set_srate + * Set symbol frequency + * MasterClock: master clock frequency (hz) + * SymbolRate: symbol rate (bauds) + * return symbol frequency + */ +static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate) +{ + u32 tmp; + u8 sfr[3]; + + dprintk(state->verbose, FE_DEBUG, 1, "-->"); + /* + * in order to have the maximum precision, the symbol rate entered into + * the chip is computed as the closest value of the "true value". + * In this purpose, the symbol rate value is rounded (1 is added on the bit + * below the LSB ) + * + * srate = (SFR * master_clk) >> 20 + * <=> + * SFR = srate << 20 / master_clk + * + * rounded: + * SFR = (srate << 21 + master_clk) / (2 * master_clk) + * + * stored as 20 bit number with an offset of 4 bit: + * sfr = SFR << 4; + */ + + tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk); + tmp <<= 4; + + sfr[0] = tmp >> 16; + sfr[1] = tmp >> 8; + sfr[2] = tmp; + + stb0899_write_regs(state, STB0899_SFRH, sfr, 3); + + return srate; +} + +/* + * stb0899_calc_derot_time + * Compute the amount of time needed by the derotator to lock + * SymbolRate: Symbol rate + * return: derotator time constant (ms) + */ +static long stb0899_calc_derot_time(long srate) +{ + if (srate > 0) + return (100000 / (srate / 1000)); + else + return 0; +} + +/* + * stb0899_carr_width + * Compute the width of the carrier + * return: width of carrier (kHz or Mhz) + */ +long stb0899_carr_width(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + return (internal->srate + (internal->srate * internal->rolloff) / 100); +} + +/* + * stb0899_first_subrange + * Compute the first subrange of the search + */ +static void stb0899_first_subrange(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + struct stb0899_config *config = state->config; + + int range = 0; + u32 bandwidth = 0; + + if (config->tuner_get_bandwidth) { + stb0899_i2c_gate_ctrl(&state->frontend, 1); + config->tuner_get_bandwidth(&state->frontend, &bandwidth); + stb0899_i2c_gate_ctrl(&state->frontend, 0); + range = bandwidth - stb0899_carr_width(state) / 2; + } + + if (range > 0) + internal->sub_range = MIN(internal->srch_range, range); + else + internal->sub_range = 0; + + internal->freq = params->freq; + internal->tuner_offst = 0L; + internal->sub_dir = 1; +} + +/* + * stb0899_check_tmg + * check for timing lock + * internal.Ttiming: time to wait for loop lock + */ +static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + int lock; + u8 reg; + s8 timing; + + msleep(internal->t_derot); + + stb0899_write_reg(state, STB0899_RTF, 0xf2); + reg = stb0899_read_reg(state, STB0899_TLIR); + lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg); + timing = stb0899_read_reg(state, STB0899_RTF); + + if (lock >= 42) { + if ((lock > 48) && (ABS(timing) >= 110)) { + internal->status = ANALOGCARRIER; + dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !"); + } else { + internal->status = TIMINGOK; + dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !"); + } + } else { + internal->status = NOTIMING; + dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !"); + } + return internal->status; +} + +/* + * stb0899_search_tmg + * perform a fs/2 zig-zag to find timing + */ +static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + short int derot_step, derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; + u8 cfr[2]; + + internal->status = NOTIMING; + + /* timing loop computation & symbol rate optimisation */ + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_step = (params->srate / 2L) / internal->mclk; + + while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) { + index++; + derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ + + if (ABS(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } + internal->direction = -internal->direction; /* Change zigzag direction */ + } + + if (internal->status == TIMINGOK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq); + } + + return internal->status; +} + +/* + * stb0899_check_carrier + * Check for carrier found + */ +static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u8 reg; + + msleep(internal->t_derot); /* wait for derotator ok */ + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + reg = stb0899_read_reg(state, STB0899_DSTATUS); + dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(CARRIER_FOUND, reg)) { + internal->status = CARRIEROK; + dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !"); + } else { + internal->status = NOCARRIER; + dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !"); + } + + return internal->status; +} + +/* + * stb0899_search_carrier + * Search for a QPSK carrier with the derotator + */ +static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; + u8 cfr[2]; + u8 reg; + + internal->status = NOCARRIER; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + do { + dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk); + if (stb0899_check_carrier(state) == NOCARRIER) { + index++; + last_derot_freq = derot_freq; + derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ + + if(ABS(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } + } + + internal->direction = -internal->direction; /* Change zigzag direction */ + } while ((internal->status != CARRIEROK) && next_loop); + + if (internal->status == CARRIEROK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq); + } else { + internal->derot_freq = last_derot_freq; + } + + return internal->status; +} + +/* + * stb0899_check_data + * Check for data found + */ +static enum stb0899_status stb0899_check_data(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + int lock = 0, index = 0, dataTime = 500, loop; + u8 reg; + + internal->status = NODATA; + + /* RESET FEC */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + msleep(1); + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + if (params->srate <= 2000000) + dataTime = 2000; + else if (params->srate <= 5000000) + dataTime = 1500; + else if (params->srate <= 15000000) + dataTime = 1000; + else + dataTime = 500; + + stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ + while (1) { + /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ + reg = stb0899_read_reg(state, STB0899_VSTATUS); + lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg); + loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg); + + if (lock || loop || (index > dataTime)) + break; + index++; + } + + if (lock) { /* DATA LOCK indicator */ + internal->status = DATAOK; + dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !"); + } + + return internal->status; +} + +/* + * stb0899_search_data + * Search for a QPSK carrier with the derotator + */ +static enum stb0899_status stb0899_search_data(struct stb0899_state *state) +{ + short int derot_freq, derot_step, derot_limit, next_loop = 3; + u8 cfr[2]; + u8 reg; + int index = 1; + + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + derot_step = (params->srate / 4L) / internal->mclk; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; + + do { + if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { + + derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ + if (ABS(derot_freq) > derot_limit) + next_loop--; + + if (next_loop) { + dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk); + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq)); + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + + stb0899_check_carrier(state); + index++; + } + } + internal->direction = -internal->direction; /* change zig zag direction */ + } while ((internal->status != DATAOK) && next_loop); + + if (internal->status == DATAOK) { + stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */ + internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]); + dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq); + } + + return internal->status; +} + +/* + * stb0899_check_range + * check if the found frequency is in the correct range + */ +static enum stb0899_status stb0899_check_range(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + int range_offst, tp_freq; + + range_offst = internal->srch_range / 2000; + tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000; + + if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) { + internal->status = RANGEOK; + dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !"); + } else { + internal->status = OUTOFRANGE; + dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !"); + } + + return internal->status; +} + +/* + * NextSubRange + * Compute the next subrange of the search + */ +static void next_sub_range(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_params *params = &state->params; + + long old_sub_range; + + if (internal->sub_dir > 0) { + old_sub_range = internal->sub_range; + internal->sub_range = MIN((internal->srch_range / 2) - + (internal->tuner_offst + internal->sub_range / 2), + internal->sub_range); + + if (internal->sub_range < 0) + internal->sub_range = 0; + + internal->tuner_offst += (old_sub_range + internal->sub_range) / 2; + } + + internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000; + internal->sub_dir = -internal->sub_dir; +} + +/* + * stb0899_dvbs_algo + * Search for a signal, timing, carrier and data for a + * given frequency in a given range + */ +enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state) +{ + struct stb0899_params *params = &state->params; + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u8 bclc, reg; + u8 cfr[2]; + u8 eq_const[10]; + s32 clnI = 3; + u32 bandwidth = 0; + + /* BETA values rated @ 99MHz */ + s32 betaTab[5][4] = { + /* 5 10 20 30MBps */ + { 37, 34, 32, 31 }, /* QPSK 1/2 */ + { 37, 35, 33, 31 }, /* QPSK 2/3 */ + { 37, 35, 33, 31 }, /* QPSK 3/4 */ + { 37, 36, 33, 32 }, /* QPSK 5/6 */ + { 37, 36, 33, 32 } /* QPSK 7/8 */ + }; + + internal->direction = 1; + + stb0899_set_srate(state, internal->master_clk, params->srate); + /* Carrier loop optimization versus symbol rate for acquisition*/ + if (params->srate <= 5000000) { + stb0899_write_reg(state, STB0899_ACLC, 0x89); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x1c); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 0; + } else if (params->srate <= 15000000) { + stb0899_write_reg(state, STB0899_ACLC, 0xc9); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x22); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 1; + } else if(params->srate <= 25000000) { + stb0899_write_reg(state, STB0899_ACLC, 0x89); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x27); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 2; + } else { + stb0899_write_reg(state, STB0899_ACLC, 0xc8); + bclc = stb0899_read_reg(state, STB0899_BCLC); + STB0899_SETFIELD_VAL(BETA, bclc, 0x29); + stb0899_write_reg(state, STB0899_BCLC, bclc); + clnI = 3; + } + + dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition"); + /* Set the timing loop to acquisition */ + stb0899_write_reg(state, STB0899_RTC, 0x46); + stb0899_write_reg(state, STB0899_CFD, 0xee); + + /* !! WARNING !! + * Do not read any status variables while acquisition, + * If any needed, read before the acquisition starts + * querying status while acquiring causes the + * acquisition to go bad and hence no locks. + */ + dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d", + internal->derot_percent, params->srate, internal->mclk); + + /* Initial calculations */ + internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol */ + internal->t_derot = stb0899_calc_derot_time(params->srate); + internal->t_data = 500; + + dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger"); + /* RESET Stream merger */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* + * Set KDIVIDER to an intermediate value between + * 1/2 and 7/8 for acquisition + */ + reg = stb0899_read_reg(state, STB0899_DEMAPVIT); + STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60); + stb0899_write_reg(state, STB0899_DEMAPVIT, reg); + + stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */ + stb0899_write_reg(state, STB0899_VITSYNC, 0x19); + + stb0899_first_subrange(state); + do { + /* Initialisations */ + cfr[0] = cfr[1] = 0; + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency */ + + stb0899_write_reg(state, STB0899_RTF, 0); + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); + stb0899_write_reg(state, STB0899_CFD, reg); + + internal->derot_freq = 0; + internal->status = NOAGC1; + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + /* Move tuner to frequency */ + dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency"); + if (state->config->tuner_set_frequency) + state->config->tuner_set_frequency(&state->frontend, internal->freq); + + if (state->config->tuner_get_frequency) + state->config->tuner_get_frequency(&state->frontend, &internal->freq); + + msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop */ + dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq); + internal->status = AGC1OK; + + /* There is signal in the band */ + if (config->tuner_get_bandwidth) + config->tuner_get_bandwidth(&state->frontend, &bandwidth); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + if (params->srate <= bandwidth / 2) + stb0899_search_tmg(state); /* For low rates (SCPC) */ + else + stb0899_check_tmg(state); /* For high rates (MCPC) */ + + if (internal->status == TIMINGOK) { + dprintk(state->verbose, FE_DEBUG, 1, + "TIMING OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_search_carrier(state) == CARRIEROK) { /* Search for carrier */ + dprintk(state->verbose, FE_DEBUG, 1, + "CARRIER OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_search_data(state) == DATAOK) { /* Check for data */ + dprintk(state->verbose, FE_DEBUG, 1, + "DATA OK ! Derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + if (stb0899_check_range(state) == RANGEOK) { + dprintk(state->verbose, FE_DEBUG, 1, + "RANGE OK ! derot freq=%d, mclk=%d", + internal->derot_freq, internal->mclk); + + internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000); + reg = stb0899_read_reg(state, STB0899_PLPARM); + internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg); + dprintk(state->verbose, FE_DEBUG, 1, + "freq=%d, internal resultant freq=%d", + params->freq, internal->freq); + + dprintk(state->verbose, FE_DEBUG, 1, + "internal puncture rate=%d", + internal->fecrate); + } + } + } + } + if (internal->status != RANGEOK) + next_sub_range(state); + + } while (internal->sub_range && internal->status != RANGEOK); + + /* Set the timing loop to tracking */ + stb0899_write_reg(state, STB0899_RTC, 0x33); + stb0899_write_reg(state, STB0899_CFD, 0xf7); + /* if locked and range ok, set Kdiv */ + if (internal->status == RANGEOK) { + dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !"); + stb0899_write_reg(state, STB0899_EQON, 0x41); /* Equalizer OFF while acquiring */ + stb0899_write_reg(state, STB0899_VITSYNC, 0x39); /* SN to b'11 for acquisition */ + + /* + * Carrier loop optimization versus + * symbol Rate/Puncture Rate for Tracking + */ + reg = stb0899_read_reg(state, STB0899_BCLC); + switch (internal->fecrate) { + case STB0899_FEC_1_2: /* 13 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_2_3: /* 18 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 44); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_3_4: /* 21 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 60); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_5_6: /* 24 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 75); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + case STB0899_FEC_6_7: /* 25 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 88); + stb0899_write_reg(state, STB0899_ACLC, 0x88); + stb0899_write_reg(state, STB0899_BCLC, 0x9a); + break; + case STB0899_FEC_7_8: /* 26 */ + stb0899_write_reg(state, STB0899_DEMAPVIT, 94); + STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]); + stb0899_write_reg(state, STB0899_BCLC, reg); + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate"); + break; + } + /* release stream merger RESET */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* disable carrier detector */ + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 0); + stb0899_write_reg(state, STB0899_CFD, reg); + + stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10); + } + + return internal->status; +} + +/* + * stb0899_dvbs2_config_uwp + * Configure UWP state machine + */ +static void stb0899_dvbs2_config_uwp(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + u32 uwp1, uwp2, uwp3, reg; + + uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); + uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2); + uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3); + + STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave); + STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant); + STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof); + + STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse); + STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine); + STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold); + + STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq); + STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO); + STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg); +} + +/* + * stb0899_dvbs2_config_csm_auto + * Set CSM to AUTO mode + */ +static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state) +{ + u32 reg; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg); +} + +long Log2Int(int number) +{ + int i; + + i = 0; + while ((1 << i) <= ABS(number)) + i++; + + if (number == 0) + i = 1; + + return i - 1; +} + +/* + * stb0899_dvbs2_calc_srate + * compute BTR_NOM_FREQ for the symbol rate + */ +static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq; + u32 master_clk, srate; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + decim = 1 << dec_rate; + master_clk = internal->master_clk / 1000; + srate = internal->srate / 1000; + + if (decim <= 4) { + intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk; + remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; + } else { + intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100; + remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk; + } + btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk); + + return btr_nom_freq; +} + +/* + * stb0899_dvbs2_calc_dev + * compute the correction to be applied to symbol rate + */ +static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + u32 dec_ratio, correction, master_clk, srate; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + + master_clk = internal->master_clk / 1000; /* for integer Caculation*/ + srate = internal->srate / 1000; /* for integer Caculation*/ + correction = (512 * master_clk) / (2 * dec_ratio * srate); + + return correction; +} + +/* + * stb0899_dvbs2_set_srate + * Set DVBS2 symbol rate + */ +static void stb0899_dvbs2_set_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + + u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq; + u32 correction, freq_adj, band_lim, decim_cntrl, reg; + u8 anti_alias; + + /*set decimation to 1*/ + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + + win_sel = 0; + if (dec_rate >= 5) + win_sel = dec_rate - 4; + + decim = (1 << dec_rate); + /* (FSamp/Fsymbol *100) for integer Caculation */ + f_sym = internal->master_clk / ((decim * internal->srate) / 1000); + + if (f_sym <= 2250) /* don't band limit signal going into btr block*/ + band_lim = 1; + else + band_lim = 0; /* band limit signal going into btr block*/ + + decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl); + + if (f_sym <= 3450) + anti_alias = 0; + else if (f_sym <= 4250) + anti_alias = 1; + else + anti_alias = 2; + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias); + btr_nom_freq = stb0899_dvbs2_calc_srate(state); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq); + + correction = stb0899_dvbs2_calc_dev(state); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); + STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); + + /* scale UWP+CSM frequency to sample rate*/ + freq_adj = internal->srate / (internal->master_clk / 4096); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj); +} + +/* + * stb0899_dvbs2_set_btr_loopbw + * set bit timing loop bandwidth as a percentage of the symbol rate + */ +static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 sym_peak = 23, zeta = 707, loopbw_percent = 60; + s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft; + s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift; + u32 decim, K, wn, k_direct, k_indirect; + u32 reg; + + dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); + dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; + dec_rate = Log2Int(dec_ratio); + decim = (1 << dec_rate); + + sym_peak *= 576000; + K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000); + K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/ + + if (K != 0) { + K = sym_peak / K; + wn = (4 * zeta * zeta) + 1000000; + wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn; /*wn =wn 10^-8*/ + + k_indirect = (wn * wn) / K; + k_indirect = k_indirect; /*kindirect = kindirect 10^-6*/ + k_direct = (2 * wn * zeta) / K; /*kDirect = kDirect 10^-2*/ + k_direct *= 100; + + k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2; + k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset; + k_btr1 = k_direct / (1 << k_direct_shift); + k_btr1 /= 10000; + + k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/; + k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset; + k_btr0 = k_indirect * (1 << (-k_indirect_shift)); + k_btr0 /= 1000000; + + k_btr2_rshft = 0; + if (k_btr0_rshft > 15) { + k_btr2_rshft = k_btr0_rshft - 15; + k_btr0_rshft = 15; + } + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN); + STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft); + STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0); + STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft); + STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1); + STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg); + } else + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f); +} + +/* + * stb0899_dvbs2_set_carr_freq + * set nominal frequency for carrier search + */ +static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk) +{ + struct stb0899_config *config = state->config; + s32 crl_nom_freq; + u32 reg; + + crl_nom_freq = (1 << config->crl_nco_bits) / master_clk; + crl_nom_freq *= carr_freq; + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); +} + +/* + * stb0899_dvbs2_init_calc + * Initialize DVBS2 UWP, CSM, carrier and timing loops + */ +static void stb0899_dvbs2_init_calc(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + s32 steps, step_size; + u32 range, reg; + + /* config uwp and csm */ + stb0899_dvbs2_config_uwp(state); + stb0899_dvbs2_config_csm_auto(state); + + /* initialize BTR */ + stb0899_dvbs2_set_srate(state); + stb0899_dvbs2_set_btr_loopbw(state); + + if (internal->srate / 1000000 >= 15) + step_size = (1 << 17) / 5; + else if (internal->srate / 1000000 >= 10) + step_size = (1 << 17) / 7; + else if (internal->srate / 1000000 >= 5) + step_size = (1 << 17) / 10; + else + step_size = (1 << 17) / 4; + + range = internal->srch_range / 1000000; + steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000)); + steps = (steps + 6) / 10; + steps = (steps == 0) ? 1 : steps; + if (steps % 2 == 0) + stb0899_dvbs2_set_carr_freq(state, internal->center_freq - + (internal->step_size * (internal->srate / 20000000)), + (internal->master_clk) / 1000000); + else + stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000); + + /*Set Carrier Search params (zigzag, num steps and freq step size*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2); + STB0899_SETFIELD_VAL(ZIGZAG, reg, 1); + STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps); + STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg); +} + +/* + * stb0899_dvbs2_btr_init + * initialize the timing loop + */ +static void stb0899_dvbs2_btr_init(struct stb0899_state *state) +{ + u32 reg; + + /* set enable BTR loopback */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL); + STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1); + STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg); + + /* fix btr freq accum at 0 */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000); + + /* fix btr freq accum at 0 */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000); +} + +/* + * stb0899_dvbs2_reacquire + * trigger a DVB-S2 acquisition + */ +static void stb0899_dvbs2_reacquire(struct stb0899_state *state) +{ + u32 reg = 0; + + /* demod soft reset */ + STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); + + /*Reset Timing Loop */ + stb0899_dvbs2_btr_init(state); + + /* reset Carrier loop */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30)); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30)); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0); + + /*release demod soft reset */ + reg = 0; + STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg); + + /* start acquisition process */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0); + + /* equalizer Init */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1); + + /*Start equilizer */ + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0); + STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0); + STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05); + STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + + /* RESET Packet delineator */ + stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a); +} + +/* + * stb0899_dvbs2_get_dmd_status + * get DVB-S2 Demod LOCK status + */ +static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout) +{ + int time = -10, lock = 0, uwp, csm; + u32 reg; + + do { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS); + dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(IF_AGC_LOCK, reg)) + dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !"); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); + dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg); + uwp = STB0899_GETFIELD(UWP_LOCK, reg); + csm = STB0899_GETFIELD(CSM_LOCK, reg); + if (uwp && csm) + lock = 1; + + time += 10; + msleep(10); + + } while ((!lock) && (time <= timeout)); + + if (lock) { + dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !"); + return DVBS2_DEMOD_LOCK; + } else { + return DVBS2_DEMOD_NOLOCK; + } +} + +/* + * stb0899_dvbs2_get_data_lock + * get FEC status + */ +static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout) +{ + int time = 0, lock = 0; + u8 reg; + + while ((!lock) && (time < timeout)) { + reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); + dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg); + lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg); + time++; + } + + return lock; +} + +/* + * stb0899_dvbs2_get_fec_status + * get DVB-S2 FEC LOCK status + */ +static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout) +{ + int time = 0, Locked; + + do { + Locked = stb0899_dvbs2_get_data_lock(state, 1); + time++; + msleep(1); + + } while ((!Locked) && (time < timeout)); + + if (Locked) { + dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !"); + return DVBS2_FEC_LOCK; + } else { + return DVBS2_FEC_NOLOCK; + } +} + +#if 0 +/* + * stb0899_dvbs2_get_modcod + * get MODCOD + */ +static u32 stb0899_dvbs2_get_modcod(struct stb0899_state *state) +{ + u32 reg; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + return (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2); +} +#endif + +/* + * stb0899_dvbs2_init_csm + * set parameters for manual mode + */ +static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod) +{ + struct stb0899_internal *internal = &state->internal; + + s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80; + s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr; + u32 csm1, csm2, csm3, csm4; + + if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) { + switch (modcod) { + case STB0899_QPSK_12: + gamma_acq = 25; + gamma_rho_acq = 2700; + gamma_trk = 12; + gamma_rho_trk = 180; + lock_count_thr = 8; + break; + case STB0899_QPSK_35: + gamma_acq = 38; + gamma_rho_acq = 7182; + gamma_trk = 14; + gamma_rho_trk = 308; + lock_count_thr = 8; + break; + case STB0899_QPSK_23: + gamma_acq = 42; + gamma_rho_acq = 9408; + gamma_trk = 17; + gamma_rho_trk = 476; + lock_count_thr = 8; + break; + case STB0899_QPSK_34: + gamma_acq = 53; + gamma_rho_acq = 16642; + gamma_trk = 19; + gamma_rho_trk = 646; + lock_count_thr = 8; + break; + case STB0899_QPSK_45: + gamma_acq = 53; + gamma_rho_acq = 17119; + gamma_trk = 22; + gamma_rho_trk = 880; + lock_count_thr = 8; + break; + case STB0899_QPSK_56: + gamma_acq = 55; + gamma_rho_acq = 19250; + gamma_trk = 23; + gamma_rho_trk = 989; + lock_count_thr = 8; + break; + case STB0899_QPSK_89: + gamma_acq = 60; + gamma_rho_acq = 24240; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + case STB0899_QPSK_910: + gamma_acq = 66; + gamma_rho_acq = 29634; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + default: + gamma_acq = 66; + gamma_rho_acq = 29634; + gamma_trk = 24; + gamma_rho_trk = 1176; + lock_count_thr = 8; + break; + } + + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2); + csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3); + csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4); + + STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass); + STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain); + STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift); + STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift); + STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq); + STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq); + STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk); + STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk); + STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr); + STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4); + } +} + +/* + * stb0899_dvbs2_get_srate + * get DVB-S2 Symbol Rate + */ +static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg; + int div1, div2, rem1, rem2; + + div1 = config->btr_nco_bits / 2; + div2 = config->btr_nco_bits - div1 - 1; + + bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL); + decimRate = STB0899_GETFIELD(DECIM_RATE, reg); + decimRate = (1 << decimRate); + + intval1 = internal->master_clk / (1 << div1); + intval2 = bTrNomFreq / (1 << div2); + + rem1 = internal->master_clk % (1 << div1); + rem2 = bTrNomFreq % (1 << div2); + /* only for integer calculation */ + srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1)); + srate /= decimRate; /*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */ + + return srate; +} + +/* + * stb0899_dvbs2_algo + * Search for signal, timing, carrier and data for a given + * frequency in a given range + */ +enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + enum stb0899_modcod modcod; + + s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum; + int i = 0; + u32 reg, csm1; + + if (internal->srate <= 2000000) { + searchTime = 5000; /* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs */ + FecLockTime = 350; /* 350 ms max time to lock FEC, SYMB <= 2Mbs */ + } else if (internal->srate <= 5000000) { + searchTime = 2500; /* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs */ + FecLockTime = 170; /* 170 ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs */ + } else if (internal->srate <= 10000000) { + searchTime = 1500; /* 1500 ms max time to lock UWP and CSM, 5Mbs <SYMB <= 10Mbs */ + FecLockTime = 80; /* 80 ms max time to lock FEC, 5Mbs< SYMB <= 10Mbs */ + } else if (internal->srate <= 15000000) { + searchTime = 500; /* 500 ms max time to lock UWP and CSM, 10Mbs <SYMB <= 15Mbs */ + FecLockTime = 50; /* 50 ms max time to lock FEC, 10Mbs< SYMB <= 15Mbs */ + } else if (internal->srate <= 20000000) { + searchTime = 300; /* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs */ + FecLockTime = 30; /* 50 ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs */ + } else if (internal->srate <= 25000000) { + searchTime = 250; /* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs */ + FecLockTime = 25; /* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ + } else { + searchTime = 150; /* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs */ + FecLockTime = 20; /* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs */ + } + + /* Maintain Stream Merger in reset during acquisition */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + /* Move tuner to frequency */ + if (state->config->tuner_set_frequency) + state->config->tuner_set_frequency(&state->frontend, internal->freq); + if (state->config->tuner_get_frequency) + state->config->tuner_get_frequency(&state->frontend, &internal->freq); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + /* Set IF AGC to acquisition */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 4); + STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); + STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); + + /* Initialisation */ + stb0899_dvbs2_init_calc(state); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + switch (internal->inversion) { + case IQ_SWAP_OFF: + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0); + break; + case IQ_SWAP_ON: + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); + break; + case IQ_SWAP_AUTO: /* use last successful search first */ + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1); + break; + } + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); + stb0899_dvbs2_reacquire(state); + + /* Wait for demod lock (UWP and CSM) */ + internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); + + if (internal->status == DVBS2_DEMOD_LOCK) { + dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !"); + i = 0; + /* Demod Locked, check FEC status */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + + /*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/ + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + /* Read the frequency offset*/ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); + stb0899_dvbs2_reacquire(state); + internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); + i++; + } + } + + if (internal->status != DVBS2_FEC_LOCK) { + if (internal->inversion == IQ_SWAP_AUTO) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg); + /* IQ Spectrum Inversion */ + STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg); + /* start acquistion process */ + stb0899_dvbs2_reacquire(state); + + /* Wait for demod lock (UWP and CSM) */ + internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime); + if (internal->status == DVBS2_DEMOD_LOCK) { + i = 0; + /* Demod Locked, check FEC */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + /*try thrice for false locks, (UWP and CSM Locked but no FEC) */ + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + /* Read the frequency offset*/ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + /* Set the Nominal frequency to the found frequency offset for the next reacquire*/ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ); + STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg); + + stb0899_dvbs2_reacquire(state); + internal->status = stb0899_dvbs2_get_fec_status(state, searchTime); + i++; + } + } +/* + if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED) + pParams->IQLocked = !iqSpectrum; +*/ + } + } + if (internal->status == DVBS2_FEC_LOCK) { + dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !"); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; + pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; + + if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && + (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) && + (pilots == 1)) { + + stb0899_dvbs2_init_csm(state, pilots, modcod); + /* Wait for UWP,CSM and data LOCK 20ms max */ + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + + i = 0; + while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) { + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1); + STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1); + + internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime); + i++; + } + } + + if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) && + (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) && + (pilots == 1)) { + + /* Equalizer Disable update */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + } + + /* slow down the Equalizer once locked */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL); + STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg); + + /* Store signal parameters */ + offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); + + offsetfreq = offsetfreq / ((1 << 30) / 1000); + offsetfreq *= (internal->master_clk / 1000000); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2); + if (STB0899_GETFIELD(SPECTRUM_INVERT, reg)) + offsetfreq *= -1; + + internal->freq = internal->freq - offsetfreq; + internal->srate = stb0899_dvbs2_get_srate(state); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2; + internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01; + internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01; + + /* Set IF AGC to tracking */ + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg, 3); + + /* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/ + if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23)) + STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16); + + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2); + STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg); + } + + /* Release Stream Merger Reset */ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESRS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + return internal->status; +} diff --git a/linux/drivers/media/dvb/frontends/stb0899_cfg.h b/linux/drivers/media/dvb/frontends/stb0899_cfg.h new file mode 100644 index 000000000..1c860e469 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb0899_cfg.h @@ -0,0 +1,421 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_CFG_H +#define __STB0899_CFG_H + +static const struct stb0899_s2_reg stb0899_s2_init_2[] = { + + { STB0899_OFF0_DMD_STATUS , STB0899_BASE_DMD_STATUS , 0x00000103 }, /* DMDSTATUS */ + { STB0899_OFF0_CRL_FREQ , STB0899_BASE_CRL_FREQ , 0x3ed1da56 }, /* CRLFREQ */ + { STB0899_OFF0_BTR_FREQ , STB0899_BASE_BTR_FREQ , 0x00004000 }, /* BTRFREQ */ + { STB0899_OFF0_IF_AGC_GAIN , STB0899_BASE_IF_AGC_GAIN , 0x00002ade }, /* IFAGCGAIN */ + { STB0899_OFF0_BB_AGC_GAIN , STB0899_BASE_BB_AGC_GAIN , 0x000001bc }, /* BBAGCGAIN */ + { STB0899_OFF0_DC_OFFSET , STB0899_BASE_DC_OFFSET , 0x00000200 }, /* DCOFFSET */ + { STB0899_OFF0_DMD_CNTRL , STB0899_BASE_DMD_CNTRL , 0x0000000f }, /* DMDCNTRL */ + + { STB0899_OFF0_IF_AGC_CNTRL , STB0899_BASE_IF_AGC_CNTRL , 0x03fb4a20 }, /* IFAGCCNTRL */ + { STB0899_OFF0_BB_AGC_CNTRL , STB0899_BASE_BB_AGC_CNTRL , 0x00200c97 }, /* BBAGCCNTRL */ + + { STB0899_OFF0_CRL_CNTRL , STB0899_BASE_CRL_CNTRL , 0x00000016 }, /* CRLCNTRL */ + { STB0899_OFF0_CRL_PHS_INIT , STB0899_BASE_CRL_PHS_INIT , 0x00000000 }, /* CRLPHSINIT */ + { STB0899_OFF0_CRL_FREQ_INIT , STB0899_BASE_CRL_FREQ_INIT , 0x00000000 }, /* CRLFREQINIT */ + { STB0899_OFF0_CRL_LOOP_GAIN , STB0899_BASE_CRL_LOOP_GAIN , 0x00000000 }, /* CRLLOOPGAIN */ + { STB0899_OFF0_CRL_NOM_FREQ , STB0899_BASE_CRL_NOM_FREQ , 0x3ed097b6 }, /* CRLNOMFREQ */ + { STB0899_OFF0_CRL_SWP_RATE , STB0899_BASE_CRL_SWP_RATE , 0x00000000 }, /* CRLSWPRATE */ + { STB0899_OFF0_CRL_MAX_SWP , STB0899_BASE_CRL_MAX_SWP , 0x00000000 }, /* CRLMAXSWP */ + { STB0899_OFF0_CRL_LK_CNTRL , STB0899_BASE_CRL_LK_CNTRL , 0x0f6cdc01 }, /* CRLLKCNTRL */ + { STB0899_OFF0_DECIM_CNTRL , STB0899_BASE_DECIM_CNTRL , 0x00000000 }, /* DECIMCNTRL */ + { STB0899_OFF0_BTR_CNTRL , STB0899_BASE_BTR_CNTRL , 0x00003993 }, /* BTRCNTRL */ + { STB0899_OFF0_BTR_LOOP_GAIN , STB0899_BASE_BTR_LOOP_GAIN , 0x000d3c6f }, /* BTRLOOPGAIN */ + { STB0899_OFF0_BTR_PHS_INIT , STB0899_BASE_BTR_PHS_INIT , 0x00000000 }, /* BTRPHSINIT */ + { STB0899_OFF0_BTR_FREQ_INIT , STB0899_BASE_BTR_FREQ_INIT , 0x00000000 }, /* BTRFREQINIT */ + { STB0899_OFF0_BTR_NOM_FREQ , STB0899_BASE_BTR_NOM_FREQ , 0x0238e38e }, /* BTRNOMFREQ */ + { STB0899_OFF0_BTR_LK_CNTRL , STB0899_BASE_BTR_LK_CNTRL , 0x00000000 }, /* BTRLKCNTRL */ + { STB0899_OFF0_DECN_CNTRL , STB0899_BASE_DECN_CNTRL , 0x00000000 }, /* DECNCNTRL */ + { STB0899_OFF0_TP_CNTRL , STB0899_BASE_TP_CNTRL , 0x00000000 }, /* TPCNTRL */ + { STB0899_OFF0_TP_BUF_STATUS , STB0899_BASE_TP_BUF_STATUS , 0x00000000 }, /* TPBUFSTATUS */ + { STB0899_OFF0_DC_ESTIM , STB0899_BASE_DC_ESTIM , 0x00000000 }, /* DCESTIM */ + { STB0899_OFF0_FLL_CNTRL , STB0899_BASE_FLL_CNTRL , 0x00000000 }, /* FLLCNTRL */ + { STB0899_OFF0_FLL_FREQ_WD , STB0899_BASE_FLL_FREQ_WD , 0x40070000 }, /* FLLFREQWD */ + { STB0899_OFF0_ANTI_ALIAS_SEL , STB0899_BASE_ANTI_ALIAS_SEL , 0x00000001 }, /* ANTIALIASSEL */ + { STB0899_OFF0_RRC_ALPHA , STB0899_BASE_RRC_ALPHA , 0x00000002 }, /* RRCALPHA */ + { STB0899_OFF0_DC_ADAPT_LSHFT , STB0899_BASE_DC_ADAPT_LSHFT , 0x00000000 }, /* DCADAPTISHFT */ + { STB0899_OFF0_IMB_OFFSET , STB0899_BASE_IMB_OFFSET , 0x0000fe01 }, /* IMBOFFSET */ + { STB0899_OFF0_IMB_ESTIMATE , STB0899_BASE_IMB_ESTIMATE , 0x00000000 }, /* IMBESTIMATE */ + { STB0899_OFF0_IMB_CNTRL , STB0899_BASE_IMB_CNTRL , 0x00000001 }, /* IMBCNTRL */ + { STB0899_OFF0_IF_AGC_CNTRL2 , STB0899_BASE_IF_AGC_CNTRL2 , 0x00005007 }, /* IFAGCCNTRL2 */ + { STB0899_OFF0_DMD_CNTRL2 , STB0899_BASE_DMD_CNTRL2 , 0x00000002 }, /* DMDCNTRL2 */ + { STB0899_OFF0_TP_BUFFER , STB0899_BASE_TP_BUFFER , 0x00000000 }, /* TPBUFFER */ + { STB0899_OFF0_TP_BUFFER1 , STB0899_BASE_TP_BUFFER1 , 0x00000000 }, /* TPBUFFER1 */ + { STB0899_OFF0_TP_BUFFER2 , STB0899_BASE_TP_BUFFER2 , 0x00000000 }, /* TPBUFFER2 */ + { STB0899_OFF0_TP_BUFFER3 , STB0899_BASE_TP_BUFFER3 , 0x00000000 }, /* TPBUFFER3 */ + { STB0899_OFF0_TP_BUFFER4 , STB0899_BASE_TP_BUFFER4 , 0x00000000 }, /* TPBUFFER4 */ + { STB0899_OFF0_TP_BUFFER5 , STB0899_BASE_TP_BUFFER5 , 0x00000000 }, /* TPBUFFER5 */ + { STB0899_OFF0_TP_BUFFER6 , STB0899_BASE_TP_BUFFER6 , 0x00000000 }, /* TPBUFFER6 */ + { STB0899_OFF0_TP_BUFFER7 , STB0899_BASE_TP_BUFFER7 , 0x00000000 }, /* TPBUFFER7 */ + { STB0899_OFF0_TP_BUFFER8 , STB0899_BASE_TP_BUFFER8 , 0x00000000 }, /* TPBUFFER8 */ + { STB0899_OFF0_TP_BUFFER9 , STB0899_BASE_TP_BUFFER9 , 0x00000000 }, /* TPBUFFER9 */ + { STB0899_OFF0_TP_BUFFER10 , STB0899_BASE_TP_BUFFER10 , 0x00000000 }, /* TPBUFFER10 */ + { STB0899_OFF0_TP_BUFFER11 , STB0899_BASE_TP_BUFFER11 , 0x00000000 }, /* TPBUFFER11 */ + { STB0899_OFF0_TP_BUFFER12 , STB0899_BASE_TP_BUFFER12 , 0x00000000 }, /* TPBUFFER12 */ + { STB0899_OFF0_TP_BUFFER13 , STB0899_BASE_TP_BUFFER13 , 0x00000000 }, /* TPBUFFER13 */ + { STB0899_OFF0_TP_BUFFER14 , STB0899_BASE_TP_BUFFER14 , 0x00000000 }, /* TPBUFFER14 */ + { STB0899_OFF0_TP_BUFFER15 , STB0899_BASE_TP_BUFFER15 , 0x00000000 }, /* TPBUFFER15 */ + { STB0899_OFF0_TP_BUFFER16 , STB0899_BASE_TP_BUFFER16 , 0x0000ff00 }, /* TPBUFFER16 */ + { STB0899_OFF0_TP_BUFFER17 , STB0899_BASE_TP_BUFFER17 , 0x00000100 }, /* TPBUFFER17 */ + { STB0899_OFF0_TP_BUFFER18 , STB0899_BASE_TP_BUFFER18 , 0x0000fe01 }, /* TPBUFFER18 */ + { STB0899_OFF0_TP_BUFFER19 , STB0899_BASE_TP_BUFFER19 , 0x000004fe }, /* TPBUFFER19 */ + { STB0899_OFF0_TP_BUFFER20 , STB0899_BASE_TP_BUFFER20 , 0x0000cfe7 }, /* TPBUFFER20 */ + { STB0899_OFF0_TP_BUFFER21 , STB0899_BASE_TP_BUFFER21 , 0x0000bec6 }, /* TPBUFFER21 */ + { STB0899_OFF0_TP_BUFFER22 , STB0899_BASE_TP_BUFFER22 , 0x0000c2bf }, /* TPBUFFER22 */ + { STB0899_OFF0_TP_BUFFER23 , STB0899_BASE_TP_BUFFER23 , 0x0000c1c1 }, /* TPBUFFER23 */ + { STB0899_OFF0_TP_BUFFER24 , STB0899_BASE_TP_BUFFER24 , 0x0000c1c1 }, /* TPBUFFER24 */ + { STB0899_OFF0_TP_BUFFER25 , STB0899_BASE_TP_BUFFER25 , 0x0000c1c1 }, /* TPBUFFER25 */ + { STB0899_OFF0_TP_BUFFER26 , STB0899_BASE_TP_BUFFER26 , 0x0000c1c1 }, /* TPBUFFER26 */ + { STB0899_OFF0_TP_BUFFER27 , STB0899_BASE_TP_BUFFER27 , 0x0000c1c0 }, /* TPBUFFER27 */ + { STB0899_OFF0_TP_BUFFER28 , STB0899_BASE_TP_BUFFER28 , 0x0000c0c0 }, /* TPBUFFER28 */ + { STB0899_OFF0_TP_BUFFER29 , STB0899_BASE_TP_BUFFER29 , 0x0000c1c1 }, /* TPBUFFER29 */ + { STB0899_OFF0_TP_BUFFER30 , STB0899_BASE_TP_BUFFER30 , 0x0000c1c1 }, /* TPBUFFER30 */ + { STB0899_OFF0_TP_BUFFER31 , STB0899_BASE_TP_BUFFER31 , 0x0000c0c1 }, /* TPBUFFER31 */ + { STB0899_OFF0_TP_BUFFER32 , STB0899_BASE_TP_BUFFER32 , 0x0000c0c1 }, /* TPBUFFER32 */ + { STB0899_OFF0_TP_BUFFER33 , STB0899_BASE_TP_BUFFER33 , 0x0000c1c1 }, /* TPBUFFER33 */ + { STB0899_OFF0_TP_BUFFER34 , STB0899_BASE_TP_BUFFER34 , 0x0000c1c1 }, /* TPBUFFER34 */ + { STB0899_OFF0_TP_BUFFER35 , STB0899_BASE_TP_BUFFER35 , 0x0000c0c1 }, /* TPBUFFER35 */ + { STB0899_OFF0_TP_BUFFER36 , STB0899_BASE_TP_BUFFER36 , 0x0000c1c1 }, /* TPBUFFER36 */ + { STB0899_OFF0_TP_BUFFER37 , STB0899_BASE_TP_BUFFER37 , 0x0000c0c1 }, /* TPBUFFER37 */ + { STB0899_OFF0_TP_BUFFER38 , STB0899_BASE_TP_BUFFER38 , 0x0000c1c1 }, /* TPBUFFER38 */ + { STB0899_OFF0_TP_BUFFER39 , STB0899_BASE_TP_BUFFER39 , 0x0000c0c0 }, /* TPBUFFER39 */ + { STB0899_OFF0_TP_BUFFER40 , STB0899_BASE_TP_BUFFER40 , 0x0000c1c0 }, /* TPBUFFER40 */ + { STB0899_OFF0_TP_BUFFER41 , STB0899_BASE_TP_BUFFER41 , 0x0000c1c1 }, /* TPBUFFER41 */ + { STB0899_OFF0_TP_BUFFER42 , STB0899_BASE_TP_BUFFER42 , 0x0000c0c0 }, /* TPBUFFER42 */ + { STB0899_OFF0_TP_BUFFER43 , STB0899_BASE_TP_BUFFER43 , 0x0000c1c0 }, /* TPBUFFER43 */ + { STB0899_OFF0_TP_BUFFER44 , STB0899_BASE_TP_BUFFER44 , 0x0000c0c1 }, /* TPBUFFER44 */ + { STB0899_OFF0_TP_BUFFER45 , STB0899_BASE_TP_BUFFER45 , 0x0000c1be }, /* TPBUFFER45 */ + { STB0899_OFF0_TP_BUFFER46 , STB0899_BASE_TP_BUFFER46 , 0x0000c1c9 }, /* TPBUFFER46 */ + { STB0899_OFF0_TP_BUFFER47 , STB0899_BASE_TP_BUFFER47 , 0x0000c0da }, /* TPBUFFER47 */ + { STB0899_OFF0_TP_BUFFER48 , STB0899_BASE_TP_BUFFER48 , 0x0000c0ba }, /* TPBUFFER48 */ + { STB0899_OFF0_TP_BUFFER49 , STB0899_BASE_TP_BUFFER49 , 0x0000c1c4 }, /* TPBUFFER49 */ + { STB0899_OFF0_TP_BUFFER50 , STB0899_BASE_TP_BUFFER50 , 0x0000c1bf }, /* TPBUFFER50 */ + { STB0899_OFF0_TP_BUFFER51 , STB0899_BASE_TP_BUFFER51 , 0x0000c0c1 }, /* TPBUFFER51 */ + { STB0899_OFF0_TP_BUFFER52 , STB0899_BASE_TP_BUFFER52 , 0x0000c1c0 }, /* TPBUFFER52 */ + { STB0899_OFF0_TP_BUFFER53 , STB0899_BASE_TP_BUFFER53 , 0x0000c0c1 }, /* TPBUFFER53 */ + { STB0899_OFF0_TP_BUFFER54 , STB0899_BASE_TP_BUFFER54 , 0x0000c1c1 }, /* TPBUFFER54 */ + { STB0899_OFF0_TP_BUFFER55 , STB0899_BASE_TP_BUFFER55 , 0x0000c1c1 }, /* TPBUFFER55 */ + { STB0899_OFF0_TP_BUFFER56 , STB0899_BASE_TP_BUFFER56 , 0x0000c1c1 }, /* TPBUFFER56 */ + { STB0899_OFF0_TP_BUFFER57 , STB0899_BASE_TP_BUFFER57 , 0x0000c1c1 }, /* TPBUFFER57 */ + { STB0899_OFF0_TP_BUFFER58 , STB0899_BASE_TP_BUFFER58 , 0x0000c1c1 }, /* TPBUFFER58 */ + { STB0899_OFF0_TP_BUFFER59 , STB0899_BASE_TP_BUFFER59 , 0x0000c1c1 }, /* TPBUFFER59 */ + { STB0899_OFF0_TP_BUFFER60 , STB0899_BASE_TP_BUFFER60 , 0x0000c1c1 }, /* TPBUFFER60 */ + { STB0899_OFF0_TP_BUFFER61 , STB0899_BASE_TP_BUFFER61 , 0x0000c1c1 }, /* TPBUFFER61 */ + { STB0899_OFF0_TP_BUFFER62 , STB0899_BASE_TP_BUFFER62 , 0x0000c1c1 }, /* TPBUFFER62 */ + { STB0899_OFF0_TP_BUFFER63 , STB0899_BASE_TP_BUFFER63 , 0x0000c1c0 }, /* TPBUFFER63 */ + { STB0899_OFF0_RESET_CNTRL , STB0899_BASE_RESET_CNTRL , 0x00000001 }, /* RESETCNTRL */ + { STB0899_OFF0_ACM_ENABLE , STB0899_BASE_ACM_ENABLE , 0x00005654 }, /* ACMENABLE */ + { STB0899_OFF0_DESCR_CNTRL , STB0899_BASE_DESCR_CNTRL , 0x00000000 }, /* DESCRCNTRL */ + { STB0899_OFF0_CSM_CNTRL1 , STB0899_BASE_CSM_CNTRL1 , 0x00020019 }, /* CSMCNTRL1 */ + { STB0899_OFF0_CSM_CNTRL2 , STB0899_BASE_CSM_CNTRL2 , 0x004b3237 }, /* CSMCNTRL2 */ + { STB0899_OFF0_CSM_CNTRL3 , STB0899_BASE_CSM_CNTRL3 , 0x0003dd17 }, /* CSMCNTRL3 */ + { STB0899_OFF0_CSM_CNTRL4 , STB0899_BASE_CSM_CNTRL4 , 0x00008008 }, /* CSMCNTRL4 */ + { STB0899_OFF0_UWP_CNTRL1 , STB0899_BASE_UWP_CNTRL1 , 0x002a3106 }, /* UWPCNTRL1 */ + { STB0899_OFF0_UWP_CNTRL2 , STB0899_BASE_UWP_CNTRL2 , 0x0006140a }, /* UWPCNTRL2 */ + { STB0899_OFF0_UWP_STAT1 , STB0899_BASE_UWP_STAT1 , 0x00008000 }, /* UWPSTAT1 */ + { STB0899_OFF0_UWP_STAT2 , STB0899_BASE_UWP_STAT2 , 0x00000000 }, /* UWPSTAT2 */ + { STB0899_OFF0_DMD_STAT2 , STB0899_BASE_DMD_STAT2 , 0x00000000 }, /* DMDSTAT2 */ + { STB0899_OFF0_FREQ_ADJ_SCALE , STB0899_BASE_FREQ_ADJ_SCALE , 0x00000471 }, /* FREQADJSCALE */ + { STB0899_OFF0_UWP_CNTRL3 , STB0899_BASE_UWP_CNTRL3 , 0x017b0465 }, /* UWPCNTRL3 */ + { STB0899_OFF0_SYM_CLK_SEL , STB0899_BASE_SYM_CLK_SEL , 0x00000002 }, /* SYMCLKSEL */ + { STB0899_OFF0_SOF_SRCH_TO , STB0899_BASE_SOF_SRCH_TO , 0x00196464 }, /* SOFSRCHTO */ + { STB0899_OFF0_ACQ_CNTRL1 , STB0899_BASE_ACQ_CNTRL1 , 0x00000603 }, /* ACQCNTRL1 */ + { STB0899_OFF0_ACQ_CNTRL2 , STB0899_BASE_ACQ_CNTRL2 , 0x02046666 }, /* ACQCNTRL2 */ + { STB0899_OFF0_ACQ_CNTRL3 , STB0899_BASE_ACQ_CNTRL3 , 0x10046583 }, /* ACQCNTRL3 */ + { STB0899_OFF0_FE_SETTLE , STB0899_BASE_FE_SETTLE , 0x00010404 }, /* FESETTLE */ + { STB0899_OFF0_AC_DWELL , STB0899_BASE_AC_DWELL , 0x0002aa8a }, /* ACDWELL */ + { STB0899_OFF0_ACQUIRE_TRIG , STB0899_BASE_ACQUIRE_TRIG , 0x00000000 }, /* ACQUIRETRIG */ + { STB0899_OFF0_LOCK_LOST , STB0899_BASE_LOCK_LOST , 0x00000001 }, /* LOCKLOST */ + { STB0899_OFF0_ACQ_STAT1 , STB0899_BASE_ACQ_STAT1 , 0x00000500 }, /* ACQSTAT1 */ + { STB0899_OFF0_ACQ_TIMEOUT , STB0899_BASE_ACQ_TIMEOUT , 0x0028a0a0 }, /* ACQTIMEOUT */ + { STB0899_OFF0_ACQ_TIME , STB0899_BASE_ACQ_TIME , 0x00000000 }, /* ACQTIME */ + { STB0899_OFF0_FINAL_AGC_CNTRL , STB0899_BASE_FINAL_AGC_CNTRL , 0x00800c17 }, /* FINALAGCCNTRL*/ + { STB0899_OFF0_FINAL_AGC_GAIN , STB0899_BASE_FINAL_AGC_GAIN , 0x00000000 }, /* FINALAGCCGAIN*/ + { STB0899_OFF0_EQUALIZER_INIT , STB0899_BASE_EQUALIZER_INIT , 0x00000000 }, /* EQUILIZERINIT*/ + { STB0899_OFF0_EQ_CNTRL , STB0899_BASE_EQ_CNTRL , 0x00054802 }, /* EQCNTL */ + { STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */ + { STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */ + { STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */ + { STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */ + { STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */ + { STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */ + { STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */ + { STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */ + { STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */ + { STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */ + { STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/ + { STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */ + { STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */ + { STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */ + { STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */ + { STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */ + { STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */ + { STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */ + { STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */ + { STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */ + { STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */ + { STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/ + { STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */ + { STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */ + { STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */ + { STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */ + { STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */ + { STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */ + { STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */ + { STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */ + { STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */ + { STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */ + { STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT10*/ + { STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */ + { STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */ + { STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */ + { STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */ + { STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */ + { STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */ + { STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */ + { STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */ + { STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */ + { STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */ + { STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/ + { 0xffff , 0xffffffff , 0xffffffff }, +}; +#if 0 +static const struct stb0899_s1_reg stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x01 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x23 }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xf7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xf1 }, + { STB0899_LDT2 , 0xe3 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfd }, + { STB0899_QDCCOMP , 0xff }, + { STB0899_POWERI , 0x0c }, + { STB0899_POWERQ , 0x0f }, + { STB0899_RCOMP , 0x6c }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x06 }, + { STB0899_AGC2I2 , 0x00 }, + { STB0899_TLIR , 0x30 }, + { STB0899_RTF , 0x7f }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xbc }, + { STB0899_CFRM , 0xea }, + { STB0899_CFRL , 0x31 }, + { STB0899_NIRM , 0x2b }, + { STB0899_NIRL , 0x80 }, + { STB0899_ISYMB , 0x1d }, + { STB0899_QSYMB , 0xa6 }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0x02 }, + { STB0899_EQUAQ1 , 0xff }, + { STB0899_EQUAI2 , 0x04 }, + { STB0899_EQUAQ2 , 0x05 }, + { STB0899_EQUAI3 , 0x02 }, + { STB0899_EQUAQ3 , 0xfd }, + { STB0899_EQUAI4 , 0x03 }, + { STB0899_EQUAQ4 , 0x07 }, + { STB0899_EQUAI5 , 0x08 }, + { STB0899_EQUAQ5 , 0xf5 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0x86 }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x0a }, + { STB0899_ECNT3L , 0xad }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xb0 }, + { STB0899_VTH23 , 0x7a }, + { STB0899_VTH34 , 0x58 }, + { STB0899_VTH56 , 0x38 }, + { STB0899_VTH67 , 0x34 }, + { STB0899_VTH78 , 0x24 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x41 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x00 }, + { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x1b }, + { STB0899_TSLLSTKL , 0xb3 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0x00 }, + { STB0899_PCKLENUL , 0xbc }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xbd }, + { STB0899_TSSTATUS , 0x90 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x95 }, + { STB0899_ERRCTRL3 , 0x8d }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x19 }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0xf0 }, + { STB0899_MATSTRL , 0x02 }, + { STB0899_UPLSTRM , 0x45 }, + { STB0899_UPLSTRL , 0x60 }, + { STB0899_DFLSTRM , 0xe3 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x47 }, + { STB0899_SYNCDSTRM , 0x05 }, + { STB0899_SYNCDSTRL , 0x18 }, + { STB0899_CFGPDELSTATUS1 , 0x19 }, + { STB0899_CFGPDELSTATUS2 , 0x2b }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x01 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; +#endif +static const struct stb0899_s2_reg stb0899_s2_init_4[] = { + { STB0899_OFF0_BLOCK_LNGTH , STB0899_BASE_BLOCK_LNGTH , 0x00000008 }, /* BLOCKLNGTH */ + { STB0899_OFF0_ROW_STR , STB0899_BASE_ROW_STR , 0x000000b4 }, /* ROWSTR */ + { STB0899_OFF0_BN_END_ADDR , STB0899_BASE_BN_END_ADDR , 0x000004b5 }, /* BNANDADDR */ + { STB0899_OFF0_CN_END_ADDR , STB0899_BASE_CN_END_ADDR , 0x00000b4b }, /* CNANDADDR */ + { STB0899_OFF0_INFO_LENGTH , STB0899_BASE_INFO_LENGTH , 0x00000078 }, /* INFOLENGTH */ + { STB0899_OFF0_BOT_ADDR , STB0899_BASE_BOT_ADDR , 0x000001e0 }, /* BOT_ADDR */ + { STB0899_OFF0_BCH_BLK_LN , STB0899_BASE_BCH_BLK_LN , 0x0000a8c0 }, /* BCHBLKLN */ + { STB0899_OFF0_BCH_T , STB0899_BASE_BCH_T , 0x0000000c }, /* BCHT */ + { STB0899_OFF0_CNFG_MODE , STB0899_BASE_CNFG_MODE , 0x00000001 }, /* CNFGMODE */ + { STB0899_OFF0_LDPC_STAT , STB0899_BASE_LDPC_STAT , 0x0000000d }, /* LDPCSTAT */ + { STB0899_OFF0_ITER_SCALE , STB0899_BASE_ITER_SCALE , 0x00000040 }, /* ITERSCALE */ + { STB0899_OFF0_INPUT_MODE , STB0899_BASE_INPUT_MODE , 0x00000000 }, /* INPUTMODE */ + { STB0899_OFF0_LDPCDECRST , STB0899_BASE_LDPCDECRST , 0x00000000 }, /* LDPCDECRST */ + { STB0899_OFF0_CLK_PER_BYTE_RW , STB0899_BASE_CLK_PER_BYTE_RW , 0x00000008 }, /* CLKPERBYTE */ + { STB0899_OFF0_BCH_ERRORS , STB0899_BASE_BCH_ERRORS , 0x00000000 }, /* BCHERRORS */ + { STB0899_OFF0_LDPC_ERRORS , STB0899_BASE_LDPC_ERRORS , 0x00000000 }, /* LDPCERRORS */ + { STB0899_OFF0_BCH_MODE , STB0899_BASE_BCH_MODE , 0x00000000 }, /* BCHMODE */ + { STB0899_OFF0_ERR_ACC_PER , STB0899_BASE_ERR_ACC_PER , 0x00000008 }, /* ERRACCPER */ + { STB0899_OFF0_BCH_ERR_ACC , STB0899_BASE_BCH_ERR_ACC , 0x00000000 }, /* BCHERRACC */ + { STB0899_OFF0_FEC_TP_SEL , STB0899_BASE_FEC_TP_SEL , 0x00000000 }, /* FECTPSEL */ + { 0xffff , 0xffffffff , 0xffffffff }, +}; + +static const struct stb0899_s1_reg stb0899_s1_init_5[] = { + { STB0899_TSTCK , 0x00 }, + { STB0899_TSTRES , 0x00 }, + { STB0899_TSTOUT , 0x00 }, + { STB0899_TSTIN , 0x00 }, + { STB0899_TSTSYS , 0x00 }, + { STB0899_TSTCHIP , 0x00 }, + { STB0899_TSTFREE , 0x00 }, + { STB0899_TSTI2C , 0x00 }, + { STB0899_BITSPEEDM , 0x00 }, + { STB0899_BITSPEEDL , 0x00 }, + { STB0899_TBUSBIT , 0x00 }, + { STB0899_TSTDIS , 0x00 }, + { STB0899_TSTDISRX , 0x00 }, + { STB0899_TSTJETON , 0x00 }, + { STB0899_TSTDCADJ , 0x00 }, + { STB0899_TSTAGC1 , 0x00 }, + { STB0899_TSTAGC1N , 0x00 }, + { STB0899_TSTPOLYPH , 0x00 }, + { STB0899_TSTR , 0x00 }, + { STB0899_TSTAGC2 , 0x00 }, + { STB0899_TSTCTL1 , 0x00 }, + { STB0899_TSTCTL2 , 0x00 }, + { STB0899_TSTCTL3 , 0x00 }, + { STB0899_TSTDEMAP , 0x00 }, + { STB0899_TSTDEMAP2 , 0x00 }, + { STB0899_TSTDEMMON , 0x00 }, + { STB0899_TSTRATE , 0x00 }, + { STB0899_TSTSELOUT , 0x00 }, + { STB0899_TSYNC , 0x00 }, + { STB0899_TSTERR , 0x00 }, + { STB0899_TSTRAM1 , 0x00 }, + { STB0899_TSTVSELOUT , 0x00 }, + { STB0899_TSTFORCEIN , 0x00 }, + { STB0899_TSTRS1 , 0x00 }, + { STB0899_TSTRS2 , 0x00 }, + { STB0899_TSTRS3 , 0x00 }, + { STB0899_GHOSTREG , 0x81 }, + { 0xffff , 0xff }, +}; + +#define STB0899_DVBS2_ESNO_AVE 3 +#define STB0899_DVBS2_ESNO_QUANT 32 +#define STB0899_DVBS2_AVFRAMES_COARSE 10 +#define STB0899_DVBS2_AVFRAMES_FINE 20 +#define STB0899_DVBS2_MISS_THRESHOLD 6 +#define STB0899_DVBS2_UWP_THRESHOLD_ACQ 1125 +#define STB0899_DVBS2_UWP_THRESHOLD_TRACK 758 +#define STB0899_DVBS2_UWP_THRESHOLD_SOF 1350 +#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT 1664100 + +#define STB0899_DVBS2_BTR_NCO_BITS 28 +#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET 15 +#define STB0899_DVBS2_CRL_NCO_BITS 30 +#define STB0899_DVBS2_LDPC_MAX_ITER 70 + +#endif //__STB0899_CFG_H diff --git a/linux/drivers/media/dvb/frontends/stb0899_drv.c b/linux/drivers/media/dvb/frontends/stb0899_drv.c new file mode 100644 index 000000000..63c547f31 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb0899_drv.c @@ -0,0 +1,1979 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> + +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + +#include "stb0899_drv.h" +#include "stb0899_priv.h" +#include "stb0899_reg.h" + +static unsigned int verbose = 0;//1; +module_param(verbose, int, 0644); + +/* C/N in dB/10, NIRM/NIRL */ +static const struct stb0899_tab stb0899_cn_tab[] = { + { 200, 2600 }, + { 190, 2700 }, + { 180, 2860 }, + { 170, 3020 }, + { 160, 3210 }, + { 150, 3440 }, + { 140, 3710 }, + { 130, 4010 }, + { 120, 4360 }, + { 110, 4740 }, + { 100, 5190 }, + { 90, 5670 }, + { 80, 6200 }, + { 70, 6770 }, + { 60, 7360 }, + { 50, 7970 }, + { 40, 8250 }, + { 30, 9000 }, + { 20, 9450 }, + { 15, 9600 }, +}; + +/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10. + * As measured, connected to a modulator. + * -8.0 to -50.0 dBm directly connected, + * -52.0 to -74.8 with extra attenuation. + * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm. + * Crude linear extrapolation below -84.8dBm and above -8.0dBm. + */ +static const struct stb0899_tab stb0899_dvbsrf_tab[] = { + { -950, -128 }, + { -748, -94 }, + { -745, -92 }, + { -735, -90 }, + { -720, -87 }, + { -670, -77 }, + { -640, -70 }, + { -610, -62 }, + { -600, -60 }, + { -590, -56 }, + { -560, -41 }, + { -540, -25 }, + { -530, -17 }, + { -520, -11 }, + { -500, 1 }, + { -490, 6 }, + { -480, 10 }, + { -440, 22 }, + { -420, 27 }, + { -400, 31 }, + { -380, 34 }, + { -340, 40 }, + { -320, 43 }, + { -280, 48 }, + { -250, 52 }, + { -230, 55 }, + { -180, 61 }, + { -140, 66 }, + { -90, 73 }, + { -80, 74 }, + { 500, 127 } +}; + +/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10. + * As measured, connected to a modulator. + * -8.0 to -50.1 dBm directly connected, + * -53.0 to -76.6 with extra attenuation. + * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm. + * Crude linear extrapolation below -76.6dBm and above -8.0dBm. + */ +static const struct stb0899_tab stb0899_dvbs2rf_tab[] = { + { 700, 0 }, + { -80, 3217 }, + { -150, 3893 }, + { -190, 4217 }, + { -240, 4621 }, + { -280, 4945 }, + { -320, 5273 }, + { -350, 5545 }, + { -370, 5741 }, + { -410, 6147 }, + { -450, 6671 }, + { -490, 7413 }, + { -501, 7665 }, + { -530, 8767 }, + { -560, 10219 }, + { -580, 10939 }, + { -590, 11518 }, + { -600, 11723 }, + { -650, 12659 }, + { -690, 13219 }, + { -730, 13645 }, + { -750, 13909 }, + { -766, 14153 }, + { -999, 16383 } +}; + +/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/ +struct stb0899_tab stb0899_quant_tab[] = { + { 0, 0 }, + { 0, 100 }, + { 600, 200 }, + { 950, 299 }, + { 1200, 398 }, + { 1400, 501 }, + { 1560, 603 }, + { 1690, 700 }, + { 1810, 804 }, + { 1910, 902 }, + { 2000, 1000 }, + { 2080, 1096 }, + { 2160, 1202 }, + { 2230, 1303 }, + { 2350, 1496 }, + { 2410, 1603 }, + { 2460, 1698 }, + { 2510, 1799 }, + { 2600, 1995 }, + { 2650, 2113 }, + { 2690, 2213 }, + { 2720, 2291 }, + { 2760, 2399 }, + { 2800, 2512 }, + { 2860, 2692 }, + { 2930, 2917 }, + { 2960, 3020 }, + { 3010, 3199 }, + { 3040, 3311 }, + { 3060, 3388 }, + { 3120, 3631 }, + { 3190, 3936 }, + { 3400, 5012 }, + { 3610, 6383 }, + { 3800, 7943 }, + { 4210, 12735 }, + { 4500, 17783 }, + { 4690, 22131 }, + { 4810, 25410 } +}; + +/* DVB-S2 Es/N0 estimate in dB/100 vs read value */ +struct stb0899_tab stb0899_est_tab[] = { + { 0, 0 }, + { 0, 1 }, + { 301, 2 }, + { 1204, 16 }, + { 1806, 64 }, + { 2408, 256 }, + { 2709, 512 }, + { 3010, 1023 }, + { 3311, 2046 }, + { 3612, 4093 }, + { 3823, 6653 }, + { 3913, 8185 }, + { 4010, 10233 }, + { 4107, 12794 }, + { 4214, 16368 }, + { 4266, 18450 }, + { 4311, 20464 }, + { 4353, 22542 }, + { 4391, 24604 }, + { 4425, 26607 }, + { 4457, 28642 }, + { 4487, 30690 }, + { 4515, 32734 }, + { 4612, 40926 }, + { 4692, 49204 }, + { 4816, 65464 }, + { 4913, 81846 }, + { 4993, 98401 }, + { 5060, 114815 }, + { 5118, 131220 }, + { 5200, 158489 }, + { 5300, 199526 }, + { 5400, 251189 }, + { 5500, 316228 }, + { 5600, 398107 }, + { 5720, 524807 }, + { 5721, 526017 }, +}; + +int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg) +{ + int ret; + + u8 b0[] = { reg >> 8, reg & 0xff }; + u8 buf; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + },{ + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + if (ret != -ERESTARTSYS) + dprintk(state->verbose, FE_ERROR, 1, + "Read error, Reg=[0x%02x], Status=%d", + reg, ret); + + return ret < 0 ? ret : -EREMOTEIO; + } + if (unlikely(*state->verbose >= FE_DEBUGREG)) + dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x", + reg, buf); + + return (unsigned int)buf; +} + +int stb0899_read_reg(struct stb0899_state *state, unsigned int reg) +{ + int result; + + result = _stb0899_read_reg(state, reg); + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((reg != 0xf2ff) && (reg != 0xf6ff) && + (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + _stb0899_read_reg(state, (reg | 0x00ff)); + + return result; +} + +u32 _stb0899_read_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset) +{ + int status; + u32 data; + u8 buf[7] = { 0 }; + u16 tmpaddr; + + u8 buf_0[] = { + GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ + GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ + GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ + }; + u8 buf_1[] = { + 0x00, /* 0xf3 Reg Offset */ + 0x00, /* 0x44 Reg Offset */ + }; + + struct i2c_msg msg_0 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_0, + .len = 6 + }; + + struct i2c_msg msg_1 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_1, + .len = 2 + }; + + struct i2c_msg msg_r = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = buf, + .len = 4 + }; + + tmpaddr = stb0899_reg_offset & 0xff00; + if (!(stb0899_reg_offset & 0x8)) + tmpaddr = stb0899_reg_offset | 0x20; + + buf_1[0] = GETBYTE(tmpaddr, BYTE1); + buf_1[1] = GETBYTE(tmpaddr, BYTE0); + + status = i2c_transfer(state->i2c, &msg_0, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + + goto err; + } + + /* Dummy */ + status = i2c_transfer(state->i2c, &msg_1, 1); + if (status < 1) + goto err; + + status = i2c_transfer(state->i2c, &msg_r, 1); + if (status < 1) + goto err; + + buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); + buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); + + /* Actual */ + status = i2c_transfer(state->i2c, &msg_1, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + goto err; + } + + status = i2c_transfer(state->i2c, &msg_r, 1); + if (status < 1) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status); + return status < 0 ? status : -EREMOTEIO; + } + + data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]); + if (unlikely(*state->verbose >= FE_DEBUGREG)) + printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data); + + return data; + +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data) +{ + int status; + + /* Base Address Setup */ + u8 buf_0[] = { + GETBYTE(stb0899_i2cdev, BYTE1), /* 0xf3 S2 Base Address (MSB) */ + GETBYTE(stb0899_i2cdev, BYTE0), /* 0xfc S2 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE0), /* 0x00 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE1), /* 0x04 Base Address (LSB) */ + GETBYTE(stb0899_base_addr, BYTE2), /* 0x00 Base Address (MSB) */ + GETBYTE(stb0899_base_addr, BYTE3), /* 0x00 Base Address (MSB) */ + }; + u8 buf_1[] = { + 0x00, /* 0xf3 Reg Offset */ + 0x00, /* 0x44 Reg Offset */ + 0x00, /* data */ + 0x00, /* data */ + 0x00, /* data */ + 0x00, /* data */ + }; + + struct i2c_msg msg_0 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_0, + .len = 6 + }; + + struct i2c_msg msg_1 = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf_1, + .len = 6 + }; + + buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1); + buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0); + buf_1[2] = GETBYTE(stb0899_data, BYTE0); + buf_1[3] = GETBYTE(stb0899_data, BYTE1); + buf_1[4] = GETBYTE(stb0899_data, BYTE2); + buf_1[5] = GETBYTE(stb0899_data, BYTE3); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) + printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data); + + status = i2c_transfer(state->i2c, &msg_0, 1); + if (unlikely(status < 1)) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); + goto err; + } + status = i2c_transfer(state->i2c, &msg_1, 1); + if (unlikely(status < 1)) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n", + __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status); + + return status < 0 ? status : -EREMOTEIO; + } + + return 0; + +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count) +{ + int status; + + u8 b0[] = { reg >> 8, reg & 0xff }; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + },{ + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = buf, + .len = count + } + }; + + status = i2c_transfer(state->i2c, msg, 2); + if (status != 2) { + if (status != -ERESTARTSYS) + printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n", + __func__, reg, count, status); + goto err; + } + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((reg != 0xf2ff) && (reg != 0xf6ff) && + (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + _stb0899_read_reg(state, (reg | 0x00ff)); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) { + printk(" %02x", buf[i]); + } + printk("\n"); + } + + return 0; +err: + return status < 0 ? status : -EREMOTEIO; +} + +int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count) +{ + int ret; + u8 buf[2 + count]; + struct i2c_msg i2c_msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + count + }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + memcpy(&buf[2], data, count); + + if (unlikely(*state->verbose >= FE_DEBUGREG)) { + int i; + + printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); + for (i = 0; i < count; i++) + printk(" %02x", data[i]); + printk("\n"); + } + ret = i2c_transfer(state->i2c, &i2c_msg, 1); + + /* + * Bug ID 9: + * access to 0xf2xx/0xf6xx + * must be followed by read from 0xf2ff/0xf6ff. + */ + if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) + stb0899_read_reg(state, (reg | 0x00ff)); + + if (ret != 1) { + if (ret != -ERESTARTSYS) + dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d", + reg, data[0], count, ret); + return ret < 0 ? ret : -EREMOTEIO; + } + + return 0; +} + +int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data) +{ + return stb0899_write_regs(state, reg, &data, 1); +} + +/* + * stb0899_get_mclk + * Get STB0899 master clock frequency + * ExtClk: external clock frequency (Hz) + */ +static u32 stb0899_get_mclk(struct stb0899_state *state) +{ + u32 mclk = 0, div = 0; + + div = stb0899_read_reg(state, STB0899_NCOARSE); + mclk = (div + 1) * state->config->xtal_freq / 6; + dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk); + + return mclk; +} + +/* + * stb0899_set_mclk + * Set STB0899 master Clock frequency + * Mclk: demodulator master clock + * ExtClk: external clock frequency (Hz) + */ +static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk) +{ + struct stb0899_internal *internal = &state->internal; + u8 mdiv = 0; + + dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config); + mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1; + dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv); + + stb0899_write_reg(state, STB0899_NCOARSE, mdiv); + internal->master_clk = stb0899_get_mclk(state); + + dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk); +} + +static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable) +{ + struct stb0899_config *config = state->config; + const struct stb0899_postproc *postproc = config->postproc; + + /* post process event */ + if (postproc) { + if (enable) { + if (postproc[ctl].level == STB0899_GPIOPULLUP) + stb0899_write_reg(state, postproc[ctl].gpio, 0x02); + else + stb0899_write_reg(state, postproc[ctl].gpio, 0x82); + } else { + if (postproc[ctl].level == STB0899_GPIOPULLUP) + stb0899_write_reg(state, postproc[ctl].gpio, 0x82); + else + stb0899_write_reg(state, postproc[ctl].gpio, 0x02); + } + } + return 0; +} + +static void stb0899_release(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; + + dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); + kfree(state); +} + +/* + * stb0899_get_alpha + * return: rolloff + */ +static int stb0899_get_alpha(struct stb0899_state *state) +{ + u8 mode_coeff; + + mode_coeff = stb0899_read_reg(state, STB0899_DEMOD); + + if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1) + return 20; + else + return 35; +} + +/* + * stb0899_init_calc + */ +static void stb0899_init_calc(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + int master_clk; + u8 agc[2]; + u8 agc1cn; + u32 reg; + + /* Read registers (in burst mode) */ + agc1cn = stb0899_read_reg(state, STB0899_AGC1CN); + stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */ + + /* Initial calculations */ + master_clk = stb0899_get_mclk(state); + internal->t_agc1 = 0; + internal->t_agc2 = 0; + internal->master_clk = master_clk; + internal->mclk = master_clk / 65536L; + internal->rolloff = stb0899_get_alpha(state); + + /* DVBS2 Initial calculations */ + /* Set AGC value to the middle */ + internal->agc_gain = 8154; + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL); + STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg); + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA); + internal->rrc_alpha = STB0899_GETFIELD(RRC_ALPHA, reg); + + internal->center_freq = 0; + internal->av_frame_coarse = 10; + internal->av_frame_fine = 20; + internal->step_size = 2; +/* + if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO)) + pParams->IQLocked = 0; + else + pParams->IQLocked = 1; +*/ +} + +static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (1) { + reg = stb0899_read_reg(state, STB0899_DISSTATUS); + if (!STB0899_GETFIELD(FIFOFULL, reg)) + break; + if ((jiffies - start) > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out !!"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, i; + + if (cmd->msg_len > 8) + return -EINVAL; + + /* enable FIFO precharge */ + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + for (i = 0; i < cmd->msg_len; i++) { + /* wait for FIFO empty */ + if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0) + return -ETIMEDOUT; + + stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]); + } + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + return 0; +} + +static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (!STB0899_GETFIELD(RXEND, reg)) { + reg = stb0899_read_reg(state, STB0899_DISRX_ST0); + if (jiffies - start > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); + return -ETIMEDOUT; + } + msleep(10); + } + + return 0; +} + +static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, length = 0, i; + int result; + + if (stb0899_wait_diseqc_rxidle(state, 100) < 0) + return -ETIMEDOUT; + + reg = stb0899_read_reg(state, STB0899_DISRX_ST0); + if (STB0899_GETFIELD(RXEND, reg)) { + + reg = stb0899_read_reg(state, STB0899_DISRX_ST1); + length = STB0899_GETFIELD(FIFOBYTENBR, reg); + + if (length > sizeof (reply->msg)) { + result = -EOVERFLOW; + goto exit; + } + reply->msg_len = length; + + /* extract data */ + for (i = 0; i < length; i++) + reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO); + } + + return 0; +exit: + + return result; +} + +static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout) +{ + u8 reg = 0; + unsigned long start = jiffies; + + while (!STB0899_GETFIELD(TXIDLE, reg)) { + reg = stb0899_read_reg(state, STB0899_DISSTATUS); + if (jiffies - start > timeout) { + dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); + return -ETIMEDOUT; + } + msleep(10); + } + return 0; +} + +static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct stb0899_state *state = fe->demodulator_priv; + u8 reg, old_state; + + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + old_state = reg; + /* set to burst mode */ + STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x02); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + switch (burst) { + case SEC_MINI_A: + /* unmodulated */ + stb0899_write_reg(state, STB0899_DISFIFO, 0x00); + break; + case SEC_MINI_B: + /* modulated */ + stb0899_write_reg(state, STB0899_DISFIFO, 0xff); + break; + } + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + /* restore state */ + stb0899_write_reg(state, STB0899_DISCNTRL1, old_state); + + return 0; +} + +static int stb0899_diseqc_init(struct stb0899_state *state) +{ + struct dvb_diseqc_master_cmd tx_data; +/* + struct dvb_diseqc_slave_reply rx_data; +*/ + u8 f22_tx, f22_rx, reg; + + u32 mclk, tx_freq = 22000;/* count = 0, i; */ +#if 0 + u32 trial = 0; /* try max = 2 (try 20khz and 17.5 khz) */ + u32 ret_1 = 0; /* 20 Khz status */ + u32 ret_2 = 0; /* 17.5 Khz status */ +#endif + tx_data.msg[0] = 0xe2; + tx_data.msg_len = 3; + reg = stb0899_read_reg(state, STB0899_DISCNTRL2); + STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL2, reg); + + /* disable Tx spy */ + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + reg = stb0899_read_reg(state, STB0899_DISCNTRL1); + STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0); + stb0899_write_reg(state, STB0899_DISCNTRL1, reg); + + mclk = stb0899_get_mclk(state); + f22_tx = mclk / (tx_freq * 32); + stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */ + state->rx_freq = 20000; + f22_rx = mclk / (state->rx_freq * 32); + +#if 0 + while ((count < 5) && (trial < 2)) { + stb0899_write_reg(state, STB0899_DISF22RX, f22_rx); /* 2 possible values 17.5k/20k */ + + for (i = 0; i < 5; i++) { + msleep(50); + stb0899_send_diseqc_msg(&state->frontend, &tx_data); + msleep(100); + stb0899_recv_slave_reply(&state->frontend, &rx_data); + if (rx_data.msg_len >= 1) { + if ((rx_data.msg[0] == 0xe4) || (rx_data.msg[0] == 0xe5)) + count++; + } + } + if (trial == 0) + ret_1 = count; + else + ret_2 = count; + + trial++; + state->rx_freq = 17500; + f22_rx = mclk / (state->rx_freq * 32); + } + if (ret_1 > ret_2) { + state->rx_freq = 20000; + f22_rx = mclk / (state->rx_freq * 32); + } else { + state->rx_freq = 17500; + f22_rx = mclk / (state->rx_freq * 32); + } + + stb0899_write_reg(state, STB0899_DISF22RX, f22_rx); + if ((ret_1 == 0) && (ret_2 == 0)) + state->rx_freq = 0; /* no DiSEqC 2.0 slave */ + +#endif + return 0; +} + +static int stb0899_sleep(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; +/* + u8 reg; +*/ + dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))"); +#if 0 + reg = stb0899_read_reg(state, STB0899_SYNTCTRL); + STB0899_SETFIELD_VAL(STANDBY, reg, 1); + stb0899_write_reg(state, STB0899_SYNTCTRL, reg); +#endif + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); + + return 0; +} + +static int stb0899_wakeup(struct dvb_frontend *fe) +{ + int rc; + struct stb0899_state *state = fe->demodulator_priv; + + if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI))) + return rc; + /* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */ + if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00))) + return rc; + if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00))) + return rc; + + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1); + + return 0; +} + +static int stb0899_init(struct dvb_frontend *fe) +{ + int i; + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_config *config = state->config; + + dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... "); + + /* init device */ + dprintk(state->verbose, FE_DEBUG, 1, "init device"); + for (i = 0; config->init_dev[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod"); + /* init S2 demod */ + for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++) + stb0899_write_s2reg(state, STB0899_S2DEMOD, + config->init_s2_demod[i].base_address, + config->init_s2_demod[i].offset, + config->init_s2_demod[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod"); + /* init S1 demod */ + for (i = 0; config->init_s1_demod[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC"); + /* init S2 fec */ + for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++) + stb0899_write_s2reg(state, STB0899_S2FEC, + config->init_s2_fec[i].base_address, + config->init_s2_fec[i].offset, + config->init_s2_fec[i].data); + + dprintk(state->verbose, FE_DEBUG, 1, "init TST"); + /* init test */ + for (i = 0; config->init_tst[i].address != 0xffff; i++) + stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data); + + stb0899_init_calc(state); + stb0899_diseqc_init(state); + + return 0; +} + +static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val) +{ + int res = 0; + int min = 0, med; + + if (val < tab[min].read) + res = tab[min].real; + else if (val >= tab[max].read) + res = tab[max].real; + else { + while ((max - min) > 1) { + med = (max + min) / 2; + if (val >= tab[min].read && val < tab[med].read) + max = med; + else + min = med; + } + res = ((val - tab[min].read) * + (tab[max].real - tab[min].real) / + (tab[max].read - tab[min].read)) + + tab[min].real; + } + + return res; +} + +static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + int val; + u32 reg; + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + + reg = stb0899_read_reg(state, STB0899_AGCIQIN); + val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg); + + *strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val); + *strength += 750; + dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm", + val & 0xff, *strength); + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN); + val = STB0899_GETFIELD(IF_AGC_GAIN, reg); + + *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); + *strength += 750; + dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", + val & 0x3fff, *strength); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + unsigned int val, quant, quantn = -1, est, estn = -1; + u8 buf[2]; + u32 reg; + + reg = stb0899_read_reg(state, STB0899_VSTATUS); + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + + stb0899_read_regs(state, STB0899_NIRM, buf, 2); + val = MAKEWORD16(buf[0], buf[1]); + + *snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val); + dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n", + buf[0], buf[1], val, *snr); + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1); + quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg); + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2); + est = STB0899_GETFIELD(ESN0_EST, reg); + if (est == 1) + val = 301; /* C/N = 30.1 dB */ + else if (est == 2) + val = 270; /* C/N = 27.0 dB */ + else { + /* quantn = 100 * log(quant^2) */ + quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100); + /* estn = 100 * log(est) */ + estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est); + /* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */ + val = (quantn - estn) / 10; + } + *snr = val; + dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm", + quant, quantn, est, estn, val); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + u8 reg; + *status = 0; + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS"); + if (internal->lock) { + reg = stb0899_read_reg(state, STB0899_VSTATUS); + if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK"); + *status |= FE_HAS_CARRIER | FE_HAS_LOCK; + + reg = stb0899_read_reg(state, STB0899_PLPARM); + if (STB0899_GETFIELD(VITCURPUN, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC"); + *status |= FE_HAS_VITERBI | FE_HAS_SYNC; + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); + } + } + } + break; + case SYS_DVBS2: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2"); + if (internal->lock) { + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2); + if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) { + *status |= FE_HAS_CARRIER; + dprintk(state->verbose, FE_DEBUG, 1, + "UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER"); + + reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1); + if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) { + *status |= FE_HAS_LOCK; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK"); + + } + if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) { + *status |= FE_HAS_VITERBI; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI"); + } + if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) { + *status |= FE_HAS_SYNC; + dprintk(state->verbose, FE_DEBUG, 1, + "Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC"); + /* post process event */ + stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1); + } + } + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + return 0; +} + +/* + * stb0899_get_error + * viterbi error for DVB-S/DSS + * packet error for DVB-S2 + * Bit Error Rate or Packet Error Rate * 10 ^ 7 + */ +static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + u8 lsb, msb; + u32 i; + + *ber = 0; + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + if (internal->lock) { + /* average 5 BER values */ + for (i = 0; i < 5; i++) { + msleep(100); + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber += MAKEWORD16(msb, lsb); + } + *ber /= 5; + /* Viterbi Check */ + if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) { + /* Error Rate */ + *ber *= 9766; + /* ber = ber * 10 ^ 7 */ + *ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); + *ber /= 8; + } + } + break; + case SYS_DVBS2: + if (internal->lock) { + /* Average 5 PER values */ + for (i = 0; i < 5; i++) { + msleep(100); + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber += MAKEWORD16(msb, lsb); + } + /* ber = ber * 10 ^ 7 */ + *ber *= 10000000; + *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); + } + break; + default: + dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system"); + return -EINVAL; + } + + return 0; +} + +static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct stb0899_state *state = fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00); + break; + case SEC_VOLTAGE_18: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); + break; + case SEC_VOLTAGE_OFF: + stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82); + stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + u8 div, reg; + + /* wait for diseqc idle */ + if (stb0899_wait_diseqc_txidle(state, 100) < 0) + return -ETIMEDOUT; + + switch (tone) { + case SEC_TONE_ON: + div = (internal->master_clk / 100) / 5632; + div = (div + 5) / 10; + stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66); + reg = stb0899_read_reg(state, STB0899_ACRPRESC); + STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03); + stb0899_write_reg(state, STB0899_ACRPRESC, reg); + stb0899_write_reg(state, STB0899_ACRDIV1, div); + break; + case SEC_TONE_OFF: + stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20); + break; + default: + return -EINVAL; + } + return 0; +} + +int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int i2c_stat; + struct stb0899_state *state = fe->demodulator_priv; + + i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT); + if (i2c_stat < 0) + goto err; + + if (enable) { + dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ..."); + i2c_stat |= STB0899_I2CTON; + if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) + goto err; + } else { + dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ..."); + i2c_stat &= ~STB0899_I2CTON; + if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0) + goto err; + } + return 0; +err: + dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed"); + return -EREMOTEIO; +} + + +static inline void CONVERT32(u32 x, char *str) +{ + *str++ = (x >> 24) & 0xff; + *str++ = (x >> 16) & 0xff; + *str++ = (x >> 8) & 0xff; + *str++ = (x >> 0) & 0xff; + *str = '\0'; +} + +int stb0899_get_dev_id(struct stb0899_state *state) +{ + u8 chip_id, release; + u16 id; + u32 demod_ver = 0, fec_ver = 0; + char demod_str[5] = { 0 }; + char fec_str[5] = { 0 }; + + id = stb0899_read_reg(state, STB0899_DEV_ID); + dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id); + chip_id = STB0899_GETFIELD(CHIP_ID, id); + release = STB0899_GETFIELD(CHIP_REL, id); + + dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]", + chip_id, release); + + CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str); + + demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID); + dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver); + CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str); + fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG); + if (! (chip_id > 0)) { + dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899"); + + return -ENODEV; + } + dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver); + + return 0; +} + +static void stb0899_set_delivery(struct stb0899_state *state) +{ + u8 reg; + u8 stop_clk[2]; + + stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1); + stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2); + + switch (state->delsys) { + case SYS_DVBS: + dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S"); + /* FECM/Viterbi ON */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xb1); + stb0899_write_reg(state, STB0899_TSULC, 0x40); + stb0899_write_reg(state, STB0899_RSLLC, 0x42); + stb0899_write_reg(state, STB0899_TSLPL, 0x12); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); + + STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); + break; + case SYS_DVBS2: + /* FECM/Viterbi OFF */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xb1); + stb0899_write_reg(state, STB0899_TSULC, 0x42); + stb0899_write_reg(state, STB0899_RSLLC, 0x40); + stb0899_write_reg(state, STB0899_TSLPL, 0x02); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0); + + STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0); + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0); + break; + case SYS_DSS: + /* FECM/Viterbi ON */ + reg = stb0899_read_reg(state, STB0899_FECM); + STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1); + STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1); + stb0899_write_reg(state, STB0899_FECM, reg); + + stb0899_write_reg(state, STB0899_RSULC, 0xa1); + stb0899_write_reg(state, STB0899_TSULC, 0x61); + stb0899_write_reg(state, STB0899_RSLLC, 0x42); + + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESLDPC, reg, 1); + stb0899_write_reg(state, STB0899_TSTRES, reg); + + STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1); + STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1); + + STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1); + STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1); + + STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0); + + STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1); + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + break; + } + STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0); + stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2); +} + +/* + * stb0899_set_iterations + * set the LDPC iteration scale function + */ +static void stb0899_set_iterations(struct stb0899_state *state) +{ + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + + s32 iter_scale; + u32 reg; + + iter_scale = 17 * (internal->master_clk / 1000); + iter_scale += 410000; + iter_scale /= (internal->srate / 1000000); + iter_scale /= 1000; + + if (iter_scale > config->ldpc_max_iter) + iter_scale = config->ldpc_max_iter; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER); + STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale); + stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); +} + +static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_params *i_params = &state->params; + struct stb0899_internal *internal = &state->internal; + struct stb0899_config *config = state->config; + struct dtv_frontend_properties *props = &fe->dtv_property_cache; + + u32 SearchRange, gain; + + i_params->freq = p->frequency; + i_params->srate = p->u.qpsk.symbol_rate; + state->delsys = props->delivery_system; + dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys); + + SearchRange = 10000000; + dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate); + /* checking Search Range is meaningless for a fixed 3 Mhz */ + if (INRANGE(i_params->srate, 1000000, 45000000)) { + dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE"); + stb0899_set_delivery(state); + + if (state->config->tuner_set_rfsiggain) { + if (internal->srate > 15000000) + gain = 8; /* 15Mb < srate < 45Mb, gain = 8dB */ + else if (internal->srate > 5000000) + gain = 12; /* 5Mb < srate < 15Mb, gain = 12dB */ + else + gain = 14; /* 1Mb < srate < 5Mb, gain = 14db */ + state->config->tuner_set_rfsiggain(fe, gain); + } + + if (i_params->srate <= 5000000) + stb0899_set_mclk(state, config->lo_clk); + else + stb0899_set_mclk(state, config->hi_clk); + + switch (state->delsys) { + case SYS_DVBS: + case SYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system"); + internal->freq = i_params->freq; + internal->srate = i_params->srate; + /* + * search = user search range + + * 500Khz + + * 2 * Tuner_step_size + + * 10% of the symbol rate + */ + internal->srch_range = SearchRange + 1500000 + (i_params->srate / 5); + internal->derot_percent = 30; + + /* What to do for tuners having no bandwidth setup ? */ + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + if (state->config->tuner_set_bandwidth) + state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10); + if (state->config->tuner_get_bandwidth) + state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + + /* Set DVB-S1 AGC */ + stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11); + + /* Run the search algorithm */ + dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo .."); + if (stb0899_dvbs_algo(state) == RANGEOK) { + internal->lock = 1; + dprintk(state->verbose, FE_DEBUG, 1, + "-------------------------------------> DVB-S LOCK !"); + +// stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors */ +// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); +// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); +// dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status); +// dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl); + + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + internal->lock = 0; + + return DVBFE_ALGO_SEARCH_FAILED; + } + break; + case SYS_DVBS2: + internal->freq = i_params->freq; + internal->srate = i_params->srate; + internal->srch_range = SearchRange; + + /* enable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 1); + + if (state->config->tuner_set_bandwidth) + state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange)); + if (state->config->tuner_get_bandwidth) + state->config->tuner_get_bandwidth(fe, &internal->tuner_bw); + + /* disable tuner I/O */ + stb0899_i2c_gate_ctrl(&state->frontend, 0); + +// pParams->SpectralInv = pSearch->IQ_Inversion; + + /* Set DVB-S2 AGC */ + stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c); + + /* Set IterScale =f(MCLK,SYMB) */ + stb0899_set_iterations(state); + + /* Run the search algorithm */ + dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo .."); + if (stb0899_dvbs2_algo(state) == DVBS2_FEC_LOCK) { + internal->lock = 1; + dprintk(state->verbose, FE_DEBUG, 1, + "-------------------------------------> DVB-S2 LOCK !"); + +// stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors */ +// internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS); +// internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1); + + return DVBFE_ALGO_SEARCH_SUCCESS; + } else { + internal->lock = 0; + + return DVBFE_ALGO_SEARCH_FAILED; + } + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + return DVBFE_ALGO_SEARCH_INVALID; + } + } + + return DVBFE_ALGO_SEARCH_ERROR; +} +#if 0 +static enum stb0899_status stb0899_track_carrier(struct stb0899_state *state) +{ + u8 reg; + + reg = stb0899_read_reg(state, STB0899_DSTATUS); + dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(CARRIER_FOUND, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !"); + return CARRIEROK; + } else { + dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !"); + return NOCARRIER; + } + + return NOCARRIER; +} + +static enum stb0899_status stb0899_get_ifagc(struct stb0899_state *state) +{ + u8 reg; + + reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS); + dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg); + if (STB0899_GETFIELD(IF_AGC_LOCK, reg)) { + dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !"); + return AGC1OK; + } else { + dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCK LOST !"); + return NOAGC1; + } + + return NOAGC1; +} + +static int stb0899_get_s1fec(struct stb0899_internal *internal, enum fe_code_rate *fec) +{ + switch (internal->fecrate) { + case STB0899_FEC_1_2: + *fec = FEC_1_2; + break; + case STB0899_FEC_2_3: + *fec = FEC_2_3; + break; + case STB0899_FEC_3_4: + *fec = FEC_3_4; + break; + case STB0899_FEC_5_6: + *fec = FEC_5_6; + break; + case STB0899_FEC_6_7: + *fec = FEC_6_7; + break; + case STB0899_FEC_7_8: + *fec = FEC_7_8; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int stb0899_get_modcod(struct stb0899_internal *internal, struct dvbs2_params *params) +{ + switch (internal->modcod) { + case STB0899_DUMMY_PLF: + params->modulation = DVBFE_MOD_NONE; + params->fec = DVBFE_FEC_NONE; + break; + case STB0899_QPSK_14: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_1_4; + break; + case STB0899_QPSK_13: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_1_3; + break; + case STB0899_QPSK_25: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_2_5; + break; + case STB0899_QPSK_12: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_1_2; + break; + case STB0899_QPSK_35: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_3_5; + break; + case STB0899_QPSK_23: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_2_3; + break; + case STB0899_QPSK_34: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_3_4; + break; + case STB0899_QPSK_45: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_4_5; + break; + case STB0899_QPSK_56: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_5_6; + break; + case STB0899_QPSK_89: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_8_9; + break; + case STB0899_QPSK_910: + params->modulation = DVBFE_MOD_QPSK; + params->fec = DVBFE_FEC_9_10; + break; + case STB0899_8PSK_35: + params->modulation = DVBFE_MOD_8PSK; + params->fec = DVBFE_FEC_3_5; + break; + case STB0899_8PSK_23: + params->modulation = DVBFE_MOD_8PSK; + params->fec = DVBFE_FEC_2_3; + break; + case STB0899_8PSK_34: + params->modulation = DVBFE_MOD_8PSK; + params->fec = DVBFE_FEC_3_4; + break; + case STB0899_8PSK_56: + params->modulation = DVBFE_MOD_8PSK; + params->fec = DVBFE_FEC_5_6; + break; + case STB0899_8PSK_89: + params->modulation = DVBFE_MOD_8PSK; + params->fec = DVBFE_FEC_8_9; + break; + case STB0899_8PSK_910: + params->modulation = DVBFE_MOD_8PSK; + params->fec = DVBFE_FEC_9_10; + break; + case STB0899_16APSK_23: + params->modulation = DVBFE_MOD_16APSK; + params->fec = DVBFE_FEC_2_3; + break; + case STB0899_16APSK_34: + params->modulation = DVBFE_MOD_16APSK; + params->fec = DVBFE_FEC_3_4; + break; + case STB0899_16APSK_45: + params->modulation = DVBFE_MOD_16APSK; + params->fec = DVBFE_FEC_4_5; + break; + case STB0899_16APSK_56: + params->modulation = DVBFE_MOD_16APSK; + params->fec = DVBFE_FEC_5_6; + break; + case STB0899_16APSK_89: + params->modulation = DVBFE_MOD_16APSK; + params->fec = DVBFE_FEC_8_9; + break; + case STB0899_16APSK_910: + params->modulation = DVBFE_MOD_16APSK; + params->fec = DVBFE_FEC_9_10; + break; + case STB0899_32APSK_34: + params->modulation = DVBFE_MOD_32APSK; + params->fec = DVBFE_FEC_3_4; + break; + case STB0899_32APSK_45: + params->modulation = DVBFE_MOD_32APSK; + params->fec = DVBFE_FEC_4_5; + break; + case STB0899_32APSK_56: + params->modulation = DVBFE_MOD_32APSK; + params->fec = DVBFE_FEC_5_6; + break; + case STB0899_32APSK_89: + params->modulation = DVBFE_MOD_32APSK; + params->fec = DVBFE_FEC_8_9; + break; + case STB0899_32APSK_910: + params->modulation = DVBFE_MOD_32APSK; + params->fec = DVBFE_FEC_9_10; + break; + default: + return -EINVAL; + } + + return 0; +} +#endif +/* + * stb0899_track + * periodically check the signal level against a specified + * threshold level and perform derotator centering. + * called once we have a lock from a succesful search + * event. + * + * Will be called periodically called to maintain the + * lock. + * + * Will be used to get parameters as well as info from + * the decoded baseband header + * + * Once a new lock has established, the internal state + * frequency (internal->freq) is updated + */ +static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ +#if 0 + u32 lock_lost; + + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + switch (state->delsys) { + case DVBFE_DELSYS_DVBS: + dprintk(state->verbose, FE_DEBUG, 1, "Tracking DVB-S state"); + if (stb0899_track_carrier(state) == CARRIEROK) { + params->frequency = internal->freq; + params->inversion = internal->inversion; + params->delivery = state->delsys; + params->delsys.dvbs.symbol_rate = internal->srate; + params->delsys.dvbs.modulation = DVBFE_MOD_QPSK; + stb0899_get_s1fec(internal, ¶ms->delsys.dvbs.fec); + } + break; + case DVBFE_DELSYS_DSS: + dprintk(state->verbose, FE_DEBUG, 1, "Tracking DSS state"); + if (stb0899_track_carrier(state) == CARRIEROK) { + params->frequency = internal->freq; + params->inversion = internal->inversion; + params->delivery = state->delsys; + params->delsys.dss.symbol_rate = internal->srate; + params->delsys.dss.modulation = DVBFE_MOD_QPSK; + stb0899_get_s1fec(internal, ¶ms->delsys.dss.fec); + } + break; + case DVBFE_DELSYS_DVBS2: + dprintk(state->verbose, FE_DEBUG, 1, "Tracking DVB-S2 state"); + if (stb0899_get_ifagc(state) == AGC1OK) { + params->frequency = internal->freq; + params->inversion = internal->inversion; + params->delivery = state->delsys; + params->delsys.dvbs2.symbol_rate = internal->srate; + stb0899_get_modcod(internal, ¶ms->delsys.dvbs2); + params->delsys.dvbs2.rolloff = internal->rolloff; + params->delsys.dvbs2.matype_1 = stb0899_read_reg(state, STB0899_MATSTRL); + params->delsys.dvbs2.matype_2 = stb0899_read_reg(state, STB0899_MATSTRM); + params->delsys.dvbs2.upl_1 = stb0899_read_reg(state, STB0899_UPLSTRL); + params->delsys.dvbs2.upl_2 = stb0899_read_reg(state, STB0899_UPLSTRM); + params->delsys.dvbs2.dfl_1 = stb0899_read_reg(state, STB0899_DFLSTRL); + params->delsys.dvbs2.dfl_2 = stb0899_read_reg(state, STB0899_DFLSTRM); + params->delsys.dvbs2.sync = stb0899_read_reg(state, STB0899_SYNCSTR); + params->delsys.dvbs2.syncd_1 = stb0899_read_reg(state, STB0899_SYNCDSTRL); + params->delsys.dvbs2.syncd_2 = stb0899_read_reg(state, STB0899_SYNCDSTRM); + } + lock_lost = STB0899_READ_S2REG(STB0899_S2DEMOD, LOCK_LOST); + dprintk(state->verbose, FE_DEBUG, 1, "Lock Lost=[0x%02x]\n", lock_lost); + if (STB0899_GETFIELD(LOCK_LOST, lock_lost)) + dprintk(state->verbose, FE_ERROR, 1, "Demodulator LOST LOCK !\n"); + break; + default: + dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system"); + return -EINVAL; + } + +// *delay = HZ/10; +#endif + return 0; +} + +static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct stb0899_state *state = fe->demodulator_priv; + struct stb0899_internal *internal = &state->internal; + + dprintk(state->verbose, FE_DEBUG, 1, "Get params"); + p->u.qpsk.symbol_rate = internal->srate; + + return 0; +} + +static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static struct dvb_frontend_ops stb0899_ops = { + + .info = { + .name = "STB0899 Multistandard", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 5000000, + .symbol_rate_max = 45000000, + + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = stb0899_release, + .init = stb0899_init, + .sleep = stb0899_sleep, +// .wakeup = stb0899_wakeup, + + .i2c_gate_ctrl = stb0899_i2c_gate_ctrl, + + .get_frontend_algo = stb0899_frontend_algo, + .search = stb0899_search, + .track = stb0899_track, + .get_frontend = stb0899_get_frontend, + + + .read_status = stb0899_read_status, + .read_snr = stb0899_read_snr, + .read_signal_strength = stb0899_read_signal_strength, + .read_ber = stb0899_read_ber, + + .set_voltage = stb0899_set_voltage, + .set_tone = stb0899_set_tone, + + .diseqc_send_master_cmd = stb0899_send_diseqc_msg, + .diseqc_recv_slave_reply = stb0899_recv_slave_reply, + .diseqc_send_burst = stb0899_send_diseqc_burst, +}; + +struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c) +{ + struct stb0899_state *state = NULL; + enum stb0899_inversion inversion; + + state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL); + if (state == NULL) + goto error; + + inversion = config->inversion; + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stb0899_ops; + state->frontend.demodulator_priv = state; + state->internal.inversion = inversion; + + stb0899_wakeup(&state->frontend); + if (stb0899_get_dev_id(state) == -ENODEV) { + printk("%s: Exiting .. !\n", __func__); + goto error; + } + + printk("%s: Attaching STB0899 \n", __func__); + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stb0899_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STB0899 Multi-Std frontend"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/stb0899_drv.h b/linux/drivers/media/dvb/frontends/stb0899_drv.h new file mode 100644 index 000000000..98b200ce0 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb0899_drv.h @@ -0,0 +1,162 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_DRV_H +#define __STB0899_DRV_H + +#include <linux/kernel.h> +#include <linux/module.h> + +#include "dvb_frontend.h" + +#define STB0899_TSMODE_SERIAL 1 +#define STB0899_CLKPOL_FALLING 2 +#define STB0899_CLKNULL_PARITY 3 +#define STB0899_SYNC_FORCED 4 +#define STB0899_FECMODE_DSS 5 + +struct stb0899_s1_reg { + u16 address; + u8 data; +}; + +struct stb0899_s2_reg { + u16 offset; + u32 base_address; + u32 data; +}; + +enum stb0899_inversion { + IQ_SWAP_OFF = 0, + IQ_SWAP_ON, + IQ_SWAP_AUTO +}; + +#define STB0899_GPIO00 0xf140 +#define STB0899_GPIO01 0xf141 +#define STB0899_GPIO02 0xf142 +#define STB0899_GPIO03 0xf143 +#define STB0899_GPIO04 0xf144 +#define STB0899_GPIO05 0xf145 +#define STB0899_GPIO06 0xf146 +#define STB0899_GPIO07 0xf147 +#define STB0899_GPIO08 0xf148 +#define STB0899_GPIO09 0xf149 +#define STB0899_GPIO10 0xf14a +#define STB0899_GPIO11 0xf14b +#define STB0899_GPIO12 0xf14c +#define STB0899_GPIO13 0xf14d +#define STB0899_GPIO14 0xf14e +#define STB0899_GPIO15 0xf14f +#define STB0899_GPIO16 0xf150 +#define STB0899_GPIO17 0xf151 +#define STB0899_GPIO18 0xf152 +#define STB0899_GPIO19 0xf153 +#define STB0899_GPIO20 0xf154 + +#define STB0899_GPIOPULLUP 0x01 /* Output device is connected to Vdd */ +#define STB0899_GPIOPULLDN 0x00 /* Output device is connected to Vss */ + +#define STB0899_POSTPROC_GPIO_POWER 0x00 +#define STB0899_POSTPROC_GPIO_LOCK 0x01 + +/* + * Post process output configuration control + * 1. POWER ON/OFF (index 0) + * 2. FE_HAS_LOCK/LOCK_LOSS (index 1) + * + * @gpio = one of the above listed GPIO's + * @level = output state: pulled up or low + */ +struct stb0899_postproc { + u16 gpio; + u8 level; +}; + +struct stb0899_config { + const struct stb0899_s1_reg *init_dev; + const struct stb0899_s2_reg *init_s2_demod; + const struct stb0899_s1_reg *init_s1_demod; + const struct stb0899_s2_reg *init_s2_fec; + const struct stb0899_s1_reg *init_tst; + + const struct stb0899_postproc *postproc; + + enum stb0899_inversion inversion; + + u32 xtal_freq; + + u8 demod_address; + u8 ts_output_mode; + u8 block_sync_mode; + u8 ts_pfbit_toggle; + + u8 clock_polarity; + u8 data_clk_parity; + u8 fec_mode; + u8 data_output_ctl; + u8 data_fifo_mode; + u8 out_rate_comp; + u8 i2c_repeater; +// int inversion; + int lo_clk; + int hi_clk; + + u32 esno_ave; + u32 esno_quant; + u32 avframes_coarse; + u32 avframes_fine; + u32 miss_threshold; + u32 uwp_threshold_acq; + u32 uwp_threshold_track; + u32 uwp_threshold_sof; + u32 sof_search_timeout; + + u32 btr_nco_bits; + u32 btr_gain_shift_offset; + u32 crl_nco_bits; + u32 ldpc_max_iter; + + int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency); + int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain); +}; + +#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_STB0899 + + +#endif diff --git a/linux/drivers/media/dvb/frontends/stb0899_priv.h b/linux/drivers/media/dvb/frontends/stb0899_priv.h new file mode 100644 index 000000000..e57ff227b --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb0899_priv.h @@ -0,0 +1,274 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_PRIV_H +#define __STB0899_PRIV_H + +#include "dvb_frontend.h" +#include "stb0899_drv.h" + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 +#define FE_DEBUGREG 4 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((*x > FE_ERROR) && (*x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_NOTICE) && (*x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_INFO) && (*x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((*x > FE_DEBUG) && (*x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (*x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ + ((y <= val) && (val <= x)) ? 1 : 0) + +#define BYTE0 0 +#define BYTE1 8 +#define BYTE2 16 +#define BYTE3 24 + +#define GETBYTE(x, y) (((x) >> (y)) & 0xff) +#define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define MAKEWORD16(a, b) (((a) << 8) | (b)) + +#define MIN(x, y) ((x) <= (y) ? (x) : (y)) +#define MAX(x, y) ((x) >= (y) ? (x) : (y)) +#define ABS(x) ((x) >= 0 ? (x) : -(x)) + +#define LSB(x) ((x & 0xff)) +#define MSB(y) ((y >> 8) & 0xff) + + +#define STB0899_GETFIELD(bitf, val) ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1)) + + +#define STB0899_SETFIELD(mask, val, width, offset) (mask & (~(((1 << width) - 1) << \ + offset))) | ((val & \ + ((1 << width) - 1)) << offset) + +#define STB0899_SETFIELD_VAL(bitf, mask, val) (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\ + STB0899_OFFST_##bitf))) | \ + (val << STB0899_OFFST_##bitf)) + + +enum stb0899_status { + NOAGC1 = 0, + AGC1OK, + NOTIMING, + ANALOGCARRIER, + TIMINGOK, + NOAGC2, + AGC2OK, + NOCARRIER, + CARRIEROK, + NODATA, + FALSELOCK, + DATAOK, + OUTOFRANGE, + RANGEOK, + DVBS2_DEMOD_LOCK, + DVBS2_DEMOD_NOLOCK, + DVBS2_FEC_LOCK, + DVBS2_FEC_NOLOCK +}; + +enum stb0899_modcod { + STB0899_DUMMY_PLF, + STB0899_QPSK_14, + STB0899_QPSK_13, + STB0899_QPSK_25, + STB0899_QPSK_12, + STB0899_QPSK_35, + STB0899_QPSK_23, + STB0899_QPSK_34, + STB0899_QPSK_45, + STB0899_QPSK_56, + STB0899_QPSK_89, + STB0899_QPSK_910, + STB0899_8PSK_35, + STB0899_8PSK_23, + STB0899_8PSK_34, + STB0899_8PSK_56, + STB0899_8PSK_89, + STB0899_8PSK_910, + STB0899_16APSK_23, + STB0899_16APSK_34, + STB0899_16APSK_45, + STB0899_16APSK_56, + STB0899_16APSK_89, + STB0899_16APSK_910, + STB0899_32APSK_34, + STB0899_32APSK_45, + STB0899_32APSK_56, + STB0899_32APSK_89, + STB0899_32APSK_910 +}; + +enum stb0899_frame { + STB0899_LONG_FRAME, + STB0899_SHORT_FRAME +}; + +enum stb0899_alpha { + RRC_20, + RRC_25, + RRC_35 +}; + +struct stb0899_tab { + s32 real; + s32 read; +}; + +enum stb0899_fec { + STB0899_FEC_1_2 = 13, + STB0899_FEC_2_3 = 18, + STB0899_FEC_3_4 = 21, + STB0899_FEC_5_6 = 24, + STB0899_FEC_6_7 = 25, + STB0899_FEC_7_8 = 26 +}; + +struct stb0899_params { + u32 freq; /* Frequency */ + u32 srate; /* Symbol rate */ + enum fe_code_rate fecrate; +}; + +struct stb0899_internal { + u32 master_clk; + u32 freq; /* Demod internal Frequency */ + u32 srate; /* Demod internal Symbol rate */ + enum stb0899_fec fecrate; /* Demod internal FEC rate */ + u32 srch_range; /* Demod internal Search Range */ + u32 sub_range; /* Demod current sub range (Hz) */ + u32 tuner_step; /* Tuner step (Hz) */ + u32 tuner_offst; /* Relative offset to carrier (Hz) */ + u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */ + + s32 mclk; /* Masterclock Divider factor (binary) */ + s32 rolloff; /* Current RollOff of the filter (x100) */ + + s16 derot_freq; /* Current derotator frequency (Hz) */ + s16 derot_percent; + + s16 direction; /* Current derotator search direction */ + s16 derot_step; /* Derotator step (binary value) */ + s16 t_derot; /* Derotator time constant (ms) */ + s16 t_data; /* Data recovery time constant (ms) */ + s16 sub_dir; /* Direction of the next sub range */ + + s16 t_agc1; /* Agc1 time constant (ms) */ + s16 t_agc2; /* Agc2 time constant (ms) */ + + u32 lock; /* Demod internal lock state */ + enum stb0899_status status; /* Demod internal status */ + + /* DVB-S2 */ + s32 agc_gain; /* RF AGC Gain */ + s32 center_freq; /* Nominal carrier frequency */ + s32 av_frame_coarse; /* Coarse carrier freq search frames */ + s32 av_frame_fine; /* Fine carrier freq search frames */ + + s16 step_size; /* Carrier frequency search step size */ + + enum stb0899_alpha rrc_alpha; + enum stb0899_inversion inversion; + enum stb0899_modcod modcod; + u8 pilots; /* Pilots found */ + + enum stb0899_frame frame_length; + u8 v_status; /* VSTATUS */ + u8 err_ctrl; /* ERRCTRLn */ +}; + +struct stb0899_state { + struct i2c_adapter *i2c; + struct stb0899_config *config; + struct dvb_frontend frontend; + + u32 *verbose; /* Cached module verbosity level */ + + struct stb0899_internal internal; /* Device internal parameters */ + + /* cached params from API */ + enum fe_delivery_system delsys; + struct stb0899_params params; + + u32 rx_freq; /* DiSEqC 2.0 receiver freq */ + struct mutex search_lock; +}; +/* stb0899.c */ +extern int stb0899_read_reg(struct stb0899_state *state, + unsigned int reg); + +extern u32 _stb0899_read_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset); + +extern int stb0899_read_regs(struct stb0899_state *state, + unsigned int reg, u8 *buf, + u32 count); + +extern int stb0899_write_regs(struct stb0899_state *state, + unsigned int reg, u8 *data, + u32 count); + +extern int stb0899_write_reg(struct stb0899_state *state, + unsigned int reg, + u8 data); + +extern int stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data); + +extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); + +#if 0 +extern int _stb0899_write_s2reg(struct stb0899_state *state, + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data); +#endif + +#define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG)) +//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA) (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA)) + +/* stb0899_algo.c */ +extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state); +extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state); +extern long stb0899_carr_width(struct stb0899_state *state); + +#endif //__STB0899_PRIV_H diff --git a/linux/drivers/media/dvb/frontends/stb0899_reg.h b/linux/drivers/media/dvb/frontends/stb0899_reg.h new file mode 100644 index 000000000..ba1ed5630 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb0899_reg.h @@ -0,0 +1,2027 @@ +/* + STB0899 Multistandard Frontend driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB0899_REG_H +#define __STB0899_REG_H + +/* S1 */ +#define STB0899_DEV_ID 0xf000 +#define STB0899_CHIP_ID (0x0f << 4) +#define STB0899_OFFST_CHIP_ID 4 +#define STB0899_WIDTH_CHIP_ID 4 +#define STB0899_CHIP_REL (0x0f << 0) +#define STB0899_OFFST_CHIP_REL 0 +#define STB0899_WIDTH_CHIP_REL 4 + +#define STB0899_DEMOD 0xf40e +#define STB0899_MODECOEFF (0x01 << 0) +#define STB0899_OFFST_MODECOEFF 0 +#define STB0899_WIDTH_MODECOEFF 1 + +#define STB0899_RCOMPC 0xf410 +#define STB0899_AGC1CN 0xf412 +#define STB0899_AGC1REF 0xf413 +#define STB0899_RTC 0xf417 +#define STB0899_TMGCFG 0xf418 +#define STB0899_AGC2REF 0xf419 +#define STB0899_TLSR 0xf41a + +#define STB0899_CFD 0xf41b +#define STB0899_CFD_ON (0x01 << 7) +#define STB0899_OFFST_CFD_ON 7 +#define STB0899_WIDTH_CFD_ON 1 + +#define STB0899_ACLC 0xf41c + +#define STB0899_BCLC 0xf41d +#define STB0899_OFFST_ALGO 6 +#define STB0899_WIDTH_ALGO_QPSK2 2 +#define STB0899_ALGO_QPSK2 (2 << 6) +#define STB0899_ALGO_QPSK1 (1 << 6) +#define STB0899_ALGO_BPSK (0 << 6) +#define STB0899_OFFST_BETA 0 +#define STB0899_WIDTH_BETA 6 + +#define STB0899_EQON 0xf41e +#define STB0899_LDT 0xf41f +#define STB0899_LDT2 0xf420 +#define STB0899_EQUALREF 0xf425 +#define STB0899_TMGRAMP 0xf426 +#define STB0899_TMGTHD 0xf427 +#define STB0899_IDCCOMP 0xf428 +#define STB0899_QDCCOMP 0xf429 +#define STB0899_POWERI 0xf42a +#define STB0899_POWERQ 0xf42b +#define STB0899_RCOMP 0xf42c + +#define STB0899_AGCIQIN 0xf42e +#define STB0899_AGCIQVALUE (0xff << 0) +#define STB0899_OFFST_AGCIQVALUE 0 +#define STB0899_WIDTH_AGCIQVALUE 8 + +#define STB0899_AGC2I1 0xf436 +#define STB0899_AGC2I2 0xf437 + +#define STB0899_TLIR 0xf438 +#define STB0899_TLIR_TMG_LOCK_IND (0xff << 0) +#define STB0899_OFFST_TLIR_TMG_LOCK_IND 0 +#define STB0899_WIDTH_TLIR_TMG_LOCK_IND 8 + +#define STB0899_RTF 0xf439 +#define STB0899_RTF_TIMING_LOOP_FREQ (0xff << 0) +#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ 0 +#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ 8 + +#define STB0899_DSTATUS 0xf43a +#define STB0899_CARRIER_FOUND (0x01 << 7) +#define STB0899_OFFST_CARRIER_FOUND 7 +#define STB0899_WIDTH_CARRIER_FOUND 1 +#define STB0899_TMG_LOCK (0x01 << 6) +#define STB0899_OFFST_TMG_LOCK 6 +#define STB0899_WIDTH_TMG_LOCK 1 +#define STB0899_DEMOD_LOCK (0x01 << 5) +#define STB0899_OFFST_DEMOD_LOCK 5 +#define STB0899_WIDTH_DEMOD_LOCK 1 +#define STB0899_TMG_AUTO (0x01 << 4) +#define STB0899_OFFST_TMG_AUTO 4 +#define STB0899_WIDTH_TMG_AUTO 1 +#define STB0899_END_MAIN (0x01 << 3) +#define STB0899_OFFST_END_MAIN 3 +#define STB0899_WIDTH_END_MAIN 1 + +#define STB0899_LDI 0xf43b +#define STB0899_OFFST_LDI 0 +#define STB0899_WIDTH_LDI 8 + +#define STB0899_CFRM 0xf43e +#define STB0899_OFFST_CFRM 0 +#define STB0899_WIDTH_CFRM 8 + +#define STB0899_CFRL 0xf43f +#define STB0899_OFFST_CFRL 0 +#define STB0899_WIDTH_CFRL 8 + +#define STB0899_NIRM 0xf440 +#define STB0899_OFFST_NIRM 0 +#define STB0899_WIDTH_NIRM 8 + +#define STB0899_NIRL 0xf441 +#define STB0899_OFFST_NIRL 0 +#define STB0899_WIDTH_NIRL 8 + +#define STB0899_ISYMB 0xf444 +#define STB0899_QSYMB 0xf445 + +#define STB0899_SFRH 0xf446 +#define STB0899_OFFST_SFRH 0 +#define STB0899_WIDTH_SFRH 8 + +#define STB0899_SFRM 0xf447 +#define STB0899_OFFST_SFRM 0 +#define STB0899_WIDTH_SFRM 8 + +#define STB0899_SFRL 0xf448 +#define STB0899_OFFST_SFRL 4 +#define STB0899_WIDTH_SFRL 4 + +#define STB0899_SFRUPH 0xf44c +#define STB0899_SFRUPM 0xf44d +#define STB0899_SFRUPL 0xf44e + +#define STB0899_EQUAI1 0xf4e0 +#define STB0899_EQUAQ1 0xf4e1 +#define STB0899_EQUAI2 0xf4e2 +#define STB0899_EQUAQ2 0xf4e3 +#define STB0899_EQUAI3 0xf4e4 +#define STB0899_EQUAQ3 0xf4e5 +#define STB0899_EQUAI4 0xf4e6 +#define STB0899_EQUAQ4 0xf4e7 +#define STB0899_EQUAI5 0xf4e8 +#define STB0899_EQUAQ5 0xf4e9 + +#define STB0899_DSTATUS2 0xf50c +#define STB0899_DS2_TMG_AUTOSRCH (0x01 << 7) +#define STB8999_OFFST_DS2_TMG_AUTOSRCH 7 +#define STB0899_WIDTH_DS2_TMG_AUTOSRCH 1 +#define STB0899_DS2_END_MAINLOOP (0x01 << 6) +#define STB0899_OFFST_DS2_END_MAINLOOP 6 +#define STB0899_WIDTH_DS2_END_MAINLOOP 1 +#define STB0899_DS2_CFSYNC (0x01 << 5) +#define STB0899_OFFST_DS2_CFSYNC 5 +#define STB0899_WIDTH_DS2_CFSYNC 1 +#define STB0899_DS2_TMGLOCK (0x01 << 4) +#define STB0899_OFFST_DS2_TMGLOCK 4 +#define STB0899_WIDTH_DS2_TMGLOCK 1 +#define STB0899_DS2_DEMODWAIT (0x01 << 3) +#define STB0899_OFFST_DS2_DEMODWAIT 3 +#define STB0899_WIDTH_DS2_DEMODWAIT 1 +#define STB0899_DS2_FECON (0x01 << 1) +#define STB0899_OFFST_DS2_FECON 1 +#define STB0899_WIDTH_DS2_FECON 1 + +/* S1 FEC */ +#define STB0899_VSTATUS 0xf50d +#define STB0899_VSTATUS_VITERBI_ON (0x01 << 7) +#define STB0899_OFFST_VSTATUS_VITERBI_ON 7 +#define STB0899_WIDTH_VSTATUS_VITERBI_ON 1 +#define STB0899_VSTATUS_END_LOOPVIT (0x01 << 6) +#define STB0899_OFFST_VSTATUS_END_LOOPVIT 6 +#define STB0899_WIDTH_VSTATUS_END_LOOPVIT 1 +#define STB0899_VSTATUS_PRFVIT (0x01 << 4) +#define STB0899_OFFST_VSTATUS_PRFVIT 4 +#define STB0899_WIDTH_VSTATUS_PRFVIT 1 +#define STB0899_VSTATUS_LOCKEDVIT (0x01 << 3) +#define STB0899_OFFST_VSTATUS_LOCKEDVIT 3 +#define STB0899_WIDTH_VSTATUS_LOCKEDVIT 1 + +#define STB0899_VERROR 0xf50f + +#define STB0899_IQSWAP 0xf523 +#define STB0899_SYM (0x01 << 3) +#define STB0899_OFFST_SYM 3 +#define STB0899_WIDTH_SYM 1 + +#define STB0899_FECAUTO1 0xf530 +#define STB0899_DSSSRCH (0x01 << 3) +#define STB0899_OFFST_DSSSRCH 3 +#define STB0899_WIDTH_DSSSRCH 1 +#define STB0899_SYMSRCH (0x01 << 2) +#define STB0899_OFFST_SYMSRCH 2 +#define STB0899_WIDTH_SYMSRCH 1 +#define STB0899_QPSKSRCH (0x01 << 1) +#define STB0899_OFFST_QPSKSRCH 1 +#define STB0899_WIDTH_QPSKSRCH 1 +#define STB0899_BPSKSRCH (0x01 << 0) +#define STB0899_OFFST_BPSKSRCH 0 +#define STB0899_WIDTH_BPSKSRCH 1 + +#define STB0899_FECM 0xf533 +#define STB0899_FECM_NOT_DVB (0x01 << 7) +#define STB0899_OFFST_FECM_NOT_DVB 7 +#define STB0899_WIDTH_FECM_NOT_DVB 1 +#define STB0899_FECM_RSVD1 (0x07 << 4) +#define STB0899_OFFST_FECM_RSVD1 4 +#define STB0899_WIDTH_FECM_RSVD1 3 +#define STB0899_FECM_VITERBI_ON (0x01 << 3) +#define STB0899_OFFST_FECM_VITERBI_ON 3 +#define STB0899_WIDTH_FECM_VITERBI_ON 1 +#define STB0899_FECM_RSVD0 (0x01 << 2) +#define STB0899_OFFST_FECM_RSVD0 2 +#define STB0899_WIDTH_FECM_RSVD0 1 +#define STB0899_FECM_SYNCDIS (0x01 << 1) +#define STB0899_OFFST_FECM_SYNCDIS 1 +#define STB0899_WIDTH_FECM_SYNCDIS 1 +#define STB0899_FECM_SYMI (0x01 << 0) +#define STB0899_OFFST_FECM_SYMI 0 +#define STB0899_WIDTH_FECM_SYMI 1 + +#define STB0899_VTH12 0xf534 +#define STB0899_VTH23 0xf535 +#define STB0899_VTH34 0xf536 +#define STB0899_VTH56 0xf537 +#define STB0899_VTH67 0xf538 +#define STB0899_VTH78 0xf539 + +#define STB0899_PRVIT 0xf53c +#define STB0899_PR_7_8 (0x01 << 5) +#define STB0899_OFFST_PR_7_8 5 +#define STB0899_WIDTH_PR_7_8 1 +#define STB0899_PR_6_7 (0x01 << 4) +#define STB0899_OFFST_PR_6_7 4 +#define STB0899_WIDTH_PR_6_7 1 +#define STB0899_PR_5_6 (0x01 << 3) +#define STB0899_OFFST_PR_5_6 3 +#define STB0899_WIDTH_PR_5_6 1 +#define STB0899_PR_3_4 (0x01 << 2) +#define STB0899_OFFST_PR_3_4 2 +#define STB0899_WIDTH_PR_3_4 1 +#define STB0899_PR_2_3 (0x01 << 1) +#define STB0899_OFFST_PR_2_3 1 +#define STB0899_WIDTH_PR_2_3 1 +#define STB0899_PR_1_2 (0x01 << 0) +#define STB0899_OFFST_PR_1_2 0 +#define STB0899_WIDTH_PR_1_2 1 + +#define STB0899_VITSYNC 0xf53d +#define STB0899_AM (0x01 << 7) +#define STB0899_OFFST_AM 7 +#define STB0899_WIDTH_AM 1 +#define STB0899_FREEZE (0x01 << 6) +#define STB0899_OFFST_FREEZE 6 +#define STB0899_WIDTH_FREEZE 1 +#define STB0899_SN_65536 (0x03 << 4) +#define STB0899_OFFST_SN_65536 4 +#define STB0899_WIDTH_SN_65536 2 +#define STB0899_SN_16384 (0x01 << 5) +#define STB0899_OFFST_SN_16384 5 +#define STB0899_WIDTH_SN_16384 1 +#define STB0899_SN_4096 (0x01 << 4) +#define STB0899_OFFST_SN_4096 4 +#define STB0899_WIDTH_SN_4096 1 +#define STB0899_SN_1024 (0x00 << 4) +#define STB0899_OFFST_SN_1024 4 +#define STB0899_WIDTH_SN_1024 0 +#define STB0899_TO_128 (0x03 << 2) +#define STB0899_OFFST_TO_128 2 +#define STB0899_WIDTH_TO_128 2 +#define STB0899_TO_64 (0x01 << 3) +#define STB0899_OFFST_TO_64 3 +#define STB0899_WIDTH_TO_64 1 +#define STB0899_TO_32 (0x01 << 2) +#define STB0899_OFFST_TO_32 2 +#define STB0899_WIDTH_TO_32 1 +#define STB0899_TO_16 (0x00 << 2) +#define STB0899_OFFST_TO_16 2 +#define STB0899_WIDTH_TO_16 0 +#define STB0899_HYST_128 (0x03 << 1) +#define STB0899_OFFST_HYST_128 1 +#define STB0899_WIDTH_HYST_128 2 +#define STB0899_HYST_64 (0x01 << 1) +#define STB0899_OFFST_HYST_64 1 +#define STB0899_WIDTH_HYST_64 1 +#define STB0899_HYST_32 (0x01 << 0) +#define STB0899_OFFST_HYST_32 0 +#define STB0899_WIDTH_HYST_32 1 +#define STB0899_HYST_16 (0x00 << 0) +#define STB0899_OFFST_HYST_16 0 +#define STB0899_WIDTH_HYST_16 0 + +#define STB0899_RSULC 0xf548 +#define STB0899_ULDIL_ON (0x01 << 7) +#define STB0899_OFFST_ULDIL_ON 7 +#define STB0899_WIDTH_ULDIL_ON 1 +#define STB0899_ULAUTO_ON (0x01 << 6) +#define STB0899_OFFST_ULAUTO_ON 6 +#define STB0899_WIDTH_ULAUTO_ON 1 +#define STB0899_ULRS_ON (0x01 << 5) +#define STB0899_OFFST_ULRS_ON 5 +#define STB0899_WIDTH_ULRS_ON 1 +#define STB0899_ULDESCRAM_ON (0x01 << 4) +#define STB0899_OFFST_ULDESCRAM_ON 4 +#define STB0899_WIDTH_ULDESCRAM_ON 1 +#define STB0899_UL_DISABLE (0x01 << 2) +#define STB0899_OFFST_UL_DISABLE 2 +#define STB0899_WIDTH_UL_DISABLE 1 +#define STB0899_NOFTHRESHOLD (0x01 << 0) +#define STB0899_OFFST_NOFTHRESHOLD 0 +#define STB0899_WIDTH_NOFTHRESHOLD 1 + +#define STB0899_RSLLC 0xf54a +#define STB0899_DEMAPVIT 0xf583 +#define STB0899_DEMAPVIT_RSVD (0x01 << 7) +#define STB0899_OFFST_DEMAPVIT_RSVD 7 +#define STB0899_WIDTH_DEMAPVIT_RSVD 1 +#define STB0899_DEMAPVIT_KDIVIDER (0x7f << 0) +#define STB0899_OFFST_DEMAPVIT_KDIVIDER 0 +#define STB0899_WIDTH_DEMAPVIT_KDIVIDER 7 + +#define STB0899_PLPARM 0xf58c +#define STB0899_VITMAPPING (0x07 << 5) +#define STB0899_OFFST_VITMAPPING 5 +#define STB0899_WIDTH_VITMAPPING 3 +#define STB0899_VITMAPPING_BPSK (0x01 << 5) +#define STB0899_OFFST_VITMAPPING_BPSK 5 +#define STB0899_WIDTH_VITMAPPING_BPSK 1 +#define STB0899_VITMAPPING_QPSK (0x00 << 5) +#define STB0899_OFFST_VITMAPPING_QPSK 5 +#define STB0899_WIDTH_VITMAPPING_QPSK 0 +#define STB0899_VITCURPUN (0x1f << 0) +#define STB0899_OFFST_VITCURPUN 0 +#define STB0899_WIDTH_VITCURPUN 5 +#define STB0899_VITCURPUN_1_2 (0x0d << 0) +#define STB0899_VITCURPUN_2_3 (0x12 << 0) +#define STB0899_VITCURPUN_3_4 (0x15 << 0) +#define STB0899_VITCURPUN_5_6 (0x18 << 0) +#define STB0899_VITCURPUN_6_7 (0x19 << 0) +#define STB0899_VITCURPUN_7_8 (0x1a << 0) + +/* S2 DEMOD */ +#define STB0899_OFF0_DMD_STATUS 0xf300 +#define STB0899_BASE_DMD_STATUS 0x00000000 +#define STB0899_IF_AGC_LOCK (0x01 << 8) +#define STB0899_OFFST_IF_AGC_LOCK 0 +#define STB0899_WIDTH_IF_AGC_LOCK 1 + +#define STB0899_OFF0_CRL_FREQ 0xf304 +#define STB0899_BASE_CRL_FREQ 0x00000000 +#define STB0899_CARR_FREQ (0x3fffffff << 0) +#define STB0899_OFFST_CARR_FREQ 0 +#define STB0899_WIDTH_CARR_FREQ 30 + +#define STB0899_OFF0_BTR_FREQ 0xf308 +#define STB0899_BASE_BTR_FREQ 0x00000000 +#define STB0899_BTR_FREQ (0xfffffff << 0) +#define STB0899_OFFST_BTR_FREQ 0 +#define STB0899_WIDTH_BTR_FREQ 28 + +#define STB0899_OFF0_IF_AGC_GAIN 0xf30c +#define STB0899_BASE_IF_AGC_GAIN 0x00000000 +#define STB0899_IF_AGC_GAIN (0x3fff < 0) +#define STB0899_OFFST_IF_AGC_GAIN 0 +#define STB0899_WIDTH_IF_AGC_GAIN 14 + +#define STB0899_OFF0_BB_AGC_GAIN 0xf310 +#define STB0899_BASE_BB_AGC_GAIN 0x00000000 +#define STB0899_BB_AGC_GAIN (0x3fff < 0) +#define STB0899_OFFST_BB_AGC_GAIN 0 +#define STB0899_WIDTH_BB_AGC_GAIN 14 + +#define STB0899_OFF0_DC_OFFSET 0xf314 +#define STB0899_BASE_DC_OFFSET 0x00000000 +#define STB0899_I (0xff < 8) +#define STB0899_OFFST_I 8 +#define STB0899_WIDTH_I 8 +#define STB0899_Q (0xff < 0) +#define STB0899_OFFST_Q 8 +#define STB0899_WIDTH_Q 8 + +#define STB0899_OFF0_DMD_CNTRL 0xf31c +#define STB0899_BASE_DMD_CNTRL 0x00000000 +#define STB0899_ADC0_PINS1IN (0x01 << 6) +#define STB0899_OFFST_ADC0_PINS1IN 6 +#define STB0899_WIDTH_ADC0_PINS1IN 1 +#define STB0899_IN2COMP1_OFFBIN0 (0x01 << 3) +#define STB0899_OFFST_IN2COMP1_OFFBIN0 3 +#define STB0899_WIDTH_IN2COMP1_OFFBIN0 1 +#define STB0899_DC_COMP (0x01 << 2) +#define STB0899_OFFST_DC_COMP 2 +#define STB0899_WIDTH_DC_COMP 1 +#define STB0899_MODMODE (0x03 << 0) +#define STB0899_OFFST_MODMODE 0 +#define STB0899_WIDTH_MODMODE 2 + +#define STB0899_OFF0_IF_AGC_CNTRL 0xf320 +#define STB0899_BASE_IF_AGC_CNTRL 0x00000000 +#define STB0899_IF_GAIN_INIT (0x3fff << 13) +#define STB0899_OFFST_IF_GAIN_INIT 13 +#define STB0899_WIDTH_IF_GAIN_INIT 14 +#define STB0899_IF_GAIN_SENSE (0x01 << 12) +#define STB0899_OFFST_IF_GAIN_SENSE 12 +#define STB0899_WIDTH_IF_GAIN_SENSE 1 +#define STB0899_IF_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_IF_LOOP_GAIN 8 +#define STB0899_WIDTH_IF_LOOP_GAIN 4 +#define STB0899_IF_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_IF_LD_GAIN_INIT 7 +#define STB0899_WIDTH_IF_LD_GAIN_INIT 1 +#define STB0899_IF_AGC_REF (0x7f << 0) +#define STB0899_OFFST_IF_AGC_REF 0 +#define STB0899_WIDTH_IF_AGC_REF 7 + +#define STB0899_OFF0_BB_AGC_CNTRL 0xf324 +#define STB0899_BASE_BB_AGC_CNTRL 0x00000000 +#define STB0899_BB_GAIN_INIT (0x3fff << 12) +#define STB0899_OFFST_BB_GAIN_INIT 12 +#define STB0899_WIDTH_BB_GAIN_INIT 14 +#define STB0899_BB_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_BB_LOOP_GAIN 8 +#define STB0899_WIDTH_BB_LOOP_GAIN 4 +#define STB0899_BB_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_BB_LD_GAIN_INIT 7 +#define STB0899_WIDTH_BB_LD_GAIN_INIT 1 +#define STB0899_BB_AGC_REF (0x7f << 0) +#define STB0899_OFFST_BB_AGC_REF 0 +#define STB0899_WIDTH_BB_AGC_REF 7 + +#define STB0899_OFF0_CRL_CNTRL 0xf328 +#define STB0899_BASE_CRL_CNTRL 0x00000000 +#define STB0899_CRL_LOCK_CLEAR (0x01 << 5) +#define STB0899_OFFST_CRL_LOCK_CLEAR 5 +#define STB0899_WIDTH_CRL_LOCK_CLEAR 1 +#define STB0899_CRL_SWPR_CLEAR (0x01 << 4) +#define STB0899_OFFST_CRL_SWPR_CLEAR 4 +#define STB0899_WIDTH_CRL_SWPR_CLEAR 1 +#define STB0899_CRL_SWP_ENA (0x01 << 3) +#define STB0899_OFFST_CRL_SWP_ENA 3 +#define STB0899_WIDTH_CRL_SWP_ENA 1 +#define STB0899_CRL_DET_SEL (0x01 << 2) +#define STB0899_OFFST_CRL_DET_SEL 2 +#define STB0899_WIDTH_CRL_DET_SEL 1 +#define STB0899_CRL_SENSE (0x01 << 1) +#define STB0899_OFFST_CRL_SENSE 1 +#define STB0899_WIDTH_CRL_SENSE 1 +#define STB0899_CRL_PHSERR_CLEAR (0x01 << 0) +#define STB0899_OFFST_CRL_PHSERR_CLEAR 0 +#define STB0899_WIDTH_CRL_PHSERR_CLEAR 1 + +#define STB0899_OFF0_CRL_PHS_INIT 0xf32c +#define STB0899_BASE_CRL_PHS_INIT 0x00000000 +#define STB0899_CRL_PHS_INIT_31 (0x1 << 30) +#define STB0899_OFFST_CRL_PHS_INIT_31 30 +#define STB0899_WIDTH_CRL_PHS_INIT_31 1 +#define STB0899_CRL_LD_INIT_PHASE (0x1 << 24) +#define STB0899_OFFST_CRL_LD_INIT_PHASE 24 +#define STB0899_WIDTH_CRL_LD_INIT_PHASE 1 +#define STB0899_CRL_INIT_PHASE (0xffffff << 0) +#define STB0899_OFFST_CRL_INIT_PHASE 0 +#define STB0899_WIDTH_CRL_INIT_PHASE 24 + +#define STB0899_OFF0_CRL_FREQ_INIT 0xf330 +#define STB0899_BASE_CRL_FREQ_INIT 0x00000000 +#define STB0899_CRL_FREQ_INIT_31 (0x1 << 30) +#define STB0899_OFFST_CRL_FREQ_INIT_31 30 +#define STB0899_WIDTH_CRL_FREQ_INIT_31 1 +#define STB0899_CRL_LD_FREQ_INIT (0x1 << 24) +#define STB0899_OFFST_CRL_LD_FREQ_INIT 24 +#define STB0899_WIDTH_CRL_LD_FREQ_INIT 1 +#define STB0899_CRL_FREQ_INIT (0xffffff << 0) +#define STB0899_OFFST_CRL_FREQ_INIT 0 +#define STB0899_WIDTH_CRL_FREQ_INIT 24 + +#define STB0899_OFF0_CRL_LOOP_GAIN 0xf334 +#define STB0899_BASE_CRL_LOOP_GAIN 0x00000000 +#define STB0899_KCRL2_RSHFT (0xf << 16) +#define STB0899_OFFST_KCRL2_RSHFT 16 +#define STB0899_WIDTH_KCRL2_RSHFT 4 +#define STB0899_KCRL1 (0xf << 12) +#define STB0899_OFFST_KCRL1 12 +#define STB0899_WIDTH_KCRL1 4 +#define STB0899_KCRL1_RSHFT (0xf << 8) +#define STB0899_OFFST_KCRL1_RSHFT 8 +#define STB0899_WIDTH_KCRL1_RSHFT 4 +#define STB0899_KCRL0 (0xf << 4) +#define STB0899_OFFST_KCRL0 4 +#define STB0899_WIDTH_KCRL0 4 +#define STB0899_KCRL0_RSHFT (0xf << 0) +#define STB0899_OFFST_KCRL0_RSHFT 0 +#define STB0899_WIDTH_KCRL0_RSHFT 4 + +#define STB0899_OFF0_CRL_NOM_FREQ 0xf338 +#define STB0899_BASE_CRL_NOM_FREQ 0x00000000 +#define STB0899_CRL_NOM_FREQ (0x3fffffff << 0) +#define STB0899_OFFST_CRL_NOM_FREQ 0 +#define STB0899_WIDTH_CRL_NOM_FREQ 30 + +#define STB0899_OFF0_CRL_SWP_RATE 0xf33c +#define STB0899_BASE_CRL_SWP_RATE 0x00000000 +#define STB0899_CRL_SWP_RATE (0x3fffffff << 0) +#define STB0899_OFFST_CRL_SWP_RATE 0 +#define STB0899_WIDTH_CRL_SWP_RATE 30 + +#define STB0899_OFF0_CRL_MAX_SWP 0xf340 +#define STB0899_BASE_CRL_MAX_SWP 0x00000000 +#define STB0899_CRL_MAX_SWP (0x3fffffff << 0) +#define STB0899_OFFST_CRL_MAX_SWP 0 +#define STB0899_WIDTH_CRL_MAX_SWP 30 + +#define STB0899_OFF0_CRL_LK_CNTRL 0xf344 +#define STB0899_BASE_CRL_LK_CNTRL 0x00000000 + +#define STB0899_OFF0_DECIM_CNTRL 0xf348 +#define STB0899_BASE_DECIM_CNTRL 0x00000000 +#define STB0899_BAND_LIMIT_B (0x01 << 5) +#define STB0899_OFFST_BAND_LIMIT_B 5 +#define STB0899_WIDTH_BAND_LIMIT_B 1 +#define STB0899_WIN_SEL (0x03 << 3) +#define STB0899_OFFST_WIN_SEL 3 +#define STB0899_WIDTH_WIN_SEL 2 +#define STB0899_DECIM_RATE (0x07 << 0) +#define STB0899_OFFST_DECIM_RATE 0 +#define STB0899_WIDTH_DECIM_RATE 3 + +#define STB0899_OFF0_BTR_CNTRL 0xf34c +#define STB0899_BASE_BTR_CNTRL 0x00000000 +#define STB0899_BTR_FREQ_CORR (0x7ff << 4) +#define STB0899_OFFST_BTR_FREQ_CORR 4 +#define STB0899_WIDTH_BTR_FREQ_CORR 11 +#define STB0899_BTR_CLR_LOCK (0x01 << 3) +#define STB0899_OFFST_BTR_CLR_LOCK 3 +#define STB0899_WIDTH_BTR_CLR_LOCK 1 +#define STB0899_BTR_SENSE (0x01 << 2) +#define STB0899_OFFST_BTR_SENSE 2 +#define STB0899_WIDTH_BTR_SENSE 1 +#define STB0899_BTR_ERR_ENA (0x01 << 1) +#define STB0899_OFFST_BTR_ERR_ENA 1 +#define STB0899_WIDTH_BTR_ERR_ENA 1 +#define STB0899_INTRP_PHS_SENSE (0x01 << 0) +#define STB0899_OFFST_INTRP_PHS_SENSE 0 +#define STB0899_WIDTH_INTRP_PHS_SENSE 1 + +#define STB0899_OFF0_BTR_LOOP_GAIN 0xf350 +#define STB0899_BASE_BTR_LOOP_GAIN 0x00000000 +#define STB0899_KBTR2_RSHFT (0x0f << 16) +#define STB0899_OFFST_KBTR2_RSHFT 16 +#define STB0899_WIDTH_KBTR2_RSHFT 4 +#define STB0899_KBTR1 (0x0f << 12) +#define STB0899_OFFST_KBTR1 12 +#define STB0899_WIDTH_KBTR1 4 +#define STB0899_KBTR1_RSHFT (0x0f << 8) +#define STB0899_OFFST_KBTR1_RSHFT 8 +#define STB0899_WIDTH_KBTR1_RSHFT 4 +#define STB0899_KBTR0 (0x0f << 4) +#define STB0899_OFFST_KBTR0 4 +#define STB0899_WIDTH_KBTR0 4 +#define STB0899_KBTR0_RSHFT (0x0f << 0) +#define STB0899_OFFST_KBTR0_RSHFT 0 +#define STB0899_WIDTH_KBTR0_RSHFT 4 + +#define STB0899_OFF0_BTR_PHS_INIT 0xf354 +#define STB0899_BASE_BTR_PHS_INIT 0x00000000 +#define STB0899_BTR_LD_PHASE_INIT (0x01 << 28) +#define STB0899_OFFST_BTR_LD_PHASE_INIT 28 +#define STB0899_WIDTH_BTR_LD_PHASE_INIT 1 +#define STB0899_BTR_INIT_PHASE (0xfffffff << 0) +#define STB0899_OFFST_BTR_INIT_PHASE 0 +#define STB0899_WIDTH_BTR_INIT_PHASE 28 + +#define STB0899_OFF0_BTR_FREQ_INIT 0xf358 +#define STB0899_BASE_BTR_FREQ_INIT 0x00000000 +#define STB0899_BTR_LD_FREQ_INIT (1 << 28) +#define STB0899_OFFST_BTR_LD_FREQ_INIT 28 +#define STB0899_WIDTH_BTR_LD_FREQ_INIT 1 +#define STB0899_BTR_FREQ_INIT (0xfffffff << 0) +#define STB0899_OFFST_BTR_FREQ_INIT 0 +#define STB0899_WIDTH_BTR_FREQ_INIT 28 + +#define STB0899_OFF0_BTR_NOM_FREQ 0xf35c +#define STB0899_BASE_BTR_NOM_FREQ 0x00000000 +#define STB0899_BTR_NOM_FREQ (0xfffffff << 0) +#define STB0899_OFFST_BTR_NOM_FREQ 0 +#define STB0899_WIDTH_BTR_NOM_FREQ 28 + +#define STB0899_OFF0_BTR_LK_CNTRL 0xf360 +#define STB0899_BASE_BTR_LK_CNTRL 0x00000000 +#define STB0899_BTR_MIN_ENERGY (0x0f << 24) +#define STB0899_OFFST_BTR_MIN_ENERGY 24 +#define STB0899_WIDTH_BTR_MIN_ENERGY 4 +#define STB0899_BTR_LOCK_TH_LO (0xff << 16) +#define STB0899_OFFST_BTR_LOCK_TH_LO 16 +#define STB0899_WIDTH_BTR_LOCK_TH_LO 8 +#define STB0899_BTR_LOCK_TH_HI (0xff << 8) +#define STB0899_OFFST_BTR_LOCK_TH_HI 8 +#define STB0899_WIDTH_BTR_LOCK_TH_HI 8 +#define STB0899_BTR_LOCK_GAIN (0x03 << 6) +#define STB0899_OFFST_BTR_LOCK_GAIN 6 +#define STB0899_WIDTH_BTR_LOCK_GAIN 2 +#define STB0899_BTR_LOCK_LEAK (0x3f << 0) +#define STB0899_OFFST_BTR_LOCK_LEAK 0 +#define STB0899_WIDTH_BTR_LOCK_LEAK 6 + +#define STB0899_OFF0_DECN_CNTRL 0xf364 +#define STB0899_BASE_DECN_CNTRL 0x00000000 + +#define STB0899_OFF0_TP_CNTRL 0xf368 +#define STB0899_BASE_TP_CNTRL 0x00000000 + +#define STB0899_OFF0_TP_BUF_STATUS 0xf36c +#define STB0899_BASE_TP_BUF_STATUS 0x00000000 +#define STB0899_TP_BUFFER_FULL (1 << 0) + +#define STB0899_OFF0_DC_ESTIM 0xf37c +#define STB0899_BASE_DC_ESTIM 0x0000 +#define STB0899_I_DC_ESTIMATE (0xff << 8) +#define STB0899_OFFST_I_DC_ESTIMATE 8 +#define STB0899_WIDTH_I_DC_ESTIMATE 8 +#define STB0899_Q_DC_ESTIMATE (0xff << 0) +#define STB0899_OFFST_Q_DC_ESTIMATE 0 +#define STB0899_WIDTH_Q_DC_ESTIMATE 8 + +#define STB0899_OFF0_FLL_CNTRL 0xf310 +#define STB0899_BASE_FLL_CNTRL 0x00000020 +#define STB0899_CRL_FLL_ACC (0x01 << 4) +#define STB0899_OFFST_CRL_FLL_ACC 4 +#define STB0899_WIDTH_CRL_FLL_ACC 1 +#define STB0899_FLL_AVG_PERIOD (0x0f << 0) +#define STB0899_OFFST_FLL_AVG_PERIOD 0 +#define STB0899_WIDTH_FLL_AVG_PERIOD 4 + +#define STB0899_OFF0_FLL_FREQ_WD 0xf314 +#define STB0899_BASE_FLL_FREQ_WD 0x00000020 +#define STB0899_FLL_FREQ_WD (0xffffffff << 0) +#define STB0899_OFFST_FLL_FREQ_WD 0 +#define STB0899_WIDTH_FLL_FREQ_WD 32 + +#define STB0899_OFF0_ANTI_ALIAS_SEL 0xf358 +#define STB0899_BASE_ANTI_ALIAS_SEL 0x00000020 +#define STB0899_ANTI_ALIAS_SELB (0x03 << 0) +#define STB0899_OFFST_ANTI_ALIAS_SELB 0 +#define STB0899_WIDTH_ANTI_ALIAS_SELB 2 + +#define STB0899_OFF0_RRC_ALPHA 0xf35c +#define STB0899_BASE_RRC_ALPHA 0x00000020 +#define STB0899_RRC_ALPHA (0x03 << 0) +#define STB0899_OFFST_RRC_ALPHA 0 +#define STB0899_WIDTH_RRC_ALPHA 2 + +#define STB0899_OFF0_DC_ADAPT_LSHFT 0xf360 +#define STB0899_BASE_DC_ADAPT_LSHFT 0x00000020 +#define STB0899_DC_ADAPT_LSHFT (0x077 << 0) +#define STB0899_OFFST_DC_ADAPT_LSHFT 0 +#define STB0899_WIDTH_DC_ADAPT_LSHFT 3 + +#define STB0899_OFF0_IMB_OFFSET 0xf364 +#define STB0899_BASE_IMB_OFFSET 0x00000020 +#define STB0899_PHS_IMB_COMP (0xff << 8) +#define STB0899_OFFST_PHS_IMB_COMP 8 +#define STB0899_WIDTH_PHS_IMB_COMP 8 +#define STB0899_AMPL_IMB_COMP (0xff << 0) +#define STB0899_OFFST_AMPL_IMB_COMP 0 +#define STB0899_WIDTH_AMPL_IMB_COMP 8 + +#define STB0899_OFF0_IMB_ESTIMATE 0xf368 +#define STB0899_BASE_IMB_ESTIMATE 0x00000020 +#define STB0899_PHS_IMB_ESTIMATE (0xff << 8) +#define STB0899_OFFST_PHS_IMB_ESTIMATE 8 +#define STB0899_WIDTH_PHS_IMB_ESTIMATE 8 +#define STB0899_AMPL_IMB_ESTIMATE (0xff << 0) +#define STB0899_OFFST_AMPL_IMB_ESTIMATE 0 +#define STB0899_WIDTH_AMPL_IMB_ESTIMATE 8 + +#define STB0899_OFF0_IMB_CNTRL 0xf36c +#define STB0899_BASE_IMB_CNTRL 0x00000020 +#define STB0899_PHS_ADAPT_LSHFT (0x07 << 4) +#define STB0899_OFFST_PHS_ADAPT_LSHFT 4 +#define STB0899_WIDTH_PHS_ADAPT_LSHFT 3 +#define STB0899_AMPL_ADAPT_LSHFT (0x07 << 1) +#define STB0899_OFFST_AMPL_ADAPT_LSHFT 1 +#define STB0899_WIDTH_AMPL_ADAPT_LSHFT 3 +#define STB0899_IMB_COMP (0x01 << 0) +#define STB0899_OFFST_IMB_COMP 0 +#define STB0899_WIDTH_IMB_COMP 1 + +#define STB0899_OFF0_IF_AGC_CNTRL2 0xf374 +#define STB0899_BASE_IF_AGC_CNTRL2 0x00000020 +#define STB0899_IF_AGC_LOCK_TH (0xff << 11) +#define STB0899_OFFST_IF_AGC_LOCK_TH 11 +#define STB0899_WIDTH_IF_AGC_LOCK_TH 8 +#define STB0899_IF_AGC_SD_DIV (0xff << 3) +#define STB0899_OFFST_IF_AGC_SD_DIV 3 +#define STB0899_WIDTH_IF_AGC_SD_DIV 8 +#define STB0899_IF_AGC_DUMP_PER (0x07 << 0) +#define STB0899_OFFST_IF_AGC_DUMP_PER 0 +#define STB0899_WIDTH_IF_AGC_DUMP_PER 3 + +#define STB0899_OFF0_DMD_CNTRL2 0xf378 +#define STB0899_BASE_DMD_CNTRL2 0x00000020 +#define STB0899_SPECTRUM_INVERT (0x01 << 2) +#define STB0899_OFFST_SPECTRUM_INVERT 2 +#define STB0899_WIDTH_SPECTRUM_INVERT 1 +#define STB0899_AGC_MODE (0x01 << 1) +#define STB0899_OFFST_AGC_MODE 1 +#define STB0899_WIDTH_AGC_MODE 1 +#define STB0899_CRL_FREQ_ADJ (0x01 << 0) +#define STB0899_OFFST_CRL_FREQ_ADJ 0 +#define STB0899_WIDTH_CRL_FREQ_ADJ 1 + +#define STB0899_OFF0_TP_BUFFER 0xf300 +#define STB0899_BASE_TP_BUFFER 0x00000040 +#define STB0899_TP_BUFFER_IN (0xffff << 0) +#define STB0899_OFFST_TP_BUFFER_IN 0 +#define STB0899_WIDTH_TP_BUFFER_IN 16 + +#define STB0899_OFF0_TP_BUFFER1 0xf304 +#define STB0899_BASE_TP_BUFFER1 0x00000040 +#define STB0899_OFF0_TP_BUFFER2 0xf308 +#define STB0899_BASE_TP_BUFFER2 0x00000040 +#define STB0899_OFF0_TP_BUFFER3 0xf30c +#define STB0899_BASE_TP_BUFFER3 0x00000040 +#define STB0899_OFF0_TP_BUFFER4 0xf310 +#define STB0899_BASE_TP_BUFFER4 0x00000040 +#define STB0899_OFF0_TP_BUFFER5 0xf314 +#define STB0899_BASE_TP_BUFFER5 0x00000040 +#define STB0899_OFF0_TP_BUFFER6 0xf318 +#define STB0899_BASE_TP_BUFFER6 0x00000040 +#define STB0899_OFF0_TP_BUFFER7 0xf31c +#define STB0899_BASE_TP_BUFFER7 0x00000040 +#define STB0899_OFF0_TP_BUFFER8 0xf320 +#define STB0899_BASE_TP_BUFFER8 0x00000040 +#define STB0899_OFF0_TP_BUFFER9 0xf324 +#define STB0899_BASE_TP_BUFFER9 0x00000040 +#define STB0899_OFF0_TP_BUFFER10 0xf328 +#define STB0899_BASE_TP_BUFFER10 0x00000040 +#define STB0899_OFF0_TP_BUFFER11 0xf32c +#define STB0899_BASE_TP_BUFFER11 0x00000040 +#define STB0899_OFF0_TP_BUFFER12 0xf330 +#define STB0899_BASE_TP_BUFFER12 0x00000040 +#define STB0899_OFF0_TP_BUFFER13 0xf334 +#define STB0899_BASE_TP_BUFFER13 0x00000040 +#define STB0899_OFF0_TP_BUFFER14 0xf338 +#define STB0899_BASE_TP_BUFFER14 0x00000040 +#define STB0899_OFF0_TP_BUFFER15 0xf33c +#define STB0899_BASE_TP_BUFFER15 0x00000040 +#define STB0899_OFF0_TP_BUFFER16 0xf340 +#define STB0899_BASE_TP_BUFFER16 0x00000040 +#define STB0899_OFF0_TP_BUFFER17 0xf344 +#define STB0899_BASE_TP_BUFFER17 0x00000040 +#define STB0899_OFF0_TP_BUFFER18 0xf348 +#define STB0899_BASE_TP_BUFFER18 0x00000040 +#define STB0899_OFF0_TP_BUFFER19 0xf34c +#define STB0899_BASE_TP_BUFFER19 0x00000040 +#define STB0899_OFF0_TP_BUFFER20 0xf350 +#define STB0899_BASE_TP_BUFFER20 0x00000040 +#define STB0899_OFF0_TP_BUFFER21 0xf354 +#define STB0899_BASE_TP_BUFFER21 0x00000040 +#define STB0899_OFF0_TP_BUFFER22 0xf358 +#define STB0899_BASE_TP_BUFFER22 0x00000040 +#define STB0899_OFF0_TP_BUFFER23 0xf35c +#define STB0899_BASE_TP_BUFFER23 0x00000040 +#define STB0899_OFF0_TP_BUFFER24 0xf360 +#define STB0899_BASE_TP_BUFFER24 0x00000040 +#define STB0899_OFF0_TP_BUFFER25 0xf364 +#define STB0899_BASE_TP_BUFFER25 0x00000040 +#define STB0899_OFF0_TP_BUFFER26 0xf368 +#define STB0899_BASE_TP_BUFFER26 0x00000040 +#define STB0899_OFF0_TP_BUFFER27 0xf36c +#define STB0899_BASE_TP_BUFFER27 0x00000040 +#define STB0899_OFF0_TP_BUFFER28 0xf370 +#define STB0899_BASE_TP_BUFFER28 0x00000040 +#define STB0899_OFF0_TP_BUFFER29 0xf374 +#define STB0899_BASE_TP_BUFFER29 0x00000040 +#define STB0899_OFF0_TP_BUFFER30 0xf378 +#define STB0899_BASE_TP_BUFFER30 0x00000040 +#define STB0899_OFF0_TP_BUFFER31 0xf37c +#define STB0899_BASE_TP_BUFFER31 0x00000040 +#define STB0899_OFF0_TP_BUFFER32 0xf300 +#define STB0899_BASE_TP_BUFFER32 0x00000060 +#define STB0899_OFF0_TP_BUFFER33 0xf304 +#define STB0899_BASE_TP_BUFFER33 0x00000060 +#define STB0899_OFF0_TP_BUFFER34 0xf308 +#define STB0899_BASE_TP_BUFFER34 0x00000060 +#define STB0899_OFF0_TP_BUFFER35 0xf30c +#define STB0899_BASE_TP_BUFFER35 0x00000060 +#define STB0899_OFF0_TP_BUFFER36 0xf310 +#define STB0899_BASE_TP_BUFFER36 0x00000060 +#define STB0899_OFF0_TP_BUFFER37 0xf314 +#define STB0899_BASE_TP_BUFFER37 0x00000060 +#define STB0899_OFF0_TP_BUFFER38 0xf318 +#define STB0899_BASE_TP_BUFFER38 0x00000060 +#define STB0899_OFF0_TP_BUFFER39 0xf31c +#define STB0899_BASE_TP_BUFFER39 0x00000060 +#define STB0899_OFF0_TP_BUFFER40 0xf320 +#define STB0899_BASE_TP_BUFFER40 0x00000060 +#define STB0899_OFF0_TP_BUFFER41 0xf324 +#define STB0899_BASE_TP_BUFFER41 0x00000060 +#define STB0899_OFF0_TP_BUFFER42 0xf328 +#define STB0899_BASE_TP_BUFFER42 0x00000060 +#define STB0899_OFF0_TP_BUFFER43 0xf32c +#define STB0899_BASE_TP_BUFFER43 0x00000060 +#define STB0899_OFF0_TP_BUFFER44 0xf330 +#define STB0899_BASE_TP_BUFFER44 0x00000060 +#define STB0899_OFF0_TP_BUFFER45 0xf334 +#define STB0899_BASE_TP_BUFFER45 0x00000060 +#define STB0899_OFF0_TP_BUFFER46 0xf338 +#define STB0899_BASE_TP_BUFFER46 0x00000060 +#define STB0899_OFF0_TP_BUFFER47 0xf33c +#define STB0899_BASE_TP_BUFFER47 0x00000060 +#define STB0899_OFF0_TP_BUFFER48 0xf340 +#define STB0899_BASE_TP_BUFFER48 0x00000060 +#define STB0899_OFF0_TP_BUFFER49 0xf344 +#define STB0899_BASE_TP_BUFFER49 0x00000060 +#define STB0899_OFF0_TP_BUFFER50 0xf348 +#define STB0899_BASE_TP_BUFFER50 0x00000060 +#define STB0899_OFF0_TP_BUFFER51 0xf34c +#define STB0899_BASE_TP_BUFFER51 0x00000060 +#define STB0899_OFF0_TP_BUFFER52 0xf350 +#define STB0899_BASE_TP_BUFFER52 0x00000060 +#define STB0899_OFF0_TP_BUFFER53 0xf354 +#define STB0899_BASE_TP_BUFFER53 0x00000060 +#define STB0899_OFF0_TP_BUFFER54 0xf358 +#define STB0899_BASE_TP_BUFFER54 0x00000060 +#define STB0899_OFF0_TP_BUFFER55 0xf35c +#define STB0899_BASE_TP_BUFFER55 0x00000060 +#define STB0899_OFF0_TP_BUFFER56 0xf360 +#define STB0899_BASE_TP_BUFFER56 0x00000060 +#define STB0899_OFF0_TP_BUFFER57 0xf364 +#define STB0899_BASE_TP_BUFFER57 0x00000060 +#define STB0899_OFF0_TP_BUFFER58 0xf368 +#define STB0899_BASE_TP_BUFFER58 0x00000060 +#define STB0899_OFF0_TP_BUFFER59 0xf36c +#define STB0899_BASE_TP_BUFFER59 0x00000060 +#define STB0899_OFF0_TP_BUFFER60 0xf370 +#define STB0899_BASE_TP_BUFFER60 0x00000060 +#define STB0899_OFF0_TP_BUFFER61 0xf374 +#define STB0899_BASE_TP_BUFFER61 0x00000060 +#define STB0899_OFF0_TP_BUFFER62 0xf378 +#define STB0899_BASE_TP_BUFFER62 0x00000060 +#define STB0899_OFF0_TP_BUFFER63 0xf37c +#define STB0899_BASE_TP_BUFFER63 0x00000060 + +#define STB0899_OFF0_RESET_CNTRL 0xf300 +#define STB0899_BASE_RESET_CNTRL 0x00000400 +#define STB0899_DVBS2_RESET (0x01 << 0) +#define STB0899_OFFST_DVBS2_RESET 0 +#define STB0899_WIDTH_DVBS2_RESET 1 + +#define STB0899_OFF0_ACM_ENABLE 0xf304 +#define STB0899_BASE_ACM_ENABLE 0x00000400 +#define STB0899_ACM_ENABLE 1 + +#define STB0899_OFF0_DESCR_CNTRL 0xf30c +#define STB0899_BASE_DESCR_CNTRL 0x00000400 +#define STB0899_OFFST_DESCR_CNTRL 0 +#define STB0899_WIDTH_DESCR_CNTRL 16 + +#define STB0899_OFF0_UWP_CNTRL1 0xf320 +#define STB0899_BASE_UWP_CNTRL1 0x00000400 +#define STB0899_UWP_TH_SOF (0x7fff << 11) +#define STB0899_OFFST_UWP_TH_SOF 11 +#define STB0899_WIDTH_UWP_TH_SOF 15 +#define STB0899_UWP_ESN0_QUANT (0xff << 3) +#define STB0899_OFFST_UWP_ESN0_QUANT 3 +#define STB0899_WIDTH_UWP_ESN0_QUANT 8 +#define STB0899_UWP_ESN0_AVE (0x03 << 1) +#define STB0899_OFFST_UWP_ESN0_AVE 1 +#define STB0899_WIDTH_UWP_ESN0_AVE 2 +#define STB0899_UWP_START (0x01 << 0) +#define STB0899_OFFST_UWP_START 0 +#define STB0899_WIDTH_UWP_START 1 + +#define STB0899_OFF0_UWP_CNTRL2 0xf324 +#define STB0899_BASE_UWP_CNTRL2 0x00000400 +#define STB0899_UWP_MISS_TH (0xff << 16) +#define STB0899_OFFST_UWP_MISS_TH 16 +#define STB0899_WIDTH_UWP_MISS_TH 8 +#define STB0899_FE_FINE_TRK (0xff << 8) +#define STB0899_OFFST_FE_FINE_TRK 8 +#define STB0899_WIDTH_FE_FINE_TRK 8 +#define STB0899_FE_COARSE_TRK (0xff << 0) +#define STB0899_OFFST_FE_COARSE_TRK 0 +#define STB0899_WIDTH_FE_COARSE_TRK 8 + +#define STB0899_OFF0_UWP_STAT1 0xf328 +#define STB0899_BASE_UWP_STAT1 0x00000400 +#define STB0899_UWP_STATE (0x03ff << 15) +#define STB0899_OFFST_UWP_STATE 15 +#define STB0899_WIDTH_UWP_STATE 10 +#define STB0899_UW_MAX_PEAK (0x7fff << 0) +#define STB0899_OFFST_UW_MAX_PEAK 0 +#define STB0899_WIDTH_UW_MAX_PEAK 15 + +#define STB0899_OFF0_UWP_STAT2 0xf32c +#define STB0899_BASE_UWP_STAT2 0x00000400 +#define STB0899_ESNO_EST (0x07ffff << 7) +#define STB0899_OFFST_ESN0_EST 7 +#define STB0899_WIDTH_ESN0_EST 19 +#define STB0899_UWP_DECODE_MOD (0x7f << 0) +#define STB0899_OFFST_UWP_DECODE_MOD 0 +#define STB0899_WIDTH_UWP_DECODE_MOD 7 + +#define STB0899_OFF0_DMD_CORE_ID 0xf334 +#define STB0899_BASE_DMD_CORE_ID 0x00000400 +#define STB0899_CORE_ID (0xffffffff << 0) +#define STB0899_OFFST_CORE_ID 0 +#define STB0899_WIDTH_CORE_ID 32 + +#define STB0899_OFF0_DMD_VERSION_ID 0xf33c +#define STB0899_BASE_DMD_VERSION_ID 0x00000400 +#define STB0899_VERSION_ID (0xff << 0) +#define STB0899_OFFST_VERSION_ID 0 +#define STB0899_WIDTH_VERSION_ID 8 + +#define STB0899_OFF0_DMD_STAT2 0xf340 +#define STB0899_BASE_DMD_STAT2 0x00000400 +#define STB0899_CSM_LOCK (0x01 << 1) +#define STB0899_OFFST_CSM_LOCK 1 +#define STB0899_WIDTH_CSM_LOCK 1 +#define STB0899_UWP_LOCK (0x01 << 0) +#define STB0899_OFFST_UWP_LOCK 0 +#define STB0899_WIDTH_UWP_LOCK 1 + +#define STB0899_OFF0_FREQ_ADJ_SCALE 0xf344 +#define STB0899_BASE_FREQ_ADJ_SCALE 0x00000400 +#define STB0899_FREQ_ADJ_SCALE (0x0fff << 0) +#define STB0899_OFFST_FREQ_ADJ_SCALE 0 +#define STB0899_WIDTH_FREQ_ADJ_SCALE 12 + +#define STB0899_OFF0_UWP_CNTRL3 0xf34c +#define STB0899_BASE_UWP_CNTRL3 0x00000400 +#define STB0899_UWP_TH_TRACK (0x7fff << 15) +#define STB0899_OFFST_UWP_TH_TRACK 15 +#define STB0899_WIDTH_UWP_TH_TRACK 15 +#define STB0899_UWP_TH_ACQ (0x7fff << 0) +#define STB0899_OFFST_UWP_TH_ACQ 0 +#define STB0899_WIDTH_UWP_TH_ACQ 15 + +#define STB0899_OFF0_SYM_CLK_SEL 0xf350 +#define STB0899_BASE_SYM_CLK_SEL 0x00000400 +#define STB0899_SYM_CLK_SEL (0x03 << 0) +#define STB0899_OFFST_SYM_CLK_SEL 0 +#define STB0899_WIDTH_SYM_CLK_SEL 2 + +#define STB0899_OFF0_SOF_SRCH_TO 0xf354 +#define STB0899_BASE_SOF_SRCH_TO 0x00000400 +#define STB0899_SOF_SEARCH_TIMEOUT (0x3fffff << 0) +#define STB0899_OFFST_SOF_SEARCH_TIMEOUT 0 +#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT 22 + +#define STB0899_OFF0_ACQ_CNTRL1 0xf358 +#define STB0899_BASE_ACQ_CNTRL1 0x00000400 +#define STB0899_FE_FINE_ACQ (0xff << 8) +#define STB0899_OFFST_FE_FINE_ACQ 8 +#define STB0899_WIDTH_FE_FINE_ACQ 8 +#define STB0899_FE_COARSE_ACQ (0xff << 0) +#define STB0899_OFFST_FE_COARSE_ACQ 0 +#define STB0899_WIDTH_FE_COARSE_ACQ 8 + +#define STB0899_OFF0_ACQ_CNTRL2 0xf35c +#define STB0899_BASE_ACQ_CNTRL2 0x00000400 +#define STB0899_ZIGZAG (0x01 << 25) +#define STB0899_OFFST_ZIGZAG 25 +#define STB0899_WIDTH_ZIGZAG 1 +#define STB0899_NUM_STEPS (0xff << 17) +#define STB0899_OFFST_NUM_STEPS 17 +#define STB0899_WIDTH_NUM_STEPS 8 +#define STB0899_FREQ_STEPSIZE (0x1ffff << 0) +#define STB0899_OFFST_FREQ_STEPSIZE 0 +#define STB0899_WIDTH_FREQ_STEPSIZE 17 + +#define STB0899_OFF0_ACQ_CNTRL3 0xf360 +#define STB0899_BASE_ACQ_CNTRL3 0x00000400 +#define STB0899_THRESHOLD_SCL (0x3f << 23) +#define STB0899_OFFST_THRESHOLD_SCL 23 +#define STB0899_WIDTH_THRESHOLD_SCL 6 +#define STB0899_UWP_TH_SRCH (0x7fff << 8) +#define STB0899_OFFST_UWP_TH_SRCH 8 +#define STB0899_WIDTH_UWP_TH_SRCH 15 +#define STB0899_AUTO_REACQUIRE (0x01 << 7) +#define STB0899_OFFST_AUTO_REACQUIRE 7 +#define STB0899_WIDTH_AUTO_REACQUIRE 1 +#define STB0899_TRACK_LOCK_SEL (0x01 << 6) +#define STB0899_OFFST_TRACK_LOCK_SEL 6 +#define STB0899_WIDTH_TRACK_LOCK_SEL 1 +#define STB0899_ACQ_SEARCH_MODE (0x03 << 4) +#define STB0899_OFFST_ACQ_SEARCH_MODE 4 +#define STB0899_WIDTH_ACQ_SEARCH_MODE 2 +#define STB0899_CONFIRM_FRAMES (0x0f << 0) +#define STB0899_OFFST_CONFIRM_FRAMES 0 +#define STB0899_WIDTH_CONFIRM_FRAMES 4 + +#define STB0899_OFF0_FE_SETTLE 0xf364 +#define STB0899_BASE_FE_SETTLE 0x00000400 +#define STB0899_SETTLING_TIME (0x3fffff << 0) +#define STB0899_OFFST_SETTLING_TIME 0 +#define STB0899_WIDTH_SETTLING_TIME 22 + +#define STB0899_OFF0_AC_DWELL 0xf368 +#define STB0899_BASE_AC_DWELL 0x00000400 +#define STB0899_DWELL_TIME (0x3fffff << 0) +#define STB0899_OFFST_DWELL_TIME 0 +#define STB0899_WIDTH_DWELL_TIME 22 + +#define STB0899_OFF0_ACQUIRE_TRIG 0xf36c +#define STB0899_BASE_ACQUIRE_TRIG 0x00000400 +#define STB0899_ACQUIRE (0x01 << 0) +#define STB0899_OFFST_ACQUIRE 0 +#define STB0899_WIDTH_ACQUIRE 1 + +#define STB0899_OFF0_LOCK_LOST 0xf370 +#define STB0899_BASE_LOCK_LOST 0x00000400 +#define STB0899_LOCK_LOST (0x01 << 0) +#define STB0899_OFFST_LOCK_LOST 0 +#define STB0899_WIDTH_LOCK_LOST 1 + +#define STB0899_OFF0_ACQ_STAT1 0xf374 +#define STB0899_BASE_ACQ_STAT1 0x00000400 +#define STB0899_STEP_FREQ (0x1fffff << 11) +#define STB0899_OFFST_STEP_FREQ 11 +#define STB0899_WIDTH_STEP_FREQ 21 +#define STB0899_ACQ_STATE (0x07 << 8) +#define STB0899_OFFST_ACQ_STATE 8 +#define STB0899_WIDTH_ACQ_STATE 3 +#define STB0899_UW_DETECT_COUNT (0xff << 0) +#define STB0899_OFFST_UW_DETECT_COUNT 0 +#define STB0899_WIDTH_UW_DETECT_COUNT 8 + +#define STB0899_OFF0_ACQ_TIMEOUT 0xf378 +#define STB0899_BASE_ACQ_TIMEOUT 0x00000400 +#define STB0899_ACQ_TIMEOUT (0x3fffff << 0) +#define STB0899_OFFST_ACQ_TIMEOUT 0 +#define STB0899_WIDTH_ACQ_TIMEOUT 22 + +#define STB0899_OFF0_ACQ_TIME 0xf37c +#define STB0899_BASE_ACQ_TIME 0x00000400 +#define STB0899_ACQ_TIME_SYM (0xffffff << 0) +#define STB0899_OFFST_ACQ_TIME_SYM 0 +#define STB0899_WIDTH_ACQ_TIME_SYM 24 + +#define STB0899_OFF0_FINAL_AGC_CNTRL 0xf308 +#define STB0899_BASE_FINAL_AGC_CNTRL 0x00000440 +#define STB0899_FINAL_GAIN_INIT (0x3fff << 12) +#define STB0899_OFFST_FINAL_GAIN_INIT 12 +#define STB0899_WIDTH_FINAL_GAIN_INIT 14 +#define STB0899_FINAL_LOOP_GAIN (0x0f << 8) +#define STB0899_OFFST_FINAL_LOOP_GAIN 8 +#define STB0899_WIDTH_FINAL_LOOP_GAIN 4 +#define STB0899_FINAL_LD_GAIN_INIT (0x01 << 7) +#define STB0899_OFFST_FINAL_LD_GAIN_INIT 7 +#define STB0899_WIDTH_FINAL_LD_GAIN_INIT 1 +#define STB0899_FINAL_AGC_REF (0x7f << 0) +#define STB0899_OFFST_FINAL_AGC_REF 0 +#define STB0899_WIDTH_FINAL_AGC_REF 7 + +#define STB0899_OFF0_FINAL_AGC_GAIN 0xf30c +#define STB0899_BASE_FINAL_AGC_GAIN 0x00000440 +#define STB0899_FINAL_AGC_GAIN (0x3fff << 0) +#define STB0899_OFFST_FINAL_AGC_GAIN 0 +#define STB0899_WIDTH_FINAL_AGC_GAIN 14 + +#define STB0899_OFF0_EQUALIZER_INIT 0xf310 +#define STB0899_BASE_EQUALIZER_INIT 0x00000440 +#define STB0899_EQ_SRST (0x01 << 1) +#define STB0899_OFFST_EQ_SRST 1 +#define STB0899_WIDTH_EQ_SRST 1 +#define STB0899_EQ_INIT (0x01 << 0) +#define STB0899_OFFST_EQ_INIT 0 +#define STB0899_WIDTH_EQ_INIT 1 + +#define STB0899_OFF0_EQ_CNTRL 0xf314 +#define STB0899_BASE_EQ_CNTRL 0x00000440 +#define STB0899_EQ_ADAPT_MODE (0x01 << 18) +#define STB0899_OFFST_EQ_ADAPT_MODE 18 +#define STB0899_WIDTH_EQ_ADAPT_MODE 1 +#define STB0899_EQ_DELAY (0x0f << 14) +#define STB0899_OFFST_EQ_DELAY 14 +#define STB0899_WIDTH_EQ_DELAY 4 +#define STB0899_EQ_QUANT_LEVEL (0xff << 6) +#define STB0899_OFFST_EQ_QUANT_LEVEL 6 +#define STB0899_WIDTH_EQ_QUANT_LEVEL 8 +#define STB0899_EQ_DISABLE_UPDATE (0x01 << 5) +#define STB0899_OFFST_EQ_DISABLE_UPDATE 5 +#define STB0899_WIDTH_EQ_DISABLE_UPDATE 1 +#define STB0899_EQ_BYPASS (0x01 << 4) +#define STB0899_OFFST_EQ_BYPASS 4 +#define STB0899_WIDTH_EQ_BYPASS 1 +#define STB0899_EQ_SHIFT (0x0f << 0) +#define STB0899_OFFST_EQ_SHIFT 0 +#define STB0899_WIDTH_EQ_SHIFT 4 + +#define STB0899_OFF0_EQ_I_INIT_COEFF_0 0xf320 +#define STB0899_OFF1_EQ_I_INIT_COEFF_1 0xf324 +#define STB0899_OFF2_EQ_I_INIT_COEFF_2 0xf328 +#define STB0899_OFF3_EQ_I_INIT_COEFF_3 0xf32c +#define STB0899_OFF4_EQ_I_INIT_COEFF_4 0xf330 +#define STB0899_OFF5_EQ_I_INIT_COEFF_5 0xf334 +#define STB0899_OFF6_EQ_I_INIT_COEFF_6 0xf338 +#define STB0899_OFF7_EQ_I_INIT_COEFF_7 0xf33c +#define STB0899_OFF8_EQ_I_INIT_COEFF_8 0xf340 +#define STB0899_OFF9_EQ_I_INIT_COEFF_9 0xf344 +#define STB0899_OFFa_EQ_I_INIT_COEFF_10 0xf348 +#define STB0899_BASE_EQ_I_INIT_COEFF_N 0x00000440 +#define STB0899_EQ_I_INIT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_I_INIT_COEFF_N 0 +#define STB0899_WIDTH_EQ_I_INIT_COEFF_N 12 + +#define STB0899_OFF0_EQ_Q_INIT_COEFF_0 0xf350 +#define STB0899_OFF1_EQ_Q_INIT_COEFF_1 0xf354 +#define STB0899_OFF2_EQ_Q_INIT_COEFF_2 0xf358 +#define STB0899_OFF3_EQ_Q_INIT_COEFF_3 0xf35c +#define STB0899_OFF4_EQ_Q_INIT_COEFF_4 0xf360 +#define STB0899_OFF5_EQ_Q_INIT_COEFF_5 0xf364 +#define STB0899_OFF6_EQ_Q_INIT_COEFF_6 0xf368 +#define STB0899_OFF7_EQ_Q_INIT_COEFF_7 0xf36c +#define STB0899_OFF8_EQ_Q_INIT_COEFF_8 0xf370 +#define STB0899_OFF9_EQ_Q_INIT_COEFF_9 0xf374 +#define STB0899_OFFa_EQ_Q_INIT_COEFF_10 0xf378 +#define STB0899_BASE_EQ_Q_INIT_COEFF_N 0x00000440 +#define STB0899_EQ_Q_INIT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_Q_INIT_COEFF_N 0 +#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N 12 + +#define STB0899_OFF0_EQ_I_OUT_COEFF_0 0xf300 +#define STB0899_OFF1_EQ_I_OUT_COEFF_1 0xf304 +#define STB0899_OFF2_EQ_I_OUT_COEFF_2 0xf308 +#define STB0899_OFF3_EQ_I_OUT_COEFF_3 0xf30c +#define STB0899_OFF4_EQ_I_OUT_COEFF_4 0xf310 +#define STB0899_OFF5_EQ_I_OUT_COEFF_5 0xf314 +#define STB0899_OFF6_EQ_I_OUT_COEFF_6 0xf318 +#define STB0899_OFF7_EQ_I_OUT_COEFF_7 0xf31c +#define STB0899_OFF8_EQ_I_OUT_COEFF_8 0xf320 +#define STB0899_OFF9_EQ_I_OUT_COEFF_9 0xf324 +#define STB0899_OFFa_EQ_I_OUT_COEFF_10 0xf328 +#define STB0899_BASE_EQ_I_OUT_COEFF_N 0x00000460 +#define STB0899_EQ_I_OUT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_I_OUT_COEFF_N 0 +#define STB0899_WIDTH_EQ_I_OUT_COEFF_N 12 + +#define STB0899_OFF0_EQ_Q_OUT_COEFF_0 0xf330 +#define STB0899_OFF1_EQ_Q_OUT_COEFF_1 0xf334 +#define STB0899_OFF2_EQ_Q_OUT_COEFF_2 0xf338 +#define STB0899_OFF3_EQ_Q_OUT_COEFF_3 0xf33c +#define STB0899_OFF4_EQ_Q_OUT_COEFF_4 0xf340 +#define STB0899_OFF5_EQ_Q_OUT_COEFF_5 0xf344 +#define STB0899_OFF6_EQ_Q_OUT_COEFF_6 0xf348 +#define STB0899_OFF7_EQ_Q_OUT_COEFF_7 0xf34c +#define STB0899_OFF8_EQ_Q_OUT_COEFF_8 0xf350 +#define STB0899_OFF9_EQ_Q_OUT_COEFF_9 0xf354 +#define STB0899_OFFa_EQ_Q_OUT_COEFF_10 0xf358 +#define STB0899_BASE_EQ_Q_OUT_COEFF_N 0x00000460 +#define STB0899_EQ_Q_OUT_COEFF_N (0x0fff << 0) +#define STB0899_OFFST_EQ_Q_OUT_COEFF_N 0 +#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N 12 + +/* S2 FEC */ +#define STB0899_OFF0_BLOCK_LNGTH 0xfa04 +#define STB0899_BASE_BLOCK_LNGTH 0x00000000 +#define STB0899_BLOCK_LENGTH (0xff << 0) +#define STB0899_OFFST_BLOCK_LENGTH 0 +#define STB0899_WIDTH_BLOCK_LENGTH 8 + +#define STB0899_OFF0_ROW_STR 0xfa08 +#define STB0899_BASE_ROW_STR 0x00000000 +#define STB0899_ROW_STRIDE (0xff << 0) +#define STB0899_OFFST_ROW_STRIDE 0 +#define STB0899_WIDTH_ROW_STRIDE 8 + +#define STB0899_OFF0_MAX_ITER 0xfa0c +#define STB0899_BASE_MAX_ITER 0x00000000 +#define STB0899_MAX_ITERATIONS (0xff << 0) +#define STB0899_OFFST_MAX_ITERATIONS 0 +#define STB0899_WIDTH_MAX_ITERATIONS 8 + +#define STB0899_OFF0_BN_END_ADDR 0xfa10 +#define STB0899_BASE_BN_END_ADDR 0x00000000 +#define STB0899_BN_END_ADDR (0x0fff << 0) +#define STB0899_OFFST_BN_END_ADDR 0 +#define STB0899_WIDTH_BN_END_ADDR 12 + +#define STB0899_OFF0_CN_END_ADDR 0xfa14 +#define STB0899_BASE_CN_END_ADDR 0x00000000 +#define STB0899_CN_END_ADDR (0x0fff << 0) +#define STB0899_OFFST_CN_END_ADDR 0 +#define STB0899_WIDTH_CN_END_ADDR 12 + +#define STB0899_OFF0_INFO_LENGTH 0xfa1c +#define STB0899_BASE_INFO_LENGTH 0x00000000 +#define STB0899_INFO_LENGTH (0xff << 0) +#define STB0899_OFFST_INFO_LENGTH 0 +#define STB0899_WIDTH_INFO_LENGTH 8 + +#define STB0899_OFF0_BOT_ADDR 0xfa20 +#define STB0899_BASE_BOT_ADDR 0x00000000 +#define STB0899_BOTTOM_BASE_ADDR (0x03ff << 0) +#define STB0899_OFFST_BOTTOM_BASE_ADDR 0 +#define STB0899_WIDTH_BOTTOM_BASE_ADDR 10 + +#define STB0899_OFF0_BCH_BLK_LN 0xfa24 +#define STB0899_BASE_BCH_BLK_LN 0x00000000 +#define STB0899_BCH_BLOCK_LENGTH (0xffff << 0) +#define STB0899_OFFST_BCH_BLOCK_LENGTH 0 +#define STB0899_WIDTH_BCH_BLOCK_LENGTH 16 + +#define STB0899_OFF0_BCH_T 0xfa28 +#define STB0899_BASE_BCH_T 0x00000000 +#define STB0899_BCH_T (0x0f << 0) +#define STB0899_OFFST_BCH_T 0 +#define STB0899_WIDTH_BCH_T 4 + +#define STB0899_OFF0_CNFG_MODE 0xfa00 +#define STB0899_BASE_CNFG_MODE 0x00000800 +#define STB0899_MODCOD (0x1f << 2) +#define STB0899_OFFST_MODCOD 2 +#define STB0899_WIDTH_MODCOD 5 +#define STB0899_MODCOD_SEL (0x01 << 1) +#define STB0899_OFFST_MODCOD_SEL 1 +#define STB0899_WIDTH_MODCOD_SEL 1 +#define STB0899_CONFIG_MODE (0x01 << 0) +#define STB0899_OFFST_CONFIG_MODE 0 +#define STB0899_WIDTH_CONFIG_MODE 1 + +#define STB0899_OFF0_LDPC_STAT 0xfa04 +#define STB0899_BASE_LDPC_STAT 0x00000800 +#define STB0899_ITERATION (0xff << 3) +#define STB0899_OFFST_ITERATION 3 +#define STB0899_WIDTH_ITERATION 8 +#define STB0899_LDPC_DEC_STATE (0x07 << 0) +#define STB0899_OFFST_LDPC_DEC_STATE 0 +#define STB0899_WIDTH_LDPC_DEC_STATE 3 + +#define STB0899_OFF0_ITER_SCALE 0xfa08 +#define STB0899_BASE_ITER_SCALE 0x00000800 +#define STB0899_ITERATION_SCALE (0xff << 0) +#define STB0899_OFFST_ITERATION_SCALE 0 +#define STB0899_WIDTH_ITERATION_SCALE 8 + +#define STB0899_OFF0_INPUT_MODE 0xfa0c +#define STB0899_BASE_INPUT_MODE 0x00000800 +#define STB0899_SD_BLOCK1_STREAM0 (0x01 << 0) +#define STB0899_OFFST_SD_BLOCK1_STREAM0 0 +#define STB0899_WIDTH_SD_BLOCK1_STREAM0 1 + +#define STB0899_OFF0_LDPCDECRST 0xfa10 +#define STB0899_BASE_LDPCDECRST 0x00000800 +#define STB0899_LDPC_DEC_RST (0x01 << 0) +#define STB0899_OFFST_LDPC_DEC_RST 0 +#define STB0899_WIDTH_LDPC_DEC_RST 1 + +#define STB0899_OFF0_CLK_PER_BYTE_RW 0xfa14 +#define STB0899_BASE_CLK_PER_BYTE_RW 0x00000800 +#define STB0899_CLKS_PER_BYTE (0x0f << 0) +#define STB0899_OFFST_CLKS_PER_BYTE 0 +#define STB0899_WIDTH_CLKS_PER_BYTE 5 + +#define STB0899_OFF0_BCH_ERRORS 0xfa18 +#define STB0899_BASE_BCH_ERRORS 0x00000800 +#define STB0899_BCH_ERRORS (0x0f << 0) +#define STB0899_OFFST_BCH_ERRORS 0 +#define STB0899_WIDTH_BCH_ERRORS 4 + +#define STB0899_OFF0_LDPC_ERRORS 0xfa1c +#define STB0899_BASE_LDPC_ERRORS 0x00000800 +#define STB0899_LDPC_ERRORS (0xffff << 0) +#define STB0899_OFFST_LDPC_ERRORS 0 +#define STB0899_WIDTH_LDPC_ERRORS 16 + +#define STB0899_OFF0_BCH_MODE 0xfa20 +#define STB0899_BASE_BCH_MODE 0x00000800 +#define STB0899_BCH_CORRECT_N (0x01 << 1) +#define STB0899_OFFST_BCH_CORRECT_N 1 +#define STB0899_WIDTH_BCH_CORRECT_N 1 +#define STB0899_FULL_BYPASS (0x01 << 0) +#define STB0899_OFFST_FULL_BYPASS 0 +#define STB0899_WIDTH_FULL_BYPASS 1 + +#define STB0899_OFF0_ERR_ACC_PER 0xfa24 +#define STB0899_BASE_ERR_ACC_PER 0x00000800 +#define STB0899_BCH_ERR_ACC_PERIOD (0x0f << 0) +#define STB0899_OFFST_BCH_ERR_ACC_PERIOD 0 +#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD 4 + +#define STB0899_OFF0_BCH_ERR_ACC 0xfa28 +#define STB0899_BASE_BCH_ERR_ACC 0x00000800 +#define STB0899_BCH_ERR_ACCUM (0xff << 0) +#define STB0899_OFFST_BCH_ERR_ACCUM 0 +#define STB0899_WIDTH_BCH_ERR_ACCUM 8 + +#define STB0899_OFF0_FEC_CORE_ID_REG 0xfa2c +#define STB0899_BASE_FEC_CORE_ID_REG 0x00000800 +#define STB0899_FEC_CORE_ID (0xffffffff << 0) +#define STB0899_OFFST_FEC_CORE_ID 0 +#define STB0899_WIDTH_FEC_CORE_ID 32 + +#define STB0899_OFF0_FEC_VER_ID_REG 0xfa34 +#define STB0899_BASE_FEC_VER_ID_REG 0x00000800 +#define STB0899_FEC_VER_ID (0xff << 0) +#define STB0899_OFFST_FEC_VER_ID 0 +#define STB0899_WIDTH_FEC_VER_ID 8 + +#define STB0899_OFF0_FEC_TP_SEL 0xfa38 +#define STB0899_BASE_FEC_TP_SEL 0x00000800 + +#define STB0899_OFF0_CSM_CNTRL1 0xf310 +#define STB0899_BASE_CSM_CNTRL1 0x00000400 +#define STB0899_CSM_FORCE_FREQLOCK (0x01 << 19) +#define STB0899_OFFST_CSM_FORCE_FREQLOCK 19 +#define STB0899_WIDTH_CSM_FORCE_FREQLOCK 1 +#define STB0899_CSM_FREQ_LOCKSTATE (0x01 << 18) +#define STB0899_OFFST_CSM_FREQ_LOCKSTATE 18 +#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE 1 +#define STB0899_CSM_AUTO_PARAM (0x01 << 17) +#define STB0899_OFFST_CSM_AUTO_PARAM 17 +#define STB0899_WIDTH_CSM_AUTO_PARAM 1 +#define STB0899_FE_LOOP_SHIFT (0x07 << 14) +#define STB0899_OFFST_FE_LOOP_SHIFT 14 +#define STB0899_WIDTH_FE_LOOP_SHIFT 3 +#define STB0899_CSM_AGC_SHIFT (0x07 << 11) +#define STB0899_OFFST_CSM_AGC_SHIFT 11 +#define STB0899_WIDTH_CSM_AGC_SHIFT 3 +#define STB0899_CSM_AGC_GAIN (0x1ff << 2) +#define STB0899_OFFST_CSM_AGC_GAIN 2 +#define STB0899_WIDTH_CSM_AGC_GAIN 9 +#define STB0899_CSM_TWO_PASS (0x01 << 1) +#define STB0899_OFFST_CSM_TWO_PASS 1 +#define STB0899_WIDTH_CSM_TWO_PASS 1 +#define STB0899_CSM_DVT_TABLE (0x01 << 0) +#define STB0899_OFFST_CSM_DVT_TABLE 0 +#define STB0899_WIDTH_CSM_DVT_TABLE 1 + +#define STB0899_OFF0_CSM_CNTRL2 0xf314 +#define STB0899_BASE_CSM_CNTRL2 0x00000400 +#define STB0899_CSM_GAMMA_RHO_ACQ (0x1ff << 9) +#define STB0899_OFFST_CSM_GAMMA_RHOACQ 9 +#define STB0899_WIDTH_CSM_GAMMA_RHOACQ 9 +#define STB0899_CSM_GAMMA_ACQ (0x1ff << 0) +#define STB0899_OFFST_CSM_GAMMA_ACQ 0 +#define STB0899_WIDTH_CSM_GAMMA_ACQ 9 + +#define STB0899_OFF0_CSM_CNTRL3 0xf318 +#define STB0899_BASE_CSM_CNTRL3 0x00000400 +#define STB0899_CSM_GAMMA_RHO_TRACK (0x1ff << 9) +#define STB0899_OFFST_CSM_GAMMA_RHOTRACK 9 +#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK 9 +#define STB0899_CSM_GAMMA_TRACK (0x1ff << 0) +#define STB0899_OFFST_CSM_GAMMA_TRACK 0 +#define STB0899_WIDTH_CSM_GAMMA_TRACK 9 + +#define STB0899_OFF0_CSM_CNTRL4 0xf31c +#define STB0899_BASE_CSM_CNTRL4 0x00000400 +#define STB0899_CSM_PHASEDIFF_THRESH (0x0f << 8) +#define STB0899_OFFST_CSM_PHASEDIFF_THRESH 8 +#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH 4 +#define STB0899_CSM_LOCKCOUNT_THRESH (0xff << 0) +#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH 0 +#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH 8 + +/* Check on chapter 8 page 42 */ +#define STB0899_ERRCTRL1 0xf574 +#define STB0899_ERRCTRL2 0xf575 +#define STB0899_ERRCTRL3 0xf576 +#define STB0899_ERR_SRC_S1 (0x1f << 3) +#define STB0899_OFFST_ERR_SRC_S1 3 +#define STB0899_WIDTH_ERR_SRC_S1 5 +#define STB0899_ERR_SRC_S2 (0x0f << 0) +#define STB0899_OFFST_ERR_SRC_S2 0 +#define STB0899_WIDTH_ERR_SRC_S2 4 +#define STB0899_NOE (0x07 << 0) +#define STB0899_OFFST_NOE 0 +#define STB0899_WIDTH_NOE 3 + +#define STB0899_ECNT1M 0xf524 +#define STB0899_ECNT1L 0xf525 +#define STB0899_ECNT2M 0xf526 +#define STB0899_ECNT2L 0xf527 +#define STB0899_ECNT3M 0xf528 +#define STB0899_ECNT3L 0xf529 + +#define STB0899_DMONMSK1 0xf57b +#define STB0899_DMONMSK1_WAIT_1STEP (1 << 7) +#define STB0899_DMONMSK1_FREE_14 (1 << 6) +#define STB0899_DMONMSK1_AVRGVIT_CALC (1 << 5) +#define STB0899_DMONMSK1_FREE_12 (1 << 4) +#define STB0899_DMONMSK1_FREE_11 (1 << 3) +#define STB0899_DMONMSK1_B0DIV_CALC (1 << 2) +#define STB0899_DMONMSK1_KDIVB1_CALC (1 << 1) +#define STB0899_DMONMSK1_KDIVB2_CALC (1 << 0) + +#define STB0899_DMONMSK0 0xf57c +#define STB0899_DMONMSK0_SMOTTH_CALC (1 << 7) +#define STB0899_DMONMSK0_FREE_6 (1 << 6) +#define STB0899_DMONMSK0_SIGPOWER_CALC (1 << 5) +#define STB0899_DMONMSK0_QSEUIL_CALC (1 << 4) +#define STB0899_DMONMSK0_FREE_3 (1 << 3) +#define STB0899_DMONMSK0_FREE_2 (1 << 2) +#define STB0899_DMONMSK0_KVDIVB1_CALC (1 << 1) +#define STB0899_DMONMSK0_KVDIVB2_CALC (1 << 0) + +#define STB0899_TSULC 0xf549 +#define STB0899_ULNOSYNCBYTES (0x01 << 7) +#define STB0899_OFFST_ULNOSYNCBYTES 7 +#define STB0899_WIDTH_ULNOSYNCBYTES 1 +#define STB0899_ULPARITY_ON (0x01 << 6) +#define STB0899_OFFST_ULPARITY_ON 6 +#define STB0899_WIDTH_ULPARITY_ON 1 +#define STB0899_ULSYNCOUTRS (0x01 << 5) +#define STB0899_OFFST_ULSYNCOUTRS 5 +#define STB0899_WIDTH_ULSYNCOUTRS 1 +#define STB0899_ULDSS_PACKETS (0x01 << 0) +#define STB0899_OFFST_ULDSS_PACKETS 0 +#define STB0899_WIDTH_ULDSS_PACKETS 1 + +#define STB0899_TSLPL 0xf54b +#define STB0899_LLDVBS2_MODE (0x01 << 4) +#define STB0899_OFFST_LLDVBS2_MODE 4 +#define STB0899_WIDTH_LLDVBS2_MODE 1 +#define STB0899_LLISSYI_ON (0x01 << 3) +#define STB0899_OFFST_LLISSYI_ON 3 +#define STB0899_WIDTH_LLISSYI_ON 1 +#define STB0899_LLNPD_ON (0x01 << 2) +#define STB0899_OFFST_LLNPD_ON 2 +#define STB0899_WIDTH_LLNPD_ON 1 +#define STB0899_LLCRC8_ON (0x01 << 1) +#define STB0899_OFFST_LLCRC8_ON 1 +#define STB0899_WIDTH_LLCRC8_ON 1 + +#define STB0899_TSCFGH 0xf54c +#define STB0899_OUTRS_PS (0x01 << 6) +#define STB0899_OFFST_OUTRS_PS 6 +#define STB0899_WIDTH_OUTRS_PS 1 +#define STB0899_SYNCBYTE (0x01 << 5) +#define STB0899_OFFST_SYNCBYTE 5 +#define STB0899_WIDTH_SYNCBYTE 1 +#define STB0899_PFBIT (0x01 << 4) +#define STB0899_OFFST_PFBIT 4 +#define STB0899_WIDTH_PFBIT 1 +#define STB0899_ERR_BIT (0x01 << 3) +#define STB0899_OFFST_ERR_BIT 3 +#define STB0899_WIDTH_ERR_BIT 1 +#define STB0899_MPEG (0x01 << 2) +#define STB0899_OFFST_MPEG 2 +#define STB0899_WIDTH_MPEG 1 +#define STB0899_CLK_POL (0x01 << 1) +#define STB0899_OFFST_CLK_POL 1 +#define STB0899_WIDTH_CLK_POL 1 +#define STB0899_FORCE0 (0x01 << 0) +#define STB0899_OFFST_FORCE0 0 +#define STB0899_WIDTH_FORCE0 1 + +#define STB0899_TSCFGM 0xf54d +#define STB0899_LLPRIORITY (0x01 << 3) +#define STB0899_OFFST_LLPRIORIY 3 +#define STB0899_WIDTH_LLPRIORITY 1 +#define STB0899_EN188 (0x01 << 2) +#define STB0899_OFFST_EN188 2 +#define STB0899_WIDTH_EN188 1 + +#define STB0899_TSCFGL 0xf54e +#define STB0899_DEL_ERRPCK (0x01 << 7) +#define STB0899_OFFST_DEL_ERRPCK 7 +#define STB0899_WIDTH_DEL_ERRPCK 1 +#define STB0899_ERRFLAGSTD (0x01 << 5) +#define STB0899_OFFST_ERRFLAGSTD 5 +#define STB0899_WIDTH_ERRFLAGSTD 1 +#define STB0899_MPEGERR (0x01 << 4) +#define STB0899_OFFST_MPEGERR 4 +#define STB0899_WIDTH_MPEGERR 1 +#define STB0899_BCH_CHK (0x01 << 3) +#define STB0899_OFFST_BCH_CHK 5 +#define STB0899_WIDTH_BCH_CHK 1 +#define STB0899_CRC8CHK (0x01 << 2) +#define STB0899_OFFST_CRC8CHK 2 +#define STB0899_WIDTH_CRC8CHK 1 +#define STB0899_SPEC_INFO (0x01 << 1) +#define STB0899_OFFST_SPEC_INFO 1 +#define STB0899_WIDTH_SPEC_INFO 1 +#define STB0899_LOW_PRIO_CLK (0x01 << 0) +#define STB0899_OFFST_LOW_PRIO_CLK 0 +#define STB0899_WIDTH_LOW_PRIO_CLK 1 +#define STB0899_ERROR_NORM (0x00 << 0) +#define STB0899_OFFST_ERROR_NORM 0 +#define STB0899_WIDTH_ERROR_NORM 0 + +#define STB0899_TSOUT 0xf54f +#define STB0899_RSSYNCDEL 0xf550 +#define STB0899_TSINHDELH 0xf551 +#define STB0899_TSINHDELM 0xf552 +#define STB0899_TSINHDELL 0xf553 +#define STB0899_TSLLSTKM 0xf55a +#define STB0899_TSLLSTKL 0xf55b +#define STB0899_TSULSTKM 0xf55c +#define STB0899_TSULSTKL 0xf55d +#define STB0899_TSSTATUS 0xf561 + +#define STB0899_PDELCTRL 0xf600 +#define STB0899_INVERT_RES (0x01 << 7) +#define STB0899_OFFST_INVERT_RES 7 +#define STB0899_WIDTH_INVERT_RES 1 +#define STB0899_FORCE_ACCEPTED (0x01 << 6) +#define STB0899_OFFST_FORCE_ACCEPTED 6 +#define STB0899_WIDTH_FORCE_ACCEPTED 1 +#define STB0899_FILTER_EN (0x01 << 5) +#define STB0899_OFFST_FILTER_EN 5 +#define STB0899_WIDTH_FILTER_EN 1 +#define STB0899_LOCKFALL_THRESH (0x01 << 4) +#define STB0899_OFFST_LOCKFALL_THRESH 4 +#define STB0899_WIDTH_LOCKFALL_THRESH 1 +#define STB0899_HYST_EN (0x01 << 3) +#define STB0899_OFFST_HYST_EN 3 +#define STB0899_WIDTH_HYST_EN 1 +#define STB0899_HYST_SWRST (0x01 << 2) +#define STB0899_OFFST_HYST_SWRST 2 +#define STB0899_WIDTH_HYST_SWRST 1 +#define STB0899_ALGO_EN (0x01 << 1) +#define STB0899_OFFST_ALGO_EN 1 +#define STB0899_WIDTH_ALGO_EN 1 +#define STB0899_ALGO_SWRST (0x01 << 0) +#define STB0899_OFFST_ALGO_SWRST 0 +#define STB0899_WIDTH_ALGO_SWRST 1 + +#define STB0899_PDELCTRL2 0xf601 +#define STB0899_BBHCTRL1 0xf602 +#define STB0899_BBHCTRL2 0xf603 +#define STB0899_HYSTTHRESH 0xf604 + +#define STB0899_MATCSTM 0xf605 +#define STB0899_MATCSTL 0xf606 +#define STB0899_UPLCSTM 0xf607 +#define STB0899_UPLCSTL 0xf608 +#define STB0899_DFLCSTM 0xf609 +#define STB0899_DFLCSTL 0xf60a +#define STB0899_SYNCCST 0xf60b +#define STB0899_SYNCDCSTM 0xf60c +#define STB0899_SYNCDCSTL 0xf60d +#define STB0899_ISI_ENTRY 0xf60e +#define STB0899_ISI_BIT_EN 0xf60f +#define STB0899_MATSTRM 0xf610 +#define STB0899_MATSTRL 0xf611 +#define STB0899_UPLSTRM 0xf612 +#define STB0899_UPLSTRL 0xf613 +#define STB0899_DFLSTRM 0xf614 +#define STB0899_DFLSTRL 0xf615 +#define STB0899_SYNCSTR 0xf616 +#define STB0899_SYNCDSTRM 0xf617 +#define STB0899_SYNCDSTRL 0xf618 + +#define STB0899_CFGPDELSTATUS1 0xf619 +#define STB0899_BADDFL (0x01 << 6) +#define STB0899_OFFST_BADDFL 6 +#define STB0899_WIDTH_BADDFL 1 +#define STB0899_CONTINUOUS_STREAM (0x01 << 5) +#define STB0899_OFFST_CONTINUOUS_STREAM 5 +#define STB0899_WIDTH_CONTINUOUS_STREAM 1 +#define STB0899_ACCEPTED_STREAM (0x01 << 4) +#define STB0899_OFFST_ACCEPTED_STREAM 4 +#define STB0899_WIDTH_ACCEPTED_STREAM 1 +#define STB0899_BCH_ERRFLAG (0x01 << 3) +#define STB0899_OFFST_BCH_ERRFLAG 3 +#define STB0899_WIDTH_BCH_ERRFLAG 1 +#define STB0899_CRCRES (0x01 << 2) +#define STB0899_OFFST_CRCRES 2 +#define STB0899_WIDTH_CRCRES 1 +#define STB0899_CFGPDELSTATUS_LOCK (0x01 << 1) +#define STB0899_OFFST_CFGPDELSTATUS_LOCK 1 +#define STB0899_WIDTH_CFGPDELSTATUS_LOCK 1 +#define STB0899_1STLOCK (0x01 << 0) +#define STB0899_OFFST_1STLOCK 0 +#define STB0899_WIDTH_1STLOCK 1 + +#define STB0899_CFGPDELSTATUS2 0xf61a +#define STB0899_BBFERRORM 0xf61b +#define STB0899_BBFERRORL 0xf61c +#define STB0899_UPKTERRORM 0xf61d +#define STB0899_UPKTERRORL 0xf61e + +#define STB0899_TSTCK 0xff10 + +#define STB0899_TSTRES 0xff11 +#define STB0899_FRESLDPC (0x01 << 7) +#define STB0899_OFFST_FRESLDPC 7 +#define STB0899_WIDTH_FRESLDPC 1 +#define STB0899_FRESRS (0x01 << 6) +#define STB0899_OFFST_FRESRS 6 +#define STB0899_WIDTH_FRESRS 1 +#define STB0899_FRESVIT (0x01 << 5) +#define STB0899_OFFST_FRESVIT 5 +#define STB0899_WIDTH_FRESVIT 1 +#define STB0899_FRESMAS1_2 (0x01 << 4) +#define STB0899_OFFST_FRESMAS1_2 4 +#define STB0899_WIDTH_FRESMAS1_2 1 +#define STB0899_FRESACS (0x01 << 3) +#define STB0899_OFFST_FRESACS 3 +#define STB0899_WIDTH_FRESACS 1 +#define STB0899_FRESSYM (0x01 << 2) +#define STB0899_OFFST_FRESSYM 2 +#define STB0899_WIDTH_FRESSYM 1 +#define STB0899_FRESMAS (0x01 << 1) +#define STB0899_OFFST_FRESMAS 1 +#define STB0899_WIDTH_FRESMAS 1 +#define STB0899_FRESINT (0x01 << 0) +#define STB0899_OFFST_FRESINIT 0 +#define STB0899_WIDTH_FRESINIT 1 + +#define STB0899_TSTOUT 0xff12 +#define STB0899_EN_SIGNATURE (0x01 << 7) +#define STB0899_OFFST_EN_SIGNATURE 7 +#define STB0899_WIDTH_EN_SIGNATURE 1 +#define STB0899_BCLK_CLK (0x01 << 6) +#define STB0899_OFFST_BCLK_CLK 6 +#define STB0899_WIDTH_BCLK_CLK 1 +#define STB0899_SGNL_OUT (0x01 << 5) +#define STB0899_OFFST_SGNL_OUT 5 +#define STB0899_WIDTH_SGNL_OUT 1 +#define STB0899_TS (0x01 << 4) +#define STB0899_OFFST_TS 4 +#define STB0899_WIDTH_TS 1 +#define STB0899_CTEST (0x01 << 0) +#define STB0899_OFFST_CTEST 0 +#define STB0899_WIDTH_CTEST 1 + +#define STB0899_TSTIN 0xff13 +#define STB0899_TEST_IN (0x01 << 7) +#define STB0899_OFFST_TEST_IN 7 +#define STB0899_WIDTH_TEST_IN 1 +#define STB0899_EN_ADC (0x01 << 6) +#define STB0899_OFFST_EN_ADC 6 +#define STB0899_WIDTH_ENADC 1 +#define STB0899_SGN_ADC (0x01 << 5) +#define STB0899_OFFST_SGN_ADC 5 +#define STB0899_WIDTH_SGN_ADC 1 +#define STB0899_BCLK_IN (0x01 << 4) +#define STB0899_OFFST_BCLK_IN 4 +#define STB0899_WIDTH_BCLK_IN 1 +#define STB0899_JETONIN_MODE (0x01 << 3) +#define STB0899_OFFST_JETONIN_MODE 3 +#define STB0899_WIDTH_JETONIN_MODE 1 +#define STB0899_BCLK_VALUE (0x01 << 2) +#define STB0899_OFFST_BCLK_VALUE 2 +#define STB0899_WIDTH_BCLK_VALUE 1 +#define STB0899_SGNRST_T12 (0x01 << 1) +#define STB0899_OFFST_SGNRST_T12 1 +#define STB0899_WIDTH_SGNRST_T12 1 +#define STB0899_LOWSP_ENAX (0x01 << 0) +#define STB0899_OFFST_LOWSP_ENAX 0 +#define STB0899_WIDTH_LOWSP_ENAX 1 + +#define STB0899_TSTSYS 0xff14 +#define STB0899_TSTCHIP 0xff15 +#define STB0899_TSTFREE 0xff16 +#define STB0899_TSTI2C 0xff17 +#define STB0899_BITSPEEDM 0xff1c +#define STB0899_BITSPEEDL 0xff1d +#define STB0899_TBUSBIT 0xff1e +#define STB0899_TSTDIS 0xff24 +#define STB0899_TSTDISRX 0xff25 +#define STB0899_TSTJETON 0xff28 +#define STB0899_TSTDCADJ 0xff40 +#define STB0899_TSTAGC1 0xff41 +#define STB0899_TSTAGC1N 0xff42 +#define STB0899_TSTPOLYPH 0xff48 +#define STB0899_TSTR 0xff49 +#define STB0899_TSTAGC2 0xff4a +#define STB0899_TSTCTL1 0xff4b +#define STB0899_TSTCTL2 0xff4c +#define STB0899_TSTCTL3 0xff4d +#define STB0899_TSTDEMAP 0xff50 +#define STB0899_TSTDEMAP2 0xff51 +#define STB0899_TSTDEMMON 0xff52 +#define STB0899_TSTRATE 0xff53 +#define STB0899_TSTSELOUT 0xff54 +#define STB0899_TSYNC 0xff55 +#define STB0899_TSTERR 0xff56 +#define STB0899_TSTRAM1 0xff58 +#define STB0899_TSTVSELOUT 0xff59 +#define STB0899_TSTFORCEIN 0xff5a +#define STB0899_TSTRS1 0xff5c +#define STB0899_TSTRS2 0xff5d +#define STB0899_TSTRS3 0xff53 + +#define STB0899_INTBUFSTATUS 0xf200 +#define STB0899_INTBUFCTRL 0xf201 +#define STB0899_PCKLENUL 0xf55e +#define STB0899_PCKLENLL 0xf55f +#define STB0899_RSPCKLEN 0xf560 + +/* 2 registers */ +#define STB0899_SYNCDCST 0xf60c + +/* DiSEqC */ +#define STB0899_DISCNTRL1 0xf0a0 +#define STB0899_TIMOFF (0x01 << 7) +#define STB0899_OFFST_TIMOFF 7 +#define STB0899_WIDTH_TIMOFF 1 +#define STB0899_DISEQCRESET (0x01 << 6) +#define STB0899_OFFST_DISEQCRESET 6 +#define STB0899_WIDTH_DISEQCRESET 1 +#define STB0899_TIMCMD (0x03 << 4) +#define STB0899_OFFST_TIMCMD 4 +#define STB0899_WIDTH_TIMCMD 2 +#define STB0899_DISPRECHARGE (0x01 << 2) +#define STB0899_OFFST_DISPRECHARGE 2 +#define STB0899_WIDTH_DISPRECHARGE 1 +#define STB0899_DISEQCMODE (0x03 << 0) +#define STB0899_OFFST_DISEQCMODE 0 +#define STB0899_WIDTH_DISEQCMODE 2 + +#define STB0899_DISCNTRL2 0xf0a1 +#define STB0899_RECEIVER_ON (0x01 << 7) +#define STB0899_OFFST_RECEIVER_ON 7 +#define STB0899_WIDTH_RECEIVER_ON 1 +#define STB0899_IGNO_SHORT_22K (0x01 << 6) +#define STB0899_OFFST_IGNO_SHORT_22K 6 +#define STB0899_WIDTH_IGNO_SHORT_22K 1 +#define STB0899_ONECHIP_TRX (0x01 << 5) +#define STB0899_OFFST_ONECHIP_TRX 5 +#define STB0899_WIDTH_ONECHIP_TRX 1 +#define STB0899_EXT_ENVELOP (0x01 << 4) +#define STB0899_OFFST_EXT_ENVELOP 4 +#define STB0899_WIDTH_EXT_ENVELOP 1 +#define STB0899_PIN_SELECT (0x03 << 2) +#define STB0899_OFFST_PIN_SELCT 2 +#define STB0899_WIDTH_PIN_SELCT 2 +#define STB0899_IRQ_RXEND (0x01 << 1) +#define STB0899_OFFST_IRQ_RXEND 1 +#define STB0899_WIDTH_IRQ_RXEND 1 +#define STB0899_IRQ_4NBYTES (0x01 << 0) +#define STB0899_OFFST_IRQ_4NBYTES 0 +#define STB0899_WIDTH_IRQ_4NBYTES 1 + +#define STB0899_DISRX_ST0 0xf0a4 +#define STB0899_RXEND (0x01 << 7) +#define STB0899_OFFST_RXEND 7 +#define STB0899_WIDTH_RXEND 1 +#define STB0899_RXACTIVE (0x01 << 6) +#define STB0899_OFFST_RXACTIVE 6 +#define STB0899_WIDTH_RXACTIVE 1 +#define STB0899_SHORT22K (0x01 << 5) +#define STB0899_OFFST_SHORT22K 5 +#define STB0899_WIDTH_SHORT22K 1 +#define STB0899_CONTTONE (0x01 << 4) +#define STB0899_OFFST_CONTTONE 4 +#define STB0899_WIDTH_CONTONE 1 +#define STB0899_4BFIFOREDY (0x01 << 3) +#define STB0899_OFFST_4BFIFOREDY 3 +#define STB0899_WIDTH_4BFIFOREDY 1 +#define STB0899_FIFOEMPTY (0x01 << 2) +#define STB0899_OFFST_FIFOEMPTY 2 +#define STB0899_WIDTH_FIFOEMPTY 1 +#define STB0899_ABORTTRX (0x01 << 0) +#define STB0899_OFFST_ABORTTRX 0 +#define STB0899_WIDTH_ABORTTRX 1 + +#define STB0899_DISRX_ST1 0xf0a5 +#define STB0899_RXFAIL (0x01 << 7) +#define STB0899_OFFST_RXFAIL 7 +#define STB0899_WIDTH_RXFAIL 1 +#define STB0899_FIFOPFAIL (0x01 << 6) +#define STB0899_OFFST_FIFOPFAIL 6 +#define STB0899_WIDTH_FIFOPFAIL 1 +#define STB0899_RXNONBYTES (0x01 << 5) +#define STB0899_OFFST_RXNONBYTES 5 +#define STB0899_WIDTH_RXNONBYTES 1 +#define STB0899_FIFOOVF (0x01 << 4) +#define STB0899_OFFST_FIFOOVF 4 +#define STB0899_WIDTH_FIFOOVF 1 +#define STB0899_FIFOBYTENBR (0x0f << 0) +#define STB0899_OFFST_FIFOBYTENBR 0 +#define STB0899_WIDTH_FIFOBYTENBR 4 + +#define STB0899_DISPARITY 0xf0a6 + +#define STB0899_DISFIFO 0xf0a7 + +#define STB0899_DISSTATUS 0xf0a8 +#define STB0899_FIFOFULL (0x01 << 6) +#define STB0899_OFFST_FIFOFULL 6 +#define STB0899_WIDTH_FIFOFULL 1 +#define STB0899_TXIDLE (0x01 << 5) +#define STB0899_OFFST_TXIDLE 5 +#define STB0899_WIDTH_TXIDLE 1 +#define STB0899_GAPBURST (0x01 << 4) +#define STB0899_OFFST_GAPBURST 4 +#define STB0899_WIDTH_GAPBURST 1 +#define STB0899_TXFIFOBYTES (0x0f << 0) +#define STB0899_OFFST_TXFIFOBYTES 0 +#define STB0899_WIDTH_TXFIFOBYTES 4 +#define STB0899_DISF22 0xf0a9 + +#define STB0899_DISF22RX 0xf0aa + +/* General Purpose */ +#define STB0899_SYSREG 0xf101 +#define STB0899_ACRPRESC 0xf110 +#define STB0899_OFFST_RSVD2 7 +#define STB0899_WIDTH_RSVD2 1 +#define STB0899_OFFST_ACRPRESC 4 +#define STB0899_WIDTH_ACRPRESC 3 +#define STB0899_OFFST_RSVD1 3 +#define STB0899_WIDTH_RSVD1 1 +#define STB0899_OFFST_ACRPRESC2 0 +#define STB0899_WIDTH_ACRPRESC2 3 + +#define STB0899_ACRDIV1 0xf111 +#define STB0899_ACRDIV2 0xf112 +#define STB0899_DACR1 0xf113 +#define STB0899_DACR2 0xf114 +#define STB0899_OUTCFG 0xf11c +#define STB0899_MODECFG 0xf11d +#define STB0899_NCOARSE 0xf1b3 + +#define STB0899_SYNTCTRL 0xf1b6 +#define STB0899_STANDBY (0x01 << 7) +#define STB0899_OFFST_STANDBY 7 +#define STB0899_WIDTH_STANDBY 1 +#define STB0899_BYPASSPLL (0x01 << 6) +#define STB0899_OFFST_BYPASSPLL 6 +#define STB0899_WIDTH_BYPASSPLL 1 +#define STB0899_SEL1XRATIO (0x01 << 5) +#define STB0899_OFFST_SEL1XRATIO 5 +#define STB0899_WIDTH_SEL1XRATIO 1 +#define STB0899_SELOSCI (0x01 << 1) +#define STB0899_OFFST_SELOSCI 1 +#define STB0899_WIDTH_SELOSCI 1 + +#define STB0899_FILTCTRL 0xf1b7 +#define STB0899_SYSCTRL 0xf1b8 + +#define STB0899_STOPCLK1 0xf1c2 +#define STB0899_STOP_CKINTBUF108 (0x01 << 7) +#define STB0899_OFFST_STOP_CKINTBUF108 7 +#define STB0899_WIDTH_STOP_CKINTBUF108 1 +#define STB0899_STOP_CKINTBUF216 (0x01 << 6) +#define STB0899_OFFST_STOP_CKINTBUF216 6 +#define STB0899_WIDTH_STOP_CKINTBUF216 1 +#define STB0899_STOP_CHK8PSK (0x01 << 5) +#define STB0899_OFFST_STOP_CHK8PSK 5 +#define STB0899_WIDTH_STOP_CHK8PSK 1 +#define STB0899_STOP_CKFEC108 (0x01 << 4) +#define STB0899_OFFST_STOP_CKFEC108 4 +#define STB0899_WIDTH_STOP_CKFEC108 1 +#define STB0899_STOP_CKFEC216 (0x01 << 3) +#define STB0899_OFFST_STOP_CKFEC216 3 +#define STB0899_WIDTH_STOP_CKFEC216 1 +#define STB0899_STOP_CKCORE216 (0x01 << 2) +#define STB0899_OFFST_STOP_CKCORE216 2 +#define STB0899_WIDTH_STOP_CKCORE216 1 +#define STB0899_STOP_CKADCI108 (0x01 << 1) +#define STB0899_OFFST_STOP_CKADCI108 1 +#define STB0899_WIDTH_STOP_CKADCI108 1 +#define STB0899_STOP_INVCKADCI108 (0x01 << 0) +#define STB0899_OFFST_STOP_INVCKADCI108 0 +#define STB0899_WIDTH_STOP_INVCKADCI108 1 + +#define STB0899_STOPCLK2 0xf1c3 +#define STB0899_STOP_CKS2DMD108 (0x01 << 2) +#define STB0899_OFFST_STOP_CKS2DMD108 2 +#define STB0899_WIDTH_STOP_CKS2DMD108 1 +#define STB0899_STOP_CKPKDLIN108 (0x01 << 1) +#define STB0899_OFFST_STOP_CKPKDLIN108 1 +#define STB0899_WIDTH_STOP_CKPKDLIN108 1 +#define STB0899_STOP_CKPKDLIN216 (0x01 << 0) +#define STB0899_OFFST_STOP_CKPKDLIN216 0 +#define STB0899_WIDTH_STOP_CKPKDLIN216 1 + +#define STB0899_TSTTNR1 0xf1e0 +#define STB0899_BYPASS_ADC (0x01 << 7) +#define STB0899_OFFST_BYPASS_ADC 7 +#define STB0899_WIDTH_BYPASS_ADC 1 +#define STB0899_INVADCICKOUT (0x01 << 6) +#define STB0899_OFFST_INVADCICKOUT 6 +#define STB0899_WIDTH_INVADCICKOUT 1 +#define STB0899_ADCTEST_VOLTAGE (0x03 << 4) +#define STB0899_OFFST_ADCTEST_VOLTAGE 4 +#define STB0899_WIDTH_ADCTEST_VOLTAGE 1 +#define STB0899_ADC_RESET (0x01 << 3) +#define STB0899_OFFST_ADC_RESET 3 +#define STB0899_WIDTH_ADC_RESET 1 +#define STB0899_TSTTNR1_2 (0x01 << 2) +#define STB0899_OFFST_TSTTNR1_2 2 +#define STB0899_WIDTH_TSTTNR1_2 1 +#define STB0899_ADCPON (0x01 << 1) +#define STB0899_OFFST_ADCPON 1 +#define STB0899_WIDTH_ADCPON 1 +#define STB0899_ADCIN_MODE (0x01 << 0) +#define STB0899_OFFST_ADCIN_MODE 0 +#define STB0899_WIDTH_ADCIN_MODE 1 + +#define STB0899_TSTTNR2 0xf1e1 +#define STB0899_TSTTNR2_7 (0x01 << 7) +#define STB0899_OFFST_TSTTNR2_7 7 +#define STB0899_WIDTH_TSTTNR2_7 1 +#define STB0899_NOT_DISRX_WIRED (0x01 << 6) +#define STB0899_OFFST_NOT_DISRX_WIRED 6 +#define STB0899_WIDTH_NOT_DISRX_WIRED 1 +#define STB0899_DISEQC_DCURRENT (0x01 << 5) +#define STB0899_OFFST_DISEQC_DCURRENT 5 +#define STB0899_WIDTH_DISEQC_DCURRENT 1 +#define STB0899_DISEQC_ZCURRENT (0x01 << 4) +#define STB0899_OFFST_DISEQC_ZCURRENT 4 +#define STB0899_WIDTH_DISEQC_ZCURRENT 1 +#define STB0899_DISEQC_SINC_SOURCE (0x03 << 2) +#define STB0899_OFFST_DISEQC_SINC_SOURCE 2 +#define STB0899_WIDTH_DISEQC_SINC_SOURCE 2 +#define STB0899_SELIQSRC (0x03 << 0) +#define STB0899_OFFST_SELIQSRC 0 +#define STB0899_WIDTH_SELIQSRC 2 + +#define STB0899_TSTTNR3 0xf1e2 + +#define STB0899_I2CCFG 0xf129 +#define STB0899_I2CCFGRSVD (0x0f << 4) +#define STB0899_OFFST_I2CCFGRSVD 4 +#define STB0899_WIDTH_I2CCFGRSVD 4 +#define STB0899_I2CFASTMODE (0x01 << 3) +#define STB0899_OFFST_I2CFASTMODE 3 +#define STB0899_WIDTH_I2CFASTMODE 1 +#define STB0899_STATUSWR (0x01 << 2) +#define STB0899_OFFST_STATUSWR 2 +#define STB0899_WIDTH_STATUSWR 1 +#define STB0899_I2CADDRINC (0x03 << 0) +#define STB0899_OFFST_I2CADDRINC 0 +#define STB0899_WIDTH_I2CADDRINC 2 + +#define STB0899_I2CRPT 0xf12a +#define STB0899_I2CTON (0x01 << 7) +#define STB0899_OFFST_I2CTON 7 +#define STB0899_WIDTH_I2CTON 1 +#define STB0899_ENARPTLEVEL (0x01 << 6) +#define STB0899_OFFST_ENARPTLEVEL 6 +#define STB0899_WIDTH_ENARPTLEVEL 2 +#define STB0899_SCLTDELAY (0x01 << 3) +#define STB0899_OFFST_SCLTDELAY 3 +#define STB0899_WIDTH_SCLTDELAY 1 +#define STB0899_STOPENA (0x01 << 2) +#define STB0899_OFFST_STOPENA 2 +#define STB0899_WIDTH_STOPENA 1 +#define STB0899_STOPSDAT2SDA (0x01 << 1) +#define STB0899_OFFST_STOPSDAT2SDA 1 +#define STB0899_WIDTH_STOPSDAT2SDA 1 + +#define STB0899_IOPVALUE8 0xf136 +#define STB0899_IOPVALUE7 0xf137 +#define STB0899_IOPVALUE6 0xf138 +#define STB0899_IOPVALUE5 0xf139 +#define STB0899_IOPVALUE4 0xf13a +#define STB0899_IOPVALUE3 0xf13b +#define STB0899_IOPVALUE2 0xf13c +#define STB0899_IOPVALUE1 0xf13d +#define STB0899_IOPVALUE0 0xf13e + +#define STB0899_GPIO00CFG 0xf140 + +#define STB0899_GPIO01CFG 0xf141 +#define STB0899_GPIO02CFG 0xf142 +#define STB0899_GPIO03CFG 0xf143 +#define STB0899_GPIO04CFG 0xf144 +#define STB0899_GPIO05CFG 0xf145 +#define STB0899_GPIO06CFG 0xf146 +#define STB0899_GPIO07CFG 0xf147 +#define STB0899_GPIO08CFG 0xf148 +#define STB0899_GPIO09CFG 0xf149 +#define STB0899_GPIO10CFG 0xf14a +#define STB0899_GPIO11CFG 0xf14b +#define STB0899_GPIO12CFG 0xf14c +#define STB0899_GPIO13CFG 0xf14d +#define STB0899_GPIO14CFG 0xf14e +#define STB0899_GPIO15CFG 0xf14f +#define STB0899_GPIO16CFG 0xf150 +#define STB0899_GPIO17CFG 0xf151 +#define STB0899_GPIO18CFG 0xf152 +#define STB0899_GPIO19CFG 0xf153 +#define STB0899_GPIO20CFG 0xf154 + +#define STB0899_SDATCFG 0xf155 +#define STB0899_SCLTCFG 0xf156 +#define STB0899_AGCRFCFG 0xf157 +#define STB0899_GPIO22 0xf158 /* AGCBB2CFG */ +#define STB0899_GPIO21 0xf159 /* AGCBB1CFG */ +#define STB0899_DIRCLKCFG 0xf15a +#define STB0899_CLKOUT27CFG 0xf15b +#define STB0899_STDBYCFG 0xf15c +#define STB0899_CS0CFG 0xf15d +#define STB0899_CS1CFG 0xf15e +#define STB0899_DISEQCOCFG 0xf15f + +#define STB0899_GPIO32CFG 0xf160 +#define STB0899_GPIO33CFG 0xf161 +#define STB0899_GPIO34CFG 0xf162 +#define STB0899_GPIO35CFG 0xf163 +#define STB0899_GPIO36CFG 0xf164 +#define STB0899_GPIO37CFG 0xf165 +#define STB0899_GPIO38CFG 0xf166 +#define STB0899_GPIO39CFG 0xf167 + +#define STB0899_IRQSTATUS_3 0xf120 +#define STB0899_IRQSTATUS_2 0xf121 +#define STB0899_IRQSTATUS_1 0xf122 +#define STB0899_IRQSTATUS_0 0xf123 + +#define STB0899_IRQMSK_3 0xf124 +#define STB0899_IRQMSK_2 0xf125 +#define STB0899_IRQMSK_1 0xf126 +#define STB0899_IRQMSK_0 0xf127 + +#define STB0899_IRQCFG 0xf128 + +#define STB0899_GHOSTREG 0xf000 + +#define STB0899_S2DEMOD 0xf3fc +#define STB0899_S2FEC 0xfafc + + +#endif diff --git a/linux/drivers/media/dvb/frontends/stb6100.c b/linux/drivers/media/dvb/frontends/stb6100.c new file mode 100644 index 000000000..29bc07b86 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb6100.c @@ -0,0 +1,552 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> + +#include "dvb_frontend.h" +#include "stb6100.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); + + +#define FE_ERROR 0 +#define FE_NOTICE 1 +#define FE_INFO 2 +#define FE_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > FE_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ + else if ((x > FE_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + +struct stb6100_lkup { + u32 val_low; + u32 val_high; + u8 reg; +}; + +static int stb6100_release(struct dvb_frontend *fe); + +static const struct stb6100_lkup lkup[] = { + { 0, 950000, 0x0a }, + { 950000, 1000000, 0x0a }, + { 1000000, 1075000, 0x0c }, + { 1075000, 1200000, 0x00 }, + { 1200000, 1300000, 0x01 }, + { 1300000, 1370000, 0x02 }, + { 1370000, 1470000, 0x04 }, + { 1470000, 1530000, 0x05 }, + { 1530000, 1650000, 0x06 }, + { 1650000, 1800000, 0x08 }, + { 1800000, 1950000, 0x0a }, + { 1950000, 2150000, 0x0c }, + { 2150000, 9999999, 0x0c }, + { 0, 0, 0x00 } +}; + +/* Register names for easy debugging. */ +static const char *stb6100_regnames[] = { + [STB6100_LD] = "LD", + [STB6100_VCO] = "VCO", + [STB6100_NI] = "NI", + [STB6100_NF_LSB] = "NF", + [STB6100_K] = "K", + [STB6100_G] = "G", + [STB6100_F] = "F", + [STB6100_DLB] = "DLB", + [STB6100_TEST1] = "TEST1", + [STB6100_FCCK] = "FCCK", + [STB6100_LPEN] = "LPEN", + [STB6100_TEST3] = "TEST3", +}; + +/* Template for normalisation, i.e. setting unused or undocumented + * bits as required according to the documentation. + */ +struct stb6100_regmask { + u8 mask; + u8 set; +}; + +static const struct stb6100_regmask stb6100_template[] = { + [STB6100_LD] = { 0xff, 0x00 }, + [STB6100_VCO] = { 0xff, 0x00 }, + [STB6100_NI] = { 0xff, 0x00 }, + [STB6100_NF_LSB] = { 0xff, 0x00 }, + [STB6100_K] = { 0xc7, 0x38 }, + [STB6100_G] = { 0xef, 0x10 }, + [STB6100_F] = { 0x1f, 0xc0 }, + [STB6100_DLB] = { 0x38, 0xc4 }, + [STB6100_TEST1] = { 0x00, 0x8f }, + [STB6100_FCCK] = { 0x40, 0x0d }, + [STB6100_LPEN] = { 0xf0, 0x0b }, + [STB6100_TEST3] = { 0x00, 0xde }, +}; + +static void stb6100_normalise_regs(u8 regs[]) +{ + int i; + + for (i = 0; i < STB6100_NUMREGS; i++) + regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set; +} + +static int stb6100_read_regs(struct stb6100_state *state, u8 regs[]) +{ + int rc; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = I2C_M_RD, + .buf = regs, + .len = STB6100_NUMREGS + }; + + rc = i2c_transfer(state->i2c, &msg, 1); + if (unlikely(rc != 1)) { + dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]", + state->config->tuner_address, rc); + + return -EREMOTEIO; + } + if (unlikely(verbose > FE_DEBUG)) { + int i; + + dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address); + for (i = 0; i < STB6100_NUMREGS; i++) + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]); + } + return 0; +} + +static int stb6100_read_reg(struct stb6100_state *state, u8 reg) +{ + u8 regs[STB6100_NUMREGS]; + int rc; + + if (unlikely(reg >= STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); + return -EINVAL; + } + if ((rc = stb6100_read_regs(state, regs)) < 0) + return rc; + return (unsigned int)regs[reg]; +} + +static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) +{ + int rc; + u8 cmdbuf[len + 1]; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = 0, + .buf = cmdbuf, + .len = len + 1 + }; + + if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d", + start, len); + return -EINVAL; + } + memcpy(&cmdbuf[1], buf, len); + cmdbuf[0] = start; + + if (unlikely(verbose > FE_DEBUG)) { + int i; + + dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len); + for (i = 0; i < len; i++) + dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]); + } + rc = i2c_transfer(state->i2c, &msg, 1); + if (unlikely(rc != 1)) { + dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]", + (unsigned int)state->config->tuner_address, start, len, rc); + return -EREMOTEIO; + } + return 0; +} + +static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data) +{ + if (unlikely(reg >= STB6100_NUMREGS)) { + dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg); + return -EREMOTEIO; + } + data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set; + return stb6100_write_reg_range(state, &data, reg, 1); +} + +static int stb6100_write_regs(struct stb6100_state *state, u8 regs[]) +{ + stb6100_normalise_regs(regs); + return stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 1); +} + +static int stb6100_get_status(struct dvb_frontend *fe, u32 *status) +{ + int rc; + struct stb6100_state *state = fe->tuner_priv; + + if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0) + return rc; + + return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0; +} + +static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + int rc; + u8 f; + struct stb6100_state *state = fe->tuner_priv; + + if ((rc = stb6100_read_reg(state, STB6100_F)) < 0) + return rc; + f = rc & STB6100_F_F; + + state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */ + + *bandwidth = state->bandwidth = state->status.bandwidth * 1000; + dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth); + return 0; +} + +static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + u32 tmp; + int rc; + struct stb6100_state *state = fe->tuner_priv; + + dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth); + + bandwidth /= 2; /* ZIF */ + + if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */ + tmp = 31; + else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */ + tmp = 0; + else /* if 5 < bw/2 < 36 */ + tmp = (bandwidth + 500000) / 1000000 - 5; + + /* Turn on LPF bandwidth setting clock control, + * set bandwidth, wait 10ms, turn off. + */ + if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0) + return rc; + if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0) + return rc; + msleep(1); + if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0) + return rc; + + return 0; +} + +static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + int rc; + u32 nint, nfrac, fvco; + int psd2, odiv; + struct stb6100_state *state = fe->tuner_priv; + u8 regs[STB6100_NUMREGS]; + + if ((rc = stb6100_read_regs(state, regs)) < 0) + return rc; + + odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT; + psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT; + nint = regs[STB6100_NI]; + nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB]; + fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2); + *frequency = state->frequency = fvco >> (odiv + 1); + + dprintk(verbose, FE_DEBUG, 1, + "frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u", + state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac); + return 0; +} + +#if 0 +static int stb6100_set_rfgain(struct dvb_frontend *fe, u32 rfgain) +{ + + return 0; +} +#endif + +static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + int rc; + const struct stb6100_lkup *ptr; + struct stb6100_state *state = fe->tuner_priv; + struct dvb_frontend_parameters p; + + u32 srate = 0, fvco, nint, nfrac; + u8 regs[STB6100_NUMREGS]; + u8 g, psd2, odiv; + + if ((rc = stb6100_read_regs(state, regs)) < 0) + return rc; + + if (fe->ops.get_frontend) { + dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); + fe->ops.get_frontend(fe, &p); + } + srate = p.u.qpsk.symbol_rate; + + regs[STB6100_DLB] = 0xdc; + /* Disable LPEN */ + regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */ + + if ((rc = stb6100_write_regs(state, regs)) < 0) + return rc; + + /* Baseband gain. */ + if (srate >= 15000000) + g = 9; // +4 dB + else if (srate >= 5000000) + g = 11; // +8 dB + else + g = 14; // +14 dB + + regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g; + regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */ + regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */ + + /* VCO divide ratio (LO divide ratio, VCO prescaler enable). */ + if (frequency <= 1075000) + odiv = 1; + else + odiv = 0; + regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT); + + if ((frequency > 1075000) && (frequency <= 1325000)) + psd2 = 0; + else + psd2 = 1; + regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT); + + /* OSM */ + for (ptr = lkup; + (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high); + ptr++); + if (ptr->val_high == 0) { + printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency); + return -EINVAL; + } + regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg; + + /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */ + fvco = frequency << (1 + odiv); + /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */ + nint = fvco / (state->reference << psd2); + /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */ + nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference; + dprintk(verbose, FE_DEBUG, 1, + "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u", + frequency, srate, (unsigned int)g, (unsigned int)odiv, + (unsigned int)psd2, state->reference, + ptr->reg, fvco, nint, nfrac); + regs[STB6100_NI] = nint; + regs[STB6100_NF_LSB] = nfrac; + regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB); + regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */ + regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */ + regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */ + regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */ + /* Power up. */ + regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN; + + msleep(2); + if ((rc = stb6100_write_regs(state, regs)) < 0) + return rc; + + msleep(2); + regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */ + if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0) + return rc; + + regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */ + if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0) + return rc; + + msleep(10); /* wait for LO to lock */ + regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */ + regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */ + if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0) + return rc; + regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */ + stb6100_normalise_regs(regs); + if ((rc = stb6100_write_reg_range(state, ®s[1], 1, STB6100_NUMREGS - 3)) < 0) + return rc; + + msleep(100); + + return 0; +} + +static int stb6100_sleep(struct dvb_frontend *fe) +{ + /* TODO: power down */ + return 0; +} + +static int stb6100_init(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + struct tuner_state *status = &state->status; + + status->tunerstep = 125000; + status->ifreq = 0; + status->refclock = 27000000; /* Hz */ + status->iqsense = 1; + status->bandwidth = 36000; /* kHz */ + state->bandwidth = status->bandwidth * 1000; /* MHz */ + state->reference = status->refclock / 1000; /* kHz */ + + /* Set default bandwidth. */ + return stb6100_set_bandwidth(fe, status->bandwidth); +} + +static int stb6100_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *state) +{ + switch (param) { + case DVBFE_TUNER_FREQUENCY: + stb6100_get_frequency(fe, &state->frequency); + break; + case DVBFE_TUNER_TUNERSTEP: + break; + case DVBFE_TUNER_IFFREQ: + break; + case DVBFE_TUNER_BANDWIDTH: + stb6100_get_bandwidth(fe, &state->bandwidth); + break; + case DVBFE_TUNER_REFCLOCK: + break; + default: + break; + } + + return 0; +} + +static int stb6100_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *state) +{ + struct stb6100_state *tstate = fe->tuner_priv; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + stb6100_set_frequency(fe, state->frequency); + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_TUNERSTEP: + break; + case DVBFE_TUNER_IFFREQ: + break; + case DVBFE_TUNER_BANDWIDTH: + stb6100_set_bandwidth(fe, state->bandwidth); + tstate->bandwidth = state->bandwidth; + break; + case DVBFE_TUNER_REFCLOCK: + break; + default: + break; + } + + return 0; +} + +static struct dvb_tuner_ops stb6100_ops = { + .info = { + .name = "STB6100 Silicon Tuner", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0, + }, + + .init = stb6100_init, + .sleep = stb6100_sleep, + .get_status = stb6100_get_status, + .get_state = stb6100_get_state, + .set_state = stb6100_set_state, + .release = stb6100_release +}; + +struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + struct stb6100_config *config, + struct i2c_adapter *i2c) +{ + struct stb6100_state *state = NULL; + + state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c = i2c; + state->frontend = fe; + state->reference = config->refclock / 1000; /* kHz */ + fe->tuner_priv = state; + fe->ops.tuner_ops = stb6100_ops; + + printk("%s: Attaching STB6100 \n", __func__); + return fe; + +error: + kfree(state); + return NULL; +} + +static int stb6100_release(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +EXPORT_SYMBOL(stb6100_attach); +MODULE_PARM_DESC(verbose, "Set Verbosity level"); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("STB6100 Silicon tuner"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/stb6100.h b/linux/drivers/media/dvb/frontends/stb6100.h new file mode 100644 index 000000000..395d05659 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb6100.h @@ -0,0 +1,115 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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 __STB_6100_REG_H +#define __STB_6100_REG_H + +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + +#define STB6100_LD 0x00 +#define STB6100_LD_LOCK (1 << 0) + +#define STB6100_VCO 0x01 +#define STB6100_VCO_OSCH (0x01 << 7) +#define STB6100_VCO_OSCH_SHIFT 7 +#define STB6100_VCO_OCK (0x03 << 5) +#define STB6100_VCO_OCK_SHIFT 5 +#define STB6100_VCO_ODIV (0x01 << 4) +#define STB6100_VCO_ODIV_SHIFT 4 +#define STB6100_VCO_OSM (0x0f << 0) + +#define STB6100_NI 0x02 +#define STB6100_NF_LSB 0x03 + +#define STB6100_K 0x04 +#define STB6100_K_PSD2 (0x01 << 2) +#define STB6100_K_PSD2_SHIFT 2 +#define STB6100_K_NF_MSB (0x03 << 0) + +#define STB6100_G 0x05 +#define STB6100_G_G (0x0f << 0) +#define STB6100_G_GCT (0x07 << 5) + +#define STB6100_F 0x06 +#define STB6100_F_F (0x1f << 0) + +#define STB6100_DLB 0x07 + +#define STB6100_TEST1 0x08 + +#define STB6100_FCCK 0x09 +#define STB6100_FCCK_FCCK (0x01 << 6) + +#define STB6100_LPEN 0x0a +#define STB6100_LPEN_LPEN (0x01 << 4) +#define STB6100_LPEN_SYNP (0x01 << 5) +#define STB6100_LPEN_OSCP (0x01 << 6) +#define STB6100_LPEN_BEN (0x01 << 7) + +#define STB6100_TEST3 0x0b + +#define STB6100_NUMREGS 0x0c + + +#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \ + ((y <= val) && (val <= x)) ? 1 : 0) + +#define CHKRANGE(val, x, y) (((val >= x) && (val < y)) ? 1 : 0) + +struct stb6100_config { + u8 tuner_address; + u32 refclock; +}; + +struct stb6100_state { + struct i2c_adapter *i2c; + + const struct stb6100_config *config; + struct dvb_tuner_ops ops; + struct dvb_frontend *frontend; + struct tuner_state status; + + u32 frequency; + u32 srate; + u32 bandwidth; + u32 reference; +}; + +#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + struct stb6100_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, + struct stb6100_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_STB6100 + +#endif diff --git a/linux/drivers/media/dvb/frontends/stb6100_cfg.h b/linux/drivers/media/dvb/frontends/stb6100_cfg.h new file mode 100644 index 000000000..d3133405d --- /dev/null +++ b/linux/drivers/media/dvb/frontends/stb6100_cfg.h @@ -0,0 +1,108 @@ +/* + STB6100 Silicon Tuner + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + Copyright (C) ST Microelectronics + + 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. +*/ + +static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *frequency = t_state.frequency; + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + } + return 0; +} + +static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + return 0; +} + +static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = &fe->ops; + struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *bandwidth = t_state.bandwidth; + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} + +static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.bandwidth = bandwidth; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} diff --git a/linux/drivers/media/dvb/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c index 7a882faf5..cb5b1efd8 100644 --- a/linux/drivers/media/dvb/frontends/tda10048.c +++ b/linux/drivers/media/dvb/frontends/tda10048.c @@ -195,7 +195,7 @@ static struct init_tab { static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) { int ret; - u8 buf [] = { reg, data }; + u8 buf[] = { reg, data }; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; @@ -213,9 +213,9 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) { int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, { .addr = state->config->demod_address, @@ -393,43 +393,89 @@ static int tda10048_get_tps(struct tda10048_state *state, val = tda10048_readreg(state, TDA10048_OUT_CONF2); switch ((val & 0x60) >> 5) { - case 0: p->constellation = QPSK; break; - case 1: p->constellation = QAM_16; break; - case 2: p->constellation = QAM_64; break; + case 0: + p->constellation = QPSK; + break; + case 1: + p->constellation = QAM_16; + break; + case 2: + p->constellation = QAM_64; + break; } switch ((val & 0x18) >> 3) { - case 0: p->hierarchy_information = HIERARCHY_NONE; break; - case 1: p->hierarchy_information = HIERARCHY_1; break; - case 2: p->hierarchy_information = HIERARCHY_2; break; - case 3: p->hierarchy_information = HIERARCHY_4; break; + case 0: + p->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + p->hierarchy_information = HIERARCHY_1; + break; + case 2: + p->hierarchy_information = HIERARCHY_2; + break; + case 3: + p->hierarchy_information = HIERARCHY_4; + break; } switch (val & 0x07) { - case 0: p->code_rate_HP = FEC_1_2; break; - case 1: p->code_rate_HP = FEC_2_3; break; - case 2: p->code_rate_HP = FEC_3_4; break; - case 3: p->code_rate_HP = FEC_5_6; break; - case 4: p->code_rate_HP = FEC_7_8; break; + case 0: + p->code_rate_HP = FEC_1_2; + break; + case 1: + p->code_rate_HP = FEC_2_3; + break; + case 2: + p->code_rate_HP = FEC_3_4; + break; + case 3: + p->code_rate_HP = FEC_5_6; + break; + case 4: + p->code_rate_HP = FEC_7_8; + break; } val = tda10048_readreg(state, TDA10048_OUT_CONF3); switch (val & 0x07) { - case 0: p->code_rate_LP = FEC_1_2; break; - case 1: p->code_rate_LP = FEC_2_3; break; - case 2: p->code_rate_LP = FEC_3_4; break; - case 3: p->code_rate_LP = FEC_5_6; break; - case 4: p->code_rate_LP = FEC_7_8; break; + case 0: + p->code_rate_LP = FEC_1_2; + break; + case 1: + p->code_rate_LP = FEC_2_3; + break; + case 2: + p->code_rate_LP = FEC_3_4; + break; + case 3: + p->code_rate_LP = FEC_5_6; + break; + case 4: + p->code_rate_LP = FEC_7_8; + break; } val = tda10048_readreg(state, TDA10048_OUT_CONF1); switch ((val & 0x0c) >> 2) { - case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; - case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; - case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; - case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; + case 0: + p->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + p->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + p->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + p->guard_interval = GUARD_INTERVAL_1_4; + break; } switch (val & 0x02) { - case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; + case 0: + p->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->transmission_mode = TRANSMISSION_MODE_8K; + break; } return 0; diff --git a/linux/drivers/media/dvb/frontends/tda8261.c b/linux/drivers/media/dvb/frontends/tda8261.c new file mode 100644 index 000000000..b6d177799 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/tda8261.c @@ -0,0 +1,230 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + 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 <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include "dvb_frontend.h" +#include "tda8261.h" + +struct tda8261_state { + struct dvb_frontend *fe; + struct i2c_adapter *i2c; + const struct tda8261_config *config; + + /* state cache */ + u32 frequency; + u32 bandwidth; +}; + +static int tda8261_read(struct tda8261_state *state, u8 *buf) +{ + const struct tda8261_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 2 }; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) + printk("%s: read error, err=%d\n", __func__, err); + + return err; +} + +static int tda8261_write(struct tda8261_state *state, u8 *buf) +{ + const struct tda8261_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 }; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) + printk("%s: write error, err=%d\n", __func__, err); + + return err; +} + +static int tda8261_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda8261_state *state = fe->tuner_priv; + u8 result = 0; + int err = 0; + + *status = 0; + + if ((err = tda8261_read(state, &result)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + if ((result >> 6) & 0x01) { + printk("%s: Tuner Phase Locked\n", __func__); + *status = 1; + } + + return err; +} + +static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */ +static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 }; + +static int tda8261_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda8261_state *state = fe->tuner_priv; + int err = 0; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_BANDWIDTH: + tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */ + break; + default: + printk("%s: Unknown parameter (param=%d)\n", __func__, param); + err = -EINVAL; + break; + } + + return err; +} + +static int tda8261_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda8261_state *state = fe->tuner_priv; + const struct tda8261_config *config = state->config; + u32 frequency, N, status = 0; + u8 buf[4]; + int err = 0; + + if (param & DVBFE_TUNER_FREQUENCY) { + /** + * N = Max VCO Frequency / Channel Spacing + * Max VCO Frequency = VCO frequency + (channel spacing - 1) + * (to account for half channel spacing on either side) + */ + frequency = tstate->frequency; + if ((frequency < 950000) || (frequency > 2150000)) { + printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); + return -EINVAL; + } + N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size]; + printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n", + __func__, config->step_size, div_tab[config->step_size], N, N); + + buf[0] = (N >> 8) & 0xff; + buf[1] = N & 0xff; + buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1); + + if (frequency < 1450000) + buf[3] = 0x00; + if (frequency < 2000000) + buf[3] = 0x40; + if (frequency < 2150000) + buf[3] = 0x80; + + /* Set params */ + if ((err = tda8261_write(state, buf)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + /* sleep for some time */ + printk("%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + if ((err = tda8261_get_status(fe, &status)) < 0) { + printk("%s: I/O Error\n", __func__); + return err; + } + if (status == 1) { + printk("%s: Tuner Phase locked: status=%d\n", __func__, status); + state->frequency = frequency; /* cache successful state */ + } else { + printk("%s: No Phase lock: status=%d\n", __func__, status); + } + } else { + printk("%s: Unknown parameter (param=%d)\n", __func__, param); + return -EINVAL; + } + + return 0; +} + +static int tda8261_release(struct dvb_frontend *fe) +{ + struct tda8261_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static struct dvb_tuner_ops tda8261_ops = { + + .info = { + .name = "TDA8261", +// .tuner_name = NULL, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0 + }, + + .set_state = tda8261_set_state, + .get_state = tda8261_get_state, + .get_status = tda8261_get_status, + .release = tda8261_release +}; + +struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c) +{ + struct tda8261_state *state = NULL; + + if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL) + goto exit; + + state->config = config; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + fe->ops.tuner_ops = tda8261_ops; + + fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size]; +// fe->ops.tuner_ops.tuner_name = &config->buf; + +// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n", +// __func__, fe->ops.tuner_ops.tuner_name); + printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__); + + return fe; + +exit: + kfree(state); + return NULL; +} + +EXPORT_SYMBOL(tda8261_attach); +MODULE_PARM_DESC(verbose, "Set verbosity level"); + +MODULE_AUTHOR("Manu Abraham"); +MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/tda8261.h b/linux/drivers/media/dvb/frontends/tda8261.h new file mode 100644 index 000000000..006e45351 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/tda8261.h @@ -0,0 +1,55 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + 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 __TDA8261_H +#define __TDA8261_H + +enum tda8261_step { + TDA8261_STEP_2000 = 0, /* 2000 kHz */ + TDA8261_STEP_1000, /* 1000 kHz */ + TDA8261_STEP_500, /* 500 kHz */ + TDA8261_STEP_250, /* 250 kHz */ + TDA8261_STEP_125 /* 125 kHz */ +}; + +struct tda8261_config { +// u8 buf[16]; + u8 addr; + enum tda8261_step step_size; +}; + +#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, + const struct tda8261_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif //CONFIG_DVB_TDA8261 + +#endif// __TDA8261_H diff --git a/linux/drivers/media/dvb/frontends/tda8261_cfg.h b/linux/drivers/media/dvb/frontends/tda8261_cfg.h new file mode 100644 index 000000000..1af1ee49b --- /dev/null +++ b/linux/drivers/media/dvb/frontends/tda8261_cfg.h @@ -0,0 +1,84 @@ +/* + TDA8261 8PSK/QPSK tuner driver + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + 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. +*/ + +static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *frequency = t_state.frequency; + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + } + return 0; +} + +static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + struct tuner_state t_state; + int err = 0; + + t_state.frequency = frequency; + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->set_state) { + if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + } + printk("%s: Frequency=%d\n", __func__, t_state.frequency); + return 0; +} + +static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_frontend_ops *frontend_ops = &fe->ops; + struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; + struct tuner_state t_state; + int err = 0; + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_state) { + if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) { + printk("%s: Invalid parameter\n", __func__); + return err; + } + *bandwidth = t_state.bandwidth; + } + printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); + return 0; +} diff --git a/linux/drivers/media/dvb/frontends/z0194a.h b/linux/drivers/media/dvb/frontends/z0194a.h index d2876d2e1..07f3fc099 100644 --- a/linux/drivers/media/dvb/frontends/z0194a.h +++ b/linux/drivers/media/dvb/frontends/z0194a.h @@ -12,7 +12,7 @@ #ifndef Z0194A #define Z0194A -static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe, +static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) { u8 aclk = 0; @@ -40,7 +40,7 @@ static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe, return 0; } -static u8 sharp_z0194a__inittab[] = { +static u8 sharp_z0194a_inittab[] = { 0x01, 0x15, 0x02, 0x00, 0x03, 0x00, @@ -82,16 +82,4 @@ static u8 sharp_z0194a__inittab[] = { 0xff, 0xff }; -static struct stv0299_config sharp_z0194a_config = { - .demod_address = 0x68, - .inittab = sharp_z0194a__inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a__set_symbol_rate, -}; - #endif diff --git a/linux/drivers/media/dvb/frontends/zl10353.c b/linux/drivers/media/dvb/frontends/zl10353.c index 11160a3ee..2e449a457 100644 --- a/linux/drivers/media/dvb/frontends/zl10353.c +++ b/linux/drivers/media/dvb/frontends/zl10353.c @@ -225,15 +225,18 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, /* These are extrapolated from the 7 and 8MHz values */ zl10353_single_write(fe, MCLK_RATIO, 0x97); zl10353_single_write(fe, 0x64, 0x34); + zl10353_single_write(fe, 0xcc, 0xdd); break; case BANDWIDTH_7_MHZ: zl10353_single_write(fe, MCLK_RATIO, 0x86); zl10353_single_write(fe, 0x64, 0x35); + zl10353_single_write(fe, 0xcc, 0x73); break; case BANDWIDTH_8_MHZ: default: zl10353_single_write(fe, MCLK_RATIO, 0x75); zl10353_single_write(fe, 0x64, 0x36); + zl10353_single_write(fe, 0xcc, 0x73); } zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); diff --git a/linux/drivers/media/dvb/siano/sms-cards.c b/linux/drivers/media/dvb/siano/sms-cards.c index 9da260fe3..6f9b77360 100644 --- a/linux/drivers/media/dvb/siano/sms-cards.c +++ b/linux/drivers/media/dvb/siano/sms-cards.c @@ -42,6 +42,10 @@ struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5510), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5520), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5530), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5580), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5590), diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig index 867027cea..9e2ece9e4 100644 --- a/linux/drivers/media/dvb/ttpci/Kconfig +++ b/linux/drivers/media/dvb/ttpci/Kconfig @@ -104,6 +104,8 @@ config DVB_BUDGET_CI select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE @@ -131,6 +133,8 @@ config DVB_BUDGET_AV select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_TDA8261 if !DVB_FE_CUSTOMISE select DVB_TUA6100 if !DVB_FE_CUSTOMISE help Support for simple SAA7146 based DVB cards diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index bb63e2121..b99057a68 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -36,7 +36,6 @@ #include <linux/fs.h> #include <linux/timer.h> #include <linux/poll.h> -#include <linux/byteorder/swabb.h> #include <linux/smp_lock.h> #include <linux/kernel.h> @@ -52,6 +51,10 @@ #include <linux/i2c.h> #include <linux/kthread.h> #include <asm/unaligned.h> +#include <asm/byteorder.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28) +#include <linux/byteorder/swabb.h> +#endif #include <asm/system.h> diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c index 1032ea778..f996cef79 100644 --- a/linux/drivers/media/dvb/ttpci/budget-av.c +++ b/linux/drivers/media/dvb/ttpci/budget-av.c @@ -35,6 +35,11 @@ #include "budget.h" #include "stv0299.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "tda8261.h" +#include "tda8261_cfg.h" #include "tda1002x.h" #include "tda1004x.h" #include "tua6100.h" @@ -882,6 +887,281 @@ static struct stv0299_config philips_sd1878_config = { .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, }; +/* KNC1 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x08 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x33 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xee }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +/* STB0899 demodulator config for the KNC1 and clones */ +static struct stb0899_config knc1_dvbs2_config = { + .init_dev = knc1_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = knc1_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, +// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ + .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ +// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_OFF, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 90000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = tda8261_get_frequency, + .tuner_set_frequency = tda8261_set_frequency, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = tda8261_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +/* + * SD1878/SHA tuner config + * 1F, Single I/P, Horizontal mount, High Sensitivity + */ +static const struct tda8261_config sd1878c_config = { +// .name = "SD1878/SHA", + .addr = 0x60, + .step_size = TDA8261_STEP_1000 /* kHz */ +}; + static u8 read_pwm(struct budget_av *budget_av) { u8 b = 0xff; @@ -905,8 +1185,11 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBS_TV_STAR 0x0014 #define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 #define SUBID_DVBS_TV_STAR_CI 0x0016 +#define SUBID_DVBS2_KNC1 0x0018 +#define SUBID_DVBS2_KNC1_OEM 0x0019 #define SUBID_DVBS_EASYWATCH_1 0x001a #define SUBID_DVBS_EASYWATCH_2 0x001b +#define SUBID_DVBS2_EASYWATCH 0x001d #define SUBID_DVBS_EASYWATCH 0x001e #define SUBID_DVBC_EASYWATCH 0x002a @@ -941,6 +1224,9 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBT_KNC1_PLUS: case SUBID_DVBC_EASYWATCH: case SUBID_DVBC_KNC1_PLUS_MK3: + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; } @@ -993,7 +1279,14 @@ static void frontend_init(struct budget_av *budget_av) fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; } break; + case SUBID_DVBS2_KNC1: + case SUBID_DVBS2_KNC1_OEM: + case SUBID_DVBS2_EASYWATCH: + budget_av->reinitialise_demod = 1; + if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) + dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); + break; case SUBID_DVBS_CINERGY1200: fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, &budget_av->budget.i2c_adap); @@ -1260,6 +1553,8 @@ static struct saa7146_ext_vv vv_data = { static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); +MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); @@ -1290,6 +1585,9 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), + MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), + MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c index 969877f58..89797e1bd 100644 --- a/linux/drivers/media/dvb/ttpci/budget-ci.c +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c @@ -47,6 +47,11 @@ #include "stv0299.h" #include "stv0297.h" #include "tda1004x.h" +#include "stb0899_drv.h" +#include "stb0899_reg.h" +#include "stb0899_cfg.h" +#include "stb6100.h" +#include "stb6100_cfg.h" #include "lnbp21.h" #include "bsbe1.h" #include "bsru6.h" @@ -1079,7 +1084,271 @@ static struct tda10023_config tda10023_config = { .deltaf = 0xa511, }; +/* TT S2-3200 DVB-S (STB0899) Inittab */ +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { + + { STB0899_DEV_ID , 0x81 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x8c }, + { STB0899_DISF22RX , 0x9a }, + { STB0899_SYSREG , 0x0b }, + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0x30 }, + { STB0899_IRQSTATUS_2 , 0x00 }, + { STB0899_IRQSTATUS_1 , 0x00 }, + { STB0899_IRQSTATUS_0 , 0x00 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x20 }, + { STB0899_IOPVALUE3 , 0xc9 }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x40 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x00 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x41 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x7a }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xc7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xdd }, + { STB0899_LDT2 , 0xc9 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfb }, + { STB0899_QDCCOMP , 0x03 }, + { STB0899_POWERI , 0x3b }, + { STB0899_POWERQ , 0x3d }, + { STB0899_RCOMP , 0x81 }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x04 }, + { STB0899_AGC2I2 , 0xf5 }, + { STB0899_TLIR , 0x25 }, + { STB0899_RTF , 0x80 }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xca }, + { STB0899_CFRM , 0xf1 }, + { STB0899_CFRL , 0xf3 }, + { STB0899_NIRM , 0x2a }, + { STB0899_NIRL , 0x05 }, + { STB0899_ISYMB , 0x17 }, + { STB0899_QSYMB , 0xfa }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0xfd }, + { STB0899_EQUAQ1 , 0x04 }, + { STB0899_EQUAI2 , 0x0f }, + { STB0899_EQUAQ2 , 0xff }, + { STB0899_EQUAI3 , 0xdf }, + { STB0899_EQUAQ3 , 0xfa }, + { STB0899_EQUAI4 , 0x37 }, + { STB0899_EQUAQ4 , 0x0d }, + { STB0899_EQUAI5 , 0xbd }, + { STB0899_EQUAQ5 , 0xf7 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0xff }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x00 }, + { STB0899_ECNT3L , 0x00 }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xf0 }, + { STB0899_VTH23 , 0xa0 }, + { STB0899_VTH34 , 0x78 }, + { STB0899_VTH56 , 0x4e }, + { STB0899_VTH67 , 0x48 }, + { STB0899_VTH78 , 0x38 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x40 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x0c }, + { STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x00 }, + { STB0899_TSLLSTKL , 0x00 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0xab }, + { STB0899_PCKLENUL , 0x00 }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xcc }, + { STB0899_TSSTATUS , 0x80 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x96 }, + { STB0899_ERRCTRL3 , 0x89 }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x1f }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0x00 }, + { STB0899_MATSTRL , 0x00 }, + { STB0899_UPLSTRM , 0x00 }, + { STB0899_UPLSTRL , 0x00 }, + { STB0899_DFLSTRM , 0x00 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x00 }, + { STB0899_SYNCDSTRM , 0x00 }, + { STB0899_SYNCDSTRL , 0x00 }, + { STB0899_CFGPDELSTATUS1 , 0x10 }, + { STB0899_CFGPDELSTATUS2 , 0x00 }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x00 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; +static struct stb0899_config tt3200_config = { + .init_dev = tt3200_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = tt3200_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .postproc = NULL, + + .demod_address = 0x68, + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL +}; + +struct stb6100_config tt3200_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; static void frontend_init(struct budget_ci *budget_ci) { @@ -1160,6 +1429,46 @@ static void frontend_init(struct budget_ci *budget_ci) } } break; + + case 0x1019: // TT S2-3200 PCI + /* + * NOTE! on some STB0899 versions, the internal PLL takes a longer time + * to settle, aka LOCK. On the older revisions of the chip, we don't see + * this, as a result on the newer chips the entire clock tree, will not + * be stable after a freshly POWER 'ed up situation. + * In this case, we should RESET the STB0899 (Active LOW) and wait for + * PLL stabilization. + * + * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is + * connected to the SAA7146 GPIO, GPIO2, Pin 142 + */ + /* Reset Demodulator */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); + /* Wait for everything to die */ + msleep(50); + /* Pull it up out of Reset state */ + saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); + /* Wait for PLL to stabilize */ + msleep(250); + /* + * PLL state should be stable now. Ideally, we should check + * for PLL LOCK status. But well, never mind! + */ + budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { + if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { + printk("%s: No LNBP21 found!\n", __FUNCTION__); + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } else { + dvb_frontend_detach(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } + break; + } if (budget_ci->budget.dvb_frontend == NULL) { @@ -1250,6 +1559,7 @@ MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), @@ -1259,6 +1569,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), + MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), { .vendor = 0, } diff --git a/linux/drivers/media/dvb/ttpci/budget.h b/linux/drivers/media/dvb/ttpci/budget.h index 6129196b8..e1ebf5e8a 100644 --- a/linux/drivers/media/dvb/ttpci/budget.h +++ b/linux/drivers/media/dvb/ttpci/budget.h @@ -104,6 +104,7 @@ static struct saa7146_pci_extension_data x_var = { \ #define BUDGET_CIN1200C_MK3 15 #define BUDGET_KNC1C_MK3 16 #define BUDGET_KNC1CP_MK3 17 +#define BUDGET_KNC1S2 18 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 13085a8e2..8775b78af 100644 --- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -828,6 +828,12 @@ static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) ISO_BUF_COUNT, &ttusb->iso_dma_handle); + if (!ttusb->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + memset(ttusb->iso_buffer, 0, ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); @@ -1679,7 +1685,14 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb_setup_interfaces(ttusb); - ttusb_alloc_iso_urbs(ttusb); + result = ttusb_alloc_iso_urbs(ttusb); + if (result < 0) { + dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__); + mutex_unlock(&ttusb->semi2c); + kfree(ttusb); + return result; + } + if (ttusb_init_controller(ttusb)) printk("ttusb_init_controller: error\n"); diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 5c2885e17..7cfc2e4d0 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1166,6 +1166,12 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) ISO_BUF_COUNT), &dec->iso_dma_handle); + if (!dec->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + memset(dec->iso_buffer, 0, ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); @@ -1263,6 +1269,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec) dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE, GFP_ATOMIC, &dec->irq_dma_handle); if(!dec->irq_buffer) { + usb_free_urb(dec->irq_urb); return -ENOMEM; } usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, diff --git a/linux/drivers/media/radio/Kconfig b/linux/drivers/media/radio/Kconfig index 04cd7c04b..5189c4eb4 100644 --- a/linux/drivers/media/radio/Kconfig +++ b/linux/drivers/media/radio/Kconfig @@ -355,6 +355,20 @@ config USB_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support" depends on USB && VIDEO_V4L2 ---help--- + This is a driver for USB devices with the Silicon Labs SI470x + chip. Currently these devices are known to work: + - 10c4:818a: Silicon Labs USB FM Radio Reference Design + - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) + - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700) + + Sound is provided by the ALSA USB Audio/MIDI driver. Therefore + if you don't want to use the device solely for RDS receiving, + it is recommended to also select SND_USB_AUDIO. + + Please have a look at the documentation, especially on how + to redirect the audio stream from the radio to your sound device: + Documentation/video4linux/si470x.txt + Say Y here if you want to connect this type of radio to your computer's USB port. diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c index 7172977c7..d1865b164 100644 --- a/linux/drivers/media/radio/dsbr100.c +++ b/linux/drivers/media/radio/dsbr100.c @@ -94,8 +94,8 @@ */ #include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define DRIVER_VERSION "v0.41" -#define RADIO_VERSION KERNEL_VERSION(0,4,1) +#define DRIVER_VERSION "v0.43" +#define RADIO_VERSION KERNEL_VERSION(0, 4, 3) static struct v4l2_queryctrl radio_qctrl[] = { { @@ -105,7 +105,27 @@ static struct v4l2_queryctrl radio_qctrl[] = { .maximum = 1, .default_value = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, - } + }, +/* HINT: the disabled controls are only here to satify kradio and such apps */ + { .id = V4L2_CID_AUDIO_VOLUME, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .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_LOUDNESS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, }; #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" @@ -132,6 +152,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf, static void usb_dsbr100_disconnect(struct usb_interface *intf); static int usb_dsbr100_open(struct inode *inode, struct file *file); static int usb_dsbr100_close(struct inode *inode, struct file *file); +static int usb_dsbr100_suspend(struct usb_interface *intf, + pm_message_t message); +static int usb_dsbr100_resume(struct usb_interface *intf); static int radio_nr = -1; module_param(radio_nr, int, 0); @@ -158,10 +181,16 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); /* USB subsystem interface */ static struct usb_driver usb_dsbr100_driver = { - .name = "dsbr100", - .probe = usb_dsbr100_probe, - .disconnect = usb_dsbr100_disconnect, - .id_table = usb_dsbr100_device_table, + .name = "dsbr100", + .probe = usb_dsbr100_probe, + .disconnect = usb_dsbr100_disconnect, + .id_table = usb_dsbr100_device_table, + .suspend = usb_dsbr100_suspend, + .resume = usb_dsbr100_resume, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) + .reset_resume = usb_dsbr100_resume, +#endif + .supports_autosuspend = 0, }; /* Low-level device interface begins here */ @@ -172,11 +201,11 @@ static int dsbr100_start(struct dsbr100_device *radio) if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 || + 0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 || usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), DSB100_ONOFF, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x01, 0x00, radio->transfer_buffer, 8, 300)<0) + 0x01, 0x00, radio->transfer_buffer, 8, 300) < 0) return -1; radio->muted=0; return (radio->transfer_buffer)[0]; @@ -189,11 +218,11 @@ static int dsbr100_stop(struct dsbr100_device *radio) if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 || + 0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 || usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), DSB100_ONOFF, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x00, radio->transfer_buffer, 8, 300)<0) + 0x00, 0x00, radio->transfer_buffer, 8, 300) < 0) return -1; radio->muted=1; return (radio->transfer_buffer)[0]; @@ -202,24 +231,24 @@ static int dsbr100_stop(struct dsbr100_device *radio) /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ static int dsbr100_setfreq(struct dsbr100_device *radio, int freq) { - freq = (freq/16*80)/1000+856; + freq = (freq / 16 * 80) / 1000 + 856; if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), DSB100_TUNE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - (freq>>8)&0x00ff, freq&0xff, - radio->transfer_buffer, 8, 300)<0 || + (freq >> 8) & 0x00ff, freq & 0xff, + radio->transfer_buffer, 8, 300) < 0 || usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 || + 0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 || usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) { + 0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) { radio->stereo = -1; return -1; } - radio->stereo = ! ((radio->transfer_buffer)[0]&0x01); + radio->stereo = !((radio->transfer_buffer)[0] & 0x01); return (radio->transfer_buffer)[0]; } @@ -230,10 +259,10 @@ static void dsbr100_getstat(struct dsbr100_device *radio) if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0) + 0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0) radio->stereo = -1; else - radio->stereo = ! (radio->transfer_buffer[0]&0x01); + radio->stereo = !(radio->transfer_buffer[0] & 0x01); } @@ -266,7 +295,7 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "dsbr100", sizeof(v->driver)); strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + sprintf(v->bus_info, "USB"); v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER; return 0; @@ -283,9 +312,9 @@ static int vidioc_g_tuner(struct file *file, void *priv, dsbr100_getstat(radio); strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; - v->rangelow = FREQ_MIN*FREQ_MUL; - v->rangehigh = FREQ_MAX*FREQ_MUL; - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->rangelow = FREQ_MIN * FREQ_MUL; + v->rangehigh = FREQ_MAX * FREQ_MUL; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; v->capability = V4L2_TUNER_CAP_LOW; if(radio->stereo) v->audmode = V4L2_TUNER_MODE_STEREO; @@ -310,8 +339,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct dsbr100_device *radio = video_drvdata(file); radio->curfreq = f->frequency; - if (dsbr100_setfreq(radio, radio->curfreq)==-1) - warn("Set frequency failed"); + if (dsbr100_setfreq(radio, radio->curfreq) == -1) + dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); return 0; } @@ -332,8 +361,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } @@ -362,12 +390,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv, case V4L2_CID_AUDIO_MUTE: if (ctrl->value) { if (dsbr100_stop(radio) == -1) { - warn("Radio did not respond properly"); + dev_warn(&radio->usbdev->dev, + "Radio did not respond properly\n"); return -EBUSY; } } else { if (dsbr100_start(radio) == -1) { - warn("Radio did not respond properly"); + dev_warn(&radio->usbdev->dev, + "Radio did not respond properly\n"); return -EBUSY; } } @@ -411,18 +441,25 @@ static int vidioc_s_audio(struct file *file, void *priv, static int usb_dsbr100_open(struct inode *inode, struct file *file) { struct dsbr100_device *radio = video_drvdata(file); + int retval; lock_kernel(); radio->users = 1; radio->muted = 1; - if (dsbr100_start(radio)<0) { - warn("Radio did not start up properly"); + if (dsbr100_start(radio) < 0) { + dev_warn(&radio->usbdev->dev, + "Radio did not start up properly\n"); radio->users = 0; unlock_kernel(); return -EIO; } - dsbr100_setfreq(radio, radio->curfreq); + + retval = dsbr100_setfreq(radio, radio->curfreq); + + if (retval == -1) + printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n"); + unlock_kernel(); return 0; } @@ -441,6 +478,36 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file) return 0; } +/* Suspend device - stop device. */ +static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + int retval; + + retval = dsbr100_stop(radio); + if (retval == -1) + dev_warn(&intf->dev, "dsbr100_stop failed\n"); + + dev_info(&intf->dev, "going into suspend..\n"); + + return 0; +} + +/* Resume device - start device. */ +static int usb_dsbr100_resume(struct usb_interface *intf) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + int retval; + + retval = dsbr100_start(radio); + if (retval == -1) + dev_warn(&intf->dev, "dsbr100_start failed\n"); + + dev_info(&intf->dev, "coming out of suspend..\n"); + + return 0; +} + /* File system interface */ static const struct file_operations usb_dsbr100_fops = { .owner = THIS_MODULE, @@ -483,13 +550,20 @@ static int usb_dsbr100_probe(struct usb_interface *intf, { struct dsbr100_device *radio; - if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL))) + radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL); + + if (!radio) return -ENOMEM; - if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) { + + radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL); + + if (!(radio->transfer_buffer)) { kfree(radio); return -ENOMEM; } - if (!(radio->videodev = video_device_alloc())) { + radio->videodev = video_device_alloc(); + + if (!(radio->videodev)) { kfree(radio->transfer_buffer); kfree(radio); return -ENOMEM; @@ -499,10 +573,10 @@ static int usb_dsbr100_probe(struct usb_interface *intf, radio->removed = 0; radio->users = 0; radio->usbdev = interface_to_usbdev(intf); - radio->curfreq = FREQ_MIN*FREQ_MUL; + radio->curfreq = FREQ_MIN * FREQ_MUL; video_set_drvdata(radio->videodev, radio); if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) { - warn("Could not register video device"); + dev_warn(&intf->dev, "Could not register video device\n"); video_device_release(radio->videodev); kfree(radio->transfer_buffer); kfree(radio); diff --git a/linux/drivers/media/radio/radio-aimslab.c b/linux/drivers/media/radio/radio-aimslab.c index 483ada689..4f3886097 100644 --- a/linux/drivers/media/radio/radio-aimslab.c +++ b/linux/drivers/media/radio/radio-aimslab.c @@ -1,7 +1,7 @@ /* radiotrack (radioreveal) driver for Linux radio support * (c) 1997 M. Kirkwood * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> - * Converted to new API by Alan Cox <Alan.Cox@linux.org> + * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> * * History: diff --git a/linux/drivers/media/radio/radio-cadet.c b/linux/drivers/media/radio/radio-cadet.c index f40c079ea..d05141fd9 100644 --- a/linux/drivers/media/radio/radio-cadet.c +++ b/linux/drivers/media/radio/radio-cadet.c @@ -23,7 +23,7 @@ * 2002-01-17 Adam Belay <ambx1@neo.rr.com> * Updated to latest pnp code * - * 2003-01-31 Alan Cox <alan@redhat.com> + * 2003-01-31 Alan Cox <alan@lxorguk.ukuu.org.uk> * Cleaned up locking, delay code, general odds and ends * * 2006-07-30 Hans J. Koch <koch@hjk-az.de> diff --git a/linux/drivers/media/radio/radio-gemtek.c b/linux/drivers/media/radio/radio-gemtek.c index 003c7b2f7..5dbd342bf 100644 --- a/linux/drivers/media/radio/radio-gemtek.c +++ b/linux/drivers/media/radio/radio-gemtek.c @@ -8,7 +8,7 @@ * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff * * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Converted to new API by Alan Cox <Alan.Cox@linux.org> + * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> * * TODO: Allow for more than one of these foolish entities :-) diff --git a/linux/drivers/media/radio/radio-mr800.c b/linux/drivers/media/radio/radio-mr800.c index 2ae8e1447..208ade5b0 100644 --- a/linux/drivers/media/radio/radio-mr800.c +++ b/linux/drivers/media/radio/radio-mr800.c @@ -73,6 +73,11 @@ MODULE_LICENSE("GPL"); #define USB_AMRADIO_VENDOR 0x07ca #define USB_AMRADIO_PRODUCT 0xb800 +/* dev_warn macro with driver name */ +#define MR800_DRIVER_NAME "radio-mr800" +#define amradio_dev_warn(dev, fmt, arg...) \ + dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) + /* Probably USB_TIMEOUT should be modified in module parameter */ #define BUFFER_LENGTH 8 #define USB_TIMEOUT 500 @@ -155,7 +160,7 @@ MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); /* USB subsystem interface */ static struct usb_driver usb_amradio_driver = { - .name = "radio-mr800", + .name = MR800_DRIVER_NAME, .probe = usb_amradio_probe, .disconnect = usb_amradio_disconnect, .suspend = usb_amradio_suspend, @@ -362,7 +367,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, radio->curfreq = f->frequency; if (amradio_setfreq(radio, radio->curfreq) < 0) - warn("Set frequency failed"); + amradio_dev_warn(&radio->videodev->dev, + "set frequency failed\n"); return 0; } @@ -385,8 +391,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } @@ -417,12 +422,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv, case V4L2_CID_AUDIO_MUTE: if (ctrl->value) { if (amradio_stop(radio) < 0) { - warn("amradio_stop() failed"); + amradio_dev_warn(&radio->videodev->dev, + "amradio_stop failed\n"); return -1; } } else { if (amradio_start(radio) < 0) { - warn("amradio_start() failed"); + amradio_dev_warn(&radio->videodev->dev, + "amradio_start failed\n"); return -1; } } @@ -472,16 +479,23 @@ static int usb_amradio_open(struct inode *inode, struct file *file) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + lock_kernel(); + radio->users = 1; radio->muted = 1; if (amradio_start(radio) < 0) { - warn("Radio did not start up properly"); + amradio_dev_warn(&radio->videodev->dev, + "radio did not start up properly\n"); radio->users = 0; + unlock_kernel(); return -EIO; } if (amradio_setfreq(radio, radio->curfreq) < 0) - warn("Set frequency failed"); + amradio_dev_warn(&radio->videodev->dev, + "set frequency failed\n"); + + unlock_kernel(); return 0; } @@ -506,9 +520,9 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) struct amradio_device *radio = usb_get_intfdata(intf); if (amradio_stop(radio) < 0) - warn("amradio_stop() failed"); + dev_warn(&intf->dev, "amradio_stop failed\n"); - info("radio-mr800: Going into suspend.."); + dev_info(&intf->dev, "going into suspend..\n"); return 0; } @@ -519,9 +533,9 @@ static int usb_amradio_resume(struct usb_interface *intf) struct amradio_device *radio = usb_get_intfdata(intf); if (amradio_start(radio) < 0) - warn("amradio_start() failed"); + dev_warn(&intf->dev, "amradio_start failed\n"); - info("radio-mr800: Coming out of suspend.."); + dev_info(&intf->dev, "coming out of suspend..\n"); return 0; } @@ -600,7 +614,7 @@ static int usb_amradio_probe(struct usb_interface *intf, video_set_drvdata(radio->videodev, radio); if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - warn("Could not register video device"); + dev_warn(&intf->dev, "could not register video device\n"); video_device_release(radio->videodev); kfree(radio->buffer); kfree(radio); @@ -615,9 +629,13 @@ static int __init amradio_init(void) { int retval = usb_register(&usb_amradio_driver); - info(DRIVER_VERSION " " DRIVER_DESC); + pr_info(KBUILD_MODNAME + ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); + if (retval) - err("usb_register failed. Error number %d", retval); + pr_err(KBUILD_MODNAME + ": usb_register failed. Error number %d\n", retval); + return retval; } diff --git a/linux/drivers/media/radio/radio-rtrack2.c b/linux/drivers/media/radio/radio-rtrack2.c index 59592bb84..72413df42 100644 --- a/linux/drivers/media/radio/radio-rtrack2.c +++ b/linux/drivers/media/radio/radio-rtrack2.c @@ -1,7 +1,7 @@ /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff * * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood - * Converted to new API by Alan Cox <Alan.Cox@linux.org> + * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> * * TODO: Allow for more than one of these foolish entities :-) diff --git a/linux/drivers/media/radio/radio-sf16fmi.c b/linux/drivers/media/radio/radio-sf16fmi.c index edf7480bc..20326e7a5 100644 --- a/linux/drivers/media/radio/radio-sf16fmi.c +++ b/linux/drivers/media/radio/radio-sf16fmi.c @@ -3,7 +3,7 @@ * (c) 1997 M. Kirkwood * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz * - * Fitted to new interface by Alan Cox <alan.cox@linux.org> + * Fitted to new interface by Alan Cox <alan@lxorguk.ukuu.org.uk> * Made working and cleaned up functions <mikael.hedin@irf.se> * Support for ISAPnP by Ladislav Michl <ladis@psi.cz> * diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c index e332b3de5..5d6237b6d 100644 --- a/linux/drivers/media/radio/radio-si470x.c +++ b/linux/drivers/media/radio/radio-si470x.c @@ -4,6 +4,7 @@ * 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) + * - KWorld USB FM Radio SnapMusic Mobile 700 (FM700) * * Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net> * @@ -24,19 +25,6 @@ /* - * User Notes: - * - USB Audio is provided by the alsa snd_usb_audio module. - * For listing you have to redirect the sound, for example using: - * arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B - - * - regarding module parameters in /sys/module/radio_si470x/parameters: - * the contents of read-only files (0444) are not updated, even if - * space, band and de are changed using private video controls - * - increase tune_timeout, if you often get -EIO errors - * - hw_freq_seek returns -EAGAIN, when timed out or band limit is reached - */ - - -/* * History: * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net> * Version 1.0.0 @@ -105,6 +93,9 @@ * - afc indication * - more safety checks, let si470x_get_freq return errno * - vidioc behavior corrected according to v4l2 spec + * 2008-10-20 Alexey Klimov <klimov.linux@gmail.com> + * - add support for KWorld USB FM Radio FM700 + * - blacklisted KWorld radio in hid-core.c and hid-ids.h * * ToDo: * - add firmware download/update support @@ -146,6 +137,8 @@ static struct usb_device_id si470x_usb_driver_id_table[] = { { 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) }, + /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) }, /* Terminating entry */ { } }; diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 47102c2c8..c4ee10c37 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -184,7 +184,7 @@ config VIDEO_MSP3400 config VIDEO_CS5345 tristate "Cirrus Logic CS5345 audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Cirrus Logic CS5345 24-bit, 192 kHz stereo A/D converter. @@ -204,7 +204,7 @@ config VIDEO_CS53L32A config VIDEO_M52790 tristate "Mitsubishi M52790 A/V switch" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Mitsubishi M52790 A/V switch. @@ -242,7 +242,7 @@ config VIDEO_WM8739 config VIDEO_VP27SMPX tristate "Panasonic VP27s internal MPX" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the internal MPX of the Panasonic VP27s tuner. @@ -387,7 +387,7 @@ comment "MPEG video encoders" config VIDEO_CX2341X tristate "Conexant CX2341x MPEG encoders" - depends on VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_COMMON + depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON ---help--- Support for the Conexant CX23416 MPEG encoders and CX23415 MPEG encoder/decoders. @@ -750,6 +750,12 @@ config SOC_CAMERA_PLATFORM help This is a generic SoC camera platform driver, useful for testing +config SOC_CAMERA_OV772X + tristate "ov772x camera support" + depends on SOC_CAMERA && I2C + help + This is a ov772x camera driver + config VIDEO_PXA27x tristate "PXA27x Quick Capture Interface driver" depends on VIDEO_DEV && PXA27x && SOC_CAMERA diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index 745780e1f..53d43f9e0 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -10,7 +10,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o videodev-objs := v4l2-dev.o v4l2-ioctl.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-compat-ioctl32.o v4l2-int-device.o obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o @@ -134,6 +134,7 @@ obj-$(CONFIG_SOC_CAMERA) += soc_camera.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o +obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o obj-$(CONFIG_VIDEO_AU0828) += au0828/ diff --git a/linux/drivers/media/video/arv.c b/linux/drivers/media/video/arv.c index a6c2ff1b4..c15dfd37c 100644 --- a/linux/drivers/media/video/arv.c +++ b/linux/drivers/media/video/arv.c @@ -397,8 +397,7 @@ out_up: return ret; } -static int ar_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int ar_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct ar_device *ar = video_get_drvdata(dev); @@ -544,7 +543,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, ar_do_ioctl); + return video_usercopy(file, cmd, arg, ar_do_ioctl); } #if USE_INT @@ -871,7 +870,7 @@ static int __init ar_init(void) } printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", - ar->vdev->minor, M32R_IRQ_INT3, freq); + ar->vdev->num, M32R_IRQ_INT3, freq); return 0; diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c index 5f07a8a07..d60123b41 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.c +++ b/linux/drivers/media/video/au0828/au0828-cards.c @@ -90,6 +90,7 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */ + case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; @@ -185,7 +186,7 @@ void au0828_gpio_setup(struct au0828_dev *dev) } /* table of devices that work with this driver */ -struct usb_device_id au0828_usb_id_table [] = { +struct usb_device_id au0828_usb_id_table[] = { { USB_DEVICE(0x2040, 0x7200), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x7240), @@ -198,6 +199,8 @@ struct usb_device_id au0828_usb_id_table [] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x721b), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x721e), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x721f), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x2040, 0x7280), diff --git a/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c index 59dcb3255..05e38f41c 100644 --- a/linux/drivers/media/video/au0828/au0828-core.c +++ b/linux/drivers/media/video/au0828/au0828-core.c @@ -92,7 +92,8 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, cp, size, 1000); diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c index bc76e4079..9966f83d5 100644 --- a/linux/drivers/media/video/au0828/au0828-dvb.c +++ b/linux/drivers/media/video/au0828/au0828-dvb.c @@ -178,7 +178,8 @@ static int start_urb_transfer(struct au0828_dev *dev) purb->status = -EINPROGRESS; usb_fill_bulk_urb(purb, dev->usbdev, - usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE), + usb_rcvbulkpipe(dev->usbdev, + _AU0828_BULKPIPE), purb->transfer_buffer, URB_BUFSIZE, urb_completion, diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index c7bca940a..09188617b 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -4270,7 +4270,7 @@ static int __devinit bttv_register_video(struct bttv *btv) video_nr[btv->c.nr]) < 0) goto err; printk(KERN_INFO "bttv%d: registered device video%d\n", - btv->c.nr,btv->video_dev->minor & 0x1f); + btv->c.nr, btv->video_dev->num); if (device_create_file(&btv->video_dev->dev, &dev_attr_card)<0) { printk(KERN_ERR "bttv%d: device_create_file 'card' " @@ -4287,7 +4287,7 @@ static int __devinit bttv_register_video(struct bttv *btv) vbi_nr[btv->c.nr]) < 0) goto err; printk(KERN_INFO "bttv%d: registered device vbi%d\n", - btv->c.nr,btv->vbi_dev->minor & 0x1f); + btv->c.nr, btv->vbi_dev->num); if (!btv->has_radio) return 0; @@ -4299,7 +4299,7 @@ static int __devinit bttv_register_video(struct bttv *btv) radio_nr[btv->c.nr]) < 0) goto err; printk(KERN_INFO "bttv%d: registered device radio%d\n", - btv->c.nr,btv->radio_dev->minor & 0x1f); + btv->c.nr, btv->radio_dev->num); /* all done */ return 0; diff --git a/linux/drivers/media/video/bt8xx/bttv-gpio.c b/linux/drivers/media/video/bt8xx/bttv-gpio.c index dce6dae57..74c325e59 100644 --- a/linux/drivers/media/video/bt8xx/bttv-gpio.c +++ b/linux/drivers/media/video/bt8xx/bttv-gpio.c @@ -42,7 +42,7 @@ static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); int len = strlen(sub->wanted); - if (0 == strncmp(dev->bus_id, sub->wanted, len)) + if (0 == strncmp(dev_name(dev), sub->wanted, len)) return 1; return 0; } @@ -91,15 +91,14 @@ int bttv_sub_add_device(struct bttv_core *core, char *name) sub->dev.parent = &core->pci->dev; sub->dev.bus = &bttv_sub_bus_type; sub->dev.release = release_sub_device; - snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d", - name, core->nr); + dev_set_name(&sub->dev, "%s%d", name, core->nr); err = device_register(&sub->dev); if (0 != err) { kfree(sub); return err; } - printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id); + printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); list_add_tail(&sub->list,&core->subs); return 0; } diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h index 0f2a33eb3..20f027ee4 100644 --- a/linux/drivers/media/video/bt8xx/bttv.h +++ b/linux/drivers/media/video/bt8xx/bttv.h @@ -311,7 +311,7 @@ struct bttv_sub_device { struct bttv_sub_driver { struct device_driver drv; - char wanted[BUS_ID_SIZE]; + char wanted[20]; int (*probe)(struct bttv_sub_device *sub); void (*remove)(struct bttv_sub_device *sub); }; diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h index 403695f9a..92961e130 100644 --- a/linux/drivers/media/video/bt8xx/bttvp.h +++ b/linux/drivers/media/video/bt8xx/bttvp.h @@ -461,7 +461,7 @@ struct bttv { }; /* our devices */ -#define BTTV_MAX 16 +#define BTTV_MAX 32 extern unsigned int bttv_num; extern struct bttv bttvs[BTTV_MAX]; diff --git a/linux/drivers/media/video/bw-qcam.c b/linux/drivers/media/video/bw-qcam.c index ca8fabdf3..e534eaf39 100644 --- a/linux/drivers/media/video/bw-qcam.c +++ b/linux/drivers/media/video/bw-qcam.c @@ -707,8 +707,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l * Video4linux interfacing */ -static int qcam_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct qcam_device *qcam=(struct qcam_device *)dev; @@ -868,7 +867,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file, static int qcam_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl); + return video_usercopy(file, cmd, arg, qcam_do_ioctl); } static ssize_t qcam_read(struct file *file, char __user *buf, diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c index ba4d43b90..bdad822a5 100644 --- a/linux/drivers/media/video/c-qcam.c +++ b/linux/drivers/media/video/c-qcam.c @@ -501,8 +501,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le * Video4linux interfacing */ -static int qcam_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct qcam_device *qcam=(struct qcam_device *)dev; @@ -668,9 +667,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file, } static int qcam_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl); + return video_usercopy(file, cmd, arg, qcam_do_ioctl); } static ssize_t qcam_read(struct file *file, char __user *buf, @@ -816,7 +815,7 @@ static int init_cqcam(struct parport *port) } printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", - qcam->vdev.minor, qcam->pport->name); + qcam->vdev.num, qcam->pport->name); qcams[num_cams++] = qcam; diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c index 26c08f00b..1184b9186 100644 --- a/linux/drivers/media/video/cafe_ccic.c +++ b/linux/drivers/media/video/cafe_ccic.c @@ -1483,12 +1483,9 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp) { struct cafe_camera *cam; - lock_kernel(); cam = cafe_find_dev(iminor(inode)); - if (cam == NULL) { - unlock_kernel(); + if (cam == NULL) return -ENODEV; - } filp->private_data = cam; mutex_lock(&cam->s_mutex); @@ -1500,7 +1497,6 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp) } (cam->users)++; mutex_unlock(&cam->s_mutex); - unlock_kernel(); return 0; } @@ -2066,10 +2062,10 @@ static void cafe_dfs_cam_setup(struct cafe_camera *cam) if (!cafe_dfs_root) return; - sprintf(fname, "regs-%d", cam->v4ldev.minor); + sprintf(fname, "regs-%d", cam->v4ldev.num); cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, cam, &cafe_dfs_reg_ops); - sprintf(fname, "cam-%d", cam->v4ldev.minor); + sprintf(fname, "cam-%d", cam->v4ldev.num); cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, cam, &cafe_dfs_cam_ops); } @@ -2103,15 +2099,8 @@ static int cafe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; - u16 classword; struct cafe_camera *cam; - /* - * Make sure we have a camera here - we'll get calls for - * the other cafe devices as well. - */ - pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword); - if (classword != PCI_CLASS_MULTIMEDIA_VIDEO) - return -ENODEV; + /* * Start putting together one of our big camera structures. */ @@ -2299,8 +2288,8 @@ static int cafe_pci_resume(struct pci_dev *pdev) static struct pci_device_id cafe_ids[] = { - { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ - { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, + PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, { 0, } }; diff --git a/linux/drivers/media/video/cpia.c b/linux/drivers/media/video/cpia.c index 0bee440ab..004f36928 100644 --- a/linux/drivers/media/video/cpia.c +++ b/linux/drivers/media/video/cpia.c @@ -39,10 +39,6 @@ #include <asm/io.h> #include <linux/mutex.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif - #include "cpia.h" #include "compat.h" @@ -1352,7 +1348,7 @@ static void create_proc_cpia_cam(struct cam_data *cam) if (!cpia_proc_root || !cam) return; - snprintf(name, sizeof(name), "video%d", cam->vdev.minor); + snprintf(name, sizeof(name), "video%d", cam->vdev.num); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root); if (!ent) @@ -1377,7 +1373,7 @@ static void destroy_proc_cpia_cam(struct cam_data *cam) if (!cam || !cam->proc_entry) return; - snprintf(name, sizeof(name), "video%d", cam->vdev.minor); + snprintf(name, sizeof(name), "video%d", cam->vdev.num); remove_proc_entry(name, cpia_proc_root); cam->proc_entry = NULL; } @@ -3338,8 +3334,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf, return cam->decompressed_frame.count; } -static int cpia_do_ioctl(struct inode *inode, struct file *file, - unsigned int ioctlnr, void *arg) +static int cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = file->private_data; struct cam_data *cam = video_get_drvdata(dev); @@ -3352,9 +3347,9 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, if (mutex_lock_interruptible(&cam->busy_lock)) return -EINTR; - //DBG("cpia_ioctl: %u\n", ioctlnr); + /* DBG("cpia_ioctl: %u\n", cmd); */ - switch (ioctlnr) { + switch (cmd) { /* query capabilities */ case VIDIOCGCAP: { @@ -3729,7 +3724,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, static int cpia_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl); + return video_usercopy(file, cmd, arg, cpia_do_ioctl); } @@ -4010,7 +4005,7 @@ void cpia_unregister_camera(struct cam_data *cam) } #ifdef CONFIG_PROC_FS - DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor); + DBG("destroying /proc/cpia/video%d\n", cam->vdev.num); destroy_proc_cpia_cam(cam); #endif if (!cam->open_count) { diff --git a/linux/drivers/media/video/cpia2/cpia2_core.c b/linux/drivers/media/video/cpia2/cpia2_core.c index 8e55d3a21..08e98e70a 100644 --- a/linux/drivers/media/video/cpia2/cpia2_core.c +++ b/linux/drivers/media/video/cpia2/cpia2_core.c @@ -25,7 +25,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox <alan@redhat.com> + * Alan Cox <alan@lxorguk.ukuu.org.uk> * ****************************************************************************/ diff --git a/linux/drivers/media/video/cpia2/cpia2_usb.c b/linux/drivers/media/video/cpia2/cpia2_usb.c index bd9277873..d1b8fb10c 100644 --- a/linux/drivers/media/video/cpia2/cpia2_usb.c +++ b/linux/drivers/media/video/cpia2/cpia2_usb.c @@ -25,7 +25,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox <alan@redhat.com> + * Alan Cox <alan@lxorguk.ukuu.org.uk> ****************************************************************************/ #include <linux/kernel.h> diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c index 897e8d1a5..3c2d7eac1 100644 --- a/linux/drivers/media/video/cpia2/cpia2_v4l.c +++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c @@ -26,7 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox <alan@redhat.com> + * Alan Cox <alan@lxorguk.ukuu.org.uk> ****************************************************************************/ #include <linux/version.h> @@ -1572,8 +1572,7 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) * cpia2_ioctl * *****************************************************************************/ -static int cpia2_do_ioctl(struct inode *inode, struct file *file, - unsigned int ioctl_nr, void *arg) +static int cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct camera_data *cam = video_drvdata(file); int retval = 0; @@ -1591,7 +1590,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file, } /* Priority check */ - switch (ioctl_nr) { + switch (cmd) { case VIDIOCSWIN: case VIDIOCMCAPTURE: case VIDIOC_S_FMT: @@ -1618,7 +1617,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file, break; } - switch (ioctl_nr) { + switch (cmd) { case VIDIOCGCAP: /* query capabilities */ retval = ioctl_cap_query(arg, cam); break; @@ -1683,7 +1682,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUMINPUT: case VIDIOC_G_INPUT: case VIDIOC_S_INPUT: - retval = ioctl_input(ioctl_nr, arg,cam); + retval = ioctl_input(cmd, arg, cam); break; case VIDIOC_ENUM_FMT: @@ -1843,9 +1842,9 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file, } static int cpia2_ioctl(struct inode *inode, struct file *file, - unsigned int ioctl_nr, unsigned long iarg) + unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl); + return video_usercopy(file, cmd, arg, cpia2_do_ioctl); } /****************************************************************************** @@ -1973,7 +1972,7 @@ void cpia2_unregister_camera(struct camera_data *cam) } else { LOG("/dev/video%d removed while open, " "deferring video_unregister_device\n", - cam->vdev->minor); + cam->vdev->num); } } diff --git a/linux/drivers/media/video/cx18/cx18-av-audio.c b/linux/drivers/media/video/cx18/cx18-av-audio.c index 0b5583788..486cad0c2 100644 --- a/linux/drivers/media/video/cx18/cx18-av-audio.c +++ b/linux/drivers/media/video/cx18/cx18-av-audio.c @@ -215,12 +215,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) void cx18_av_audio_set_path(struct cx18 *cx) { struct cx18_av_state *state = &cx->av_state; + u8 v; /* stop microcontroller */ - cx18_av_and_or(cx, 0x803, ~0x10, 0); + v = cx18_av_read(cx, 0x803) & ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); /* assert soft reset */ - cx18_av_and_or(cx, 0x810, ~0x1, 0x01); + v = cx18_av_read(cx, 0x810) | 0x01; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); /* Mute everything to prevent the PFFT! */ cx18_av_write(cx, 0x8d3, 0x1f); @@ -240,12 +243,14 @@ void cx18_av_audio_set_path(struct cx18 *cx) set_audclk_freq(cx, state->audclk_freq); /* deassert soft reset */ - cx18_av_and_or(cx, 0x810, ~0x1, 0x00); + v = cx18_av_read(cx, 0x810) & ~0x01; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { /* When the microcontroller detects the * audio format, it will unmute the lines */ - cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + v = cx18_av_read(cx, 0x803) | 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); } } @@ -347,19 +352,23 @@ static int get_mute(struct cx18 *cx) static void set_mute(struct cx18 *cx, int mute) { struct cx18_av_state *state = &cx->av_state; + u8 v; if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { /* Must turn off microcontroller in order to mute sound. * Not sure if this is the best method, but it does work. * If the microcontroller is running, then it will undo any * changes to the mute register. */ + v = cx18_av_read(cx, 0x803); if (mute) { /* disable microcontroller */ - cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + v &= ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); cx18_av_write(cx, 0x8d3, 0x1f); } else { /* enable microcontroller */ - cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + v |= 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); } } else { /* SRC1_MUTE_EN */ @@ -375,16 +384,26 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: + { + u8 v; if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - cx18_av_and_or(cx, 0x803, ~0x10, 0); + v = cx18_av_read(cx, 0x803) & ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); cx18_av_write(cx, 0x8d3, 0x1f); } - cx18_av_and_or(cx, 0x810, ~0x1, 1); + v = cx18_av_read(cx, 0x810) | 0x1; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); + retval = set_audclk_freq(cx, *(u32 *)arg); - cx18_av_and_or(cx, 0x810, ~0x1, 0); - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) - cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + + v = cx18_av_read(cx, 0x810) & ~0x1; + cx18_av_write_expect(cx, 0x810, v, v, 0x0f); + if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { + v = cx18_av_read(cx, 0x803) | 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + } return retval; + } case VIDIOC_G_CTRL: switch (ctrl->id) { diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c index 73f5141a4..518bd701d 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.c +++ b/linux/drivers/media/video/cx18/cx18-av-core.c @@ -36,12 +36,31 @@ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) return 0; } +int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask) +{ + u32 reg = 0xc40000 + (addr & ~3); + int shift = (addr & 3) * 8; + u32 x = cx18_read_reg(cx, reg); + + x = (x & ~((u32)0xff << shift)) | ((u32)value << shift); + cx18_write_reg_expect(cx, x, reg, + ((u32)eval << shift), ((u32)mask << shift)); + return 0; +} + int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) { cx18_write_reg(cx, value, 0xc40000 + addr); return 0; } +int +cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask) +{ + cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask); + return 0; +} + int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) { cx18_write_reg_noretry(cx, value, 0xc40000 + addr); @@ -98,14 +117,16 @@ static void cx18_av_initialize(struct cx18 *cx) cx18_av_loadfw(cx); /* Stop 8051 code execution */ - cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000); + cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000, + 0x03000000, 0x13000000); /* initallize the PLL by toggling sleep bit */ v = cx18_av_read4(cx, CXADEC_HOST_REG1); - /* enable sleep mode */ - cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1); + /* enable sleep mode - register appears to be read only... */ + cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe); /* disable sleep mode */ - cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe); + cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe, + v & 0xfffe, 0xffff); /* initialize DLLs */ v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; @@ -125,9 +146,10 @@ static void cx18_av_initialize(struct cx18 *cx) v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; /* enable TUNE_FIL_RST */ - cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v); + cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F); /* disable TUNE_FIL_RST */ - cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE); + cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, + v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F); /* enable 656 output */ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); @@ -251,10 +273,9 @@ void cx18_av_std_setup(struct cx18 *cx) pll_int, pll_frac, pll_post); if (pll_post) { - int fin, fsc; - int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac); + int fin, fsc, pll; - pll >>= 25; + pll = (28636364L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; pll /= pll_post; CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", pll / 1000000, pll % 1000000); @@ -324,6 +345,7 @@ static void input_change(struct cx18 *cx) { struct cx18_av_state *state = &cx->av_state; v4l2_std_id std = state->std; + u8 v; /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); @@ -333,31 +355,34 @@ static void input_change(struct cx18 *cx) if (std & V4L2_STD_525_60) { if (std == V4L2_STD_NTSC_M_JP) { /* Japan uses EIAJ audio standard */ - cx18_av_write(cx, 0x808, 0xf7); - cx18_av_write(cx, 0x80b, 0x02); + cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f); } else if (std == V4L2_STD_NTSC_M_KR) { /* South Korea uses A2 audio standard */ - cx18_av_write(cx, 0x808, 0xf8); - cx18_av_write(cx, 0x80b, 0x03); + cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); } else { /* Others use the BTSC audio standard */ - cx18_av_write(cx, 0x808, 0xf6); - cx18_av_write(cx, 0x80b, 0x01); + cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f); } } else if (std & V4L2_STD_PAL) { /* Follow tuner change procedure for PAL */ - cx18_av_write(cx, 0x808, 0xff); - cx18_av_write(cx, 0x80b, 0x03); + cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); } else if (std & V4L2_STD_SECAM) { /* Select autodetect for SECAM */ - cx18_av_write(cx, 0x808, 0xff); - cx18_av_write(cx, 0x80b, 0x03); + cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); + cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); } - if (cx18_av_read(cx, 0x803) & 0x10) { + v = cx18_av_read(cx, 0x803); + if (v & 0x10) { /* restart audio decoder microcontroller */ - cx18_av_and_or(cx, 0x803, ~0x10, 0x00); - cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + v &= ~0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); + v |= 0x10; + cx18_av_write_expect(cx, 0x803, v, v, 0x1f); } } @@ -368,6 +393,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && vid_input <= CX18_AV_COMPOSITE8); u8 reg; + u8 v; CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n", vid_input, aud_input); @@ -413,16 +439,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, return -EINVAL; } - cx18_av_write(cx, 0x103, reg); + cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7); /* Set INPUT_MODE to Composite (0) or S-Video (1) */ cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + v = cx18_av_read(cx, 0x102); + if (reg & 0x80) + v &= ~0x2; + else + v |= 0x2; /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) - cx18_av_and_or(cx, 0x102, ~0x4, 4); + v |= 0x4; else - cx18_av_and_or(cx, 0x102, ~0x4, 0); + v &= ~0x4; + cx18_av_write_expect(cx, 0x102, v, v, 0x17); + /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/ state->vid_input = vid_input; @@ -799,40 +832,47 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) } case VIDIOC_S_TUNER: + { + u8 v; + if (state->radio) break; + v = cx18_av_read(cx, 0x809); + v &= ~0xf; + switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: /* mono -> mono stereo -> mono bilingual -> lang1 */ - cx18_av_and_or(cx, 0x809, ~0xf, 0x00); break; case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1: /* mono -> mono stereo -> stereo bilingual -> lang1 */ - cx18_av_and_or(cx, 0x809, ~0xf, 0x04); + v |= 0x4; break; case V4L2_TUNER_MODE_LANG1_LANG2: /* mono -> mono stereo -> stereo bilingual -> lang1/lang2 */ - cx18_av_and_or(cx, 0x809, ~0xf, 0x07); + v |= 0x7; break; case V4L2_TUNER_MODE_LANG2: /* mono -> mono stereo -> stereo bilingual -> lang2 */ - cx18_av_and_or(cx, 0x809, ~0xf, 0x01); + v |= 0x1; break; default: return -EINVAL; } + cx18_av_write_expect(cx, 0x809, v, v, 0xff); state->audmode = vt->audmode; break; + } case VIDIOC_G_FMT: return get_v4lfmt(cx, (struct v4l2_format *)arg); diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h index b67d8df20..a07988c6f 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.h +++ b/linux/drivers/media/video/cx18/cx18-av-core.h @@ -302,6 +302,9 @@ struct cx18_av_state { int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); +int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask); +int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, + u32 mask); u8 cx18_av_read(struct cx18 *cx, u16 addr); u32 cx18_av_read4(struct cx18 *cx, u16 addr); u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr); diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index 522a035b2..924691dca 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -43,11 +43,13 @@ int cx18_av_loadfw(struct cx18 *cx) /* The firmware load often has byte errors, so allow for several retries, both at byte level and at the firmware load level. */ while (retries1 < 5) { - cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); - cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); + cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000, + 0x00008430, 0xffffffff); /* cx25843 */ + cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff); - /* Reset the Mako core (Register is undocumented.) */ - cx18_av_write4(cx, 0x8100, 0x00010000); + /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */ + cx18_av_write4_expect(cx, 0x8100, 0x00010000, + 0x00008430, 0xffffffff); /* cx25843 */ /* Put the 8051 in reset and enable firmware upload */ cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); @@ -61,7 +63,7 @@ int cx18_av_loadfw(struct cx18 *cx) int retries2; int unrec_err = 0; - for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES; + for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES; retries2++) { cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control); @@ -80,7 +82,7 @@ int cx18_av_loadfw(struct cx18 *cx) } cx18_log_write_retries(cx, retries2, cx->reg_mem + 0xc40000 + CXADEC_DL_CTL); - if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES) + if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES) break; } if (i == size) @@ -93,7 +95,8 @@ int cx18_av_loadfw(struct cx18 *cx) return -EIO; } - cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); + cx18_av_write4_expect(cx, CXADEC_DL_CTL, + 0x13000000 | fw->size, 0x13000000, 0x13000000); /* Output to the 416 */ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); @@ -118,7 +121,8 @@ int cx18_av_loadfw(struct cx18 *cx) passthrough */ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); - cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6); + cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6, + 0x3F00FFFF); /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ @@ -136,7 +140,7 @@ int cx18_av_loadfw(struct cx18 *cx) v |= 0xFF; /* Auto by default */ v |= 0x400; /* Stereo by default */ v |= 0x14000000; - cx18_av_write4(cx, CXADEC_STD_DET_CTL, v); + cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF); release_firmware(fw); diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 085121c2b..54f0fde42 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -187,7 +187,7 @@ MODULE_VERSION(CX18_VERSION); /* Generic utility functions */ int cx18_msleep_timeout(unsigned int msecs, int intr) { - int timeout = msecs_to_jiffies(msecs); + long int timeout = msecs_to_jiffies(msecs); int sig; do { @@ -446,9 +446,16 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->i2c_bus_lock[0]); mutex_init(&cx->i2c_bus_lock[1]); mutex_init(&cx->gpio_lock); + mutex_init(&cx->epu2apu_mb_lock); + mutex_init(&cx->epu2cpu_mb_lock); spin_lock_init(&cx->lock); - spin_lock_init(&cx->dma_reg_lock); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) + INIT_WORK(&cx->work, cx18_work_handler); +#else + INIT_WORK(&cx->work, cx18_work_handler, cx); +#endif /* start counting open_id at 1 */ cx->open_id = 1; @@ -465,8 +472,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); - init_waitqueue_head(&cx->mb_epu_waitq); - init_waitqueue_head(&cx->mb_hpu_waitq); init_waitqueue_head(&cx->dma_waitq); /* VBI */ @@ -581,10 +586,10 @@ static void cx18_load_and_init_modules(struct cx18 *cx) #ifdef MODULE /* load modules */ -#ifndef CONFIG_MEDIA_TUNER +#ifdef CONFIG_MEDIA_TUNER_MODULE hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); #endif -#ifndef CONFIG_VIDEO_CS5345 +#ifdef CONFIG_VIDEO_CS5345_MODULE hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); #endif #endif @@ -613,6 +618,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; + int i; int vbi_buf_size; u32 devtype; struct cx18 *cx; @@ -698,7 +704,8 @@ static int __devinit cx18_probe(struct pci_dev *dev, /* active i2c */ CX18_DEBUG_INFO("activating i2c...\n"); - if (init_cx18_i2c(cx)) { + retval = init_cx18_i2c(cx); + if (retval) { CX18_ERR("Could not initialize i2c\n"); goto free_map; } @@ -730,8 +737,6 @@ static int __devinit cx18_probe(struct pci_dev *dev, cx->std = V4L2_STD_NTSC_M; if (cx->options.tuner == -1) { - int i; - for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { if ((cx->std & cx->card->tuners[i].std) == 0) continue; @@ -836,8 +841,11 @@ err: CX18_ERR("Error %d on initialization\n", retval); cx18_log_statistics(cx); - kfree(cx18_cards[cx18_cards_active]); - cx18_cards[cx18_cards_active] = NULL; + i = cx->num; + spin_lock(&cx18_cards_lock); + kfree(cx18_cards[i]); + cx18_cards[i] = NULL; + spin_unlock(&cx18_cards_lock); return retval; } @@ -927,6 +935,8 @@ static void cx18_remove(struct pci_dev *pci_dev) cx18_halt_firmware(cx); + flush_scheduled_work(); + cx18_streams_cleanup(cx, 1); exit_cx18_i2c(cx); diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index fa8be0731..ce7680675 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -41,6 +41,7 @@ #include <linux/pagemap.h> #include <linux/workqueue.h> #include <linux/mutex.h> +#include <asm/byteorder.h> #include <linux/dvb/video.h> #include <linux/dvb/audio.h> @@ -198,12 +199,14 @@ struct cx18_options { #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ /* per-cx18, i_flags */ -#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ -#define CX18_F_I_EOS 4 /* End of encoder stream reached */ -#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ -#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ -#define CX18_F_I_INITED 21 /* set after first open */ -#define CX18_F_I_FAILED 22 /* set if first open failed */ +#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ +#define CX18_F_I_EOS 4 /* End of encoder stream */ +#define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define CX18_F_I_HAVE_WORK 15 /* there is work to be done */ +#define CX18_F_I_WORK_HANDLER_DVB 18 /* work to be done for DVB */ +#define CX18_F_I_INITED 21 /* set after first open */ +#define CX18_F_I_FAILED 22 /* set if first open failed */ /* These are the VBI types as they appear in the embedded VBI private packets. */ #define CX18_SLICED_TYPE_TELETEXT_B (1) @@ -349,11 +352,18 @@ struct cx18_i2c_algo_callback_data { int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ }; -#define CX18_MAX_MMIO_RETRIES 10 +#define CX18_MAX_MMIO_WR_RETRIES 10 +#define CX18_MAX_MMIO_RD_RETRIES 2 struct cx18_mmio_stats { - atomic_t retried_write[CX18_MAX_MMIO_RETRIES+1]; - atomic_t retried_read[CX18_MAX_MMIO_RETRIES+1]; + atomic_t retried_write[CX18_MAX_MMIO_WR_RETRIES+1]; + atomic_t retried_read[CX18_MAX_MMIO_RD_RETRIES+1]; +}; + +#define CX18_MAX_MB_ACK_DELAY 100 + +struct cx18_mbox_stats { + atomic_t mb_ack_delay[CX18_MAX_MB_ACK_DELAY+1]; }; /* Struct to hold info about cx18 cards */ @@ -374,7 +384,10 @@ struct cx18 { u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* Hardware description of the board */ unsigned mdl_offset; - struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct cx18_av_state av_state; @@ -401,8 +414,6 @@ struct cx18 { spinlock_t lock; /* lock access to this struct */ int search_pack_header; - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - int open_id; /* incremented each time an open occurs, used as unique ID. Starts at 1, so 0 can be used as uninitialized value in the stream->id. */ @@ -426,12 +437,12 @@ struct cx18 { wait_queue_head_t mb_apu_waitq; wait_queue_head_t mb_cpu_waitq; - wait_queue_head_t mb_epu_waitq; - wait_queue_head_t mb_hpu_waitq; wait_queue_head_t cap_w; /* when the current DMA is finished this queue is woken up */ wait_queue_head_t dma_waitq; + struct work_struct work; + /* i2c */ struct i2c_adapter i2c_adap[2]; struct i2c_algo_bit_data i2c_algo[2]; @@ -447,6 +458,7 @@ struct cx18 { /* Statistics */ struct cx18_mmio_stats mmio_stats; + struct cx18_mbox_stats mbox_stats; /* v4l2 and User settings */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index afc694e7b..4845f732e 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -23,6 +23,8 @@ #include "cx18-dvb.h" #include "cx18-io.h" #include "cx18-streams.h" +#include "cx18-queue.h" +#include "cx18-scb.h" #include "cx18-cards.h" #include "s5h1409.h" #include "mxl5005s.h" @@ -107,20 +109,23 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - if (stream) { - mutex_lock(&stream->dvb.feedlock); - if (stream->dvb.feeding++ == 0) { - CX18_DEBUG_INFO("Starting Transport DMA\n"); - ret = cx18_start_v4l2_encode_stream(stream); - if (ret < 0) { - CX18_DEBUG_INFO( - "Failed to start Transport DMA\n"); - stream->dvb.feeding--; - } - } else - ret = 0; - mutex_unlock(&stream->dvb.feedlock); - } + if (!stream) + return -EINVAL; + + mutex_lock(&stream->dvb.feedlock); + if (stream->dvb.feeding++ == 0) { + CX18_DEBUG_INFO("Starting Transport DMA\n"); + set_bit(CX18_F_S_STREAMING, &stream->s_flags); + ret = cx18_start_v4l2_encode_stream(stream); + if (ret < 0) { + CX18_DEBUG_INFO("Failed to start Transport DMA\n"); + stream->dvb.feeding--; + if (stream->dvb.feeding == 0) + clear_bit(CX18_F_S_STREAMING, &stream->s_flags); + } + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); return ret; } @@ -300,3 +305,26 @@ static int dvb_register(struct cx18_stream *stream) return ret; } + +void cx18_dvb_work_handler(struct cx18 *cx) +{ + struct cx18_buffer *buf; + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS]; + + while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) { + if (s->dvb.enabled) + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + + cx18_buf_sync_for_device(s, buf); + cx18_enqueue(s, buf, &s->q_free); + + if (s->handle == CX18_INVALID_TASK_HANDLE || + !test_bit(CX18_F_S_STREAMING, &s->s_flags)) + continue; + + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } +} diff --git a/linux/drivers/media/video/cx18/cx18-dvb.h b/linux/drivers/media/video/cx18/cx18-dvb.h index bf8d8f6f5..bbdcefc87 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.h +++ b/linux/drivers/media/video/cx18/cx18-dvb.h @@ -23,3 +23,4 @@ int cx18_dvb_register(struct cx18_stream *stream); void cx18_dvb_unregister(struct cx18_stream *stream); +void cx18_dvb_work_handler(struct cx18 *cx); diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c index 51534428c..d9c5f55ab 100644 --- a/linux/drivers/media/video/cx18/cx18-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-firmware.c @@ -134,7 +134,8 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) return size; } -static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, + u32 *entry_addr) { const struct firmware *fw = NULL; int i, j; @@ -152,6 +153,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) return -ENOMEM; } + *entry_addr = 0; src = (const u32 *)fw->data; vers = fw->data + sizeof(seghdr); sz = fw->size; @@ -168,10 +170,12 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) } CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, seghdr.addr + seghdr.size - 1); + if (*entry_addr == 0) + *entry_addr = seghdr.addr; if (offset + seghdr.size > sz) break; for (i = 0; i < seghdr.size; i += 4096) { - cx18_setup_page(cx, offset + i); + cx18_setup_page(cx, seghdr.addr + i); for (j = i; j < seghdr.size && j < i + 4096; j += 4) { /* no need for endianness conversion on the ppc */ cx18_raw_writel(cx, src[(offset + j) / 4], @@ -192,16 +196,16 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) fn, apu_version, fw->size); size = fw->size; release_firmware(fw); - /* Clear bit0 for APU to start from 0 */ - cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); return size; } void cx18_halt_firmware(struct cx18 *cx) { CX18_DEBUG_INFO("Preparing for firmware halt.\n"); - cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ - cx18_write_reg(cx, 0x00020002, CX18_ADEC_CONTROL); + cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, + 0x0000000F, 0x000F000F); + cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL, + 0x00000002, 0x00020002); } void cx18_init_power(struct cx18 *cx, int lowpwr) @@ -211,7 +215,8 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN); /* ADEC out of sleep */ - cx18_write_reg(cx, 0x00020000, CX18_ADEC_CONTROL); + cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL, + 0x00000000, 0x00020002); /* The fast clock is at 200/245 MHz */ cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); @@ -248,22 +253,34 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) /* VFC = disabled */ /* USB = disabled */ - cx18_write_reg(cx, lowpwr ? 0xFFFF0020 : 0x00060004, - CX18_CLOCK_SELECT1); - cx18_write_reg(cx, lowpwr ? 0xFFFF0004 : 0x00060006, - CX18_CLOCK_SELECT2); - - cx18_write_reg(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1); - cx18_write_reg(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2); + if (lowpwr) { + cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1, + 0x00000020, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2, + 0x00000004, 0xFFFFFFFF); + } else { + /* This doesn't explicitly set every clock select */ + cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1, + 0x00000004, 0x00060006); + cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2, + 0x00000006, 0x00060006); + } - cx18_write_reg(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1); - cx18_write_reg(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2); + cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1, + 0x00000002, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2, + 0x00000104, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1, + 0x00009026, 0xFFFFFFFF); + cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2, + 0x00003105, 0xFFFFFFFF); } void cx18_init_memory(struct cx18 *cx) { cx18_msleep_timeout(10, 0); - cx18_write_reg(cx, 0x10000, CX18_DDR_SOFT_RESET); + cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET, + 0x00000000, 0x00010001); cx18_msleep_timeout(10, 0); cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); @@ -282,13 +299,15 @@ void cx18_init_memory(struct cx18 *cx) cx18_msleep_timeout(10, 0); - cx18_write_reg(cx, 0x20000, CX18_DDR_SOFT_RESET); + cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET, + 0x00000000, 0x00020002); cx18_msleep_timeout(10, 0); /* use power-down mode when idle */ cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG); - cx18_write_reg(cx, 0x10001, CX18_REG_BUS_TIMEOUT_EN); + cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN, + 0x00000001, 0x00010001); cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7); cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR); @@ -310,7 +329,9 @@ int cx18_firmware_init(struct cx18 *cx) /* Allow chip to control CLKRUN */ cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); - cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + /* Stop the firmware */ + cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, + 0x0000000F, 0x000F000F); cx18_msleep_timeout(1, 0); @@ -319,13 +340,22 @@ int cx18_firmware_init(struct cx18 *cx) /* Only if the processor is not running */ if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) { + u32 fw_entry_addr = 0; int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", - cx->enc_mem, cx); + cx->enc_mem, cx, &fw_entry_addr); + + if (sz <= 0) + return sz; + + /* Clear bit0 for APU to start from 0 */ + cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); + + cx18_write_enc(cx, 0xE51FF004, 0); /* ldr pc, [pc, #-4] */ + cx18_write_enc(cx, fw_entry_addr, 4); - cx18_write_enc(cx, 0xE51FF004, 0); - cx18_write_enc(cx, 0xa00000, 4); /* todo: not hardcoded */ /* Start APU */ - cx18_write_reg(cx, 0x00010000, CX18_PROC_SOFT_RESET); + cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET, + 0x00000000, 0x00010001); cx18_msleep_timeout(500, 0); sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", @@ -335,7 +365,9 @@ int cx18_firmware_init(struct cx18 *cx) int retries = 0; /* start the CPU */ - cx18_write_reg(cx, 0x00080000, CX18_PROC_SOFT_RESET); + cx18_write_reg_expect(cx, + 0x00080000, CX18_PROC_SOFT_RESET, + 0x00000000, 0x00080008); while (retries++ < 50) { /* Loop for max 500mS */ if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 0) @@ -351,7 +383,18 @@ int cx18_firmware_init(struct cx18 *cx) if (sz <= 0) return -EIO; } + + /* + * The CPU firmware apparently sets up to receive an interrupt for it's + * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*). We get an interrupt + * when it sends us an ack, but by the time we process it, that flag in + * the SW2 status register has been cleared by the CPU firmware. + * We'll prevent that not so useful behavior by clearing the CPU's + * interrupt enables for Ack IRQ's we want to process. + */ + cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + /* initialize GPIO */ - cx18_write_reg(cx, 0x14001400, 0xC78110); + cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); return 0; } diff --git a/linux/drivers/media/video/cx18/cx18-gpio.c b/linux/drivers/media/video/cx18/cx18-gpio.c index 0e5604219..17b7a32fc 100644 --- a/linux/drivers/media/video/cx18/cx18-gpio.c +++ b/linux/drivers/media/video/cx18/cx18-gpio.c @@ -47,15 +47,21 @@ static void gpio_write(struct cx18 *cx) { - u32 dir = cx->gpio_dir; - u32 val = cx->gpio_val; - - cx18_write_reg(cx, (dir & 0xffff) << 16, CX18_REG_GPIO_DIR1); - cx18_write_reg(cx, ((dir & 0xffff) << 16) | (val & 0xffff), - CX18_REG_GPIO_OUT1); - cx18_write_reg(cx, dir & 0xffff0000, CX18_REG_GPIO_DIR2); - cx18_write_reg_sync(cx, (dir & 0xffff0000) | ((val & 0xffff0000) >> 16), - CX18_REG_GPIO_OUT2); + u32 dir_lo = cx->gpio_dir & 0xffff; + u32 val_lo = cx->gpio_val & 0xffff; + u32 dir_hi = cx->gpio_dir >> 16; + u32 val_hi = cx->gpio_val >> 16; + + cx18_write_reg_expect(cx, dir_lo << 16, + CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo); + cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo, + CX18_REG_GPIO_OUT1, val_lo, dir_lo); + cx18_write_reg_expect(cx, dir_hi << 16, + CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi); + cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi, + CX18_REG_GPIO_OUT2, val_hi, dir_hi); + if (!cx18_retry_mmio) + (void) cx18_read_reg(cx, CX18_REG_GPIO_OUT2); /* sync */ } void cx18_reset_i2c_slaves_gpio(struct cx18 *cx) diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c index f28a1ff2e..1af9ea149 100644 --- a/linux/drivers/media/video/cx18/cx18-i2c.c +++ b/linux/drivers/media/video/cx18/cx18-i2c.c @@ -27,6 +27,7 @@ #include "cx18-gpio.h" #include "cx18-av-core.h" #include "cx18-i2c.h" +#include "cx18-irq.h" #define CX18_REG_I2C_1_WR 0xf15000 #define CX18_REG_I2C_1_RD 0xf15008 @@ -424,22 +425,31 @@ int init_cx18_i2c(struct cx18 *cx) if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) { /* Reset/Unreset I2C hardware block */ /* Clock select 220MHz */ - cx18_write_reg(cx, 0x10000000, 0xc71004); + cx18_write_reg_expect(cx, 0x10000000, 0xc71004, + 0x00000000, 0x10001000); /* Clock Enable */ - cx18_write_reg_sync(cx, 0x10001000, 0xc71024); + cx18_write_reg_expect(cx, 0x10001000, 0xc71024, + 0x00001000, 0x10001000); } /* courtesy of Steven Toth <stoth@hauppauge.com> */ - cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c); + cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); + if (!cx18_retry_mmio) + (void) cx18_read_reg(cx, 0xc7001c); /* sync */ mdelay(10); - cx18_write_reg_sync(cx, 0x00c000c0, 0xc7001c); + cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0); + if (!cx18_retry_mmio) + (void) cx18_read_reg(cx, 0xc7001c); /* sync */ mdelay(10); - cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c); + cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); + if (!cx18_retry_mmio) + (void) cx18_read_reg(cx, 0xc7001c); /* sync */ mdelay(10); /* Set to edge-triggered intrs. */ - cx18_write_reg_sync(cx, 0x00c00000, 0xc730c8); + cx18_write_reg(cx, 0x00c00000, 0xc730c8); /* Clear any stale intrs */ - cx18_write_reg_sync(cx, 0x00c00000, 0xc730c4); + cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS, + ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT); /* Hw I2C1 Clock Freq ~100kHz */ cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR); diff --git a/linux/drivers/media/video/cx18/cx18-io.c b/linux/drivers/media/video/cx18/cx18-io.c index 700ab9439..3c6485fce 100644 --- a/linux/drivers/media/video/cx18/cx18-io.c +++ b/linux/drivers/media/video/cx18/cx18-io.c @@ -31,19 +31,23 @@ void cx18_log_statistics(struct cx18 *cx) if (!(cx18_debug & CX18_DBGFLG_INFO)) return; - for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++) + for (i = 0; i <= CX18_MAX_MMIO_WR_RETRIES; i++) CX18_DEBUG_INFO("retried_write[%d] = %d\n", i, atomic_read(&cx->mmio_stats.retried_write[i])); - for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++) + for (i = 0; i <= CX18_MAX_MMIO_RD_RETRIES; i++) CX18_DEBUG_INFO("retried_read[%d] = %d\n", i, atomic_read(&cx->mmio_stats.retried_read[i])); + for (i = 0; i <= CX18_MAX_MB_ACK_DELAY; i++) + if (atomic_read(&cx->mbox_stats.mb_ack_delay[i])) + CX18_DEBUG_INFO("mb_ack_delay[%d] = %d\n", i, + atomic_read(&cx->mbox_stats.mb_ack_delay[i])); return; } void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) { int i; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { cx18_raw_writel_noretry(cx, val, addr); if (val == cx18_raw_readl_noretry(cx, addr)) break; @@ -55,7 +59,7 @@ u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr) { int i; u32 val; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_RD_RETRIES; i++) { val = cx18_raw_readl_noretry(cx, addr); if (val != 0xffffffff) /* PCI bus read error */ break; @@ -68,7 +72,7 @@ u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr) { int i; u16 val; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_RD_RETRIES; i++) { val = cx18_raw_readw_noretry(cx, addr); if (val != 0xffff) /* PCI bus read error */ break; @@ -80,7 +84,7 @@ u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr) void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) { int i; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { cx18_writel_noretry(cx, val, addr); if (val == cx18_readl_noretry(cx, addr)) break; @@ -88,10 +92,23 @@ void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) cx18_log_write_retries(cx, i, addr); } +void _cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, + u32 eval, u32 mask) +{ + int i; + eval &= mask; + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { + cx18_writel_noretry(cx, val, addr); + if (eval == (cx18_readl_noretry(cx, addr) & mask)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr) { int i; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { cx18_writew_noretry(cx, val, addr); if (val == cx18_readw_noretry(cx, addr)) break; @@ -102,7 +119,7 @@ void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr) void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr) { int i; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { cx18_writeb_noretry(cx, val, addr); if (val == cx18_readb_noretry(cx, addr)) break; @@ -114,7 +131,7 @@ u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr) { int i; u32 val; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_RD_RETRIES; i++) { val = cx18_readl_noretry(cx, addr); if (val != 0xffffffff) /* PCI bus read error */ break; @@ -127,7 +144,7 @@ u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr) { int i; u16 val; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_RD_RETRIES; i++) { val = cx18_readw_noretry(cx, addr); if (val != 0xffff) /* PCI bus read error */ break; @@ -140,7 +157,7 @@ u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr) { int i; u8 val; - for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + for (i = 0; i < CX18_MAX_MMIO_RD_RETRIES; i++) { val = cx18_readb_noretry(cx, addr); if (val != 0xff) /* PCI bus read error */ break; @@ -218,7 +235,7 @@ void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) { u32 r; - cx18_write_reg(cx, val, SW1_INT_STATUS); + cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val); r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI); cx18_write_reg(cx, r | val, SW1_INT_ENABLE_PCI); } @@ -233,7 +250,7 @@ void cx18_sw1_irq_disable(struct cx18 *cx, u32 val) void cx18_sw2_irq_enable(struct cx18 *cx, u32 val) { u32 r; - cx18_write_reg(cx, val, SW2_INT_STATUS); + cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val); r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI); cx18_write_reg(cx, r | val, SW2_INT_ENABLE_PCI); } @@ -245,6 +262,13 @@ void cx18_sw2_irq_disable(struct cx18 *cx, u32 val) cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_PCI); } +void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val) +{ + u32 r; + r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU); + cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU); +} + void cx18_setup_page(struct cx18 *cx, u32 addr) { u32 val; diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h index 197d4fbd9..4486b73fa 100644 --- a/linux/drivers/media/video/cx18/cx18-io.h +++ b/linux/drivers/media/video/cx18/cx18-io.h @@ -39,19 +39,19 @@ static inline void cx18_io_delay(struct cx18 *cx) /* Statistics gathering */ static inline -void cx18_log_write_retries(struct cx18 *cx, int i, const void *addr) +void cx18_log_write_retries(struct cx18 *cx, int i, const void __iomem *addr) { - if (i > CX18_MAX_MMIO_RETRIES) - i = CX18_MAX_MMIO_RETRIES; + if (i > CX18_MAX_MMIO_WR_RETRIES) + i = CX18_MAX_MMIO_WR_RETRIES; atomic_inc(&cx->mmio_stats.retried_write[i]); return; } static inline -void cx18_log_read_retries(struct cx18 *cx, int i, const void *addr) +void cx18_log_read_retries(struct cx18 *cx, int i, const void __iomem *addr) { - if (i > CX18_MAX_MMIO_RETRIES) - i = CX18_MAX_MMIO_RETRIES; + if (i > CX18_MAX_MMIO_RD_RETRIES) + i = CX18_MAX_MMIO_RD_RETRIES; atomic_inc(&cx->mmio_stats.retried_read[i]); return; } @@ -133,6 +133,8 @@ static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) cx18_writel_noretry(cx, val, addr); } +void _cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, + u32 eval, u32 mask); static inline void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) @@ -271,6 +273,21 @@ static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) cx18_write_reg_noretry(cx, val, reg); } +static inline void _cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, + u32 eval, u32 mask) +{ + _cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask); +} + +static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, + u32 eval, u32 mask) +{ + if (cx18_retry_mmio) + _cx18_write_reg_expect(cx, val, reg, eval, mask); + else + cx18_write_reg_noretry(cx, val, reg); +} + static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg) { @@ -373,6 +390,7 @@ void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); +void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val); void cx18_setup_page(struct cx18 *cx, u32 addr); #endif /* CX18_IO_H */ diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c index 85a56974b..3e23fc350 100644 --- a/linux/drivers/media/video/cx18/cx18-irq.c +++ b/linux/drivers/media/video/cx18/cx18-irq.c @@ -29,10 +29,22 @@ #include "cx18-mailbox.h" #include "cx18-vbi.h" #include "cx18-scb.h" +#include "cx18-dvb.h" -#define DMA_MAGIC_COOKIE 0x000001fe +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +void cx18_work_handler(struct work_struct *work) +{ + struct cx18 *cx = container_of(work, struct cx18, work); +#else +void cx18_work_handler(void *arg) +{ + struct cx18 *cx = arg; +#endif + if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags)) + cx18_dvb_work_handler(cx); +} -static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) +static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) { u32 handle = mb->args[0]; struct cx18_stream *s = NULL; @@ -53,7 +65,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) " handle %d\n", handle); mb->error = CXERR_NOT_OPEN; mb->cmd = 0; - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); return; } @@ -67,17 +79,11 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) if (buf) { cx18_buf_sync_for_cpu(s, buf); if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { - /* process the buffer here */ - CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n", + CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", buf->bytesused); - dvb_dmx_swfilter(&s->dvb.demux, buf->buf, - buf->bytesused); - - cx18_buf_sync_for_device(s, buf); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); + set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags); + set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags); } else set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); } else { @@ -86,13 +92,13 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) } mb->error = 0; mb->cmd = 0; - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); wake_up(&cx->dma_waitq); if (s->id != -1) wake_up(&s->waitq); } -static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) +static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) { char str[256] = { 0 }; char *p; @@ -102,14 +108,14 @@ static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252); str[252] = 0; } - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); p = strchr(str, '.'); if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) CX18_INFO("FW version: %s\n", p - 1); } -static void hpu_cmd(struct cx18 *cx, u32 sw1) +static void epu_cmd(struct cx18 *cx, u32 sw1) { struct cx18_mailbox mb; @@ -119,18 +125,30 @@ static void hpu_cmd(struct cx18 *cx, u32 sw1) switch (mb.cmd) { case CX18_EPU_DMA_DONE: - epu_dma_done(cx, &mb); + epu_dma_done(cx, &mb, CPU); break; case CX18_EPU_DEBUG: - epu_debug(cx, &mb); + epu_debug(cx, &mb, CPU); break; default: - CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd); + CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n", + mb.cmd); break; } } - if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU)) - CX18_WARN("Unexpected interrupt %08x\n", sw1); + + if (sw1 & IRQ_APU_TO_EPU) { + cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb)); + CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd); + } +} + +static void xpu_ack(struct cx18 *cx, u32 sw2) +{ + if (sw2 & IRQ_CPU_TO_EPU_ACK) + wake_up(&cx->mb_cpu_waitq); + if (sw2 & IRQ_APU_TO_EPU_ACK) + wake_up(&cx->mb_apu_waitq); } #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) @@ -144,43 +162,37 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) u32 sw2, sw2_mask; u32 hw2, hw2_mask; - spin_lock(&cx->dma_reg_lock); - + sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI); + sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask; + sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI); + sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask; hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI); hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask; - sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; - sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask; - sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; - sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask; - cx18_write_reg(cx, sw2&sw2_mask, SW2_INT_STATUS); - cx18_write_reg(cx, sw1&sw1_mask, SW1_INT_STATUS); - cx18_write_reg(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS); + if (sw1) + cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1); + if (sw2) + cx18_write_reg_expect(cx, sw2, SW2_INT_STATUS, ~sw2, sw2); + if (hw2) + cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); if (sw1 || sw2 || hw2) - CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + CX18_DEBUG_HI_IRQ("received interrupts " + "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); /* To do: interrupt-based I2C handling - if (hw2 & 0x00c00000) { + if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { } */ - if (sw2) { - if (sw2 & (cx18_readl(cx, &cx->scb->cpu2hpu_irq_ack) | - cx18_readl(cx, &cx->scb->cpu2epu_irq_ack))) - wake_up(&cx->mb_cpu_waitq); - if (sw2 & (cx18_readl(cx, &cx->scb->apu2hpu_irq_ack) | - cx18_readl(cx, &cx->scb->apu2epu_irq_ack))) - wake_up(&cx->mb_apu_waitq); - if (sw2 & cx18_readl(cx, &cx->scb->epu2hpu_irq_ack)) - wake_up(&cx->mb_epu_waitq); - if (sw2 & cx18_readl(cx, &cx->scb->hpu2epu_irq_ack)) - wake_up(&cx->mb_hpu_waitq); - } + if (sw2) + xpu_ack(cx, sw2); if (sw1) - hpu_cmd(cx, sw1); - spin_unlock(&cx->dma_reg_lock); + epu_cmd(cx, sw1); + + if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags)) + schedule_work(&cx->work); - return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE; + return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/linux/drivers/media/video/cx18/cx18-irq.h b/linux/drivers/media/video/cx18/cx18-irq.h index cbcd2022f..6472e42c6 100644 --- a/linux/drivers/media/video/cx18/cx18-irq.h +++ b/linux/drivers/media/video/cx18/cx18-irq.h @@ -28,6 +28,7 @@ #define SW1_INT_ENABLE_PCI 0xc7311c #define SW2_INT_SET 0xc73140 #define SW2_INT_STATUS 0xc73144 +#define SW2_INT_ENABLE_CPU 0xc73158 #define SW2_INT_ENABLE_PCI 0xc7315c #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) @@ -36,6 +37,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id, struct pt_regs *regs); irqreturn_t cx18_irq_handler(int irq, void *dev_id); #endif -void cx18_irq_work_handler(struct work_struct *work); -void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock); -void cx18_unfinished_dma(unsigned long arg); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +void cx18_work_handler(struct work_struct *work); +#else +void cx18_work_handler(void *arg); +#endif diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index 9d18dd22d..35f7188d4 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -30,11 +30,6 @@ #define API_FAST (1 << 2) /* Short timeout */ #define API_SLOW (1 << 3) /* Additional 300ms timeout */ -#define APU 0 -#define CPU 1 -#define EPU 2 -#define HPU 3 - struct cx18_api_info { u32 cmd; u8 flags; /* Flags, see above */ @@ -83,7 +78,7 @@ static const struct cx18_api_info api_info[] = { API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST), - API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, 0), + API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), API_ENTRY(0, 0, 0), }; @@ -97,70 +92,12 @@ static const struct cx18_api_info *find_api_info(u32 cmd) return NULL; } -static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu, - u32 *state, u32 *irq, u32 *req) +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu) { - struct cx18_mailbox __iomem *mb = NULL; - int wait_count = 0; - u32 ack; - - switch (rpu) { - case APU: - mb = &cx->scb->epu2apu_mb; - *state = cx18_readl(cx, &cx->scb->apu_state); - *irq = cx18_readl(cx, &cx->scb->epu2apu_irq); - break; - - case CPU: - mb = &cx->scb->epu2cpu_mb; - *state = cx18_readl(cx, &cx->scb->cpu_state); - *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq); - break; - - case HPU: - mb = &cx->scb->epu2hpu_mb; - *state = cx18_readl(cx, &cx->scb->hpu_state); - *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq); - break; - } - - if (mb == NULL) - return mb; - - do { - *req = cx18_readl(cx, &mb->request); - ack = cx18_readl(cx, &mb->ack); - wait_count++; - } while (*req != ack && wait_count < 600); - - if (*req == ack) { - (*req)++; - if (*req == 0 || *req == 0xffffffff) - *req = 1; - return mb; - } - return NULL; -} - -long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) -{ - const struct cx18_api_info *info = find_api_info(mb->cmd); struct cx18_mailbox __iomem *ack_mb; u32 ack_irq; - u8 rpu = CPU; - - if (info == NULL && mb->cmd) { - CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); - return -EINVAL; - } - if (info) - rpu = info->rpu; switch (rpu) { - case HPU: - ack_irq = IRQ_EPU_TO_HPU_ACK; - ack_mb = &cx->scb->hpu2epu_mb; - break; case APU: ack_irq = IRQ_EPU_TO_APU_ACK; ack_mb = &cx->scb->apu2epu_mb; @@ -170,26 +107,33 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) ack_mb = &cx->scb->cpu2epu_mb; break; default: - CX18_WARN("Unknown RPU for command %x\n", mb->cmd); + CX18_WARN("Unhandled RPU (%d) for command %x ack\n", + rpu, mb->cmd); return -EINVAL; } cx18_setup_page(cx, SCB_OFFSET); cx18_write_sync(cx, mb->request, &ack_mb->ack); - cx18_write_reg(cx, ack_irq, SW2_INT_SET); + cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); return 0; } +static void cx18_api_log_ack_delay(struct cx18 *cx, int msecs) +{ + if (msecs > CX18_MAX_MB_ACK_DELAY) + msecs = CX18_MAX_MB_ACK_DELAY; + atomic_inc(&cx->mbox_stats.mb_ack_delay[msecs]); +} static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) { const struct cx18_api_info *info = find_api_info(cmd); - u32 state = 0, irq = 0, req, oldreq, err; + u32 state, irq, req, ack, err; struct cx18_mailbox __iomem *mb; + u32 __iomem *xpu_state; wait_queue_head_t *waitq; - int timeout = 100; - int cnt = 0; - int sig = 0; + struct mutex *mb_lock; + long int timeout, ret; int i; if (info == NULL) { @@ -201,50 +145,116 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) CX18_DEBUG_HI_API("%s\n", info->name); else CX18_DEBUG_API("%s\n", info->name); - cx18_setup_page(cx, SCB_OFFSET); - mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); - if (mb == NULL) { - CX18_ERR("mb %s busy\n", info->name); - return -EBUSY; + switch (info->rpu) { + case APU: + waitq = &cx->mb_apu_waitq; + mb_lock = &cx->epu2apu_mb_lock; + irq = IRQ_EPU_TO_APU; + mb = &cx->scb->epu2apu_mb; + xpu_state = &cx->scb->apu_state; + break; + case CPU: + waitq = &cx->mb_cpu_waitq; + mb_lock = &cx->epu2cpu_mb_lock; + irq = IRQ_EPU_TO_CPU; + mb = &cx->scb->epu2cpu_mb; + xpu_state = &cx->scb->cpu_state; + break; + default: + CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); + return -EINVAL; } - oldreq = req - 1; + mutex_lock(mb_lock); + cx18_setup_page(cx, SCB_OFFSET); + + /* + * Wait for an in-use mailbox to complete + * + * If the XPU is responding with Ack's, the mailbox shouldn't be in + * a busy state, since we serialize access to it on our end. + * + * If the wait for ack after sending a previous command was interrupted + * by a signal, we may get here and find a busy mailbox. After waiting, + * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. + */ + state = cx18_readl(cx, xpu_state); + req = cx18_readl(cx, &mb->request); + timeout = msecs_to_jiffies(20); /* 1 field at 50 Hz vertical refresh */ + ret = wait_event_timeout(*waitq, + (ack = cx18_readl(cx, &mb->ack)) == req, + timeout); + if (req != ack) { + /* waited long enough, make the mbox "not busy" from our end */ + cx18_writel(cx, req, &mb->ack); + CX18_ERR("mbox was found stuck busy when setting up for %s; " + "clearing busy and trying to proceed\n", info->name); + } else if (ret != timeout) + CX18_DEBUG_API("waited %u usecs for busy mbox to be acked\n", + jiffies_to_usecs(timeout-ret)); + + /* Build the outgoing mailbox */ + req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; + cx18_writel(cx, cmd, &mb->cmd); for (i = 0; i < args; i++) cx18_writel(cx, data[i], &mb->args[i]); cx18_writel(cx, 0, &mb->error); cx18_writel(cx, req, &mb->request); - - switch (info->rpu) { - case APU: waitq = &cx->mb_apu_waitq; break; - case CPU: waitq = &cx->mb_cpu_waitq; break; - case EPU: waitq = &cx->mb_epu_waitq; break; - case HPU: waitq = &cx->mb_hpu_waitq; break; - default: return -EINVAL; - } - if (info->flags & API_FAST) - timeout /= 2; - cx18_write_reg(cx, irq, SW1_INT_SET); - - while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) - && cnt < 660) { - if (cnt > 200 && !in_atomic()) - sig = cx18_msleep_timeout(10, 1); - cnt++; - } - if (sig) - return -EINTR; - if (cnt == 660) { - cx18_writel(cx, oldreq, &mb->request); - CX18_ERR("mb %s failed\n", info->name); + cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ + + /* + * Notify the XPU and wait for it to send an Ack back + * 21 ms = ~ 0.5 frames at a frame rate of 24 fps + * 42 ms = ~ 1 frame at a frame rate of 24 fps + */ + timeout = msecs_to_jiffies((info->flags & API_FAST) ? 21 : 42); + + CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", + irq, info->name); + cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); + + ret = wait_event_timeout( + *waitq, + cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), + timeout); + if (ret == 0) { + /* Timed out */ + mutex_unlock(mb_lock); + i = jiffies_to_msecs(timeout); + cx18_api_log_ack_delay(cx, i); + CX18_WARN("sending %s timed out waiting %d msecs for RPU " + "acknowledgement\n", info->name, i); return -EINVAL; + } else if (ret < 0) { + /* Interrupted */ + mutex_unlock(mb_lock); + CX18_WARN("sending %s was interrupted waiting for RPU" + "acknowledgement\n", info->name); + return -EINTR; } + + i = jiffies_to_msecs(timeout-ret); + cx18_api_log_ack_delay(cx, i); + if (ret != timeout) + CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", + i, info->name); + + /* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++) data[i] = cx18_readl(cx, &mb->args[i]); err = cx18_readl(cx, &mb->error); - if (!in_atomic() && (info->flags & API_SLOW)) + mutex_unlock(mb_lock); + + /* + * Wait for XPU to perform extra actions for the caller in some cases. + * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers + * back in a burst shortly thereafter + */ + if (info->flags & API_SLOW) cx18_msleep_timeout(300, 0); + if (err) CX18_DEBUG_API("mailbox error %08x for command %s\n", err, info->name); @@ -253,12 +263,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) { - int res = cx18_api_call(cx, cmd, args, data); - - /* Allow a single retry, probably already too late though. - If there is no free mailbox then that is usually an indication - of a more serious problem. */ - return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res; + return cx18_api_call(cx, cmd, args, data); } static int cx18_set_filter_param(struct cx18_stream *s) diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.h b/linux/drivers/media/video/cx18/cx18-mailbox.h index d99564153..54758f32d 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.h +++ b/linux/drivers/media/video/cx18/cx18-mailbox.h @@ -30,6 +30,11 @@ #define MB_RESERVED_HANDLE_0 0 #define MB_RESERVED_HANDLE_1 0xFFFFFFFF +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + struct cx18; /* The cx18_mailbox struct is the mailbox structure which is used for passing @@ -68,6 +73,6 @@ int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); int cx18_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); -long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb); +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu); #endif diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index a33ba04a2..174682c25 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -88,15 +88,13 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, if (buf->id != id) continue; + buf->bytesused = bytesused; - /* the transport buffers are handled differently, - they are not moved to the full queue */ - if (s->type != CX18_ENC_STREAM_TYPE_TS) { - atomic_dec(&s->q_free.buffers); - atomic_inc(&s->q_full.buffers); - s->q_full.bytesused += buf->bytesused; - list_move_tail(&buf->list, &s->q_full.list); - } + atomic_dec(&s->q_free.buffers); + atomic_inc(&s->q_full.buffers); + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + spin_unlock(&s->qlock); return buf; } diff --git a/linux/drivers/media/video/cx18/cx18-scb.h b/linux/drivers/media/video/cx18/cx18-scb.h index 86b4cb15d..594713bbe 100644 --- a/linux/drivers/media/video/cx18/cx18-scb.h +++ b/linux/drivers/media/video/cx18/cx18-scb.h @@ -128,22 +128,22 @@ struct cx18_scb { u32 apu2cpu_irq; /* Value to write to register SW2 register set (0xC7003140) after the command is cleared */ - u32 apu2cpu_irq_ack; + u32 cpu2apu_irq_ack; u32 reserved2[13]; u32 hpu2cpu_mb_offset; u32 hpu2cpu_irq; - u32 hpu2cpu_irq_ack; + u32 cpu2hpu_irq_ack; u32 reserved3[13]; u32 ppu2cpu_mb_offset; u32 ppu2cpu_irq; - u32 ppu2cpu_irq_ack; + u32 cpu2ppu_irq_ack; u32 reserved4[13]; u32 epu2cpu_mb_offset; u32 epu2cpu_irq; - u32 epu2cpu_irq_ack; + u32 cpu2epu_irq_ack; u32 reserved5[13]; u32 reserved6[8]; @@ -153,22 +153,22 @@ struct cx18_scb { u32 reserved11[7]; u32 cpu2apu_mb_offset; u32 cpu2apu_irq; - u32 cpu2apu_irq_ack; + u32 apu2cpu_irq_ack; u32 reserved12[13]; u32 hpu2apu_mb_offset; u32 hpu2apu_irq; - u32 hpu2apu_irq_ack; + u32 apu2hpu_irq_ack; u32 reserved13[13]; u32 ppu2apu_mb_offset; u32 ppu2apu_irq; - u32 ppu2apu_irq_ack; + u32 apu2ppu_irq_ack; u32 reserved14[13]; u32 epu2apu_mb_offset; u32 epu2apu_irq; - u32 epu2apu_irq_ack; + u32 apu2epu_irq_ack; u32 reserved15[13]; u32 reserved16[8]; @@ -178,22 +178,22 @@ struct cx18_scb { u32 reserved21[7]; u32 cpu2hpu_mb_offset; u32 cpu2hpu_irq; - u32 cpu2hpu_irq_ack; + u32 hpu2cpu_irq_ack; u32 reserved22[13]; u32 apu2hpu_mb_offset; u32 apu2hpu_irq; - u32 apu2hpu_irq_ack; + u32 hpu2apu_irq_ack; u32 reserved23[13]; u32 ppu2hpu_mb_offset; u32 ppu2hpu_irq; - u32 ppu2hpu_irq_ack; + u32 hpu2ppu_irq_ack; u32 reserved24[13]; u32 epu2hpu_mb_offset; u32 epu2hpu_irq; - u32 epu2hpu_irq_ack; + u32 hpu2epu_irq_ack; u32 reserved25[13]; u32 reserved26[8]; @@ -203,22 +203,22 @@ struct cx18_scb { u32 reserved31[7]; u32 cpu2ppu_mb_offset; u32 cpu2ppu_irq; - u32 cpu2ppu_irq_ack; + u32 ppu2cpu_irq_ack; u32 reserved32[13]; u32 apu2ppu_mb_offset; u32 apu2ppu_irq; - u32 apu2ppu_irq_ack; + u32 ppu2apu_irq_ack; u32 reserved33[13]; u32 hpu2ppu_mb_offset; u32 hpu2ppu_irq; - u32 hpu2ppu_irq_ack; + u32 ppu2hpu_irq_ack; u32 reserved34[13]; u32 epu2ppu_mb_offset; u32 epu2ppu_irq; - u32 epu2ppu_irq_ack; + u32 ppu2epu_irq_ack; u32 reserved35[13]; u32 reserved36[8]; @@ -228,22 +228,22 @@ struct cx18_scb { u32 reserved41[7]; u32 cpu2epu_mb_offset; u32 cpu2epu_irq; - u32 cpu2epu_irq_ack; + u32 epu2cpu_irq_ack; u32 reserved42[13]; u32 apu2epu_mb_offset; u32 apu2epu_irq; - u32 apu2epu_irq_ack; + u32 epu2apu_irq_ack; u32 reserved43[13]; u32 hpu2epu_mb_offset; u32 hpu2epu_irq; - u32 hpu2epu_irq_ack; + u32 epu2hpu_irq_ack; u32 reserved44[13]; u32 ppu2epu_mb_offset; u32 ppu2epu_irq; - u32 ppu2epu_irq_ack; + u32 epu2ppu_irq_ack; u32 reserved45[13]; u32 reserved46[8]; diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index f85f4a2cd..d29a0b61b 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -200,16 +200,18 @@ static int cx18_prep_dev(struct cx18 *cx, int type) /* Initialize v4l2 variables and register v4l2 devices */ int cx18_streams_setup(struct cx18 *cx) { - int type; + int type, ret; /* Setup V4L2 Devices */ for (type = 0; type < CX18_MAX_STREAMS; type++) { /* Prepare device */ - if (cx18_prep_dev(cx, type)) + ret = cx18_prep_dev(cx, type); + if (ret < 0) break; /* Allocate Stream */ - if (cx18_stream_alloc(&cx->streams[type])) + ret = cx18_stream_alloc(&cx->streams[type]); + if (ret < 0) break; } if (type == CX18_MAX_STREAMS) @@ -217,14 +219,14 @@ int cx18_streams_setup(struct cx18 *cx) /* One or more streams could not be initialized. Clean 'em all up. */ cx18_streams_cleanup(cx, 0); - return -ENOMEM; + return ret; } static int cx18_reg_dev(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; int vfl_type = cx18_stream_info[type].vfl_type; - int num; + int num, ret; /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? * We need a VFL_TYPE_TS defined. @@ -233,9 +235,10 @@ static int cx18_reg_dev(struct cx18 *cx, int type) /* just return if no DVB is supported */ if ((cx->card->hw_all & CX18_HW_DVB) == 0) return 0; - if (cx18_dvb_register(s) < 0) { + ret = cx18_dvb_register(s); + if (ret < 0) { CX18_ERR("DVB failed to register\n"); - return -EINVAL; + return ret; } } @@ -252,12 +255,13 @@ static int cx18_reg_dev(struct cx18 *cx, int type) } /* Register device. First try the desired minor, then any free one. */ - if (video_register_device(s->v4l2dev, vfl_type, num)) { + ret = video_register_device(s->v4l2dev, vfl_type, num); + if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n", s->name, num); video_device_release(s->v4l2dev); s->v4l2dev = NULL; - return -ENOMEM; + return ret; } num = s->v4l2dev->num; @@ -290,18 +294,22 @@ static int cx18_reg_dev(struct cx18 *cx, int type) int cx18_streams_register(struct cx18 *cx) { int type; - int err = 0; + int err; + int ret = 0; /* Register V4L2 devices */ - for (type = 0; type < CX18_MAX_STREAMS; type++) - err |= cx18_reg_dev(cx, type); + for (type = 0; type < CX18_MAX_STREAMS; type++) { + err = cx18_reg_dev(cx, type); + if (err && ret == 0) + ret = err; + } - if (err == 0) + if (ret == 0) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ cx18_streams_cleanup(cx, 1); - return -ENOMEM; + return ret; } /* Unregister v4l2 devices */ @@ -579,9 +587,6 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) #endif } - /* Tell the CX23418 it can't use our buffers anymore */ - cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); - if (s->type != CX18_ENC_STREAM_TYPE_TS) atomic_dec(&cx->ana_capturing); atomic_dec(&cx->tot_capturing); @@ -589,6 +594,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* Tell the CX23418 it can't use our buffers anymore */ + cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index 9f6be2d45..366cc1472 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -25,7 +25,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 #define CX18_DRIVER_VERSION_MINOR 0 -#define CX18_DRIVER_VERSION_PATCHLEVEL 1 +#define CX18_DRIVER_VERSION_PATCHLEVEL 2 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index ae914cdc5..d98e64545 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -1823,7 +1823,7 @@ int cx23885_417_register(struct cx23885_dev *dev) cx23885_mc417_init(dev); printk(KERN_INFO "%s: registered device video%d [mpeg]\n", - dev->name, dev->v4l_device->minor & 0x1f); + dev->name, dev->v4l_device->num); return 0; } diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index 2b497b28b..dc3f79638 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -40,16 +40,16 @@ struct cx23885_board cx23885_boards[] = { .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX23885_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX23885_VMUX_COMPOSITE3, .vmux = 2, - },{ + }, { .type = CX23885_VMUX_COMPOSITE4, .vmux = 3, - }}, + } }, }, [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = { .name = "Hauppauge WinTV-HVR1800lp", @@ -58,19 +58,19 @@ struct cx23885_board cx23885_boards[] = { .type = CX23885_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, - },{ + }, { .type = CX23885_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, - },{ + }, { .type = CX23885_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX23885_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xff02, - }}, + } }, }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", @@ -85,20 +85,20 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN5_CH2 | CX25840_VIN2_CH1, .gpio0 = 0, - },{ + }, { .type = CX23885_VMUX_COMPOSITE1, .vmux = CX25840_VIN7_CH3 | CX25840_VIN4_CH2 | CX25840_VIN6_CH1, .gpio0 = 0, - },{ + }, { .type = CX23885_VMUX_SVIDEO, .vmux = CX25840_VIN7_CH3 | CX25840_VIN4_CH2 | CX25840_VIN8_CH1 | CX25840_SVIDEO_ON, .gpio0 = 0, - }}, + } }, }, [CX23885_BOARD_HAUPPAUGE_HVR1250] = { .name = "Hauppauge WinTV-HVR1250", @@ -107,19 +107,19 @@ struct cx23885_board cx23885_boards[] = { .type = CX23885_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, - },{ + }, { .type = CX23885_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, - },{ + }, { .type = CX23885_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX23885_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xff02, - }}, + } }, }, [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = { .name = "DViCO FusionHDTV5 Express", @@ -170,43 +170,43 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x3400, .card = CX23885_BOARD_UNKNOWN, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x7600, .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x7800, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x7801, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x7809, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x7911, .card = CX23885_BOARD_HAUPPAUGE_HVR1250, - },{ + }, { .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, .card = CX23885_BOARD_HAUPPAUGE_HVR1500, @@ -226,11 +226,11 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x8010, .card = CX23885_BOARD_HAUPPAUGE_HVR1400, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd618, .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb78, .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, @@ -248,23 +248,25 @@ void cx23885_card_list(struct cx23885_dev *dev) if (0 == dev->pci->subsystem_vendor && 0 == dev->pci->subsystem_device) { - printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n" - "%s: be autodetected. Please pass card=<n> insmod option to\n" - "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Best regards,\n" + printk(KERN_INFO + "%s: Board has no valid PCIe Subsystem ID and can't\n" + "%s: be autodetected. Pass card=<n> insmod option\n" + "%s: to workaround that. Redirect complaints to the\n" + "%s: vendor of the TV card. Best regards,\n" "%s: -- tux\n", dev->name, dev->name, dev->name, dev->name, dev->name); } else { - printk("%s: Your board isn't known (yet) to the driver. You can\n" - "%s: try to pick one of the existing card configs via\n" + printk(KERN_INFO + "%s: Your board isn't known (yet) to the driver.\n" + "%s: Try to pick one of the existing card configs via\n" "%s: card=<n> insmod option. Updating to the latest\n" "%s: version might help as well.\n", dev->name, dev->name, dev->name, dev->name); } - printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n", + printk(KERN_INFO "%s: Here is a list of valid choices for the card=<n> insmod option:\n", dev->name); for (i = 0; i < cx23885_bcount; i++) - printk("%s: card=%d -> %s\n", + printk(KERN_INFO "%s: card=%d -> %s\n", dev->name, i, cx23885_boards[i].name); } @@ -272,11 +274,11 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) { struct tveeprom tv; - tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data); + tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, + eeprom_data); /* Make sure we support the board model */ - switch (tv.model) - { + switch (tv.model) { case 71009: /* WinTV-HVR1200 (PCIe, Retail, full height) * DVB-T and basic analog */ @@ -304,21 +306,51 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 71999: /* WinTV-HVR1200 (PCIe, OEM, full height) * DVB-T and basic analog */ - case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ - 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 */ - 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 79561: /* WinTV-HVR1250 (PCIe, OEM, No 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 */ + case 76601: + /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual + channel ATSC and MPEG2 HW Encoder */ + 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 */ + 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 79561: + /* WinTV-HVR1250 (PCIe, OEM, No 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 */ case 80019: /* WinTV-HVR1400 (Express Card, Retail, IR, * DVB-T and Basic analog */ @@ -330,7 +362,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) * DVB-T and MPEG2 HW Encoder */ break; default: - printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); + printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n", + dev->name, tv.model); break; } @@ -353,7 +386,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) return -EINVAL; } - switch(dev->board) { + switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: @@ -384,7 +417,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) void cx23885_gpio_setup(struct cx23885_dev *dev) { - switch(dev->board) { + switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: /* GPIO-0 cx24227 demodulator reset */ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ @@ -618,10 +651,3 @@ void cx23885_card_setup(struct cx23885_dev *dev) } /* ------------------------------------------------------------------ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c index 6fc69988a..4f68156d2 100644 --- a/linux/drivers/media/video/cx23885/cx23885-core.c +++ b/linux/drivers/media/video/cx23885/cx23885-core.c @@ -38,12 +38,12 @@ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages"); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card,"card type"); +MODULE_PARM_DESC(card, "card type"); #define dprintk(level, fmt, arg...)\ do { if (debug >= level)\ @@ -365,13 +365,12 @@ void cx23885_wakeup(struct cx23885_tsport *port, list_del(&buf->vb.queue); wake_up(&buf->vb.done); } - if (list_empty(&q->active)) { + if (list_empty(&q->active)) del_timer(&q->timeout); - } else { + else mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - } if (bc != 1) - printk("%s: %d buffers handled (should be 1)\n", + printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", __func__, bc); } @@ -382,8 +381,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, unsigned int i, lines; u32 cdt; - if (ch->cmds_start == 0) - { + if (ch->cmds_start == 0) { dprintk(1, "%s() Erasing channel [%s]\n", __func__, ch->name); cx_write(ch->ptr1_reg, 0); @@ -419,15 +417,15 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, /* write CMDS */ if (ch->jumponly) - cx_write(ch->cmds_start + 0, 8); + cx_write(ch->cmds_start + 0, 8); else - cx_write(ch->cmds_start + 0, risc); + cx_write(ch->cmds_start + 0, risc); cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ cx_write(ch->cmds_start + 8, cdt); cx_write(ch->cmds_start + 12, (lines*16) >> 3); cx_write(ch->cmds_start + 16, ch->ctrl_start); if (ch->jumponly) - cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) ); + cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); else cx_write(ch->cmds_start + 20, 64 >> 2); for (i = 24; i < 80; i += 4) @@ -437,9 +435,9 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, cx_write(ch->ptr1_reg, ch->fifo_start); cx_write(ch->ptr2_reg, cdt); cx_write(ch->cnt2_reg, (lines*16) >> 3); - cx_write(ch->cnt1_reg, (bpl >> 3) -1); + cx_write(ch->cnt1_reg, (bpl >> 3) - 1); - dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n", + dprintk(2, "[bridge %d] sram setup %s: bpl=%d lines=%d\n", dev->bridge, ch->name, bpl, @@ -470,43 +468,43 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, u32 risc; unsigned int i, j, n; - printk("%s: %s - dma channel status dump\n", + printk(KERN_WARNING "%s: %s - dma channel status dump\n", dev->name, ch->name); for (i = 0; i < ARRAY_SIZE(name); i++) - printk("%s: cmds: %-15s: 0x%08x\n", + printk(KERN_WARNING "%s: cmds: %-15s: 0x%08x\n", dev->name, name[i], cx_read(ch->cmds_start + 4*i)); for (i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i + 14)); - printk("%s: risc%d: ", dev->name, i); + printk(KERN_WARNING "%s: risc%d: ", dev->name, i); cx23885_risc_decode(risc); } for (i = 0; i < (64 >> 2); i += n) { risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ - printk("%s: (0x%08x) iq %x: ", dev->name, + printk(KERN_WARNING "%s: (0x%08x) iq %x: ", dev->name, ch->ctrl_start + 4 * i, i); n = cx23885_risc_decode(risc); for (j = 1; j < n; j++) { risc = cx_read(ch->ctrl_start + 4 * (i + j)); - printk("%s: iq %x: 0x%08x [ arg #%d ]\n", + printk(KERN_WARNING "%s: iq %x: 0x%08x [ arg #%d ]\n", dev->name, i+j, risc, j); } } - printk("%s: fifo: 0x%08x -> 0x%x\n", + printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n", dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); - printk("%s: ctrl: 0x%08x -> 0x%x\n", + printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n", dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); - printk("%s: ptr1_reg: 0x%08x\n", + printk(KERN_WARNING "%s: ptr1_reg: 0x%08x\n", dev->name, cx_read(ch->ptr1_reg)); - printk("%s: ptr2_reg: 0x%08x\n", + printk(KERN_WARNING "%s: ptr2_reg: 0x%08x\n", dev->name, cx_read(ch->ptr2_reg)); - printk("%s: cnt1_reg: 0x%08x\n", + printk(KERN_WARNING "%s: cnt1_reg: 0x%08x\n", dev->name, cx_read(ch->cnt1_reg)); - printk("%s: cnt2_reg: 0x%08x\n", + printk(KERN_WARNING "%s: cnt2_reg: 0x%08x\n", dev->name, cx_read(ch->cnt2_reg)); } @@ -516,13 +514,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port, struct cx23885_dev *dev = port->dev; unsigned int i, j, n; - printk("%s: risc disasm: %p [dma=0x%08lx]\n", + printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n", dev->name, risc->cpu, (unsigned long)risc->dma); for (i = 0; i < (risc->size >> 2); i += n) { - printk("%s: %04d: ", dev->name, i); + printk(KERN_INFO "%s: %04d: ", dev->name, i); n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i])); for (j = 1; j < n; j++) - printk("%s: %04d: 0x%08x [ arg #%d ]\n", + printk(KERN_INFO "%s: %04d: 0x%08x [ arg #%d ]\n", dev->name, i + j, risc->cpu[i + j], j); if (risc->cpu[i] == cpu_to_le32(RISC_JUMP)) break; @@ -601,7 +599,7 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not * occur on the cx23887 bridge. */ - if(dev->bridge == CX23885_BRIDGE_885) + if (dev->bridge == CX23885_BRIDGE_885) cx_clear(RDR_TLCTL0, 1 << 4); return 0; @@ -609,13 +607,13 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev) static int get_resources(struct cx23885_dev *dev) { - if (request_mem_region(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0), + if (request_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0), dev->name)) return 0; printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - dev->name, (unsigned long long)pci_resource_start(dev->pci,0)); + dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); return -EBUSY; } @@ -624,7 +622,8 @@ 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_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) +static int cx23885_init_tsport(struct cx23885_dev *dev, + struct cx23885_tsport *port, int portno) { dprintk(1, "%s(portno=%d)\n", __func__, portno); @@ -645,17 +644,17 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p init_timer(&port->mpegq.timeout); mutex_init(&port->frontends.lock); - INIT_LIST_HEAD(&port->frontends.frontend.felist); + INIT_LIST_HEAD(&port->frontends.felist); port->frontends.active_fe_id = 0; /* This should be hardcoded allow a single frontend * attachment to this tsport, keeping the -dvb.c * code clean and safe. */ - if(!port->num_frontends) + if (!port->num_frontends) port->num_frontends = 1; - switch(portno) { + switch (portno) { case 1: port->reg_gpcnt = VID_B_GPCNT; port->reg_gpcnt_ctl = VID_B_GPCNT_CTL; @@ -756,13 +755,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) mutex_unlock(&devlist); /* Configure the internal memory */ - if(dev->pci->device == 0x8880) { + if (dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 25000000; dev->sram_channels = cx23887_sram_channels; } else - if(dev->pci->device == 0x8852) { + if (dev->pci->device == 0x8852) { dev->bridge = CX23885_BRIDGE_885; /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 28000000; @@ -843,8 +842,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) } /* PCIe stuff */ - dev->lmmio = ioremap(pci_resource_start(dev->pci,0), - pci_resource_len(dev->pci,0)); + dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0)); dev->bmmio = (u8 __iomem *)dev->lmmio; @@ -874,7 +873,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_i2c_register(&dev->i2c_bus[1]); cx23885_i2c_register(&dev->i2c_bus[2]); cx23885_card_setup(dev); - cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); + cx23885_call_i2c_clients(&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL); cx23885_ir_init(dev); if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { @@ -920,8 +919,8 @@ static int cx23885_dev_setup(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)); + release_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0)); if (!atomic_dec_and_test(&dev->refcount)) return; @@ -948,7 +947,7 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) iounmap(dev->lmmio); } -static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, +static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, unsigned int lines) @@ -969,31 +968,31 @@ static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, } if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - *(rp++)=cpu_to_le32(0); /* bits 63-32 */ - offset+=bpl; + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL| + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_SOL| (sg_dma_len(sg)-offset)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= (sg_dma_len(sg)-offset); offset = 0; sg++; while (todo > sg_dma_len(sg)) { - *(rp++)=cpu_to_le32(RISC_WRITE| + *(rp++) = cpu_to_le32(RISC_WRITE| sg_dma_len(sg)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); sg++; } - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - *(rp++)=cpu_to_le32(0); /* bits 63-32 */ + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += todo; } offset += padding; @@ -1022,9 +1021,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, 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 = fields * (1 + ((bpl + padding) * lines) + / PAGE_SIZE + lines); instructions += 2; - if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + rc = btcx_riscmem_alloc(pci, risc, instructions*12); + if (rc < 0) return rc; /* write risc instructions */ @@ -1038,7 +1039,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -1060,7 +1061,8 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; - if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0) + rc = btcx_riscmem_alloc(pci, risc, instructions*12); + if (rc < 0) return rc; /* write risc instructions */ @@ -1069,7 +1071,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -1079,7 +1081,8 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, __le32 *rp; int rc; - if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0) + rc = btcx_riscmem_alloc(pci, risc, 4*16); + if (rc < 0) return rc; /* write risc instructions */ @@ -1173,22 +1176,23 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* setup fifo + format */ cx23885_sram_channel_setup(dev, - &dev->sram_channels[ port->sram_chno ], + &dev->sram_channels[port->sram_chno], port->ts_packet_size, buf->risc.dma); - if(debug > 5) { - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] ); + if (debug > 5) { + cx23885_sram_channel_dump(dev, + &dev->sram_channels[port->sram_chno]); cx23885_risc_disasm(port, &buf->risc); } /* write TS length to chip */ cx_write(port->reg_lngth, buf->vb.width); - if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && - (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) { - printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n", + if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && + (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { + printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", __func__, cx23885_boards[dev->board].portb, - cx23885_boards[dev->board].portc ); + cx23885_boards[dev->board].portc); return -EINVAL; } @@ -1198,7 +1202,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, udelay(100); /* If the port supports SRC SELECT, configure it */ - if(port->reg_src_sel) + if (port->reg_src_sel) cx_write(port->reg_src_sel, port->src_sel_val); cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val); @@ -1207,7 +1211,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_gen_ctrl, port->gen_ctrl_val); udelay(100); - // NOTE: this is 2 (reserved) for portb, does it matter? + /* NOTE: this is 2 (reserved) for portb, does it matter? */ /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; @@ -1241,11 +1245,11 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(ALT_PIN_OUT_SEL, 0x10100045); } - switch(dev->bridge) { + switch (dev->bridge) { case CX23885_BRIDGE_885: case CX23885_BRIDGE_887: /* enable irqs */ - dprintk(1, "%s() enabling TS int's and DMA\n", __func__ ); + dprintk(1, "%s() enabling TS int's and DMA\n", __func__); cx_set(port->reg_ts_int_msk, port->ts_int_msk_val); cx_set(port->reg_dma_ctl, port->dma_ctl_val); cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask); @@ -1310,8 +1314,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf; dprintk(5, "%s()\n", __func__); - if (list_empty(&q->active)) - { + if (list_empty(&q->active)) { struct cx23885_buffer *prev; prev = NULL; @@ -1329,7 +1332,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port, 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", + dprintk(5, "[%p/%d] restart_queue - f/active\n", buf, buf->vb.i); } else if (prev->vb.width == buf->vb.width && @@ -1340,8 +1343,9 @@ int cx23885_restart_queue(struct cx23885_tsport *port, 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 */ - dprintk(5,"[%p/%d] restart_queue - move to active\n", + /* 64 bit bits 63-32 */ + prev->risc.jmp[2] = cpu_to_le32(0); + dprintk(5, "[%p/%d] restart_queue - m/active\n", buf, buf->vb.i); } else { return 0; @@ -1380,7 +1384,8 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, buf->vb.size = size; buf->vb.field = field /*V4L2_FIELD_TOP*/; - if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) goto fail; cx23885_risc_databuffer(dev->pci, &buf->risc, videobuf_to_dma(&buf->vb)->sglist, @@ -1406,7 +1411,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ if (list_empty(&cx88q->active)) { - dprintk( 1, "queue is empty - first active\n" ); + 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 = VIDEOBUF_ACTIVE; @@ -1415,7 +1420,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.i, __func__); } else { - dprintk( 1, "queue is not empty - append to active\n" ); + dprintk(1, "queue is not empty - append to active\n"); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); list_add_tail(&buf->vb.queue, &cx88q->active); @@ -1423,7 +1428,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) 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 */ - dprintk( 1, "[%p/%d] %s - append to active\n", + dprintk(1, "[%p/%d] %s - append to active\n", buf, buf->vb.i, __func__); } } @@ -1449,7 +1454,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); } if (restart) { - dprintk(1, "restarting queue\n" ); + dprintk(1, "restarting queue\n"); cx23885_restart_queue(port, q); } spin_unlock_irqrestore(&port->slock, flags); @@ -1471,10 +1476,11 @@ static void cx23885_timeout(unsigned long data) struct cx23885_tsport *port = (struct cx23885_tsport *)data; struct cx23885_dev *dev = port->dev; - dprintk(1, "%s()\n",__func__); + dprintk(1, "%s()\n", __func__); if (debug > 5) - cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]); + cx23885_sram_channel_dump(dev, + &dev->sram_channels[port->sram_chno]); cx23885_stop_dma(port); do_cancel_buffers(port, "timeout", 1); @@ -1550,16 +1556,23 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) if ((status & VID_BC_MSK_OPC_ERR) || (status & VID_BC_MSK_BAD_PKT) || (status & VID_BC_MSK_SYNC) || - (status & VID_BC_MSK_OF)) - { + (status & VID_BC_MSK_OF)) { + if (status & VID_BC_MSK_OPC_ERR) - dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR); + dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", + VID_BC_MSK_OPC_ERR); + if (status & VID_BC_MSK_BAD_PKT) - dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT); + dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", + VID_BC_MSK_BAD_PKT); + if (status & VID_BC_MSK_SYNC) - dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC); + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", + VID_BC_MSK_SYNC); + if (status & VID_BC_MSK_OF) - dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF); + dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", + VID_BC_MSK_OF); printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); @@ -1593,7 +1606,7 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) return handled; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static irqreturn_t cx23885_irq(int irq, void *dev_id, struct pt_regs *regs) #else static irqreturn_t cx23885_irq(int irq, void *dev_id) @@ -1617,7 +1630,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) ts2_status = cx_read(VID_C_INT_STAT); ts2_mask = cx_read(VID_C_INT_MSK); - if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) + if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0)) goto out; vida_count = cx_read(VID_A_GPCNT); @@ -1632,38 +1645,56 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) 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) || - (pci_status & PCI_MSK_AL_RD) || - (pci_status & PCI_MSK_AL_WR) || - (pci_status & PCI_MSK_APB_DMA) || - (pci_status & PCI_MSK_VID_C) || - (pci_status & PCI_MSK_VID_B) || - (pci_status & PCI_MSK_VID_A) || - (pci_status & PCI_MSK_AUD_INT) || - (pci_status & PCI_MSK_AUD_EXT) ) - { + if ((pci_status & PCI_MSK_RISC_RD) || + (pci_status & PCI_MSK_RISC_WR) || + (pci_status & PCI_MSK_AL_RD) || + (pci_status & PCI_MSK_AL_WR) || + (pci_status & PCI_MSK_APB_DMA) || + (pci_status & PCI_MSK_VID_C) || + (pci_status & PCI_MSK_VID_B) || + (pci_status & PCI_MSK_VID_A) || + (pci_status & PCI_MSK_AUD_INT) || + (pci_status & PCI_MSK_AUD_EXT)) { if (pci_status & PCI_MSK_RISC_RD) - dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD); + dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", + PCI_MSK_RISC_RD); + if (pci_status & PCI_MSK_RISC_WR) - dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR); + dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", + PCI_MSK_RISC_WR); + if (pci_status & PCI_MSK_AL_RD) - dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD); + dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", + PCI_MSK_AL_RD); + if (pci_status & PCI_MSK_AL_WR) - dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR); + dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", + PCI_MSK_AL_WR); + if (pci_status & PCI_MSK_APB_DMA) - dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA); + dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", + PCI_MSK_APB_DMA); + if (pci_status & PCI_MSK_VID_C) - dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C); + dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", + PCI_MSK_VID_C); + if (pci_status & PCI_MSK_VID_B) - dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B); + dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", + PCI_MSK_VID_B); + if (pci_status & PCI_MSK_VID_A) - dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A); + dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", + PCI_MSK_VID_A); + if (pci_status & PCI_MSK_AUD_INT) - dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT); + dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", + PCI_MSK_AUD_INT); + if (pci_status & PCI_MSK_AUD_EXT) - dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT); + dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", + PCI_MSK_AUD_EXT); } @@ -1775,13 +1806,13 @@ static struct pci_device_id cx23885_pci_tbl[] = { .device = 0x8852, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - },{ + }, { /* CX23887 Rev 2 */ .vendor = 0x14f1, .device = 0x8880, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - },{ + }, { /* --- end of list --- */ } }; @@ -1819,9 +1850,3 @@ module_init(cx23885_init); module_exit(cx23885_fini); /* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 9b96b0600..a11fdbfb5 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -79,19 +79,19 @@ static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field); + return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); } static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct cx23885_tsport *port = q->priv_data; - cx23885_buf_queue(port, (struct cx23885_buffer*)vb); + cx23885_buf_queue(port, (struct cx23885_buffer *)vb); } static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { - cx23885_free_buffer(q, (struct cx23885_buffer*)vb); + cx23885_free_buffer(q, (struct cx23885_buffer *)vb); } static struct videobuf_queue_ops dvb_qops = { @@ -451,7 +451,8 @@ static int dvb_register(struct cx23885_tsport *port) .fname = XC3028L_DEFAULT_FIRMWARE, .max_len = 64, .demod = 5000, - /* This is true for all demods with v36 firmware? */ + /* This is true for all demods with + v36 firmware? */ .type = XC2028_D2633, }; @@ -526,12 +527,14 @@ static int dvb_register(struct cx23885_tsport *port) } break; default: - printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " + " isn't supported yet\n", dev->name); break; } if (NULL == fe0->dvb.frontend) { - printk("%s: frontend initialization failed\n", dev->name); + printk(KERN_ERR "%s: frontend initialization failed\n", + dev->name); return -1; } /* define general-purpose callback pointer */ @@ -569,7 +572,8 @@ int cx23885_dvb_register(struct cx23885_tsport *port) port->num_frontends); for (i = 1; i <= port->num_frontends; i++) { - if (videobuf_dvb_alloc_frontend(dev, &port->frontends, i) == NULL) { + if (videobuf_dvb_alloc_frontend( + &port->frontends, i) == NULL) { printk(KERN_ERR "%s() failed to alloc\n", __func__); return -ENOMEM; } @@ -579,7 +583,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) err = -EINVAL; dprintk(1, "%s\n", __func__); - dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n", dev->board, dev->name, dev->pci_bus, @@ -589,14 +593,16 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ - printk("%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock, + printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); + videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, + &dev->pci->dev, &port->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx23885_buffer), port); } err = dvb_register(port); if (err != 0) - printk("%s() dvb_register failed err = %d\n", __func__, err); + printk(KERN_ERR "%s() dvb_register failed err = %d\n", + __func__, err); return err; } @@ -613,15 +619,9 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) * implement MFE support. */ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); - if(fe0->dvb.frontend) + if (fe0->dvb.frontend) videobuf_dvb_unregister_bus(&port->frontends); return 0; } -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off -*/ diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c index 6f3a43607..ced5648d8 100644 --- a/linux/drivers/media/video/cx23885/cx23885-i2c.c +++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c @@ -132,7 +132,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, printk(" >\n"); } - for (cnt = 1; cnt < msg->len; cnt++ ) { + for (cnt = 1; cnt < msg->len; cnt++) { /* following bytes */ wdata = msg->buf[cnt]; ctrl = bus->i2c_period | (1 << 12) | (1 << 2); @@ -152,9 +152,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (retval == 0) goto eio; if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); + dprintk(1, " %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) - printk(" >\n"); + dprintk(1, " >\n"); } } return msg->len; @@ -163,7 +163,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, retval = -EIO; err: if (i2c_debug) - printk(" ERR: %d\n", retval); + printk(KERN_ERR " ERR: %d\n", retval); return retval; } @@ -195,12 +195,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, if (i2c_debug) { if (joined) - printk(" R"); + dprintk(1, " R"); else - printk(" <R %02x", (msg->addr << 1) + 1); + dprintk(1, " <R %02x", (msg->addr << 1) + 1); } - for(cnt = 0; cnt < msg->len; cnt++) { + for (cnt = 0; cnt < msg->len; cnt++) { ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; @@ -217,9 +217,9 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, goto eio; msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); + dprintk(1, " %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) - printk(" >\n"); + dprintk(1, " >\n"); } } return msg->len; @@ -228,7 +228,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, retval = -EIO; err: if (i2c_debug) - printk(" ERR: %d\n", retval); + printk(KERN_ERR " ERR: %d\n", retval); return retval; } @@ -372,17 +372,17 @@ static struct i2c_client cx23885_i2c_client_template = { }; static char *i2c_devs[128] = { - [0x10 >> 1] = "tda10048", - [0x12 >> 1] = "dib7000pc", - [ 0x1c >> 1 ] = "lgdt3303", - [ 0x86 >> 1 ] = "tda9887", - [ 0x32 >> 1 ] = "cx24227", - [ 0x88 >> 1 ] = "cx25837", - [ 0x84 >> 1 ] = "tda8295", - [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", + [0x10 >> 1] = "tda10048", + [0x12 >> 1] = "dib7000pc", + [0x1c >> 1] = "lgdt3303", + [0x86 >> 1] = "tda9887", + [0x32 >> 1] = "cx24227", + [0x88 >> 1] = "cx25837", + [0x84 >> 1] = "tda8295", + [0xa0 >> 1] = "eeprom", + [0xc0 >> 1] = "tuner/mt2131/tda8275", [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028", - [0xc8 >> 1] = "tuner/xc3028L", + [0xc8 >> 1] = "tuner/xc3028L", }; static void do_i2c_scan(char *name, struct i2c_client *c) @@ -395,7 +395,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", + printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -427,11 +427,12 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) bus->i2c_client.adapter = &bus->i2c_adap; if (0 == bus->i2c_rc) { - printk("%s: i2c bus %d registered\n", dev->name, bus->nr); + dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr); if (i2c_scan) do_i2c_scan(dev->name, &bus->i2c_client); } else - printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", + dev->name, bus->nr); return bus->i2c_rc; } diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c index 70333ee2b..0b5d20481 100644 --- a/linux/drivers/media/video/cx23885/cx23885-video.c +++ b/linux/drivers/media/video/cx23885/cx23885-video.c @@ -320,11 +320,10 @@ static void cx23885_video_wakeup(struct cx23885_dev *dev, list_del(&buf->vb.queue); wake_up(&buf->vb.done); } - if (list_empty(&q->active)) { + if (list_empty(&q->active)) del_timer(&q->timeout); - } else { + else mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - } if (bc != 1) printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", __func__, bc); @@ -414,12 +413,12 @@ static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, static int res_check(struct cx23885_fh *fh, unsigned int bit) { - return (fh->resources & bit); + return fh->resources & bit; } static int res_locked(struct cx23885_dev *dev, unsigned int bit) { - return (dev->resources & bit); + return dev->resources & bit; } static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, @@ -964,14 +963,16 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -static int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +static int cx23885_get_control(struct cx23885_dev *dev, + struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); return 0; } -static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +static int cx23885_set_control(struct cx23885_dev *dev, + struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" " (disabled - no action)\n", __func__); @@ -1156,29 +1157,29 @@ 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)); + 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)); + 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)); + 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)); + return videobuf_dqbuf(get_queue(fh), p, + file->f_flags & O_NONBLOCK); } static int vidioc_streamon(struct file *file, void *priv, @@ -1809,7 +1810,7 @@ int cx23885_video_register(struct cx23885_dev *dev) goto fail_unreg; } printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->minor & 0x1f); + dev->name, dev->video_dev->num); #if 0 dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); @@ -1821,7 +1822,7 @@ int cx23885_video_register(struct cx23885_dev *dev) goto fail_unreg; } printk(KERN_INFO "%s/0: registered device vbi%d\n", - dev->name, dev->vbi_dev->minor & 0x1f); + dev->name, dev->vbi_dev->num); if (dev->has_radio) { dev->radio_dev = cx23885_vdev_init(dev, dev->pci, @@ -1834,7 +1835,7 @@ int cx23885_video_register(struct cx23885_dev *dev) goto fail_unreg; } printk(KERN_INFO "%s/0: registered device radio%d\n", - dev->name, dev->radio_dev->minor & 0x1f); + dev->name, dev->radio_dev->num); } #endif /* initial device configuration */ diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 2dde9e01a..26f755354 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -38,7 +38,7 @@ #include <linux/version.h> #include <linux/mutex.h> -#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1) +#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 1) #define UNSET (-1U) @@ -371,14 +371,14 @@ struct sram_channel { /* ----------------------------------------------------------- */ #define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) -#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2)) +#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) -#define cx_andor(reg,mask,value) \ +#define cx_andor(reg, mask, value) \ writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ ((value) & (mask)), dev->lmmio+((reg)>>2)) -#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) -#define cx_clear(reg,bit) cx_andor((reg),(bit),0) +#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) +#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) /* ----------------------------------------------------------- */ /* cx23885-core.c */ @@ -415,7 +415,8 @@ extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; -extern int cx23885_tuner_callback(void *priv, int component, int command, int arg); +extern int cx23885_tuner_callback(void *priv, int component, + 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); @@ -483,11 +484,3 @@ 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 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/linux/drivers/media/video/cx25840/Kconfig b/linux/drivers/media/video/cx25840/Kconfig index de515dada..451133ad4 100644 --- a/linux/drivers/media/video/cx25840/Kconfig +++ b/linux/drivers/media/video/cx25840/Kconfig @@ -1,6 +1,6 @@ config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Conexant CX2584x audio/video decoders. diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c index c675cbeae..3dd2f6629 100644 --- a/linux/drivers/media/video/cx88/cx88-alsa.c +++ b/linux/drivers/media/video/cx88/cx88-alsa.c @@ -60,7 +60,7 @@ #define timestamp() if(debug>=2) { u64 time; u32 rem; rdtscll(time); \ time = (time - chip->starttime)<<12; \ rem = do_div(time, INT); \ - dprintk(2, "%s - called at %u.%03u us\n", __FUNCTION__, \ + dprintk(2, "%s - called at %u.%03u us\n", __func__, \ (unsigned int)time, (rem << 9) / FRAC); } #endif /**************************************************************************** diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c index 5f44368f6..3d2afe195 100644 --- a/linux/drivers/media/video/cx88/cx88-blackbird.c +++ b/linux/drivers/media/video/cx88/cx88-blackbird.c @@ -1097,7 +1097,7 @@ static int mpeg_open(struct inode *inode, struct file *file) } } - if (blackbird_initialize_codec(dev) < 0) { + if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) { if (drv) drv->request_release(drv); unlock_kernel(); @@ -1128,6 +1128,8 @@ static int mpeg_open(struct inode *inode, struct file *file) fh->mpegq.field); unlock_kernel(); + atomic_inc(&dev->core->mpeg_users); + return 0; } @@ -1137,7 +1139,7 @@ static int mpeg_release(struct inode *inode, struct file *file) struct cx8802_dev *dev = fh->dev; struct cx8802_driver *drv = NULL; - if (dev->mpeg_active) + if (dev->mpeg_active && atomic_read(&dev->core->mpeg_users) == 1) blackbird_stop_codec(dev); cx8802_cancel_buffers(fh->dev); @@ -1157,6 +1159,8 @@ static int mpeg_release(struct inode *inode, struct file *file) if (drv) drv->request_release(drv); + atomic_dec(&dev->core->mpeg_users); + return 0; } @@ -1177,6 +1181,10 @@ static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); return videobuf_poll_stream(file, &fh->mpegq, wait); } @@ -1307,7 +1315,7 @@ static int blackbird_register_video(struct cx8802_dev *dev) return err; } printk(KERN_INFO "%s/2: registered device video%d [mpeg]\n", - dev->core->name,dev->mpeg_dev->minor & 0x1f); + dev->core->name, dev->mpeg_dev->num); return 0; } diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index eac3508d6..f9b5a9c09 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1270,7 +1270,6 @@ static const struct cx88_board cx88_boards[] = { }, }, [CX88_BOARD_WINFAST_DTV2000H] = { - /* video inputs and radio still in testing */ .name = "WinFast DTV2000 H", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, .radio_type = UNSET, @@ -1284,7 +1283,35 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x00008203, .gpio2 = 0x00017304, .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0001d701, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d701, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE2, + .vmux = 2, + .gpio0 = 0x0001d503, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d503, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 3, + .gpio0 = 0x0001d701, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d701, + .gpio3 = 0x02000000, }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00015702, + .gpio1 = 0x0000f207, + .gpio2 = 0x00015702, + .gpio3 = 0x02000000, + }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_GENIATECH_DVBS] = { @@ -1314,22 +1341,26 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x84bf, + /* 1: TV Audio / FM Mono */ .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x84bf, + /* 2: Line-In */ .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x84bf, + /* 2: Line-In */ .audioroute = 2, }}, - /* FIXME Radio tunes but only noise is heard */ .radio = { .type = CX88_RADIO, .gpio0 = 0x84bf, + /* 4: FM Stereo (untested) */ + .audioroute = 8, }, .mpeg = CX88_MPEG_DVB, .num_frontends = 2, @@ -1398,23 +1429,27 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xef88, + /* 1: TV Audio / FM Mono */ .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xef88, + /* 2: Line-In */ .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xef88, + /* 2: Line-In */ .audioroute = 2, }}, - /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, .radio = { .type = CX88_RADIO, .gpio0 = 0xef88, + /* 4: FM Stereo (untested) */ + .audioroute = 8, }, }, [CX88_BOARD_ADSTECH_PTV_390] = { @@ -1788,27 +1823,38 @@ static const struct cx88_board cx88_boards[] = { * d 0 I * e 1 O * f 1 O + * + * WM8775 ADC + * + * 1: TV Audio / FM Mono + * 2: Line-In + * 3: Line-In Expansion + * 4: FM Stereo */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xc4bf, + /* 1: TV Audio / FM Mono */ .audioroute = 1, }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xc4bf, + /* 2: Line-In */ .audioroute = 2, }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xc4bf, + /* 2: Line-In */ .audioroute = 2, } }, - /* FIXME Radio tunes but only noise is heard */ .radio = { .type = CX88_RADIO, .gpio0 = 0xc4bf, + /* 4: FM Stereo */ + .audioroute = 8, }, .mpeg = CX88_MPEG_DVB, .num_frontends = 2, @@ -1861,6 +1907,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_TBS_8910] = { + .name = "TBS 8910 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_TBS_8920] = { .name = "TBS 8920 DVB-S/S2", .tuner_type = TUNER_ABSENT, @@ -1873,6 +1931,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_PROF_6200] = { + .name = "Prof 6200 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_PROF_7300] = { .name = "PROF 7300 DVB-S/S2", .tuner_type = UNSET, @@ -1885,6 +1955,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_SATTRADE_ST4200] = { + .name = "SATTRADE ST4200 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -1911,7 +1993,11 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = PCI_VENDOR_ID_ATI, .subdevice = 0x00f8, .card = CX88_BOARD_ATI_WONDER_PRO, - },{ + }, { + .subvendor = PCI_VENDOR_ID_ATI, + .subdevice = 0x00f9, + .card = CX88_BOARD_ATI_WONDER_PRO, + }, { .subvendor = 0x107d, .subdevice = 0x6611, .card = CX88_BOARD_WINFAST2000XP_EXPERT, @@ -2271,13 +2357,25 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x2011, .card = CX88_BOARD_OMICOM_SS4_PCI, }, { + .subvendor = 0x8910, + .subdevice = 0x8888, + .card = CX88_BOARD_TBS_8910, + }, { .subvendor = 0x8920, .subdevice = 0x8888, .card = CX88_BOARD_TBS_8920, }, { + .subvendor = 0xb022, + .subdevice = 0x3022, + .card = CX88_BOARD_PROF_6200, + }, { .subvendor = 0xB033, .subdevice = 0x3033, .card = CX88_BOARD_PROF_7300, + }, { + .subvendor = 0xb200, + .subdevice = 0x4200, + .card = CX88_BOARD_SATTRADE_ST4200, }, }; @@ -2888,8 +2986,11 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_TEVII_S420: case CX88_BOARD_TEVII_S460: case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_TBS_8910: case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_6200: case CX88_BOARD_PROF_7300: + case CX88_BOARD_SATTRADE_ST4200: cx_write(MO_SRST_IO, 0); msleep(100); cx_write(MO_SRST_IO, 1); @@ -3058,8 +3159,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - if (!core->board.num_frontends) - core->board.num_frontends=1; + if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB)) + core->board.num_frontends = 1; info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n", pci->subsystem_vendor, pci->subsystem_device, core->board.name, diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c index 4ce5f7589..c9de13b56 100644 --- a/linux/drivers/media/video/cx88/cx88-core.c +++ b/linux/drivers/media/video/cx88/cx88-core.c @@ -574,7 +574,8 @@ void cx88_wakeup(struct cx88_core *core, mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); } if (bc != 1) - printk("%s: %d buffers handled (should be 1)\n",__func__,bc); + dprintk(2, "%s: %d buffers handled (should be 1)\n", + __func__, bc); } void cx88_shutdown(struct cx88_core *core) @@ -868,6 +869,9 @@ static int set_tvaudio(struct cx88_core *core) } else if (V4L2_STD_SECAM_L & norm) { core->tvaudio = WW_L; + } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) { + core->tvaudio = WW_BG; + } else if (V4L2_STD_SECAM_DK & norm) { core->tvaudio = WW_DK; diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 1a0f971c6..5a9fafd25 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -121,7 +121,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe); if (!fe_id) { - printk(KERN_ERR "%s() No frontend found\n", __FUNCTION__); + printk(KERN_ERR "%s() No frontend found\n", __func__); return -EINVAL; } @@ -582,14 +582,14 @@ static struct cx24116_config tevii_s460_config = { static struct stv0299_config tevii_tuner_sharp_config = { .demod_address = 0x68, - .inittab = sharp_z0194a__inittab, + .inittab = sharp_z0194a_inittab, .mclk = 88000000UL, .invert = 1, .skip_reinit = 0, .lock_output = 1, .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 100, - .set_symbol_rate = sharp_z0194a__set_symbol_rate, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, .set_ts_params = cx24116_set_ts_param, }; @@ -605,10 +605,15 @@ static int dvb_register(struct cx8802_dev *dev) struct videobuf_dvb_frontend *fe0, *fe1 = NULL; int mfe_shared = 0; /* bus not shared by default */ + if (0 != core->i2c_rc) { + printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); + goto frontend_detach; + } + /* Get the first frontend */ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); if (!fe0) - return -EINVAL; + goto frontend_detach; /* multi-frontend gate control is undefined or defaults to fe0 */ dev->frontends.gate = 0; @@ -655,38 +660,35 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_HAUPPAUGE_HVR3000: + /* MFE frontend 1 */ + mfe_shared = 1; + dev->frontends.gate = 2; /* DVB-S init */ fe0->dvb.frontend = dvb_attach(cx24123_attach, - &hauppauge_novas_config, - &dev->core->i2c_adap); + &hauppauge_novas_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { - if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) { - dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __FUNCTION__); - } - } else { - dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __FUNCTION__); + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; } - /* DVB-T init */ + /* MFE frontend 2 */ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); - if (fe1) { - dev->frontends.gate = 2; - mfe_shared = 1; - fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); - if (fe1->dvb.frontend) { - fe1->dvb.frontend->id = 1; - if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) { - dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __FUNCTION__); - } - } else { - dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __FUNCTION__); - } - } else { - dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __FUNCTION__); + if (!fe1) + goto frontend_detach; + /* DVB-T init */ + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if (!dvb_attach(simple_tuner_attach, + fe1->dvb.frontend, + &dev->core->i2c_adap, + 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: @@ -796,7 +798,7 @@ static int dvb_register(struct cx8802_dev *dev) if (fe0->dvb.frontend) fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (attach_xc3028(0x61, dev) < 0) - return -EINVAL; + goto frontend_detach; break; case CX88_BOARD_PCHDTV_HD3000: fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, @@ -1000,50 +1002,51 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_HAUPPAUGE_HVR4000: + /* MFE frontend 1 */ + mfe_shared = 1; + dev->frontends.gate = 2; /* DVB-S/S2 Init */ fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { - if(!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) { - dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __FUNCTION__); - } - } else { - dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __FUNCTION__); + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; } - /* DVB-T Init */ + /* MFE frontend 2 */ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); - if (fe1) { - dev->frontends.gate = 2; - mfe_shared = 1; - fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); - if (fe1->dvb.frontend) { - fe1->dvb.frontend->id = 1; - if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) { - dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __FUNCTION__); - } - } else { - dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __FUNCTION__); - } - } else { - dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __FUNCTION__); + if (!fe1) + goto frontend_detach; + /* DVB-T Init */ + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if (!dvb_attach(simple_tuner_attach, + fe1->dvb.frontend, + &dev->core->i2c_adap, + 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; } break; case CX88_BOARD_HAUPPAUGE_HVR4000LITE: fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { - dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00); + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; } break; + case CX88_BOARD_PROF_6200: + case CX88_BOARD_TBS_8910: case CX88_BOARD_TEVII_S420: fe0->dvb.frontend = dvb_attach(stv0299_attach, &tevii_tuner_sharp_config, @@ -1065,7 +1068,6 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - } } break; @@ -1073,21 +1075,18 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx24116_attach, &tevii_s460_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + if (fe0->dvb.frontend != NULL) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - } break; case CX88_BOARD_OMICOM_SS4_PCI: case CX88_BOARD_TBS_8920: case CX88_BOARD_PROF_7300: + case CX88_BOARD_SATTRADE_ST4200: fe0->dvb.frontend = dvb_attach(cx24116_attach, &hauppauge_hvr4000_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + if (fe0->dvb.frontend != NULL) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - } break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", @@ -1099,7 +1098,7 @@ static int dvb_register(struct cx8802_dev *dev) printk(KERN_ERR "%s/2: frontend initialization failed\n", core->name); - return -EINVAL; + goto frontend_detach; } /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = cx88_tuner_callback; @@ -1117,10 +1116,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->pci->dev, adapter_nr, mfe_shared); frontend_detach: - if (fe0->dvb.frontend) { - dvb_frontend_detach(fe0->dvb.frontend); - fe0->dvb.frontend = NULL; - } + videobuf_dvb_dealloc_frontends(&dev->frontends); return -EINVAL; } @@ -1208,8 +1204,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; struct cx8802_dev *dev = drv->core->dvbdev; - int err, i; - struct videobuf_dvb_frontend *fe; + int err; dprintk( 1, "%s\n", __func__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", @@ -1225,39 +1220,58 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* If vp3054 isn't enabled, a stub will just return 0 */ err = vp3054_i2c_probe(dev); if (0 != err) - goto fail_core; + goto fail_probe; /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); dev->ts_gen_cntrl = 0x0c; - for (i = 1; i <= core->board.num_frontends; i++) { - fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); - if (!fe) { - printk(KERN_ERR "%s() failed to get frontend(%d)\n", __FUNCTION__, i); - continue; + err = -ENODEV; + if (core->board.num_frontends) { + struct videobuf_dvb_frontend *fe; + int i; + + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); + if (fe == NULL) { + printk(KERN_ERR "%s() failed to get frontend(%d)\n", + __func__, i); + goto fail_probe; + } + videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_TOP, + sizeof(struct cx88_buffer), + dev); + /* init struct videobuf_dvb */ + fe->dvb.name = dev->core->name; } - videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_TOP, - sizeof(struct cx88_buffer), - dev); - /* init struct videobuf_dvb */ - fe->dvb.name = dev->core->name; + } else { + /* no frontends allocated */ + printk(KERN_ERR "%s/2 .num_frontends should be non-zero\n", + core->name); + goto fail_core; } err = dvb_register(dev); - if (err != 0) + if (err) + /* frontends/adapter de-allocated in dvb_register */ printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", core->name, err); + return err; +fail_probe: + videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends); fail_core: return err; } static int cx8802_dvb_remove(struct cx8802_driver *drv) { + struct cx88_core *core = drv->core; struct cx8802_dev *dev = drv->core->dvbdev; + dprintk( 1, "%s\n", __func__); + videobuf_dvb_unregister_bus(&dev->frontends); vp3054_i2c_remove(dev); diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 01de23007..1ab691d20 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -116,8 +116,10 @@ static int detach_inform(struct i2c_client *client) void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) { +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) struct videobuf_dvb_frontends *f = &core->dvbdev->frontends; struct videobuf_dvb_frontend *fe = NULL; +#endif if (0 != core->i2c_rc) return; diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index 88c237790..dbad45a35 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -808,8 +808,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, { struct cx8802_dev *dev; struct cx88_core *core; - struct videobuf_dvb_frontend *demod; - int err,i; + int err; /* general setup */ core = cx88_core_get(pci_dev); @@ -822,11 +821,6 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, if (!core->board.mpeg) goto fail_core; - if (!core->board.num_frontends) { - printk(KERN_ERR "%s() .num_frontends should be non-zero, err = %d\n", __FUNCTION__, err); - goto fail_core; - } - err = -ENOMEM; dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) @@ -841,19 +835,28 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, INIT_LIST_HEAD(&dev->drvlist); list_add_tail(&dev->devlist,&cx8802_devlist); +#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) mutex_init(&dev->frontends.lock); - INIT_LIST_HEAD(&dev->frontends.frontend.felist); - - printk(KERN_INFO "%s() allocating %d frontend(s)\n", __FUNCTION__, core->board.num_frontends); - - for (i = 1; i <= core->board.num_frontends; i++) { - demod = videobuf_dvb_alloc_frontend(dev, &dev->frontends, i); - if(demod == NULL) { - printk(KERN_ERR "%s() failed to alloc\n", __FUNCTION__); - err = -ENOMEM; - goto fail_free; + INIT_LIST_HEAD(&dev->frontends.felist); + + if (core->board.num_frontends) { + struct videobuf_dvb_frontend *fe; + int i; + + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, + core->board.num_frontends); + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_alloc_frontend(&dev->frontends, i); + if(fe == NULL) { + printk(KERN_ERR "%s() failed to alloc\n", + __func__); + videobuf_dvb_dealloc_frontends(&dev->frontends); + err = -ENOMEM; + goto fail_free; + } } } +#endif /* Maintain a reference so cx88-video can query the 8802 device. */ core->dvbdev = dev; diff --git a/linux/drivers/media/video/cx88/cx88-tvaudio.c b/linux/drivers/media/video/cx88/cx88-tvaudio.c index 5eb95dbbe..0039354cf 100644 --- a/linux/drivers/media/video/cx88/cx88-tvaudio.c +++ b/linux/drivers/media/video/cx88/cx88-tvaudio.c @@ -771,6 +771,14 @@ void cx88_set_tvaudio(struct cx88_core *core) case WW_FM: set_audio_standard_FM(core, radio_deemphasis); break; + case WW_I2SADC: + set_audio_start(core, 0x01); + /* Slave/Philips/Autobaud */ + cx_write(AUD_I2SINPUTCNTL, 0); + /* Switch to "I2S ADC mode" */ + cx_write(AUD_I2SCNTL, 0x1); + set_audio_finish(core, EN_I2SIN_ENABLE); + break; case WW_NONE: default: printk("%s/0: unknown tv audio mode [%d]\n", @@ -948,6 +956,9 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) break; } break; + case WW_I2SADC: + /* DO NOTHING */ + break; } if (UNSET != ctl) { diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index c4fdb6da2..40136a431 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -427,24 +427,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) /* 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 { - /* 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 */ @@ -455,9 +438,19 @@ 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); - } - + /* 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 ) { + /* "I2S ADC mode" */ + core->tvaudio = WW_I2SADC; + cx88_set_tvaudio(core); + } else { + /* Normal mode */ + cx_write(AUD_I2SCNTL, 0x0); + cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + } } return 0; @@ -1058,9 +1051,24 @@ static int video_open(struct inode *inode, struct file *file) cx_write(MO_GP0_IO, core->board.radio.gpio0); cx_write(MO_GP1_IO, core->board.radio.gpio1); cx_write(MO_GP2_IO, core->board.radio.gpio2); - core->tvaudio = WW_FM; - cx88_set_tvaudio(core); - cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); + if (core->board.radio.audioroute) { + if(core->board.audio_chip && + core->board.audio_chip == V4L2_IDENT_WM8775) { + struct v4l2_routing route; + + route.input = core->board.radio.audioroute; + cx88_call_i2c_clients(core, + VIDIOC_INT_S_AUDIO_ROUTING, &route); + } + /* "I2S ADC mode" */ + core->tvaudio = WW_I2SADC; + cx88_set_tvaudio(core); + } else { + /* FM Mode */ + core->tvaudio = WW_FM; + cx88_set_tvaudio(core); + cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); + } cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); } unlock_kernel(); @@ -1445,8 +1453,12 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) struct cx8800_fh *fh = priv; struct cx8800_dev *dev = fh->dev; - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + /* We should remember that this driver also supports teletext, */ + /* so we have to test if the v4l2_buf_type is VBI capture data. */ + if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) return -EINVAL; + if (unlikely(i != fh->type)) return -EINVAL; @@ -1461,8 +1473,10 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) struct cx8800_dev *dev = fh->dev; int err, res; - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; + if (i != fh->type) return -EINVAL; @@ -2177,7 +2191,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; } printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", - core->name,dev->video_dev->minor & 0x1f); + core->name, dev->video_dev->num); dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, @@ -2188,7 +2202,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; } printk(KERN_INFO "%s/0: registered device vbi%d\n", - core->name,dev->vbi_dev->minor & 0x1f); + core->name, dev->vbi_dev->num); if (core->board.radio.type == CX88_RADIO) { dev->radio_dev = cx88_vdev_init(core,dev->pci, @@ -2201,7 +2215,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; } printk(KERN_INFO "%s/0: registered device radio%d\n", - core->name,dev->radio_dev->minor & 0x1f); + core->name, dev->radio_dev->num); } /* everything worked */ diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 774c0b9b1..6f8e575a3 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -54,12 +54,11 @@ /* ----------------------------------------------------------- */ /* defines and enums */ -/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ -#define CX88_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 ) +/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */ +#define CX88_NORMS (V4L2_STD_ALL \ + & ~V4L2_STD_PAL_H \ + & ~V4L2_STD_NTSC_M_KR \ + & ~V4L2_STD_SECAM_LC) #define FORMAT_FLAGS_PACKED 0x01 #define FORMAT_FLAGS_PLANAR 0x02 @@ -230,6 +229,9 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TEVII_S420 73 #define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74 #define CX88_BOARD_PROF_7300 75 +#define CX88_BOARD_SATTRADE_ST4200 76 +#define CX88_BOARD_TBS_8910 77 +#define CX88_BOARD_PROF_6200 78 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -356,6 +358,7 @@ struct cx88_core { /* various v4l controls */ u32 freq; atomic_t users; + atomic_t mpeg_users; /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ struct cx8802_dev *dvbdev; @@ -651,6 +654,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); #define WW_EIAJ 7 #define WW_I2SPT 8 #define WW_FM 9 +#define WW_I2SADC 10 void cx88_set_tvaudio(struct cx88_core *core); void cx88_newstation(struct cx88_core *core); diff --git a/linux/drivers/media/video/dabusb.c b/linux/drivers/media/video/dabusb.c index 21280dbc3..7ba206b34 100644 --- a/linux/drivers/media/video/dabusb.c +++ b/linux/drivers/media/video/dabusb.c @@ -202,7 +202,7 @@ static void dabusb_iso_complete (struct urb *purb) err("dabusb_iso_complete: invalid len %d", len); } else - warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status); + dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status); if (dst != purb->actual_length) err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length); } @@ -299,7 +299,7 @@ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) } if( ret == -EPIPE ) { - warn("CLEAR_FEATURE request to remove STALL condition."); + dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n"); if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) err("request failed"); } diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index d6856b331..b86b0870d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -496,11 +496,12 @@ static int em28xx_audio_init(struct em28xx *dev) struct snd_card *card; #endif static int devnr; - int ret, err; + int err; - if (dev->has_audio_class) { + if (dev->has_alsa_audio != 1) { /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module */ + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ return 0; } @@ -521,7 +522,12 @@ static int em28xx_audio_init(struct em28xx *dev) } spin_lock_init(&adev->slock); - ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); + err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); + if (err < 0) { + snd_card_free(card); + return err; + } + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); pcm->info_flags = 0; pcm->private_data = dev; @@ -533,7 +539,7 @@ static int em28xx_audio_init(struct em28xx *dev) err = snd_card_register(card); if (err < 0) { snd_card_free(card); - return -ENOMEM; + return err; } adev->sndcard = card; adev->udev = dev->udev; @@ -547,9 +553,10 @@ static int em28xx_audio_fini(struct em28xx *dev) if (dev == NULL) return 0; - if (dev->has_audio_class) { + if (dev->has_alsa_audio != 1) { /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module */ + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 4f078da31..57c91838e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -593,6 +593,7 @@ struct em28xx_board em28xx_boards[] = { .mts_firmware = 1, .has_12mhz_i2s = 1, .has_dvb = 1, + .ir_codes = ir_codes_hauppauge_new, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -616,6 +617,7 @@ struct em28xx_board em28xx_boards[] = { .mts_firmware = 1, .has_12mhz_i2s = 1, .has_dvb = 1, + .ir_codes = ir_codes_pinnacle_pctv_hd, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -639,6 +641,7 @@ struct em28xx_board em28xx_boards[] = { .mts_firmware = 1, .has_12mhz_i2s = 1, .has_dvb = 1, + .ir_codes = ir_codes_ati_tv_wonder_hd_600, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -1088,6 +1091,21 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + [EM2874_BOARD_PINNACLE_PCTV_80E] = { + .name = "Pinnacle PCTV HD Mini", + .vchannels = 0, + .tuner_type = TUNER_ABSENT, + .has_dvb = 1, + .ir_codes = ir_codes_pinnacle_pctv_hd, + .decoder = EM28XX_NODECODER, +#ifdef DJH_DEBUG + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + } }, +#endif + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1185,6 +1203,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, { USB_DEVICE(0x2304, 0x0227), .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, + { USB_DEVICE(0x2304, 0x023f), + .driver_info = EM2874_BOARD_PINNACLE_PCTV_80E }, { USB_DEVICE(0x0413, 0x6023), .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, { USB_DEVICE(0x093b, 0xa005), @@ -1260,6 +1280,17 @@ static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = { { -1, -1, -1, -1}, }; +/* Pinnacle PCTV HD Mini (80e) GPIOs + 0-5: not used + 6: demod reset, active low + 7: LED on, active high */ +static struct em28xx_reg_seq em2874_pinnacle_80e_digital[] = { + {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ + {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/ + {EM2874_R80_GPIO, 0xc0, 0xff, 10}, + { -1, -1, -1, -1}, +}; + /* * EEPROM hash table for devices with generic USB IDs */ @@ -1307,6 +1338,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; dev->has_dvb = em28xx_boards[dev->model].has_dvb; dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; + dev->ir_codes = em28xx_boards[dev->model].ir_codes; dev->valid = em28xx_boards[dev->model].valid; } @@ -1317,17 +1349,34 @@ void em28xx_pre_card_setup(struct em28xx *dev) { int rc; - rc = em28xx_read_reg(dev, EM2880_R04_GPO); - if (rc >= 0) - dev->reg_gpo = rc; + /* Set the default GPO/GPIO for legacy devices */ + dev->reg_gpo_num = EM2880_R04_GPO; + dev->reg_gpio_num = EM28XX_R08_GPIO; dev->wait_after_write = 5; + + /* Based on the Chip ID, set the device configuration */ rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); if (rc > 0) { + dev->chip_id = rc; switch (rc) { + case CHIP_ID_EM2750: + em28xx_info("chip ID is em2750\n"); + break; + case CHIP_ID_EM2820: + em28xx_info("chip ID is em2820\n"); + break; + case CHIP_ID_EM2840: + em28xx_info("chip ID is em2840\n"); + break; case CHIP_ID_EM2860: em28xx_info("chip ID is em2860\n"); break; + case CHIP_ID_EM2874: + em28xx_info("chip ID is em2874\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; case CHIP_ID_EM2883: em28xx_info("chip ID is em2882/em2883\n"); dev->wait_after_write = 0; @@ -1336,6 +1385,12 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_info("em28xx chip ID = %d\n", rc); } } + + /* Prepopulate cached GPO register content */ + rc = em28xx_read_reg(dev, dev->reg_gpo_num); + if (rc >= 0) + dev->reg_gpo = rc; + em28xx_set_model(dev); /* request some modules */ @@ -1509,6 +1564,13 @@ void em28xx_pre_card_setup(struct em28xx *dev) /* enables audio for that device */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; + + case EM2874_BOARD_PINNACLE_PCTV_80E: + /* Set 400 KHz clock */ + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x45", 1); + + dev->digital_gpio = em2874_pinnacle_80e_digital; + break; } em28xx_gpio_set(dev, dev->tun_analog_gpio); @@ -1717,6 +1779,7 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); dev->tuner_type = em28xx_boards[dev->model].tuner_type; + dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; /* request some modules */ switch (dev->model) { @@ -1800,4 +1863,6 @@ void em28xx_card_setup(struct em28xx *dev) #endif em28xx_config_tuner(dev); + + em28xx_ir_init(dev); } diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 1a30e361c..ef6830cd5 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -69,19 +69,29 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, int ret, byte; if (dev->state & DEV_DISCONNECTED) - return(-ENODEV); + return -ENODEV; + + if (len > URB_MAX_CTRL_SIZE) + return -EINVAL; em28xx_regdbg("req=%02x, reg=%02x ", req, reg); ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, buf, len, HZ); + 0x0000, reg, dev->urb_buf, len, HZ); + if (ret < 0) { + if (reg_debug) + printk(" failed!\n"); + return ret; + } + + if (len) + memcpy(buf, dev->urb_buf, len); if (reg_debug) { - printk(ret < 0 ? " failed!\n" : "%02x values: ", ret); + printk("%02x values: ", ret); for (byte = 0; byte < len; byte++) printk(" %02x", (unsigned char)buf[byte]); - printk("\n"); } @@ -104,14 +114,16 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, &val, 1, HZ); + 0x0000, reg, dev->urb_buf, 1, HZ); + if (ret < 0) { + printk(" failed!\n"); + return ret; + } - if (reg_debug) - printk(ret < 0 ? " failed!\n" : - "%02x\n", (unsigned char) val); + val = dev->urb_buf[0]; - if (ret < 0) - return ret; + if (reg_debug) + printk("%02x\n", (unsigned char) val); return val; } @@ -130,19 +142,13 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, { int ret; - /*usb_control_msg seems to expect a kmalloced buffer */ - unsigned char *bufs; - if (dev->state & DEV_DISCONNECTED) return -ENODEV; - if (len < 1) + if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) return -EINVAL; - bufs = kmalloc(len, GFP_KERNEL); - em28xx_regdbg("req=%02x reg=%02x:", req, reg); - if (reg_debug) { int i; for (i = 0; i < len; ++i) @@ -150,16 +156,14 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, printk("\n"); } - if (!bufs) - return -ENOMEM; - memcpy(bufs, buf, len); + memcpy(dev->urb_buf, buf, len); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, bufs, len, HZ); + 0x0000, reg, dev->urb_buf, len, HZ); + if (dev->wait_after_write) msleep(dev->wait_after_write); - kfree(bufs); return ret; } @@ -175,9 +179,9 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) Not sure what happens on reading GPO register. */ if (rc >= 0) { - if (reg == EM2880_R04_GPO) + if (reg == dev->reg_gpo_num) dev->reg_gpo = buf[0]; - else if (reg == EM28XX_R08_GPIO) + else if (reg == dev->reg_gpio_num) dev->reg_gpio = buf[0]; } @@ -196,9 +200,9 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 newval; /* Uses cache for gpo/gpio registers */ - if (reg == EM2880_R04_GPO) + if (reg == dev->reg_gpo_num) oldval = dev->reg_gpo; - else if (reg == EM28XX_R08_GPIO) + else if (reg == dev->reg_gpio_num) oldval = dev->reg_gpio; else oldval = em28xx_read_reg(dev, reg); @@ -270,6 +274,8 @@ static int em28xx_set_audio_source(struct em28xx *dev) break; case EM28XX_AMUX_LINE_IN: input = EM28XX_AUDIO_SRC_LINE; + video = disable; + line = enable; break; case EM28XX_AMUX_AC97_VIDEO: input = EM28XX_AUDIO_SRC_LINE; @@ -290,11 +296,11 @@ static int em28xx_set_audio_source(struct em28xx *dev) /* Sets AC97 mixer registers This is seems to be needed, even for non-ac97 configs */ - ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video); + ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video); if (ret < 0) return ret; - ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line); + ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line); return ret; } @@ -310,7 +316,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Mute */ s[1] |= 0x80; - ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); + ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, s); if (ret < 0) return ret; @@ -332,7 +338,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Unmute device */ if (!dev->mute) s[1] &= ~0x80; - ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); + ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, s); return ret; } @@ -359,6 +365,24 @@ int em28xx_colorlevels_set_default(struct em28xx *dev) int em28xx_capture_start(struct em28xx *dev, int start) { int rc; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* The Transport Stream Enable Register moved in em2874 */ + if (!start) { + rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, + 0x00, + EM2874_TS1_CAPTURE_ENABLE); + return rc; + } + + /* Enable Transport Stream */ + rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, + EM2874_TS1_CAPTURE_ENABLE, + EM2874_TS1_CAPTURE_ENABLE); + return rc; + } + + /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 3bab56b99..ec3e3b157 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -332,14 +332,25 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) struct em28xx_eeprom *em_eeprom = (void *)eedata; int i, err, size = len, block; + if (dev->chip_id == CHIP_ID_EM2874) { + /* Empia switched to a 16-bit addressable eeprom in newer + devices. While we could certainly write a routine to read + the eeprom, there is nothing of use in there that cannot be + accessed through registers, and there is the risk that we + could corrupt the eeprom (since a 16-bit read call is + interpreted as a write call by 8-bit eeproms). + */ + return 0; + } + dev->i2c_client.addr = 0xa0 >> 1; /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client, &buf, 0); if (err < 0) { - em28xx_errdev("%s: i2c_master_recv failed! err [%d]\n", - __func__, err); - return err; + em28xx_errdev("board has no eeprom\n"); + memset(eedata, 0, len); + return -ENODEV; } buf = 0; @@ -609,14 +620,16 @@ int em28xx_i2c_register(struct em28xx *dev) dev->i2c_client.adapter = &dev->i2c_adap; retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); - if (retval < 0) { + if ((retval < 0) && (retval != -ENODEV)) { em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); + return retval; } if (i2c_scan) em28xx_do_i2c_scan(dev); + return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index 8d21eaad9..29900920d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -39,12 +39,48 @@ static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); -#define dprintk(fmt, arg...) \ +#define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ } -/* ----------------------------------------------------------------------- */ +#define dprintk(fmt, arg...) \ + if (ir_debug) { \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ + } + +/********************************************************** + Polling structure used by em28xx IR's + **********************************************************/ + +struct em28xx_ir_poll_result { + unsigned int toggle_bit:1; + unsigned int read_count:7; + u8 rc_address; + u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */ +}; + +struct em28xx_IR { + struct em28xx *dev; + struct input_dev *input; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* poll external decoder */ + int polling; + struct work_struct work; + struct timer_list timer; + unsigned int last_toggle:1; + unsigned int last_readcount; + unsigned int repeat_interval; + + int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); +}; + +/********************************************************** + I2C IR based get keycodes - should be used with ir-kbd-i2c + **********************************************************/ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { @@ -52,7 +88,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) /* poll IR chip */ if (1 != i2c_master_recv(&ir->c, &b, 1)) { - dprintk("read error\n"); + i2cdprintk("read error\n"); return -EIO; } @@ -60,7 +96,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) down, while 0xff indicates that no button is hold down. 0xfe sequences are sometimes interrupted by 0xFF */ - dprintk("key %02x\n", b); + i2cdprintk("key %02x\n", b); if (b == 0xff) return 0; @@ -74,7 +110,6 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } - int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[2]; @@ -103,7 +138,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) ((buf[0]&0x10)>>3) | /* 0000 0010 */ ((buf[0]&0x20)>>5); /* 0000 0001 */ - dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", + i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", code, buf[0]); /* return key */ @@ -120,11 +155,11 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, /* poll IR chip */ if (3 != i2c_master_recv(&ir->c, buf, 3)) { - dprintk("read error\n"); + i2cdprintk("read error\n"); return -EIO; } - dprintk("key %02x\n", buf[2]&0x3f); + i2cdprintk("key %02x\n", buf[2]&0x3f); if (buf[0] != 0x00) return 0; @@ -134,6 +169,276 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, return 1; } +/********************************************************** + Poll based get keycode functions + **********************************************************/ + +/* This is for the em2860/em2880 */ +static int default_polling_getkey(struct em28xx_IR *ir, + struct em28xx_ir_poll_result *poll_result) +{ + struct em28xx *dev = ir->dev; + int rc; + u8 msg[3] = { 0, 0, 0 }; + + /* Read key toggle, brand, and key code + on registers 0x45, 0x46 and 0x47 + */ + rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR, + msg, sizeof(msg)); + if (rc < 0) + return rc; + + /* Infrared toggle (Reg 0x45[7]) */ + poll_result->toggle_bit = (msg[0] >> 7); + + /* Infrared read count (Reg 0x45[6:0] */ + poll_result->read_count = (msg[0] & 0x7f); + + /* Remote Control Address (Reg 0x46) */ + poll_result->rc_address = msg[1]; + + /* Remote Control Data (Reg 0x47) */ + poll_result->rc_data[0] = msg[2]; + + return 0; +} + +static int em2874_polling_getkey(struct em28xx_IR *ir, + struct em28xx_ir_poll_result *poll_result) +{ + struct em28xx *dev = ir->dev; + int rc; + u8 msg[5] = { 0, 0, 0, 0, 0 }; + + /* Read key toggle, brand, and key code + on registers 0x51-55 + */ + rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR, + msg, sizeof(msg)); + if (rc < 0) + return rc; + + /* Infrared toggle (Reg 0x51[7]) */ + poll_result->toggle_bit = (msg[0] >> 7); + + /* Infrared read count (Reg 0x51[6:0] */ + poll_result->read_count = (msg[0] & 0x7f); + + /* Remote Control Address (Reg 0x52) */ + poll_result->rc_address = msg[1]; + + /* Remote Control Data (Reg 0x53-55) */ + poll_result->rc_data[0] = msg[2]; + poll_result->rc_data[1] = msg[3]; + poll_result->rc_data[2] = msg[4]; + + return 0; +} + +/********************************************************** + Polling code for em28xx + **********************************************************/ + +static void em28xx_ir_handle_key(struct em28xx_IR *ir) +{ + int result; + int do_sendkey = 0; + struct em28xx_ir_poll_result poll_result; + + /* read the registers containing the IR status */ + result = ir->get_key(ir, &poll_result); + if (result < 0) { + dprintk("ir->get_key() failed %d\n", result); + return; + } + + dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n", + poll_result.toggle_bit, poll_result.read_count, + ir->last_readcount, poll_result.rc_data[0]); + + if (ir->dev->chip_id == CHIP_ID_EM2874) { + /* The em2874 clears the readcount field every time the + register is read. The em2860/2880 datasheet says that it + is supposed to clear the readcount, but it doesn't. So with + the em2874, we are looking for a non-zero read count as + opposed to a readcount that is incrementing */ + ir->last_readcount = 0; + } + + if (poll_result.read_count == 0) { + /* The button has not been pressed since the last read */ + } else if (ir->last_toggle != poll_result.toggle_bit) { + /* A button has been pressed */ + dprintk("button has been pressed\n"); + ir->last_toggle = poll_result.toggle_bit; + ir->repeat_interval = 0; + do_sendkey = 1; + } else if (poll_result.toggle_bit == ir->last_toggle && + poll_result.read_count > 0 && + poll_result.read_count != ir->last_readcount) { + /* The button is still being held down */ + dprintk("button being held down\n"); + + /* Debouncer for first keypress */ + if (ir->repeat_interval++ > 9) { + /* Start repeating after 1 second */ + do_sendkey = 1; + } + } + + if (do_sendkey) { + dprintk("sending keypress\n"); + ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0], + poll_result.rc_data[0]); + ir_input_nokey(ir->input, &ir->ir); + } + + ir->last_readcount = poll_result.read_count; + return; +} + +static void ir_timer(unsigned long data) +{ + struct em28xx_IR *ir = (struct em28xx_IR *)data; + + schedule_work(&ir->work); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void em28xx_ir_work(void *data) +#else +static void em28xx_ir_work(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + struct em28xx_IR *ir = data; +#else + struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work); +#endif + + em28xx_ir_handle_key(ir); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); +} + +void em28xx_ir_start(struct em28xx_IR *ir) +{ + setup_timer(&ir->timer, ir_timer, (unsigned long)ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&ir->work, em28xx_ir_work, ir); +#else + INIT_WORK(&ir->work, em28xx_ir_work); +#endif + schedule_work(&ir->work); +} + +static void em28xx_ir_stop(struct em28xx_IR *ir) +{ + del_timer_sync(&ir->timer); + flush_scheduled_work(); +} + +int em28xx_ir_init(struct em28xx *dev) +{ + struct em28xx_IR *ir; + struct input_dev *input_dev; + u8 ir_config; + int err = -ENOMEM; + + if (dev->ir_codes == NULL) { + /* No remote control support */ + return 0; + } + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) + goto err_out_free; + + ir->input = input_dev; + + /* Setup the proper handler based on the chip */ + switch (dev->chip_id) { + case CHIP_ID_EM2860: + case CHIP_ID_EM2883: + ir->get_key = default_polling_getkey; + break; + case CHIP_ID_EM2874: + ir->get_key = em2874_polling_getkey; + /* For now we only support RC5, so enable it */ + ir_config = EM2874_IR_RC5; + em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); + break; + default: + printk("Unrecognized em28xx chip id: IR not supported\n"); + goto err_out_free; + } + + /* This is how often we ask the chip for IR information */ + ir->polling = 100; /* ms */ + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", + dev->name); + + usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); + strlcat(ir->phys, "/input0", sizeof(ir->phys)); + + ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_USB; + input_dev->id.version = 1; + input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + input_dev->dev.parent = &dev->udev->dev; +#else + input_dev->cdev.dev = &dev->udev->dev; +#endif + /* record handles to ourself */ + ir->dev = dev; + dev->ir = ir; + + em28xx_ir_start(ir); + + /* all done */ + err = input_register_device(ir->input); + if (err) + goto err_out_stop; + + return 0; + err_out_stop: + em28xx_ir_stop(ir); + dev->ir = NULL; + err_out_free: + input_free_device(input_dev); + kfree(ir); + return err; +} + +int em28xx_ir_fini(struct em28xx *dev) +{ + struct em28xx_IR *ir = dev->ir; + + /* skip detach on non attached boards */ + if (!ir) + return 0; + + em28xx_ir_stop(ir); + input_unregister_device(ir->input); + kfree(ir); + + /* done */ + dev->ir = NULL; + return 0; +} + +/********************************************************** + Handle Webcam snapshot button + **********************************************************/ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void em28xx_query_sbutton(void *data) #else @@ -232,9 +537,3 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev) } return; } - -/* ---------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index fac1ab23f..491d66abe 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -71,10 +71,32 @@ #define EM28XX_R42_AC97ADDR 0x42 #define EM28XX_R43_AC97BUSY 0x43 -/* em202 registers */ -#define EM28XX_R02_MASTER_AC97 0x02 -#define EM28XX_R10_LINE_IN_AC97 0x10 -#define EM28XX_R14_VIDEO_AC97 0x14 +#define EM28XX_R45_IR 0x45 + /* 0x45 bit 7 - parity bit + bits 6-0 - count + 0x46 IR brand + 0x47 IR data + */ + +/* em2874 registers */ +#define EM2874_R50_IR_CONFIG 0x50 +#define EM2874_R51_IR 0x51 +#define EM2874_R5F_TS_ENABLE 0x5f +#define EM2874_R80_GPIO 0x80 + +/* em2874 IR config register (0x50) */ +#define EM2874_IR_NEC 0x00 +#define EM2874_IR_RC5 0x04 +#define EM2874_IR_RC5_MODE_0 0x08 +#define EM2874_IR_RC5_MODE_6A 0x0b + +/* em2874 Transport Stream Enable Register (0x5f) */ +#define EM2874_TS1_CAPTURE_ENABLE (1 << 0) +#define EM2874_TS1_FILTER_ENABLE (1 << 1) +#define EM2874_TS1_NULL_DISCARD (1 << 2) +#define EM2874_TS2_CAPTURE_ENABLE (1 << 4) +#define EM2874_TS2_FILTER_ENABLE (1 << 5) +#define EM2874_TS2_NULL_DISCARD (1 << 6) /* register settings */ #define EM2800_AUDIO_SRC_TUNER 0x0d @@ -84,6 +106,62 @@ /* FIXME: Need to be populated with the other chip ID's */ enum em28xx_chip_id { + CHIP_ID_EM2820 = 18, + CHIP_ID_EM2840 = 20, + CHIP_ID_EM2750 = 33, CHIP_ID_EM2860 = 34, CHIP_ID_EM2883 = 36, + CHIP_ID_EM2874 = 65, }; + +/* + * Registers used by em202 and other AC97 chips + */ + +/* Standard AC97 registers */ +#define AC97_RESET 0x00 +#define AC97_MASTER_VOL 0x02 +#define AC97_LINE_LEVEL_VOL 0x04 +#define AC97_MASTER_MONO_VOL 0x06 + +#define AC97_PC_BEEP_VOL 0x0a +#define AC97_PHONE_VOL 0x0c +#define AC97_MIC_VOL 0x0e +#define AC97_LINEIN_VOL 0x10 +#define AC97_CD_VOL 0x12 +#define AC97_VIDEO_VOL 0x14 +#define AC97_AUX_VOL 0x16 +#define AC97_PCM_OUT_VOL 0x18 +#define AC97_RECORD_SELECT 0x1a +#define AC97_RECORD_GAIN 0x1c +#define AC97_GENERAL_PURPOSE 0x20 +#define AC97_3D_CTRL 0x22 +#define AC97_AUD_INT_AND_PAG 0x24 +#define AC97_POWER_DOWN_CTRL 0x26 +#define AC97_EXT_AUD_ID 0x28 +#define AC97_EXT_AUD_CTRL 0x2a + +/* Supported rate varies for each AC97 device + if write an unsupported value, it will return the closest one + */ +#define AC97_PCM_OUT_FRONT_SRATE 0x2c +#define AC97_PCM_OUT_SURR_SRATE 0x2e +#define AC97_PCM_OUT_LFE_SRATE 0x30 +#define AC97_PCM_IN_SRATE 0x32 +#define AC97_LFE_MASTER_VOL 0x36 +#define AC97_SURR_MASTER_VOL 0x38 +#define AC97_SPDIF_OUT_CTRL 0x3a + +#define AC97_VENDOR_ID1 0x7c +#define AC97_VENDOR_ID2 0x7e + +/* EMP202 vendor registers */ +#define EM202_EXT_MODEM_CTRL 0x3e +#define EM202_GPIO_CONF 0x4c +#define EM202_GPIO_POLARITY 0x4e +#define EM202_GPIO_STICKY 0x50 +#define EM202_GPIO_MASK 0x52 +#define EM202_GPIO_STATUS 0x54 +#define EM202_SPDIF_OUT_SEL 0x6a +#define EM202_ANTIPOP 0x72 +#define EM202_EAPD_GPIO_ACCESS 0x74 diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 2d0cd4abc..625c9dea1 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1275,7 +1275,7 @@ static int vidioc_querycap(struct file *file, void *priv, 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)); + strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info)); cap->version = EM28XX_VERSION_CODE; @@ -1465,7 +1465,7 @@ static int radio_querycap(struct file *file, void *priv, 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)); + strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info)); cap->version = EM28XX_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; @@ -1656,11 +1656,13 @@ static void em28xx_release_resources(struct em28xx *dev) /*FIXME: I2C IR should be disconnected */ - em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", - dev->vdev->num, dev->vbi_dev->num); list_del(&dev->devlist); if (dev->sbutton_input_dev) em28xx_deregister_snapshot_button(dev); + + if (dev->ir) + em28xx_ir_fini(dev); + if (dev->radio_dev) { if (-1 != dev->radio_dev->minor) video_unregister_device(dev->radio_dev); @@ -1669,6 +1671,8 @@ static void em28xx_release_resources(struct em28xx *dev) dev->radio_dev = NULL; } if (dev->vbi_dev) { + em28xx_info("V4L2 device /dev/vbi%d deregistered\n", + dev->vbi_dev->num); if (-1 != dev->vbi_dev->minor) video_unregister_device(dev->vbi_dev); else @@ -1676,6 +1680,8 @@ static void em28xx_release_resources(struct em28xx *dev) dev->vbi_dev = NULL; } if (dev->vdev) { + em28xx_info("V4L2 device /dev/video%d deregistered\n", + dev->vdev->num); if (-1 != dev->vdev->minor) video_unregister_device(dev->vdev); else @@ -1982,6 +1988,19 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } +int em28xx_supports_audio_extension(struct em28xx *dev) +{ + /* The chip dictates whether we support the Empia analog audio + extension */ + switch (dev->chip_id) { + case CHIP_ID_EM2874: + /* Either a digital-only device or provides AC97 audio */ + return 0; + case CHIP_ID_EM2883: + default: + return 1; + } +} /* * em28xx_init_dev() @@ -2015,8 +2034,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, errCode = em28xx_config(dev); if (errCode) { em28xx_errdev("error configuring device\n"); - em28xx_devused &= ~(1<<dev->devno); - kfree(dev); return -ENOMEM; } @@ -2104,7 +2121,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, goto fail_unreg; } em28xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->minor & 0x1f); + dev->radio_dev->num); } /* init video dma queues */ @@ -2153,7 +2170,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, fail_unreg: em28xx_release_resources(dev); mutex_unlock(&dev->lock); - kfree(dev); return retval; } @@ -2171,7 +2187,7 @@ static void request_module_async(struct work_struct *work) if (dev->has_audio_class) request_module("snd-usb-audio"); - else + else if (dev->has_alsa_audio) request_module("em28xx-alsa"); if (dev->has_dvb) @@ -2204,7 +2220,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; - int i, nr, ifnum; + int i, nr, ifnum, isoc_pipe; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -2231,19 +2247,29 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting[0].desc.bInterfaceClass); - endpoint = &interface->cur_altsetting->endpoint[1].desc; + endpoint = &interface->cur_altsetting->endpoint[0].desc; /* check if the device has the iso in endpoint at the correct place */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_ISOC) { - em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC && + (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) + { + /* It's a newer em2874/em2875 device */ + isoc_pipe = 0; + } else { + isoc_pipe = 1; + endpoint = &interface->cur_altsetting->endpoint[1].desc; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_ISOC) { + em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); + em28xx_devused &= ~(1<<nr); + return -ENODEV; + } + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { + em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); + em28xx_devused &= ~(1<<nr); + return -ENODEV; + } } if (nr >= EM28XX_MAXBOARDS) { @@ -2275,9 +2301,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, } } - 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]; @@ -2294,7 +2317,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. + u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. wMaxPacketSize); dev->alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); @@ -2307,11 +2330,26 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate device struct */ retval = em28xx_init_dev(&dev, udev, nr); - if (retval) + if (retval) { + em28xx_devused &= ~(1<<dev->devno); + kfree(dev); + return retval; + } em28xx_info("Found %s\n", em28xx_boards[dev->model].name); + if (dev->has_audio_class == 0) { + /* We don't have a USB audio class, let's see if we support + ALSA Audio */ + dev->has_alsa_audio = em28xx_supports_audio_extension(dev); + if (dev->has_alsa_audio) + printk(KERN_INFO DRIVER_NAME " supports alsa audio\n"); + } else { + printk(KERN_INFO DRIVER_NAME " has usb audio class\n"); + } + + /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index d73b8c983..2e108be19 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -98,11 +98,15 @@ #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 #define EM2883_BOARD_KWORLD_HYBRID_A316 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 +#define EM2874_BOARD_PINNACLE_PCTV_80E 59 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 #define EM28XX_DEF_BUF 8 +/*Limits the max URB message size */ +#define URB_MAX_CTRL_SIZE 80 + /* Params for validated field */ #define EM28XX_BOARD_NOT_VALIDATED 1 #define EM28XX_BOARD_VALIDATED 0 @@ -269,6 +273,7 @@ struct em28xx_input { #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) enum em28xx_decoder { + EM28XX_NODECODER, EM28XX_TVP5150, EM28XX_SAA7113, EM28XX_SAA7114 @@ -284,6 +289,7 @@ struct em28xx_board { char *name; int vchannels; int tuner_type; + int tuner_addr; /* i2c flags */ unsigned int tda9887_conf; @@ -301,6 +307,7 @@ struct em28xx_board { struct em28xx_input input[MAX_EM28XX_INPUT]; struct em28xx_input radio; + IR_KEYTAB_TYPE *ir_codes; }; struct em28xx_eeprom { @@ -375,17 +382,21 @@ 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 */ + enum em28xx_chip_id chip_id; unsigned int is_em2800:1; unsigned int has_msp34xx:1; unsigned int has_tda9887:1; unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; + unsigned int has_alsa_audio:1; unsigned int has_12mhz_i2s:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; unsigned int valid:1; /* report for validated boards */ + struct em28xx_IR *ir; + /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; @@ -460,6 +471,8 @@ struct em28xx { unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */ + char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */ + /* helper funcs that call usb_control_msg */ int (*em28xx_write_regs) (struct em28xx *dev, u16 reg, char *buf, int len); @@ -472,9 +485,15 @@ struct em28xx { enum em28xx_mode mode; + /* register numbers for GPO/GPIO registers */ + u16 reg_gpo_num, reg_gpio_num; + /* Caches GPO and GPIO registers */ unsigned char reg_gpo, reg_gpio; + /* Infrared remote control support */ + IR_KEYTAB_TYPE *ir_codes; + /* Snapshot button */ char snapshot_button_path[30]; /* path of the input dev */ struct input_dev *sbutton_input_dev; @@ -544,7 +563,6 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); int em28xx_tuner_callback(void *ptr, int component, int command, int arg); /* 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, @@ -552,6 +570,9 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, void em28xx_register_snapshot_button(struct em28xx *dev); void em28xx_deregister_snapshot_button(struct em28xx *dev); +int em28xx_ir_init(struct em28xx *dev); +int em28xx_ir_fini(struct em28xx *dev); + /* printk macros */ #define em28xx_err(fmt, arg...) do {\ diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c index f58aee5aa..52e0f2710 100644 --- a/linux/drivers/media/video/et61x251/et61x251_core.c +++ b/linux/drivers/media/video/et61x251/et61x251_core.c @@ -592,7 +592,7 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam) cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " "use it, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -1199,7 +1199,7 @@ static void et61x251_release_resources(struct kref *kref) cam = container_of(kref, struct et61x251_device, kref); - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); @@ -1241,7 +1241,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) if (cam->users) { DBG(2, "Device /dev/video%d is already in use", - cam->v4ldev->minor); + cam->v4ldev->num); DBG(3, "Simultaneous opens are not supported"); if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { @@ -1284,7 +1284,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) cam->frame_count = 0; et61x251_empty_framequeues(cam); - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); + DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); out: mutex_unlock(&cam->open_mutex); @@ -1308,7 +1308,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); + DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); kref_put(&cam->kref, et61x251_release_resources); @@ -1585,7 +1585,7 @@ et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, + strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), sizeof(cap.bus_info)); if (copy_to_user(arg, &cap, sizeof(cap))) @@ -1849,7 +1849,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -1862,7 +1862,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -ENOMEM; } @@ -2072,7 +2072,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -2084,7 +2084,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -ENOMEM; } @@ -2132,7 +2132,7 @@ et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->minor); + "/dev/video%d again.", cam->v4ldev->num); return -EIO; } @@ -2609,7 +2609,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; @@ -2662,7 +2662,7 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " "memory deallocation are deferred.", - cam->v4ldev->minor); + cam->v4ldev->num); cam->state |= DEV_MISCONFIGURED; et61x251_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig index 4d0817471..6b557c057 100644 --- a/linux/drivers/media/video/gspca/Kconfig +++ b/linux/drivers/media/video/gspca/Kconfig @@ -3,16 +3,16 @@ menuconfig USB_GSPCA depends on VIDEO_V4L2 default m ---help--- - Say Y here if you want to enable selecting webcams based - on the GSPCA framework. + Say Y here if you want to enable selecting webcams based + on the GSPCA framework. - See <file:Documentation/video4linux/gspca.txt> for more info. + See <file:Documentation/video4linux/gspca.txt> for more info. - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. - To compile this driver as modules, choose M here: the - modules will be called gspca_main. + To compile this driver as modules, choose M here: the + modules will be called gspca_main. if USB_GSPCA && VIDEO_V4L2 @@ -23,190 +23,190 @@ config USB_GSPCA_CONEX tristate "Conexant Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the Conexant chip. + Say Y here if you want support for cameras based on the Conexant chip. - To compile this driver as a module, choose M here: the - module will be called gspca_conex. + To compile this driver as a module, choose M here: the + module will be called gspca_conex. config USB_GSPCA_ETOMS tristate "Etoms USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the Etoms chip. + Say Y here if you want support for cameras based on the Etoms chip. - To compile this driver as a module, choose M here: the - module will be called gspca_etoms. + To compile this driver as a module, choose M here: the + module will be called gspca_etoms. config USB_GSPCA_FINEPIX tristate "Fujifilm FinePix USB V4L2 driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the FinePix chip. + Say Y here if you want support for cameras based on the FinePix chip. - To compile this driver as a module, choose M here: the - module will be called gspca_finepix. + To compile this driver as a module, choose M here: the + module will be called gspca_finepix. config USB_GSPCA_MARS tristate "Mars USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the Mars chip. + Say Y here if you want support for cameras based on the Mars chip. - To compile this driver as a module, choose M here: the - module will be called gspca_mars. + To compile this driver as a module, choose M here: the + module will be called gspca_mars. config USB_GSPCA_OV519 tristate "OV519 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the OV519 chip. + Say Y here if you want support for cameras based on the OV519 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_ov519. + To compile this driver as a module, choose M here: the + module will be called gspca_ov519. config USB_GSPCA_PAC207 tristate "Pixart PAC207 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the PAC207 chip. + Say Y here if you want support for cameras based on the PAC207 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_pac207. + To compile this driver as a module, choose M here: the + module will be called gspca_pac207. config USB_GSPCA_PAC7311 tristate "Pixart PAC7311 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the PAC7311 chip. + Say Y here if you want support for cameras based on the PAC7311 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_pac7311. + To compile this driver as a module, choose M here: the + module will be called gspca_pac7311. config USB_GSPCA_SONIXB tristate "SN9C102 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SONIXB chip. + Say Y here if you want support for cameras based on the SONIXB chip. - To compile this driver as a module, choose M here: the - module will be called gspca_sonixb. + To compile this driver as a module, choose M here: the + module will be called gspca_sonixb. config USB_GSPCA_SONIXJ tristate "SONIX JPEG USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SONIXJ chip. + Say Y here if you want support for cameras based on the SONIXJ chip. - To compile this driver as a module, choose M here: the - module will be called gspca_sonixj + To compile this driver as a module, choose M here: the + module will be called gspca_sonixj config USB_GSPCA_SPCA500 tristate "SPCA500 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SPCA500 chip. + Say Y here if you want support for cameras based on the SPCA500 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_spca500. + To compile this driver as a module, choose M here: the + module will be called gspca_spca500. config USB_GSPCA_SPCA501 tristate "SPCA501 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SPCA501 chip. + Say Y here if you want support for cameras based on the SPCA501 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_spca501. + To compile this driver as a module, choose M here: the + module will be called gspca_spca501. config USB_GSPCA_SPCA505 tristate "SPCA505 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SPCA505 chip. + Say Y here if you want support for cameras based on the SPCA505 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_spca505. + To compile this driver as a module, choose M here: the + module will be called gspca_spca505. config USB_GSPCA_SPCA506 tristate "SPCA506 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SPCA506 chip. + Say Y here if you want support for cameras based on the SPCA506 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_spca506. + To compile this driver as a module, choose M here: the + module will be called gspca_spca506. config USB_GSPCA_SPCA508 tristate "SPCA508 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SPCA508 chip. + Say Y here if you want support for cameras based on the SPCA508 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_spca508. + To compile this driver as a module, choose M here: the + module will be called gspca_spca508. config USB_GSPCA_SPCA561 tristate "SPCA561 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the SPCA561 chip. + Say Y here if you want support for cameras based on the SPCA561 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_spca561. + To compile this driver as a module, choose M here: the + module will be called gspca_spca561. config USB_GSPCA_STK014 tristate "Syntek DV4000 (STK014) USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the STK014 chip. + Say Y here if you want support for cameras based on the STK014 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_stk014. + To compile this driver as a module, choose M here: the + module will be called gspca_stk014. config USB_GSPCA_SUNPLUS tristate "SUNPLUS USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the Sunplus - SPCA504(abc) SPCA533 SPCA536 chips. + Say Y here if you want support for cameras based on the Sunplus + SPCA504(abc) SPCA533 SPCA536 chips. - To compile this driver as a module, choose M here: the - module will be called gspca_spca5xx. + To compile this driver as a module, choose M here: the + module will be called gspca_spca5xx. config USB_GSPCA_T613 tristate "T613 (JPEG Compliance) USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the T613 chip. + Say Y here if you want support for cameras based on the T613 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_t613. + To compile this driver as a module, choose M here: the + module will be called gspca_t613. config USB_GSPCA_TV8532 tristate "TV8532 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the TV8531 chip. + Say Y here if you want support for cameras based on the TV8531 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_tv8532. + To compile this driver as a module, choose M here: the + module will be called gspca_tv8532. config USB_GSPCA_VC032X tristate "VC032X USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the VC032X chip. + Say Y here if you want support for cameras based on the VC032X chip. - To compile this driver as a module, choose M here: the - module will be called gspca_vc032x. + To compile this driver as a module, choose M here: the + module will be called gspca_vc032x. config USB_GSPCA_ZC3XX - tristate "VC3xx USB Camera Driver" + tristate "ZC3XX USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the ZC3XX chip. + Say Y here if you want support for cameras based on the ZC3XX chip. - To compile this driver as a module, choose M here: the - module will be called gspca_zc3xx. + To compile this driver as a module, choose M here: the + module will be called gspca_zc3xx. endif diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c index a9d51ba7c..de28354ea 100644 --- a/linux/drivers/media/video/gspca/conex.c +++ b/linux/drivers/media/video/gspca/conex.c @@ -846,10 +846,13 @@ static int sd_start(struct gspca_dev *gspca_dev) return 0; } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { int retry = 50; + if (!gspca_dev->present) + return; reg_w_val(gspca_dev, 0x0000, 0x00); reg_r(gspca_dev, 0x0002, 1); reg_w_val(gspca_dev, 0x0053, 0x00); diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c index 65d3cbfe6..03cb94466 100644 --- a/linux/drivers/media/video/gspca/finepix.c +++ b/linux/drivers/media/video/gspca/finepix.c @@ -276,6 +276,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* Stop the state machine */ if (dev->state != FPIX_NOP) wait_for_completion(&dev->can_close); +} + +/* called on streamoff with alt 0 and disconnect */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct usb_fpix *dev = (struct usb_fpix *) gspca_dev; usb_free_urb(dev->control_urb); dev->control_urb = NULL; @@ -308,9 +314,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int ret; int size_ret; - /* Reset bulk in endpoint */ - usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr); - /* Init the device */ memset(gspca_dev->usb_buf, 0, 12); gspca_dev->usb_buf[0] = 0xc6; @@ -385,6 +388,7 @@ static int sd_start(struct gspca_dev *gspca_dev) error: /* Free the ressources */ sd_stopN(gspca_dev); + sd_stop0(gspca_dev); return ret; } @@ -425,6 +429,7 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, + .stop0 = sd_stop0, }; /* -- device connect -- */ diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index 4e0e7a32a..35f504440 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -49,7 +49,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 3, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 4, 0) static int video_nr = -1; @@ -154,8 +154,11 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ len = urb->iso_frame_desc[i].actual_length; - if (len == 0) + if (len == 0) { + if (gspca_dev->empty_packet == 0) + gspca_dev->empty_packet = 1; continue; + } st = urb->iso_frame_desc[i].status; if (st) { PDEBUG(D_ERR, @@ -174,7 +177,6 @@ static void fill_frame(struct gspca_dev *gspca_dev, } /* resubmit the URB */ - urb->status = 0; st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); @@ -210,11 +212,18 @@ static void bulk_irq(struct urb *urb { struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; struct gspca_frame *frame; + int st; PDEBUG(D_PACK, "bulk irq"); if (!gspca_dev->streaming) return; - if (urb->status != 0 && urb->status != -ECONNRESET) { + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + urb->status = 0; + break; + default: #ifdef CONFIG_PM if (!gspca_dev->frozen) #endif @@ -233,6 +242,13 @@ static void bulk_irq(struct urb *urb urb->transfer_buffer, urb->actual_length); } + + /* resubmit the URB */ + if (gspca_dev->cam.bulk_nurbs != 0) { + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); + } } /* @@ -530,11 +546,14 @@ static int create_urbs(struct gspca_dev *gspca_dev, nurbs = DEF_NURBS; } else { /* bulk */ npkt = 0; - bsize = gspca_dev->cam. bulk_size; + bsize = gspca_dev->cam.bulk_size; if (bsize == 0) bsize = psize; PDEBUG(D_STREAM, "bulk bsize:%d", bsize); - nurbs = 1; + if (gspca_dev->cam.bulk_nurbs != 0) + nurbs = gspca_dev->cam.bulk_nurbs; + else + nurbs = 1; } gspca_dev->nurbs = nurbs; @@ -607,6 +626,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) if (ret < 0) goto out; + /* clear the bulk endpoint */ + if (gspca_dev->alt == 0) /* if bulk transfer */ + usb_clear_halt(gspca_dev->dev, + usb_rcvintpipe(gspca_dev->dev, + gspca_dev->cam.epaddr)); + /* start the cam */ ret = gspca_dev->sd_desc->start(gspca_dev); if (ret < 0) { @@ -616,8 +641,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->streaming = 1; atomic_set(&gspca_dev->nevent, 0); - /* bulk transfers are started by the subdriver */ - if (gspca_dev->alt == 0) + /* some bulk transfers are started by the subdriver */ + if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0) break; /* submit the URBs */ @@ -656,15 +681,14 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev) { gspca_dev->streaming = 0; atomic_set(&gspca_dev->nevent, 0); - if (gspca_dev->present) { - if (gspca_dev->sd_desc->stopN) - gspca_dev->sd_desc->stopN(gspca_dev); - destroy_urbs(gspca_dev); - gspca_set_alt0(gspca_dev); - if (gspca_dev->sd_desc->stop0) - gspca_dev->sd_desc->stop0(gspca_dev); - PDEBUG(D_STREAM, "stream off OK"); - } + if (gspca_dev->present + && gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_set_alt0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); + PDEBUG(D_STREAM, "stream off OK"); } static void gspca_set_default_mode(struct gspca_dev *gspca_dev) @@ -738,7 +762,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (fmtdesc->index == index) break; /* new format */ index++; - if (index >= sizeof fmt_tb / sizeof fmt_tb[0]) + if (index >= ARRAY_SIZE(fmt_tb)) return -EINVAL; } } @@ -873,7 +897,7 @@ static int dev_open(struct inode *inode, struct file *file) int ret; PDEBUG(D_STREAM, "%s open", current->comm); - gspca_dev = (struct gspca_dev *) video_devdata(file); + gspca_dev = video_drvdata(file); if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; if (!gspca_dev->present) { @@ -885,6 +909,13 @@ static int dev_open(struct inode *inode, struct file *file) ret = -EBUSY; goto out; } + + /* protect the subdriver against rmmod */ + if (!try_module_get(gspca_dev->module)) { + ret = -ENODEV; + goto out; + } + gspca_dev->users++; /* one more user */ @@ -894,10 +925,10 @@ static int dev_open(struct inode *inode, struct file *file) #ifdef GSPCA_DEBUG /* activate the v4l2 debug */ if (gspca_debug & D_V4L2) - gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL + gspca_dev->vdev->debug |= V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; else - gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL + gspca_dev->vdev->debug &= ~(V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG); #endif ret = 0; @@ -931,6 +962,7 @@ static int dev_close(struct inode *inode, struct file *file) gspca_dev->memory = GSPCA_MEMORY_NO; } file->private_data = NULL; + module_put(gspca_dev->module); mutex_unlock(&gspca_dev->queue_lock); PDEBUG(D_STREAM, "close done"); @@ -1758,11 +1790,6 @@ out: return ret; } -static void dev_release(struct video_device *vfd) -{ - /* nothing */ -} - static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = dev_open, @@ -1810,7 +1837,7 @@ static struct video_device gspca_template = { .name = "gspca main driver", .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, - .release = dev_release, /* mandatory */ + .release = video_device_release, .minor = -1, }; @@ -1860,6 +1887,7 @@ int gspca_dev_probe(struct usb_interface *intf, gspca_dev->nbalt = intf->num_altsetting; gspca_dev->sd_desc = sd_desc; gspca_dev->nbufread = 2; + gspca_dev->empty_packet = -1; /* don't check the empty packets */ /* configure the subdriver and initialize the USB device */ ret = gspca_dev->sd_desc->config(gspca_dev, id); @@ -1879,17 +1907,18 @@ int gspca_dev_probe(struct usb_interface *intf, init_waitqueue_head(&gspca_dev->wq); /* init video stuff */ - memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); - gspca_dev->vdev.parent = &dev->dev; - memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops); - gspca_dev->vdev.fops = &gspca_dev->fops; - gspca_dev->fops.owner = module; /* module protection */ + gspca_dev->vdev = video_device_alloc(); + memcpy(gspca_dev->vdev, &gspca_template, sizeof gspca_template); + gspca_dev->vdev->parent = &dev->dev; + gspca_dev->module = module; gspca_dev->present = 1; - ret = video_register_device(&gspca_dev->vdev, + video_set_drvdata(gspca_dev->vdev, gspca_dev); + ret = video_register_device(gspca_dev->vdev, VFL_TYPE_GRABBER, video_nr); if (ret < 0) { err("video_register_device err %d", ret); + video_device_release(gspca_dev->vdev); goto out; } @@ -1897,7 +1926,8 @@ int gspca_dev_probe(struct usb_interface *intf, PDEBUG(D_PROBE, "probe ok"); return 0; out: - kref_put(&gspca_dev->kref, gspca_delete); + kfree(gspca_dev->usb_buf); + kfree(gspca_dev); return ret; } EXPORT_SYMBOL(gspca_dev_probe); @@ -1915,7 +1945,7 @@ void gspca_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); /* We don't want people trying to open up the device */ - video_unregister_device(&gspca_dev->vdev); + video_unregister_device(gspca_dev->vdev); gspca_dev->present = 0; gspca_dev->streaming = 0; @@ -1998,7 +2028,7 @@ int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, desired lumination fast (with the risc of a slight overshoot) */ steps = abs(desired_avg_lum - avg_lum) / deadzone; - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n", + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", avg_lum, desired_avg_lum, steps); for (i = 0; i < steps; i++) { diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 1d9dc90b4..a557738e8 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -58,6 +58,10 @@ struct cam { int bulk_size; /* buffer size when image transfer by bulk */ struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; + __u8 bulk_nurbs; /* number of URBs in bulk mode + * - cannot be > MAX_NURBS + * - when 0 and bulk_size != 0 means + * 1 URB and submit done by subdriver */ __u8 epaddr; }; @@ -97,7 +101,7 @@ struct sd_desc { cam_pkt_op pkt_scan; /* optional operations */ cam_v_op stopN; /* called on stream off - main alt */ - cam_v_op stop0; /* called on stream off - alt 0 */ + cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ cam_v_op dq_callback; /* called when a frame has been dequeued */ cam_jpg_op get_jcomp; cam_jpg_op set_jcomp; @@ -120,8 +124,8 @@ struct gspca_frame { }; struct gspca_dev { - struct video_device vdev; /* !! must be the first item */ - struct file_operations fops; + struct video_device *vdev; + struct module *module; /* subdriver handling the device */ struct usb_device *dev; struct kref kref; struct file *capt_file; /* file doing video capture */ @@ -142,22 +146,21 @@ struct gspca_dev { char fr_q; /* next frame to queue */ char fr_o; /* next frame to dequeue */ signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */ - char last_packet_type; + __u8 last_packet_type; + __s8 empty_packet; /* if (-1) don't check empty packets */ + __u8 streaming; - __u8 iface; /* USB interface number */ - __u8 alt; /* USB alternate setting */ __u8 curr_mode; /* current camera mode */ __u32 pixfmt; /* current mode parameters */ __u16 width; __u16 height; + __u32 sequence; /* frame sequence number */ atomic_t nevent; /* number of frames done */ wait_queue_head_t wq; /* wait queue */ struct mutex usb_lock; /* usb exchange protection */ struct mutex read_lock; /* read protection */ struct mutex queue_lock; /* ISOC queue protection */ - __u32 sequence; /* frame sequence number */ - char streaming; #ifdef CONFIG_PM char frozen; /* suspend - resume */ #endif @@ -166,6 +169,8 @@ struct gspca_dev { char nbufread; /* number of buffers for read() */ char nurbs; /* number of allocated URBs */ char memory; /* memory type (V4L2_MEMORY_xxx) */ + __u8 iface; /* USB interface number */ + __u8 alt; /* USB alternate setting */ __u8 nbalt; /* number of USB alternate settings */ }; diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c index 277ca34a8..492cdd3b5 100644 --- a/linux/drivers/media/video/gspca/mars.c +++ b/linux/drivers/media/video/gspca/mars.c @@ -123,7 +123,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->epaddr = 0x01; cam->cam_mode = vga_mode; - cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + cam->nmodes = ARRAY_SIZE(vga_mode); sd->qindex = 1; /* set the quantization table */ return 0; } diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c index 895bcf082..b18d98191 100644 --- a/linux/drivers/media/video/gspca/ov519.c +++ b/linux/drivers/media/video/gspca/ov519.c @@ -40,22 +40,18 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ /* Determined by sensor type */ - char sif; + __u8 sif; - unsigned char primary_i2c_slave; /* I2C write id of sensor */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; + __u8 brightness; + __u8 contrast; + __u8 colors; __u8 hflip; __u8 vflip; - char compress; /* Should the next frame be compressed? */ - char compress_inited; /* Are compression params uploaded? */ - char stopped; /* Streaming is temporarily paused */ + __u8 stopped; /* Streaming is temporarily paused */ - char frame_rate; /* current Framerate (OV519 only) */ - char clockdiv; /* clockdiv override for OV519 only */ + __u8 frame_rate; /* current Framerate (OV519 only) */ + __u8 clockdiv; /* clockdiv override for OV519 only */ char sensor; /* Type of image sensor chip (SEN_*) */ #define SEN_UNKNOWN 0 @@ -67,7 +63,6 @@ struct sd { #define SEN_OV7670 6 #define SEN_OV76BE 7 #define SEN_OV8610 8 - }; /* V4L2 controls supported by the driver */ @@ -184,15 +179,15 @@ static struct v4l2_pix_format sif_mode[] = { }; /* OV519 Camera interface register numbers */ -#define OV519_CAM_H_SIZE 0x10 -#define OV519_CAM_V_SIZE 0x11 -#define OV519_CAM_X_OFFSETL 0x12 -#define OV519_CAM_X_OFFSETH 0x13 -#define OV519_CAM_Y_OFFSETL 0x14 -#define OV519_CAM_Y_OFFSETH 0x15 -#define OV519_CAM_DIVIDER 0x16 -#define OV519_CAM_DFR 0x20 -#define OV519_CAM_FORMAT 0x25 +#define OV519_R10_H_SIZE 0x10 +#define OV519_R11_V_SIZE 0x11 +#define OV519_R12_X_OFFSETL 0x12 +#define OV519_R13_X_OFFSETH 0x13 +#define OV519_R14_Y_OFFSETL 0x14 +#define OV519_R15_Y_OFFSETH 0x15 +#define OV519_R16_DIVIDER 0x16 +#define OV519_R20_DFR 0x20 +#define OV519_R25_FORMAT 0x25 /* OV519 System Controller register numbers */ #define OV519_SYS_RESET1 0x51 @@ -562,8 +557,8 @@ static const struct ov_i2c_regvals norm_7670[] = { { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a }, - { OV7670_REG_COM3, 0 }, - { OV7670_REG_COM14, 0 }, + { OV7670_REG_COM3, 0x00 }, + { OV7670_REG_COM14, 0x00 }, /* Mystery scaling numbers */ { 0x70, 0x3a }, { 0x71, 0x35 }, @@ -595,8 +590,8 @@ static const struct ov_i2c_regvals norm_7670[] = { { OV7670_REG_COM8, OV7670_COM8_FASTAEC | OV7670_COM8_AECSTEP | OV7670_COM8_BFILT }, - { OV7670_REG_GAIN, 0 }, - { OV7670_REG_AECH, 0 }, + { OV7670_REG_GAIN, 0x00 }, + { OV7670_REG_AECH, 0x00 }, { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ { OV7670_REG_BD50MAX, 0x05 }, @@ -634,16 +629,16 @@ static const struct ov_i2c_regvals norm_7670[] = { { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 }, { 0x4e, 0x20 }, - { OV7670_REG_GFIX, 0 }, + { OV7670_REG_GFIX, 0x00 }, { 0x6b, 0x4a }, { 0x74, 0x10 }, { 0x8d, 0x4f }, - { 0x8e, 0 }, - { 0x8f, 0 }, - { 0x90, 0 }, - { 0x91, 0 }, - { 0x96, 0 }, - { 0x9a, 0 }, + { 0x8e, 0x00 }, + { 0x8f, 0x00 }, + { 0x90, 0x00 }, + { 0x91, 0x00 }, + { 0x96, 0x00 }, + { 0x9a, 0x00 }, { 0xb0, 0x84 }, { 0xb1, 0x0c }, { 0xb2, 0x0e }, @@ -681,17 +676,17 @@ static const struct ov_i2c_regvals norm_7670[] = { /* Matrix coefficients */ { 0x4f, 0x80 }, { 0x50, 0x80 }, - { 0x51, 0 }, + { 0x51, 0x00 }, { 0x52, 0x22 }, { 0x53, 0x5e }, { 0x54, 0x80 }, { 0x58, 0x9e }, { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, - { OV7670_REG_EDGE, 0 }, + { OV7670_REG_EDGE, 0x00 }, { 0x75, 0x05 }, { 0x76, 0xe1 }, - { 0x4c, 0 }, + { 0x4c, 0x00 }, { 0x77, 0x01 }, { OV7670_REG_COM13, OV7670_COM13_GAMMA | OV7670_COM13_UVSAT @@ -704,7 +699,7 @@ static const struct ov_i2c_regvals norm_7670[] = { { 0x34, 0x11 }, { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, { 0xa4, 0x88 }, - { 0x96, 0 }, + { 0x96, 0x00 }, { 0x97, 0x30 }, { 0x98, 0x20 }, { 0x99, 0x30 }, @@ -942,11 +937,11 @@ static int i2c_w(struct sd *sd, /* Initiate 3-byte write cycle */ rc = reg_w(sd, R518_I2C_CTL, 0x01); + if (rc < 0) + return rc; /* wait for write complete */ msleep(4); - if (rc < 0) - return rc; return reg_r8(sd, R518_I2C_CTL); } @@ -1029,7 +1024,7 @@ static inline int ov51x_restart(struct sd *sd) */ static int init_ov_sensor(struct sd *sd) { - int i, success; + int i; /* Reset the sensor */ if (i2c_w(sd, 0x12, 0x80) < 0) @@ -1038,11 +1033,11 @@ static int init_ov_sensor(struct sd *sd) /* Wait for it to initialize */ msleep(150); - for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + for (i = 0; i < i2c_detect_tries; i++) { if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f && i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) { - success = 1; - continue; + PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); + return 0; } /* Reset the sensor */ @@ -1054,10 +1049,7 @@ static int init_ov_sensor(struct sd *sd) if (i2c_r(sd, 0x00) < 0) return -EIO; } - if (!success) - return -EIO; - PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); - return 0; + return -EIO; } /* Set the read and write slave IDs. The "slave" argument is the write slave, @@ -1073,7 +1065,6 @@ static int ov51x_set_slave_ids(struct sd *sd, rc = reg_w(sd, R51x_I2C_W_SID, slave); if (rc < 0) return rc; - sd->primary_i2c_slave = slave; return reg_w(sd, R51x_I2C_R_SID, slave + 1); } @@ -1285,7 +1276,6 @@ static int ov6xx0_configure(struct sd *sd) /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ static void ov51x_led_control(struct sd *sd, int on) { -/* PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ } @@ -1352,7 +1342,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } if (ov8xx0_configure(sd) < 0) { PDEBUG(D_ERR, - "Failed to configure OV8xx0 sensor"); + "Failed to configure OV8xx0 sensor"); goto error; } } @@ -1482,7 +1472,7 @@ static int ov519_mode_init_regs(struct sd *sd) return -EIO; if (sd->sensor == SEN_OV7640) { /* Select 8-bit input mode */ - reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); + reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10); } } else { if (write_regvals(sd, mode_init_519_ov7670, @@ -1490,14 +1480,14 @@ static int ov519_mode_init_regs(struct sd *sd) return -EIO; } - reg_w(sd, OV519_CAM_H_SIZE, sd->gspca_dev.width >> 4); - reg_w(sd, OV519_CAM_V_SIZE, sd->gspca_dev.height >> 3); - reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); - reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); - reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); - reg_w(sd, OV519_CAM_Y_OFFSETH, 0x00); - reg_w(sd, OV519_CAM_DIVIDER, 0x00); - reg_w(sd, OV519_CAM_FORMAT, 0x03); /* YUV422 */ + reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); + reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3); + reg_w(sd, OV519_R12_X_OFFSETL, 0x00); + reg_w(sd, OV519_R13_X_OFFSETH, 0x00); + reg_w(sd, OV519_R14_Y_OFFSETL, 0x00); + reg_w(sd, OV519_R15_Y_OFFSETH, 0x00); + reg_w(sd, OV519_R16_DIVIDER, 0x00); + reg_w(sd, OV519_R25_FORMAT, 0x03); /* YUV422 */ reg_w(sd, 0x26, 0x00); /* Undocumented */ /******** Set the framerate ********/ @@ -1509,8 +1499,8 @@ static int ov519_mode_init_regs(struct sd *sd) switch (sd->sensor) { case SEN_OV7640: switch (sd->frame_rate) { -/*fixme: default was 30 fps */ - case 30: + default: +/* case 30: */ reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0xff); break; @@ -1522,8 +1512,7 @@ static int ov519_mode_init_regs(struct sd *sd) reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0x1b); break; - default: -/* case 15: */ + case 15: reg_w(sd, 0xa4, 0x04); reg_w(sd, 0x23, 0xff); sd->clockdiv = 1; @@ -1576,7 +1565,6 @@ static int ov519_mode_init_regs(struct sd *sd) } break; } - return 0; } @@ -1692,7 +1680,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd) * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ i2c_w(sd, 0x2d, 0x85); - } else if (sd->clockdiv >= 0) { + } else { i2c_w(sd, 0x11, sd->clockdiv); } @@ -1894,7 +1882,6 @@ static int sd_start(struct gspca_dev *gspca_dev) ret = ov51x_restart(sd); if (ret < 0) goto out; - PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); ov51x_led_control(sd, 1); return 0; out: @@ -1904,8 +1891,10 @@ out: static void sd_stopN(struct gspca_dev *gspca_dev) { - ov51x_stop((struct sd *) gspca_dev); - ov51x_led_control((struct sd *) gspca_dev, 0); + struct sd *sd = (struct sd *) gspca_dev; + + ov51x_stop(sd); + ov51x_led_control(sd, 0); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -1960,9 +1949,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) int val; val = sd->brightness; - PDEBUG(D_CONF, "brightness:%d", val); -/* if (gspca_dev->streaming) - * ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: @@ -1984,8 +1970,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); break; } -/* if (gspca_dev->streaming) - * ov51x_restart(sd); */ } static void setcontrast(struct gspca_dev *gspca_dev) @@ -1994,9 +1978,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) int val; val = sd->contrast; - PDEBUG(D_CONF, "contrast:%d", val); -/* if (gspca_dev->streaming) - ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV7610: case SEN_OV6620: @@ -2032,8 +2013,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); break; } -/* if (gspca_dev->streaming) - ov51x_restart(sd); */ } static void setcolors(struct gspca_dev *gspca_dev) @@ -2042,9 +2021,6 @@ static void setcolors(struct gspca_dev *gspca_dev) int val; val = sd->colors; - PDEBUG(D_CONF, "saturation:%d", val); -/* if (gspca_dev->streaming) - ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: @@ -2069,8 +2045,6 @@ static void setcolors(struct gspca_dev *gspca_dev) /* set REG_COM13 values for UV sat auto mode */ break; } -/* if (gspca_dev->streaming) - ov51x_restart(sd); */ } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) @@ -2078,7 +2052,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; - setbrightness(gspca_dev); + if (gspca_dev->streaming) + setbrightness(gspca_dev); return 0; } @@ -2095,7 +2070,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; - setcontrast(gspca_dev); + if (gspca_dev->streaming) + setcontrast(gspca_dev); return 0; } @@ -2112,7 +2088,8 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->colors = val; - setcolors(gspca_dev); + if (gspca_dev->streaming) + setcolors(gspca_dev); return 0; } @@ -2129,7 +2106,8 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->hflip = val; - sethvflip(sd); + if (gspca_dev->streaming) + sethvflip(sd); return 0; } @@ -2146,7 +2124,8 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; - sethvflip(sd); + if (gspca_dev->streaming) + sethvflip(sd); return 0; } @@ -2187,7 +2166,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x05a9, 0x8519)}, {} }; -#undef DVNAME + MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 0b0c573d0..39473e6b9 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -536,6 +536,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2471)}, {USB_DEVICE(0x093a, 0x2472)}, {USB_DEVICE(0x093a, 0x2476)}, + {USB_DEVICE(0x145f, 0x013a)}, {USB_DEVICE(0x2001, 0xf115)}, {} }; diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index a122634e0..f443df77e 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -763,10 +763,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->present) + return; if (sd->sensor == SENSOR_PAC7302) { reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x78, 0x40); diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c index 4bae911da..5ca8ab780 100644 --- a/linux/drivers/media/video/gspca/sonixb.c +++ b/linux/drivers/media/video/gspca/sonixb.c @@ -132,8 +132,6 @@ struct sensor_data { ignore atleast the 2 next frames for the new settings to come into effect before doing any other adjustments */ #define AUTOGAIN_IGNORE_FRAMES 3 -#define AUTOGAIN_DEADZONE 1000 -#define DESIRED_AVG_LUM 7000 /* V4L2 controls supported by the driver */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); @@ -857,18 +855,29 @@ static void setfreq(struct gspca_dev *gspca_dev) static void do_autogain(struct gspca_dev *gspca_dev) { + int deadzone, desired_avg_lum; struct sd *sd = (struct sd *) gspca_dev; int avg_lum = atomic_read(&sd->avg_lum); if (avg_lum == -1) return; + /* SIF / VGA sensors have a different autoexposure area and thus + different avg_lum values for the same picture brightness */ + if (sensor_data[sd->sensor].flags & F_SIF) { + deadzone = 1000; + desired_avg_lum = 7000; + } else { + deadzone = 3000; + desired_avg_lum = 23000; + } + if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - sd->brightness * DESIRED_AVG_LUM / 127, - AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) { - PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n", + sd->brightness * desired_avg_lum / 127, + deadzone, GAIN_KNEE, EXPOSURE_KNEE)) { + PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", (int)sd->gain, (int)sd->exposure); sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; } @@ -1256,8 +1265,8 @@ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, - {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, #endif + {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index aa11df134..93cc65b5f 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -24,6 +24,8 @@ #include "gspca.h" #include "jpeg.h" +#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0) + MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -40,6 +42,7 @@ struct sd { unsigned char colors; unsigned char autogain; __u8 vflip; /* ov7630 only */ + __u8 infrared; /* mi0360 only */ signed char ag_cnt; #define AG_CNT_START 13 @@ -73,6 +76,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { { @@ -150,6 +155,22 @@ static struct ctrl sd_ctrls[] = { .set = sd_setvflip, .get = sd_getvflip, }, +/* mi0360 only */ +#define INFRARED_IDX 5 + { + { + .id = V4L2_CID_INFRARED, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Infrared", + .minimum = 0, + .maximum = 1, + .step = 1, +#define INFRARED_DEF 0 + .default_value = INFRARED_DEF, + }, + .set = sd_setinfrared, + .get = sd_getinfrared, + }, }; static struct v4l2_pix_format vga_mode[] = { @@ -231,13 +252,13 @@ static const __u8 sn_ov7630[] = { static const __u8 sn_ov7648[] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, + 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, /* reg8 reg9 rega regb regc regd rege regf */ - 0xa1, 0x6e, 0x18, 0x65, 0x00, 0x00, 0x00, 0x10, + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ - 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x82, + 0x03, 0x00, 0x00, 0x01, 0x00, 0x28, 0x1e, 0x00, /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const __u8 sn_ov7660[] = { @@ -469,6 +490,53 @@ static const __u8 ov7630_sensor_init[][8] = { /* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ {} }; + +static const __u8 ov7648_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */ + {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10}, + {0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10}, + {0xc1, 0x21, 0x13, 0xa0, 0x04, 0x84, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1a, 0x02, 0xba, 0xf4, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x41, 0xc0, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0xa0, 0x80, 0x32, 0x10}, + {0xd1, 0x21, 0x27, 0xfe, 0xa0, 0x00, 0x91, 0x10}, + {0xd1, 0x21, 0x2b, 0x00, 0x88, 0x85, 0x80, 0x10}, + {0xc1, 0x21, 0x2f, 0x9c, 0x00, 0xc4, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0xa6, 0x60, 0x88, 0x12, 0x10}, + {0xd1, 0x21, 0x64, 0x88, 0x00, 0x00, 0x94, 0x10}, + {0xd1, 0x21, 0x68, 0x7a, 0x0c, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6c, 0x11, 0x33, 0x22, 0x00, 0x10}, + {0xd1, 0x21, 0x70, 0x11, 0x00, 0x10, 0x50, 0x10}, + {0xd1, 0x21, 0x74, 0x20, 0x06, 0x00, 0xb5, 0x10}, + {0xd1, 0x21, 0x78, 0x8a, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x7c, 0x00, 0x43, 0x00, 0x00, 0x10}, + + {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10}, +/* {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */ +/* {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */ + {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10}, +/*...*/ +/* {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, jfm done */ + {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, +/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, * GAIN - def */ +/* {0xb1, 0x21, 0x01, 0x6c, 0x6c, 0x00, 0x00, 0x10}, * B R - def: 80 */ +/*...*/ + {0xa1, 0x21, 0x11, 0x81, 0x00, 0x00, 0x00, 0x10}, /* CLKRC */ +/* {0xa1, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x2a, 0x91, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */ +/* {0xb1, 0x21, 0x01, 0x64, 0x84, 0x00, 0x00, 0x10}, * B R - def: 80 */ + + {} +}; + static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ /* (delay 20ms) */ @@ -557,64 +625,6 @@ static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, {} }; -/* reg 0x04 reg 0x07 reg 0x10 */ -/* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */ - -static const __u8 ov7648_sensor_init[][8] = { - {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10}, - {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10}, - {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10}, - {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10}, - {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10}, - {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10}, - {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10}, - {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10}, - {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10}, - {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10}, - {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10}, - {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10}, - {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10}, - {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10}, - {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10}, - {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10}, - /* {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10}, - * This is currently setting a - * blue tint, and some things more , i leave it here for future test if - * somene is having problems with color on this sensor - {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10}, - {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10}, - {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10}, - {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10}, - {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10}, */ - {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, - {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */ - {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */ - {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/ -/* {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10}, * Bright/Witene */ - {} -}; static const __u8 qtable4[] = { 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06, @@ -833,8 +843,8 @@ static int configure_gpio(struct gspca_dev *gspca_dev, break; #endif case SENSOR_OV7648: - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0xae); + reg_w1(gspca_dev, 0x01, 0x63); + reg_w1(gspca_dev, 0x17, 0x20); reg_w1(gspca_dev, 0x01, 0x42); break; #if 1 @@ -930,6 +940,13 @@ static void ov7648_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; + i2c_w8(gspca_dev, ov7648_sensor_init[i]); + i++; +/* win: dble reset */ + i2c_w8(gspca_dev, ov7648_sensor_init[i]); /* reset */ + i++; + msleep(20); +/* win: i2c reg read 00..7f */ while (ov7648_sensor_init[i][0]) { i2c_w8(gspca_dev, ov7648_sensor_init[i]); i++; @@ -971,6 +988,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->colors = COLOR_DEF; sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; + sd->vflip = VFLIP_DEF; + sd->infrared = INFRARED_DEF; switch (sd->sensor) { case SENSOR_OV7630: @@ -981,7 +1000,8 @@ static int sd_config(struct gspca_dev *gspca_dev, } if (sd->sensor != SENSOR_OV7630) gspca_dev->ctrl_dis |= (1 << VFLIP_IDX); - + if (sd->sensor != SENSOR_MI0360) + gspca_dev->ctrl_dis |= (1 << INFRARED_IDX); return 0; } @@ -1208,12 +1228,24 @@ static void setautogain(struct gspca_dev *gspca_dev) static void setvflip(struct sd *sd) { - if (sd->sensor != SENSOR_OV7630) - return; i2c_w1(&sd->gspca_dev, 0x75, /* COMN */ sd->vflip ? 0x82 : 0x02); } +static void setinfrared(struct sd *sd) +{ +/*fixme: different sequence for StarCam Clip and StarCam 370i */ +#if 1 +/* Clip */ + i2c_w1(&sd->gspca_dev, 0x02, /* gpio */ + sd->infrared ? 0x66 : 0x64); +#else +/* 370i */ + i2c_w1(&sd->gspca_dev, 0x02, /* gpio */ + sd->infrared ? 0x55 : 0x54); +#endif +} + /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -1248,7 +1280,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg17 = 0xe2; break; case SENSOR_OV7648: - reg17 = 0xae; + reg17 = 0x20; break; #if 1 /*jfm: from win trace */ @@ -1269,6 +1301,10 @@ static int sd_start(struct gspca_dev *gspca_dev) for (i = 0; i < 8; i++) reg_w(gspca_dev, 0x84, reg84, sizeof reg84); switch (sd->sensor) { + case SENSOR_OV7648: + reg_w1(gspca_dev, 0x9a, 0x0a); + reg_w1(gspca_dev, 0x99, 0x60); + break; case SENSOR_OV7660: reg_w1(gspca_dev, 0x9a, 0x05); break; @@ -1313,8 +1349,8 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_OV7648: ov7648_InitSensor(gspca_dev); - reg17 = 0xa2; - reg1 = 0x44; + reg17 = 0x21; +/* reg1 = 0x42; * 42 - 46? */ /* if (mode) ; * 320x2... else @@ -1358,8 +1394,10 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x17, reg17); switch (sd->sensor) { - case SENSOR_HV7131R: case SENSOR_MI0360: + setinfrared(sd); + /* fall thru */ + case SENSOR_HV7131R: case SENSOR_MO4000: case SENSOR_OM6802: setbrightness(gspca_dev); @@ -1384,6 +1422,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 }; static const __u8 stopmi0360[] = { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 }; + static const __u8 stopov7648[] = + { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 }; __u8 data; const __u8 *sn9c1xx; @@ -1397,8 +1437,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev) i2c_w8(gspca_dev, stopmi0360); data = 0x29; break; - case SENSOR_OV7630: case SENSOR_OV7648: + i2c_w8(gspca_dev, stopov7648); + /* fall thru */ + case SENSOR_OV7630: data = 0x29; break; default: @@ -1613,6 +1655,24 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->infrared = val; + if (gspca_dev->streaming) + setinfrared(sd); + return 0; +} + +static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->infrared; + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -1638,8 +1698,8 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)}, - {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, #endif + {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)}, /* bw600.inf: @@ -1664,7 +1724,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/ /*bw600.inf:*/ - {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/ + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c110?*/ {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)}, /* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ @@ -1672,8 +1732,8 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, #endif {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, + {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE -/* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */ {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, /* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c index a3f616709..2e1c5e50e 100644 --- a/linux/drivers/media/video/gspca/spca500.c +++ b/linux/drivers/media/video/gspca/spca500.c @@ -650,10 +650,10 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->subtype = id->driver_info; if (sd->subtype != LogitechClickSmart310) { cam->cam_mode = vga_mode; - cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + cam->nmodes = ARRAY_SIZE(vga_mode); } else { cam->cam_mode = sif_mode; - cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + cam->nmodes = ARRAY_SIZE(sif_mode); } sd->qindex = 5; sd->brightness = BRIGHTNESS_DEF; diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c index 979344907..17dab9859 100644 --- a/linux/drivers/media/video/gspca/spca501.c +++ b/linux/drivers/media/video/gspca/spca501.c @@ -34,6 +34,8 @@ struct sd { unsigned short contrast; __u8 brightness; __u8 colors; + __u8 blue_balance; + __u8 red_balance; char subtype; #define Arowana300KCMOSCamera 0 @@ -52,6 +54,10 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { #define MY_BRIGHTNESS 0 @@ -63,7 +69,7 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 127, .step = 1, - .default_value = 63, + .default_value = 0, }, .set = sd_setbrightness, .get = sd_getbrightness, @@ -75,9 +81,9 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, - .maximum = 0xffff, + .maximum = 64725, .step = 1, - .default_value = 0xaa00, + .default_value = 64725, }, .set = sd_setcontrast, .get = sd_getcontrast, @@ -91,11 +97,39 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 63, .step = 1, - .default_value = 31, + .default_value = 20, }, .set = sd_setcolors, .get = sd_getcolors, }, +#define MY_BLUE_BALANCE 3 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setblue_balance, + .get = sd_getblue_balance, + }, +#define MY_RED_BALANCE 4 + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0, + }, + .set = sd_setred_balance, + .get = sd_getred_balance, + }, }; static struct v4l2_pix_format vga_mode[] = { @@ -1822,6 +1856,7 @@ static int reg_write(struct usb_device *dev, return ret; } +#if 0 /* returns: negative is error, pos or zero is data */ static int reg_read(struct gspca_dev *gspca_dev, __u16 req, /* bRequest */ @@ -1845,6 +1880,7 @@ static int reg_read(struct gspca_dev *gspca_dev, } return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; } +#endif static int write_vector(struct gspca_dev *gspca_dev, const __u16 data[][3]) @@ -1869,18 +1905,18 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness); reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness); - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness); } static void getbrightness(struct gspca_dev *gspca_dev) { +#if 0 struct sd *sd = (struct sd *) gspca_dev; __u16 brightness; - brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x11, 2); - sd->brightness = brightness << 1; + brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x12, 2); + sd->brightness = brightness; +#endif } static void setcontrast(struct gspca_dev *gspca_dev) @@ -1906,7 +1942,6 @@ static void getcontrast(struct gspca_dev *gspca_dev) 0x01, 1) & 0xff); #endif -/* spca50x->contrast = 0xaa01; */ } static void setcolors(struct gspca_dev *gspca_dev) @@ -1918,11 +1953,25 @@ static void setcolors(struct gspca_dev *gspca_dev) static void getcolors(struct gspca_dev *gspca_dev) { +#if 0 struct sd *sd = (struct sd *) gspca_dev; sd->colors = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x0c, 2); -/* sd->hue = (reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x13, */ -/* 2) & 0xFF) << 8; */ +#endif +} + +static void setblue_balance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->blue_balance); +} + +static void setred_balance(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->red_balance); } /* this function is called at probe time */ @@ -1941,6 +1990,14 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + switch (sd->subtype) { case Arowana300KCMOSCamera: case SmileIntlCamera: @@ -1959,15 +2016,17 @@ static int sd_config(struct gspca_dev *gspca_dev, goto error; break; } + PDEBUG(D_STREAM, "Initializing SPCA501 finished"); return 0; error: return -EINVAL; } -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) +static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + int mode; switch (sd->subtype) { case ThreeComHomeConnectLite: @@ -1987,14 +2046,6 @@ static int sd_init(struct gspca_dev *gspca_dev) /* Generic 501 open data */ write_vector(gspca_dev, spca501_open_data); } - PDEBUG(D_STREAM, "Initializing SPCA501 finished"); - return 0; -} - -static int sd_start(struct gspca_dev *gspca_dev) -{ - struct usb_device *dev = gspca_dev->dev; - int mode; /* memorize the wanted pixel format */ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; @@ -2033,8 +2084,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { + if (!gspca_dev->present) + return; reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); } @@ -2121,6 +2175,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue_balance = val; + if (gspca_dev->streaming) + setblue_balance(gspca_dev); + return 0; +} + +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->blue_balance; + return 0; +} + +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red_balance = val; + if (gspca_dev->streaming) + setred_balance(gspca_dev); + return 0; +} + +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->red_balance; + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c index 62bab3cc1..c52598e94 100644 --- a/linux/drivers/media/video/gspca/spca505.c +++ b/linux/drivers/media/video/gspca/spca505.c @@ -811,8 +811,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { + if (!gspca_dev->present) + return; + /* This maybe reset or power control */ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); reg_write(gspca_dev->dev, 0x03, 0x01, 0x0); diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 5b65dd66b..4c0046cc7 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -780,10 +780,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) } } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->present) + return; if (sd->chip_revision == Rev012A) { reg_w_val(gspca_dev->dev, 0x8118, 0x29); reg_w_val(gspca_dev->dev, 0x8114, 0x08); diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c index 8204dabb1..4e18f90ba 100644 --- a/linux/drivers/media/video/gspca/tv8532.c +++ b/linux/drivers/media/video/gspca/tv8532.c @@ -30,15 +30,10 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; /* current length of tmpbuf */ - __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */ - __u8 tmpbuf2[352 * 288]; /* no protection... */ + __u16 brightness; + __u16 contrast; - unsigned short brightness; - unsigned short contrast; - - char packet; - char synchro; + __u8 packet; }; /* V4L2 controls supported by the driver */ @@ -392,6 +387,8 @@ static void setbrightness(struct gspca_dev *gspca_dev) /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); tv_8532ReadRegisters(gspca_dev); @@ -443,6 +440,10 @@ static int sd_start(struct gspca_dev *gspca_dev) /************************************************/ tv_8532_PollReg(gspca_dev); reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ + + gspca_dev->empty_packet = 0; /* check the empty packets */ + sd->packet = 0; /* ignore the first packets */ + return 0; } @@ -451,111 +452,36 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); } -static void tv8532_preprocess(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; -/* we should received a whole frame with header and EOL marker - * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2 - * sequence 2bytes header the Alternate pixels bayer GB 4 bytes - * Alternate pixels bayer RG 4 bytes EOL */ - int width = gspca_dev->width; - int height = gspca_dev->height; - unsigned char *dst = sd->tmpbuf2; - unsigned char *data = sd->tmpbuf; - int i; - - /* precompute where is the good bayer line */ - if (((data[3] + data[width + 7]) >> 1) - + (data[4] >> 2) - + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1) - + (data[3] >> 2) - + (data[width + 5] >> 1)) - data += 3; - else - data += 2; - for (i = 0; i < height / 2; i++) { - memcpy(dst, data, width); - data += width + 3; - dst += width; - memcpy(dst, data, width); - data += width + 7; - dst += width; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - - if (data[0] != 0x80) { - sd->packet++; - if (sd->buflen + len > sizeof sd->tmpbuf) { - if (gspca_dev->last_packet_type != DISCARD_PACKET) { - PDEBUG(D_PACK, "buffer overflow"); - gspca_dev->last_packet_type = DISCARD_PACKET; - } - return; - } - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; - return; - } - - /* here we detect 0x80 */ - /* counter is limited so we need few header for a frame :) */ - - /* header 0x80 0x80 0x80 0x80 0x80 */ - /* packet 00 63 127 145 00 */ - /* sof 0 1 1 0 0 */ - - /* update sequence */ - if (sd->packet == 63 || sd->packet == 127) - sd->synchro = 1; - - /* is there a frame start ? */ - if (sd->packet >= (gspca_dev->height >> 1) - 1) { - PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro, - sd->packet); - if (!sd->synchro) { /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - tv8532_preprocess(gspca_dev); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, sd->tmpbuf2, - gspca_dev->width * - gspca_dev->width); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, - frame, data, 0); - memcpy(sd->tmpbuf, data, len); - sd->buflen = len; - sd->packet = 0; - return; - } - if (gspca_dev->last_packet_type != DISCARD_PACKET) { - PDEBUG(D_PACK, - "Warning wrong TV8532 frame detection %d", - sd->packet); - gspca_dev->last_packet_type = DISCARD_PACKET; - } - return; - } - - if (!sd->synchro) { - /* Drop packet frame corrupt */ - PDEBUG(D_PACK, "DROP SOF %d packet %d", - sd->synchro, sd->packet); - sd->packet = 0; - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - sd->synchro = 1; - sd->packet++; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; + int packet_type0, packet_type1; + + packet_type0 = packet_type1 = INTER_PACKET; + if (gspca_dev->empty_packet) { + gspca_dev->empty_packet = 0; + sd->packet = gspca_dev->height / 2; + packet_type0 = FIRST_PACKET; + } else if (sd->packet == 0) + return; /* 2 more lines in 352x288 ! */ + sd->packet--; + if (sd->packet == 0) + packet_type1 = LAST_PACKET; + + /* each packet contains: + * - header 2 bytes + * - RG line + * - 4 bytes + * - GB line + * - 4 bytes + */ + gspca_frame_add(gspca_dev, packet_type0, + frame, data + 2, gspca_dev->width); + gspca_frame_add(gspca_dev, packet_type1, + frame, data + gspca_dev->width + 6, gspca_dev->width); } static void setcontrast(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index 95531138e..f6fae60ae 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -1830,10 +1830,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(dev, 0xa0, 0x09, 0xb003); } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; + if (!gspca_dev->present) + return; reg_w(dev, 0x89, 0xffff, 0xffff); } diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index 0b1871cec..adbca6a9d 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -2266,7 +2266,7 @@ static const struct usb_action hdcs2020b_NoFliker[] = { {} }; -static const struct usb_action hv7131bxx_Initial[] = { +static const struct usb_action hv7131bxx_Initial[] = { /* 320x240 */ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, @@ -2290,7 +2290,7 @@ static const struct usb_action hv7131bxx_Initial[] = { {0xaa, 0x14, 0x0001}, {0xaa, 0x15, 0x00e8}, {0xaa, 0x16, 0x0002}, - {0xaa, 0x17, 0x0086}, + {0xaa, 0x17, 0x0086}, /* 00,17,88,aa */ {0xaa, 0x31, 0x0038}, {0xaa, 0x32, 0x0038}, {0xaa, 0x33, 0x0038}, @@ -2309,72 +2309,11 @@ static const struct usb_action hv7131bxx_Initial[] = { {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xaa, 0x02, 0x0080}, /* {0xaa, 0x02, 0x0090}; */ - {0xa1, 0x01, 0x0002}, - {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, - {0xa1, 0x01, 0x0091}, - {0xa1, 0x01, 0x0095}, - {0xa1, 0x01, 0x0096}, - - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - - {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf8, ZC3XX_R10B_RGB01}, - {0xa0, 0xf8, ZC3XX_R10C_RGB02}, - {0xa0, 0xf8, ZC3XX_R10D_RGB10}, - {0xa0, 0x50, ZC3XX_R10E_RGB11}, - {0xa0, 0xf8, ZC3XX_R10F_RGB12}, - {0xa0, 0xf8, ZC3XX_R110_RGB20}, - {0xa0, 0xf8, ZC3XX_R111_RGB21}, - {0xa0, 0x50, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x25, 0x0007}, - {0xaa, 0x26, 0x00a1}, - {0xaa, 0x27, 0x0020}, - {0xaa, 0x20, 0x0000}, - {0xaa, 0x21, 0x00a0}, - {0xaa, 0x22, 0x0016}, - {0xaa, 0x23, 0x0040}, - - {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2F */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */ - {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa1, 0x01, 0x001d}, - {0xa1, 0x01, 0x001e}, - {0xa1, 0x01, 0x001f}, - {0xa1, 0x01, 0x0020}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, -/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {0xaa, 0x02, 0x0090}, /* 00,02,80,aa */ {} }; -static const struct usb_action hv7131bxx_InitialScale[] = { +static const struct usb_action hv7131bxx_InitialScale[] = { /* 640x480*/ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, @@ -2418,65 +2357,156 @@ static const struct usb_action hv7131bxx_InitialScale[] = { {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */ - {0xa1, 0x01, 0x0002}, - {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, - {0xa1, 0x01, 0x0091}, - {0xa1, 0x01, 0x0095}, - {0xa1, 0x01, 0x0096}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - - {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf8, ZC3XX_R10B_RGB01}, - {0xa0, 0xf8, ZC3XX_R10C_RGB02}, - {0xa0, 0xf8, ZC3XX_R10D_RGB10}, - {0xa0, 0x50, ZC3XX_R10E_RGB11}, - {0xa0, 0xf8, ZC3XX_R10F_RGB12}, - {0xa0, 0xf8, ZC3XX_R110_RGB20}, - {0xa0, 0xf8, ZC3XX_R111_RGB21}, - {0xa0, 0x50, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x25, 0x0007}, - {0xaa, 0x26, 0x00a1}, - {0xaa, 0x27, 0x0020}, - {0xaa, 0x20, 0x0000}, - {0xaa, 0x21, 0x0040}, - {0xaa, 0x22, 0x0013}, - {0xaa, 0x23, 0x004c}, - {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */ - {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 60 */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa1, 0x01, 0x001d}, - {0xa1, 0x01, 0x001e}, - {0xa1, 0x01, 0x001f}, - {0xa1, 0x01, 0x0020}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, -/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {} +}; +static const struct usb_action hv7131b_50HZ[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ + {0xaa, 0x22, 0x001b}, /* 00,22,1b,aa */ + {0xaa, 0x23, 0x00fc}, /* 00,23,fc,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0xea, ZC3XX_R196_SYNC01MID}, /* 01,96,ea,cc */ + {0xa0, 0x60, ZC3XX_R197_SYNC01HIGH}, /* 01,97,60,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x1b, ZC3XX_R01F_HSYNC_2}, /* 00,1f,1b,cc */ + {0xa0, 0xfc, ZC3XX_R020_HSYNC_3}, /* 00,20,fc,cc */ + {} +}; +static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ + {0xaa, 0x22, 0x0012}, /* 00,22,12,aa */ + {0xaa, 0x23, 0x0080}, /* 00,23,80,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */ + {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */ + {0xa0, 0xd4, ZC3XX_R196_SYNC01MID}, /* 01,96,d4,cc */ + {0xa0, 0xc0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,c0,cc */ + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x12, ZC3XX_R01F_HSYNC_2}, /* 00,1f,12,cc */ + {0xa0, 0x80, ZC3XX_R020_HSYNC_3}, /* 00,20,80,cc */ + {} +}; +static const struct usb_action hv7131b_60HZ[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ + {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0040}, /* 00,21,40,aa */ + {0xaa, 0x22, 0x0013}, /* 00,22,13,aa */ + {0xaa, 0x23, 0x004c}, /* 00,23,4c,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0xc3, ZC3XX_R196_SYNC01MID}, /* 01,96,c3,cc */ + {0xa0, 0x50, ZC3XX_R197_SYNC01HIGH}, /* 01,97,50,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */ + {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, /* 00,1f,13,cc */ + {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, /* 00,20,4c,cc */ + {} +}; +static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ + {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ + {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ + {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */ + {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */ + {0xa0, 0x86, ZC3XX_R196_SYNC01MID}, /* 01,96,86,cc */ + {0xa0, 0xa0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,a0,cc */ + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ + {} +}; +static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ + {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0003}, /* 00,23,03,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x10, ZC3XX_R01E_HSYNC_1}, /* 00,1e,10,cc */ + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, /* 00,1f,00,cc */ + {0xa0, 0x03, ZC3XX_R020_HSYNC_3}, /* 00,20,03,cc */ + {} +}; +static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ + {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ + {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ + {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ {} }; @@ -6358,6 +6388,7 @@ static void setmatrix(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_GC0305: + case SENSOR_HV7131B: matrix = gc0305_matrix; break; case SENSOR_MC501CB: @@ -6393,6 +6424,8 @@ static void setbrightness(struct gspca_dev *gspca_dev) /*fixme: is it really write to 011d and 018d for all other sensors? */ brightness = sd->brightness; reg_w(gspca_dev->dev, brightness, 0x011d); + if (sd->sensor == SENSOR_HV7131B) + return; if (brightness < 0x70) brightness += 0x10; else @@ -6534,6 +6567,7 @@ static void setquality(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_GC0305: + case SENSOR_HV7131B: case SENSOR_OV7620: case SENSOR_PO2030: return; @@ -6596,9 +6630,9 @@ static int setlightfreq(struct gspca_dev *gspca_dev) hdcs2020b_50HZ, hdcs2020b_50HZ, hdcs2020b_60HZ, hdcs2020b_60HZ}, /* SENSOR_HV7131B 5 */ - {NULL, NULL, - NULL, NULL, - NULL, NULL}, + {hv7131b_NoFlikerScale, hv7131b_NoFliker, + hv7131b_50HZScale, hv7131b_50HZ, + hv7131b_60HZScale, hv7131b_60HZ}, /* SENSOR_HV7131C 6 */ {NULL, NULL, NULL, NULL, @@ -7155,7 +7189,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->gamma = gamma[(int) sd->sensor]; sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value; - sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value; switch (sd->sensor) { case SENSOR_GC0305: @@ -7214,7 +7247,6 @@ static int sd_start(struct gspca_dev *gspca_dev) mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; zc3_init = init_tb[(int) sd->sensor][mode]; switch (sd->sensor) { - case SENSOR_HV7131B: case SENSOR_HV7131C: zcxx_probeSensor(gspca_dev); break; @@ -7339,10 +7371,13 @@ static int sd_start(struct gspca_dev *gspca_dev) return 0; } +/* called on streamoff with alt 0 and on disconnect */ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->present) + return; send_unknown(gspca_dev->dev, sd->sensor); } diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index 5f0fa6e90..a67bed7d7 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -394,10 +394,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr, goto err_out_detach; } - /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */ + /* Phys addr can only be set after attaching (for ir->c.dev) */ snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - ir->c.adapter->dev.bus_id, - ir->c.dev.bus_id); + dev_name(&ir->c.adapter->dev), + dev_name(&ir->c.dev)); /* init + register input device */ ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes); diff --git a/linux/drivers/media/video/ivtv/Kconfig b/linux/drivers/media/video/ivtv/Kconfig index 0069898bd..c46bfb156 100644 --- a/linux/drivers/media/video/ivtv/Kconfig +++ b/linux/drivers/media/video/ivtv/Kconfig @@ -1,6 +1,6 @@ config VIDEO_IVTV tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" - depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && PCI && I2C depends on INPUT # due to VIDEO_IR select I2C_ALGOBIT select VIDEO_IR @@ -12,7 +12,6 @@ config VIDEO_IVTV select VIDEO_SAA711X select VIDEO_SAA717X select VIDEO_SAA7127 - select VIDEO_TVAUDIO select VIDEO_CS53L32A select VIDEO_M52790 select VIDEO_WM8775 @@ -32,7 +31,7 @@ config VIDEO_IVTV config VIDEO_FB_IVTV tristate "Conexant cx23415 framebuffer support" - depends on VIDEO_IVTV && FB && EXPERIMENTAL + depends on VIDEO_IVTV && FB select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/linux/drivers/media/video/ivtv/ivtv-cards.c b/linux/drivers/media/video/ivtv/ivtv-cards.c index c52371f9e..2883c8780 100644 --- a/linux/drivers/media/video/ivtv/ivtv-cards.c +++ b/linux/drivers/media/video/ivtv/ivtv-cards.c @@ -877,15 +877,13 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, .name = "Yuan PG600-2, GotView PCI DVD Lite", - .comment = "only Composite and S-Video inputs are supported, not the tuner\n", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, -#if 0 .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - /* XC2028 support has not yet been tested on this card, until - that's done support for this tuner is disabled. */ + /* XC2028 support apparently works for the Yuan, it's still + uncertain whether it also works with the GotView. */ .video_inputs = { { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, { IVTV_CARD_INPUT_SVIDEO1, 1, @@ -901,17 +899,6 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, -#else - .hw_all = IVTV_HW_CX25840, - .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, - }, -#endif .pci_list = ivtv_pci_pg600v2, .i2c = &ivtv_i2c_std, }; diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index c9750a058..db866d912 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -879,43 +879,43 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) #ifdef MODULE /* load modules */ -#ifndef CONFIG_MEDIA_TUNER +#ifdef CONFIG_MEDIA_TUNER_MODULE hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif -#ifndef CONFIG_VIDEO_CX25840 +#ifdef CONFIG_VIDEO_CX25840_MODULE hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840); #endif -#ifndef CONFIG_VIDEO_SAA711X +#ifdef CONFIG_VIDEO_SAA711X_MODULE hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X); #endif -#ifndef CONFIG_VIDEO_SAA7127 +#ifdef CONFIG_VIDEO_SAA7127_MODULE hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127); #endif -#ifndef CONFIG_VIDEO_SAA717X +#ifdef CONFIG_VIDEO_SAA717X_MODULE hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X); #endif -#ifndef CONFIG_VIDEO_UPD64031A +#ifdef CONFIG_VIDEO_UPD64031A_MODULE hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A); #endif -#ifndef CONFIG_VIDEO_UPD64083 +#ifdef CONFIG_VIDEO_UPD64083_MODULE hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X); #endif -#ifndef CONFIG_VIDEO_MSP3400 +#ifdef CONFIG_VIDEO_MSP3400_MODULE hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX); #endif -#ifndef CONFIG_VIDEO_VP27SMPX +#ifdef CONFIG_VIDEO_VP27SMPX_MODULE hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX); #endif -#ifndef CONFIG_VIDEO_WM8775 +#ifdef CONFIG_VIDEO_WM8775_MODULE hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775); #endif -#ifndef CONFIG_VIDEO_WM8739 +#ifdef CONFIG_VIDEO_WM8739_MODULE hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739); #endif -#ifndef CONFIG_VIDEO_CS53L32A +#ifdef CONFIG_VIDEO_CS53L32A_MODULE hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A); #endif -#ifndef CONFIG_VIDEO_M52790 +#ifdef CONFIG_VIDEO_M52790_MODULE hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790); #endif #endif @@ -1215,6 +1215,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); + /* Turn off the output signal. The mpeg decoder is not yet + active so without this you would get a green image until the + mpeg decoder becomes active. */ + ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL); } /* clear interrupt mask, effectively disabling interrupts */ @@ -1334,6 +1338,10 @@ int ivtv_init_on_first_open(struct ivtv *itv) ivtv_s_frequency(NULL, &fh, &vf); if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { + /* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes + the mpeg decoder so now the saa7127 receives a proper + signal. */ + ivtv_saa7127(itv, VIDIOC_STREAMON, NULL); ivtv_init_mpeg_decoder(itv); } ivtv_s_std(NULL, &fh, &itv->tuner_std); @@ -1370,6 +1378,10 @@ static void ivtv_remove(struct pci_dev *pci_dev) /* Stop all decoding */ IVTV_DEBUG_INFO("Stopping decoding\n"); + + /* Turn off the TV-out */ + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) + ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL); if (atomic_read(&itv->decoding) > 0) { int type; diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 5c401fae5..9128df0f3 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -55,6 +55,7 @@ #include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/system.h> +#include <asm/byteorder.h> #include "compat.h" #include <linux/dvb/video.h> diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c index 6c37203db..c251ddb2f 100644 --- a/linux/drivers/media/video/ivtv/ivtv-i2c.c +++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c @@ -760,6 +760,7 @@ int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg) { return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg); } +EXPORT_SYMBOL(ivtv_saa7127); int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg) { diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 208fb5484..4bae38d21 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1756,12 +1756,12 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg) return 0; } -static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, +static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, unsigned int cmd, unsigned long arg) { struct video_device *vfd = video_devdata(filp); struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - int ret; + long ret; /* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */ switch (cmd) { @@ -1830,20 +1830,19 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f if (ivtv_debug & IVTV_DBGFLG_IOCTL) vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - ret = video_ioctl2(inode, filp, cmd, arg); + ret = __video_ioctl2(filp, cmd, arg); vfd->debug = 0; return ret; } -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; struct ivtv *itv = id->itv; - int res; + long res; mutex_lock(&itv->serialize_lock); - res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg); + res = ivtv_serialized_ioctl(itv, filp, cmd, arg); mutex_unlock(&itv->serialize_lock); return res; } diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.h b/linux/drivers/media/video/ivtv/ivtv-ioctl.h index 70188588b..58f003412 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.h @@ -30,7 +30,6 @@ void ivtv_set_funcs(struct video_device *vdev); int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std); int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); int ivtv_s_input(struct file *file, void *fh, unsigned int inp); -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); +long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); #endif diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 5bbf31e39..9b7aa79eb 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -48,7 +48,7 @@ static const struct file_operations ivtv_v4l2_enc_fops = { .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, .open = ivtv_v4l2_open, - .ioctl = ivtv_v4l2_ioctl, + .unlocked_ioctl = ivtv_v4l2_ioctl, .compat_ioctl = v4l_compat_ioctl32, .release = ivtv_v4l2_close, .poll = ivtv_v4l2_enc_poll, @@ -59,7 +59,7 @@ static const struct file_operations ivtv_v4l2_dec_fops = { .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, .open = ivtv_v4l2_open, - .ioctl = ivtv_v4l2_ioctl, + .unlocked_ioctl = ivtv_v4l2_ioctl, .compat_ioctl = v4l_compat_ioctl32, .release = ivtv_v4l2_close, .poll = ivtv_v4l2_dec_poll, diff --git a/linux/drivers/media/video/ivtv/ivtvfb.c b/linux/drivers/media/video/ivtv/ivtvfb.c index 1ac3af3fc..5e3613d86 100644 --- a/linux/drivers/media/video/ivtv/ivtvfb.c +++ b/linux/drivers/media/video/ivtv/ivtvfb.c @@ -48,6 +48,7 @@ #endif #include "ivtv-driver.h" +#include "ivtv-i2c.h" #include "ivtv-udma.h" #include "ivtv-mailbox.h" @@ -903,11 +904,16 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info) switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); + ivtv_saa7127(itv, VIDIOC_STREAMON, NULL); break; case FB_BLANK_NORMAL: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_VSYNC_SUSPEND: + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); + ivtv_saa7127(itv, VIDIOC_STREAMON, NULL); + break; case FB_BLANK_POWERDOWN: + ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL); ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); break; } diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c index 9a5662024..ca3a89616 100644 --- a/linux/drivers/media/video/ov511.c +++ b/linux/drivers/media/video/ov511.c @@ -1098,9 +1098,10 @@ ov51x_clear_snapshot(struct usb_ov511 *ov) reg_w(ov, R51x_SYS_SNAP, 0x02); reg_w(ov, R51x_SYS_SNAP, 0x00); } else if (ov->bclass == BCL_OV518) { - warn("snapshot reset not supported yet on OV518(+)"); + dev_warn(&ov->dev->dev, + "snapshot reset not supported yet on OV518(+)\n"); } else { - err("clear snap: invalid bridge type"); + dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n"); } } @@ -1115,14 +1116,16 @@ ov51x_check_snapshot(struct usb_ov511 *ov) if (ov->bclass == BCL_OV511) { ret = reg_r(ov, R51x_SYS_SNAP); if (ret < 0) { - err("Error checking snspshot status (%d)", ret); + dev_err(&ov->dev->dev, + "Error checking snspshot status (%d)\n", ret); } else if (ret & 0x08) { status = 1; } } else if (ov->bclass == BCL_OV518) { - warn("snapshot check not supported yet on OV518(+)"); + dev_warn(&ov->dev->dev, + "snapshot check not supported yet on OV518(+)\n"); } else { - err("check snap: invalid bridge type"); + dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n"); } return status; @@ -4012,8 +4015,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) /* Do not call this function directly! */ static int -ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = file->private_data; struct usb_ov511 *ov = video_get_drvdata(vdev); @@ -4462,7 +4464,7 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file, if (mutex_lock_interruptible(&ov->lock)) return -EINTR; - rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); + rc = video_usercopy(file, cmd, arg, ov51x_v4l1_ioctl_internal); mutex_unlock(&ov->lock); return rc; @@ -5221,7 +5223,8 @@ saa7111a_configure(struct usb_ov511 *ov) if (ov->bclass == BCL_OV511) reg_w(ov, 0x11, 0x00); else - warn("SAA7111A not yet supported with OV518/OV518+"); + dev_warn(&ov->dev->dev, + "SAA7111A not yet supported with OV518/OV518+\n"); return 0; } @@ -5460,7 +5463,8 @@ ov518_configure(struct usb_ov511 *ov) * required. OV518 has no uncompressed mode, to save RAM. */ if (!dumppix && !ov->compress) { ov->compress = 1; - warn("Compression required with OV518...enabling"); + dev_warn(&ov->dev->dev, + "Compression required with OV518...enabling\n"); } if (ov->bridge == BRG_OV518) { diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c new file mode 100644 index 000000000..2ddc2ab70 --- /dev/null +++ b/linux/drivers/media/video/ov772x.c @@ -0,0 +1,972 @@ +/* + * ov772x Camera Driver + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on ov7670 and soc_camera_platform driver, + * + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/videodev2.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-common.h> +#include <media/soc_camera.h> +#include <media/ov772x.h> + +/* + * register offset + */ +#define GAIN 0x00 /* AGC - Gain control gain setting */ +#define BLUE 0x01 /* AWB - Blue channel gain setting */ +#define RED 0x02 /* AWB - Red channel gain setting */ +#define GREEN 0x03 /* AWB - Green channel gain setting */ +#define COM1 0x04 /* Common control 1 */ +#define BAVG 0x05 /* U/B Average Level */ +#define GAVG 0x06 /* Y/Gb Average Level */ +#define RAVG 0x07 /* V/R Average Level */ +#define AECH 0x08 /* Exposure Value - AEC MSBs */ +#define COM2 0x09 /* Common control 2 */ +#define PID 0x0A /* Product ID Number MSB */ +#define VER 0x0B /* Product ID Number LSB */ +#define COM3 0x0C /* Common control 3 */ +#define COM4 0x0D /* Common control 4 */ +#define COM5 0x0E /* Common control 5 */ +#define COM6 0x0F /* Common control 6 */ +#define AEC 0x10 /* Exposure Value */ +#define CLKRC 0x11 /* Internal clock */ +#define COM7 0x12 /* Common control 7 */ +#define COM8 0x13 /* Common control 8 */ +#define COM9 0x14 /* Common control 9 */ +#define COM10 0x15 /* Common control 10 */ +#define HSTART 0x17 /* Horizontal sensor size */ +#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */ +#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */ +#define VSIZE 0x1A /* Vertical sensor size */ +#define PSHFT 0x1B /* Data format - pixel delay select */ +#define MIDH 0x1C /* Manufacturer ID byte - high */ +#define MIDL 0x1D /* Manufacturer ID byte - low */ +#define LAEC 0x1F /* Fine AEC value */ +#define COM11 0x20 /* Common control 11 */ +#define BDBASE 0x22 /* Banding filter Minimum AEC value */ +#define DBSTEP 0x23 /* Banding filter Maximum Setp */ +#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ +#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ +#define VPT 0x26 /* AGC/AEC Fast mode operating region */ +#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */ +#define EXHCH 0x2A /* Dummy pixel insert MSB */ +#define EXHCL 0x2B /* Dummy pixel insert LSB */ +#define VOUTSIZE 0x2C /* Vertical data output size MSBs */ +#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ +#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */ +#define YAVE 0x2F /* Y/G Channel Average value */ +#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */ +#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */ +#define HREF 0x32 /* Image start and size control */ +#define DM_LNL 0x33 /* Dummy line low 8 bits */ +#define DM_LNH 0x34 /* Dummy line high 8 bits */ +#define ADOFF_B 0x35 /* AD offset compensation value for B channel */ +#define ADOFF_R 0x36 /* AD offset compensation value for R channel */ +#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */ +#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */ +#define OFF_B 0x39 /* Analog process B channel offset value */ +#define OFF_R 0x3A /* Analog process R channel offset value */ +#define OFF_GB 0x3B /* Analog process Gb channel offset value */ +#define OFF_GR 0x3C /* Analog process Gr channel offset value */ +#define COM12 0x3D /* Common control 12 */ +#define COM13 0x3E /* Common control 13 */ +#define COM14 0x3F /* Common control 14 */ +#define COM15 0x40 /* Common control 15*/ +#define COM16 0x41 /* Common control 16 */ +#define TGT_B 0x42 /* BLC blue channel target value */ +#define TGT_R 0x43 /* BLC red channel target value */ +#define TGT_GB 0x44 /* BLC Gb channel target value */ +#define TGT_GR 0x45 /* BLC Gr channel target value */ +#define LCC0 0x46 /* Lens correction control 0 */ +#define LCC1 0x47 /* Lens correction option 1 - X coordinate */ +#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */ +#define LCC3 0x49 /* Lens correction option 3 */ +#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */ +#define LCC5 0x4B /* Lens correction option 5 */ +#define LCC6 0x4C /* Lens correction option 6 */ +#define FIXGAIN 0x4D /* Analog fix gain amplifer */ +#define AREF0 0x4E /* Sensor reference control */ +#define AREF1 0x4F /* Sensor reference current control */ +#define AREF2 0x50 /* Analog reference control */ +#define AREF3 0x51 /* ADC reference control */ +#define AREF4 0x52 /* ADC reference control */ +#define AREF5 0x53 /* ADC reference control */ +#define AREF6 0x54 /* Analog reference control */ +#define AREF7 0x55 /* Analog reference control */ +#define UFIX 0x60 /* U channel fixed value output */ +#define VFIX 0x61 /* V channel fixed value output */ +#define AW_BB_BLK 0x62 /* AWB option for advanced AWB */ +#define AW_B_CTRL0 0x63 /* AWB control byte 0 */ +#define DSP_CTRL1 0x64 /* DSP control byte 1 */ +#define DSP_CTRL2 0x65 /* DSP control byte 2 */ +#define DSP_CTRL3 0x66 /* DSP control byte 3 */ +#define DSP_CTRL4 0x67 /* DSP control byte 4 */ +#define AW_B_BIAS 0x68 /* AWB BLC level clip */ +#define AW_BCTRL1 0x69 /* AWB control 1 */ +#define AW_BCTRL2 0x6A /* AWB control 2 */ +#define AW_BCTRL3 0x6B /* AWB control 3 */ +#define AW_BCTRL4 0x6C /* AWB control 4 */ +#define AW_BCTRL5 0x6D /* AWB control 5 */ +#define AW_BCTRL6 0x6E /* AWB control 6 */ +#define AW_BCTRL7 0x6F /* AWB control 7 */ +#define AW_BCTRL8 0x70 /* AWB control 8 */ +#define AW_BCTRL9 0x71 /* AWB control 9 */ +#define AW_BCTRL10 0x72 /* AWB control 10 */ +#define AW_BCTRL11 0x73 /* AWB control 11 */ +#define AW_BCTRL12 0x74 /* AWB control 12 */ +#define AW_BCTRL13 0x75 /* AWB control 13 */ +#define AW_BCTRL14 0x76 /* AWB control 14 */ +#define AW_BCTRL15 0x77 /* AWB control 15 */ +#define AW_BCTRL16 0x78 /* AWB control 16 */ +#define AW_BCTRL17 0x79 /* AWB control 17 */ +#define AW_BCTRL18 0x7A /* AWB control 18 */ +#define AW_BCTRL19 0x7B /* AWB control 19 */ +#define AW_BCTRL20 0x7C /* AWB control 20 */ +#define AW_BCTRL21 0x7D /* AWB control 21 */ +#define GAM1 0x7E /* Gamma Curve 1st segment input end point */ +#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ +#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ +#define GAM4 0x81 /* Gamma Curve 4th segment input end point */ +#define GAM5 0x82 /* Gamma Curve 5th segment input end point */ +#define GAM6 0x83 /* Gamma Curve 6th segment input end point */ +#define GAM7 0x84 /* Gamma Curve 7th segment input end point */ +#define GAM8 0x85 /* Gamma Curve 8th segment input end point */ +#define GAM9 0x86 /* Gamma Curve 9th segment input end point */ +#define GAM10 0x87 /* Gamma Curve 10th segment input end point */ +#define GAM11 0x88 /* Gamma Curve 11th segment input end point */ +#define GAM12 0x89 /* Gamma Curve 12th segment input end point */ +#define GAM13 0x8A /* Gamma Curve 13th segment input end point */ +#define GAM14 0x8B /* Gamma Curve 14th segment input end point */ +#define GAM15 0x8C /* Gamma Curve 15th segment input end point */ +#define SLOP 0x8D /* Gamma curve highest segment slope */ +#define DNSTH 0x8E /* De-noise threshold */ +#define EDGE0 0x8F /* Edge enhancement control 0 */ +#define EDGE1 0x90 /* Edge enhancement control 1 */ +#define DNSOFF 0x91 /* Auto De-noise threshold control */ +#define EDGE2 0x92 /* Edge enhancement strength low point control */ +#define EDGE3 0x93 /* Edge enhancement strength high point control */ +#define MTX1 0x94 /* Matrix coefficient 1 */ +#define MTX2 0x95 /* Matrix coefficient 2 */ +#define MTX3 0x96 /* Matrix coefficient 3 */ +#define MTX4 0x97 /* Matrix coefficient 4 */ +#define MTX5 0x98 /* Matrix coefficient 5 */ +#define MTX6 0x99 /* Matrix coefficient 6 */ +#define MTX_CTRL 0x9A /* Matrix control */ +#define BRIGHT 0x9B /* Brightness control */ +#define CNTRST 0x9C /* Contrast contrast */ +#define CNTRST_CTRL 0x9D /* Contrast contrast center */ +#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */ +#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */ +#define SCAL0 0xA0 /* Scaling control 0 */ +#define SCAL1 0xA1 /* Scaling control 1 */ +#define SCAL2 0xA2 /* Scaling control 2 */ +#define FIFODLYM 0xA3 /* FIFO manual mode delay control */ +#define FIFODLYA 0xA4 /* FIFO auto mode delay control */ +#define SDE 0xA6 /* Special digital effect control */ +#define USAT 0xA7 /* U component saturation control */ +#define VSAT 0xA8 /* V component saturation control */ +#define HUE0 0xA9 /* Hue control 0 */ +#define HUE1 0xAA /* Hue control 1 */ +#define SIGN 0xAB /* Sign bit for Hue and contrast */ +#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */ + +/* + * register detail + */ + +/* COM2 */ +#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ + /* Output drive capability */ +#define OCAP_1x 0x00 /* 1x */ +#define OCAP_2x 0x01 /* 2x */ +#define OCAP_3x 0x02 /* 3x */ +#define OCAP_4x 0x03 /* 4x */ + +/* COM3 */ +#define SWAP_MASK 0x38 + +#define VFIMG_ON_OFF 0x80 /* Vertical flip image ON/OFF selection */ +#define HMIMG_ON_OFF 0x40 /* Horizontal mirror image ON/OFF selection */ +#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */ +#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */ +#define SWAP_ML 0x08 /* Swap output MSB/LSB */ + /* Tri-state option for output clock */ +#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */ + /* 1: No tri-state at this period */ + /* Tri-state option for output data */ +#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */ + /* 1: No tri-state at this period */ +#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */ + +/* COM4 */ + /* PLL frequency control */ +#define PLL_BYPASS 0x00 /* 00: Bypass PLL */ +#define PLL_4x 0x40 /* 01: PLL 4x */ +#define PLL_6x 0x80 /* 10: PLL 6x */ +#define PLL_8x 0xc0 /* 11: PLL 8x */ + /* AEC evaluate window */ +#define AEC_FULL 0x00 /* 00: Full window */ +#define AEC_1p2 0x10 /* 01: 1/2 window */ +#define AEC_1p4 0x20 /* 10: 1/4 window */ +#define AEC_2p3 0x30 /* 11: Low 2/3 window */ + +/* COM5 */ +#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */ +#define AFR_SPPED 0x40 /* Auto frame rate control speed slection */ + /* Auto frame rate max rate control */ +#define AFR_NO_RATE 0x00 /* No reduction of frame rate */ +#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */ +#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */ +#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */ + /* Auto frame rate active point control */ +#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */ +#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */ +#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ +#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ + /* AEC max step control */ +#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ + /* 1 : No limit to AEC increase step */ + +/* COM7 */ + /* SCCB Register Reset */ +#define SCCB_RESET 0x80 /* 0 : No change */ + /* 1 : Resets all registers to default */ + /* Resolution selection */ +#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */ +#define SLCT_VGA 0x00 /* 0 : VGA */ +#define SLCT_QVGA 0x40 /* 1 : QVGA */ +#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */ + /* RGB output format control */ +#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */ +#define FMT_RGB565 0x04 /* 01 : RGB 565 */ +#define FMT_RGB555 0x08 /* 10 : RGB 555 */ +#define FMT_RGB444 0x0c /* 11 : RGB 444 */ + /* Output format control */ +#define OFMT_YUV 0x00 /* 00 : YUV */ +#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */ +#define OFMT_RGB 0x02 /* 10 : RGB */ +#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */ + +/* COM8 */ +#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */ + /* AEC Setp size limit */ +#define UNLMT_STEP 0x40 /* 0 : Step size is limited */ + /* 1 : Unlimited step size */ +#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */ +#define AEC_BND 0x10 /* Enable AEC below banding value */ +#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */ +#define AGC_ON 0x04 /* AGC Enable */ +#define AWB_ON 0x02 /* AWB Enable */ +#define AEC_ON 0x01 /* AEC Enable */ + +/* COM9 */ +#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */ + /* Automatic gain ceiling - maximum AGC value */ +#define GAIN_2x 0x00 /* 000 : 2x */ +#define GAIN_4x 0x10 /* 001 : 4x */ +#define GAIN_8x 0x20 /* 010 : 8x */ +#define GAIN_16x 0x30 /* 011 : 16x */ +#define GAIN_32x 0x40 /* 100 : 32x */ +#define GAIN_64x 0x50 /* 101 : 64x */ +#define GAIN_128x 0x60 /* 110 : 128x */ +#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ +#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ + +/* COM11 */ +#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */ +#define SGLF_TRIG 0x01 /* Single frame transfer trigger */ + +/* EXHCH */ +#define VSIZE_LSB 0x04 /* Vertical data output size LSB */ + +/* DSP_CTRL1 */ +#define FIFO_ON 0x80 /* FIFO enable/disable selection */ +#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */ +#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */ +#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */ +#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */ +#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */ +#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */ +#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */ + +/* DSP_CTRL3 */ +#define UV_MASK 0x80 /* UV output sequence option */ +#define UV_ON 0x80 /* ON */ +#define UV_OFF 0x00 /* OFF */ +#define CBAR_MASK 0x20 /* DSP Color bar mask */ +#define CBAR_ON 0x20 /* ON */ +#define CBAR_OFF 0x00 /* OFF */ + +/* HSTART */ +#define HST_VGA 0x23 +#define HST_QVGA 0x3F + +/* HSIZE */ +#define HSZ_VGA 0xA0 +#define HSZ_QVGA 0x50 + +/* VSTART */ +#define VST_VGA 0x07 +#define VST_QVGA 0x03 + +/* VSIZE */ +#define VSZ_VGA 0xF0 +#define VSZ_QVGA 0x78 + +/* HOUTSIZE */ +#define HOSZ_VGA 0xA0 +#define HOSZ_QVGA 0x50 + +/* VOUTSIZE */ +#define VOSZ_VGA 0xF0 +#define VOSZ_QVGA 0x78 + +/* + * bit configure (32 bit) + * this is used in struct ov772x_color_format :: option + */ +#define OP_UV 0x00000001 +#define OP_SWAP_RGB 0x00000002 + +/* + * struct + */ +struct regval_list { + unsigned char reg_num; + unsigned char value; +}; + +struct ov772x_color_format { + char *name; + __u32 fourcc; + const struct regval_list *regs; + unsigned int option; +}; + +struct ov772x_win_size { + char *name; + __u32 width; + __u32 height; + unsigned char com7_bit; + const struct regval_list *regs; +}; + +struct ov772x_priv { + struct ov772x_camera_info *info; + struct i2c_client *client; + struct soc_camera_device icd; + const struct ov772x_color_format *fmt; + const struct ov772x_win_size *win; +}; + +#define ENDMARKER { 0xff, 0xff } + +static const struct regval_list ov772x_default_regs[] = +{ + { COM3, 0x00 }, + { COM4, PLL_4x | 0x01 }, + { 0x16, 0x00 }, /* Mystery */ + { COM11, 0x10 }, /* Mystery */ + { 0x28, 0x00 }, /* Mystery */ + { HREF, 0x00 }, + { COM13, 0xe2 }, /* Mystery */ + { AREF0, 0xef }, + { AREF2, 0x60 }, + { AREF6, 0x7a }, + ENDMARKER, +}; + +/* + * register setting for color format + */ +static const struct regval_list ov772x_RGB555_regs[] = { + { COM7, FMT_RGB555 | OFMT_RGB }, + ENDMARKER, +}; + +static const struct regval_list ov772x_RGB565_regs[] = { + { COM7, FMT_RGB565 | OFMT_RGB }, + ENDMARKER, +}; + +static const struct regval_list ov772x_YYUV_regs[] = { + { COM3, SWAP_YUV }, + { COM7, OFMT_YUV }, + ENDMARKER, +}; + +static const struct regval_list ov772x_UVYY_regs[] = { + { COM7, OFMT_YUV }, + ENDMARKER, +}; + + +/* + * register setting for window size + */ +static const struct regval_list ov772x_qvga_regs[] = { + { HSTART, HST_QVGA }, + { HSIZE, HSZ_QVGA }, + { VSTART, VST_QVGA }, + { VSIZE, VSZ_QVGA }, + { HOUTSIZE, HOSZ_QVGA }, + { VOUTSIZE, VOSZ_QVGA }, + ENDMARKER, +}; + +static const struct regval_list ov772x_vga_regs[] = { + { HSTART, HST_VGA }, + { HSIZE, HSZ_VGA }, + { VSTART, VST_VGA }, + { VSIZE, VSZ_VGA }, + { HOUTSIZE, HOSZ_VGA }, + { VOUTSIZE, VOSZ_VGA }, + ENDMARKER, +}; + +/* + * supported format list + */ + +#define SETFOURCC(type) .name = (#type), .fourcc = (V4L2_PIX_FMT_ ## type) +static const struct soc_camera_data_format ov772x_fmt_lists[] = { + { + SETFOURCC(YUYV), + .depth = 16, + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + SETFOURCC(YVYU), + .depth = 16, + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + SETFOURCC(UYVY), + .depth = 16, + .colorspace = V4L2_COLORSPACE_JPEG, + }, + { + SETFOURCC(RGB555), + .depth = 16, + .colorspace = V4L2_COLORSPACE_SRGB, + }, + { + SETFOURCC(RGB555X), + .depth = 16, + .colorspace = V4L2_COLORSPACE_SRGB, + }, + { + SETFOURCC(RGB565), + .depth = 16, + .colorspace = V4L2_COLORSPACE_SRGB, + }, + { + SETFOURCC(RGB565X), + .depth = 16, + .colorspace = V4L2_COLORSPACE_SRGB, + }, +}; + +/* + * color format list + */ +#define T_YUYV 0 +static const struct ov772x_color_format ov772x_cfmts[] = { + [T_YUYV] = { + SETFOURCC(YUYV), + .regs = ov772x_YYUV_regs, + }, + { + SETFOURCC(YVYU), + .regs = ov772x_YYUV_regs, + .option = OP_UV, + }, + { + SETFOURCC(UYVY), + .regs = ov772x_UVYY_regs, + }, + { + SETFOURCC(RGB555), + .regs = ov772x_RGB555_regs, + .option = OP_SWAP_RGB, + }, + { + SETFOURCC(RGB555X), + .regs = ov772x_RGB555_regs, + }, + { + SETFOURCC(RGB565), + .regs = ov772x_RGB565_regs, + .option = OP_SWAP_RGB, + }, + { + SETFOURCC(RGB565X), + .regs = ov772x_RGB565_regs, + }, +}; + + +/* + * window size list + */ +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 +#define QVGA_WIDTH 320 +#define QVGA_HEIGHT 240 +#define MAX_WIDTH VGA_WIDTH +#define MAX_HEIGHT VGA_HEIGHT + +static const struct ov772x_win_size ov772x_win_vga = { + .name = "VGA", + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .com7_bit = SLCT_VGA, + .regs = ov772x_vga_regs, +}; + +static const struct ov772x_win_size ov772x_win_qvga = { + .name = "QVGA", + .width = QVGA_WIDTH, + .height = QVGA_HEIGHT, + .com7_bit = SLCT_QVGA, + .regs = ov772x_qvga_regs, +}; + + +/* + * general function + */ + +static int ov772x_write_array(struct i2c_client *client, + const struct regval_list *vals) +{ + while (vals->reg_num != 0xff) { + int ret = i2c_smbus_write_byte_data(client, + vals->reg_num, + vals->value); + if (ret < 0) + return ret; + vals++; + } + return 0; +} + +static int ov772x_mask_set(struct i2c_client *client, + u8 command, + u8 mask, + u8 set) +{ + s32 val = i2c_smbus_read_byte_data(client, command); + val &= ~mask; + val |= set; + + return i2c_smbus_write_byte_data(client, command, val); +} + +static int ov772x_reset(struct i2c_client *client) +{ + int ret = i2c_smbus_write_byte_data(client, COM7, SCCB_RESET); + msleep(1); + return ret; +} + +/* + * soc_camera_ops function + */ + +static int ov772x_init(struct soc_camera_device *icd) +{ + return 0; +} + +static int ov772x_release(struct soc_camera_device *icd) +{ + return 0; +} + +static int ov772x_start_capture(struct soc_camera_device *icd) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret; + + + if (!priv->win) + priv->win = &ov772x_win_vga; + if (!priv->fmt) + priv->fmt = &ov772x_cfmts[T_YUYV]; + + /* + * reset hardware + */ + ov772x_reset(priv->client); + ret = ov772x_write_array(priv->client, ov772x_default_regs); + if (ret < 0) + goto start_end; + + /* + * set color format + */ + ret = ov772x_write_array(priv->client, priv->fmt->regs); + if (ret < 0) + goto start_end; + + /* + * set size format + */ + ret = ov772x_write_array(priv->client, priv->win->regs); + if (ret < 0) + goto start_end; + + /* + * set COM7 bit ( QVGA or VGA ) + */ + ret = ov772x_mask_set(priv->client, + COM7, SLCT_MASK, priv->win->com7_bit); + if (ret < 0) + goto start_end; + + /* + * set UV setting + */ + if (priv->fmt->option & OP_UV) { + ret = ov772x_mask_set(priv->client, + DSP_CTRL3, UV_MASK, UV_ON); + if (ret < 0) + goto start_end; + } + + /* + * set SWAP setting + */ + if (priv->fmt->option & OP_SWAP_RGB) { + ret = ov772x_mask_set(priv->client, + COM3, SWAP_MASK, SWAP_RGB); + if (ret < 0) + goto start_end; + } + + dev_info(&icd->dev, + "format %s, win %s\n", priv->fmt->name, priv->win->name); + +start_end: + priv->fmt = NULL; + priv->win = NULL; + + return ret; +} + +static int ov772x_stop_capture(struct soc_camera_device *icd) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + ov772x_reset(priv->client); + return 0; +} + +static int ov772x_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + + return SOCAM_PCLK_SAMPLE_RISING | + SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_MASTER | + priv->info->buswidth; +} + +static int ov772x_get_chip_id(struct soc_camera_device *icd, + struct v4l2_chip_ident *id) +{ + id->ident = V4L2_IDENT_OV772X; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov772x_get_register(struct soc_camera_device *icd, + struct v4l2_register *reg) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret; + + if (reg->reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_byte_data(priv->client, reg->reg); + if (ret < 0) + return ret; + + reg->val = (__u64)ret; + + return 0; +} + +static int ov772x_set_register(struct soc_camera_device *icd, + struct v4l2_register *reg) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + + if (reg->reg > 0xff || + reg->val > 0xff) + return -EINVAL; + + return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val); +} +#endif + +static int ov772x_set_fmt_cap(struct soc_camera_device *icd, + __u32 pixfmt, + struct v4l2_rect *rect) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret = -EINVAL; + int i; + + /* + * select format + */ + priv->fmt = NULL; + for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { + if (pixfmt == ov772x_cfmts[i].fourcc) { + priv->fmt = ov772x_cfmts + i; + ret = 0; + break; + } + } + + return ret; +} + +static int ov772x_try_fmt_cap(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + struct ov772x_priv *priv; + + priv = container_of(icd, struct ov772x_priv, icd); + + /* QVGA */ + if (pix->width <= ov772x_win_qvga.width || + pix->height <= ov772x_win_qvga.height) { + priv->win = &ov772x_win_qvga; + pix->width = ov772x_win_qvga.width; + pix->height = ov772x_win_qvga.height; + } + + /* VGA */ + else if (pix->width <= ov772x_win_vga.width || + pix->height <= ov772x_win_vga.height) { + priv->win = &ov772x_win_vga; + pix->width = ov772x_win_vga.width; + pix->height = ov772x_win_vga.height; + } + + pix->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov772x_video_probe(struct soc_camera_device *icd) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + u8 pid, ver; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + /* + * ov772x only use 8 or 10 bit bus width + */ + if (SOCAM_DATAWIDTH_10 != priv->info->buswidth && + SOCAM_DATAWIDTH_8 != priv->info->buswidth) { + dev_err(&icd->dev, "bus width error\n"); + return -ENODEV; + } + + icd->formats = ov772x_fmt_lists; + icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists); + + if (priv->info->link.power) + priv->info->link.power(&priv->client->dev, 1); + + /* + * check and show product ID and manufacturer ID + */ + pid = i2c_smbus_read_byte_data(priv->client, PID); + ver = i2c_smbus_read_byte_data(priv->client, VER); + if (pid != 0x77 || + ver != 0x21) { + if (priv->info->link.power) + priv->info->link.power(&priv->client->dev, 0); + return -ENODEV; + } + + dev_info(&icd->dev, + "ov772x Product ID %0x:%0x Manufacturer ID %x:%x\n", + pid, + ver, + i2c_smbus_read_byte_data(priv->client, MIDH), + i2c_smbus_read_byte_data(priv->client, MIDL)); + + + return soc_camera_video_start(icd); +} + +static void ov772x_video_remove(struct soc_camera_device *icd) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + + soc_camera_video_stop(icd); + + if (priv->info->link.power) + priv->info->link.power(&priv->client->dev, 0); + +} + +static struct soc_camera_ops ov772x_ops = { + .owner = THIS_MODULE, + .probe = ov772x_video_probe, + .remove = ov772x_video_remove, + .init = ov772x_init, + .release = ov772x_release, + .start_capture = ov772x_start_capture, + .stop_capture = ov772x_stop_capture, + .set_fmt_cap = ov772x_set_fmt_cap, + .try_fmt_cap = ov772x_try_fmt_cap, + .set_bus_param = ov772x_set_bus_param, + .query_bus_param = ov772x_query_bus_param, + .get_chip_id = ov772x_get_chip_id, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .get_register = ov772x_get_register, + .set_register = ov772x_set_register, +#endif +}; + +/* + * i2c_driver function + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) +static int ov772x_probe(struct i2c_client *client) +#else +static int ov772x_probe(struct i2c_client *client, + const struct i2c_device_id *did) +#endif +{ + struct ov772x_priv *priv; + struct ov772x_camera_info *info; + struct soc_camera_device *icd; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; + + info = client->dev.platform_data; + if (!info) + return -EINVAL; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&adapter->dev, + "I2C-Adapter doesn't support " + "I2C_FUNC_SMBUS_BYTE_DATA\n"); + return -EIO; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = info; + priv->client = client; + i2c_set_clientdata(client, priv); + + icd = &priv->icd; + icd->ops = &ov772x_ops; + icd->control = &client->dev; + icd->width_max = MAX_WIDTH; + icd->height_max = MAX_HEIGHT; + icd->iface = priv->info->link.bus_id; + + ret = soc_camera_device_register(icd); + + if (ret) + kfree(priv); + + return ret; +} + +static int ov772x_remove(struct i2c_client *client) +{ + struct ov772x_priv *priv = i2c_get_clientdata(client); + + soc_camera_device_unregister(&priv->icd); + kfree(priv); + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static const struct i2c_device_id ov772x_id[] = { + {"ov772x", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov772x_id); +#endif + +static struct i2c_driver ov772x_i2c_driver = { + .driver = { + .name = "ov772x", + }, + .probe = ov772x_probe, + .remove = ov772x_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + .id_table = ov772x_id, +#endif +}; + +/* + * module function + */ + +static int __init ov772x_module_init(void) +{ + printk(KERN_INFO "ov772x driver\n"); + return i2c_add_driver(&ov772x_i2c_driver); +} + +static void __exit ov772x_module_exit(void) +{ + i2c_del_driver(&ov772x_i2c_driver); +} + +module_init(ov772x_module_init); +module_exit(ov772x_module_exit); + +MODULE_DESCRIPTION("SoC Camera driver for ov772x"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); diff --git a/linux/drivers/media/video/pms.c b/linux/drivers/media/video/pms.c index 00b623e00..522f75def 100644 --- a/linux/drivers/media/video/pms.c +++ b/linux/drivers/media/video/pms.c @@ -10,8 +10,8 @@ * 14478 Potsdam, Germany * * Most of this code is directly derived from his userspace driver. - * His driver works so send any reports to alan@redhat.com unless the - * userspace driver also doesn't work for you... + * His driver works so send any reports to alan@lxorguk.ukuu.org.uk + * unless the userspace driver also doesn't work for you... * * Changes: * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it> @@ -681,8 +681,7 @@ static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int * Video4linux interfacing */ -static int pms_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int pms_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); struct pms_device *pd=(struct pms_device *)dev; @@ -867,7 +866,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file, static int pms_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, pms_do_ioctl); + return video_usercopy(file, cmd, arg, pms_do_ioctl); } static ssize_t pms_read(struct file *file, char __user *buf, diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c index da5b5a7e9..744bc192c 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -435,6 +435,10 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0); ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0); + /* prevent the PTSs from slowly drifting away in the generated + MPEG stream */ + ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC, 2, 4, 1); + return ret; } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index b79829f8a..447fcede8 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -61,7 +61,6 @@ static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; static DEFINE_MUTEX(pvr2_unit_mtx); static int ctlchg; -static int initusbreset = 1; static int procreload; static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; @@ -72,8 +71,6 @@ module_param(ctlchg, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); module_param(init_pause_msec, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); -module_param(initusbreset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe"); module_param(procreload, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(procreload, "Attempt init failure recovery with firmware reload"); @@ -1984,9 +1981,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } hdw->fw1_state = FW1_STATE_OK; - if (initusbreset) { - pvr2_hdw_device_reset(hdw); - } if (!pvr2_hdw_dev_ok(hdw)) return; for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) { @@ -2425,7 +2419,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, scnprintf(hdw->bus_info,sizeof(hdw->bus_info), "usb %s address %d", - hdw->usb_dev->dev.bus_id, + dev_name(&hdw->usb_dev->dev), hdw->usb_dev->devnum); ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 16461dd92..770f31e60 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -637,10 +637,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->class = &class_ptr->class; if (pvr2_hdw_get_sn(sfp->channel.hdw)) { - snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu", + dev_set_name(class_dev, "sn-%lu", pvr2_hdw_get_sn(sfp->channel.hdw)); } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { - snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c", + dev_set_name(class_dev, "unit-%c", pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); } else { kfree(class_dev); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 429c96d4f..09fabfd2f 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -169,8 +169,7 @@ static const char *get_v4l_name(int v4l_type) * This is part of Video 4 Linux API. The procedure handles ioctl() calls. * */ -static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_v4l2 *vp = fh->vhead; @@ -864,8 +863,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, #endif default : - ret = v4l_compat_translate_ioctl(inode,file,cmd, - arg,pvr2_v4l2_do_ioctl); + ret = v4l_compat_translate_ioctl(file, cmd, + arg, pvr2_v4l2_do_ioctl); } pvr2_hdw_commit_ctl(hdw); @@ -891,10 +890,9 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, return ret; } - static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) { - int minor_id = dip->devbase.minor; + int num = dip->devbase.num; struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; enum pvr2_config cfg = dip->config; int v4l_type = dip->v4l_type; @@ -910,7 +908,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) video_unregister_device(&dip->devbase); printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n", - get_v4l_name(v4l_type),minor_id & 0x1f, + get_v4l_name(v4l_type), num, pvr2_config_get_name(cfg)); } @@ -959,7 +957,7 @@ static int pvr2_v4l2_ioctl(struct inode *inode, struct file *file, #define IVTV_IOC_G_CODEC 0xFFEE7703 #define IVTV_IOC_S_CODEC 0xFFEE7704 if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0; - return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl); + return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl); } @@ -1317,7 +1315,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, } printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n", - get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f, + get_v4l_name(dip->v4l_type), dip->devbase.num, pvr2_config_get_name(dip->config)); pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index 69917b2f9..d657e6f8d 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -1416,7 +1416,7 @@ static int pwc_video_ioctl(struct inode *inode, struct file *file, mutex_lock(&pdev->modlock); if (!pdev->unplugged) - r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); + r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl); mutex_unlock(&pdev->modlock); out: return r; @@ -1799,7 +1799,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id goto err; } else { - PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); + PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num); } /* occupy slot */ diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c index 76a1376c9..d7c147328 100644 --- a/linux/drivers/media/video/pwc/pwc-v4l.c +++ b/linux/drivers/media/video/pwc/pwc-v4l.c @@ -337,8 +337,7 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) } -int pwc_video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +int pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct pwc_device *pdev; diff --git a/linux/drivers/media/video/pwc/pwc.h b/linux/drivers/media/video/pwc/pwc.h index 926defb11..ade796037 100644 --- a/linux/drivers/media/video/pwc/pwc.h +++ b/linux/drivers/media/video/pwc/pwc.h @@ -341,8 +341,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power); extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); /** Functions in pwc-v4l.c */ -extern int pwc_video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg); +extern int pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg); /** pwc-uncompress.c */ /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index 5a872787e..ab9814144 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -193,7 +193,7 @@ struct s2255_dmaqueue { #define S2255_FW_FAILED 3 #define S2255_FW_DISCONNECTING 4 -#define S2255_FW_MARKER 0x22552f2f +#define S2255_FW_MARKER cpu_to_le32(0x22552f2f) /* 2255 read states */ #define S2255_READ_IDLE 0 #define S2255_READ_FRAME 1 diff --git a/linux/drivers/media/video/saa5246a.c b/linux/drivers/media/video/saa5246a.c index 355490467..086fc807a 100644 --- a/linux/drivers/media/video/saa5246a.c +++ b/linux/drivers/media/video/saa5246a.c @@ -15,7 +15,7 @@ * <richard.guenther@student.uni-tuebingen.de> * * with changes by - * Alan Cox <Alan.Cox@linux.org> + * Alan Cox <alan@lxorguk.ukuu.org.uk> * * and * @@ -805,8 +805,7 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t, * * Returns 0 if successful */ -static int do_saa5246a_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg) { struct saa5246a_device *t = video_drvdata(file); @@ -954,7 +953,7 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file, cmd = vtx_fix_command(cmd); mutex_lock(&t->lock); - err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl); + err = video_usercopy(file, cmd, arg, do_saa5246a_ioctl); mutex_unlock(&t->lock); return err; } diff --git a/linux/drivers/media/video/saa5249.c b/linux/drivers/media/video/saa5249.c index 2f63455d3..86352dbe7 100644 --- a/linux/drivers/media/video/saa5249.c +++ b/linux/drivers/media/video/saa5249.c @@ -8,7 +8,7 @@ * you can add arbitary multiple teletext devices to Linux video4linux * now (well 32 anyway). * - * Alan Cox <Alan.Cox@linux.org> + * Alan Cox <alan@lxorguk.ukuu.org.uk> * * The original driver was heavily modified to match the i2c interface * It was truncated to use the WinTV boards, too. @@ -191,8 +191,7 @@ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf) * Standard character-device-driver functions */ -static int do_saa5249_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg) { static int virtual_mode = false; struct saa5249_device *t = video_drvdata(file); @@ -489,7 +488,7 @@ static int saa5249_ioctl(struct inode *inode, struct file *file, cmd = vtx_fix_command(cmd); mutex_lock(&t->lock); - err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl); + err = video_usercopy(file, cmd, arg, do_saa5249_ioctl); mutex_unlock(&t->lock); return err; } diff --git a/linux/drivers/media/video/saa7110.c b/linux/drivers/media/video/saa7110.c index 15eb8bd7a..b7afe3124 100644 --- a/linux/drivers/media/video/saa7110.c +++ b/linux/drivers/media/video/saa7110.c @@ -48,7 +48,7 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ -#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ +#define SAA7110_MAX_OUTPUT 1 /* 1 YUV */ #define SAA7110_NR_REG 0x35 @@ -328,7 +328,7 @@ saa7110_command (struct i2c_client *client, case DECODER_SET_INPUT: v = *(int *) arg; - if (v < 0 || v > SAA7110_MAX_INPUT) { + if (v < 0 || v >= SAA7110_MAX_INPUT) { v4l_dbg(1, debug, client, "input=%d not available\n", v); return -EINVAL; } diff --git a/linux/drivers/media/video/saa7127.c b/linux/drivers/media/video/saa7127.c index 0b126a849..fd7d15305 100644 --- a/linux/drivers/media/video/saa7127.c +++ b/linux/drivers/media/video/saa7127.c @@ -29,7 +29,7 @@ * Note: the saa7126 is identical to the saa7127, and the saa7128 is * identical to the saa7129, except that the saa7126 and saa7128 have * macrovision anti-taping support. This driver will almost certainly - * work find for those chips, except of course for the missing anti-taping + * work fine for those chips, except of course for the missing anti-taping * support. * * This program is free software; you can redistribute it and/or modify diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index c839114a0..2e9a015e9 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -1002,7 +1002,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->name,(unsigned long long)pci_resource_start(pci_dev,0)); goto fail1; } - dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000); + dev->lmmio = ioremap(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; @@ -1057,7 +1058,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, goto fail4; } printk(KERN_INFO "%s: registered device video%d [v4l2]\n", - dev->name,dev->video_dev->minor & 0x1f); + dev->name, dev->video_dev->num); dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); @@ -1066,7 +1067,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (err < 0) goto fail4; printk(KERN_INFO "%s: registered device vbi%d\n", - dev->name,dev->vbi_dev->minor & 0x1f); + dev->name, dev->vbi_dev->num); if (card_has_radio(dev)) { dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); @@ -1075,7 +1076,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (err < 0) goto fail4; printk(KERN_INFO "%s: registered device radio%d\n", - dev->name,dev->radio_dev->minor & 0x1f); + dev->name, dev->radio_dev->num); } /* everything worked */ diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 11a7c76bc..704442f55 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -953,21 +953,15 @@ static int dvb_init(struct saa7134_dev *dev) /* FIXME: add support for multi-frontend */ mutex_init(&dev->frontends.lock); - INIT_LIST_HEAD(&dev->frontends.frontend.felist); - dev->frontends.active_fe_id = 0; + INIT_LIST_HEAD(&dev->frontends.felist); printk(KERN_INFO "%s() allocating 1 frontend\n", __func__); - - if (videobuf_dvb_alloc_frontend(dev, &dev->frontends, 1) == NULL) { + fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1); + if (!fe0) { printk(KERN_ERR "%s() failed to alloc\n", __func__); return -ENOMEM; } - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); - if (!fe0) - return -EINVAL; - /* init struct videobuf_dvb */ dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; @@ -1380,7 +1374,7 @@ static int dvb_init(struct saa7134_dev *dev) }; if (!fe0->dvb.frontend) - return -1; + goto dettach_frontend; fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { @@ -1392,7 +1386,7 @@ static int dvb_init(struct saa7134_dev *dev) if (NULL == fe0->dvb.frontend) { printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); - return -1; + goto dettach_frontend; } /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = saa7134_tuner_callback; @@ -1415,11 +1409,8 @@ static int dvb_init(struct saa7134_dev *dev) return ret; dettach_frontend: - if (fe0->dvb.frontend) - dvb_frontend_detach(fe0->dvb.frontend); - fe0->dvb.frontend = NULL; - - return -1; + videobuf_dvb_dealloc_frontends(&dev->frontends); + return -EINVAL; } static int dvb_fini(struct saa7134_dev *dev) @@ -1458,8 +1449,7 @@ static int dvb_fini(struct saa7134_dev *dev) } } } - if (fe0->dvb.frontend) - videobuf_dvb_unregister_bus(&dev->frontends); + videobuf_dvb_unregister_bus(&dev->frontends); return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c index 9ebe166cc..53de5545c 100644 --- a/linux/drivers/media/video/saa7134/saa7134-empress.c +++ b/linux/drivers/media/video/saa7134/saa7134-empress.c @@ -546,7 +546,7 @@ static int empress_init(struct saa7134_dev *dev) return err; } printk(KERN_INFO "%s: registered device video%d [mpeg]\n", - dev->name,dev->empress_dev->minor & 0x1f); + dev->name, dev->empress_dev->num); videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops, &dev->pci->dev, &dev->slock, diff --git a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c index f7a3f1d0a..477d9e091 100644 --- a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -161,7 +161,7 @@ static struct saa7134_tvaudio tvaudio[] = { .mode = TVAUDIO_FM_MONO, } }; -#define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio)) +#define TVAUDIO ARRAY_SIZE(tvaudio) /* ------------------------------------------------------------------ */ diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index 837fc5424..82f9a889a 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -277,7 +277,7 @@ struct saa7134_format { #define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151 #define SAA7134_BOARD_ASUSTeK_TIGER 152 -#define SAA7134_MAXBOARDS 8 +#define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 /* ----------------------------------------------------------- */ diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c index 5a346d0c5..8935c1632 100644 --- a/linux/drivers/media/video/se401.c +++ b/linux/drivers/media/video/se401.c @@ -983,8 +983,7 @@ static int se401_close(struct inode *inode, struct file *file) return 0; } -static int se401_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int se401_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = file->private_data; struct usb_se401 *se401 = (struct usb_se401 *)vdev; @@ -1150,7 +1149,7 @@ static int se401_do_ioctl(struct inode *inode, struct file *file, static int se401_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, se401_do_ioctl); + return video_usercopy(file, cmd, arg, se401_do_ioctl); } static ssize_t se401_read(struct file *file, char __user *buf, @@ -1420,7 +1419,7 @@ static int se401_probe(struct usb_interface *intf, return -EIO; } dev_info(&intf->dev, "registered new video device: video%d\n", - se401->vdev.minor); + se401->vdev.num); usb_set_intfdata (intf, se401); return 0; diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index 76838091d..2fb8bee0b 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -37,42 +37,43 @@ #include <media/soc_camera.h> #include <media/sh_mobile_ceu.h> #include <media/videobuf-dma-contig.h> +#include "compat.h" /* register offsets for sh7722 / sh7723 */ -#define CAPSR 0x00 -#define CAPCR 0x04 -#define CAMCR 0x08 -#define CMCYR 0x0c -#define CAMOR 0x10 -#define CAPWR 0x14 -#define CAIFR 0x18 -#define CSTCR 0x20 /* not on sh7723 */ -#define CSECR 0x24 /* not on sh7723 */ -#define CRCNTR 0x28 -#define CRCMPR 0x2c -#define CFLCR 0x30 -#define CFSZR 0x34 -#define CDWDR 0x38 -#define CDAYR 0x3c -#define CDACR 0x40 -#define CDBYR 0x44 -#define CDBCR 0x48 -#define CBDSR 0x4c -#define CFWCR 0x5c -#define CLFCR 0x60 -#define CDOCR 0x64 -#define CDDCR 0x68 -#define CDDAR 0x6c -#define CEIER 0x70 -#define CETCR 0x74 -#define CSTSR 0x7c -#define CSRTR 0x80 -#define CDSSR 0x84 -#define CDAYR2 0x90 -#define CDACR2 0x94 -#define CDBYR2 0x98 -#define CDBCR2 0x9c +#define CAPSR 0x00 /* Capture start register */ +#define CAPCR 0x04 /* Capture control register */ +#define CAMCR 0x08 /* Capture interface control register */ +#define CMCYR 0x0c /* Capture interface cycle register */ +#define CAMOR 0x10 /* Capture interface offset register */ +#define CAPWR 0x14 /* Capture interface width register */ +#define CAIFR 0x18 /* Capture interface input format register */ +#define CSTCR 0x20 /* Camera strobe control register (<= sh7722) */ +#define CSECR 0x24 /* Camera strobe emission count register (<= sh7722) */ +#define CRCNTR 0x28 /* CEU register control register */ +#define CRCMPR 0x2c /* CEU register forcible control register */ +#define CFLCR 0x30 /* Capture filter control register */ +#define CFSZR 0x34 /* Capture filter size clip register */ +#define CDWDR 0x38 /* Capture destination width register */ +#define CDAYR 0x3c /* Capture data address Y register */ +#define CDACR 0x40 /* Capture data address C register */ +#define CDBYR 0x44 /* Capture data bottom-field address Y register */ +#define CDBCR 0x48 /* Capture data bottom-field address C register */ +#define CBDSR 0x4c /* Capture bundle destination size register */ +#define CFWCR 0x5c /* Firewall operation control register */ +#define CLFCR 0x60 /* Capture low-pass filter control register */ +#define CDOCR 0x64 /* Capture data output control register */ +#define CDDCR 0x68 /* Capture data complexity level register */ +#define CDDAR 0x6c /* Capture data complexity level address register */ +#define CEIER 0x70 /* Capture event interrupt enable register */ +#define CETCR 0x74 /* Capture event flag clear register */ +#define CSTSR 0x7c /* Capture status register */ +#define CSRTR 0x80 /* Capture software reset register */ +#define CDSSR 0x84 /* Capture data size register */ +#define CDAYR2 0x90 /* Capture data address Y register 2 */ +#define CDACR2 0x94 /* Capture data address C register 2 */ +#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ +#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ static DEFINE_MUTEX(camera_lock); @@ -165,6 +166,7 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10); if (pcdev->active) { + pcdev->active->state = VIDEOBUF_ACTIVE; ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active)); ceu_write(pcdev, CAPSR, 0x1); /* start capture */ } @@ -236,7 +238,7 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); - vb->state = VIDEOBUF_ACTIVE; + vb->state = VIDEOBUF_QUEUED; spin_lock_irqsave(&pcdev->lock, flags); list_add_tail(&vb->queue, &pcdev->capture); @@ -323,12 +325,24 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; + unsigned long flags; BUG_ON(icd != pcdev->icd); /* disable capture, disable interrupts */ ceu_write(pcdev, CEIER, 0); ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ + + /* make sure active buffer is canceled */ + spin_lock_irqsave(&pcdev->lock, flags); + if (pcdev->active) { + list_del(&pcdev->active->queue); + pcdev->active->state = VIDEOBUF_ERROR; + wake_up_all(&pcdev->active->done); + pcdev->active = NULL; + } + spin_unlock_irqrestore(&pcdev->lock, flags); + icd->ops->release(icd); dev_info(&icd->dev, @@ -391,7 +405,20 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */ ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width); ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */ - ceu_write(pcdev, CDOCR, 0x00000016); + + /* A few words about byte order (observed in Big Endian mode) + * + * In data fetch mode bytes are received in chunks of 8 bytes. + * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) + * + * The data is however by default written to memory in reverse order: + * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) + * + * The lowest three bits of CDOCR allows us to do swapping, + * using 7 we swap the data bytes to match the incoming order: + * D0, D1, D2, D3, D4, D5, D6, D7 + */ + ceu_write(pcdev, CDOCR, 0x00000017); ceu_write(pcdev, CDWDR, cdwdr_width); ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ @@ -583,7 +610,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) /* request irq */ err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED, - pdev->dev.bus_id, pcdev); + dev_name(&pdev->dev), pcdev); if (err) { dev_err(&pdev->dev, "Unable to register CEU interrupt.\n"); goto exit_release_mem; @@ -592,8 +619,8 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) pcdev->ici.priv = pcdev; pcdev->ici.dev.parent = &pdev->dev; pcdev->ici.nr = pdev->id; - pcdev->ici.drv_name = pdev->dev.bus_id, - pcdev->ici.ops = &sh_mobile_ceu_host_ops, + pcdev->ici.drv_name = dev_name(&pdev->dev); + pcdev->ici.ops = &sh_mobile_ceu_host_ops; err = soc_camera_host_register(&pcdev->ici); if (err) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c index fd867dadf..3ce12faf5 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_core.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c @@ -1012,7 +1012,7 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam) cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. " "To use it, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -1738,7 +1738,7 @@ static void sn9c102_release_resources(struct kref *kref) cam = container_of(kref, struct sn9c102_device, kref); - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); @@ -1796,7 +1796,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) if (cam->users) { DBG(2, "Device /dev/video%d is already in use", - cam->v4ldev->minor); + cam->v4ldev->num); DBG(3, "Simultaneous opens are not supported"); /* open() must follow the open flags and should block @@ -1849,7 +1849,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) cam->frame_count = 0; sn9c102_empty_framequeues(cam); - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); + DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); out: mutex_unlock(&cam->open_mutex); @@ -1874,7 +1874,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); + DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); kref_put(&cam->kref, sn9c102_release_resources); @@ -2166,7 +2166,7 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, + strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), sizeof(cap.bus_info)); if (copy_to_user(arg, &cap, sizeof(cap))) @@ -2436,7 +2436,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -2449,7 +2449,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -ENOMEM; } @@ -2693,7 +2693,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -2705,7 +2705,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -ENOMEM; } @@ -2752,7 +2752,7 @@ sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->minor); + "/dev/video%d again.", cam->v4ldev->num); return -EIO; } @@ -3352,7 +3352,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); video_set_drvdata(cam->v4ldev, cam); cam->module_param.force_munmap = force_munmap[dev_nr]; @@ -3406,7 +3406,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf) if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " "memory deallocation are deferred.", - cam->v4ldev->minor); + cam->v4ldev->num); cam->state |= DEV_MISCONFIGURED; sn9c102_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index e23734f6d..b0d9d9589 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -55,7 +55,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, +#endif /* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, @@ -94,7 +96,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, @@ -113,7 +117,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, /* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 66ebe5956..7a46697c4 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -29,6 +29,7 @@ #include <media/v4l2-dev.h> #include <media/videobuf-core.h> #include <media/soc_camera.h> +#include "compat.h" static LIST_HEAD(hosts); static LIST_HEAD(devices); @@ -783,7 +784,7 @@ int soc_camera_host_register(struct soc_camera_host *ici) return -EINVAL; /* Number might be equal to the platform device ID */ - sprintf(ici->dev.bus_id, "camera_host%d", ici->nr); + dev_set_name(&ici->dev, "camera_host%d", ici->nr); mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { @@ -867,8 +868,7 @@ int soc_camera_device_register(struct soc_camera_device *icd) icd->devnum = num; icd->dev.bus = &soc_camera_bus_type; - snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id), - "%u-%u", icd->iface, icd->devnum); + dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); icd->dev.release = dummy_release; diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c index 1adc257eb..bb7a9d480 100644 --- a/linux/drivers/media/video/soc_camera_platform.c +++ b/linux/drivers/media/video/soc_camera_platform.c @@ -18,15 +18,7 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/soc_camera.h> - -struct soc_camera_platform_info { - int iface; - char *format_name; - unsigned long format_depth; - struct v4l2_pix_format format; - unsigned long bus_param; - int (*set_capture)(struct soc_camera_platform_info *info, int enable); -}; +#include <media/soc_camera_platform.h> struct soc_camera_platform_priv { struct soc_camera_platform_info *info; @@ -44,11 +36,21 @@ soc_camera_platform_get_info(struct soc_camera_device *icd) static int soc_camera_platform_init(struct soc_camera_device *icd) { + struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + + if (p->power) + p->power(1); + return 0; } static int soc_camera_platform_release(struct soc_camera_device *icd) { + struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + + if (p->power) + p->power(0); + return 0; } diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c index f606300e8..9615b7678 100644 --- a/linux/drivers/media/video/stk-webcam.c +++ b/linux/drivers/media/video/stk-webcam.c @@ -1332,7 +1332,7 @@ static int stk_register_video_device(struct stk_camera *dev) 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); + " /dev/video%d\n", dev->vdev.num); return err; } @@ -1427,7 +1427,7 @@ static void stk_camera_disconnect(struct usb_interface *interface) stk_remove_sysfs_files(&dev->vdev); STK_INFO("Syntek USB2.0 Camera release resources " - "video device /dev/video%d\n", dev->vdev.minor); + "video device /dev/video%d\n", dev->vdev.num); video_unregister_device(&dev->vdev); } diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c index f74c08b41..be5ed5940 100644 --- a/linux/drivers/media/video/stv680.c +++ b/linux/drivers/media/video/stv680.c @@ -1137,8 +1137,7 @@ static int stv_close (struct inode *inode, struct file *file) return 0; } -static int stv680_do_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = file->private_data; struct usb_stv *stv680 = video_get_drvdata(vdev); @@ -1308,7 +1307,7 @@ static int stv680_do_ioctl (struct inode *inode, struct file *file, static int stv680_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl); + return video_usercopy(file, cmd, arg, stv680_do_ioctl); } static int stv680_mmap (struct file *file, struct vm_area_struct *vma) @@ -1475,7 +1474,8 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id retval = -EIO; goto error_vdev; } - PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); + PDEBUG(0, "STV(i): registered new video device: video%d", + stv680->vdev->num); usb_set_intfdata (intf, stv680); retval = stv680_create_sysfs_files(stv680->vdev); diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c index 7e670f2bc..0a86c80a2 100644 --- a/linux/drivers/media/video/tvaudio.c +++ b/linux/drivers/media/video/tvaudio.c @@ -1,5 +1,5 @@ /* - * experimental driver for simple i2c audio chips. + * Driver for simple i2c audio chips. * * Copyright (c) 2000 Gerd Knorr * based on code by: @@ -7,6 +7,10 @@ * Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Greg Alexander (galexand@acm.org) * + * Copyright(c) 2005-2008 Mauro Carvalho Chehab + * - Some cleanups, code fixes, etc + * - Convert it to V4L2 API + * * This code is placed under the terms of the GNU General Public License * * OPTIONS: @@ -33,6 +37,7 @@ #include <media/tvaudio.h> #include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv-legacy.h> @@ -61,7 +66,6 @@ typedef int (*checkit)(struct CHIPSTATE*); typedef int (*initialize)(struct CHIPSTATE*); typedef int (*getmode)(struct CHIPSTATE*); typedef void (*setmode)(struct CHIPSTATE*, int mode); -typedef void (*checkmode)(struct CHIPSTATE*); /* i2c command */ typedef struct AUDIOCMD { @@ -82,6 +86,7 @@ struct CHIPDESC { #define CHIP_HAS_VOLUME 1 #define CHIP_HAS_BASSTREBLE 2 #define CHIP_HAS_INPUTSEL 4 +#define CHIP_NEED_CHECKMODE 8 /* various i2c command sequences */ audiocmd init; @@ -99,23 +104,20 @@ struct CHIPDESC { getmode getmode; setmode setmode; - /* check / autoswitch audio after channel switches */ - checkmode checkmode; - /* input switch register + values for v4l inputs */ int inputreg; int inputmap[4]; int inputmute; int inputmask; }; -static struct CHIPDESC chiplist[]; /* current state of the chip */ struct CHIPSTATE { struct i2c_client *c; - /* index into CHIPDESC array */ - int type; + /* chip-specific description - should point to + an entry at CHIPDESC table */ + struct CHIPDESC *desc; /* shadow register set */ audiocmd shadow; @@ -155,7 +157,7 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) { unsigned char buffer[2]; - if (-1 == subaddr) { + if (subaddr < 0) { v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n", chip->c->name, val); chip->shadow.bytes[1] = val; @@ -166,6 +168,13 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) return -1; } } else { + if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(chip->c, + "Tried to access a non-existent register: %d\n", + subaddr); + return -EINVAL; + } + 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; @@ -180,12 +189,20 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) return 0; } -static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask) +static int chip_write_masked(struct CHIPSTATE *chip, + int subaddr, int val, int mask) { if (mask != 0) { - if (-1 == subaddr) { + if (subaddr < 0) { val = (chip->shadow.bytes[1] & ~mask) | (val & mask); } else { + if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(chip->c, + "Tried to access a non-existent register: %d\n", + subaddr); + return -EINVAL; + } + val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask); } } @@ -231,6 +248,15 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) if (0 == cmd->count) return 0; + if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) { + v4l_info(chip->c, + "Tried to access a non-existent register range: %d to %d\n", + cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1); + return -EINVAL; + } + + /* FIXME: it seems that the shadow bytes are wrong bellow !*/ + /* 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]); @@ -266,7 +292,8 @@ static void chip_thread_wake(unsigned long data) static int chip_thread(void *data) { struct CHIPSTATE *chip = data; - struct CHIPDESC *desc = chiplist + chip->type; + struct CHIPDESC *desc = chip->desc; + int mode; v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name); set_freezable(); @@ -285,7 +312,26 @@ static int chip_thread(void *data) continue; /* have a look what's going on */ - desc->checkmode(chip); + mode = desc->getmode(chip); + if (mode == chip->prevmode) + continue; + + /* chip detected a new audio mode - set it */ + v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", + chip->c->name); + + chip->prevmode = mode; + + 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, V4L2_TUNER_MODE_MONO); /* schedule next check */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); @@ -295,29 +341,6 @@ static int chip_thread(void *data) return 0; } -static void generic_checkmode(struct CHIPSTATE *chip) -{ - struct CHIPDESC *desc = chiplist + chip->type; - int mode = desc->getmode(chip); - - if (mode == chip->prevmode) - return; - - v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name); - chip->prevmode = mode; - - 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,V4L2_TUNER_MODE_MONO); -} - /* ---------------------------------------------------------------------- */ /* audio chip descriptions - defines+functions for tda9840 */ @@ -780,7 +803,7 @@ static struct tda9874a_MODES { char *name; audiocmd cmd; } tda9874a_modelist[9] = { - { "A2, B/G", + { "A2, B/G", /* default */ { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} }, { "A2, M (Korea)", { 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} }, @@ -794,7 +817,7 @@ static struct tda9874a_MODES { { 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} }, { "NICAM, B/G", { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} }, - { "NICAM, D/K", /* default */ + { "NICAM, D/K", { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} }, { "NICAM, L", { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} } @@ -989,7 +1012,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip) { if (tda9874a_SIF > 2) tda9874a_SIF = 1; - if (tda9874a_STD > 8) + if (tda9874a_STD >= ARRAY_SIZE(tda9874a_modelist)) tda9874a_STD = 0; if(tda9874a_AMSEL > 1) tda9874a_AMSEL = 0; @@ -1097,7 +1120,7 @@ static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; } static int tda8425_initialize(struct CHIPSTATE *chip) { - struct CHIPDESC *desc = chiplist + chip->type; + struct CHIPDESC *desc = chip->desc; int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1, /* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF}; @@ -1267,27 +1290,28 @@ static struct CHIPDESC chiplist[] = { .addr_lo = I2C_ADDR_TDA9840 >> 1, .addr_hi = I2C_ADDR_TDA9840 >> 1, .registers = 5, + .flags = CHIP_NEED_CHECKMODE, + /* callbacks */ .checkit = tda9840_checkit, .getmode = tda9840_getmode, .setmode = tda9840_setmode, - .checkmode = generic_checkmode, .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN /* ,TDA9840_SW, TDA9840_MONO */} } }, { .name = "tda9873h", - .checkit = tda9873_checkit, .insmodopt = &tda9873, .addr_lo = I2C_ADDR_TDA985x_L >> 1, .addr_hi = I2C_ADDR_TDA985x_H >> 1, .registers = 3, - .flags = CHIP_HAS_INPUTSEL, + .flags = CHIP_HAS_INPUTSEL | CHIP_NEED_CHECKMODE, + /* callbacks */ + .checkit = tda9873_checkit, .getmode = tda9873_getmode, .setmode = tda9873_setmode, - .checkmode = generic_checkmode, .init = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } }, .inputreg = TDA9873_SW, @@ -1298,15 +1322,16 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tda9874h/a", - .checkit = tda9874a_checkit, - .initialize = tda9874a_initialize, .insmodopt = &tda9874a, .addr_lo = I2C_ADDR_TDA9874 >> 1, .addr_hi = I2C_ADDR_TDA9874 >> 1, + .flags = CHIP_NEED_CHECKMODE, + /* callbacks */ + .initialize = tda9874a_initialize, + .checkit = tda9874a_checkit, .getmode = tda9874a_getmode, .setmode = tda9874a_setmode, - .checkmode = generic_checkmode, }, { .name = "tda9850", @@ -1332,10 +1357,11 @@ static struct CHIPDESC chiplist[] = { .rightreg = TDA9855_VR, .bassreg = TDA9855_BA, .treblereg = TDA9855_TR, + + /* callbacks */ .volfunc = tda9855_volume, .bassfunc = tda9855_bass, .treblefunc = tda9855_treble, - .getmode = tda985x_getmode, .setmode = tda985x_setmode, @@ -1356,6 +1382,8 @@ static struct CHIPDESC chiplist[] = { .rightreg = TEA6300_VL, .bassreg = TEA6300_BA, .treblereg = TEA6300_TR, + + /* callbacks */ .volfunc = tea6300_shift10, .bassfunc = tea6300_shift12, .treblefunc = tea6300_shift12, @@ -1366,7 +1394,6 @@ static struct CHIPDESC chiplist[] = { }, { .name = "tea6320", - .initialize = tea6320_initialize, .insmodopt = &tea6320, .addr_lo = I2C_ADDR_TEA6300 >> 1, .addr_hi = I2C_ADDR_TEA6300 >> 1, @@ -1377,6 +1404,9 @@ static struct CHIPDESC chiplist[] = { .rightreg = TEA6320_V, .bassreg = TEA6320_BA, .treblereg = TEA6320_TR, + + /* callbacks */ + .initialize = tea6320_initialize, .volfunc = tea6320_volume, .bassfunc = tea6320_shift11, .treblefunc = tea6320_shift11, @@ -1409,16 +1439,18 @@ static struct CHIPDESC chiplist[] = { .rightreg = TDA8425_VR, .bassreg = TDA8425_BA, .treblereg = TDA8425_TR, + + /* callbacks */ + .initialize = tda8425_initialize, .volfunc = tda8425_shift10, .bassfunc = tda8425_shift12, .treblefunc = tda8425_shift12, + .setmode = tda8425_setmode, .inputreg = TDA8425_S1, .inputmap = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 }, .inputmute = TDA8425_S1_OFF, - .setmode = tda8425_setmode, - .initialize = tda8425_initialize, }, { .name = "pic16c54 (PV951)", @@ -1442,10 +1474,11 @@ static struct CHIPDESC chiplist[] = { .addr_lo = I2C_ADDR_TDA9840 >> 1, .addr_hi = I2C_ADDR_TDA9840 >> 1, .registers = 2, + .flags = CHIP_NEED_CHECKMODE, + /* callbacks */ .getmode = ta8874z_getmode, .setmode = ta8874z_setmode, - .checkmode = generic_checkmode, .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}}, }, @@ -1489,6 +1522,7 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id) } if (desc->name == NULL) { v4l_dbg(1, debug, client, "no matching chip description found\n"); + kfree(chip); return -EIO; } v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); @@ -1501,12 +1535,12 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id) /* fill required data structures */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) - strcpy(client->name, desc->name); + strlcpy(client->name, desc->name, I2C_NAME_SIZE); #else if (!id) strlcpy(client->name, desc->name, I2C_NAME_SIZE); #endif - chip->type = desc-chiplist; + chip->desc = desc; chip->shadow.count = desc->registers+1; chip->prevmode = -1; chip->audmode = V4L2_TUNER_MODE_LANG1; @@ -1518,20 +1552,49 @@ static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id) chip_cmd(chip,"init",&desc->init); if (desc->flags & CHIP_HAS_VOLUME) { - chip->left = desc->leftinit ? desc->leftinit : 65535; - chip->right = desc->rightinit ? desc->rightinit : 65535; - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + if (!desc->volfunc) { + /* This shouldn't be happen. Warn user, but keep working + without volume controls + */ + v4l_info(chip->c, "volume callback undefined!\n"); + desc->flags &= ~CHIP_HAS_VOLUME; + } else { + chip->left = desc->leftinit ? desc->leftinit : 65535; + chip->right = desc->rightinit ? desc->rightinit : 65535; + 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->treble = desc->trebleinit ? desc->trebleinit : 32768; - chip->bass = desc->bassinit ? desc->bassinit : 32768; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); + if (!desc->bassfunc || !desc->treblefunc) { + /* This shouldn't be happen. Warn user, but keep working + without bass/treble controls + */ + v4l_info(chip->c, "bass/treble callbacks undefined!\n"); + desc->flags &= ~CHIP_HAS_BASSTREBLE; + } else { + chip->treble = desc->trebleinit ? + desc->trebleinit : 32768; + chip->bass = desc->bassinit ? + desc->bassinit : 32768; + chip_write(chip, desc->bassreg, + desc->bassfunc(chip->bass)); + chip_write(chip, desc->treblereg, + desc->treblefunc(chip->treble)); + } } chip->thread = NULL; - if (desc->checkmode) { + if (desc->flags & CHIP_NEED_CHECKMODE) { + if (!desc->getmode || !desc->setmode) { + /* This shouldn't be happen. Warn user, but keep working + without kthread + */ + v4l_info(chip->c, "set/get mode callbacks undefined!\n"); + return 0; + } /* start async thread */ init_timer(&chip->wt); chip->wt.function = chip_thread_wake; @@ -1564,7 +1627,7 @@ static int chip_remove(struct i2c_client *client) static int tvaudio_get_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) { - struct CHIPDESC *desc = chiplist + chip->type; + struct CHIPDESC *desc = chip->desc; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -1588,13 +1651,13 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip, return 0; } case V4L2_CID_AUDIO_BASS: - if (desc->flags & CHIP_HAS_BASSTREBLE) + 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; + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) + break; ctrl->value = chip->treble; return 0; } @@ -1604,7 +1667,7 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip, static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) { - struct CHIPDESC *desc = chiplist + chip->type; + struct CHIPDESC *desc = chip->desc; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -1654,16 +1717,15 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, return 0; } case V4L2_CID_AUDIO_BASS: - if (desc->flags & CHIP_HAS_BASSTREBLE) + 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; - + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) + break; chip->treble = ctrl->value; chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); @@ -1680,9 +1742,12 @@ static int chip_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct CHIPSTATE *chip = i2c_get_clientdata(client); - struct CHIPDESC *desc = chiplist + chip->type; + struct CHIPDESC *desc = chip->desc; - v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd); + if (debug > 0) { + v4l_i2c_print_ioctl(chip->c, cmd); + printk("\n"); + } switch (cmd) { case AUDC_SET_RADIO: @@ -1707,7 +1772,7 @@ static int chip_command(struct i2c_client *client, break; case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) + if (!(desc->flags & CHIP_HAS_BASSTREBLE)) return -EINVAL; break; default: @@ -1804,12 +1869,20 @@ static int chip_command(struct i2c_client *client, break; case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ - if (desc->checkmode && desc->setmode) { + + /* For chips that provide getmode and setmode, and doesn't + automatically follows the stereo carrier, a kthread is + created to set the audio standard. In this case, when then + the video channel is changed, tvaudio starts on MONO mode. + After waiting for 2 seconds, the kernel thread is called, + to follow whatever audio standard is pointed by the + audio carrier. + */ + if (chip->thread) { 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 */ } break; @@ -1852,9 +1925,3 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = { .id_table = chip_id, #endif }; - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c index 5f088e669..c1809a56b 100644 --- a/linux/drivers/media/video/tveeprom.c +++ b/linux/drivers/media/video/tveeprom.c @@ -243,7 +243,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "TCL M2523_3DBH_E"}, { TUNER_ABSENT, "TCL M2523_3DIH_E"}, { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216MEX"}, + { TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"}, { TUNER_ABSENT, "Philips FRH2036B"}, { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, { TUNER_ABSENT, "MaxLinear MXL5005"}, diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c index 28c5c6761..ac8205d87 100644 --- a/linux/drivers/media/video/tvp5150.c +++ b/linux/drivers/media/video/tvp5150.c @@ -935,6 +935,21 @@ static int tvp5150_command(struct i2c_client *c, int i; fmt = arg; + /* raw vbi */ + if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + /* this is for capturing 36 raw vbi lines + if there's a way to cut off the beginning 2 vbi lines + with the tvp5150 then the vbi line count could be lowered + to 17 lines/field again, although I couldn't find a register + which could do that cropping */ + if (fmt->fmt.vbi.sample_format == V4L2_PIX_FMT_GREY) + tvp5150_write(c, TVP5150_LUMA_PROC_CTL_1, 0x70); + if (fmt->fmt.vbi.count[0] == 18 && fmt->fmt.vbi.count[1] == 18) { + tvp5150_write(c, TVP5150_VERT_BLANKING_START, 0x00); + tvp5150_write(c, TVP5150_VERT_BLANKING_STOP, 0x01); + } + break; + } if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) return -EINVAL; svbi = &fmt->fmt.sliced; diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c index d202feac0..1119bcf58 100644 --- a/linux/drivers/media/video/usbvideo/ibmcam.c +++ b/linux/drivers/media/video/usbvideo/ibmcam.c @@ -3695,7 +3695,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * unsigned char video_ep = 0; if (debug >= 1) - dev_info(&uvd->dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum); + dev_info(&dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum); /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) @@ -3746,7 +3746,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */ break; } - dev_info(&uvd->dev->dev, + dev_info(&dev->dev, "%s USB camera found (model %d, rev. 0x%04x)\n", brand, model, le16_to_cpu(dev->descriptor.bcdDevice)); } while (0); @@ -3754,7 +3754,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * /* Validate found interface: must have one ISO endpoint */ nas = intf->num_altsetting; if (debug > 0) - dev_info(&uvd->dev->dev, "Number of alternate settings=%d.\n", + dev_info(&dev->dev, "Number of alternate settings=%d.\n", nas); if (nas < 2) { err("Too few alternate settings for this camera!"); @@ -3799,7 +3799,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * actInterface = i; maxPS = le16_to_cpu(endpoint->wMaxPacketSize); if (debug > 0) - dev_info(&uvd->dev->dev, + dev_info(&dev->dev, "Active setting=%d. " "maxPS=%d.\n", i, maxPS); } else @@ -3840,7 +3840,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * RESTRICT_TO_RANGE(framerate, 0, 5); break; default: - dev_info(&uvd->dev->dev, "IBM camera: using 320x240\n"); + dev_info(&dev->dev, "IBM camera: using 320x240\n"); size = SIZE_320x240; /* No break here */ case SIZE_320x240: @@ -3869,7 +3869,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id * canvasY = 120; break; default: - dev_info(&uvd->dev->dev, "IBM NetCamera: using 176x144\n"); + dev_info(&dev->dev, "IBM NetCamera: using 176x144\n"); size = SIZE_176x144; /* No break here */ case SIZE_176x144: diff --git a/linux/drivers/media/video/usbvideo/konicawc.c b/linux/drivers/media/video/usbvideo/konicawc.c index 5c11ea64c..73abbb3f4 100644 --- a/linux/drivers/media/video/usbvideo/konicawc.c +++ b/linux/drivers/media/video/usbvideo/konicawc.c @@ -234,7 +234,8 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev cam->input = input_dev = input_allocate_device(); if (!input_dev) { - warn("Not enough memory for camera's input device\n"); + dev_warn(&dev->dev, + "Not enough memory for camera's input device\n"); return; } @@ -252,8 +253,9 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev error = input_register_device(cam->input); if (error) { - warn("Failed to register camera's input device, err: %d\n", - error); + dev_warn(&dev->dev, + "Failed to register camera's input device, err: %d\n", + error); input_free_device(cam->input); cam->input = NULL; } diff --git a/linux/drivers/media/video/usbvideo/quickcam_messenger.c b/linux/drivers/media/video/usbvideo/quickcam_messenger.c index 2f7274aba..d363e3d64 100644 --- a/linux/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/linux/drivers/media/video/usbvideo/quickcam_messenger.c @@ -98,7 +98,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev) cam->input = input_dev = input_allocate_device(); if (!input_dev) { - warn("insufficient mem for cam input device"); + dev_warn(&dev->dev, "insufficient mem for cam input device\n"); return; } @@ -116,8 +116,9 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev) error = input_register_device(cam->input); if (error) { - warn("Failed to register camera's input device, err: %d\n", - error); + dev_warn(&dev->dev, + "Failed to register camera's input device, err: %d\n", + error); input_free_device(cam->input); cam->input = NULL; } @@ -600,8 +601,9 @@ static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb) dataurb->iso_frame_desc[i].offset; if (st < 0) { - warn("Data error: packet=%d. len=%d. status=%d.", - i, n, st); + dev_warn(&uvd->dev->dev, + "Data error: packet=%d. len=%d. status=%d.\n", + i, n, st); uvd->stats.iso_err_count++; continue; } @@ -716,7 +718,7 @@ static void qcm_stop_data(struct uvd *uvd) ret = qcm_camera_off(uvd); if (ret) - warn("couldn't turn the cam off."); + dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n"); uvd->streaming = 0; diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c index c6d1e7dca..332929bb2 100644 --- a/linux/drivers/media/video/usbvideo/usbvideo.c +++ b/linux/drivers/media/video/usbvideo/usbvideo.c @@ -1059,7 +1059,7 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n", (uvd->handle != NULL) ? uvd->handle->drvName : "???", - uvd->vdev.minor, tmp2, tmp1); + uvd->vdev.num, tmp2, tmp1); usb_get_dev(uvd->dev); return 0; @@ -1281,8 +1281,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file) * History: * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. */ -static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct uvd *uvd = file->private_data; @@ -1505,7 +1504,7 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl); + return video_usercopy(file, cmd, arg, usbvideo_v4l_do_ioctl); } /* diff --git a/linux/drivers/media/video/usbvideo/vicam.c b/linux/drivers/media/video/usbvideo/vicam.c index bad26ccf8..77032eaa7 100644 --- a/linux/drivers/media/video/usbvideo/vicam.c +++ b/linux/drivers/media/video/usbvideo/vicam.c @@ -1187,7 +1187,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) return -EIO; } - printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); + printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n", + cam->vdev.num); usb_set_intfdata (intf, cam); diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c index d66cce1a5..33f37ac46 100644 --- a/linux/drivers/media/video/usbvision/usbvision-core.c +++ b/linux/drivers/media/video/usbvision/usbvision-core.c @@ -45,10 +45,6 @@ #include <linux/workqueue.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif - #include "usbvision.h" static unsigned int core_debug; diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c index d98eb913e..888051b80 100644 --- a/linux/drivers/media/video/usbvision/usbvision-i2c.c +++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c @@ -237,7 +237,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) sizeof(struct i2c_client)); sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), - " #%d", usbvision->vdev->minor & 0x1f); + " #%d", usbvision->vdev->num); PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index e10b256ae..48c8c4399 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -69,10 +69,6 @@ #include <linux/workqueue.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif - #include "usbvision.h" #include "usbvision-cards.h" @@ -527,7 +523,7 @@ static int vidioc_querycap (struct file *file, void *priv, strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, sizeof(vc->card)); - strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + strlcpy(vc->bus_info, dev_name(&usbvision->dev->dev), sizeof(vc->bus_info)); vc->version = USBVISION_DRIVER_VERSION; vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | @@ -1282,7 +1278,7 @@ static int usbvision_vbi_close(struct inode *inode, struct file *file) return -ENODEV; } -static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, +static int usbvision_do_vbi_ioctl(struct file *file, unsigned int cmd, void *arg) { /* TODO */ @@ -1292,7 +1288,7 @@ static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl); + return video_usercopy(file, cmd, arg, usbvision_do_vbi_ioctl); } @@ -1444,7 +1440,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // vbi Device: if (usbvision->vbi) { PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", - usbvision->vbi->minor & 0x1f); + usbvision->vbi->num); if (usbvision->vbi->minor != -1) { video_unregister_device(usbvision->vbi); } else { @@ -1456,7 +1452,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // Radio Device: if (usbvision->rdev) { PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", - usbvision->rdev->minor & 0x1f); + usbvision->rdev->num); if (usbvision->rdev->minor != -1) { video_unregister_device(usbvision->rdev); } else { @@ -1468,7 +1464,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // Video Device: if (usbvision->vdev) { PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", - usbvision->vdev->minor & 0x1f); + usbvision->vdev->num); if (usbvision->vdev->minor != -1) { video_unregister_device(usbvision->vdev); } else { @@ -1494,7 +1490,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) goto err_exit; } printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", - usbvision->nr,usbvision->vdev->minor & 0x1f); + usbvision->nr, usbvision->vdev->num); // Radio Device: if (usbvision_device_data[usbvision->DevModel].Radio) { @@ -1511,7 +1507,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) goto err_exit; } printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", - usbvision->nr, usbvision->rdev->minor & 0x1f); + usbvision->nr, usbvision->rdev->num); } // vbi Device: if (usbvision_device_data[usbvision->DevModel].vbi) { @@ -1527,7 +1523,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) goto err_exit; } printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", - usbvision->nr,usbvision->vbi->minor & 0x1f); + usbvision->nr, usbvision->vbi->num); } // all done return 0; diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index f16aafe9c..9de8a1db5 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -15,7 +15,9 @@ #include <linux/version.h> #include <linux/list.h> #include <linux/module.h> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) #include <linux/uaccess.h> +#endif #include <linux/usb.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index cbe9d0452..046b98871 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -288,8 +288,10 @@ static int uvc_parse_format(struct uvc_device *dev, struct uvc_format_desc *fmtdesc; struct uvc_frame *frame; const unsigned char *start = buffer; + unsigned char *_buffer; unsigned int interval; unsigned int i, n; + int _buflen; __u8 ftype; format->type = buffer[2]; @@ -410,12 +412,20 @@ static int uvc_parse_format(struct uvc_device *dev, buflen -= buffer[0]; buffer += buffer[0]; + /* Count the number of frame descriptors to test the bFrameIndex + * field when parsing the descriptors. We can't rely on the + * bNumFrameDescriptors field as some cameras don't initialize it + * properly. + */ + for (_buflen = buflen, _buffer = buffer; + _buflen > 2 && _buffer[2] == ftype; + _buflen -= _buffer[0], _buffer += _buffer[0]) + format->nframes++; + /* Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ while (buflen > 2 && buffer[2] == ftype) { - frame = &format->frame[format->nframes]; - if (ftype != VS_FRAME_FRAME_BASED) n = buflen > 25 ? buffer[25] : 0; else @@ -430,6 +440,16 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } + if (buffer[3] - 1 >= format->nframes) { + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + "interface %d frame index %u out of range\n", + dev->udev->devnum, alts->desc.bInterfaceNumber, + buffer[3]); + return -EINVAL; + } + + frame = &format->frame[buffer[3] - 1]; + frame->bFrameIndex = buffer[3]; frame->bmCapabilities = buffer[4]; frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]); @@ -486,7 +506,6 @@ static int uvc_parse_format(struct uvc_device *dev, 10000000/frame->dwDefaultFrameInterval, (100000000/frame->dwDefaultFrameInterval)%10); - format->nframes++; buflen -= buffer[0]; buffer += buffer[0]; } @@ -1709,24 +1728,6 @@ static int uvc_reset_resume(struct usb_interface *intf) * though they are compliant. */ static struct usb_device_id uvc_ids[] = { - /* ALi M5606 (Clevo M540SR) */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x0402, - .idProduct = 0x5606, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Creative Live! Optia */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x041e, - .idProduct = 0x4057, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Microsoft Lifecam NX-6000 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1812,15 +1813,6 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Silicon Motion SM371 */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x090c, - .idProduct = 0xb371, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* MT6227 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1839,6 +1831,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, + /* Syntek (Samsung Q310) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x174f, + .idProduct = 0x5931, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_STREAM_NO_FID }, /* Asus F9SG */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1857,6 +1858,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, + /* Lenovo Thinkpad SL500 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x17ef, + .idProduct = 0x480b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_STREAM_NO_FID }, /* Ecamm Pico iMage */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1887,105 +1897,6 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_IGNORE_SELECTOR_UNIT}, - /* Acer OEM Webcam - Unknown vendor */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0100, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Packard Bell OEM Webcam - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0101, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Acer Crystal Eye webcam - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0102, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Compaq Presario B1200 - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0104, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Acer Travelmate 7720 - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0105, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Medion Akoya Mini E1210 - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0141, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Acer OrbiCam - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0200, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Fujitsu Amilo SI2636 - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0202, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Advent 4211 - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0203, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0300, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Clevo M570TU - Bison Electronics */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE - | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x5986, - .idProduct = 0x0303, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, {} @@ -2004,7 +1915,9 @@ struct uvc_driver uvc_driver = { .reset_resume = uvc_reset_resume, #endif .id_table = uvc_ids, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) .supports_autosuspend = 1, +#endif }, }; diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c index 5d60b264d..ab62d7bf9 100644 --- a/linux/drivers/media/video/uvc/uvc_status.c +++ b/linux/drivers/media/video/uvc/uvc_status.c @@ -15,7 +15,11 @@ #include <linux/version.h> #include <linux/input.h> #include <linux/usb.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include <linux/usb_input.h> +#else #include <linux/usb/input.h> +#endif #include "uvcvideo.h" @@ -45,7 +49,11 @@ static int uvc_input_init(struct uvc_device *dev) input->name = dev->name; input->phys = phys; usb_to_input_id(udev, &input->id); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) input->dev.parent = &dev->intf->dev; +#else + input->cdev.dev = &dev->intf->dev; +#endif set_bit(EV_KEY, input->evbit); set_bit(BTN_0, input->keybit); @@ -118,7 +126,11 @@ static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len) data[1], data[3], attrs[data[4]], len); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void uvc_status_complete(struct urb *urb, struct pt_regs *regs) +#else static void uvc_status_complete(struct urb *urb) +#endif { struct uvc_device *dev = urb->context; int len, ret; diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index 78e4c4e09..5588698e2 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -252,7 +252,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, if (ret < 0) return ret; - if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0) + if ((ret = uvc_commit_video(video, &probe)) < 0) return ret; memcpy(&video->streaming->ctrl, &probe, sizeof probe); @@ -316,7 +316,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, return ret; /* Commit the new settings. */ - if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0) + if ((ret = uvc_commit_video(video, &probe)) < 0) return ret; memcpy(&video->streaming->ctrl, &probe, sizeof probe); @@ -413,14 +413,18 @@ static int uvc_v4l2_open(struct inode *inode, struct file *file) goto done; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ret = usb_autopm_get_interface(video->dev->intf); if (ret < 0) goto done; +#endif /* Create the device handle. */ handle = kzalloc(sizeof *handle, GFP_KERNEL); if (handle == NULL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) usb_autopm_put_interface(video->dev->intf); +#endif ret = -ENOMEM; goto done; } @@ -459,13 +463,14 @@ static int uvc_v4l2_release(struct inode *inode, struct file *file) kfree(handle); file->private_data = NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) usb_autopm_put_interface(video->dev->intf); +#endif kref_put(&video->dev->kref, uvc_delete); return 0; } -static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct uvc_video_device *video = video_get_drvdata(vdev); @@ -978,7 +983,7 @@ static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file, return uvc_xu_ctrl_query(video, arg, 1); default: - if ((ret = v4l_compat_translate_ioctl(inode, file, cmd, arg, + if ((ret = v4l_compat_translate_ioctl(file, cmd, arg, uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD) uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); @@ -992,7 +997,7 @@ static int uvc_v4l2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n"); - return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl); + return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); } static ssize_t uvc_v4l2_read(struct file *file, char __user *data, diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index b7bb23820..987e110fe 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -36,15 +36,22 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, { __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; unsigned int pipe; - int ret; pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0) : usb_sndctrlpipe(dev->udev, 0); type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT; - ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8, + return usb_control_msg(dev->udev, pipe, query, type, cs << 8, unit << 8 | intfnum, data, size, timeout); +} + +int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, + __u8 intfnum, __u8 cs, void *data, __u16 size) +{ + int ret; + ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size, + UVC_CTRL_CONTROL_TIMEOUT); if (ret != size) { uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u " "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret, @@ -55,13 +62,6 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, return 0; } -int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, - __u8 intfnum, __u8 cs, void *data, __u16 size) -{ - return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size, - UVC_CTRL_CONTROL_TIMEOUT); -} - static void uvc_fixup_buffer_size(struct uvc_video_device *video, struct uvc_streaming_control *ctrl) { @@ -102,8 +102,36 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, UVC_CTRL_STREAMING_TIMEOUT); - if (ret < 0) + + if ((query == GET_MIN || query == GET_MAX) && ret == 2) { + /* Some cameras, mostly based on Bison Electronics chipsets, + * answer a GET_MIN or GET_MAX request with the wCompQuality + * field only. + */ + uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non " + "compliance - GET_MIN/MAX(PROBE) incorrectly " + "supported. Enabling workaround.\n"); + memset(ctrl, 0, sizeof ctrl); + ctrl->wCompQuality = le16_to_cpup((__le16 *)data); + ret = 0; goto out; + } else if (query == GET_DEF && probe == 1) { + /* Many cameras don't support the GET_DEF request on their + * video probe control. Warn once and return, the caller will + * fall back to GET_CUR. + */ + uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non " + "compliance - GET_DEF(PROBE) not supported. " + "Enabling workaround.\n"); + ret = -EIO; + goto out; + } else if (ret != size) { + uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : " + "%d (exp. %u).\n", query, probe ? "probe" : "commit", + ret, size); + ret = -EIO; + goto out; + } ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); ctrl->bFormatIndex = data[2]; @@ -138,13 +166,14 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, * Try to get the value from the format and frame descriptor. */ uvc_fixup_buffer_size(video, ctrl); + ret = 0; out: kfree(data); return ret; } -int uvc_set_video_ctrl(struct uvc_video_device *video, +static int uvc_set_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl, int probe) { __u8 *data; @@ -186,6 +215,12 @@ int uvc_set_video_ctrl(struct uvc_video_device *video, video->streaming->intfnum, probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, UVC_CTRL_STREAMING_TIMEOUT); + if (ret != size) { + uvc_printk(KERN_ERR, "Failed to set UVC %s control : " + "%d (exp. %u).\n", probe ? "probe" : "commit", + ret, size); + ret = -EIO; + } kfree(data); return ret; @@ -252,6 +287,12 @@ done: return ret; } +int uvc_commit_video(struct uvc_video_device *video, + struct uvc_streaming_control *probe) +{ + return uvc_set_video_ctrl(video, probe, 0); +} + /* ------------------------------------------------------------------------ * Video codecs */ @@ -525,7 +566,11 @@ static void uvc_video_decode_bulk(struct urb *urb, } } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void uvc_video_complete(struct urb *urb, struct pt_regs *regs) +#else static void uvc_video_complete(struct urb *urb) +#endif { struct uvc_video_device *video = urb->context; struct uvc_video_queue *queue = &video->queue; diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index 9a6bc1aaf..f95040380 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -4,6 +4,7 @@ #include <linux/kernel.h> #include <linux/videodev2.h> +#include "compat.h" /* * Dynamic controls @@ -617,6 +618,7 @@ enum uvc_device_state { struct uvc_device { struct usb_device *udev; struct usb_interface *intf; + unsigned long warnings; __u32 quirks; int intfnum; char name[32]; @@ -679,6 +681,9 @@ struct uvc_driver { #define UVC_TRACE_SUSPEND (1 << 8) #define UVC_TRACE_STATUS (1 << 9) +#define UVC_WARN_MINMAX 0 +#define UVC_WARN_PROBE_DEF 1 + extern unsigned int uvc_trace_param; #define uvc_trace(flag, msg...) \ @@ -687,6 +692,12 @@ extern unsigned int uvc_trace_param; printk(KERN_DEBUG "uvcvideo: " msg); \ } while (0) +#define uvc_warn_once(dev, warn, msg...) \ + do { \ + if (!test_and_set_bit(warn, &dev->warnings)) \ + printk(KERN_INFO "uvcvideo: " msg); \ + } while (0) + #define uvc_printk(level, msg...) \ printk(level "uvcvideo: " msg) @@ -740,10 +751,10 @@ extern int uvc_video_resume(struct uvc_video_device *video); extern int uvc_video_enable(struct uvc_video_device *video, int enable); extern int uvc_probe_video(struct uvc_video_device *video, struct uvc_streaming_control *probe); +extern int uvc_commit_video(struct uvc_video_device *video, + struct uvc_streaming_control *ctrl); extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, __u8 intfnum, __u8 cs, void *data, __u16 size); -extern int uvc_set_video_ctrl(struct uvc_video_device *video, - struct uvc_streaming_control *ctrl, int probe); /* Status */ extern int uvc_status_init(struct uvc_device *dev); diff --git a/linux/drivers/media/video/v4l1-compat.c b/linux/drivers/media/video/v4l1-compat.c index 5d8a65aa5..ff1d3eb68 100644 --- a/linux/drivers/media/video/v4l1-compat.c +++ b/linux/drivers/media/video/v4l1-compat.c @@ -35,10 +35,6 @@ #include <asm/uaccess.h> #include <asm/system.h> #include <asm/pgtable.h> - -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif #include "compat.h" static unsigned int debug; @@ -62,8 +58,7 @@ MODULE_LICENSE("GPL"); */ static int -get_v4l_control(struct inode *inode, - struct file *file, +get_v4l_control(struct file *file, int cid, v4l2_kioctl drv) { @@ -72,12 +67,12 @@ get_v4l_control(struct inode *inode, int err; qctrl2.id = cid; - err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2); + err = drv(file, VIDIOC_QUERYCTRL, &qctrl2); if (err < 0) dprintk("VIDIOC_QUERYCTRL: %d\n", err); if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) { ctrl2.id = qctrl2.id; - err = drv(inode, file, VIDIOC_G_CTRL, &ctrl2); + err = drv(file, VIDIOC_G_CTRL, &ctrl2); if (err < 0) { dprintk("VIDIOC_G_CTRL: %d\n", err); return 0; @@ -90,8 +85,7 @@ get_v4l_control(struct inode *inode, } static int -set_v4l_control(struct inode *inode, - struct file *file, +set_v4l_control(struct file *file, int cid, int value, v4l2_kioctl drv) @@ -101,7 +95,7 @@ set_v4l_control(struct inode *inode, int err; qctrl2.id = cid; - err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2); + err = drv(file, VIDIOC_QUERYCTRL, &qctrl2); if (err < 0) dprintk("VIDIOC_QUERYCTRL: %d\n", err); if (err == 0 && @@ -119,7 +113,7 @@ set_v4l_control(struct inode *inode, + 32767) / 65535; ctrl2.value += qctrl2.minimum; - err = drv(inode, file, VIDIOC_S_CTRL, &ctrl2); + err = drv(file, VIDIOC_S_CTRL, &ctrl2); if (err < 0) dprintk("VIDIOC_S_CTRL: %d\n", err); } @@ -227,7 +221,6 @@ static int poll_one(struct file *file, struct poll_wqueues *pwq) } static int count_inputs( - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -237,14 +230,13 @@ static int count_inputs( for (i = 0;; i++) { memset(&input2, 0, sizeof(input2)); input2.index = i; - if (0 != drv(inode, file, VIDIOC_ENUMINPUT, &input2)) + if (0 != drv(file, VIDIOC_ENUMINPUT, &input2)) break; } return i; } static int check_size( - struct inode *inode, struct file *file, v4l2_kioctl drv, int *maxw, @@ -257,14 +249,14 @@ static int check_size( memset(&fmt2, 0, sizeof(fmt2)); desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (0 != drv(inode, file, VIDIOC_ENUM_FMT, &desc2)) + if (0 != drv(file, VIDIOC_ENUM_FMT, &desc2)) goto done; fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt2.fmt.pix.width = 10000; fmt2.fmt.pix.height = 10000; fmt2.fmt.pix.pixelformat = desc2.pixelformat; - if (0 != drv(inode, file, VIDIOC_TRY_FMT, &fmt2)) + if (0 != drv(file, VIDIOC_TRY_FMT, &fmt2)) goto done; *maxw = fmt2.fmt.pix.width; @@ -278,7 +270,6 @@ done: static noinline int v4l1_compat_get_capabilities( struct video_capability *cap, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -294,13 +285,13 @@ static noinline int v4l1_compat_get_capabilities( memset(cap, 0, sizeof(*cap)); memset(&fbuf, 0, sizeof(fbuf)); - err = drv(inode, file, VIDIOC_QUERYCAP, cap2); + err = drv(file, VIDIOC_QUERYCAP, cap2); if (err < 0) { dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n", err); goto done; } if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) { - err = drv(inode, file, VIDIOC_G_FBUF, &fbuf); + err = drv(file, VIDIOC_G_FBUF, &fbuf); if (err < 0) { dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n", err); memset(&fbuf, 0, sizeof(fbuf)); @@ -322,8 +313,8 @@ static noinline int v4l1_compat_get_capabilities( if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING) cap->type |= VID_TYPE_CLIPPING; - cap->channels = count_inputs(inode, file, drv); - check_size(inode, file, drv, + cap->channels = count_inputs(file, drv); + check_size(file, drv, &cap->maxwidth, &cap->maxheight); cap->audios = 0; /* FIXME */ cap->minwidth = 48; /* FIXME */ @@ -336,7 +327,6 @@ done: static noinline int v4l1_compat_get_frame_buffer( struct video_buffer *buffer, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -346,7 +336,7 @@ static noinline int v4l1_compat_get_frame_buffer( memset(buffer, 0, sizeof(*buffer)); memset(&fbuf, 0, sizeof(fbuf)); - err = drv(inode, file, VIDIOC_G_FBUF, &fbuf); + err = drv(file, VIDIOC_G_FBUF, &fbuf); if (err < 0) { dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n", err); goto done; @@ -391,7 +381,6 @@ done: static noinline int v4l1_compat_set_frame_buffer( struct video_buffer *buffer, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -420,7 +409,7 @@ static noinline int v4l1_compat_set_frame_buffer( break; } fbuf.fmt.bytesperline = buffer->bytesperline; - err = drv(inode, file, VIDIOC_S_FBUF, &fbuf); + err = drv(file, VIDIOC_S_FBUF, &fbuf); if (err < 0) dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n", err); return err; @@ -428,7 +417,6 @@ static noinline int v4l1_compat_set_frame_buffer( static noinline int v4l1_compat_get_win_cap_dimensions( struct video_window *win, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -443,7 +431,7 @@ static noinline int v4l1_compat_get_win_cap_dimensions( memset(win, 0, sizeof(*win)); fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY; - err = drv(inode, file, VIDIOC_G_FMT, fmt); + err = drv(file, VIDIOC_G_FMT, fmt); if (err < 0) dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n", err); if (err == 0) { @@ -458,7 +446,7 @@ static noinline int v4l1_compat_get_win_cap_dimensions( } fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - err = drv(inode, file, VIDIOC_G_FMT, fmt); + err = drv(file, VIDIOC_G_FMT, fmt); if (err < 0) { dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n", err); goto done; @@ -477,7 +465,6 @@ done: static noinline int v4l1_compat_set_win_cap_dimensions( struct video_window *win, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -490,8 +477,8 @@ static noinline int v4l1_compat_set_win_cap_dimensions( return err; } fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - drv(inode, file, VIDIOC_STREAMOFF, &fmt->type); - err1 = drv(inode, file, VIDIOC_G_FMT, fmt); + drv(file, VIDIOC_STREAMOFF, &fmt->type); + err1 = drv(file, VIDIOC_G_FMT, fmt); if (err1 < 0) dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n", err1); if (err1 == 0) { @@ -499,7 +486,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions( fmt->fmt.pix.height = win->height; fmt->fmt.pix.field = V4L2_FIELD_ANY; fmt->fmt.pix.bytesperline = 0; - err = drv(inode, file, VIDIOC_S_FMT, fmt); + err = drv(file, VIDIOC_S_FMT, fmt); if (err < 0) dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n", err); @@ -516,7 +503,7 @@ static noinline int v4l1_compat_set_win_cap_dimensions( fmt->fmt.win.chromakey = win->chromakey; fmt->fmt.win.clips = (void __user *)win->clips; fmt->fmt.win.clipcount = win->clipcount; - err2 = drv(inode, file, VIDIOC_S_FMT, fmt); + err2 = drv(file, VIDIOC_S_FMT, fmt); if (err2 < 0) dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n", err2); @@ -530,7 +517,6 @@ static noinline int v4l1_compat_set_win_cap_dimensions( static noinline int v4l1_compat_turn_preview_on_off( int *on, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -541,9 +527,9 @@ static noinline int v4l1_compat_turn_preview_on_off( /* dirty hack time. But v4l1 has no STREAMOFF * equivalent in the API, and this one at * least comes close ... */ - drv(inode, file, VIDIOC_STREAMOFF, &captype); + drv(file, VIDIOC_STREAMOFF, &captype); } - err = drv(inode, file, VIDIOC_OVERLAY, on); + err = drv(file, VIDIOC_OVERLAY, on); if (err < 0) dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n", err); return err; @@ -551,7 +537,6 @@ static noinline int v4l1_compat_turn_preview_on_off( static noinline int v4l1_compat_get_input_info( struct video_channel *chan, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -561,7 +546,7 @@ static noinline int v4l1_compat_get_input_info( memset(&input2, 0, sizeof(input2)); input2.index = chan->channel; - err = drv(inode, file, VIDIOC_ENUMINPUT, &input2); + err = drv(file, VIDIOC_ENUMINPUT, &input2); if (err < 0) { dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: " "channel=%d err=%d\n", chan->channel, err); @@ -583,7 +568,7 @@ static noinline int v4l1_compat_get_input_info( break; } chan->norm = 0; - err = drv(inode, file, VIDIOC_G_STD, &sid); + err = drv(file, VIDIOC_G_STD, &sid); if (err < 0) dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n", err); if (err == 0) { @@ -600,14 +585,13 @@ done: static noinline int v4l1_compat_set_input( struct video_channel *chan, - struct inode *inode, struct file *file, v4l2_kioctl drv) { int err; v4l2_std_id sid = 0; - err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel); + err = drv(file, VIDIOC_S_INPUT, &chan->channel); if (err < 0) dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n", err); switch (chan->norm) { @@ -622,7 +606,7 @@ static noinline int v4l1_compat_set_input( break; } if (0 != sid) { - err = drv(inode, file, VIDIOC_S_STD, &sid); + err = drv(file, VIDIOC_S_STD, &sid); if (err < 0) dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n", err); } @@ -631,7 +615,6 @@ static noinline int v4l1_compat_set_input( static noinline int v4l1_compat_get_picture( struct video_picture *pict, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -644,19 +627,19 @@ static noinline int v4l1_compat_get_picture( return err; } - pict->brightness = get_v4l_control(inode, file, + pict->brightness = get_v4l_control(file, V4L2_CID_BRIGHTNESS, drv); - pict->hue = get_v4l_control(inode, file, + pict->hue = get_v4l_control(file, V4L2_CID_HUE, drv); - pict->contrast = get_v4l_control(inode, file, + pict->contrast = get_v4l_control(file, V4L2_CID_CONTRAST, drv); - pict->colour = get_v4l_control(inode, file, + pict->colour = get_v4l_control(file, V4L2_CID_SATURATION, drv); - pict->whiteness = get_v4l_control(inode, file, + pict->whiteness = get_v4l_control(file, V4L2_CID_WHITENESS, drv); fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - err = drv(inode, file, VIDIOC_G_FMT, fmt); + err = drv(file, VIDIOC_G_FMT, fmt); if (err < 0) { dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n", err); goto done; @@ -674,7 +657,6 @@ done: static noinline int v4l1_compat_set_picture( struct video_picture *pict, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -690,15 +672,15 @@ static noinline int v4l1_compat_set_picture( } memset(&fbuf, 0, sizeof(fbuf)); - set_v4l_control(inode, file, + set_v4l_control(file, V4L2_CID_BRIGHTNESS, pict->brightness, drv); - set_v4l_control(inode, file, + set_v4l_control(file, V4L2_CID_HUE, pict->hue, drv); - set_v4l_control(inode, file, + set_v4l_control(file, V4L2_CID_CONTRAST, pict->contrast, drv); - set_v4l_control(inode, file, + set_v4l_control(file, V4L2_CID_SATURATION, pict->colour, drv); - set_v4l_control(inode, file, + set_v4l_control(file, V4L2_CID_WHITENESS, pict->whiteness, drv); /* * V4L1 uses this ioctl to set both memory capture and overlay @@ -708,7 +690,7 @@ static noinline int v4l1_compat_set_picture( */ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - err = drv(inode, file, VIDIOC_G_FMT, fmt); + err = drv(file, VIDIOC_G_FMT, fmt); /* If VIDIOC_G_FMT failed, then the driver likely doesn't support memory capture. Trying to set the memory capture parameters would be pointless. */ @@ -719,13 +701,13 @@ static noinline int v4l1_compat_set_picture( palette_to_pixelformat(pict->palette)) { fmt->fmt.pix.pixelformat = palette_to_pixelformat( pict->palette); - mem_err = drv(inode, file, VIDIOC_S_FMT, fmt); + mem_err = drv(file, VIDIOC_S_FMT, fmt); if (mem_err < 0) dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n", mem_err); } - err = drv(inode, file, VIDIOC_G_FBUF, &fbuf); + err = drv(file, VIDIOC_G_FBUF, &fbuf); /* If VIDIOC_G_FBUF failed, then the driver likely doesn't support overlay. Trying to set the overlay parameters would be quite pointless. */ @@ -736,7 +718,7 @@ static noinline int v4l1_compat_set_picture( palette_to_pixelformat(pict->palette)) { fbuf.fmt.pixelformat = palette_to_pixelformat( pict->palette); - ovl_err = drv(inode, file, VIDIOC_S_FBUF, &fbuf); + ovl_err = drv(file, VIDIOC_S_FBUF, &fbuf); if (ovl_err < 0) dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n", ovl_err); @@ -757,7 +739,6 @@ static noinline int v4l1_compat_set_picture( static noinline int v4l1_compat_get_tuner( struct video_tuner *tun, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -767,7 +748,7 @@ static noinline int v4l1_compat_get_tuner( v4l2_std_id sid; memset(&tun2, 0, sizeof(tun2)); - err = drv(inode, file, VIDIOC_G_TUNER, &tun2); + err = drv(file, VIDIOC_G_TUNER, &tun2); if (err < 0) { dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n", err); goto done; @@ -783,7 +764,7 @@ static noinline int v4l1_compat_get_tuner( for (i = 0; i < 64; i++) { memset(&std2, 0, sizeof(std2)); std2.index = i; - if (0 != drv(inode, file, VIDIOC_ENUMSTD, &std2)) + if (0 != drv(file, VIDIOC_ENUMSTD, &std2)) break; if (std2.id & V4L2_STD_PAL) tun->flags |= VIDEO_TUNER_PAL; @@ -793,7 +774,7 @@ static noinline int v4l1_compat_get_tuner( tun->flags |= VIDEO_TUNER_SECAM; } - err = drv(inode, file, VIDIOC_G_STD, &sid); + err = drv(file, VIDIOC_G_STD, &sid); if (err < 0) dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n", err); if (err == 0) { @@ -816,7 +797,6 @@ done: static noinline int v4l1_compat_select_tuner( struct video_tuner *tun, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -826,7 +806,7 @@ static noinline int v4l1_compat_select_tuner( t.index = tun->tuner; - err = drv(inode, file, VIDIOC_S_INPUT, &t); + err = drv(file, VIDIOC_S_INPUT, &t); if (err < 0) dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n", err); return err; @@ -834,7 +814,6 @@ static noinline int v4l1_compat_select_tuner( static noinline int v4l1_compat_get_frequency( unsigned long *freq, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -843,7 +822,7 @@ static noinline int v4l1_compat_get_frequency( memset(&freq2, 0, sizeof(freq2)); freq2.tuner = 0; - err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); + err = drv(file, VIDIOC_G_FREQUENCY, &freq2); if (err < 0) dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n", err); if (0 == err) @@ -853,7 +832,6 @@ static noinline int v4l1_compat_get_frequency( static noinline int v4l1_compat_set_frequency( unsigned long *freq, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -861,9 +839,9 @@ static noinline int v4l1_compat_set_frequency( struct v4l2_frequency freq2; memset(&freq2, 0, sizeof(freq2)); - drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); + drv(file, VIDIOC_G_FREQUENCY, &freq2); freq2.frequency = *freq; - err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2); + err = drv(file, VIDIOC_S_FREQUENCY, &freq2); if (err < 0) dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n", err); return err; @@ -871,7 +849,6 @@ static noinline int v4l1_compat_set_frequency( static noinline int v4l1_compat_get_audio( struct video_audio *aud, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -881,7 +858,7 @@ static noinline int v4l1_compat_get_audio( struct v4l2_tuner tun2; memset(&aud2, 0, sizeof(aud2)); - err = drv(inode, file, VIDIOC_G_AUDIO, &aud2); + err = drv(file, VIDIOC_G_AUDIO, &aud2); if (err < 0) { dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n", err); goto done; @@ -891,27 +868,27 @@ static noinline int v4l1_compat_get_audio( aud->name[sizeof(aud->name) - 1] = 0; aud->audio = aud2.index; aud->flags = 0; - i = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv); + i = get_v4l_control(file, V4L2_CID_AUDIO_VOLUME, drv); if (i >= 0) { aud->volume = i; aud->flags |= VIDEO_AUDIO_VOLUME; } - i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv); + i = get_v4l_control(file, V4L2_CID_AUDIO_BASS, drv); if (i >= 0) { aud->bass = i; aud->flags |= VIDEO_AUDIO_BASS; } - i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv); + i = get_v4l_control(file, V4L2_CID_AUDIO_TREBLE, drv); if (i >= 0) { aud->treble = i; aud->flags |= VIDEO_AUDIO_TREBLE; } - i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv); + i = get_v4l_control(file, V4L2_CID_AUDIO_BALANCE, drv); if (i >= 0) { aud->balance = i; aud->flags |= VIDEO_AUDIO_BALANCE; } - i = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv); + i = get_v4l_control(file, V4L2_CID_AUDIO_MUTE, drv); if (i >= 0) { if (i) aud->flags |= VIDEO_AUDIO_MUTE; @@ -919,13 +896,13 @@ static noinline int v4l1_compat_get_audio( } aud->step = 1; qctrl2.id = V4L2_CID_AUDIO_VOLUME; - if (drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2) == 0 && + if (drv(file, VIDIOC_QUERYCTRL, &qctrl2) == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) aud->step = qctrl2.step; aud->mode = 0; memset(&tun2, 0, sizeof(tun2)); - err = drv(inode, file, VIDIOC_G_TUNER, &tun2); + err = drv(file, VIDIOC_G_TUNER, &tun2); if (err < 0) { dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n", err); err = 0; @@ -944,7 +921,6 @@ done: static noinline int v4l1_compat_set_audio( struct video_audio *aud, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -956,24 +932,24 @@ static noinline int v4l1_compat_set_audio( memset(&tun2, 0, sizeof(tun2)); aud2.index = aud->audio; - err = drv(inode, file, VIDIOC_S_AUDIO, &aud2); + err = drv(file, VIDIOC_S_AUDIO, &aud2); if (err < 0) { dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n", err); goto done; } - set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, + set_v4l_control(file, V4L2_CID_AUDIO_VOLUME, aud->volume, drv); - set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, + set_v4l_control(file, V4L2_CID_AUDIO_BASS, aud->bass, drv); - set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, + set_v4l_control(file, V4L2_CID_AUDIO_TREBLE, aud->treble, drv); - set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, + set_v4l_control(file, V4L2_CID_AUDIO_BALANCE, aud->balance, drv); - set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, + set_v4l_control(file, V4L2_CID_AUDIO_MUTE, !!(aud->flags & VIDEO_AUDIO_MUTE), drv); - err = drv(inode, file, VIDIOC_G_TUNER, &tun2); + err = drv(file, VIDIOC_G_TUNER, &tun2); if (err < 0) dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n", err); if (err == 0) { @@ -990,7 +966,7 @@ static noinline int v4l1_compat_set_audio( tun2.audmode = V4L2_TUNER_MODE_LANG2; break; } - err = drv(inode, file, VIDIOC_S_TUNER, &tun2); + err = drv(file, VIDIOC_S_TUNER, &tun2); if (err < 0) dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n", err); } @@ -1001,7 +977,6 @@ done: static noinline int v4l1_compat_capture_frame( struct video_mmap *mm, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -1018,7 +993,7 @@ static noinline int v4l1_compat_capture_frame( memset(&buf, 0, sizeof(buf)); fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - err = drv(inode, file, VIDIOC_G_FMT, fmt); + err = drv(file, VIDIOC_G_FMT, fmt); if (err < 0) { dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n", err); goto done; @@ -1034,7 +1009,7 @@ static noinline int v4l1_compat_capture_frame( palette_to_pixelformat(mm->format); fmt->fmt.pix.field = V4L2_FIELD_ANY; fmt->fmt.pix.bytesperline = 0; - err = drv(inode, file, VIDIOC_S_FMT, fmt); + err = drv(file, VIDIOC_S_FMT, fmt); if (err < 0) { dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n", err); goto done; @@ -1042,17 +1017,17 @@ static noinline int v4l1_compat_capture_frame( } buf.index = mm->frame; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - err = drv(inode, file, VIDIOC_QUERYBUF, &buf); + err = drv(file, VIDIOC_QUERYBUF, &buf); if (err < 0) { dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n", err); goto done; } - err = drv(inode, file, VIDIOC_QBUF, &buf); + err = drv(file, VIDIOC_QBUF, &buf); if (err < 0) { dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n", err); goto done; } - err = drv(inode, file, VIDIOC_STREAMON, &captype); + err = drv(file, VIDIOC_STREAMON, &captype); if (err < 0) dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n", err); done: @@ -1062,7 +1037,6 @@ done: static noinline int v4l1_compat_sync( int *i, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -1074,7 +1048,7 @@ static noinline int v4l1_compat_sync( memset(&buf, 0, sizeof(buf)); buf.index = *i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - err = drv(inode, file, VIDIOC_QUERYBUF, &buf); + err = drv(file, VIDIOC_QUERYBUF, &buf); if (err < 0) { /* No such buffer */ dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err); @@ -1087,7 +1061,7 @@ static noinline int v4l1_compat_sync( } /* make sure capture actually runs so we don't block forever */ - err = drv(inode, file, VIDIOC_STREAMON, &captype); + err = drv(file, VIDIOC_STREAMON, &captype); if (err < 0) { dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n", err); goto done; @@ -1101,7 +1075,7 @@ static noinline int v4l1_compat_sync( if (err < 0 || /* error or sleep was interrupted */ err == 0) /* timeout? Shouldn't occur. */ break; - err = drv(inode, file, VIDIOC_QUERYBUF, &buf); + err = drv(file, VIDIOC_QUERYBUF, &buf); if (err < 0) dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err); } @@ -1109,7 +1083,7 @@ static noinline int v4l1_compat_sync( if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */ goto done; do { - err = drv(inode, file, VIDIOC_DQBUF, &buf); + err = drv(file, VIDIOC_DQBUF, &buf); if (err < 0) dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n", err); } while (err == 0 && buf.index != *i); @@ -1119,7 +1093,6 @@ done: static noinline int v4l1_compat_get_vbi_format( struct vbi_format *fmt, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -1133,7 +1106,7 @@ static noinline int v4l1_compat_get_vbi_format( } fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE; - err = drv(inode, file, VIDIOC_G_FMT, fmt2); + err = drv(file, VIDIOC_G_FMT, fmt2); if (err < 0) { dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err); goto done; @@ -1158,7 +1131,6 @@ done: static noinline int v4l1_compat_set_vbi_format( struct vbi_format *fmt, - struct inode *inode, struct file *file, v4l2_kioctl drv) { @@ -1184,7 +1156,7 @@ static noinline int v4l1_compat_set_vbi_format( fmt2->fmt.vbi.start[1] = fmt->start[1]; fmt2->fmt.vbi.count[1] = fmt->count[1]; fmt2->fmt.vbi.flags = fmt->flags; - err = drv(inode, file, VIDIOC_TRY_FMT, fmt2); + err = drv(file, VIDIOC_TRY_FMT, fmt2); if (err < 0) { dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err); goto done; @@ -1201,7 +1173,7 @@ static noinline int v4l1_compat_set_vbi_format( err = -EINVAL; goto done; } - err = drv(inode, file, VIDIOC_S_FMT, fmt2); + err = drv(file, VIDIOC_S_FMT, fmt2); if (err < 0) dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err); done: @@ -1213,8 +1185,7 @@ done: * This function is exported. */ int -v4l_compat_translate_ioctl(struct inode *inode, - struct file *file, +v4l_compat_translate_ioctl(struct file *file, int cmd, void *arg, v4l2_kioctl drv) @@ -1223,52 +1194,52 @@ v4l_compat_translate_ioctl(struct inode *inode, switch (cmd) { case VIDIOCGCAP: /* capability */ - err = v4l1_compat_get_capabilities(arg, inode, file, drv); + err = v4l1_compat_get_capabilities(arg, file, drv); break; case VIDIOCGFBUF: /* get frame buffer */ - err = v4l1_compat_get_frame_buffer(arg, inode, file, drv); + err = v4l1_compat_get_frame_buffer(arg, file, drv); break; case VIDIOCSFBUF: /* set frame buffer */ - err = v4l1_compat_set_frame_buffer(arg, inode, file, drv); + err = v4l1_compat_set_frame_buffer(arg, file, drv); break; case VIDIOCGWIN: /* get window or capture dimensions */ - err = v4l1_compat_get_win_cap_dimensions(arg, inode, file, drv); + err = v4l1_compat_get_win_cap_dimensions(arg, file, drv); break; case VIDIOCSWIN: /* set window and/or capture dimensions */ - err = v4l1_compat_set_win_cap_dimensions(arg, inode, file, drv); + err = v4l1_compat_set_win_cap_dimensions(arg, file, drv); break; case VIDIOCCAPTURE: /* turn on/off preview */ - err = v4l1_compat_turn_preview_on_off(arg, inode, file, drv); + err = v4l1_compat_turn_preview_on_off(arg, file, drv); break; case VIDIOCGCHAN: /* get input information */ - err = v4l1_compat_get_input_info(arg, inode, file, drv); + err = v4l1_compat_get_input_info(arg, file, drv); break; case VIDIOCSCHAN: /* set input */ - err = v4l1_compat_set_input(arg, inode, file, drv); + err = v4l1_compat_set_input(arg, file, drv); break; case VIDIOCGPICT: /* get tone controls & partial capture format */ - err = v4l1_compat_get_picture(arg, inode, file, drv); + err = v4l1_compat_get_picture(arg, file, drv); break; case VIDIOCSPICT: /* set tone controls & partial capture format */ - err = v4l1_compat_set_picture(arg, inode, file, drv); + err = v4l1_compat_set_picture(arg, file, drv); break; case VIDIOCGTUNER: /* get tuner information */ - err = v4l1_compat_get_tuner(arg, inode, file, drv); + err = v4l1_compat_get_tuner(arg, file, drv); break; case VIDIOCSTUNER: /* select a tuner input */ - err = v4l1_compat_select_tuner(arg, inode, file, drv); + err = v4l1_compat_select_tuner(arg, file, drv); break; case VIDIOCGFREQ: /* get frequency */ - err = v4l1_compat_get_frequency(arg, inode, file, drv); + err = v4l1_compat_get_frequency(arg, file, drv); break; case VIDIOCSFREQ: /* set frequency */ - err = v4l1_compat_set_frequency(arg, inode, file, drv); + err = v4l1_compat_set_frequency(arg, file, drv); break; case VIDIOCGAUDIO: /* get audio properties/controls */ - err = v4l1_compat_get_audio(arg, inode, file, drv); + err = v4l1_compat_get_audio(arg, file, drv); break; case VIDIOCSAUDIO: /* set audio controls */ - err = v4l1_compat_set_audio(arg, inode, file, drv); + err = v4l1_compat_set_audio(arg, file, drv); break; #if 0 case VIDIOCGMBUF: @@ -1277,16 +1248,16 @@ v4l_compat_translate_ioctl(struct inode *inode, transparent, thus there is no point to try that */ #endif case VIDIOCMCAPTURE: /* capture a frame */ - err = v4l1_compat_capture_frame(arg, inode, file, drv); + err = v4l1_compat_capture_frame(arg, file, drv); break; case VIDIOCSYNC: /* wait for a frame */ - err = v4l1_compat_sync(arg, inode, file, drv); + err = v4l1_compat_sync(arg, file, drv); break; case VIDIOCGVBIFMT: /* query VBI data capture format */ - err = v4l1_compat_get_vbi_format(arg, inode, file, drv); + err = v4l1_compat_get_vbi_format(arg, file, drv); break; case VIDIOCSVBIFMT: - err = v4l1_compat_set_vbi_format(arg, inode, file, drv); + err = v4l1_compat_set_vbi_format(arg, file, drv); break; default: err = -ENOIOCTLCMD; diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index b5baf8f7e..e87a04a60 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -28,7 +28,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Author: Alan Cox, <alan@redhat.com> + * Author: Alan Cox, <alan@lxorguk.ukuu.org.uk> * * Fixes: */ @@ -60,10 +60,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> -#ifdef CONFIG_KMOD -#include <linux/kmod.h> -#endif - #include <linux/videodev2.h> #include "compat.h" diff --git a/linux/drivers/media/video/compat_ioctl32.c b/linux/drivers/media/video/v4l2-compat-ioctl32.c index a37f3a64e..09d5c5693 100644 --- a/linux/drivers/media/video/compat_ioctl32.c +++ b/linux/drivers/media/video/v4l2-compat-ioctl32.c @@ -33,7 +33,7 @@ struct video_tuner32 { static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) { - if(!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) || + if (!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) || get_user(kp->tuner, &up->tuner) || copy_from_user(kp->name, up->name, 32) || get_user(kp->rangelow, &up->rangelow) || @@ -47,7 +47,7 @@ static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) { - if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) || put_user(kp->tuner, &up->tuner) || copy_to_user(up->name, kp->name, 32) || put_user(kp->rangelow, &up->rangelow) || @@ -66,7 +66,6 @@ struct video_audio32 { __u16 bass, treble; __u32 flags; __u8 name[16]; -// char name[16]; __u16 mode; __u16 balance; __u16 step; @@ -138,7 +137,7 @@ static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u { u32 tmp = (u32)((unsigned long)kp->base); - if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) || put_user(tmp, &up->base) || put_user(kp->height, &up->height) || put_user(kp->width, &up->width) || @@ -168,7 +167,7 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = file->f_op->unlocked_ioctl(file, cmd, arg); else if (file->f_op->ioctl) { lock_kernel(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg); #else ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg); @@ -184,7 +183,7 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* You get back everything except the clips... */ static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) { - if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) || put_user(kp->x, &up->x) || put_user(kp->y, &up->y) || put_user(kp->width, &up->width) || @@ -197,14 +196,12 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u } #endif -struct v4l2_clip32 -{ +struct v4l2_clip32 { struct v4l2_rect c; compat_caddr_t next; }; -struct v4l2_window32 -{ +struct v4l2_window32 { struct v4l2_rect w; enum v4l2_field field; __u32 chromakey; @@ -285,15 +282,13 @@ static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vb return 0; } -struct v4l2_format32 -{ +struct v4l2_format32 { enum v4l2_buf_type type; - union - { - struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE - struct v4l2_window32 win; // V4L2_BUF_TYPE_VIDEO_OVERLAY - struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE - __u8 raw_data[200]; // user-defined + union { + struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ + struct v4l2_window32 win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ + struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ + __u8 raw_data[200]; /* user-defined */ } fmt; }; @@ -310,7 +305,7 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user case V4L2_BUF_TYPE_VBI_CAPTURE: return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); default: - printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n", + printk(KERN_INFO "compat_ioctl: unexpected VIDIOC_FMT type %d\n", kp->type); return -ENXIO; } @@ -318,7 +313,7 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) { - if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || put_user(kp->type, &up->type)) return -EFAULT; switch (kp->type) { @@ -348,8 +343,7 @@ static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standa return 0; } -struct v4l2_standard32 -{ +struct v4l2_standard32 { __u32 index; __u32 id[2]; /* __u64 would get the alignment wrong */ __u8 name[24]; @@ -369,7 +363,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) { - if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || put_user(kp->index, &up->index) || copy_to_user(up->id, &kp->id, sizeof(__u64)) || copy_to_user(up->name, kp->name, 24) || @@ -395,8 +389,7 @@ static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user return 0; } -struct v4l2_buffer32 -{ +struct v4l2_buffer32 { __u32 index; enum v4l2_buf_type type; __u32 bytesused; @@ -427,7 +420,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user get_user(kp->memory, &up->memory) || get_user(kp->input, &up->input)) return -EFAULT; - switch(kp->memory) { + switch (kp->memory) { case V4L2_MEMORY_MMAP: break; case V4L2_MEMORY_USERPTR: @@ -442,7 +435,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user } break; case V4L2_MEMORY_OVERLAY: - if(get_user(kp->m.offset, &up->m.offset)) + if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; } @@ -458,7 +451,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->memory, &up->memory) || put_user(kp->input, &up->input)) return -EFAULT; - switch(kp->memory) { + switch (kp->memory) { case V4L2_MEMORY_MMAP: if (put_user(kp->length, &up->length) || put_user(kp->m.offset, &up->m.offset)) @@ -485,8 +478,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user return 0; } -struct v4l2_framebuffer32 -{ +struct v4l2_framebuffer32 { __u32 capability; __u32 flags; compat_caddr_t base; @@ -511,7 +503,7 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame { u32 tmp = (u32)((unsigned long)kp->base); - if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) || put_user(tmp, &up->base) || put_user(kp->capability, &up->capability) || put_user(kp->flags, &up->flags)) @@ -549,8 +541,7 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user } #ifdef CONFIG_VIDEO_V4L1_COMPAT -struct video_code32 -{ +struct video_code32 { char loadwhat[16]; /* name or tag of file being passed */ compat_int_t datasize; unsigned char *data; @@ -558,28 +549,28 @@ struct video_code32 static inline int microcode32(struct video_code *kp, struct video_code32 __user *up) { - if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) || - copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) || + if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) || + copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) || get_user(kp->datasize, &up->datasize) || copy_from_user(kp->data, up->data, up->datasize)) return -EFAULT; return 0; } -#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) -#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) -#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) -#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) -#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) -#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) -#define VIDIOCGFREQ32 _IOR('v',14, u32) -#define VIDIOCSFREQ32 _IOW('v',15, u32) -#define VIDIOCSMICROCODE32 _IOW('v',27, struct video_code32) +#define VIDIOCGTUNER32 _IOWR('v', 4, struct video_tuner32) +#define VIDIOCSTUNER32 _IOW('v', 5, struct video_tuner32) +#define VIDIOCGWIN32 _IOR('v', 9, struct video_window32) +#define VIDIOCSWIN32 _IOW('v', 10, struct video_window32) +#define VIDIOCGFBUF32 _IOR('v', 11, struct video_buffer32) +#define VIDIOCSFBUF32 _IOW('v', 12, struct video_buffer32) +#define VIDIOCGFREQ32 _IOR('v', 14, u32) +#define VIDIOCSFREQ32 _IOW('v', 15, u32) +#define VIDIOCSMICROCODE32 _IOW('v', 27, struct video_code32) #endif /* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */ -#define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4) +#define VIDIOC_ENUMINPUT32 (VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4)) #define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32) #define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32) #define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32) @@ -689,7 +680,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg int realcmd = cmd; /* First, convert the command. */ - switch(cmd) { + switch (cmd) { #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break; case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break; @@ -718,7 +709,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break; }; - switch(cmd) { + switch (cmd) { #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCSTUNER: case VIDIOCGTUNER: @@ -810,20 +801,20 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg break; #endif }; - if(err) + if (err) goto out; - if(compatible_arg) + if (compatible_arg) err = native_ioctl(file, realcmd, (unsigned long)up); else { mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - err = native_ioctl(file, realcmd, (unsigned long) &karg); + err = native_ioctl(file, realcmd, (unsigned long)&karg); set_fs(old_fs); } - if(err == 0) { - switch(cmd) { + if (err == 0) { + switch (cmd) { #ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGTUNER: err = put_video_tuner32(&karg.vt, up); @@ -932,6 +923,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_STREAMON32: case VIDIOC_STREAMOFF32: case VIDIOC_G_PARM: + case VIDIOC_S_PARM: case VIDIOC_G_STD: case VIDIOC_S_STD: case VIDIOC_G_TUNER: @@ -950,6 +942,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_S_INPUT32: case VIDIOC_TRY_FMT32: case VIDIOC_S_HW_FREQ_SEEK: + case VIDIOC_ENUM_FRAMESIZES: + case VIDIOC_ENUM_FRAMEINTERVALS: ret = do_video_ioctl(file, cmd, arg); break; diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c index 70f852c37..3b8f33c8d 100644 --- a/linux/drivers/media/video/v4l2-dev.c +++ b/linux/drivers/media/video/v4l2-dev.c @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Authors: Alan Cox, <alan@redhat.com> (version 1) + * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1) * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) * * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> @@ -381,7 +381,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, #else if (vfd->parent) vfd->dev.parent = vfd->parent; - sprintf(vfd->dev.bus_id, "%s%d", name_base, nr); + dev_set_name(&vfd->dev, "%s%d", name_base, nr); ret = device_register(&vfd->dev); #endif if (ret < 0) { diff --git a/linux/drivers/media/video/v4l2-int-device.c b/linux/drivers/media/video/v4l2-int-device.c index 4434a9e9e..00c9bb7d6 100644 --- a/linux/drivers/media/video/v4l2-int-device.c +++ b/linux/drivers/media/video/v4l2-int-device.c @@ -33,7 +33,7 @@ static DEFINE_MUTEX(mutex); static LIST_HEAD(int_list); -static void v4l2_int_device_try_attach_all(void) +void v4l2_int_device_try_attach_all(void) { struct v4l2_int_device *m, *s; @@ -67,6 +67,7 @@ static void v4l2_int_device_try_attach_all(void) } } } +EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all); static int ioctl_sort_cmp(const void *a, const void *b) { @@ -145,6 +146,7 @@ int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) find_ioctl(d->u.slave, cmd, (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); } +EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0); static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) { @@ -157,5 +159,6 @@ int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) find_ioctl(d->u.slave, cmd, (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); } +EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1); MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index 3a68d6e35..86dd04026 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Authors: Alan Cox, <alan@redhat.com> (version 1) + * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1) * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2) */ @@ -394,10 +394,8 @@ video_fix_command(unsigned int cmd) * Obsolete usercopy function - Should be removed soon */ int -video_usercopy(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg)) +video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, + v4l2_kioctl func) { char sbuf[128]; void *mbuf = NULL; @@ -459,7 +457,7 @@ video_usercopy(struct inode *inode, struct file *file, } /* call driver */ - err = func(inode, file, cmd, parg); + err = func(file, cmd, parg); if (err == -ENOIOCTLCMD) err = -EINVAL; if (is_ext_ctrl) { @@ -626,13 +624,13 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) return -EINVAL; } -static int __video_do_ioctl(struct inode *inode, struct file *file, +static int __video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vfd = video_devdata(file); const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; - void *fh = file->private_data; - int ret = -EINVAL; + void *fh = file->private_data; + int ret = -EINVAL; if ((vfd->debug & V4L2_DEBUG_IOCTL) && !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { @@ -676,7 +674,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, V4L2 ioctls. ********************************************************/ if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) - return v4l_compat_translate_ioctl(inode, file, cmd, arg, + return v4l_compat_translate_ioctl(file, cmd, arg, __video_do_ioctl); #endif @@ -1482,9 +1480,15 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_CROP: { struct v4l2_crop *p = arg; + __u32 type; if (!ops->vidioc_g_crop) break; + + type = p->type; + memset(p, 0, sizeof(*p)); + p->type = type; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_g_crop(file, fh, p); if (!ret) @@ -1505,10 +1509,16 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_CROPCAP: { struct v4l2_cropcap *p = arg; + __u32 type; /*FIXME: Should also show v4l2_fract pixelaspect */ if (!ops->vidioc_cropcap) break; + + type = p->type; + memset(p, 0, sizeof(*p)); + p->type = type; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_cropcap(file, fh, p); if (!ret) { @@ -1523,6 +1533,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!ops->vidioc_g_jpegcomp) break; + + memset(p, 0, sizeof(*p)); + ret = ops->vidioc_g_jpegcomp(file, fh, p); if (!ret) dbgarg(cmd, "quality=%d, APPn=%d, " @@ -1750,6 +1763,77 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret = ops->vidioc_s_hw_freq_seek(file, fh, p); break; } + case VIDIOC_ENUM_FRAMESIZES: + { + struct v4l2_frmsizeenum *p = arg; + + if (!ops->vidioc_enum_framesizes) + break; + + memset(p, 0, sizeof(*p)); + + ret = ops->vidioc_enum_framesizes(file, fh, p); + dbgarg(cmd, + "index=%d, pixelformat=%d, type=%d ", + p->index, p->pixel_format, p->type); + switch (p->type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + dbgarg2("width = %d, height=%d\n", + p->discrete.width, p->discrete.height); + break; + case V4L2_FRMSIZE_TYPE_STEPWISE: + dbgarg2("min %dx%d, max %dx%d, step %dx%d\n", + p->stepwise.min_width, p->stepwise.min_height, + p->stepwise.step_width, p->stepwise.step_height, + p->stepwise.max_width, p->stepwise.max_height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + dbgarg2("continuous\n"); + break; + default: + dbgarg2("- Unknown type!\n"); + } + + break; + } + case VIDIOC_ENUM_FRAMEINTERVALS: + { + struct v4l2_frmivalenum *p = arg; + + if (!ops->vidioc_enum_frameintervals) + break; + + memset(p, 0, sizeof(*p)); + + ret = ops->vidioc_enum_frameintervals(file, fh, p); + dbgarg(cmd, + "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", + p->index, p->pixel_format, + p->width, p->height, p->type); + switch (p->type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + dbgarg2("fps=%d/%d\n", + p->discrete.numerator, + p->discrete.denominator); + break; + case V4L2_FRMIVAL_TYPE_STEPWISE: + dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n", + p->stepwise.min.numerator, + p->stepwise.min.denominator, + p->stepwise.max.numerator, + p->stepwise.max.denominator, + p->stepwise.step.numerator, + p->stepwise.step.denominator); + break; + case V4L2_FRMIVAL_TYPE_CONTINUOUS: + dbgarg2("continuous\n"); + break; + default: + dbgarg2("- Unknown type!\n"); + } + break; + } + default: { if (!ops->vidioc_default) @@ -1769,7 +1853,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, return ret; } -int video_ioctl2(struct inode *inode, struct file *file, +int __video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) { char sbuf[128]; @@ -1833,7 +1917,7 @@ int video_ioctl2(struct inode *inode, struct file *file, } /* Handles IOCTL */ - err = __video_do_ioctl(inode, file, cmd, parg); + err = __video_do_ioctl(file, cmd, parg); if (err == -ENOIOCTLCMD) err = -EINVAL; if (is_ext_ctrl) { @@ -1861,4 +1945,11 @@ out: kfree(mbuf); return err; } +EXPORT_SYMBOL(__video_ioctl2); + +int video_ioctl2(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return __video_ioctl2(file, cmd, arg); +} EXPORT_SYMBOL(video_ioctl2); diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c index 33e2f2b2b..2d382373b 100644 --- a/linux/drivers/media/video/videobuf-dvb.c +++ b/linux/drivers/media/video/videobuf-dvb.c @@ -131,7 +131,6 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) mutex_lock(&dvb->lock); dvb->nfeeds--; if (0 == dvb->nfeeds && NULL != dvb->thread) { - // FIXME: cx8802_cancel_buffers(dev); err = kthread_stop(dvb->thread); dvb->thread = NULL; } @@ -139,50 +138,7 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) return err; } -/* ------------------------------------------------------------------ */ -/* Register a single adapter and one or more frontends */ -int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, - struct module *module, - void *adapter_priv, - struct device *device, - short *adapter_nr, - int mfe_shared) -{ - struct list_head *list, *q; - struct videobuf_dvb_frontend *fe; - int res = -EINVAL; - - fe = videobuf_dvb_get_frontend(f, 1); - if (!fe) { - printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); - goto err; - } - - /* Bring up the adapter */ - res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared); - if (res < 0) { - printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); - goto err; - } - - /* Attach all of the frontends to the adapter */ - mutex_lock(&f->lock); - list_for_each_safe(list, q, &f->frontend.felist) { - fe = list_entry(list, struct videobuf_dvb_frontend, felist); - - res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb); - if (res < 0) { - printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", - fe->dvb.name, res); - } - } - mutex_unlock(&f->lock); - -err: - return res; -} - -int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, +static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, struct module *module, void *adapter_priv, struct device *device, @@ -195,7 +151,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, mutex_init(&fe->lock); /* register adapter */ - result = dvb_register_adapter(&fe->adapter, adapter_name, module, device, adapter_nr); + result = dvb_register_adapter(&fe->adapter, adapter_name, module, + device, adapter_nr); if (result < 0) { printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", adapter_name, result); @@ -206,7 +163,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, return result; } -int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_dvb *dvb) +static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, + struct videobuf_dvb *dvb) { int result; @@ -270,6 +228,10 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_ /* register network adapter */ dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); + if (dvb->net.dvbdev == NULL) { + result = -ENOMEM; + goto fail_fe_conn; + } return 0; fail_fe_conn: @@ -284,44 +246,76 @@ fail_dmx: dvb_unregister_frontend(dvb->frontend); fail_frontend: dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(adapter); + dvb->frontend = NULL; return result; } -void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) +/* ------------------------------------------------------------------ */ +/* Register a single adapter and one or more frontends */ +int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, + struct module *module, + void *adapter_priv, + struct device *device, + short *adapter_nr, + int mfe_shared) { struct list_head *list, *q; struct videobuf_dvb_frontend *fe; + int res; - mutex_lock(&f->lock); - list_for_each_safe(list, q, &f->frontend.felist) { - fe = list_entry(list, struct videobuf_dvb_frontend, felist); + fe = videobuf_dvb_get_frontend(f, 1); + if (!fe) { + printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); + return -EINVAL; + } - dvb_net_release(&fe->dvb.net); - fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem); - fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw); - dvb_dmxdev_release(&fe->dvb.dmxdev); - dvb_dmx_release(&fe->dvb.demux); - dvb_unregister_frontend(fe->dvb.frontend); - dvb_frontend_detach(fe->dvb.frontend); + /* Bring up the adapter */ + res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, + fe->dvb.name, adapter_nr, mfe_shared); + if (res < 0) { + printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); + return res; + } - list_del(list); - kfree(fe); + /* Attach all of the frontends to the adapter */ + mutex_lock(&f->lock); + list_for_each_safe(list, q, &f->felist) { + fe = list_entry(list, struct videobuf_dvb_frontend, felist); + res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb); + if (res < 0) { + printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", + fe->dvb.name, res); + goto err; + } } mutex_unlock(&f->lock); + return 0; + +err: + mutex_unlock(&f->lock); + videobuf_dvb_unregister_bus(f); + return res; +} +EXPORT_SYMBOL(videobuf_dvb_register_bus); + +void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) +{ + videobuf_dvb_dealloc_frontends(f); dvb_unregister_adapter(&f->adapter); } +EXPORT_SYMBOL(videobuf_dvb_unregister_bus); -struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id) +struct videobuf_dvb_frontend *videobuf_dvb_get_frontend( + struct videobuf_dvb_frontends *f, int id) { struct list_head *list, *q; struct videobuf_dvb_frontend *fe, *ret = NULL; mutex_lock(&f->lock); - list_for_each_safe(list, q, &f->frontend.felist) { + list_for_each_safe(list, q, &f->felist) { fe = list_entry(list, struct videobuf_dvb_frontend, felist); if (fe->id == id) { ret = fe; @@ -333,8 +327,10 @@ struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_fro return ret; } +EXPORT_SYMBOL(videobuf_dvb_get_frontend); -int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p) +int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, + struct dvb_frontend *p) { struct list_head *list, *q; struct videobuf_dvb_frontend *fe = NULL; @@ -342,7 +338,7 @@ int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_fron mutex_lock(&f->lock); - list_for_each_safe(list, q, &f->frontend.felist) { + list_for_each_safe(list, q, &f->felist) { fe = list_entry(list, struct videobuf_dvb_frontend, felist); if (fe->dvb.frontend == p) { ret = fe->id; @@ -354,37 +350,53 @@ int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_fron return ret; } +EXPORT_SYMBOL(videobuf_dvb_find_frontend); -struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(void *private, struct videobuf_dvb_frontends *f, int id) +struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend( + struct videobuf_dvb_frontends *f, int id) { struct videobuf_dvb_frontend *fe; - fe = kzalloc(sizeof(struct videobuf_dvb_frontend),GFP_KERNEL); + fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL); if (fe == NULL) goto fail_alloc; - fe->dev = private; fe->id = id; mutex_init(&fe->dvb.lock); mutex_lock(&f->lock); - list_add_tail(&fe->felist,&f->frontend.felist); + list_add_tail(&fe->felist, &f->felist); mutex_unlock(&f->lock); fail_alloc: return fe; } - -EXPORT_SYMBOL(videobuf_dvb_register_bus); -EXPORT_SYMBOL(videobuf_dvb_unregister_bus); EXPORT_SYMBOL(videobuf_dvb_alloc_frontend); -EXPORT_SYMBOL(videobuf_dvb_get_frontend); -EXPORT_SYMBOL(videobuf_dvb_find_frontend); -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ +void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f) +{ + struct list_head *list, *q; + struct videobuf_dvb_frontend *fe; + + mutex_lock(&f->lock); + list_for_each_safe(list, q, &f->felist) { + fe = list_entry(list, struct videobuf_dvb_frontend, felist); + if (fe->dvb.net.dvbdev) { + dvb_net_release(&fe->dvb.net); + fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, + &fe->dvb.fe_mem); + fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, + &fe->dvb.fe_hw); + dvb_dmxdev_release(&fe->dvb.dmxdev); + dvb_dmx_release(&fe->dvb.demux); + dvb_unregister_frontend(fe->dvb.frontend); + } + if (fe->dvb.frontend) + /* always allocated, may have been reset */ + dvb_frontend_detach(fe->dvb.frontend); + list_del(list); /* remove list entry */ + kfree(fe); /* free frontend allocation */ + } + mutex_unlock(&f->lock); +} +EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends); diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c index 08eb57818..50f685fae 100644 --- a/linux/drivers/media/video/vino.c +++ b/linux/drivers/media/video/vino.c @@ -30,10 +30,7 @@ #include <linux/mm.h> #include <linux/time.h> #include <linux/version.h> - -#ifdef CONFIG_KMOD #include <linux/kmod.h> -#endif #include <linux/i2c.h> #include <linux/i2c-algo-sgi.h> @@ -4244,8 +4241,7 @@ error: return ret; } -static int vino_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vino_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct vino_channel_settings *vcs = video_drvdata(file); @@ -4360,7 +4356,7 @@ static int vino_ioctl(struct inode *inode, struct file *file, if (mutex_lock_interruptible(&vcs->mutex)) return -EINTR; - ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl); + ret = video_usercopy(file, cmd, arg, vino_do_ioctl); mutex_unlock(&vcs->mutex); @@ -4638,7 +4634,7 @@ static int __init vino_module_init(void) } vino_init_stage++; -#if defined(CONFIG_KMOD) && defined(MODULE) +#ifdef MODULE request_module("saa7191"); request_module("indycam"); #endif diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c index f6a12b184..692a90c35 100644 --- a/linux/drivers/media/video/vivi.c +++ b/linux/drivers/media/video/vivi.c @@ -131,12 +131,56 @@ struct vivi_fmt { int depth; }; -static struct vivi_fmt format = { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, +static struct vivi_fmt formats[] = { + { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + }, + { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + }, + { + .name = "RGB565 (LE)", + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .depth = 16, + }, + { + .name = "RGB565 (BE)", + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .depth = 16, + }, + { + .name = "RGB555 (LE)", + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .depth = 16, + }, + { + .name = "RGB555 (BE)", + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .depth = 16, + }, }; +static struct vivi_fmt *get_format(struct v4l2_format *f) +{ + struct vivi_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->fourcc == f->fmt.pix.pixelformat) + break; + } + + if (k == ARRAY_SIZE(formats)) + return NULL; + + return &formats[k]; +} + struct sg_to_addr { int pos; struct scatterlist *sg; @@ -193,6 +237,7 @@ struct vivi_fh { struct videobuf_queue vb_vidq; enum v4l2_buf_type type; + unsigned char bars[8][3]; }; /* ------------------------------------------------------------------ @@ -237,42 +282,118 @@ static u8 bars[8][3] = { #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_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos) { - int w, i, j, y; - int pos = inipos; - char *p, *s; - u8 chr, r, g, b, color; + unsigned char r_y, g_u, b_v; + unsigned char *p; + int color; - /* We will just duplicate the second pixel at the packet */ - wmax /= 2; + r_y = fh->bars[colorpos][0]; /* R or precalculated Y */ + g_u = fh->bars[colorpos][1]; /* G or precalculated U */ + b_v = fh->bars[colorpos][2]; /* B or precalculated V */ - /* Generate a standard color bar pattern */ - for (w = 0; w < wmax; w++) { - int colorpos = ((w + count) * 8/(wmax + 1)) % 8; - r = bars[colorpos][0]; - g = bars[colorpos][1]; - b = bars[colorpos][2]; - - for (color = 0; color < 4; color++) { - p = basep + pos; + for (color = 0; color < 4; color++) { + p = buf + color; + switch (fh->fmt->fourcc) { + case V4L2_PIX_FMT_YUYV: switch (color) { case 0: case 2: - *p = TO_Y(r, g, b); /* Luma */ + *p = r_y; break; case 1: - *p = TO_U(r, g, b); /* Cb */ + *p = g_u; break; case 3: - *p = TO_V(r, g, b); /* Cr */ + *p = b_v; + break; + } + break; + case V4L2_PIX_FMT_UYVY: + switch (color) { + case 1: + case 3: + *p = r_y; + break; + case 0: + *p = g_u; + break; + case 2: + *p = b_v; + break; + } + break; + case V4L2_PIX_FMT_RGB565: + switch (color) { + case 0: + case 2: + *p = (g_u << 5) | b_v; + break; + case 1: + case 3: + *p = (r_y << 3) | (g_u >> 3); + break; + } + break; + case V4L2_PIX_FMT_RGB565X: + switch (color) { + case 0: + case 2: + *p = (r_y << 3) | (g_u >> 3); + break; + case 1: + case 3: + *p = (g_u << 5) | b_v; break; } - pos++; + break; + case V4L2_PIX_FMT_RGB555: + switch (color) { + case 0: + case 2: + *p = (g_u << 5) | b_v; + break; + case 1: + case 3: + *p = (r_y << 2) | (g_u >> 3); + break; + } + break; + case V4L2_PIX_FMT_RGB555X: + switch (color) { + case 0: + case 2: + *p = (r_y << 2) | (g_u >> 3); + break; + case 1: + case 3: + *p = (g_u << 5) | b_v; + break; + } + break; } } +} + +static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax, + int hmax, int line, int count, char *timestr) +{ + int w, i, j; + int pos = inipos; + char *s; + u8 chr; + + /* We will just duplicate the second pixel at the packet */ + wmax /= 2; + + /* Generate a standard color bar pattern */ + for (w = 0; w < wmax; w++) { + int colorpos = ((w + count) * 8/(wmax + 1)) % 8; + + gen_twopix(fh, basep + pos, colorpos); + pos += 4; /* only 16 bpp supported for now */ + } /* Checks if it is possible to show timestamp */ if (TSTAMP_MAX_Y >= hmax) @@ -286,38 +407,12 @@ static void gen_line(char *basep, int inipos, int wmax, 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; - - y = TO_Y(r, g, b); - - switch (color) { - 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++; - } + /* Draw white font on black background */ + if (chr & 1 << (7 - i)) + gen_twopix(fh, basep + pos, WHITE); + else + gen_twopix(fh, basep + pos, BLACK); j++; } } @@ -327,8 +422,9 @@ end: return; } -static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) +static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf) { + struct vivi_dev *dev = fh->dev; int h , pos = 0; int hmax = buf->vb.height; int wmax = buf->vb.width; @@ -344,7 +440,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) return; for (h = 0; h < hmax; h++) { - gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count, + gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count, dev->timestr); memcpy(vbuf + pos, tmpbuf, wmax * 2); pos += wmax*2; @@ -413,7 +509,7 @@ static void vivi_thread_tick(struct vivi_fh *fh) do_gettimeofday(&buf->vb.ts); /* Fill buffer */ - vivi_fillbuff(dev, buf); + vivi_fillbuff(fh, buf); dprintk(dev, 1, "filled buffer %p\n", buf); wake_up(&buf->vb.done); @@ -639,11 +735,15 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index > 0) + struct vivi_fmt *fmt; + + if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; - strlcpy(f->description, format.name, sizeof(f->description)); - f->pixelformat = format.fourcc; + fmt = &formats[f->index]; + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; return 0; } @@ -673,13 +773,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, enum v4l2_field field; unsigned int maxw, maxh; - if (format.fourcc != f->fmt.pix.pixelformat) { - dprintk(dev, 1, "Fourcc format (0x%08x) invalid. " - "Driver accepts only 0x%08x\n", - f->fmt.pix.pixelformat, format.fourcc); + fmt = get_format(f); + if (!fmt) { + dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); return -EINVAL; } - fmt = &format; field = f->fmt.pix.field; @@ -717,6 +816,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, { struct vivi_fh *fh = priv; struct videobuf_queue *q = &fh->vb_vidq; + unsigned char r, g, b; + int k, is_yuv; int ret = vidioc_try_fmt_vid_cap(file, fh, f); if (ret < 0) @@ -730,12 +831,49 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, goto out; } - fh->fmt = &format; + fh->fmt = get_format(f); fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; fh->vb_vidq.field = f->fmt.pix.field; fh->type = f->type; + /* precalculate color bar values to speed up rendering */ + for (k = 0; k < 8; k++) { + r = bars[k][0]; + g = bars[k][1]; + b = bars[k][2]; + is_yuv = 0; + + switch (fh->fmt->fourcc) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + is_yuv = 1; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + r >>= 3; + g >>= 2; + b >>= 3; + break; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + r >>= 3; + g >>= 3; + b >>= 3; + break; + } + + if (is_yuv) { + fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ + fh->bars[k][1] = TO_U(r, g, b); /* Cb */ + fh->bars[k][2] = TO_V(r, g, b); /* Cr */ + } else { + fh->bars[k][0] = r; + fh->bars[k][1] = g; + fh->bars[k][2] = b; + } + } + ret = 0; out: mutex_unlock(&q->vb_lock); @@ -889,8 +1027,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, File operations for the device ------------------------------------------------------------------*/ -#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8) - static int vivi_open(struct inode *inode, struct file *file) { int minor = iminor(inode); @@ -939,7 +1075,7 @@ unlock: fh->dev = dev; fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fh->fmt = &format; + fh->fmt = &formats[0]; fh->width = 640; fh->height = 480; @@ -1030,11 +1166,11 @@ static int vivi_release(void) if (-1 != dev->vfd->minor) { printk(KERN_INFO "%s: unregistering /dev/video%d\n", - VIVI_MODULE_NAME, dev->vfd->minor); + VIVI_MODULE_NAME, dev->vfd->num); video_unregister_device(dev->vfd); } else { printk(KERN_INFO "%s: releasing /dev/video%d\n", - VIVI_MODULE_NAME, dev->vfd->minor); + VIVI_MODULE_NAME, dev->vfd->num); video_device_release(dev->vfd); } @@ -1174,7 +1310,7 @@ static int __init vivi_init(void) dev->vfd = vfd; printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n", - VIVI_MODULE_NAME, vfd->minor); + VIVI_MODULE_NAME, vfd->num); } if (ret < 0) { diff --git a/linux/drivers/media/video/w9966.c b/linux/drivers/media/video/w9966.c index f3f28c232..53f317dcd 100644 --- a/linux/drivers/media/video/w9966.c +++ b/linux/drivers/media/video/w9966.c @@ -728,8 +728,7 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) * Video4linux interfacing */ -static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct w9966_dev *cam = video_drvdata(file); @@ -882,7 +881,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file, static int w9966_v4l_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, w9966_v4l_do_ioctl); + return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl); } // Capture data diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c index 4e7a8400b..ab3c054c4 100644 --- a/linux/drivers/media/video/w9968cf.c +++ b/linux/drivers/media/video/w9968cf.c @@ -111,7 +111,7 @@ static int specific_debug = W9968CF_SPECIFIC_DEBUG; static unsigned int param_nv[24]; /* number of values per parameter */ -#ifdef CONFIG_KMOD +#ifdef CONFIG_MODULES module_param(ovmod_load, bool, 0644); #endif module_param(simcams, ushort, 0644); @@ -144,7 +144,7 @@ module_param(debug, ushort, 0644); module_param(specific_debug, bool, 0644); #endif -#ifdef CONFIG_KMOD +#ifdef CONFIG_MODULES MODULE_PARM_DESC(ovmod_load, "\n<0|1> Automatic 'ovcamchip' module loading." "\n0 disabled, 1 enabled." @@ -2406,7 +2406,7 @@ error: cam->sensor = CC_UNKNOWN; DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " "Try to detach and attach this device again", - symbolic(camlist, cam->id), cam->v4ldev->minor) + symbolic(camlist, cam->id), cam->v4ldev->num) return err; } @@ -2652,7 +2652,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) { mutex_lock(&w9968cf_devlist_mutex); - DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) + DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num) video_unregister_device(cam->v4ldev); list_del(&cam->v4llist); @@ -2687,7 +2687,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) DBG(2, "No supported image sensor has been detected by the " "'ovcamchip' module for the %s (/dev/video%d). Make " "sure it is loaded *before* (re)connecting the camera.", - symbolic(camlist, cam->id), cam->v4ldev->minor) + symbolic(camlist, cam->id), cam->v4ldev->num) mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); return -ENODEV; @@ -2695,7 +2695,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) if (cam->users) { DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", - symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) + symbolic(camlist, cam->id), cam->v4ldev->num, cam->command) if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); @@ -2717,7 +2717,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) } DBG(5, "Opening '%s', /dev/video%d ...", - symbolic(camlist, cam->id), cam->v4ldev->minor) + symbolic(camlist, cam->id), cam->v4ldev->num) cam->streaming = 0; cam->misconfigured = 0; @@ -2955,7 +2955,7 @@ static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, .minheight = cam->minheight, }; sprintf(cap.name, "W996[87]CF USB Camera #%d", - cam->v4ldev->minor); + cam->v4ldev->num); cap.maxwidth = (cam->upscaling && w9968cf_vpp) ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) : cam->maxwidth; @@ -3575,7 +3575,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor) + DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num) /* Set some basic constants */ w9968cf_configure_camera(cam, udev, mod_id, dev_nr); @@ -3626,7 +3626,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) DBG(2, "The device is open (/dev/video%d)! " "Process name: %s. Deregistration and memory " "deallocation are deferred on close.", - cam->v4ldev->minor, cam->command) + cam->v4ldev->num, cam->command) cam->misconfigured = 1; w9968cf_stop_transfer(cam); wake_up_interruptible(&cam->wait_queue); diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c index 0be0f095e..a8c1f6730 100644 --- a/linux/drivers/media/video/zc0301/zc0301_core.c +++ b/linux/drivers/media/video/zc0301/zc0301_core.c @@ -543,7 +543,7 @@ static int zc0301_stream_interrupt(struct zc0301_device* cam) cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " "use it, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -644,7 +644,7 @@ static void zc0301_release_resources(struct kref *kref) { struct zc0301_device *cam = container_of(kref, struct zc0301_device, kref); - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); @@ -683,7 +683,7 @@ static int zc0301_open(struct inode* inode, struct file* filp) } if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); + DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->num); DBG(3, "Simultaneous opens are not supported"); if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { @@ -726,7 +726,7 @@ static int zc0301_open(struct inode* inode, struct file* filp) cam->frame_count = 0; zc0301_empty_framequeues(cam); - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); + DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); out: mutex_unlock(&cam->open_mutex); @@ -750,7 +750,7 @@ static int zc0301_release(struct inode* inode, struct file* filp) cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); + DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); kref_put(&cam->kref, zc0301_release_resources); @@ -1024,7 +1024,7 @@ zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg) strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, + strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), sizeof(cap.bus_info)); if (copy_to_user(arg, &cap, sizeof(cap))) @@ -1279,7 +1279,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -1292,7 +1292,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -ENOMEM; } @@ -1474,7 +1474,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -EIO; } @@ -1486,7 +1486,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); + cam->v4ldev->num); return -ENOMEM; } @@ -1533,7 +1533,7 @@ zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->minor); + "/dev/video%d again.", cam->v4ldev->num); return -EIO; } @@ -2009,7 +2009,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; @@ -2048,7 +2048,7 @@ static void zc0301_usb_disconnect(struct usb_interface* intf) if (cam->users) { DBG(2, "Device /dev/video%d is open! Deregistration and " "memory deallocation are deferred.", - cam->v4ldev->minor); + cam->v4ldev->num); cam->state |= DEV_MISCONFIGURED; zc0301_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; diff --git a/linux/drivers/media/video/zoran/zoran_driver.c b/linux/drivers/media/video/zoran/zoran_driver.c index 9d57a630c..605195a82 100644 --- a/linux/drivers/media/video/zoran/zoran_driver.c +++ b/linux/drivers/media/video/zoran/zoran_driver.c @@ -2005,11 +2005,7 @@ zoran_set_input (struct zoran *zr, * ioctl routine */ -static int -zoran_do_ioctl (struct inode *inode, - struct file *file, - unsigned int cmd, - void *arg) +static int zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; @@ -3061,7 +3057,6 @@ zoran_do_ioctl (struct inode *inode, break; default: - dprintk(3, "unsupported\n"); dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unsupported type %d\n", @@ -4267,7 +4262,7 @@ zoran_ioctl (struct inode *inode, unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, zoran_do_ioctl); + return video_usercopy(file, cmd, arg, zoran_do_ioctl); } static unsigned int diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c index b0da282a5..1f43328a5 100644 --- a/linux/drivers/media/video/zr364xx.c +++ b/linux/drivers/media/video/zr364xx.c @@ -886,7 +886,7 @@ static int zr364xx_probe(struct usb_interface *intf, usb_set_intfdata(intf, cam); dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n", - cam->vdev->minor); + cam->vdev->num); return 0; } |