Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (95 commits) V4L/DVB (9296): Patch to remove warning message during cx88-dvb compilation V4L/DVB (9294): gspca: Add a stop sequence in t613. V4L/DVB (9293): gspca: Separate and fix the sensor dependant sequences in t613. V4L/DVB (9292): gspca: Call the control setting functions at init time in t613. V4L/DVB (9291): gspca: Do not set the white balance temperature by default in t613. V4L/DVB (9290): gspca: Adjust the sensor init sequences in t613. V4L/DVB (9289): gspca: Other sensor identified as om6802 in t613. V4L/DVB (9288): gspca: Write to the USB device and not USB interface in t613. V4L/DVB (9287): gspca: Change the name of the multi bytes write function in t613. V4L/DVB (9286): gspca: Compilation problem of gspca.c and the kernel version. V4L/DVB (9283): Correct typo and enable setting the gain on the mt9m111 sensor V4L/DVB (9282): Properly iterate the urbs when destroying them. V4L/DVB (9281): gspca: Add hflip and vflip to the po1030 sensor V4L/DVB (9280): gspca: Use the gspca debug macros V4L/DVB (9279): gspca: Correct some copyright headers V4L/DVB (9278): gspca: Remove the m5602_debug variable V4L/DVB (9277): gspca: propagate an error in m5602_start_transfer() V4L/DVB (9276): videobuf-dvb: two functions are now static V4L/DVB (9275): dvb: input data pointer of cx24116_writeregN() should be const V4L/DVB (9274): Remove spurious messages and turn into debug. ...
This commit is contained in:
commit
5564da7e9d
@ -1,5 +1,5 @@
|
||||
0 -> Unknown board (au0828)
|
||||
1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721f,2040:7280,0fd9:0008]
|
||||
1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008]
|
||||
2 -> Hauppauge HVR850 (au0828) [2040:7240]
|
||||
3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620]
|
||||
4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281]
|
||||
|
@ -75,3 +75,4 @@ tuner=73 - Samsung TCPG 6121P30A
|
||||
tuner=75 - Philips TEA5761 FM Radio
|
||||
tuner=76 - Xceive 5000 tuner
|
||||
tuner=77 - TCL tuner MF02GIP-5N-E
|
||||
tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
|
||||
|
@ -3481,7 +3481,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;
|
||||
}
|
||||
@ -3581,7 +3583,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 */
|
||||
@ -3910,7 +3912,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);
|
||||
}
|
||||
|
||||
@ -4092,7 +4097,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);
|
||||
|
@ -493,6 +493,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:
|
||||
@ -767,6 +768,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;
|
||||
|
@ -946,7 +946,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, },
|
||||
@ -984,6 +984,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 ----- */
|
||||
|
||||
@ -1663,6 +1684,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);
|
||||
|
||||
|
@ -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",
|
||||
@ -560,13 +562,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;
|
||||
@ -576,7 +578,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;
|
||||
@ -592,7 +595,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:
|
||||
@ -651,7 +654,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__);
|
||||
@ -748,42 +751,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;
|
||||
}
|
||||
@ -791,7 +794,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;
|
||||
@ -863,7 +866,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);
|
||||
@ -885,15 +888,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)
|
||||
@ -989,7 +990,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",
|
||||
|
@ -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
|
||||
|
@ -595,6 +595,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,
|
||||
|
@ -47,6 +47,7 @@ static int dvb_shutdown_timeout;
|
||||
static int dvb_force_auto_inversion;
|
||||
static int dvb_override_tune_delay;
|
||||
static int dvb_powerdown_on_sleep = 1;
|
||||
static int dvb_mfe_wait_time = 5;
|
||||
|
||||
module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
|
||||
MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
|
||||
@ -58,6 +59,8 @@ module_param(dvb_override_tune_delay, int, 0644);
|
||||
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
|
||||
module_param(dvb_powerdown_on_sleep, int, 0644);
|
||||
MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
|
||||
module_param(dvb_mfe_wait_time, int, 0644);
|
||||
MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
|
||||
|
||||
#define dprintk if (dvb_frontend_debug) printk
|
||||
|
||||
@ -212,8 +215,9 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
|
||||
|
||||
static void dvb_frontend_init(struct dvb_frontend *fe)
|
||||
{
|
||||
dprintk ("DVB: initialising frontend %i (%s)...\n",
|
||||
dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
|
||||
fe->dvb->num,
|
||||
fe->id,
|
||||
fe->ops.info.name);
|
||||
|
||||
if (fe->ops.init)
|
||||
@ -686,7 +690,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
|
||||
mb();
|
||||
|
||||
fe_thread = kthread_run(dvb_frontend_thread, fe,
|
||||
"kdvb-fe-%i", fe->dvb->num);
|
||||
"kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
|
||||
if (IS_ERR(fe_thread)) {
|
||||
ret = PTR_ERR(fe_thread);
|
||||
printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
|
||||
@ -710,8 +714,8 @@ static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
|
||||
*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
|
||||
|
||||
if (*freq_min == 0 || *freq_max == 0)
|
||||
printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
|
||||
fe->dvb->num);
|
||||
printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
|
||||
fe->dvb->num,fe->id);
|
||||
}
|
||||
|
||||
static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
||||
@ -724,8 +728,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
||||
dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
|
||||
if ((freq_min && parms->frequency < freq_min) ||
|
||||
(freq_max && parms->frequency > freq_max)) {
|
||||
printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
|
||||
fe->dvb->num, parms->frequency, freq_min, freq_max);
|
||||
printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
|
||||
fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -735,8 +739,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
||||
parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
|
||||
(fe->ops.info.symbol_rate_max &&
|
||||
parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
|
||||
printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
|
||||
fe->dvb->num, parms->u.qpsk.symbol_rate,
|
||||
printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
|
||||
fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
|
||||
fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -746,8 +750,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
||||
parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
|
||||
(fe->ops.info.symbol_rate_max &&
|
||||
parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
|
||||
printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
|
||||
fe->dvb->num, parms->u.qam.symbol_rate,
|
||||
printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
|
||||
fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
|
||||
fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -899,30 +903,30 @@ 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)
|
||||
@ -942,8 +946,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;
|
||||
|
||||
@ -998,27 +1000,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)
|
||||
@ -1036,7 +1036,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;
|
||||
@ -1055,14 +1055,13 @@ 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;
|
||||
|
||||
switch(c->modulation) {
|
||||
case PSK_8:
|
||||
case APSK_16:
|
||||
case APSK_32:
|
||||
case QPSK:
|
||||
p->u.qpsk.symbol_rate = c->symbol_rate;
|
||||
p->u.qpsk.fec_inner = c->fec_inner;
|
||||
@ -1089,19 +1088,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
|
||||
@ -1123,8 +1120,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 */
|
||||
@ -1198,7 +1193,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 */
|
||||
@ -1213,7 +1207,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;
|
||||
@ -1224,7 +1218,7 @@ 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);
|
||||
|
||||
r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
|
||||
@ -1335,12 +1329,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 */
|
||||
@ -1364,18 +1356,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 */
|
||||
@ -1704,13 +1694,53 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dvb_adapter *adapter = fe->dvb;
|
||||
int ret;
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
|
||||
if (adapter->mfe_shared) {
|
||||
mutex_lock (&adapter->mfe_lock);
|
||||
|
||||
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);
|
||||
if(adapter->mfe_dvbdev != dvbdev) {
|
||||
mfedev = adapter->mfe_dvbdev;
|
||||
mfe = mfedev->priv;
|
||||
mfepriv = mfe->frontend_priv;
|
||||
if (mfedev->users != -1 ||
|
||||
mfepriv->thread != NULL) {
|
||||
mutex_unlock (&adapter->mfe_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
adapter->mfe_dvbdev = dvbdev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
|
||||
if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
|
||||
return ret;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if ((ret = dvb_generic_open (inode, file)) < 0)
|
||||
@ -1730,6 +1760,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
fepriv->events.eventr = fepriv->events.eventw = 0;
|
||||
}
|
||||
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock (&adapter->mfe_lock);
|
||||
return ret;
|
||||
|
||||
err2:
|
||||
@ -1737,6 +1769,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
|
||||
err1:
|
||||
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
|
||||
fe->ops.ts_bus_ctrl(fe, 0);
|
||||
err0:
|
||||
if (adapter->mfe_shared)
|
||||
mutex_unlock (&adapter->mfe_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1806,8 +1841,9 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
|
||||
fe->dvb = dvb;
|
||||
fepriv->inversion = INVERSION_OFF;
|
||||
|
||||
printk ("DVB: registering frontend %i (%s)...\n",
|
||||
printk ("DVB: registering adapter %i frontend %i (%s)...\n",
|
||||
fe->dvb->num,
|
||||
fe->id,
|
||||
fe->ops.info.name);
|
||||
|
||||
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
|
||||
|
@ -222,6 +222,7 @@ struct dvb_frontend {
|
||||
struct dtv_frontend_properties dtv_property_cache;
|
||||
#define DVB_FRONTEND_COMPONENT_TUNER 0
|
||||
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
|
||||
int id;
|
||||
};
|
||||
|
||||
extern int dvb_register_frontend(struct dvb_adapter *dvb,
|
||||
|
@ -326,6 +326,9 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
adap->name = name;
|
||||
adap->module = module;
|
||||
adap->device = device;
|
||||
adap->mfe_shared = 0;
|
||||
adap->mfe_dvbdev = NULL;
|
||||
mutex_init (&adap->mfe_lock);
|
||||
|
||||
list_add_tail (&adap->list_head, &dvb_adapter_list);
|
||||
|
||||
|
@ -62,6 +62,10 @@ struct dvb_adapter {
|
||||
struct device *device;
|
||||
|
||||
struct module *module;
|
||||
|
||||
int mfe_shared; /* indicates mutually exclusive frontends */
|
||||
struct dvb_device *mfe_dvbdev; /* frontend device in use */
|
||||
struct mutex mfe_lock; /* access lock for thread creation */
|
||||
};
|
||||
|
||||
|
||||
|
@ -422,6 +422,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,
|
||||
|
@ -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);
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
|
||||
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);
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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;
|
||||
@ -249,7 +252,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;
|
||||
@ -284,7 +288,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);
|
||||
@ -311,7 +316,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;
|
||||
|
||||
@ -328,18 +334,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:
|
||||
@ -388,11 +396,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;
|
||||
@ -433,16 +441,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;
|
||||
@ -498,9 +506,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);
|
||||
@ -514,10 +522,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;
|
||||
@ -525,6 +535,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;
|
||||
@ -532,58 +544,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;
|
||||
@ -610,7 +629,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, "\
|
||||
@ -620,9 +639,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," \
|
||||
@ -639,7 +659,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;
|
||||
@ -690,7 +711,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;
|
||||
@ -699,19 +720,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;
|
||||
@ -740,7 +764,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;
|
||||
@ -749,7 +773,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;
|
||||
@ -771,20 +796,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;
|
||||
@ -814,13 +840,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);
|
||||
@ -853,8 +879,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)
|
||||
{
|
||||
@ -876,7 +903,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);
|
||||
|
||||
@ -907,7 +935,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);
|
||||
@ -932,7 +960,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;
|
||||
|
||||
@ -952,7 +981,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;
|
||||
@ -977,8 +1006,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)
|
||||
@ -997,12 +1026,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);
|
||||
@ -1013,7 +1042,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);
|
||||
}
|
||||
|
||||
@ -1037,8 +1066,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);
|
||||
@ -1057,20 +1086,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));
|
||||
@ -1079,7 +1113,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;
|
||||
}
|
||||
|
||||
@ -1090,6 +1124,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(cx24123_attach);
|
||||
|
||||
static struct dvb_frontend_ops cx24123_ops = {
|
||||
|
||||
@ -1126,15 +1161,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);
|
||||
|
@ -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 */
|
||||
|
@ -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 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
|
||||
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:
|
||||
|
@ -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;
|
||||
|
@ -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 } };
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -359,7 +359,7 @@ config USB_SI470X
|
||||
computer's USB port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-silabs.
|
||||
module will be called radio-si470x.
|
||||
|
||||
config USB_MR800
|
||||
tristate "AverMedia MR 800 USB FM radio support"
|
||||
|
@ -104,6 +104,7 @@
|
||||
* - hardware frequency seek support
|
||||
* - afc indication
|
||||
* - more safety checks, let si470x_get_freq return errno
|
||||
* - vidioc behavior corrected according to v4l2 spec
|
||||
*
|
||||
* ToDo:
|
||||
* - add firmware download/update support
|
||||
@ -141,9 +142,9 @@
|
||||
/* USB Device ID List */
|
||||
static struct usb_device_id si470x_usb_driver_id_table[] = {
|
||||
/* Silicon Labs USB FM Radio Reference Design */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
|
||||
{ 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) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
|
||||
/* Terminating entry */
|
||||
{ }
|
||||
};
|
||||
@ -157,7 +158,7 @@ MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
|
||||
|
||||
/* Radio Nr */
|
||||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0);
|
||||
module_param(radio_nr, int, 0444);
|
||||
MODULE_PARM_DESC(radio_nr, "Radio Nr");
|
||||
|
||||
/* Spacing (kHz) */
|
||||
@ -165,42 +166,42 @@ MODULE_PARM_DESC(radio_nr, "Radio Nr");
|
||||
/* 1: 100 kHz (Europe, Japan) */
|
||||
/* 2: 50 kHz */
|
||||
static unsigned short space = 2;
|
||||
module_param(space, ushort, 0);
|
||||
MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
|
||||
module_param(space, ushort, 0444);
|
||||
MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
|
||||
|
||||
/* Bottom of Band (MHz) */
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe)*/
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
static unsigned short band = 1;
|
||||
module_param(band, ushort, 0);
|
||||
MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
|
||||
module_param(band, ushort, 0444);
|
||||
MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
|
||||
|
||||
/* De-emphasis */
|
||||
/* 0: 75 us (USA) */
|
||||
/* 1: 50 us (Europe, Australia, Japan) */
|
||||
static unsigned short de = 1;
|
||||
module_param(de, ushort, 0);
|
||||
MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
|
||||
module_param(de, ushort, 0444);
|
||||
MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
|
||||
|
||||
/* USB timeout */
|
||||
static unsigned int usb_timeout = 500;
|
||||
module_param(usb_timeout, uint, 0);
|
||||
module_param(usb_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
|
||||
|
||||
/* Tune timeout */
|
||||
static unsigned int tune_timeout = 3000;
|
||||
module_param(tune_timeout, uint, 0);
|
||||
module_param(tune_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
|
||||
|
||||
/* Seek timeout */
|
||||
static unsigned int seek_timeout = 5000;
|
||||
module_param(seek_timeout, uint, 0);
|
||||
module_param(seek_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
|
||||
|
||||
/* RDS buffer blocks */
|
||||
static unsigned int rds_buf = 100;
|
||||
module_param(rds_buf, uint, 0);
|
||||
module_param(rds_buf, uint, 0444);
|
||||
MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
|
||||
|
||||
/* RDS maximum block errors */
|
||||
@ -209,7 +210,7 @@ static unsigned short max_rds_errors = 1;
|
||||
/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */
|
||||
/* 2 means 3-5 errors requiring correction */
|
||||
/* 3 means 6+ errors or errors in checkword, correction not possible */
|
||||
module_param(max_rds_errors, ushort, 0);
|
||||
module_param(max_rds_errors, ushort, 0644);
|
||||
MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
|
||||
|
||||
/* RDS poll frequency */
|
||||
@ -218,7 +219,7 @@ static unsigned int rds_poll_time = 40;
|
||||
/* 50 is used by radio-cadet */
|
||||
/* 75 should be okay */
|
||||
/* 80 is the usual RDS receive interval */
|
||||
module_param(rds_poll_time, uint, 0);
|
||||
module_param(rds_poll_time, uint, 0644);
|
||||
MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
|
||||
|
||||
|
||||
@ -667,23 +668,29 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
|
||||
int retval;
|
||||
|
||||
/* Spacing (kHz) */
|
||||
switch (space) {
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
|
||||
/* 0: 200 kHz (USA, Australia) */
|
||||
case 0 : spacing = 0.200 * FREQ_MUL; break;
|
||||
case 0:
|
||||
spacing = 0.200 * FREQ_MUL; break;
|
||||
/* 1: 100 kHz (Europe, Japan) */
|
||||
case 1 : spacing = 0.100 * FREQ_MUL; break;
|
||||
case 1:
|
||||
spacing = 0.100 * FREQ_MUL; break;
|
||||
/* 2: 50 kHz */
|
||||
default: spacing = 0.050 * FREQ_MUL; break;
|
||||
default:
|
||||
spacing = 0.050 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* Bottom of Band (MHz) */
|
||||
switch (band) {
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe) */
|
||||
case 0 : band_bottom = 87.5 * FREQ_MUL; break;
|
||||
case 0:
|
||||
band_bottom = 87.5 * FREQ_MUL; break;
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
default: band_bottom = 76 * FREQ_MUL; break;
|
||||
default:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
case 2 : band_bottom = 76 * FREQ_MUL; break;
|
||||
case 2:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* read channel */
|
||||
@ -706,23 +713,29 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
|
||||
unsigned short chan;
|
||||
|
||||
/* Spacing (kHz) */
|
||||
switch (space) {
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
|
||||
/* 0: 200 kHz (USA, Australia) */
|
||||
case 0 : spacing = 0.200 * FREQ_MUL; break;
|
||||
case 0:
|
||||
spacing = 0.200 * FREQ_MUL; break;
|
||||
/* 1: 100 kHz (Europe, Japan) */
|
||||
case 1 : spacing = 0.100 * FREQ_MUL; break;
|
||||
case 1:
|
||||
spacing = 0.100 * FREQ_MUL; break;
|
||||
/* 2: 50 kHz */
|
||||
default: spacing = 0.050 * FREQ_MUL; break;
|
||||
default:
|
||||
spacing = 0.050 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* Bottom of Band (MHz) */
|
||||
switch (band) {
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe) */
|
||||
case 0 : band_bottom = 87.5 * FREQ_MUL; break;
|
||||
case 0:
|
||||
band_bottom = 87.5 * FREQ_MUL; break;
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
default: band_bottom = 76 * FREQ_MUL; break;
|
||||
default:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
case 2 : band_bottom = 76 * FREQ_MUL; break;
|
||||
case 2:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
|
||||
@ -1164,7 +1177,6 @@ static const struct file_operations si470x_fops = {
|
||||
* si470x_v4l2_queryctrl - query control
|
||||
*/
|
||||
static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
|
||||
/* HINT: the disabled controls are only here to satify kradio and such apps */
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_VOLUME,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
@ -1174,18 +1186,6 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
|
||||
.step = 1,
|
||||
.default_value = 15,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_BALANCE,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_BASS,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_TREBLE,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_MUTE,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
@ -1195,10 +1195,6 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
|
||||
.step = 1,
|
||||
.default_value = 1,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_LOUDNESS,
|
||||
.flags = V4L2_CTRL_FLAG_DISABLED,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -1219,57 +1215,35 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_g_input - get input
|
||||
*/
|
||||
static int si470x_vidioc_g_input(struct file *file, void *priv,
|
||||
unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_input - set input
|
||||
*/
|
||||
static int si470x_vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
if (i != 0)
|
||||
retval = -EINVAL;
|
||||
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set input failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_queryctrl - enumerate control items
|
||||
*/
|
||||
static int si470x_vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned char i = 0;
|
||||
int retval = -EINVAL;
|
||||
|
||||
/* safety checks */
|
||||
if (!qc->id)
|
||||
/* abort if qc->id is below V4L2_CID_BASE */
|
||||
if (qc->id < V4L2_CID_BASE)
|
||||
goto done;
|
||||
|
||||
/* search video control */
|
||||
for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
|
||||
if (qc->id == si470x_v4l2_queryctrl[i].id) {
|
||||
memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
|
||||
retval = 0;
|
||||
retval = 0; /* found */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable unsupported base controls */
|
||||
/* to satisfy kradio and such apps */
|
||||
if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
|
||||
qc->flags = V4L2_CTRL_FLAG_DISABLED;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
@ -1360,44 +1334,13 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
|
||||
static int si470x_vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *audio)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
if (audio->index != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* driver constants */
|
||||
audio->index = 0;
|
||||
strcpy(audio->name, "Radio");
|
||||
audio->capability = V4L2_AUDCAP_STEREO;
|
||||
audio->mode = 0;
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": get audio failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_audio - set audio attributes
|
||||
*/
|
||||
static int si470x_vidioc_s_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *audio)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
if (audio->index != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
printk(KERN_WARNING DRIVER_NAME
|
||||
": set audio failed with %d\n", retval);
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1415,7 +1358,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
|
||||
if (tuner->index != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
@ -1424,8 +1367,13 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* driver constants */
|
||||
strcpy(tuner->name, "FM");
|
||||
switch (band) {
|
||||
tuner->type = V4L2_TUNER_RADIO;
|
||||
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
|
||||
|
||||
/* range limits */
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe, default) */
|
||||
default:
|
||||
tuner->rangelow = 87.5 * FREQ_MUL;
|
||||
@ -1442,14 +1390,18 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
|
||||
tuner->rangehigh = 90 * FREQ_MUL;
|
||||
break;
|
||||
};
|
||||
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
|
||||
tuner->capability = V4L2_TUNER_CAP_LOW;
|
||||
|
||||
/* Stereo indicator == Stereo (instead of Mono) */
|
||||
/* stereo indicator == stereo (instead of mono) */
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
|
||||
tuner->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
|
||||
else
|
||||
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
|
||||
/* mono/stereo selector */
|
||||
if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 1)
|
||||
tuner->audmode = V4L2_TUNER_MODE_MONO;
|
||||
else
|
||||
tuner->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
|
||||
/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
|
||||
tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
|
||||
@ -1474,23 +1426,28 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *tuner)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
int retval = -EINVAL;
|
||||
|
||||
/* safety checks */
|
||||
if (radio->disconnected) {
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((tuner->index != 0) && (tuner->type != V4L2_TUNER_RADIO)) {
|
||||
retval = -EINVAL;
|
||||
if (tuner->index != 0)
|
||||
goto done;
|
||||
|
||||
/* mono/stereo selector */
|
||||
switch (tuner->audmode) {
|
||||
case V4L2_TUNER_MODE_MONO:
|
||||
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
|
||||
break;
|
||||
case V4L2_TUNER_MODE_STEREO:
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
|
||||
break;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (tuner->audmode == V4L2_TUNER_MODE_MONO)
|
||||
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
|
||||
else
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
|
||||
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
@ -1515,11 +1472,12 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
|
||||
if (freq->tuner != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
freq->type = V4L2_TUNER_RADIO;
|
||||
retval = si470x_get_freq(radio, &freq->frequency);
|
||||
|
||||
done:
|
||||
@ -1544,7 +1502,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((freq->tuner != 0) && (freq->type != V4L2_TUNER_RADIO)) {
|
||||
if (freq->tuner != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
@ -1573,7 +1531,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
|
||||
if (seek->tuner != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
@ -1588,15 +1546,16 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_ioctl_ops - video device ioctl operations
|
||||
*/
|
||||
static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
|
||||
.vidioc_querycap = si470x_vidioc_querycap,
|
||||
.vidioc_g_input = si470x_vidioc_g_input,
|
||||
.vidioc_s_input = si470x_vidioc_s_input,
|
||||
.vidioc_queryctrl = si470x_vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = si470x_vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = si470x_vidioc_s_ctrl,
|
||||
.vidioc_g_audio = si470x_vidioc_g_audio,
|
||||
.vidioc_s_audio = si470x_vidioc_s_audio,
|
||||
.vidioc_g_tuner = si470x_vidioc_g_tuner,
|
||||
.vidioc_s_tuner = si470x_vidioc_s_tuner,
|
||||
.vidioc_g_frequency = si470x_vidioc_g_frequency,
|
||||
@ -1604,14 +1563,15 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
|
||||
.vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* si470x_viddev_tamples - video device interface
|
||||
* si470x_viddev_template - video device interface
|
||||
*/
|
||||
static struct video_device si470x_viddev_template = {
|
||||
.fops = &si470x_fops,
|
||||
.ioctl_ops = &si470x_ioctl_ops,
|
||||
.name = DRIVER_NAME,
|
||||
.release = video_device_release,
|
||||
.ioctl_ops = &si470x_ioctl_ops,
|
||||
};
|
||||
|
||||
|
||||
|
@ -29,43 +29,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_encoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
|
||||
MODULE_AUTHOR("Maxim Yevtyushkin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(x) (x)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct adv7170 {
|
||||
@ -80,21 +61,12 @@ struct adv7170 {
|
||||
int sat;
|
||||
};
|
||||
|
||||
#define I2C_ADV7170 0xd4
|
||||
#define I2C_ADV7171 0x54
|
||||
|
||||
static char adv7170_name[] = "adv7170";
|
||||
static char adv7171_name[] = "adv7171";
|
||||
|
||||
static char *inputs[] = { "pass_through", "play_back" };
|
||||
static char *norms[] = { "PAL", "NTSC" };
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
adv7170_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct adv7170 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -102,17 +74,13 @@ adv7170_write (struct i2c_client *client,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
adv7170_read (struct i2c_client *client,
|
||||
u8 reg)
|
||||
static inline int adv7170_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
adv7170_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int adv7170_write_block(struct i2c_client *client,
|
||||
const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
@ -133,33 +101,25 @@ adv7170_write_block (struct i2c_client *client,
|
||||
encoder->reg[reg++] = data[1];
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg &&
|
||||
block_len < 32);
|
||||
if ((ret = i2c_master_send(client, block_data,
|
||||
block_len)) < 0)
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
if ((ret = adv7170_write(client, reg,
|
||||
*data++)) < 0)
|
||||
ret = adv7170_write(client, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
// Output filter: S-Video Composite
|
||||
|
||||
#define MR050 0x11 //0x09
|
||||
#define MR060 0x14 //0x0c
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#define TR0MODE 0x4c
|
||||
#define TR0RST 0x80
|
||||
@ -167,7 +127,6 @@ adv7170_write_block (struct i2c_client *client,
|
||||
#define TR1CAPT 0x00
|
||||
#define TR1PLAY 0x00
|
||||
|
||||
|
||||
static const unsigned char init_NTSC[] = {
|
||||
0x00, 0x10, // MR0
|
||||
0x01, 0x20, // MR1
|
||||
@ -227,15 +186,11 @@ static const unsigned char init_PAL[] = {
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
adv7170_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void * arg)
|
||||
static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct adv7170 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
#if 0
|
||||
/* This is just for testing!!! */
|
||||
@ -254,18 +209,16 @@ adv7170_command (struct i2c_client *client,
|
||||
VIDEO_ENCODER_NTSC;
|
||||
cap->inputs = 2;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_NORM:
|
||||
{
|
||||
int iarg = *(int *) arg;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s_command: set norm %d",
|
||||
I2C_NAME(client), iarg);
|
||||
v4l_dbg(1, debug, client, "set norm %d\n", iarg);
|
||||
|
||||
switch (iarg) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
adv7170_write_block(client, init_NTSC,
|
||||
sizeof(init_NTSC));
|
||||
@ -285,16 +238,13 @@ adv7170_command (struct i2c_client *client,
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
|
||||
I2C_NAME(client), iarg);
|
||||
v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
|
||||
norms[iarg]);
|
||||
v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
|
||||
encoder->norm = iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_INPUT:
|
||||
{
|
||||
@ -304,19 +254,17 @@ adv7170_command (struct i2c_client *client,
|
||||
*iarg = 1: input is from ZR36060
|
||||
*iarg = 2: color bar */
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s_command: set input from %s\n",
|
||||
I2C_NAME(client),
|
||||
v4l_dbg(1, debug, client, "set input from %s\n",
|
||||
iarg == 0 ? "decoder" : "ZR36060");
|
||||
|
||||
switch (iarg) {
|
||||
|
||||
case 0:
|
||||
adv7170_write(client, 0x01, 0x20);
|
||||
adv7170_write(client, 0x08, TR1CAPT); /* TR1 */
|
||||
adv7170_write(client, 0x02, 0x0e); // Enable genlock
|
||||
adv7170_write(client, 0x07, TR0MODE | TR0RST);
|
||||
adv7170_write(client, 0x07, TR0MODE);
|
||||
//udelay(10);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@ -325,20 +273,17 @@ adv7170_command (struct i2c_client *client,
|
||||
adv7170_write(client, 0x02, 0x08);
|
||||
adv7170_write(client, 0x07, TR0MODE | TR0RST);
|
||||
adv7170_write(client, 0x07, TR0MODE);
|
||||
//udelay(10);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk(1, KERN_ERR "%s: illegal input: %d\n",
|
||||
I2C_NAME(client), iarg);
|
||||
v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
dprintk(1, KERN_DEBUG "%s: switched to %s\n", I2C_NAME(client),
|
||||
inputs[iarg]);
|
||||
v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
|
||||
encoder->input = iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_OUTPUT:
|
||||
{
|
||||
@ -348,16 +293,16 @@ adv7170_command (struct i2c_client *client,
|
||||
if (*iarg != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_ENABLE_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
encoder->enable = !!*iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -368,149 +313,67 @@ adv7170_command (struct i2c_client *client,
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] =
|
||||
{ I2C_ADV7170 >> 1, (I2C_ADV7170 >> 1) + 1,
|
||||
I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
|
||||
static unsigned short normal_i2c[] = {
|
||||
0xd4 >> 1, 0xd6 >> 1, /* adv7170 IDs */
|
||||
0x54 >> 1, 0x56 >> 1, /* adv7171 IDs */
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_adv7170;
|
||||
|
||||
static int
|
||||
adv7170_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int adv7170_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *client;
|
||||
struct adv7170 *encoder;
|
||||
char *dname;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"adv7170.c: detecting adv7170 client on address 0x%x\n",
|
||||
address << 1);
|
||||
int i;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_adv7170;
|
||||
if ((client->addr == I2C_ADV7170 >> 1) ||
|
||||
(client->addr == (I2C_ADV7170 >> 1) + 1)) {
|
||||
dname = adv7170_name;
|
||||
} else if ((client->addr == I2C_ADV7171 >> 1) ||
|
||||
(client->addr == (I2C_ADV7171 >> 1) + 1)) {
|
||||
dname = adv7171_name;
|
||||
} else {
|
||||
/* We should never get here!!! */
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
|
||||
if (encoder == NULL) {
|
||||
kfree(client);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
encoder->norm = VIDEO_MODE_NTSC;
|
||||
encoder->input = 0;
|
||||
encoder->enable = 1;
|
||||
i2c_set_clientdata(client, encoder);
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(encoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
|
||||
if (i >= 0) {
|
||||
i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
|
||||
i = adv7170_write(client, 0x07, TR0MODE);
|
||||
i = adv7170_read(client, 0x12);
|
||||
dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%02x\n",
|
||||
I2C_NAME(client), i & 1, client->addr << 1);
|
||||
v4l_dbg(1, debug, client, "revision %d\n", i & 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
|
||||
I2C_NAME(client), i);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
v4l_dbg(1, debug, client, "init error 0x%x\n", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
adv7170_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int adv7170_remove(struct i2c_client *client)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"adv7170.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &adv7170_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
adv7170_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct adv7170 *encoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(encoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_adv7170 = {
|
||||
.driver = {
|
||||
.name = "adv7170", /* name */
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_ADV7170,
|
||||
|
||||
.attach_adapter = adv7170_attach_adapter,
|
||||
.detach_client = adv7170_detach_client,
|
||||
.command = adv7170_command,
|
||||
static const struct i2c_device_id adv7170_id[] = {
|
||||
{ "adv7170", 0 },
|
||||
{ "adv7171", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adv7170_id);
|
||||
|
||||
static int __init
|
||||
adv7170_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_adv7170);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
adv7170_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_adv7170);
|
||||
}
|
||||
|
||||
module_init(adv7170_init);
|
||||
module_exit(adv7170_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "adv7170",
|
||||
.driverid = I2C_DRIVERID_ADV7170,
|
||||
.command = adv7170_command,
|
||||
.probe = adv7170_probe,
|
||||
.remove = adv7170_remove,
|
||||
.id_table = adv7170_id,
|
||||
};
|
||||
|
@ -25,43 +25,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_encoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
|
||||
MODULE_AUTHOR("Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(s) (s)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct adv7175 {
|
||||
@ -77,33 +58,23 @@ struct adv7175 {
|
||||
#define I2C_ADV7175 0xd4
|
||||
#define I2C_ADV7176 0x54
|
||||
|
||||
static char adv7175_name[] = "adv7175";
|
||||
static char adv7176_name[] = "adv7176";
|
||||
|
||||
static char *inputs[] = { "pass_through", "play_back", "color_bar" };
|
||||
static char *norms[] = { "PAL", "NTSC", "SECAM->PAL (may not work!)" };
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
adv7175_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static inline int adv7175_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
adv7175_read (struct i2c_client *client,
|
||||
u8 reg)
|
||||
static inline int adv7175_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
adv7175_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int adv7175_write_block(struct i2c_client *client,
|
||||
const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
@ -123,18 +94,17 @@ adv7175_write_block (struct i2c_client *client,
|
||||
reg++;
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg &&
|
||||
block_len < 32);
|
||||
if ((ret = i2c_master_send(client, block_data,
|
||||
block_len)) < 0)
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
if ((ret = adv7175_write(client, reg,
|
||||
*data++)) < 0)
|
||||
ret = adv7175_write(client, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
@ -143,13 +113,11 @@ adv7175_write_block (struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
set_subcarrier_freq (struct i2c_client *client,
|
||||
int pass_through)
|
||||
static void set_subcarrier_freq(struct i2c_client *client, int pass_through)
|
||||
{
|
||||
/* for some reason pass_through NTSC needs
|
||||
* a different sub-carrier freq to remain stable. */
|
||||
if(pass_through)
|
||||
if (pass_through)
|
||||
adv7175_write(client, 0x02, 0x00);
|
||||
else
|
||||
adv7175_write(client, 0x02, 0x55);
|
||||
@ -160,12 +128,12 @@ set_subcarrier_freq (struct i2c_client *client,
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
// Output filter: S-Video Composite
|
||||
/* Output filter: S-Video Composite */
|
||||
|
||||
#define MR050 0x11 //0x09
|
||||
#define MR060 0x14 //0x0c
|
||||
#define MR050 0x11 /* 0x09 */
|
||||
#define MR060 0x14 /* 0x0c */
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define TR0MODE 0x46
|
||||
#define TR0RST 0x80
|
||||
@ -216,15 +184,11 @@ static const unsigned char init_ntsc[] = {
|
||||
0x06, 0x1a, /* subc. phase */
|
||||
};
|
||||
|
||||
static int
|
||||
adv7175_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int adv7175_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct adv7175 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
/* This is just for testing!!! */
|
||||
adv7175_write_block(client, init_common,
|
||||
@ -242,15 +206,14 @@ adv7175_command (struct i2c_client *client,
|
||||
VIDEO_ENCODER_SECAM; /* well, hacky */
|
||||
cap->inputs = 2;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_NORM:
|
||||
{
|
||||
int iarg = *(int *) arg;
|
||||
|
||||
switch (iarg) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
adv7175_write_block(client, init_ntsc,
|
||||
sizeof(init_ntsc));
|
||||
@ -284,16 +247,13 @@ adv7175_command (struct i2c_client *client,
|
||||
adv7175_write(client, 0x07, TR0MODE);
|
||||
break;
|
||||
default:
|
||||
dprintk(1, KERN_ERR "%s: illegal norm: %d\n",
|
||||
I2C_NAME(client), iarg);
|
||||
v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
|
||||
norms[iarg]);
|
||||
v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
|
||||
encoder->norm = iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_INPUT:
|
||||
{
|
||||
@ -304,7 +264,6 @@ adv7175_command (struct i2c_client *client,
|
||||
*iarg = 2: color bar */
|
||||
|
||||
switch (iarg) {
|
||||
|
||||
case 0:
|
||||
adv7175_write(client, 0x01, 0x00);
|
||||
|
||||
@ -331,7 +290,7 @@ adv7175_command (struct i2c_client *client,
|
||||
adv7175_write(client, 0x0d, 0x49);
|
||||
adv7175_write(client, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(client, 0x07, TR0MODE);
|
||||
//udelay(10);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@ -343,39 +302,35 @@ adv7175_command (struct i2c_client *client,
|
||||
adv7175_write(client, 0x0d, 0x49);
|
||||
adv7175_write(client, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(client, 0x07, TR0MODE);
|
||||
//udelay(10);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk(1, KERN_ERR "%s: illegal input: %d\n",
|
||||
I2C_NAME(client), iarg);
|
||||
v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
dprintk(1, KERN_INFO "%s: switched to %s\n", I2C_NAME(client),
|
||||
inputs[iarg]);
|
||||
v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
|
||||
encoder->input = iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
/* not much choice of outputs */
|
||||
if (*iarg != 0) {
|
||||
if (*iarg != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_ENABLE_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
encoder->enable = !!*iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -390,145 +345,67 @@ adv7175_command (struct i2c_client *client,
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] =
|
||||
{ I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
|
||||
static unsigned short normal_i2c[] = {
|
||||
I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1,
|
||||
I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_adv7175;
|
||||
|
||||
static int
|
||||
adv7175_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int adv7175_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *client;
|
||||
struct adv7175 *encoder;
|
||||
char *dname;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"adv7175.c: detecting adv7175 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_adv7175;
|
||||
if ((client->addr == I2C_ADV7175 >> 1) ||
|
||||
(client->addr == (I2C_ADV7175 >> 1) + 1)) {
|
||||
dname = adv7175_name;
|
||||
} else if ((client->addr == I2C_ADV7176 >> 1) ||
|
||||
(client->addr == (I2C_ADV7176 >> 1) + 1)) {
|
||||
dname = adv7176_name;
|
||||
} else {
|
||||
/* We should never get here!!! */
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
|
||||
if (encoder == NULL) {
|
||||
kfree(client);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
encoder->norm = VIDEO_MODE_PAL;
|
||||
encoder->input = 0;
|
||||
encoder->enable = 1;
|
||||
i2c_set_clientdata(client, encoder);
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(encoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
i = adv7175_write_block(client, init_common, sizeof(init_common));
|
||||
if (i >= 0) {
|
||||
i = adv7175_write(client, 0x07, TR0MODE | TR0RST);
|
||||
i = adv7175_write(client, 0x07, TR0MODE);
|
||||
i = adv7175_read(client, 0x12);
|
||||
dprintk(1, KERN_INFO "%s_attach: rev. %d at 0x%x\n",
|
||||
I2C_NAME(client), i & 1, client->addr << 1);
|
||||
v4l_dbg(1, debug, client, "revision %d\n", i & 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
dprintk(1, KERN_ERR "%s_attach: init error 0x%x\n",
|
||||
I2C_NAME(client), i);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
v4l_dbg(1, debug, client, "init error 0x%x\n", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
adv7175_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int adv7175_remove(struct i2c_client *client)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"adv7175.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &adv7175_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
adv7175_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct adv7175 *encoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(encoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_adv7175 = {
|
||||
.driver = {
|
||||
.name = "adv7175", /* name */
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_ADV7175,
|
||||
|
||||
.attach_adapter = adv7175_attach_adapter,
|
||||
.detach_client = adv7175_detach_client,
|
||||
.command = adv7175_command,
|
||||
static const struct i2c_device_id adv7175_id[] = {
|
||||
{ "adv7175", 0 },
|
||||
{ "adv7176", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adv7175_id);
|
||||
|
||||
static int __init
|
||||
adv7175_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_adv7175);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
adv7175_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_adv7175);
|
||||
}
|
||||
|
||||
module_init(adv7175_init);
|
||||
module_exit(adv7175_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "adv7175",
|
||||
.driverid = I2C_DRIVERID_ADV7175,
|
||||
.command = adv7175_command,
|
||||
.probe = adv7175_probe,
|
||||
.remove = adv7175_remove,
|
||||
.id_table = adv7175_id,
|
||||
};
|
||||
|
@ -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),
|
||||
|
@ -91,7 +91,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);
|
||||
|
||||
|
@ -173,7 +173,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,
|
||||
|
@ -29,44 +29,25 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_decoder.h>
|
||||
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
|
||||
MODULE_AUTHOR("Mike Bernson & Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(s) (s)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct bt819 {
|
||||
@ -97,14 +78,9 @@ static struct timing timing_data[] = {
|
||||
{858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
|
||||
};
|
||||
|
||||
#define I2C_BT819 0x8a
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
bt819_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static inline int bt819_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct bt819 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -112,24 +88,15 @@ bt819_write (struct i2c_client *client,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bt819_setbit (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 bit,
|
||||
u8 value)
|
||||
static inline int bt819_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
|
||||
{
|
||||
struct bt819 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
return bt819_write(client, reg,
|
||||
(decoder->
|
||||
reg[reg] & ~(1 << bit)) |
|
||||
(value ? (1 << bit) : 0));
|
||||
(decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
|
||||
}
|
||||
|
||||
static int
|
||||
bt819_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int bt819_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
@ -150,10 +117,9 @@ bt819_write_block (struct i2c_client *client,
|
||||
decoder->reg[reg++] = data[1];
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg &&
|
||||
block_len < 32);
|
||||
if ((ret = i2c_master_send(client, block_data,
|
||||
block_len)) < 0)
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -169,20 +135,17 @@ bt819_write_block (struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
bt819_read (struct i2c_client *client,
|
||||
u8 reg)
|
||||
static inline int bt819_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
bt819_init (struct i2c_client *client)
|
||||
static int bt819_init(struct i2c_client *client)
|
||||
{
|
||||
struct bt819 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
static unsigned char init[] = {
|
||||
//0x1f, 0x00, /* Reset */
|
||||
/*0x1f, 0x00,*/ /* Reset */
|
||||
0x01, 0x59, /* 0x01 input format */
|
||||
0x02, 0x00, /* 0x02 temporal decimation */
|
||||
0x03, 0x12, /* 0x03 Cropping msb */
|
||||
@ -218,12 +181,10 @@ bt819_init (struct i2c_client *client)
|
||||
struct timing *timing = &timing_data[decoder->norm];
|
||||
|
||||
init[0x03 * 2 - 1] =
|
||||
(((timing->vdelay >> 8) & 0x03) << 6) | (((timing->
|
||||
vactive >> 8) &
|
||||
0x03) << 4) |
|
||||
(((timing->hdelay >> 8) & 0x03) << 2) | ((timing->
|
||||
hactive >> 8) &
|
||||
0x03);
|
||||
(((timing->vdelay >> 8) & 0x03) << 6) |
|
||||
(((timing->vactive >> 8) & 0x03) << 4) |
|
||||
(((timing->hdelay >> 8) & 0x03) << 2) |
|
||||
((timing->hactive >> 8) & 0x03);
|
||||
init[0x04 * 2 - 1] = timing->vdelay & 0xff;
|
||||
init[0x05 * 2 - 1] = timing->vactive & 0xff;
|
||||
init[0x06 * 2 - 1] = timing->hdelay & 0xff;
|
||||
@ -238,27 +199,22 @@ bt819_init (struct i2c_client *client)
|
||||
|
||||
/* init */
|
||||
return bt819_write_block(client, init, sizeof(init));
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
bt819_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int bt819_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
int temp;
|
||||
|
||||
struct bt819 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
if (!decoder->initialized) { // First call to bt819_init could be
|
||||
bt819_init(client); // without #FRST = 0
|
||||
if (!decoder->initialized) { /* First call to bt819_init could be */
|
||||
bt819_init(client); /* without #FRST = 0 */
|
||||
decoder->initialized = 1;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
/* This is just for testing!!! */
|
||||
bt819_init(client);
|
||||
@ -274,8 +230,8 @@ bt819_command (struct i2c_client *client,
|
||||
VIDEO_DECODER_CCIR;
|
||||
cap->inputs = 8;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_STATUS:
|
||||
{
|
||||
@ -285,9 +241,9 @@ bt819_command (struct i2c_client *client,
|
||||
|
||||
status = bt819_read(client, 0x00);
|
||||
res = 0;
|
||||
if ((status & 0x80)) {
|
||||
if ((status & 0x80))
|
||||
res |= DECODER_STATUS_GOOD;
|
||||
}
|
||||
|
||||
switch (decoder->norm) {
|
||||
case VIDEO_MODE_NTSC:
|
||||
res |= DECODER_STATUS_NTSC;
|
||||
@ -297,28 +253,25 @@ bt819_command (struct i2c_client *client,
|
||||
break;
|
||||
default:
|
||||
case VIDEO_MODE_AUTO:
|
||||
if ((status & 0x10)) {
|
||||
if ((status & 0x10))
|
||||
res |= DECODER_STATUS_PAL;
|
||||
} else {
|
||||
else
|
||||
res |= DECODER_STATUS_NTSC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
res |= DECODER_STATUS_COLOR;
|
||||
*iarg = res;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: get status %x\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
}
|
||||
v4l_dbg(1, debug, client, "get status %x\n", *iarg);
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_NORM:
|
||||
{
|
||||
int *iarg = arg;
|
||||
struct timing *timing = NULL;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: set norm %x\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
v4l_dbg(1, debug, client, "set norm %x\n", *iarg);
|
||||
|
||||
switch (*iarg) {
|
||||
case VIDEO_MODE_NTSC:
|
||||
@ -327,7 +280,7 @@ bt819_command (struct i2c_client *client,
|
||||
bt819_setbit(client, 0x01, 5, 0);
|
||||
bt819_write(client, 0x18, 0x68);
|
||||
bt819_write(client, 0x19, 0x5d);
|
||||
//bt819_setbit(client, 0x1a, 5, 1);
|
||||
/* bt819_setbit(client, 0x1a, 5, 1); */
|
||||
timing = &timing_data[VIDEO_MODE_NTSC];
|
||||
break;
|
||||
case VIDEO_MODE_PAL:
|
||||
@ -336,7 +289,7 @@ bt819_command (struct i2c_client *client,
|
||||
bt819_setbit(client, 0x01, 5, 1);
|
||||
bt819_write(client, 0x18, 0x7f);
|
||||
bt819_write(client, 0x19, 0x72);
|
||||
//bt819_setbit(client, 0x1a, 5, 0);
|
||||
/* bt819_setbit(client, 0x1a, 5, 0); */
|
||||
timing = &timing_data[VIDEO_MODE_PAL];
|
||||
break;
|
||||
case VIDEO_MODE_AUTO:
|
||||
@ -344,10 +297,7 @@ bt819_command (struct i2c_client *client,
|
||||
bt819_setbit(client, 0x01, 1, 0);
|
||||
break;
|
||||
default:
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"%s: unsupported norm %d\n",
|
||||
I2C_NAME(client), *iarg);
|
||||
v4l_dbg(1, debug, client, "unsupported norm %x\n", *iarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -366,19 +316,17 @@ bt819_command (struct i2c_client *client,
|
||||
}
|
||||
|
||||
decoder->norm = *iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_INPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: set input %x\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
v4l_dbg(1, debug, client, "set input %x\n", *iarg);
|
||||
|
||||
if (*iarg < 0 || *iarg > 7) {
|
||||
if (*iarg < 0 || *iarg > 7)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (decoder->input != *iarg) {
|
||||
decoder->input = *iarg;
|
||||
@ -391,52 +339,42 @@ bt819_command (struct i2c_client *client,
|
||||
bt819_setbit(client, 0x1a, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: set output %x\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
v4l_dbg(1, debug, client, "set output %x\n", *iarg);
|
||||
|
||||
/* not much choice of outputs */
|
||||
if (*iarg != 0) {
|
||||
if (*iarg != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_ENABLE_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
int enable = (*iarg != 0);
|
||||
|
||||
dprintk(1, KERN_INFO "%s: enable output %x\n",
|
||||
I2C_NAME(client), *iarg);
|
||||
v4l_dbg(1, debug, client, "enable output %x\n", *iarg);
|
||||
|
||||
if (decoder->enable != enable) {
|
||||
decoder->enable = enable;
|
||||
|
||||
if (decoder->enable) {
|
||||
bt819_setbit(client, 0x16, 7, 0);
|
||||
} else {
|
||||
bt819_setbit(client, 0x16, 7, 1);
|
||||
}
|
||||
bt819_setbit(client, 0x16, 7, !enable);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_PICTURE:
|
||||
{
|
||||
struct video_picture *pic = arg;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s: set picture brightness %d contrast %d colour %d\n",
|
||||
I2C_NAME(client), pic->brightness, pic->contrast,
|
||||
pic->colour);
|
||||
v4l_dbg(1, debug, client,
|
||||
"set picture brightness %d contrast %d colour %d\n",
|
||||
pic->brightness, pic->contrast, pic->colour);
|
||||
|
||||
|
||||
if (decoder->bright != pic->brightness) {
|
||||
@ -474,8 +412,8 @@ bt819_command (struct i2c_client *client,
|
||||
bt819_write(client, 0x0f,
|
||||
128 - (decoder->hue >> 8));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -486,55 +424,44 @@ bt819_command (struct i2c_client *client,
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = {
|
||||
I2C_BT819 >> 1,
|
||||
I2C_CLIENT_END,
|
||||
};
|
||||
static unsigned short normal_i2c[] = { 0x8a >> 1, I2C_CLIENT_END };
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_bt819;
|
||||
|
||||
static int
|
||||
bt819_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int bt819_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i, id;
|
||||
int i, ver;
|
||||
struct bt819 *decoder;
|
||||
struct i2c_client *client;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"bt819: detecting bt819 client on address 0x%x\n",
|
||||
address << 1);
|
||||
const char *name;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_bt819;
|
||||
ver = bt819_read(client, 0x17);
|
||||
switch (ver & 0xf0) {
|
||||
case 0x70:
|
||||
name = "bt819a";
|
||||
break;
|
||||
case 0x60:
|
||||
name = "bt817a";
|
||||
break;
|
||||
case 0x20:
|
||||
name = "bt815a";
|
||||
break;
|
||||
default:
|
||||
v4l_dbg(1, debug, client,
|
||||
"unknown chip version 0x%02x\n", ver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
v4l_info(client, "%s found @ 0x%x (%s)\n", name,
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
|
||||
if (decoder == NULL) {
|
||||
kfree(client);
|
||||
if (decoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
decoder->norm = VIDEO_MODE_NTSC;
|
||||
decoder->input = 0;
|
||||
decoder->enable = 1;
|
||||
@ -545,97 +472,33 @@ bt819_detect_client (struct i2c_adapter *adapter,
|
||||
decoder->initialized = 0;
|
||||
i2c_set_clientdata(client, decoder);
|
||||
|
||||
id = bt819_read(client, 0x17);
|
||||
switch (id & 0xf0) {
|
||||
case 0x70:
|
||||
strlcpy(I2C_NAME(client), "bt819a", sizeof(I2C_NAME(client)));
|
||||
break;
|
||||
case 0x60:
|
||||
strlcpy(I2C_NAME(client), "bt817a", sizeof(I2C_NAME(client)));
|
||||
break;
|
||||
case 0x20:
|
||||
strlcpy(I2C_NAME(client), "bt815a", sizeof(I2C_NAME(client)));
|
||||
break;
|
||||
default:
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"bt819: unknown chip version 0x%x (ver 0x%x)\n",
|
||||
id & 0xf0, id & 0x0f);
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(decoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
i = bt819_init(client);
|
||||
if (i < 0) {
|
||||
dprintk(1, KERN_ERR "%s_attach: init status %d\n",
|
||||
I2C_NAME(client), i);
|
||||
} else {
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s_attach: chip version 0x%x at address 0x%x\n",
|
||||
I2C_NAME(client), id & 0x0f,
|
||||
client->addr << 1);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
v4l_dbg(1, debug, client, "init status %d\n", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bt819_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int bt819_remove(struct i2c_client *client)
|
||||
{
|
||||
return i2c_probe(adapter, &addr_data, &bt819_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
bt819_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct bt819 *decoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_bt819 = {
|
||||
.driver = {
|
||||
.name = "bt819",
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_BT819,
|
||||
|
||||
.attach_adapter = bt819_attach_adapter,
|
||||
.detach_client = bt819_detach_client,
|
||||
.command = bt819_command,
|
||||
static const struct i2c_device_id bt819_id[] = {
|
||||
{ "bt819a", 0 },
|
||||
{ "bt817a", 0 },
|
||||
{ "bt815a", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bt819_id);
|
||||
|
||||
static int __init
|
||||
bt819_init_module (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_bt819);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
bt819_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_bt819);
|
||||
}
|
||||
|
||||
module_init(bt819_init_module);
|
||||
module_exit(bt819_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "bt819",
|
||||
.driverid = I2C_DRIVERID_BT819,
|
||||
.command = bt819_command,
|
||||
.probe = bt819_probe,
|
||||
.remove = bt819_remove,
|
||||
.id_table = bt819_id,
|
||||
};
|
||||
|
@ -29,43 +29,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/video_encoder.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_encoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
|
||||
MODULE_AUTHOR("Mike Bernson & Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(s) (s)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define BT856_REG_OFFSET 0xDA
|
||||
@ -78,14 +59,9 @@ struct bt856 {
|
||||
int enable;
|
||||
};
|
||||
|
||||
#define I2C_BT856 0x88
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
bt856_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static inline int bt856_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct bt856 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -93,46 +69,36 @@ bt856_write (struct i2c_client *client,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bt856_setbit (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 bit,
|
||||
u8 value)
|
||||
static inline int bt856_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
|
||||
{
|
||||
struct bt856 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
return bt856_write(client, reg,
|
||||
(encoder->
|
||||
reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
|
||||
(value ? (1 << bit) : 0));
|
||||
(encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
|
||||
(value ? (1 << bit) : 0));
|
||||
}
|
||||
|
||||
static void
|
||||
bt856_dump (struct i2c_client *client)
|
||||
static void bt856_dump(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
struct bt856 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
printk(KERN_INFO "%s: register dump:", I2C_NAME(client));
|
||||
v4l_info(client, "register dump:\n");
|
||||
for (i = 0; i < BT856_NR_REG; i += 2)
|
||||
printk(" %02x", encoder->reg[i]);
|
||||
printk("\n");
|
||||
printk(KERN_CONT " %02x", encoder->reg[i]);
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
bt856_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int bt856_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct bt856 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
/* This is just for testing!!! */
|
||||
dprintk(1, KERN_INFO "bt856: init\n");
|
||||
v4l_dbg(1, debug, client, "init\n");
|
||||
bt856_write(client, 0xdc, 0x18);
|
||||
bt856_write(client, 0xda, 0);
|
||||
bt856_write(client, 0xde, 0);
|
||||
@ -142,7 +108,6 @@ bt856_command (struct i2c_client *client,
|
||||
bt856_setbit(client, 0xdc, 4, 1);
|
||||
|
||||
switch (encoder->norm) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
bt856_setbit(client, 0xdc, 2, 0);
|
||||
break;
|
||||
@ -163,26 +128,23 @@ bt856_command (struct i2c_client *client,
|
||||
{
|
||||
struct video_encoder_capability *cap = arg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: get capabilities\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "get capabilities\n");
|
||||
|
||||
cap->flags = VIDEO_ENCODER_PAL |
|
||||
VIDEO_ENCODER_NTSC |
|
||||
VIDEO_ENCODER_CCIR;
|
||||
cap->inputs = 2;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_NORM:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: set norm %d\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
|
||||
|
||||
switch (*iarg) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
bt856_setbit(client, 0xdc, 2, 0);
|
||||
break;
|
||||
@ -195,27 +157,23 @@ bt856_command (struct i2c_client *client,
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
encoder->norm = *iarg;
|
||||
if (debug != 0)
|
||||
bt856_dump(client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_INPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: set input %d\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
v4l_dbg(1, debug, client, "set input %d\n", *iarg);
|
||||
|
||||
/* We only have video bus.
|
||||
* iarg = 0: input is from bt819
|
||||
* iarg = 1: input is from ZR36060 */
|
||||
|
||||
switch (*iarg) {
|
||||
|
||||
case 0:
|
||||
bt856_setbit(client, 0xde, 4, 0);
|
||||
bt856_setbit(client, 0xde, 3, 1);
|
||||
@ -234,27 +192,24 @@ bt856_command (struct i2c_client *client,
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
if (debug != 0)
|
||||
bt856_dump(client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: set output %d\n", I2C_NAME(client),
|
||||
*iarg);
|
||||
v4l_dbg(1, debug, client, "set output %d\n", *iarg);
|
||||
|
||||
/* not much choice of outputs */
|
||||
if (*iarg != 0) {
|
||||
if (*iarg != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_ENABLE_OUTPUT:
|
||||
{
|
||||
@ -262,10 +217,9 @@ bt856_command (struct i2c_client *client,
|
||||
|
||||
encoder->enable = !!*iarg;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: enable output %d\n",
|
||||
I2C_NAME(client), encoder->enable);
|
||||
}
|
||||
v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -276,64 +230,29 @@ bt856_command (struct i2c_client *client,
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_bt856;
|
||||
|
||||
static int
|
||||
bt856_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int bt856_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *client;
|
||||
struct bt856 *encoder;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"bt856.c: detecting bt856 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_bt856;
|
||||
strlcpy(I2C_NAME(client), "bt856", sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
|
||||
if (encoder == NULL) {
|
||||
kfree(client);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
encoder->norm = VIDEO_MODE_NTSC;
|
||||
encoder->enable = 1;
|
||||
i2c_set_clientdata(client, encoder);
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(encoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
bt856_write(client, 0xdc, 0x18);
|
||||
bt856_write(client, 0xda, 0);
|
||||
bt856_write(client, 0xde, 0);
|
||||
@ -359,65 +278,26 @@ bt856_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
if (debug != 0)
|
||||
bt856_dump(client);
|
||||
|
||||
dprintk(1, KERN_INFO "%s_attach: at address 0x%x\n", I2C_NAME(client),
|
||||
client->addr << 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bt856_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int bt856_remove(struct i2c_client *client)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"bt856.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &bt856_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
bt856_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct bt856 *encoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(encoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_bt856 = {
|
||||
.driver = {
|
||||
.name = "bt856",
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_BT856,
|
||||
|
||||
.attach_adapter = bt856_attach_adapter,
|
||||
.detach_client = bt856_detach_client,
|
||||
.command = bt856_command,
|
||||
static const struct i2c_device_id bt856_id[] = {
|
||||
{ "bt856", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bt856_id);
|
||||
|
||||
static int __init
|
||||
bt856_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_bt856);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
bt856_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_bt856);
|
||||
}
|
||||
|
||||
module_init(bt856_init);
|
||||
module_exit(bt856_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "bt856",
|
||||
.driverid = I2C_DRIVERID_BT856,
|
||||
.command = bt856_command,
|
||||
.probe = bt856_probe,
|
||||
.remove = bt856_remove,
|
||||
.id_table = bt856_id,
|
||||
};
|
||||
|
@ -29,42 +29,28 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_encoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
|
||||
MODULE_AUTHOR("Mike Bernson & Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define BT866_DEVNAME "bt866"
|
||||
#define I2C_BT866 0x88
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define DEBUG(x) /* Debug driver */
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct bt866 {
|
||||
struct i2c_client *i2c;
|
||||
int addr;
|
||||
unsigned char reg[256];
|
||||
u8 reg[256];
|
||||
|
||||
int norm;
|
||||
int enable;
|
||||
@ -74,20 +60,45 @@ struct bt866 {
|
||||
int sat;
|
||||
};
|
||||
|
||||
static int bt866_write(struct bt866 *dev,
|
||||
unsigned char subaddr, unsigned char data);
|
||||
|
||||
static int bt866_do_command(struct bt866 *encoder,
|
||||
unsigned int cmd, void *arg)
|
||||
static int bt866_write(struct i2c_client *client, u8 subaddr, u8 data)
|
||||
{
|
||||
struct bt866 *encoder = i2c_get_clientdata(client);
|
||||
u8 buffer[2];
|
||||
int err;
|
||||
|
||||
buffer[0] = subaddr;
|
||||
buffer[1] = data;
|
||||
|
||||
encoder->reg[subaddr] = data;
|
||||
|
||||
v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
|
||||
|
||||
for (err = 0; err < 3;) {
|
||||
if (i2c_master_send(client, buffer, 2) == 2)
|
||||
break;
|
||||
err++;
|
||||
v4l_warn(client, "error #%d writing to 0x%02x\n",
|
||||
err, subaddr);
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(100));
|
||||
}
|
||||
if (err == 3) {
|
||||
v4l_warn(client, "giving up\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt866_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct bt866 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
case ENCODER_GET_CAPABILITIES:
|
||||
{
|
||||
struct video_encoder_capability *cap = arg;
|
||||
|
||||
DEBUG(printk
|
||||
(KERN_INFO "%s: get capabilities\n",
|
||||
encoder->i2c->name));
|
||||
v4l_dbg(1, debug, client, "get capabilities\n");
|
||||
|
||||
cap->flags
|
||||
= VIDEO_ENCODER_PAL
|
||||
@ -95,18 +106,16 @@ static int bt866_do_command(struct bt866 *encoder,
|
||||
| VIDEO_ENCODER_CCIR;
|
||||
cap->inputs = 2;
|
||||
cap->outputs = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ENCODER_SET_NORM:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
DEBUG(printk(KERN_INFO "%s: set norm %d\n",
|
||||
encoder->i2c->name, *iarg));
|
||||
v4l_dbg(1, debug, client, "set norm %d\n", *iarg);
|
||||
|
||||
switch (*iarg) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
break;
|
||||
|
||||
@ -115,11 +124,10 @@ static int bt866_do_command(struct bt866 *encoder,
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
encoder->norm = *iarg;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ENCODER_SET_INPUT:
|
||||
{
|
||||
@ -155,7 +163,7 @@ static int bt866_do_command(struct bt866 *encoder,
|
||||
u8 val;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
|
||||
bt866_write(encoder, init[i], init[i+1]);
|
||||
bt866_write(client, init[i], init[i+1]);
|
||||
|
||||
val = encoder->reg[0xdc];
|
||||
|
||||
@ -164,17 +172,16 @@ static int bt866_do_command(struct bt866 *encoder,
|
||||
else
|
||||
val &= ~0x40; /* !CBSWAP */
|
||||
|
||||
bt866_write(encoder, 0xdc, val);
|
||||
bt866_write(client, 0xdc, val);
|
||||
|
||||
val = encoder->reg[0xcc];
|
||||
if (*iarg == 2)
|
||||
val |= 0x01; /* OSDBAR */
|
||||
else
|
||||
val &= ~0x01; /* !OSDBAR */
|
||||
bt866_write(encoder, 0xcc, val);
|
||||
bt866_write(client, 0xcc, val);
|
||||
|
||||
DEBUG(printk(KERN_INFO "%s: set input %d\n",
|
||||
encoder->i2c->name, *iarg));
|
||||
v4l_dbg(1, debug, client, "set input %d\n", *iarg);
|
||||
|
||||
switch (*iarg) {
|
||||
case 0:
|
||||
@ -183,48 +190,44 @@ static int bt866_do_command(struct bt866 *encoder,
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ENCODER_SET_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
DEBUG(printk(KERN_INFO "%s: set output %d\n",
|
||||
encoder->i2c->name, *iarg));
|
||||
v4l_dbg(1, debug, client, "set output %d\n", *iarg);
|
||||
|
||||
/* not much choice of outputs */
|
||||
if (*iarg != 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ENCODER_ENABLE_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
encoder->enable = !!*iarg;
|
||||
|
||||
DEBUG(printk
|
||||
(KERN_INFO "%s: enable output %d\n",
|
||||
encoder->i2c->name, encoder->enable));
|
||||
v4l_dbg(1, debug, client, "enable output %d\n", encoder->enable);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4711:
|
||||
{
|
||||
int *iarg = arg;
|
||||
__u8 val;
|
||||
|
||||
printk("bt866: square = %d\n", *iarg);
|
||||
v4l_dbg(1, debug, client, "square %d\n", *iarg);
|
||||
|
||||
val = encoder->reg[0xdc];
|
||||
if (*iarg)
|
||||
val |= 1; /* SQUARE */
|
||||
else
|
||||
val &= ~1; /* !SQUARE */
|
||||
bt866_write(encoder, 0xdc, val);
|
||||
bt866_write(client, 0xdc, val);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -235,141 +238,49 @@ static int bt866_do_command(struct bt866 *encoder,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt866_write(struct bt866 *encoder,
|
||||
unsigned char subaddr, unsigned char data)
|
||||
{
|
||||
unsigned char buffer[2];
|
||||
int err;
|
||||
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
|
||||
|
||||
buffer[0] = subaddr;
|
||||
buffer[1] = data;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
encoder->reg[subaddr] = data;
|
||||
|
||||
DEBUG(printk
|
||||
("%s: write 0x%02X = 0x%02X\n",
|
||||
encoder->i2c->name, subaddr, data));
|
||||
|
||||
for (err = 0; err < 3;) {
|
||||
if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
|
||||
break;
|
||||
err++;
|
||||
printk(KERN_WARNING "%s: I/O error #%d "
|
||||
"(write 0x%02x/0x%02x)\n",
|
||||
encoder->i2c->name, err, encoder->addr, subaddr);
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(100));
|
||||
}
|
||||
if (err == 3) {
|
||||
printk(KERN_WARNING "%s: giving up\n",
|
||||
encoder->i2c->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt866_attach(struct i2c_adapter *adapter);
|
||||
static int bt866_detach(struct i2c_client *client);
|
||||
static int bt866_command(struct i2c_client *client,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {I2C_BT866>>1, I2C_CLIENT_END};
|
||||
static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
|
||||
static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
normal_i2c,
|
||||
probe,
|
||||
ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_bt866 = {
|
||||
.driver.name = BT866_DEVNAME,
|
||||
.id = I2C_DRIVERID_BT866,
|
||||
.attach_adapter = bt866_attach,
|
||||
.detach_client = bt866_detach,
|
||||
.command = bt866_command
|
||||
};
|
||||
|
||||
|
||||
static struct i2c_client bt866_client_tmpl =
|
||||
{
|
||||
.name = "(nil)",
|
||||
.addr = 0,
|
||||
.adapter = NULL,
|
||||
.driver = &i2c_driver_bt866,
|
||||
};
|
||||
|
||||
static int bt866_found_proc(struct i2c_adapter *adapter,
|
||||
int addr, int kind)
|
||||
static int bt866_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct bt866 *encoder;
|
||||
struct i2c_client *client;
|
||||
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (client == NULL)
|
||||
return -ENOMEM;
|
||||
memcpy(client, &bt866_client_tmpl, sizeof(*client));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
|
||||
if (encoder == NULL) {
|
||||
kfree(client);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, encoder);
|
||||
client->adapter = adapter;
|
||||
client->addr = addr;
|
||||
sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
|
||||
|
||||
encoder->i2c = client;
|
||||
encoder->addr = addr;
|
||||
//encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
|
||||
|
||||
/* initialize */
|
||||
|
||||
i2c_attach_client(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt866_attach(struct i2c_adapter *adapter)
|
||||
static int bt866_remove(struct i2c_client *client)
|
||||
{
|
||||
if (adapter->id == I2C_HW_B_ZR36067)
|
||||
return i2c_probe(adapter, &addr_data, bt866_found_proc);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt866_detach(struct i2c_client *client)
|
||||
static int bt866_legacy_probe(struct i2c_adapter *adapter)
|
||||
{
|
||||
struct bt866 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
i2c_detach_client(client);
|
||||
kfree(encoder);
|
||||
kfree(client);
|
||||
|
||||
return 0;
|
||||
return adapter->id == I2C_HW_B_ZR36067;
|
||||
}
|
||||
|
||||
static int bt866_command(struct i2c_client *client,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct bt866 *encoder = i2c_get_clientdata(client);
|
||||
return bt866_do_command(encoder, cmd, arg);
|
||||
}
|
||||
static const struct i2c_device_id bt866_id[] = {
|
||||
{ "bt866", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bt866_id);
|
||||
|
||||
static int __devinit bt866_init(void)
|
||||
{
|
||||
i2c_add_driver(&i2c_driver_bt866);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit bt866_exit(void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_bt866);
|
||||
}
|
||||
|
||||
module_init(bt866_init);
|
||||
module_exit(bt866_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "bt866",
|
||||
.driverid = I2C_DRIVERID_BT866,
|
||||
.command = bt866_command,
|
||||
.probe = bt866_probe,
|
||||
.remove = bt866_remove,
|
||||
.legacy_probe = bt866_legacy_probe,
|
||||
.id_table = bt866_id,
|
||||
};
|
||||
|
@ -39,16 +39,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",
|
||||
@ -57,19 +57,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",
|
||||
@ -84,20 +84,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",
|
||||
@ -106,19 +106,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",
|
||||
@ -169,43 +169,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,
|
||||
@ -225,11 +225,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,
|
||||
@ -247,23 +247,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);
|
||||
}
|
||||
|
||||
@ -271,11 +273,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 */
|
||||
@ -303,21 +305,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 */
|
||||
@ -329,7 +361,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;
|
||||
}
|
||||
|
||||
@ -352,7 +385,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:
|
||||
@ -383,7 +416,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 */
|
||||
@ -617,10 +650,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
|
||||
*/
|
||||
|
@ -37,12 +37,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)\
|
||||
@ -364,13 +364,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);
|
||||
}
|
||||
|
||||
@ -381,8 +380,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);
|
||||
@ -418,15 +416,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)
|
||||
@ -436,9 +434,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,
|
||||
@ -469,43 +467,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));
|
||||
}
|
||||
|
||||
@ -515,13 +513,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;
|
||||
@ -600,7 +598,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;
|
||||
@ -608,13 +606,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;
|
||||
}
|
||||
@ -623,7 +621,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);
|
||||
|
||||
@ -643,7 +642,18 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
|
||||
port->mpegq.timeout.data = (unsigned long)port;
|
||||
init_timer(&port->mpegq.timeout);
|
||||
|
||||
switch(portno) {
|
||||
mutex_init(&port->frontends.lock);
|
||||
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)
|
||||
port->num_frontends = 1;
|
||||
|
||||
switch (portno) {
|
||||
case 1:
|
||||
port->reg_gpcnt = VID_B_GPCNT;
|
||||
port->reg_gpcnt_ctl = VID_B_GPCNT_CTL;
|
||||
@ -744,13 +754,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;
|
||||
@ -831,8 +841,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;
|
||||
|
||||
@ -862,7 +872,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) {
|
||||
@ -908,8 +918,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;
|
||||
@ -936,7 +946,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)
|
||||
@ -957,31 +967,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;
|
||||
@ -1010,9 +1020,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 */
|
||||
@ -1026,7 +1038,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;
|
||||
}
|
||||
|
||||
@ -1048,7 +1060,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 */
|
||||
@ -1057,7 +1070,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;
|
||||
}
|
||||
|
||||
@ -1067,7 +1080,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 */
|
||||
@ -1161,22 +1175,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;
|
||||
}
|
||||
|
||||
@ -1186,7 +1201,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);
|
||||
@ -1195,7 +1210,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;
|
||||
@ -1229,11 +1244,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);
|
||||
@ -1292,8 +1307,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;
|
||||
|
||||
@ -1311,7 +1325,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 &&
|
||||
@ -1322,8 +1336,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;
|
||||
@ -1362,7 +1377,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,
|
||||
@ -1388,7 +1404,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;
|
||||
@ -1397,7 +1413,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);
|
||||
@ -1405,7 +1421,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__);
|
||||
}
|
||||
}
|
||||
@ -1431,7 +1447,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);
|
||||
@ -1453,10 +1469,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);
|
||||
@ -1532,16 +1549,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);
|
||||
|
||||
@ -1595,7 +1619,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);
|
||||
@ -1610,38 +1634,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);
|
||||
|
||||
}
|
||||
|
||||
@ -1753,13 +1795,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 --- */
|
||||
}
|
||||
};
|
||||
@ -1797,9 +1839,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
|
||||
*/
|
||||
|
@ -78,19 +78,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 = {
|
||||
@ -312,19 +312,25 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
{
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
struct cx23885_i2c *i2c_bus = NULL;
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
|
||||
/* Get the first frontend */
|
||||
fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
|
||||
if (!fe0)
|
||||
return -EINVAL;
|
||||
|
||||
/* init struct videobuf_dvb */
|
||||
port->dvb.name = dev->name;
|
||||
fe0->dvb.name = dev->name;
|
||||
|
||||
/* init frontend */
|
||||
switch (dev->board) {
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&hauppauge_generic_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
dvb_attach(mt2131_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(mt2131_attach, fe0->dvb.frontend,
|
||||
&i2c_bus->i2c_adap,
|
||||
&hauppauge_generic_tunerconfig, 0);
|
||||
}
|
||||
@ -333,27 +339,27 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
switch (alt_tuner) {
|
||||
case 1:
|
||||
port->dvb.frontend =
|
||||
fe0->dvb.frontend =
|
||||
dvb_attach(s5h1409_attach,
|
||||
&hauppauge_ezqam_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
dvb_attach(tda829x_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(tda829x_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_bus[1].i2c_adap, 0x42,
|
||||
&tda829x_no_probe);
|
||||
dvb_attach(tda18271_attach, port->dvb.frontend,
|
||||
dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
||||
0x60, &dev->i2c_bus[1].i2c_adap,
|
||||
&hauppauge_tda18271_config);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
port->dvb.frontend =
|
||||
fe0->dvb.frontend =
|
||||
dvb_attach(s5h1409_attach,
|
||||
&hauppauge_generic_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL)
|
||||
dvb_attach(mt2131_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL)
|
||||
dvb_attach(mt2131_attach, fe0->dvb.frontend,
|
||||
&i2c_bus->i2c_adap,
|
||||
&hauppauge_generic_tunerconfig, 0);
|
||||
break;
|
||||
@ -361,42 +367,42 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
break;
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&hauppauge_hvr1800lp_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
dvb_attach(mt2131_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(mt2131_attach, fe0->dvb.frontend,
|
||||
&i2c_bus->i2c_adap,
|
||||
&hauppauge_generic_tunerconfig, 0);
|
||||
}
|
||||
break;
|
||||
case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
port->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
&fusionhdtv_5_express,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
dvb_attach(simple_tuner_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&i2c_bus->i2c_adap, 0x61,
|
||||
TUNER_LG_TDVS_H06XF);
|
||||
}
|
||||
break;
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
|
||||
i2c_bus = &dev->i2c_bus[1];
|
||||
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&hauppauge_hvr1500q_config,
|
||||
&dev->i2c_bus[0].i2c_adap);
|
||||
if (port->dvb.frontend != NULL)
|
||||
dvb_attach(xc5000_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL)
|
||||
dvb_attach(xc5000_attach, fe0->dvb.frontend,
|
||||
&i2c_bus->i2c_adap,
|
||||
&hauppauge_hvr1500q_tunerconfig);
|
||||
break;
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
||||
i2c_bus = &dev->i2c_bus[1];
|
||||
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&hauppauge_hvr1500_config,
|
||||
&dev->i2c_bus[0].i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
struct dvb_frontend *fe;
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &i2c_bus->i2c_adap,
|
||||
@ -409,7 +415,7 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
};
|
||||
|
||||
fe = dvb_attach(xc2028_attach,
|
||||
port->dvb.frontend, &cfg);
|
||||
fe0->dvb.frontend, &cfg);
|
||||
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
||||
fe->ops.tuner_ops.set_config(fe, &ctl);
|
||||
}
|
||||
@ -417,24 +423,24 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1200:
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1700:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
port->dvb.frontend = dvb_attach(tda10048_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10048_attach,
|
||||
&hauppauge_hvr1200_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
dvb_attach(tda829x_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
dvb_attach(tda829x_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_bus[1].i2c_adap, 0x42,
|
||||
&tda829x_no_probe);
|
||||
dvb_attach(tda18271_attach, port->dvb.frontend,
|
||||
dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
||||
0x60, &dev->i2c_bus[1].i2c_adap,
|
||||
&hauppauge_hvr1200_tuner_config);
|
||||
}
|
||||
break;
|
||||
case CX23885_BOARD_HAUPPAUGE_HVR1400:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
port->dvb.frontend = dvb_attach(dib7000p_attach,
|
||||
fe0->dvb.frontend = dvb_attach(dib7000p_attach,
|
||||
&i2c_bus->i2c_adap,
|
||||
0x12, &hauppauge_hvr1400_dib7000_config);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
struct dvb_frontend *fe;
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
|
||||
@ -444,12 +450,13 @@ 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,
|
||||
};
|
||||
|
||||
fe = dvb_attach(xc2028_attach,
|
||||
port->dvb.frontend, &cfg);
|
||||
fe0->dvb.frontend, &cfg);
|
||||
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
||||
fe->ops.tuner_ops.set_config(fe, &ctl);
|
||||
}
|
||||
@ -457,25 +464,25 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
|
||||
i2c_bus = &dev->i2c_bus[port->nr - 1];
|
||||
|
||||
port->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&dvico_s5h1409_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend == NULL)
|
||||
port->dvb.frontend = dvb_attach(s5h1411_attach,
|
||||
if (fe0->dvb.frontend == NULL)
|
||||
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
|
||||
&dvico_s5h1411_config,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL)
|
||||
dvb_attach(xc5000_attach, port->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL)
|
||||
dvb_attach(xc5000_attach, fe0->dvb.frontend,
|
||||
&i2c_bus->i2c_adap,
|
||||
&dvico_xc5000_tunerconfig);
|
||||
break;
|
||||
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
|
||||
i2c_bus = &dev->i2c_bus[port->nr - 1];
|
||||
|
||||
port->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&dvico_fusionhdtv_xc3028,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
struct dvb_frontend *fe;
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &i2c_bus->i2c_adap,
|
||||
@ -487,7 +494,7 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
.demod = XC3028_FE_ZARLINK456,
|
||||
};
|
||||
|
||||
fe = dvb_attach(xc2028_attach, port->dvb.frontend,
|
||||
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
|
||||
&cfg);
|
||||
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
||||
fe->ops.tuner_ops.set_config(fe, &ctl);
|
||||
@ -497,10 +504,10 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
|
||||
i2c_bus = &dev->i2c_bus[0];
|
||||
|
||||
port->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&dvico_fusionhdtv_xc3028,
|
||||
&i2c_bus->i2c_adap);
|
||||
if (port->dvb.frontend != NULL) {
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
struct dvb_frontend *fe;
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &dev->i2c_bus[1].i2c_adap,
|
||||
@ -512,73 +519,108 @@ static int dvb_register(struct cx23885_tsport *port)
|
||||
.demod = XC3028_FE_ZARLINK456,
|
||||
};
|
||||
|
||||
fe = dvb_attach(xc2028_attach, port->dvb.frontend,
|
||||
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
|
||||
&cfg);
|
||||
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
||||
fe->ops.tuner_ops.set_config(fe, &ctl);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
|
||||
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
|
||||
" isn't supported yet\n",
|
||||
dev->name);
|
||||
break;
|
||||
}
|
||||
if (NULL == port->dvb.frontend) {
|
||||
printk("%s: frontend initialization failed\n", dev->name);
|
||||
if (NULL == fe0->dvb.frontend) {
|
||||
printk(KERN_ERR "%s: frontend initialization failed\n",
|
||||
dev->name);
|
||||
return -1;
|
||||
}
|
||||
/* define general-purpose callback pointer */
|
||||
port->dvb.frontend->callback = cx23885_tuner_callback;
|
||||
fe0->dvb.frontend->callback = cx23885_tuner_callback;
|
||||
|
||||
/* Put the analog decoder in standby to keep it quiet */
|
||||
cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
|
||||
|
||||
if (port->dvb.frontend->ops.analog_ops.standby)
|
||||
port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
|
||||
if (fe0->dvb.frontend->ops.analog_ops.standby)
|
||||
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
|
||||
|
||||
/* register everything */
|
||||
return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
|
||||
&dev->pci->dev, adapter_nr);
|
||||
return videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
|
||||
&dev->pci->dev, adapter_nr, 0);
|
||||
|
||||
}
|
||||
|
||||
int cx23885_dvb_register(struct cx23885_tsport *port)
|
||||
{
|
||||
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
struct cx23885_dev *dev = port->dev;
|
||||
int err;
|
||||
int err, i;
|
||||
|
||||
dprintk(1, "%s\n", __func__);
|
||||
dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
|
||||
dev->board,
|
||||
dev->name,
|
||||
dev->pci_bus,
|
||||
dev->pci_slot);
|
||||
/* Here we need to allocate the correct number of frontends,
|
||||
* as reflected in the cards struct. The reality is that currrently
|
||||
* no cx23885 boards support this - yet. But, if we don't modify this
|
||||
* code then the second frontend would never be allocated (later)
|
||||
* and fail with error before the attach in dvb_register().
|
||||
* Without these changes we risk an OOPS later. The changes here
|
||||
* are for safety, and should provide a good foundation for the
|
||||
* future addition of any multi-frontend cx23885 based boards.
|
||||
*/
|
||||
printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
|
||||
port->num_frontends);
|
||||
|
||||
err = -ENODEV;
|
||||
for (i = 1; i <= port->num_frontends; i++) {
|
||||
if (videobuf_dvb_alloc_frontend(
|
||||
&port->frontends, i) == NULL) {
|
||||
printk(KERN_ERR "%s() failed to alloc\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* dvb stuff */
|
||||
printk("%s: cx23885 based dvb card\n", dev->name);
|
||||
videobuf_queue_sg_init(&port->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
|
||||
fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
|
||||
if (!fe0)
|
||||
err = -EINVAL;
|
||||
|
||||
dprintk(1, "%s\n", __func__);
|
||||
dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
|
||||
dev->board,
|
||||
dev->name,
|
||||
dev->pci_bus,
|
||||
dev->pci_slot);
|
||||
|
||||
err = -ENODEV;
|
||||
|
||||
/* dvb stuff */
|
||||
/* We have to init the queue for each frontend on a port. */
|
||||
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;
|
||||
}
|
||||
|
||||
int cx23885_dvb_unregister(struct cx23885_tsport *port)
|
||||
{
|
||||
/* dvb */
|
||||
if(port->dvb.frontend)
|
||||
videobuf_dvb_unregister(&port->dvb);
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
|
||||
/* FIXME: in an error condition where the we have
|
||||
* an expected number of frontends (attach problem)
|
||||
* then this might not clean up correctly, if 1
|
||||
* is invalid.
|
||||
* This comment only applies to future boards IF they
|
||||
* implement MFE support.
|
||||
*/
|
||||
fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
|
||||
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
|
||||
*/
|
||||
|
@ -131,7 +131,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);
|
||||
@ -151,9 +151,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;
|
||||
@ -162,7 +162,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;
|
||||
}
|
||||
|
||||
@ -194,12 +194,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;
|
||||
|
||||
@ -216,9 +216,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;
|
||||
@ -227,7 +227,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;
|
||||
}
|
||||
|
||||
@ -353,17 +353,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)
|
||||
@ -376,7 +376,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] : "???");
|
||||
}
|
||||
}
|
||||
@ -408,11 +408,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;
|
||||
}
|
||||
|
@ -285,11 +285,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);
|
||||
@ -379,12 +378,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,
|
||||
@ -887,14 +886,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__);
|
||||
@ -1073,29 +1074,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,
|
||||
|
@ -37,7 +37,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)
|
||||
|
||||
@ -225,7 +225,7 @@ struct cx23885_tsport {
|
||||
int nr;
|
||||
int sram_chno;
|
||||
|
||||
struct videobuf_dvb dvb;
|
||||
struct videobuf_dvb_frontends frontends;
|
||||
|
||||
/* dma queues */
|
||||
struct cx23885_dmaqueue mpegq;
|
||||
@ -262,6 +262,9 @@ struct cx23885_tsport {
|
||||
u32 src_sel_val;
|
||||
u32 vld_misc_val;
|
||||
u32 hw_sop_ctrl_val;
|
||||
|
||||
/* Allow a single tsport to have multiple frontends */
|
||||
u32 num_frontends;
|
||||
};
|
||||
|
||||
struct cx23885_dev {
|
||||
@ -367,14 +370,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 */
|
||||
@ -411,7 +414,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);
|
||||
@ -479,11 +483,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
|
||||
*/
|
||||
|
@ -1270,27 +1270,40 @@ static const struct cx88_board cx88_boards[] = {
|
||||
.mpeg = CX88_MPEG_DVB,
|
||||
},
|
||||
[CX88_BOARD_HAUPPAUGE_HVR3000] = {
|
||||
/* FIXME: Add dvb & radio support */
|
||||
.name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
|
||||
.tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
|
||||
.radio_type = UNSET,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
.tda9887_conf = TDA9887_PRESENT,
|
||||
.audio_chip = V4L2_IDENT_WM8775,
|
||||
.input = {{
|
||||
.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,
|
||||
}},
|
||||
.radio = {
|
||||
.type = CX88_RADIO,
|
||||
.gpio0 = 0x84bf,
|
||||
/* 4: FM Stereo (untested) */
|
||||
.audioroute = 8,
|
||||
},
|
||||
.mpeg = CX88_MPEG_DVB,
|
||||
.num_frontends = 2,
|
||||
},
|
||||
[CX88_BOARD_NORWOOD_MICRO] = {
|
||||
.name = "Norwood Micro TV Tuner",
|
||||
@ -1356,23 +1369,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] = {
|
||||
@ -1716,6 +1733,7 @@ static const struct cx88_board cx88_boards[] = {
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
.tda9887_conf = TDA9887_PRESENT,
|
||||
.audio_chip = V4L2_IDENT_WM8775,
|
||||
/*
|
||||
* GPIO0 (WINTV2000)
|
||||
*
|
||||
@ -1729,7 +1747,7 @@ static const struct cx88_board cx88_boards[] = {
|
||||
* BIT VALUE FUNCTION GP{x}_IO
|
||||
* 0 1 I:?
|
||||
* 1 1 I:?
|
||||
* 2 1 O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH
|
||||
* 2 1 O:MPEG PORT 0=DVB-T 1=DVB-S
|
||||
* 3 1 I:?
|
||||
* 4 1 I:?
|
||||
* 5 1 I:?
|
||||
@ -1745,22 +1763,41 @@ 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: Add radio support */
|
||||
.radio = {
|
||||
.type = CX88_RADIO,
|
||||
.gpio0 = 0xc4bf,
|
||||
/* 4: FM Stereo */
|
||||
.audioroute = 8,
|
||||
},
|
||||
.mpeg = CX88_MPEG_DVB,
|
||||
.num_frontends = 2,
|
||||
},
|
||||
[CX88_BOARD_HAUPPAUGE_HVR4000LITE] = {
|
||||
.name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2",
|
||||
@ -2662,10 +2699,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
|
||||
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
|
||||
/* Init GPIO */
|
||||
cx_write(MO_GP0_IO, core->board.input[0].gpio0);
|
||||
udelay(1000);
|
||||
cx_clear(MO_GP0_IO, 0x00000080);
|
||||
udelay(50);
|
||||
cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
|
||||
udelay(1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3004,10 +3044,14 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
|
||||
|
||||
memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
|
||||
|
||||
info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
|
||||
if (!core->board.num_frontends)
|
||||
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,
|
||||
core->boardnr, card[core->nr] == core->boardnr ?
|
||||
"insmod option" : "autodetected");
|
||||
"insmod option" : "autodetected",
|
||||
core->board.num_frontends);
|
||||
|
||||
if (tuner[core->nr] != UNSET)
|
||||
core->board.tuner_type = tuner[core->nr];
|
||||
|
@ -549,7 +549,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)
|
||||
|
@ -116,13 +116,23 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
|
||||
struct cx8802_dev *dev= fe->dvb->priv;
|
||||
struct cx8802_driver *drv = NULL;
|
||||
int ret = 0;
|
||||
int fe_id;
|
||||
|
||||
fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
|
||||
if (!fe_id) {
|
||||
printk(KERN_ERR "%s() No frontend found\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
|
||||
if (drv) {
|
||||
if (acquire)
|
||||
if (acquire){
|
||||
dev->frontends.active_fe_id = fe_id;
|
||||
ret = drv->request_acquire(drv);
|
||||
else
|
||||
} else {
|
||||
ret = drv->request_release(drv);
|
||||
dev->frontends.active_fe_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -396,7 +406,7 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
|
||||
cx_write(MO_GP0_IO, 0x00006060);
|
||||
break;
|
||||
case SEC_VOLTAGE_OFF:
|
||||
printk("LNB Voltage SEC_VOLTAGE_off\n");
|
||||
printk("LNB Voltage SEC_VOLTAGE_off\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -483,6 +493,7 @@ static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
|
||||
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
|
||||
{
|
||||
struct dvb_frontend *fe;
|
||||
struct videobuf_dvb_frontend *fe0 = NULL;
|
||||
struct xc2028_ctrl ctl;
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &dev->core->i2c_adap,
|
||||
@ -490,7 +501,12 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
|
||||
.ctrl = &ctl,
|
||||
};
|
||||
|
||||
if (!dev->dvb.frontend) {
|
||||
/* Get the first frontend */
|
||||
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
|
||||
if (!fe0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!fe0->dvb.frontend) {
|
||||
printk(KERN_ERR "%s/2: dvb frontend not attached. "
|
||||
"Can't attach xc3028\n",
|
||||
dev->core->name);
|
||||
@ -504,10 +520,13 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
|
||||
*/
|
||||
cx88_setup_xc3028(dev->core, &ctl);
|
||||
|
||||
fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
|
||||
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
|
||||
if (!fe) {
|
||||
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
|
||||
dev->core->name);
|
||||
dvb_frontend_detach(fe0->dvb.frontend);
|
||||
dvb_unregister_frontend(fe0->dvb.frontend);
|
||||
fe0->dvb.frontend = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -532,8 +551,10 @@ static int cx24116_reset_device(struct dvb_frontend *fe)
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
/* Reset the part */
|
||||
/* Put the cx24116 into reset */
|
||||
cx_write(MO_SRST_IO, 0);
|
||||
msleep(10);
|
||||
/* Take the cx24116 out of reset */
|
||||
cx_write(MO_SRST_IO, 1);
|
||||
msleep(10);
|
||||
|
||||
@ -554,14 +575,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,
|
||||
};
|
||||
|
||||
@ -574,19 +595,25 @@ static struct stv0288_config tevii_tuner_earda_config = {
|
||||
static int dvb_register(struct cx8802_dev *dev)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
|
||||
int mfe_shared = 0; /* bus not shared by default */
|
||||
|
||||
/* init struct videobuf_dvb */
|
||||
dev->dvb.name = core->name;
|
||||
dev->ts_gen_cntrl = 0x0c;
|
||||
/* Get the first frontend */
|
||||
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
|
||||
if (!fe0)
|
||||
return -EINVAL;
|
||||
|
||||
/* init frontend */
|
||||
/* multi-frontend gate control is undefined or defaults to fe0 */
|
||||
dev->frontends.gate = 0;
|
||||
|
||||
/* init frontend(s) */
|
||||
switch (core->boardnr) {
|
||||
case CX88_BOARD_HAUPPAUGE_DVB_T1:
|
||||
dev->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
&connexant_refboard_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x61, &core->i2c_adap,
|
||||
DVB_PLL_THOMSON_DTT759X))
|
||||
goto frontend_detach;
|
||||
@ -596,11 +623,11 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
case CX88_BOARD_CONEXANT_DVB_T1:
|
||||
case CX88_BOARD_KWORLD_DVB_T_CX22702:
|
||||
case CX88_BOARD_WINFAST_DTV1000:
|
||||
dev->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
&connexant_refboard_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x60, &core->i2c_adap,
|
||||
DVB_PLL_THOMSON_DTT7579))
|
||||
goto frontend_detach;
|
||||
@ -610,33 +637,67 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1100:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1300:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
dev->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx22702_attach,
|
||||
&hauppauge_hvr_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_PHILIPS_FMD1216ME_MK3))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
/* DVB-S init */
|
||||
fe0->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
&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", __func__);
|
||||
}
|
||||
} else {
|
||||
dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __func__);
|
||||
}
|
||||
/* DVB-T init */
|
||||
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", __func__);
|
||||
}
|
||||
} else {
|
||||
dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __func__);
|
||||
}
|
||||
} else {
|
||||
dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __func__);
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&dvico_fusionhdtv,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x60, NULL, DVB_PLL_THOMSON_DTT7579))
|
||||
goto frontend_detach;
|
||||
break;
|
||||
}
|
||||
/* ZL10353 replaces MT352 on later cards */
|
||||
dev->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&dvico_fusionhdtv_plus_v1_1,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x60, NULL, DVB_PLL_THOMSON_DTT7579))
|
||||
goto frontend_detach;
|
||||
}
|
||||
@ -644,31 +705,31 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
|
||||
/* The tin box says DEE1601, but it seems to be DTT7579
|
||||
* compatible, with a slightly different MT352 AGC gain. */
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&dvico_fusionhdtv_dual,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x61, NULL, DVB_PLL_THOMSON_DTT7579))
|
||||
goto frontend_detach;
|
||||
break;
|
||||
}
|
||||
/* ZL10353 replaces MT352 on later cards */
|
||||
dev->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&dvico_fusionhdtv_plus_v1_1,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x61, NULL, DVB_PLL_THOMSON_DTT7579))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&dvico_fusionhdtv,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x61, NULL, DVB_PLL_LG_Z201))
|
||||
goto frontend_detach;
|
||||
}
|
||||
@ -676,11 +737,11 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
case CX88_BOARD_KWORLD_DVB_T:
|
||||
case CX88_BOARD_DNTV_LIVE_DVB_T:
|
||||
case CX88_BOARD_ADSTECH_DVB_T_PCI:
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&dntv_live_dvbt_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
|
||||
0x61, NULL, DVB_PLL_UNKNOWN_1))
|
||||
goto frontend_detach;
|
||||
}
|
||||
@ -688,10 +749,10 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
|
||||
/* MT352 is on a secondary I2C bus made from some GPIO lines */
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
|
||||
&dev->vp3054->adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_PHILIPS_FMD1216ME_MK3))
|
||||
goto frontend_detach;
|
||||
@ -702,22 +763,22 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
#endif
|
||||
break;
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
|
||||
dev->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&dvico_fusionhdtv_hybrid,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_THOMSON_FE6600))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
|
||||
dev->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&dvico_fusionhdtv_xc3028,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend == NULL)
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
if (fe0->dvb.frontend == NULL)
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&dvico_fusionhdtv_mt352_xc3028,
|
||||
&core->i2c_adap);
|
||||
/*
|
||||
@ -725,16 +786,16 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
* We must not permit gate_ctrl to be performed, or
|
||||
* the xc3028 cannot communicate on the bus.
|
||||
*/
|
||||
if (dev->dvb.frontend)
|
||||
dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
|
||||
if (fe0->dvb.frontend)
|
||||
fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
|
||||
if (attach_xc3028(0x61, dev) < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case CX88_BOARD_PCHDTV_HD3000:
|
||||
dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
|
||||
fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_THOMSON_DTT761X))
|
||||
goto frontend_detach;
|
||||
@ -751,11 +812,11 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
|
||||
/* Select RF connector callback */
|
||||
fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
|
||||
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
&fusionhdtv_3_gold,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_MICROTUNE_4042FI5))
|
||||
goto frontend_detach;
|
||||
@ -769,11 +830,11 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
mdelay(100);
|
||||
cx_set(MO_GP0_IO, 9);
|
||||
mdelay(200);
|
||||
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
&fusionhdtv_3_gold,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_THOMSON_DTT761X))
|
||||
goto frontend_detach;
|
||||
@ -787,15 +848,15 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
mdelay(100);
|
||||
cx_set(MO_GP0_IO, 1);
|
||||
mdelay(200);
|
||||
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
&fusionhdtv_5_gold,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_LG_TDVS_H06XF))
|
||||
goto frontend_detach;
|
||||
if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
|
||||
if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x43))
|
||||
goto frontend_detach;
|
||||
}
|
||||
@ -808,25 +869,25 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
mdelay(100);
|
||||
cx_set(MO_GP0_IO, 1);
|
||||
mdelay(200);
|
||||
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
|
||||
&pchdtv_hd5500,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_LG_TDVS_H06XF))
|
||||
goto frontend_detach;
|
||||
if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
|
||||
if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x43))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_ATI_HDTVWONDER:
|
||||
dev->dvb.frontend = dvb_attach(nxt200x_attach,
|
||||
fe0->dvb.frontend = dvb_attach(nxt200x_attach,
|
||||
&ati_hdtvwonder,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x61,
|
||||
TUNER_PHILIPS_TUV1236D))
|
||||
goto frontend_detach;
|
||||
@ -834,49 +895,49 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
|
||||
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
|
||||
dev->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
&hauppauge_novas_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend) {
|
||||
if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_KWORLD_DVBS_100:
|
||||
dev->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
&kworld_dvbs_100_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
|
||||
dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
|
||||
if (fe0->dvb.frontend) {
|
||||
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
|
||||
fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_GENIATECH_DVBS:
|
||||
dev->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx24123_attach,
|
||||
&geniatech_dvbs_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
|
||||
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
|
||||
if (fe0->dvb.frontend) {
|
||||
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
|
||||
fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
|
||||
dev->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&pinnacle_pctv_hd_800i_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap,
|
||||
&pinnacle_pctv_hd_800i_tuner_config))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
|
||||
dev->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&dvico_hdtv5_pci_nano_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
struct dvb_frontend *fe;
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &core->i2c_adap,
|
||||
@ -889,17 +950,17 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
};
|
||||
|
||||
fe = dvb_attach(xc2028_attach,
|
||||
dev->dvb.frontend, &cfg);
|
||||
fe0->dvb.frontend, &cfg);
|
||||
if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
||||
fe->ops.tuner_ops.set_config(fe, &ctl);
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
|
||||
dev->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&cx88_pinnacle_hybrid_pctv,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
|
||||
if (fe0->dvb.frontend) {
|
||||
fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
|
||||
if (attach_xc3028(0x61, dev) < 0)
|
||||
goto frontend_detach;
|
||||
}
|
||||
@ -907,85 +968,118 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
case CX88_BOARD_GENIATECH_X8000_MT:
|
||||
dev->ts_gen_cntrl = 0x00;
|
||||
|
||||
dev->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
||||
&cx88_geniatech_x8000_mt,
|
||||
&core->i2c_adap);
|
||||
if (attach_xc3028(0x61, dev) < 0)
|
||||
goto frontend_detach;
|
||||
break;
|
||||
case CX88_BOARD_KWORLD_ATSC_120:
|
||||
dev->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
||||
&kworld_atsc_120_config,
|
||||
&core->i2c_adap);
|
||||
if (attach_xc3028(0x61, dev) < 0)
|
||||
goto frontend_detach;
|
||||
break;
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
|
||||
dev->dvb.frontend = dvb_attach(s5h1411_attach,
|
||||
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
|
||||
&dvico_fusionhdtv7_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
|
||||
&core->i2c_adap,
|
||||
&dvico_fusionhdtv7_tuner_config))
|
||||
goto frontend_detach;
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
|
||||
/* Support for DVB-S only, not DVB-T support */
|
||||
dev->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
/* DVB-S/S2 Init */
|
||||
fe0->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
&hauppauge_hvr4000_config,
|
||||
&dev->core->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dvb_attach(isl6421_attach, dev->dvb.frontend,
|
||||
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", __func__);
|
||||
}
|
||||
} else {
|
||||
dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __func__);
|
||||
}
|
||||
/* DVB-T Init */
|
||||
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", __func__);
|
||||
}
|
||||
} else {
|
||||
dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __func__);
|
||||
}
|
||||
} else {
|
||||
dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __func__);
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
|
||||
fe0->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
&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);
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_TEVII_S420:
|
||||
dev->dvb.frontend = dvb_attach(stv0299_attach,
|
||||
fe0->dvb.frontend = dvb_attach(stv0299_attach,
|
||||
&tevii_tuner_sharp_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
|
||||
&core->i2c_adap, DVB_PLL_OPERA1))
|
||||
goto frontend_detach;
|
||||
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
|
||||
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
|
||||
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
|
||||
} else {
|
||||
dev->dvb.frontend = dvb_attach(stv0288_attach,
|
||||
fe0->dvb.frontend = dvb_attach(stv0288_attach,
|
||||
&tevii_tuner_earda_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
|
||||
&core->i2c_adap))
|
||||
goto frontend_detach;
|
||||
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
|
||||
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
|
||||
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_TEVII_S460:
|
||||
dev->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
&tevii_s460_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
|
||||
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
|
||||
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:
|
||||
dev->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
fe0->dvb.frontend = dvb_attach(cx24116_attach,
|
||||
&hauppauge_hvr4000_config,
|
||||
&core->i2c_adap);
|
||||
if (dev->dvb.frontend != NULL) {
|
||||
core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
|
||||
dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
if (fe0->dvb.frontend != NULL) {
|
||||
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
|
||||
fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -993,29 +1087,32 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
core->name);
|
||||
break;
|
||||
}
|
||||
if (NULL == dev->dvb.frontend) {
|
||||
|
||||
if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
|
||||
printk(KERN_ERR
|
||||
"%s/2: frontend initialization failed\n",
|
||||
core->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* define general-purpose callback pointer */
|
||||
dev->dvb.frontend->callback = cx88_tuner_callback;
|
||||
fe0->dvb.frontend->callback = cx88_tuner_callback;
|
||||
|
||||
/* Ensure all frontends negotiate bus access */
|
||||
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
|
||||
fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
|
||||
if (fe1)
|
||||
fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
|
||||
|
||||
/* Put the analog decoder in standby to keep it quiet */
|
||||
cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
|
||||
|
||||
/* register everything */
|
||||
return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
|
||||
&dev->pci->dev, adapter_nr);
|
||||
return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
|
||||
&dev->pci->dev, adapter_nr, mfe_shared);
|
||||
|
||||
frontend_detach:
|
||||
if (dev->dvb.frontend) {
|
||||
dvb_frontend_detach(dev->dvb.frontend);
|
||||
dev->dvb.frontend = NULL;
|
||||
if (fe0->dvb.frontend) {
|
||||
dvb_frontend_detach(fe0->dvb.frontend);
|
||||
fe0->dvb.frontend = NULL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1039,6 +1136,38 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
|
||||
cx_clear(MO_GP0_IO, 0x00000004);
|
||||
udelay(1000);
|
||||
break;
|
||||
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000:
|
||||
if(core->dvbdev->frontends.active_fe_id == 1) {
|
||||
/* DVB-S/S2 Enabled */
|
||||
|
||||
/* Toggle reset on cx22702 leaving i2c active */
|
||||
cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080);
|
||||
udelay(1000);
|
||||
cx_clear(MO_GP0_IO, 0x00000080);
|
||||
udelay(50);
|
||||
cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
|
||||
cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
|
||||
udelay(1000);
|
||||
|
||||
cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
|
||||
core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
|
||||
} else
|
||||
if (core->dvbdev->frontends.active_fe_id == 2) {
|
||||
/* DVB-T Enabled */
|
||||
|
||||
/* Put the cx24116/cx24123 into reset */
|
||||
cx_write(MO_SRST_IO, 0);
|
||||
|
||||
/* cx22702 out of reset and enable it */
|
||||
cx_set(MO_GP0_IO, 0x00000080);
|
||||
cx_clear(MO_GP0_IO, 0x00000004);
|
||||
core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
|
||||
udelay(1000);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -ENODEV;
|
||||
}
|
||||
@ -1056,6 +1185,9 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1300:
|
||||
/* Do Nothing, leave the cx22702 on the bus. */
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000:
|
||||
break;
|
||||
default:
|
||||
err = -ENODEV;
|
||||
}
|
||||
@ -1066,7 +1198,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
|
||||
{
|
||||
struct cx88_core *core = drv->core;
|
||||
struct cx8802_dev *dev = drv->core->dvbdev;
|
||||
int err;
|
||||
int err, i;
|
||||
struct videobuf_dvb_frontend *fe;
|
||||
|
||||
dprintk( 1, "%s\n", __func__);
|
||||
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
|
||||
@ -1086,18 +1219,28 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
|
||||
|
||||
/* dvb stuff */
|
||||
printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
|
||||
videobuf_queue_sg_init(&dev->dvb.dvbq, &dvb_qops,
|
||||
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", __func__, i);
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
err = dvb_register(dev);
|
||||
if (err != 0)
|
||||
printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
|
||||
core->name, err);
|
||||
|
||||
fail_core:
|
||||
fail_core:
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1105,9 +1248,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
|
||||
{
|
||||
struct cx8802_dev *dev = drv->core->dvbdev;
|
||||
|
||||
/* dvb */
|
||||
if (dev->dvb.frontend)
|
||||
videobuf_dvb_unregister(&dev->dvb);
|
||||
videobuf_dvb_unregister_bus(&dev->frontends);
|
||||
|
||||
vp3054_i2c_remove(dev);
|
||||
|
||||
|
@ -116,18 +116,25 @@ static int detach_inform(struct i2c_client *client)
|
||||
|
||||
void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct videobuf_dvb_frontends *f = &core->dvbdev->frontends;
|
||||
struct videobuf_dvb_frontend *fe = NULL;
|
||||
if (0 != core->i2c_rc)
|
||||
return;
|
||||
|
||||
#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
|
||||
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
|
||||
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
|
||||
if (core->dvbdev && f) {
|
||||
if(f->gate <= 1) /* undefined or fe0 */
|
||||
fe = videobuf_dvb_get_frontend(f, 1);
|
||||
else
|
||||
fe = videobuf_dvb_get_frontend(f, f->gate);
|
||||
|
||||
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 1);
|
||||
|
||||
i2c_clients_command(&core->i2c_adap, cmd, arg);
|
||||
|
||||
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
|
||||
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 0);
|
||||
} else
|
||||
#endif
|
||||
i2c_clients_command(&core->i2c_adap, cmd, arg);
|
||||
|
@ -768,7 +768,8 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
|
||||
{
|
||||
struct cx8802_dev *dev;
|
||||
struct cx88_core *core;
|
||||
int err;
|
||||
struct videobuf_dvb_frontend *demod;
|
||||
int err,i;
|
||||
|
||||
/* general setup */
|
||||
core = cx88_core_get(pci_dev);
|
||||
@ -781,6 +782,11 @@ 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", __func__, err);
|
||||
goto fail_core;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
|
||||
if (NULL == dev)
|
||||
@ -795,6 +801,20 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
|
||||
INIT_LIST_HEAD(&dev->drvlist);
|
||||
list_add_tail(&dev->devlist,&cx8802_devlist);
|
||||
|
||||
mutex_init(&dev->frontends.lock);
|
||||
INIT_LIST_HEAD(&dev->frontends.felist);
|
||||
|
||||
printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, core->board.num_frontends);
|
||||
|
||||
for (i = 1; i <= core->board.num_frontends; i++) {
|
||||
demod = videobuf_dvb_alloc_frontend(&dev->frontends, i);
|
||||
if(demod == NULL) {
|
||||
printk(KERN_ERR "%s() failed to alloc\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto fail_free;
|
||||
}
|
||||
}
|
||||
|
||||
/* Maintain a reference so cx88-video can query the 8802 device. */
|
||||
core->dvbdev = dev;
|
||||
|
||||
|
@ -767,6 +767,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",
|
||||
@ -895,6 +903,9 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WW_I2SADC:
|
||||
/* DO NOTHING */
|
||||
break;
|
||||
}
|
||||
|
||||
if (UNSET != ctl) {
|
||||
|
@ -426,24 +426,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 */
|
||||
@ -454,9 +437,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;
|
||||
@ -832,9 +825,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();
|
||||
|
@ -247,7 +247,7 @@ struct cx88_input {
|
||||
enum cx88_itype type;
|
||||
u32 gpio0, gpio1, gpio2, gpio3;
|
||||
unsigned int vmux:2;
|
||||
unsigned int audioroute:2;
|
||||
unsigned int audioroute:4;
|
||||
};
|
||||
|
||||
struct cx88_board {
|
||||
@ -261,6 +261,7 @@ struct cx88_board {
|
||||
struct cx88_input radio;
|
||||
enum cx88_board_type mpeg;
|
||||
unsigned int audio_chip;
|
||||
int num_frontends;
|
||||
};
|
||||
|
||||
struct cx88_subid {
|
||||
@ -356,6 +357,7 @@ struct cx88_core {
|
||||
struct cx8802_dev *dvbdev;
|
||||
enum cx88_board_type active_type_id;
|
||||
int active_ref;
|
||||
int active_fe_id;
|
||||
};
|
||||
|
||||
struct cx8800_dev;
|
||||
@ -490,7 +492,7 @@ struct cx8802_dev {
|
||||
|
||||
#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
|
||||
/* for dvb only */
|
||||
struct videobuf_dvb dvb;
|
||||
struct videobuf_dvb_frontends frontends;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || \
|
||||
@ -628,6 +630,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);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define MODULE_NAME "gspca"
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/sched.h>
|
||||
@ -403,7 +404,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
|
||||
unsigned int i;
|
||||
|
||||
PDEBUG(D_STREAM, "kill transfer");
|
||||
for (i = 0; i < MAX_NURBS; ++i) {
|
||||
for (i = 0; i < MAX_NURBS; i++) {
|
||||
urb = gspca_dev->urb[i];
|
||||
if (urb == NULL)
|
||||
break;
|
||||
|
@ -2,7 +2,6 @@
|
||||
#define GSPCAV2_H
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* USB Driver for ALi m5602 based webcams
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -25,33 +25,6 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#undef PDEBUG
|
||||
#undef info
|
||||
#undef err
|
||||
|
||||
#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
|
||||
format "\n" , ## arg)
|
||||
#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
|
||||
format "\n" , ## arg)
|
||||
|
||||
/* Debug parameters */
|
||||
#define DBG_INIT 0x1
|
||||
#define DBG_PROBE 0x2
|
||||
#define DBG_V4L2 0x4
|
||||
#define DBG_TRACE 0x8
|
||||
#define DBG_DATA 0x10
|
||||
#define DBG_V4L2_CID 0x20
|
||||
#define DBG_GSPCA 0x40
|
||||
|
||||
#define PDEBUG(level, fmt, args...) \
|
||||
do { \
|
||||
if (m5602_debug & level) \
|
||||
info("[%s:%d] " fmt, __func__, __LINE__ , \
|
||||
## args); \
|
||||
} while (0)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define M5602_XB_SENSOR_TYPE 0x00
|
||||
#define M5602_XB_SENSOR_CTRL 0x01
|
||||
#define M5602_XB_LINE_OF_FRAME_H 0x02
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
/*
|
||||
* USB Driver for ALi m5602 based webcams
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -26,7 +26,6 @@
|
||||
int force_sensor;
|
||||
int dump_bridge;
|
||||
int dump_sensor;
|
||||
unsigned int m5602_debug;
|
||||
|
||||
static const __devinitdata struct usb_device_id m5602_table[] = {
|
||||
{USB_DEVICE(0x0402, 0x5602)},
|
||||
@ -48,7 +47,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
|
||||
1, M5602_URB_MSG_TIMEOUT);
|
||||
*i2c_data = buf[0];
|
||||
|
||||
PDEBUG(DBG_TRACE, "Reading bridge register 0x%x containing 0x%x",
|
||||
PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x",
|
||||
address, *i2c_data);
|
||||
|
||||
/* usb_control_msg(...) returns the number of bytes sent upon success,
|
||||
@ -63,7 +62,7 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
|
||||
struct usb_device *udev = sd->gspca_dev.dev;
|
||||
__u8 *buf = sd->gspca_dev.usb_buf;
|
||||
|
||||
PDEBUG(DBG_TRACE, "Writing bridge register 0x%x with 0x%x",
|
||||
PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x",
|
||||
address, i2c_data);
|
||||
|
||||
memcpy(buf, bridge_urb_skeleton,
|
||||
@ -91,7 +90,8 @@ static void m5602_dump_bridge(struct sd *sd)
|
||||
m5602_read_bridge(sd, i, &val);
|
||||
info("ALi m5602 address 0x%x contains 0x%x", i, val);
|
||||
}
|
||||
info("Warning: The camera probably won't work until it's power cycled");
|
||||
info("Warning: The ALi m5602 webcam probably won't work "
|
||||
"until it's power cycled");
|
||||
}
|
||||
|
||||
static int m5602_probe_sensor(struct sd *sd)
|
||||
@ -135,7 +135,7 @@ static int m5602_init(struct gspca_dev *gspca_dev)
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_TRACE, "Initializing ALi m5602 webcam");
|
||||
PDEBUG(D_CONF, "Initializing ALi m5602 webcam");
|
||||
/* Run the init sequence */
|
||||
err = sd->sensor->init(sd);
|
||||
|
||||
@ -146,16 +146,18 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
__u8 *buf = sd->gspca_dev.usb_buf;
|
||||
int err;
|
||||
|
||||
/* Send start command to the camera */
|
||||
const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
|
||||
memcpy(buf, buffer, sizeof(buffer));
|
||||
usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
|
||||
0x04, 0x40, 0x19, 0x0000, buf,
|
||||
4, M5602_URB_MSG_TIMEOUT);
|
||||
err = usb_control_msg(gspca_dev->dev,
|
||||
usb_sndctrlpipe(gspca_dev->dev, 0),
|
||||
0x04, 0x40, 0x19, 0x0000, buf,
|
||||
4, M5602_URB_MSG_TIMEOUT);
|
||||
|
||||
PDEBUG(DBG_V4L2, "Transfer started");
|
||||
return 0;
|
||||
PDEBUG(D_STREAM, "Transfer started");
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
static void m5602_urb_complete(struct gspca_dev *gspca_dev,
|
||||
@ -165,14 +167,14 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
if (len < 6) {
|
||||
PDEBUG(DBG_DATA, "Packet is less than 6 bytes");
|
||||
PDEBUG(D_PACK, "Packet is less than 6 bytes");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Frame delimiter: ff xx xx xx ff ff */
|
||||
if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
|
||||
data[2] != sd->frame_id) {
|
||||
PDEBUG(DBG_DATA, "Frame delimiter detected");
|
||||
PDEBUG(D_FRAM, "Frame delimiter detected");
|
||||
sd->frame_id = data[2];
|
||||
|
||||
/* Remove the extra fluff appended on each header */
|
||||
@ -187,7 +189,7 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
|
||||
/* Create a new frame */
|
||||
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
|
||||
|
||||
PDEBUG(DBG_V4L2, "Starting new frame %d",
|
||||
PDEBUG(D_FRAM, "Starting new frame %d",
|
||||
sd->frame_count);
|
||||
|
||||
} else {
|
||||
@ -198,7 +200,7 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
|
||||
len -= 4;
|
||||
|
||||
if (cur_frame_len + len <= frame->v4l2_buf.length) {
|
||||
PDEBUG(DBG_DATA, "Continuing frame %d copying %d bytes",
|
||||
PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
|
||||
sd->frame_count, len);
|
||||
|
||||
gspca_frame_add(gspca_dev, INTER_PACKET, frame,
|
||||
@ -234,8 +236,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
|
||||
struct cam *cam;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_GSPCA, "m5602_configure start");
|
||||
|
||||
cam = &gspca_dev->cam;
|
||||
cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
|
||||
sd->desc = &sd_desc;
|
||||
@ -248,11 +248,10 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
PDEBUG(DBG_GSPCA, "m5602_configure end");
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
PDEBUG(DBG_GSPCA, "m5602_configure failed");
|
||||
PDEBUG(D_ERR, "ALi m5602 webcam failed");
|
||||
cam->cam_mode = NULL;
|
||||
cam->nmodes = 0;
|
||||
|
||||
@ -282,13 +281,13 @@ static int __init mod_m5602_init(void)
|
||||
{
|
||||
if (usb_register(&sd_driver) < 0)
|
||||
return -1;
|
||||
PDEBUG(D_PROBE, "m5602 module registered");
|
||||
PDEBUG(D_PROBE, "registered");
|
||||
return 0;
|
||||
}
|
||||
static void __exit mod_m5602_exit(void)
|
||||
{
|
||||
usb_deregister(&sd_driver);
|
||||
PDEBUG(D_PROBE, "m5602 module deregistered");
|
||||
PDEBUG(D_PROBE, "deregistered");
|
||||
}
|
||||
|
||||
module_init(mod_m5602_init);
|
||||
@ -297,9 +296,6 @@ module_exit(mod_m5602_exit);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
module_param_named(debug, m5602_debug, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "toggles debug on/off");
|
||||
|
||||
module_param(force_sensor, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(force_sensor,
|
||||
"force detection of sensor, "
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the mt9m111 sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -107,7 +107,7 @@ int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
|
||||
data, 2);
|
||||
*val = data[0] & MT9M111_RMB_MIRROR_ROWS;
|
||||
PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
|
||||
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -118,7 +118,7 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 data[2] = {0x00, 0x00};
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
|
||||
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
|
||||
|
||||
/* Set the correct page map */
|
||||
err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
|
||||
@ -145,7 +145,7 @@ int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
|
||||
data, 2);
|
||||
*val = data[0] & MT9M111_RMB_MIRROR_COLS;
|
||||
PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
|
||||
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -156,7 +156,7 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 data[2] = {0x00, 0x00};
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
|
||||
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
|
||||
|
||||
/* Set the correct page map */
|
||||
err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
|
||||
@ -188,7 +188,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
((tmp & (1 << 8)) * 2) |
|
||||
(tmp & 0x7f);
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read gain %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -222,7 +222,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
|
||||
data[1] = (tmp & 0xff00) >> 8;
|
||||
data[0] = (tmp & 0xff);
|
||||
PDEBUG(DBG_V4L2_CID, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
|
||||
PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
|
||||
data[1], data[0]);
|
||||
|
||||
err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
|
||||
@ -257,7 +257,7 @@ int mt9m111_read_sensor(struct sd *sd, const u8 address,
|
||||
for (i = 0; i < len && !err; i++) {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
|
||||
|
||||
PDEBUG(DBG_TRACE, "Reading sensor register "
|
||||
PDEBUG(D_CONF, "Reading sensor register "
|
||||
"0x%x contains 0x%x ", address, *i2c_data);
|
||||
}
|
||||
out:
|
||||
@ -290,7 +290,7 @@ int mt9m111_write_sensor(struct sd *sd, const u8 address,
|
||||
memcpy(p, sensor_urb_skeleton + 16, 4);
|
||||
p[3] = i2c_data[i];
|
||||
p += 4;
|
||||
PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
|
||||
PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
|
||||
address, i2c_data[i]);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the mt9m111 sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -82,7 +82,6 @@
|
||||
/* Kernel module parameters */
|
||||
extern int force_sensor;
|
||||
extern int dump_sensor;
|
||||
extern unsigned int m5602_debug;
|
||||
|
||||
int mt9m111_probe(struct sd *sd);
|
||||
int mt9m111_init(struct sd *sd);
|
||||
@ -152,8 +151,8 @@ static struct m5602_sensor mt9m111 = {
|
||||
.default_value = DEFAULT_GAIN,
|
||||
.flags = V4L2_CTRL_FLAG_SLIDER
|
||||
},
|
||||
.set = mt9m111_set_hflip,
|
||||
.get = mt9m111_get_hflip
|
||||
.set = mt9m111_set_gain,
|
||||
.get = mt9m111_get_gain
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the ov9650 sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -40,7 +40,7 @@ int ov9650_read_sensor(struct sd *sd, const u8 address,
|
||||
for (i = 0; i < len; i++) {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
|
||||
|
||||
PDEBUG(DBG_TRACE, "Reading sensor register "
|
||||
PDEBUG(D_CONF, "Reading sensor register "
|
||||
"0x%x containing 0x%x ", address, *i2c_data);
|
||||
}
|
||||
return (err < 0) ? err : 0;
|
||||
@ -72,7 +72,7 @@ int ov9650_write_sensor(struct sd *sd, const u8 address,
|
||||
memcpy(p, sensor_urb_skeleton + 16, 4);
|
||||
p[3] = i2c_data[i];
|
||||
p += 4;
|
||||
PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
|
||||
PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
|
||||
address, i2c_data[i]);
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
goto out;
|
||||
*val |= (i2c_data & 0x3f) << 10;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
|
||||
PDEBUG(D_V4L2, "Read exposure %d", *val);
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -210,7 +210,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set exposure to %d",
|
||||
PDEBUG(D_V4L2, "Set exposure to %d",
|
||||
val & 0xffff);
|
||||
|
||||
/* The 6 MSBs */
|
||||
@ -246,7 +246,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
|
||||
*val |= i2c_data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read gain %d", *val);
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
|
||||
*val = i2c_data;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read red gain %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -291,7 +291,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set red gain to %d",
|
||||
PDEBUG(D_V4L2, "Set red gain to %d",
|
||||
val & 0xff);
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
@ -309,7 +309,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
|
||||
*val = i2c_data;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read blue gain %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -320,7 +320,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set blue gain to %d",
|
||||
PDEBUG(D_V4L2, "Set blue gain to %d",
|
||||
val & 0xff);
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
@ -340,7 +340,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
*val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
|
||||
else
|
||||
*val = (i2c_data & OV9650_HFLIP) >> 5;
|
||||
PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
|
||||
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -351,7 +351,7 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d", val);
|
||||
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
|
||||
err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -379,7 +379,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
*val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
|
||||
else
|
||||
*val = (i2c_data & 0x10) >> 4;
|
||||
PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
|
||||
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -390,7 +390,7 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
|
||||
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
|
||||
err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -420,7 +420,7 @@ int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
|
||||
*val |= i2c_data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read gain %d", *val);
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -431,7 +431,7 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set gain to %d", val & 0x3ff);
|
||||
PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff);
|
||||
|
||||
/* Read the OV9650_VREF register first to avoid
|
||||
corrupting the VREF high and low bits */
|
||||
@ -461,7 +461,7 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
|
||||
*val = (i2c_data & OV9650_AWB_EN) >> 1;
|
||||
PDEBUG(DBG_V4L2_CID, "Read auto white balance %d", *val);
|
||||
PDEBUG(D_V4L2, "Read auto white balance %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -472,7 +472,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set auto white balance to %d", val);
|
||||
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
|
||||
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -491,7 +491,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
|
||||
*val = (i2c_data & OV9650_AGC_EN) >> 2;
|
||||
PDEBUG(DBG_V4L2_CID, "Read auto gain control %d", *val);
|
||||
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -502,7 +502,7 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set auto gain control to %d", val);
|
||||
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
|
||||
err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the ov9650 sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -121,7 +121,6 @@
|
||||
/* Kernel module parameters */
|
||||
extern int force_sensor;
|
||||
extern int dump_sensor;
|
||||
extern unsigned int m5602_debug;
|
||||
|
||||
int ov9650_probe(struct sd *sd);
|
||||
int ov9650_init(struct sd *sd);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the po1030 sensor
|
||||
*
|
||||
* Copyright (c) 2008 Erik Andren
|
||||
* Copyright (c) 2008 Erik Andrén
|
||||
* Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -82,7 +82,7 @@ int po1030_read_sensor(struct sd *sd, const u8 address,
|
||||
for (i = 0; i < len; i++) {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
|
||||
|
||||
PDEBUG(DBG_TRACE, "Reading sensor register "
|
||||
PDEBUG(D_CONF, "Reading sensor register "
|
||||
"0x%x containing 0x%x ", address, *i2c_data);
|
||||
}
|
||||
return (err < 0) ? err : 0;
|
||||
@ -112,7 +112,7 @@ int po1030_write_sensor(struct sd *sd, const u8 address,
|
||||
memcpy(p, sensor_urb_skeleton + 16, 4);
|
||||
p[3] = i2c_data[i];
|
||||
p += 4;
|
||||
PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
|
||||
PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
|
||||
address, i2c_data[i]);
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
&i2c_data, 1);
|
||||
*val |= i2c_data;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Exposure read as %d", *val);
|
||||
PDEBUG(D_V4L2, "Exposure read as %d", *val);
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -196,10 +196,10 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_V4L2, "Set exposure to %d", val & 0xffff);
|
||||
PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
|
||||
|
||||
i2c_data = ((val & 0xff00) >> 8);
|
||||
PDEBUG(DBG_V4L2, "Set exposure to high byte to 0x%x",
|
||||
PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
|
||||
i2c_data);
|
||||
|
||||
err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
|
||||
@ -208,7 +208,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
|
||||
goto out;
|
||||
|
||||
i2c_data = (val & 0xff);
|
||||
PDEBUG(DBG_V4L2, "Set exposure to low byte to 0x%x",
|
||||
PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
|
||||
i2c_data);
|
||||
err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
|
||||
&i2c_data, 1);
|
||||
@ -226,7 +226,71 @@ int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
|
||||
&i2c_data, 1);
|
||||
*val = i2c_data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read global gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read global gain %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
err = po1030_read_sensor(sd, PO1030_REG_CONTROL2,
|
||||
&i2c_data, 1);
|
||||
|
||||
*val = (i2c_data >> 7) & 0x01 ;
|
||||
|
||||
PDEBUG(D_V4L2, "Read hflip %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
PDEBUG(D_V4L2, "Set hflip %d", val);
|
||||
|
||||
i2c_data = (val & 0x01) << 7;
|
||||
|
||||
err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
|
||||
&i2c_data, 1);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
|
||||
&i2c_data, 1);
|
||||
|
||||
*val = (i2c_data >> 6) & 0x01;
|
||||
|
||||
PDEBUG(D_V4L2, "Read vflip %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
PDEBUG(D_V4L2, "Set vflip %d", val);
|
||||
|
||||
i2c_data = (val & 0x01) << 6;
|
||||
|
||||
err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
|
||||
&i2c_data, 1);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -238,7 +302,7 @@ int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
int err;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
PDEBUG(DBG_V4L2, "Set global gain to %d", i2c_data);
|
||||
PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
|
||||
err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
|
||||
&i2c_data, 1);
|
||||
return (err < 0) ? err : 0;
|
||||
@ -253,7 +317,7 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
|
||||
&i2c_data, 1);
|
||||
*val = i2c_data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read red gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read red gain %d", *val);
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
@ -264,7 +328,7 @@ int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
int err;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
PDEBUG(DBG_V4L2, "Set red gain to %d", i2c_data);
|
||||
PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
|
||||
err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
|
||||
&i2c_data, 1);
|
||||
return (err < 0) ? err : 0;
|
||||
@ -279,7 +343,7 @@ int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
|
||||
&i2c_data, 1);
|
||||
*val = i2c_data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read blue gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read blue gain %d", *val);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -290,7 +354,7 @@ int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
i2c_data = val & 0xff;
|
||||
PDEBUG(DBG_V4L2, "Set blue gain to %d", i2c_data);
|
||||
PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
|
||||
err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
|
||||
&i2c_data, 1);
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
/*
|
||||
* Driver for the po1030 sensor.
|
||||
* This is probably a pixel plus sensor but we haven't identified it yet
|
||||
*
|
||||
* Copyright (c) 2008 Erik Andren
|
||||
* Copyright (c) 2008 Erik Andrén
|
||||
* Copyright (c) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (c) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -109,10 +108,13 @@
|
||||
#define PO1030_REG_YCONTRAST 0x74
|
||||
#define PO1030_REG_YSATURATION 0x75
|
||||
|
||||
#define PO1030_HFLIP (1 << 7)
|
||||
#define PO1030_VFLIP (1 << 6)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define PO1030_GLOBAL_GAIN_DEFAULT 0x12
|
||||
#define PO1030_EXPOSURE_DEFAULT 0xf0ff
|
||||
#define PO1030_EXPOSURE_DEFAULT 0x0085
|
||||
#define PO1030_BLUE_GAIN_DEFAULT 0x40
|
||||
#define PO1030_RED_GAIN_DEFAULT 0x40
|
||||
|
||||
@ -121,7 +123,6 @@
|
||||
/* Kernel module parameters */
|
||||
extern int force_sensor;
|
||||
extern int dump_sensor;
|
||||
extern unsigned int m5602_debug;
|
||||
|
||||
int po1030_probe(struct sd *sd);
|
||||
int po1030_init(struct sd *sd);
|
||||
@ -142,6 +143,10 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
|
||||
static struct m5602_sensor po1030 = {
|
||||
.name = "PO1030",
|
||||
@ -152,7 +157,7 @@ static struct m5602_sensor po1030 = {
|
||||
.init = po1030_init,
|
||||
.power_down = po1030_power_down,
|
||||
|
||||
.nctrls = 4,
|
||||
.nctrls = 6,
|
||||
.ctrls = {
|
||||
{
|
||||
{
|
||||
@ -160,7 +165,7 @@ static struct m5602_sensor po1030 = {
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.maximum = 0x4f,
|
||||
.step = 0x1,
|
||||
.default_value = PO1030_GLOBAL_GAIN_DEFAULT,
|
||||
.flags = V4L2_CTRL_FLAG_SLIDER
|
||||
@ -173,7 +178,7 @@ static struct m5602_sensor po1030 = {
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "exposure",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xffff,
|
||||
.maximum = 0x02ff,
|
||||
.step = 0x1,
|
||||
.default_value = PO1030_EXPOSURE_DEFAULT,
|
||||
.flags = V4L2_CTRL_FLAG_SLIDER
|
||||
@ -206,8 +211,33 @@ static struct m5602_sensor po1030 = {
|
||||
},
|
||||
.set = po1030_set_blue_balance,
|
||||
.get = po1030_get_blue_balance
|
||||
}, {
|
||||
{
|
||||
.id = V4L2_CID_HFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "horizontal flip",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
.set = po1030_set_hflip,
|
||||
.get = po1030_get_hflip
|
||||
}, {
|
||||
{
|
||||
.id = V4L2_CID_VFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "vertical flip",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
.set = po1030_set_vflip,
|
||||
.get = po1030_get_vflip
|
||||
}
|
||||
},
|
||||
|
||||
.nmodes = 1,
|
||||
.modes = {
|
||||
{
|
||||
@ -381,7 +411,7 @@ static const unsigned char init_po1030[][4] =
|
||||
|
||||
/* Set the y window to 1 */
|
||||
{SENSOR, PO1030_REG_WINDOWY_H, 0x00},
|
||||
{SENSOR, PO1030_REG_WINDOWX_L, 0x01},
|
||||
{SENSOR, PO1030_REG_WINDOWY_L, 0x01},
|
||||
|
||||
{SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
|
||||
{SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the s5k4aa sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -117,7 +117,7 @@ int s5k4aa_read_sensor(struct sd *sd, const u8 address,
|
||||
for (i = 0; (i < len) & !err; i++) {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
|
||||
|
||||
PDEBUG(DBG_TRACE, "Reading sensor register "
|
||||
PDEBUG(D_CONF, "Reading sensor register "
|
||||
"0x%x containing 0x%x ", address, *i2c_data);
|
||||
}
|
||||
out:
|
||||
@ -150,7 +150,7 @@ int s5k4aa_write_sensor(struct sd *sd, const u8 address,
|
||||
memcpy(p, sensor_urb_skeleton + 16, 4);
|
||||
p[3] = i2c_data[i];
|
||||
p += 4;
|
||||
PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
|
||||
PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
|
||||
address, i2c_data[i]);
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
*val = data << 8;
|
||||
err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
|
||||
*val |= data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read exposure %d", *val);
|
||||
PDEBUG(D_V4L2, "Read exposure %d", *val);
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -259,7 +259,7 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set exposure to %d", val);
|
||||
PDEBUG(D_V4L2, "Set exposure to %d", val);
|
||||
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -285,7 +285,7 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
*val = (data & S5K4AA_RM_V_FLIP) >> 7;
|
||||
PDEBUG(DBG_V4L2_CID, "Read vertical flip %d", *val);
|
||||
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
|
||||
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
@ -297,7 +297,7 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set vertical flip to %d", val);
|
||||
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
|
||||
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -341,7 +341,7 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
*val = (data & S5K4AA_RM_H_FLIP) >> 6;
|
||||
PDEBUG(DBG_V4L2_CID, "Read horizontal flip %d", *val);
|
||||
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
@ -352,7 +352,7 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set horizontal flip to %d",
|
||||
PDEBUG(D_V4L2, "Set horizontal flip to %d",
|
||||
val);
|
||||
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
@ -397,7 +397,7 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
|
||||
err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
|
||||
*val = data;
|
||||
PDEBUG(DBG_V4L2_CID, "Read gain %d", *val);
|
||||
PDEBUG(D_V4L2, "Read gain %d", *val);
|
||||
|
||||
out:
|
||||
return (err < 0) ? err : 0;
|
||||
@ -409,7 +409,7 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
PDEBUG(DBG_V4L2_CID, "Set gain to %d", val);
|
||||
PDEBUG(D_V4L2, "Set gain to %d", val);
|
||||
err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the s5k4aa sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -63,7 +63,6 @@
|
||||
/* Kernel module parameters */
|
||||
extern int force_sensor;
|
||||
extern int dump_sensor;
|
||||
extern unsigned int m5602_debug;
|
||||
|
||||
int s5k4aa_probe(struct sd *sd);
|
||||
int s5k4aa_init(struct sd *sd);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the s5k83a sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -101,7 +101,7 @@ int s5k83a_read_sensor(struct sd *sd, const u8 address,
|
||||
for (i = 0; i < len && !len; i++) {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
|
||||
|
||||
PDEBUG(DBG_TRACE, "Reading sensor register "
|
||||
PDEBUG(D_CONF, "Reading sensor register "
|
||||
"0x%x containing 0x%x ", address, *i2c_data);
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ int s5k83a_write_sensor(struct sd *sd, const u8 address,
|
||||
memcpy(p, sensor_urb_skeleton + 16, 4);
|
||||
p[3] = i2c_data[i];
|
||||
p += 4;
|
||||
PDEBUG(DBG_TRACE, "Writing sensor register 0x%x with 0x%x",
|
||||
PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
|
||||
address, i2c_data[i]);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Driver for the s5k83a sensor
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
@ -41,8 +41,6 @@
|
||||
/* Kernel module parameters */
|
||||
extern int force_sensor;
|
||||
extern int dump_sensor;
|
||||
extern unsigned int m5602_debug;
|
||||
|
||||
|
||||
int s5k83a_probe(struct sd *sd);
|
||||
int s5k83a_init(struct sd *sd);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* USB Driver for ALi m5602 based webcams
|
||||
*
|
||||
* Copyright (C) 2008 Erik Andren
|
||||
* Copyright (C) 2008 Erik Andrén
|
||||
* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
|
||||
* Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
|
||||
*
|
||||
|
@ -50,7 +50,7 @@ struct sd {
|
||||
|
||||
__u8 sensor;
|
||||
#define SENSOR_TAS5130A 0
|
||||
#define SENSOR_OTHER 1
|
||||
#define SENSOR_OM6802 1
|
||||
};
|
||||
|
||||
/* V4L2 controls supported by the driver */
|
||||
@ -188,7 +188,7 @@ static struct ctrl sd_ctrls[] = {
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 1,
|
||||
.default_value = 0,
|
||||
},
|
||||
.set = sd_setwhitebalance,
|
||||
.get = sd_getwhitebalance
|
||||
@ -261,6 +261,59 @@ static struct v4l2_pix_format vga_mode_t16[] = {
|
||||
.priv = 0},
|
||||
};
|
||||
|
||||
/* sensor specific data */
|
||||
struct additional_sensor_data {
|
||||
const __u8 data1[20];
|
||||
const __u8 data2[18];
|
||||
const __u8 data3[18];
|
||||
const __u8 data4[4];
|
||||
const __u8 data5[6];
|
||||
const __u8 stream[4];
|
||||
};
|
||||
|
||||
const static struct additional_sensor_data sensor_data[] = {
|
||||
{ /* TAS5130A */
|
||||
.data1 =
|
||||
{0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10,
|
||||
0xd4, 0xbb, 0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
|
||||
0xd8, 0xc8, 0xd9, 0xfc},
|
||||
.data2 =
|
||||
{0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60,
|
||||
0xe4, 0xa8, 0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
|
||||
0xe8, 0xe0},
|
||||
.data3 =
|
||||
{0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60,
|
||||
0xcb, 0xa8, 0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
|
||||
0xcf, 0xe0},
|
||||
.data4 = /* Freq (50/60Hz). Splitted for test purpose */
|
||||
{0x66, 0x00, 0xa8, 0xe8},
|
||||
.data5 =
|
||||
{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
|
||||
.stream =
|
||||
{0x0b, 0x04, 0x0a, 0x40},
|
||||
},
|
||||
{ /* OM6802 */
|
||||
.data1 =
|
||||
{0xd0, 0xc2, 0xd1, 0x28, 0xd2, 0x0f, 0xd3, 0x22,
|
||||
0xd4, 0xcd, 0xd5, 0x27, 0xd6, 0x2c, 0xd7, 0x06,
|
||||
0xd8, 0xb3, 0xd9, 0xfc},
|
||||
.data2 =
|
||||
{0xe0, 0x80, 0xe1, 0xff, 0xe2, 0xff, 0xe3, 0x80,
|
||||
0xe4, 0xff, 0xe5, 0xff, 0xe6, 0x80, 0xe7, 0xff,
|
||||
0xe8, 0xff},
|
||||
.data3 =
|
||||
{0xc7, 0x80, 0xc8, 0xff, 0xc9, 0xff, 0xca, 0x80,
|
||||
0xcb, 0xff, 0xcc, 0xff, 0xcd, 0x80, 0xce, 0xff,
|
||||
0xcf, 0xff},
|
||||
.data4 = /*Freq (50/60Hz). Splitted for test purpose */
|
||||
{0x66, 0xca, 0xa8, 0xf0 },
|
||||
.data5 = /* this could be removed later */
|
||||
{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
|
||||
.stream =
|
||||
{0x0b, 0x04, 0x0a, 0x78},
|
||||
}
|
||||
};
|
||||
|
||||
#define MAX_EFFECTS 7
|
||||
/* easily done by soft, this table could be removed,
|
||||
* i keep it here just in case */
|
||||
@ -365,6 +418,8 @@ static const __u8 tas5130a_sensor_init[][8] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static __u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
|
||||
|
||||
/* read 1 byte */
|
||||
static int reg_r(struct gspca_dev *gspca_dev,
|
||||
__u16 index)
|
||||
@ -385,12 +440,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
|
||||
usb_control_msg(gspca_dev->dev,
|
||||
usb_sndctrlpipe(gspca_dev->dev, 0),
|
||||
0,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
0, index,
|
||||
NULL, 0, 500);
|
||||
}
|
||||
|
||||
static void i2c_w(struct gspca_dev *gspca_dev,
|
||||
static void reg_w_buf(struct gspca_dev *gspca_dev,
|
||||
const __u8 *buffer, __u16 len)
|
||||
{
|
||||
if (len <= USB_BUF_SZ) {
|
||||
@ -398,7 +453,7 @@ static void i2c_w(struct gspca_dev *gspca_dev,
|
||||
usb_control_msg(gspca_dev->dev,
|
||||
usb_sndctrlpipe(gspca_dev->dev, 0),
|
||||
0,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
0x01, 0,
|
||||
gspca_dev->usb_buf, len, 500);
|
||||
} else {
|
||||
@ -409,14 +464,15 @@ static void i2c_w(struct gspca_dev *gspca_dev,
|
||||
usb_control_msg(gspca_dev->dev,
|
||||
usb_sndctrlpipe(gspca_dev->dev, 0),
|
||||
0,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
0x01, 0,
|
||||
tmpbuf, len, 500);
|
||||
kfree(tmpbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void other_sensor_init(struct gspca_dev *gspca_dev)
|
||||
/* Reported as OM6802*/
|
||||
static void om6802_sensor_init(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
int i;
|
||||
const __u8 *p;
|
||||
@ -436,19 +492,32 @@ static void other_sensor_init(struct gspca_dev *gspca_dev)
|
||||
0x90, 0x24,
|
||||
0x91, 0xb2,
|
||||
0x82, 0x32,
|
||||
0xfd, 0x00,
|
||||
0xfd, 0x01,
|
||||
0xfd, 0x41,
|
||||
0x00 /* table end */
|
||||
};
|
||||
|
||||
reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
|
||||
msleep(5);
|
||||
i = 4;
|
||||
while (--i < 0) {
|
||||
byte = reg_r(gspca_dev, 0x0060);
|
||||
if (!(byte & 0x01))
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
byte = reg_r(gspca_dev, 0x0063);
|
||||
if (byte != 0x17) {
|
||||
err("Bad sensor reset %02x", byte);
|
||||
/* continue? */
|
||||
}
|
||||
|
||||
p = sensor_init;
|
||||
while (*p != 0) {
|
||||
val[1] = *p++;
|
||||
val[3] = *p++;
|
||||
if (*p == 0)
|
||||
reg_w(gspca_dev, 0x3c80);
|
||||
i2c_w(gspca_dev, val, sizeof val);
|
||||
reg_w_buf(gspca_dev, val, sizeof val);
|
||||
i = 4;
|
||||
while (--i >= 0) {
|
||||
msleep(15);
|
||||
@ -457,7 +526,8 @@ static void other_sensor_init(struct gspca_dev *gspca_dev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
reg_w(gspca_dev, 0x3c80);
|
||||
msleep(15);
|
||||
reg_w(gspca_dev, 0x3c80);
|
||||
}
|
||||
|
||||
/* this function is called at probe time */
|
||||
@ -485,12 +555,75 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setbrightness(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
unsigned int brightness;
|
||||
__u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
|
||||
|
||||
brightness = sd->brightness;
|
||||
if (brightness < 7) {
|
||||
set6[1] = 0x26;
|
||||
set6[3] = 0x70 - brightness * 0x10;
|
||||
} else {
|
||||
set6[3] = 0x00 + ((brightness - 7) * 0x10);
|
||||
}
|
||||
|
||||
reg_w_buf(gspca_dev, set6, sizeof set6);
|
||||
}
|
||||
|
||||
static void setcontrast(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
unsigned int contrast = sd->contrast;
|
||||
__u16 reg_to_write;
|
||||
|
||||
if (contrast < 7)
|
||||
reg_to_write = 0x8ea9 - contrast * 0x200;
|
||||
else
|
||||
reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
|
||||
|
||||
reg_w(gspca_dev, reg_to_write);
|
||||
}
|
||||
|
||||
static void setcolors(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
__u16 reg_to_write;
|
||||
|
||||
reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */
|
||||
reg_w(gspca_dev, reg_to_write);
|
||||
}
|
||||
|
||||
static void setgamma(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
|
||||
i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
|
||||
reg_w_buf(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
|
||||
}
|
||||
|
||||
static void setwhitebalance(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
__u8 white_balance[8] =
|
||||
{0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38};
|
||||
|
||||
if (sd->whitebalance)
|
||||
white_balance[7] = 0x3c;
|
||||
|
||||
reg_w_buf(gspca_dev, white_balance, sizeof white_balance);
|
||||
}
|
||||
|
||||
static void setsharpness(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
__u16 reg_to_write;
|
||||
|
||||
reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
|
||||
|
||||
reg_w(gspca_dev, reg_to_write);
|
||||
}
|
||||
|
||||
/* this function is called at probe and resume time */
|
||||
@ -511,8 +644,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
|
||||
{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
|
||||
static const __u8 n2[] =
|
||||
{0x08, 0x00};
|
||||
static const __u8 nset[] =
|
||||
{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
|
||||
static const __u8 n3[] =
|
||||
{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
|
||||
static const __u8 n4[] =
|
||||
@ -525,51 +656,29 @@ static int sd_init(struct gspca_dev *gspca_dev)
|
||||
0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
|
||||
0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
|
||||
0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
|
||||
static const __u8 nset4[] = {
|
||||
0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
|
||||
0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
|
||||
0xe8, 0xe0
|
||||
};
|
||||
/* ojo puede ser 0xe6 en vez de 0xe9 */
|
||||
static const __u8 nset2[] = {
|
||||
0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
|
||||
0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
|
||||
0xd8, 0xc8, 0xd9, 0xfc
|
||||
};
|
||||
static const __u8 missing[] =
|
||||
{ 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
|
||||
static const __u8 nset3[] = {
|
||||
0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
|
||||
0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
|
||||
0xcf, 0xe0
|
||||
};
|
||||
static const __u8 nset5[] =
|
||||
{ 0x8f, 0x24, 0xc3, 0x00 }; /* bright */
|
||||
static const __u8 nset7[4] =
|
||||
{ 0x66, 0xca, 0xa8, 0xf8 }; /* 50/60 Hz */
|
||||
static const __u8 nset9[4] =
|
||||
{ 0x0b, 0x04, 0x0a, 0x78 };
|
||||
static const __u8 nset8[6] =
|
||||
{ 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
|
||||
static const __u8 nset10[6] =
|
||||
{ 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
|
||||
|
||||
byte = reg_r(gspca_dev, 0x06);
|
||||
test_byte = reg_r(gspca_dev, 0x07);
|
||||
if (byte == 0x08 && test_byte == 0x07) {
|
||||
PDEBUG(D_CONF, "other sensor");
|
||||
sd->sensor = SENSOR_OTHER;
|
||||
PDEBUG(D_CONF, "sensor om6802");
|
||||
sd->sensor = SENSOR_OM6802;
|
||||
} else if (byte == 0x08 && test_byte == 0x01) {
|
||||
PDEBUG(D_CONF, "sensor tas5130a");
|
||||
sd->sensor = SENSOR_TAS5130A;
|
||||
} else {
|
||||
PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte);
|
||||
PDEBUG(D_CONF, "unknown sensor %02x %02x", byte, test_byte);
|
||||
sd->sensor = SENSOR_TAS5130A;
|
||||
}
|
||||
|
||||
i2c_w(gspca_dev, n1, sizeof n1);
|
||||
reg_w_buf(gspca_dev, n1, sizeof n1);
|
||||
test_byte = 0;
|
||||
i = 5;
|
||||
while (--i >= 0) {
|
||||
i2c_w(gspca_dev, nset, sizeof nset);
|
||||
msleep(5);
|
||||
reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
|
||||
test_byte = reg_r(gspca_dev, 0x0063);
|
||||
msleep(100);
|
||||
if (test_byte == 0x17)
|
||||
@ -580,7 +689,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
|
||||
/* return -EIO; */
|
||||
/*fixme: test - continue */
|
||||
}
|
||||
i2c_w(gspca_dev, n2, sizeof n2);
|
||||
reg_w_buf(gspca_dev, n2, sizeof n2);
|
||||
|
||||
i = 0;
|
||||
while (read_indexs[i] != 0x00) {
|
||||
@ -590,58 +699,52 @@ static int sd_init(struct gspca_dev *gspca_dev)
|
||||
i++;
|
||||
}
|
||||
|
||||
i2c_w(gspca_dev, n3, sizeof n3);
|
||||
i2c_w(gspca_dev, n4, sizeof n4);
|
||||
reg_w_buf(gspca_dev, n3, sizeof n3);
|
||||
reg_w_buf(gspca_dev, n4, sizeof n4);
|
||||
reg_r(gspca_dev, 0x0080);
|
||||
reg_w(gspca_dev, 0x2c80);
|
||||
i2c_w(gspca_dev, nset2, sizeof nset2);
|
||||
i2c_w(gspca_dev, nset3, sizeof nset3);
|
||||
i2c_w(gspca_dev, nset4, sizeof nset4);
|
||||
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
|
||||
sizeof sensor_data[sd->sensor].data1);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
|
||||
sizeof sensor_data[sd->sensor].data3);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
|
||||
sizeof sensor_data[sd->sensor].data2);
|
||||
|
||||
reg_w(gspca_dev, 0x3880);
|
||||
reg_w(gspca_dev, 0x3880);
|
||||
reg_w(gspca_dev, 0x338e);
|
||||
i2c_w(gspca_dev, nset5, sizeof nset5);
|
||||
reg_w(gspca_dev, 0x00a9);
|
||||
|
||||
setbrightness(gspca_dev);
|
||||
setcontrast(gspca_dev);
|
||||
setgamma(gspca_dev);
|
||||
reg_w(gspca_dev, 0x86bb);
|
||||
reg_w(gspca_dev, 0x4aa6);
|
||||
setcolors(gspca_dev);
|
||||
setsharpness(gspca_dev);
|
||||
setwhitebalance(gspca_dev);
|
||||
|
||||
i2c_w(gspca_dev, missing, sizeof missing);
|
||||
|
||||
reg_w(gspca_dev, 0x2087);
|
||||
reg_w(gspca_dev, 0x2087); /* tied to white balance? */
|
||||
reg_w(gspca_dev, 0x2088);
|
||||
reg_w(gspca_dev, 0x2089);
|
||||
|
||||
i2c_w(gspca_dev, nset7, sizeof nset7);
|
||||
i2c_w(gspca_dev, nset10, sizeof nset10);
|
||||
i2c_w(gspca_dev, nset8, sizeof nset8);
|
||||
i2c_w(gspca_dev, nset9, sizeof nset9);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
|
||||
sizeof sensor_data[sd->sensor].data4);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
|
||||
sizeof sensor_data[sd->sensor].data5);
|
||||
reg_w_buf(gspca_dev, nset8, sizeof nset8);
|
||||
reg_w_buf(gspca_dev, nset9, sizeof nset9);
|
||||
|
||||
reg_w(gspca_dev, 0x2880);
|
||||
i2c_w(gspca_dev, nset2, sizeof nset2);
|
||||
i2c_w(gspca_dev, nset3, sizeof nset3);
|
||||
i2c_w(gspca_dev, nset4, sizeof nset4);
|
||||
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data1,
|
||||
sizeof sensor_data[sd->sensor].data1);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data3,
|
||||
sizeof sensor_data[sd->sensor].data3);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data2,
|
||||
sizeof sensor_data[sd->sensor].data2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setbrightness(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
unsigned int brightness;
|
||||
__u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 };
|
||||
|
||||
brightness = sd->brightness;
|
||||
if (brightness < 7) {
|
||||
set6[3] = 0x70 - brightness * 0x10;
|
||||
} else {
|
||||
set6[1] = 0x24;
|
||||
set6[3] = 0x00 + ((brightness - 7) * 0x10);
|
||||
}
|
||||
|
||||
i2c_w(gspca_dev, set6, sizeof set6);
|
||||
}
|
||||
|
||||
static void setflip(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
@ -651,14 +754,15 @@ static void setflip(struct gspca_dev *gspca_dev)
|
||||
if (sd->mirror)
|
||||
flipcmd[3] = 0x01;
|
||||
|
||||
i2c_w(gspca_dev, flipcmd, sizeof flipcmd);
|
||||
reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
|
||||
}
|
||||
|
||||
static void seteffect(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]);
|
||||
reg_w_buf(gspca_dev, effects_table[sd->effect],
|
||||
sizeof effects_table[0]);
|
||||
if (sd->effect == 1 || sd->effect == 5) {
|
||||
PDEBUG(D_CONF,
|
||||
"This effect have been disabled for webcam \"safety\"");
|
||||
@ -671,19 +775,6 @@ static void seteffect(struct gspca_dev *gspca_dev)
|
||||
reg_w(gspca_dev, 0xfaa6);
|
||||
}
|
||||
|
||||
static void setwhitebalance(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
__u8 white_balance[8] =
|
||||
{ 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
|
||||
|
||||
if (sd->whitebalance == 1)
|
||||
white_balance[7] = 0x3c;
|
||||
|
||||
i2c_w(gspca_dev, white_balance, sizeof white_balance);
|
||||
}
|
||||
|
||||
static void setlightfreq(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
@ -692,52 +783,46 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
|
||||
if (sd->freq == 2) /* 60hz */
|
||||
freq[1] = 0x00;
|
||||
|
||||
i2c_w(gspca_dev, freq, sizeof freq);
|
||||
reg_w_buf(gspca_dev, freq, sizeof freq);
|
||||
}
|
||||
|
||||
static void setcontrast(struct gspca_dev *gspca_dev)
|
||||
/* Is this really needed?
|
||||
* i added some module parameters for test with some users */
|
||||
static void poll_sensor(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
unsigned int contrast = sd->contrast;
|
||||
__u16 reg_to_write;
|
||||
static const __u8 poll1[] =
|
||||
{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
|
||||
0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
|
||||
0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
|
||||
0x60, 0x14};
|
||||
static const __u8 poll2[] =
|
||||
{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
|
||||
0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
|
||||
static const __u8 poll3[] =
|
||||
{0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
|
||||
static const __u8 poll4[] =
|
||||
{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
|
||||
0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
|
||||
0xc2, 0x80, 0xc3, 0x10};
|
||||
|
||||
if (contrast < 7)
|
||||
reg_to_write = 0x8ea9 - (0x200 * contrast);
|
||||
else
|
||||
reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
|
||||
|
||||
reg_w(gspca_dev, reg_to_write);
|
||||
}
|
||||
|
||||
static void setcolors(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
__u16 reg_to_write;
|
||||
|
||||
reg_to_write = 0xc0bb + sd->colors * 0x100;
|
||||
reg_w(gspca_dev, reg_to_write);
|
||||
}
|
||||
|
||||
static void setsharpness(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
__u16 reg_to_write;
|
||||
|
||||
reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
|
||||
|
||||
reg_w(gspca_dev, reg_to_write);
|
||||
if (sd->sensor != SENSOR_TAS5130A) {
|
||||
PDEBUG(D_STREAM, "[Sensor requires polling]");
|
||||
reg_w_buf(gspca_dev, poll1, sizeof poll1);
|
||||
reg_w_buf(gspca_dev, poll2, sizeof poll2);
|
||||
reg_w_buf(gspca_dev, poll3, sizeof poll3);
|
||||
reg_w_buf(gspca_dev, poll4, sizeof poll4);
|
||||
}
|
||||
}
|
||||
|
||||
static int sd_start(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
int i, mode;
|
||||
static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
|
||||
__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
|
||||
static const __u8 t3[] =
|
||||
{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
|
||||
0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
|
||||
static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
|
||||
|
||||
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
|
||||
switch (mode) {
|
||||
@ -760,25 +845,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
||||
if (sd->sensor == SENSOR_TAS5130A) {
|
||||
i = 0;
|
||||
while (tas5130a_sensor_init[i][0] != 0) {
|
||||
i2c_w(gspca_dev, tas5130a_sensor_init[i],
|
||||
reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
|
||||
sizeof tas5130a_sensor_init[0]);
|
||||
i++;
|
||||
}
|
||||
reg_w(gspca_dev, 0x3c80);
|
||||
/* just in case and to keep sync with logs (for mine) */
|
||||
i2c_w(gspca_dev, tas5130a_sensor_init[3],
|
||||
reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
|
||||
sizeof tas5130a_sensor_init[0]);
|
||||
reg_w(gspca_dev, 0x3c80);
|
||||
} else {
|
||||
other_sensor_init(gspca_dev);
|
||||
om6802_sensor_init(gspca_dev);
|
||||
}
|
||||
/* just in case and to keep sync with logs (for mine) */
|
||||
i2c_w(gspca_dev, t1, sizeof t1);
|
||||
i2c_w(gspca_dev, t2, sizeof t2);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
|
||||
sizeof sensor_data[sd->sensor].data4);
|
||||
reg_r(gspca_dev, 0x0012);
|
||||
i2c_w(gspca_dev, t3, sizeof t3);
|
||||
reg_w_buf(gspca_dev, t2, sizeof t2);
|
||||
reg_w_buf(gspca_dev, t3, sizeof t3);
|
||||
reg_w(gspca_dev, 0x0013);
|
||||
i2c_w(gspca_dev, t4, sizeof t4);
|
||||
msleep(15);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
|
||||
sizeof sensor_data[sd->sensor].stream);
|
||||
poll_sensor(gspca_dev);
|
||||
|
||||
/* restart on each start, just in case, sometimes regs goes wrong
|
||||
* when using controls from app */
|
||||
setbrightness(gspca_dev);
|
||||
@ -787,6 +876,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sd_stopN(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
|
||||
sizeof sensor_data[sd->sensor].stream);
|
||||
msleep(20);
|
||||
reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
|
||||
sizeof sensor_data[sd->sensor].stream);
|
||||
msleep(20);
|
||||
reg_w(gspca_dev, 0x0309);
|
||||
}
|
||||
|
||||
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
|
||||
struct gspca_frame *frame, /* target */
|
||||
__u8 *data, /* isoc packet */
|
||||
@ -1036,6 +1138,7 @@ static const struct sd_desc sd_desc = {
|
||||
.config = sd_config,
|
||||
.init = sd_init,
|
||||
.start = sd_start,
|
||||
.stopN = sd_stopN,
|
||||
.pkt_scan = sd_pkt_scan,
|
||||
.querymenu = sd_querymenu,
|
||||
};
|
||||
|
@ -600,13 +600,14 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
|
||||
since we may get here before the stream has been fully set-up */
|
||||
if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
|
||||
while (count >= itv->dma_data_req_size) {
|
||||
if (!ivtv_yuv_udma_stream_frame (itv, (void __user *)user_buf)) {
|
||||
bytes_written += itv->dma_data_req_size;
|
||||
user_buf += itv->dma_data_req_size;
|
||||
count -= itv->dma_data_req_size;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
bytes_written += itv->dma_data_req_size;
|
||||
user_buf += itv->dma_data_req_size;
|
||||
count -= itv->dma_data_req_size;
|
||||
}
|
||||
if (count == 0) {
|
||||
IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
|
||||
|
@ -509,7 +509,6 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_
|
||||
static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
|
||||
{
|
||||
struct ivtv_open_id *id = fh;
|
||||
struct ivtv *itv = id->itv;
|
||||
s32 w = fmt->fmt.pix.width;
|
||||
s32 h = fmt->fmt.pix.height;
|
||||
int field = fmt->fmt.pix.field;
|
||||
@ -517,7 +516,22 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format
|
||||
|
||||
w = min(w, 720);
|
||||
w = max(w, 2);
|
||||
h = min(h, itv->is_out_50hz ? 576 : 480);
|
||||
/* Why can the height be 576 even when the output is NTSC?
|
||||
|
||||
Internally the buffers of the PVR350 are always set to 720x576. The
|
||||
decoded video frame will always be placed in the top left corner of
|
||||
this buffer. For any video which is not 720x576, the buffer will
|
||||
then be cropped to remove the unused right and lower areas, with
|
||||
the remaining image being scaled by the hardware to fit the display
|
||||
area. The video can be scaled both up and down, so a 720x480 video
|
||||
can be displayed full-screen on PAL and a 720x576 video can be
|
||||
displayed without cropping on NTSC.
|
||||
|
||||
Note that the scaling only occurs on the video stream, the osd
|
||||
resolution is locked to the broadcast standard and not scaled.
|
||||
|
||||
Thanks to Ian Armstrong for this explanation. */
|
||||
h = min(h, 576);
|
||||
h = max(h, 2);
|
||||
if (id->type == IVTV_DEC_STREAM_TYPE_YUV)
|
||||
fmt->fmt.pix.field = field;
|
||||
|
@ -33,27 +33,20 @@
|
||||
* V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define __KERNEL__
|
||||
#endif
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include "ks0127.h"
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/video_decoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
#include "ks0127.h"
|
||||
|
||||
#define dprintk if (debug) printk
|
||||
|
||||
/* i2c identification */
|
||||
#define I2C_KS0127_ADDON 0xD8
|
||||
#define I2C_KS0127_ONBOARD 0xDA
|
||||
MODULE_DESCRIPTION("KS0127 video decoder driver");
|
||||
MODULE_AUTHOR("Ryan Drake");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define KS_TYPE_UNKNOWN 0
|
||||
#define KS_TYPE_0122S 1
|
||||
@ -204,8 +197,6 @@ struct adjust {
|
||||
};
|
||||
|
||||
struct ks0127 {
|
||||
struct i2c_client *client;
|
||||
unsigned char addr;
|
||||
int format_width;
|
||||
int format_height;
|
||||
int cap_width;
|
||||
@ -220,16 +211,18 @@ static int debug; /* insmod parameter */
|
||||
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug output");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static u8 reg_defaults[64];
|
||||
|
||||
|
||||
|
||||
static void init_reg_defaults(void)
|
||||
{
|
||||
static int initialized;
|
||||
u8 *table = reg_defaults;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = 1;
|
||||
|
||||
table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */
|
||||
table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */
|
||||
table[KS_CMDC] = 0x00; /* Test options */
|
||||
@ -308,50 +301,53 @@ static void init_reg_defaults(void)
|
||||
* An explanation from kayork@mail.utexas.edu:
|
||||
*
|
||||
* During I2C reads, the KS0127 only samples for a stop condition
|
||||
* during the place where the acknoledge bit should be. Any standard
|
||||
* during the place where the acknowledge bit should be. Any standard
|
||||
* I2C implementation (correctly) throws in another clock transition
|
||||
* at the 9th bit, and the KS0127 will not recognize the stop condition
|
||||
* and will continue to clock out data.
|
||||
*
|
||||
* So we have to do the read ourself. Big deal.
|
||||
workaround in i2c-algo-bit
|
||||
* workaround in i2c-algo-bit
|
||||
*/
|
||||
|
||||
|
||||
static u8 ks0127_read(struct ks0127 *ks, u8 reg)
|
||||
static u8 ks0127_read(struct i2c_client *c, u8 reg)
|
||||
{
|
||||
struct i2c_client *c = ks->client;
|
||||
char val = 0;
|
||||
struct i2c_msg msgs[] = {
|
||||
{c->addr, 0, sizeof(reg), ®},
|
||||
{c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
|
||||
{ c->addr, 0, sizeof(reg), ® },
|
||||
{ c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val }
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret != ARRAY_SIZE(msgs))
|
||||
dprintk("ks0127_write error\n");
|
||||
v4l_dbg(1, debug, c, "read error\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
|
||||
static void ks0127_write(struct i2c_client *c, u8 reg, u8 val)
|
||||
{
|
||||
char msg[] = {reg, val};
|
||||
struct ks0127 *ks = i2c_get_clientdata(c);
|
||||
char msg[] = { reg, val };
|
||||
|
||||
if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
|
||||
dprintk("ks0127_write error\n");
|
||||
if (i2c_master_send(c, msg, sizeof(msg)) != sizeof(msg))
|
||||
v4l_dbg(1, debug, c, "write error\n");
|
||||
|
||||
ks->regs[reg] = val;
|
||||
}
|
||||
|
||||
|
||||
/* generic bit-twiddling */
|
||||
static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
|
||||
static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v)
|
||||
{
|
||||
struct ks0127 *ks = i2c_get_clientdata(client);
|
||||
|
||||
u8 val = ks->regs[reg];
|
||||
val = (val & and_v) | or_v;
|
||||
ks0127_write(ks, reg, val);
|
||||
ks0127_write(client, reg, val);
|
||||
}
|
||||
|
||||
|
||||
@ -359,73 +355,69 @@ static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
|
||||
/****************************************************************************
|
||||
* ks0127 private api
|
||||
****************************************************************************/
|
||||
static void ks0127_reset(struct ks0127* ks)
|
||||
static void ks0127_reset(struct i2c_client *c)
|
||||
{
|
||||
int i;
|
||||
struct ks0127 *ks = i2c_get_clientdata(c);
|
||||
u8 *table = reg_defaults;
|
||||
int i;
|
||||
|
||||
ks->ks_type = KS_TYPE_UNKNOWN;
|
||||
|
||||
dprintk("ks0127: reset\n");
|
||||
v4l_dbg(1, debug, c, "reset\n");
|
||||
msleep(1);
|
||||
|
||||
/* initialize all registers to known values */
|
||||
/* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
|
||||
|
||||
for(i = 1; i < 33; i++)
|
||||
ks0127_write(ks, i, table[i]);
|
||||
for (i = 1; i < 33; i++)
|
||||
ks0127_write(c, i, table[i]);
|
||||
|
||||
for(i = 35; i < 40; i++)
|
||||
ks0127_write(ks, i, table[i]);
|
||||
for (i = 35; i < 40; i++)
|
||||
ks0127_write(c, i, table[i]);
|
||||
|
||||
for(i = 41; i < 56; i++)
|
||||
ks0127_write(ks, i, table[i]);
|
||||
for (i = 41; i < 56; i++)
|
||||
ks0127_write(c, i, table[i]);
|
||||
|
||||
for(i = 58; i < 64; i++)
|
||||
ks0127_write(ks, i, table[i]);
|
||||
for (i = 58; i < 64; i++)
|
||||
ks0127_write(c, i, table[i]);
|
||||
|
||||
|
||||
if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
|
||||
if ((ks0127_read(c, KS_STAT) & 0x80) == 0) {
|
||||
ks->ks_type = KS_TYPE_0122S;
|
||||
dprintk("ks0127: ks0122s Found\n");
|
||||
v4l_dbg(1, debug, c, "ks0122s found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
|
||||
|
||||
switch (ks0127_read(c, KS_CMDE) & 0x0f) {
|
||||
case 0:
|
||||
ks->ks_type = KS_TYPE_0127;
|
||||
dprintk("ks0127: ks0127 found\n");
|
||||
v4l_dbg(1, debug, c, "ks0127 found\n");
|
||||
break;
|
||||
|
||||
case 9:
|
||||
ks->ks_type = KS_TYPE_0127B;
|
||||
dprintk("ks0127: ks0127B Revision A found\n");
|
||||
v4l_dbg(1, debug, c, "ks0127B Revision A found\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk("ks0127: unknown revision\n");
|
||||
v4l_dbg(1, debug, c, "unknown revision\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ks0127_command(struct i2c_client *client,
|
||||
unsigned int cmd, void *arg)
|
||||
static int ks0127_command(struct i2c_client *c, unsigned cmd, void *arg)
|
||||
{
|
||||
struct ks0127 *ks = i2c_get_clientdata(client);
|
||||
|
||||
int *iarg = (int*)arg;
|
||||
|
||||
struct ks0127 *ks = i2c_get_clientdata(c);
|
||||
int *iarg = (int *)arg;
|
||||
int status;
|
||||
|
||||
if (!ks)
|
||||
return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case DECODER_INIT:
|
||||
dprintk("ks0127: command DECODER_INIT\n");
|
||||
ks0127_reset(ks);
|
||||
v4l_dbg(1, debug, c, "DECODER_INIT\n");
|
||||
ks0127_reset(c);
|
||||
break;
|
||||
|
||||
case DECODER_SET_INPUT:
|
||||
@ -436,161 +428,160 @@ static int ks0127_command(struct i2c_client *client,
|
||||
case KS_INPUT_COMPOSITE_4:
|
||||
case KS_INPUT_COMPOSITE_5:
|
||||
case KS_INPUT_COMPOSITE_6:
|
||||
dprintk("ks0127: command DECODER_SET_INPUT %d: "
|
||||
"Composite\n", *iarg);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_INPUT %d: Composite\n", *iarg);
|
||||
/* autodetect 50/60 Hz */
|
||||
ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
|
||||
ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
|
||||
/* VSE=0 */
|
||||
ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
|
||||
ks0127_and_or(c, KS_CMDA, ~0x40, 0x00);
|
||||
/* set input line */
|
||||
ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
|
||||
ks0127_and_or(c, KS_CMDB, 0xb0, *iarg);
|
||||
/* non-freerunning mode */
|
||||
ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
|
||||
ks0127_and_or(c, KS_CMDC, 0x70, 0x0a);
|
||||
/* analog input */
|
||||
ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
|
||||
ks0127_and_or(c, KS_CMDD, 0x03, 0x00);
|
||||
/* enable chroma demodulation */
|
||||
ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
|
||||
ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
|
||||
/* chroma trap, HYBWR=1 */
|
||||
ks0127_and_or(ks, KS_LUMA, 0x00,
|
||||
ks0127_and_or(c, KS_LUMA, 0x00,
|
||||
(reg_defaults[KS_LUMA])|0x0c);
|
||||
/* scaler fullbw, luma comb off */
|
||||
ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
|
||||
ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
|
||||
/* manual chroma comb .25 .5 .25 */
|
||||
ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
|
||||
ks0127_and_or(c, KS_VERTIC, 0x0f, 0x90);
|
||||
|
||||
/* chroma path delay */
|
||||
ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
|
||||
ks0127_and_or(c, KS_CHROMB, 0x0f, 0x90);
|
||||
|
||||
ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
|
||||
ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
|
||||
ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
|
||||
ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
|
||||
ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
|
||||
ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
|
||||
ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
|
||||
ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
|
||||
break;
|
||||
|
||||
case KS_INPUT_SVIDEO_1:
|
||||
case KS_INPUT_SVIDEO_2:
|
||||
case KS_INPUT_SVIDEO_3:
|
||||
dprintk("ks0127: command DECODER_SET_INPUT %d: "
|
||||
"S-Video\n", *iarg);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_INPUT %d: S-Video\n", *iarg);
|
||||
/* autodetect 50/60 Hz */
|
||||
ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
|
||||
ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
|
||||
/* VSE=0 */
|
||||
ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
|
||||
ks0127_and_or(c, KS_CMDA, ~0x40, 0x00);
|
||||
/* set input line */
|
||||
ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
|
||||
ks0127_and_or(c, KS_CMDB, 0xb0, *iarg);
|
||||
/* non-freerunning mode */
|
||||
ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
|
||||
ks0127_and_or(c, KS_CMDC, 0x70, 0x0a);
|
||||
/* analog input */
|
||||
ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
|
||||
ks0127_and_or(c, KS_CMDD, 0x03, 0x00);
|
||||
/* enable chroma demodulation */
|
||||
ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
|
||||
ks0127_and_or(ks, KS_LUMA, 0x00,
|
||||
ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00);
|
||||
ks0127_and_or(c, KS_LUMA, 0x00,
|
||||
reg_defaults[KS_LUMA]);
|
||||
/* disable luma comb */
|
||||
ks0127_and_or(ks, KS_VERTIA, 0x08,
|
||||
ks0127_and_or(c, KS_VERTIA, 0x08,
|
||||
(reg_defaults[KS_VERTIA]&0xf0)|0x01);
|
||||
ks0127_and_or(ks, KS_VERTIC, 0x0f,
|
||||
ks0127_and_or(c, KS_VERTIC, 0x0f,
|
||||
reg_defaults[KS_VERTIC]&0xf0);
|
||||
|
||||
ks0127_and_or(ks, KS_CHROMB, 0x0f,
|
||||
ks0127_and_or(c, KS_CHROMB, 0x0f,
|
||||
reg_defaults[KS_CHROMB]&0xf0);
|
||||
|
||||
ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
|
||||
ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
|
||||
ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
|
||||
ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
|
||||
ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]);
|
||||
ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]);
|
||||
ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
|
||||
ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
|
||||
break;
|
||||
|
||||
case KS_INPUT_YUV656:
|
||||
dprintk("ks0127: command DECODER_SET_INPUT 15: "
|
||||
"YUV656\n");
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_INPUT 15: YUV656\n");
|
||||
if (ks->norm == VIDEO_MODE_NTSC ||
|
||||
ks->norm == KS_STD_PAL_M)
|
||||
/* force 60 Hz */
|
||||
ks0127_and_or(ks, KS_CMDA, 0xfc, 0x03);
|
||||
ks0127_and_or(c, KS_CMDA, 0xfc, 0x03);
|
||||
else
|
||||
/* force 50 Hz */
|
||||
ks0127_and_or(ks, KS_CMDA, 0xfc, 0x02);
|
||||
ks0127_and_or(c, KS_CMDA, 0xfc, 0x02);
|
||||
|
||||
ks0127_and_or(ks, KS_CMDA, 0xff, 0x40); /* VSE=1 */
|
||||
ks0127_and_or(c, KS_CMDA, 0xff, 0x40); /* VSE=1 */
|
||||
/* set input line and VALIGN */
|
||||
ks0127_and_or(ks, KS_CMDB, 0xb0, (*iarg | 0x40));
|
||||
ks0127_and_or(c, KS_CMDB, 0xb0, (*iarg | 0x40));
|
||||
/* freerunning mode, */
|
||||
/* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
|
||||
ks0127_and_or(ks, KS_CMDC, 0x70, 0x87);
|
||||
ks0127_and_or(c, KS_CMDC, 0x70, 0x87);
|
||||
/* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
|
||||
ks0127_and_or(ks, KS_CMDD, 0x03, 0x08);
|
||||
ks0127_and_or(c, KS_CMDD, 0x03, 0x08);
|
||||
/* disable chroma demodulation */
|
||||
ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
|
||||
ks0127_and_or(c, KS_CTRACK, 0xcf, 0x30);
|
||||
/* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
|
||||
ks0127_and_or(ks, KS_LUMA, 0x00, 0x71);
|
||||
ks0127_and_or(ks, KS_VERTIC, 0x0f,
|
||||
ks0127_and_or(c, KS_LUMA, 0x00, 0x71);
|
||||
ks0127_and_or(c, KS_VERTIC, 0x0f,
|
||||
reg_defaults[KS_VERTIC]&0xf0);
|
||||
|
||||
/* scaler fullbw, luma comb off */
|
||||
ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
|
||||
ks0127_and_or(c, KS_VERTIA, 0x08, 0x81);
|
||||
|
||||
ks0127_and_or(ks, KS_CHROMB, 0x0f,
|
||||
ks0127_and_or(c, KS_CHROMB, 0x0f,
|
||||
reg_defaults[KS_CHROMB]&0xf0);
|
||||
|
||||
ks0127_and_or(ks, KS_CON, 0x00, 0x00);
|
||||
ks0127_and_or(ks, KS_BRT, 0x00, 32); /* spec: 34 */
|
||||
ks0127_and_or(c, KS_CON, 0x00, 0x00);
|
||||
ks0127_and_or(c, KS_BRT, 0x00, 32); /* spec: 34 */
|
||||
/* spec: 229 (e5) */
|
||||
ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
|
||||
ks0127_and_or(ks, KS_HUE, 0x00, 0);
|
||||
ks0127_and_or(c, KS_SAT, 0x00, 0xe8);
|
||||
ks0127_and_or(c, KS_HUE, 0x00, 0);
|
||||
|
||||
ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
|
||||
ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
|
||||
ks0127_and_or(c, KS_UGAIN, 0x00, 238);
|
||||
ks0127_and_or(c, KS_VGAIN, 0x00, 0x00);
|
||||
|
||||
/*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
|
||||
ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
|
||||
ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
|
||||
ks0127_and_or(c, KS_UVOFFH, 0x00, 0x4f);
|
||||
ks0127_and_or(c, KS_UVOFFL, 0x00, 0x00);
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk("ks0127: command DECODER_SET_INPUT: "
|
||||
"Unknown input %d\n", *iarg);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_INPUT: Unknown input %d\n", *iarg);
|
||||
break;
|
||||
}
|
||||
|
||||
/* hack: CDMLPF sometimes spontaneously switches on; */
|
||||
/* force back off */
|
||||
ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
|
||||
ks0127_write(c, KS_DEMOD, reg_defaults[KS_DEMOD]);
|
||||
break;
|
||||
|
||||
case DECODER_SET_OUTPUT:
|
||||
switch(*iarg) {
|
||||
case KS_OUTPUT_YUV656E:
|
||||
dprintk("ks0127: command DECODER_SET_OUTPUT: "
|
||||
"OUTPUT_YUV656E (Missing)\n");
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_OUTPUT: OUTPUT_YUV656E (Missing)\n");
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case KS_OUTPUT_EXV:
|
||||
dprintk("ks0127: command DECODER_SET_OUTPUT: "
|
||||
"OUTPUT_EXV\n");
|
||||
ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_OUTPUT: OUTPUT_EXV\n");
|
||||
ks0127_and_or(c, KS_OFMTA, 0xf0, 0x09);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DECODER_SET_NORM: //sam This block mixes old and new norm names...
|
||||
case DECODER_SET_NORM: /* sam This block mixes old and new norm names... */
|
||||
/* Set to automatic SECAM/Fsc mode */
|
||||
ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
|
||||
ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
|
||||
|
||||
ks->norm = *iarg;
|
||||
switch(*iarg)
|
||||
{
|
||||
switch (*iarg) {
|
||||
/* this is untested !! */
|
||||
/* It just detects PAL_N/NTSC_M (no special frequencies) */
|
||||
/* And you have to set the standard a second time afterwards */
|
||||
case VIDEO_MODE_AUTO:
|
||||
dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_NORM: AUTO\n");
|
||||
|
||||
/* The chip determines the format */
|
||||
/* based on the current field rate */
|
||||
ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
|
||||
ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
|
||||
ks0127_and_or(c, KS_CMDA, 0xfc, 0x00);
|
||||
ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
|
||||
/* This is wrong for PAL ! As I said, */
|
||||
/* you need to set the standard once again !! */
|
||||
ks->format_height = 240;
|
||||
@ -598,84 +589,86 @@ static int ks0127_command(struct i2c_client *client,
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
|
||||
ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_NORM: NTSC_M\n");
|
||||
ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
|
||||
ks->format_height = 240;
|
||||
ks->format_width = 704;
|
||||
break;
|
||||
|
||||
case KS_STD_NTSC_N:
|
||||
dprintk("ks0127: command KS0127_SET_STANDARD: "
|
||||
"NTSC_N (fixme)\n");
|
||||
ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
|
||||
v4l_dbg(1, debug, c,
|
||||
"KS0127_SET_NORM: NTSC_N (fixme)\n");
|
||||
ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
|
||||
ks->format_height = 240;
|
||||
ks->format_width = 704;
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_PAL:
|
||||
dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
|
||||
ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_NORM: PAL_N\n");
|
||||
ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20);
|
||||
ks->format_height = 290;
|
||||
ks->format_width = 704;
|
||||
break;
|
||||
|
||||
case KS_STD_PAL_M:
|
||||
dprintk("ks0127: command KS0127_SET_STANDARD: "
|
||||
"PAL_M (fixme)\n");
|
||||
ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
|
||||
v4l_dbg(1, debug, c,
|
||||
"KS0127_SET_NORM: PAL_M (fixme)\n");
|
||||
ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40);
|
||||
ks->format_height = 290;
|
||||
ks->format_width = 704;
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_SECAM:
|
||||
dprintk("ks0127: command KS0127_SET_STANDARD: "
|
||||
"SECAM\n");
|
||||
v4l_dbg(1, debug, c,
|
||||
"KS0127_SET_NORM: SECAM\n");
|
||||
ks->format_height = 290;
|
||||
ks->format_width = 704;
|
||||
|
||||
/* set to secam autodetection */
|
||||
ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
|
||||
ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
|
||||
ks0127_and_or(c, KS_CHROMA, 0xdf, 0x20);
|
||||
ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00);
|
||||
schedule_timeout_interruptible(HZ/10+1);
|
||||
|
||||
/* did it autodetect? */
|
||||
if (ks0127_read(ks, KS_DEMOD) & 0x40)
|
||||
if (ks0127_read(c, KS_DEMOD) & 0x40)
|
||||
break;
|
||||
|
||||
/* force to secam mode */
|
||||
ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
|
||||
ks0127_and_or(c, KS_DEMOD, 0xf0, 0x0f);
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk("ks0127: command DECODER_SET_NORM: "
|
||||
"Unknown norm %d\n", *iarg);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_NORM: Unknown norm %d\n", *iarg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DECODER_SET_PICTURE:
|
||||
dprintk("ks0127: command DECODER_SET_PICTURE "
|
||||
"not yet supported (fixme)\n");
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_SET_PICTURE: not yet supported\n");
|
||||
return -EINVAL;
|
||||
|
||||
//sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
|
||||
//sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
|
||||
//sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
|
||||
//sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
|
||||
//sam todo: KS0127_SET_AGC_MODE:
|
||||
//sam todo: KS0127_SET_AGC:
|
||||
//sam todo: KS0127_SET_CHROMA_MODE:
|
||||
//sam todo: KS0127_SET_PIXCLK_MODE:
|
||||
//sam todo: KS0127_SET_GAMMA_MODE:
|
||||
//sam todo: KS0127_SET_UGAIN:
|
||||
//sam todo: KS0127_SET_VGAIN:
|
||||
//sam todo: KS0127_SET_INVALY:
|
||||
//sam todo: KS0127_SET_INVALU:
|
||||
//sam todo: KS0127_SET_INVALV:
|
||||
//sam todo: KS0127_SET_UNUSEY:
|
||||
//sam todo: KS0127_SET_UNUSEU:
|
||||
//sam todo: KS0127_SET_UNUSEV:
|
||||
//sam todo: KS0127_SET_VSALIGN_MODE:
|
||||
/* sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE */
|
||||
/* sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE */
|
||||
/* sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE? */
|
||||
/* sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE */
|
||||
/* sam todo: KS0127_SET_AGC_MODE: */
|
||||
/* sam todo: KS0127_SET_AGC: */
|
||||
/* sam todo: KS0127_SET_CHROMA_MODE: */
|
||||
/* sam todo: KS0127_SET_PIXCLK_MODE: */
|
||||
/* sam todo: KS0127_SET_GAMMA_MODE: */
|
||||
/* sam todo: KS0127_SET_UGAIN: */
|
||||
/* sam todo: KS0127_SET_VGAIN: */
|
||||
/* sam todo: KS0127_SET_INVALY: */
|
||||
/* sam todo: KS0127_SET_INVALU: */
|
||||
/* sam todo: KS0127_SET_INVALV: */
|
||||
/* sam todo: KS0127_SET_UNUSEY: */
|
||||
/* sam todo: KS0127_SET_UNUSEU: */
|
||||
/* sam todo: KS0127_SET_UNUSEV: */
|
||||
/* sam todo: KS0127_SET_VSALIGN_MODE: */
|
||||
|
||||
case DECODER_ENABLE_OUTPUT:
|
||||
{
|
||||
@ -684,34 +677,32 @@ static int ks0127_command(struct i2c_client *client,
|
||||
iarg = arg;
|
||||
enable = (*iarg != 0);
|
||||
if (enable) {
|
||||
dprintk("ks0127: command "
|
||||
"DECODER_ENABLE_OUTPUT on "
|
||||
"(%d)\n", enable);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_ENABLE_OUTPUT on\n");
|
||||
/* All output pins on */
|
||||
ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
|
||||
ks0127_and_or(c, KS_OFMTA, 0xcf, 0x30);
|
||||
/* Obey the OEN pin */
|
||||
ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
|
||||
ks0127_and_or(c, KS_CDEM, 0x7f, 0x00);
|
||||
} else {
|
||||
dprintk("ks0127: command "
|
||||
"DECODER_ENABLE_OUTPUT off "
|
||||
"(%d)\n", enable);
|
||||
v4l_dbg(1, debug, c,
|
||||
"DECODER_ENABLE_OUTPUT off\n");
|
||||
/* Video output pins off */
|
||||
ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
|
||||
ks0127_and_or(c, KS_OFMTA, 0xcf, 0x00);
|
||||
/* Ignore the OEN pin */
|
||||
ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
|
||||
ks0127_and_or(c, KS_CDEM, 0x7f, 0x80);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//sam todo: KS0127_SET_OUTPUT_MODE:
|
||||
//sam todo: KS0127_SET_WIDTH:
|
||||
//sam todo: KS0127_SET_HEIGHT:
|
||||
//sam todo: KS0127_SET_HSCALE:
|
||||
/* sam todo: KS0127_SET_OUTPUT_MODE: */
|
||||
/* sam todo: KS0127_SET_WIDTH: */
|
||||
/* sam todo: KS0127_SET_HEIGHT: */
|
||||
/* sam todo: KS0127_SET_HSCALE: */
|
||||
|
||||
case DECODER_GET_STATUS:
|
||||
dprintk("ks0127: command DECODER_GET_STATUS\n");
|
||||
v4l_dbg(1, debug, c, "DECODER_GET_STATUS\n");
|
||||
*iarg = 0;
|
||||
status = ks0127_read(ks, KS_STAT);
|
||||
status = ks0127_read(c, KS_STAT);
|
||||
if (!(status & 0x20)) /* NOVID not set */
|
||||
*iarg = (*iarg | DECODER_STATUS_GOOD);
|
||||
if ((status & 0x01)) /* CLOCK set */
|
||||
@ -722,124 +713,81 @@ static int ks0127_command(struct i2c_client *client,
|
||||
*iarg = (*iarg | DECODER_STATUS_NTSC);
|
||||
break;
|
||||
|
||||
//Catch any unknown command
|
||||
/* Catch any unknown command */
|
||||
default:
|
||||
dprintk("ks0127: command unknown: %04X\n", cmd);
|
||||
v4l_dbg(1, debug, c, "unknown: 0x%08x\n", cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int ks0127_probe(struct i2c_adapter *adapter);
|
||||
static int ks0127_detach(struct i2c_client *client);
|
||||
static int ks0127_command(struct i2c_client *client,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
|
||||
I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
|
||||
static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
|
||||
static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
normal_i2c,
|
||||
probe,
|
||||
ignore,
|
||||
#define I2C_KS0127_ADDON 0xD8
|
||||
#define I2C_KS0127_ONBOARD 0xDA
|
||||
|
||||
static unsigned short normal_i2c[] = {
|
||||
I2C_KS0127_ADDON >> 1,
|
||||
I2C_KS0127_ONBOARD >> 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_ks0127 = {
|
||||
.driver.name = "ks0127",
|
||||
.id = I2C_DRIVERID_KS0127,
|
||||
.attach_adapter = ks0127_probe,
|
||||
.detach_client = ks0127_detach,
|
||||
.command = ks0127_command
|
||||
};
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client ks0127_client_tmpl =
|
||||
{
|
||||
.name = "(ks0127 unset)",
|
||||
.addr = 0,
|
||||
.adapter = NULL,
|
||||
.driver = &i2c_driver_ks0127,
|
||||
};
|
||||
|
||||
static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
|
||||
static int ks0127_probe(struct i2c_client *c, const struct i2c_device_id *id)
|
||||
{
|
||||
struct ks0127 *ks;
|
||||
struct i2c_client *client;
|
||||
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (client == NULL)
|
||||
return -ENOMEM;
|
||||
memcpy(client, &ks0127_client_tmpl, sizeof(*client));
|
||||
v4l_info(c, "%s chip found @ 0x%x (%s)\n",
|
||||
c->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board",
|
||||
c->addr << 1, c->adapter->name);
|
||||
|
||||
ks = kzalloc(sizeof(*ks), GFP_KERNEL);
|
||||
if (ks == NULL) {
|
||||
kfree(client);
|
||||
if (ks == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, ks);
|
||||
client->adapter = adapter;
|
||||
client->addr = addr;
|
||||
sprintf(client->name, "ks0127-%02x", adapter->id);
|
||||
i2c_set_clientdata(c, ks);
|
||||
|
||||
ks->client = client;
|
||||
ks->addr = addr;
|
||||
ks->ks_type = KS_TYPE_UNKNOWN;
|
||||
|
||||
/* power up */
|
||||
ks0127_write(ks, KS_CMDA, 0x2c);
|
||||
init_reg_defaults();
|
||||
ks0127_write(c, KS_CMDA, 0x2c);
|
||||
mdelay(10);
|
||||
|
||||
/* reset the device */
|
||||
ks0127_reset(ks);
|
||||
printk(KERN_INFO "ks0127: attach: %s video decoder\n",
|
||||
ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
|
||||
|
||||
i2c_attach_client(client);
|
||||
ks0127_reset(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ks0127_probe(struct i2c_adapter *adapter)
|
||||
static int ks0127_remove(struct i2c_client *c)
|
||||
{
|
||||
if (adapter->id == I2C_HW_B_ZR36067)
|
||||
return i2c_probe(adapter, &addr_data, ks0127_found_proc);
|
||||
return 0;
|
||||
}
|
||||
struct ks0127 *ks = i2c_get_clientdata(c);
|
||||
|
||||
static int ks0127_detach(struct i2c_client *client)
|
||||
{
|
||||
struct ks0127 *ks = i2c_get_clientdata(client);
|
||||
ks0127_write(c, KS_OFMTA, 0x20); /* tristate */
|
||||
ks0127_write(c, KS_CMDA, 0x2c | 0x80); /* power down */
|
||||
|
||||
ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
|
||||
ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
|
||||
|
||||
i2c_detach_client(client);
|
||||
kfree(ks);
|
||||
kfree(client);
|
||||
|
||||
dprintk("ks0127: detach\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __devinit ks0127_init_module(void)
|
||||
static int ks0127_legacy_probe(struct i2c_adapter *adapter)
|
||||
{
|
||||
init_reg_defaults();
|
||||
return i2c_add_driver(&i2c_driver_ks0127);
|
||||
return adapter->id == I2C_HW_B_ZR36067;
|
||||
}
|
||||
|
||||
static void __devexit ks0127_cleanup_module(void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_ks0127);
|
||||
}
|
||||
static const struct i2c_device_id ks0127_id[] = {
|
||||
{ "ks0127", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ks0127_id);
|
||||
|
||||
|
||||
module_init(ks0127_init_module);
|
||||
module_exit(ks0127_cleanup_module);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "ks0127",
|
||||
.driverid = I2C_DRIVERID_KS0127,
|
||||
.command = ks0127_command,
|
||||
.probe = ks0127_probe,
|
||||
.remove = ks0127_remove,
|
||||
.legacy_probe = ks0127_legacy_probe,
|
||||
.id_table = ks0127_id,
|
||||
};
|
||||
|
@ -31,36 +31,24 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_decoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
|
||||
MODULE_AUTHOR("Pauline Middelink");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define I2C_NAME(s) (s)->name
|
||||
|
||||
#include <linux/videodev.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <linux/video_decoder.h>
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */
|
||||
#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */
|
||||
|
||||
#define I2C_SAA7110 0x9C /* or 0x9E */
|
||||
|
||||
#define SAA7110_NR_REG 0x35
|
||||
|
||||
struct saa7110 {
|
||||
@ -81,10 +69,7 @@ struct saa7110 {
|
||||
/* I2C support functions */
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
saa7110_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static int saa7110_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct saa7110 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -92,10 +77,7 @@ saa7110_write (struct i2c_client *client,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7110_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int saa7110_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg = *data; /* first register to write to */
|
||||
@ -115,8 +97,8 @@ saa7110_write_block (struct i2c_client *client,
|
||||
memcpy(decoder->reg + reg, data + 1, len - 1);
|
||||
} else {
|
||||
for (++data, --len; len; len--) {
|
||||
if ((ret = saa7110_write(client, reg++,
|
||||
*data++)) < 0)
|
||||
ret = saa7110_write(client, reg++, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -124,8 +106,7 @@ saa7110_write_block (struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
saa7110_read (struct i2c_client *client)
|
||||
static inline int saa7110_read(struct i2c_client *client)
|
||||
{
|
||||
return i2c_smbus_read_byte(client);
|
||||
}
|
||||
@ -138,9 +119,7 @@ saa7110_read (struct i2c_client *client)
|
||||
#define FRESP_06H_SVIDEO 0x83 //0xC0
|
||||
|
||||
|
||||
static int
|
||||
saa7110_selmux (struct i2c_client *client,
|
||||
int chan)
|
||||
static int saa7110_selmux(struct i2c_client *client, int chan)
|
||||
{
|
||||
static const unsigned char modes[9][8] = {
|
||||
/* mode 0 */
|
||||
@ -197,8 +176,7 @@ static const unsigned char initseq[1 + SAA7110_NR_REG] = {
|
||||
/* 0x30 */ 0x44, 0x71, 0x02, 0x8C, 0x02
|
||||
};
|
||||
|
||||
static int
|
||||
determine_norm (struct i2c_client *client)
|
||||
static int determine_norm(struct i2c_client *client)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct saa7110 *decoder = i2c_get_clientdata(client);
|
||||
@ -212,29 +190,23 @@ determine_norm (struct i2c_client *client)
|
||||
finish_wait(&decoder->wq, &wait);
|
||||
status = saa7110_read(client);
|
||||
if (status & 0x40) {
|
||||
dprintk(1, KERN_INFO "%s: status=0x%02x (no signal)\n",
|
||||
I2C_NAME(client), status);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x (no signal)\n", status);
|
||||
return decoder->norm; // no change
|
||||
}
|
||||
if ((status & 3) == 0) {
|
||||
saa7110_write(client, 0x06, 0x83);
|
||||
if (status & 0x20) {
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s: status=0x%02x (NTSC/no color)\n",
|
||||
I2C_NAME(client), status);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x (NTSC/no color)\n", status);
|
||||
//saa7110_write(client,0x2E,0x81);
|
||||
return VIDEO_MODE_NTSC;
|
||||
}
|
||||
dprintk(1, KERN_INFO "%s: status=0x%02x (PAL/no color)\n",
|
||||
I2C_NAME(client), status);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x (PAL/no color)\n", status);
|
||||
//saa7110_write(client,0x2E,0x9A);
|
||||
return VIDEO_MODE_PAL;
|
||||
}
|
||||
//saa7110_write(client,0x06,0x03);
|
||||
if (status & 0x20) { /* 60Hz */
|
||||
dprintk(1, KERN_INFO "%s: status=0x%02x (NTSC)\n",
|
||||
I2C_NAME(client), status);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x (NTSC)\n", status);
|
||||
saa7110_write(client, 0x0D, 0x86);
|
||||
saa7110_write(client, 0x0F, 0x50);
|
||||
saa7110_write(client, 0x11, 0x2C);
|
||||
@ -254,13 +226,11 @@ determine_norm (struct i2c_client *client)
|
||||
|
||||
status = saa7110_read(client);
|
||||
if ((status & 0x03) == 0x01) {
|
||||
dprintk(1, KERN_INFO "%s: status=0x%02x (SECAM)\n",
|
||||
I2C_NAME(client), status);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x (SECAM)\n", status);
|
||||
saa7110_write(client, 0x0D, 0x87);
|
||||
return VIDEO_MODE_SECAM;
|
||||
}
|
||||
dprintk(1, KERN_INFO "%s: status=0x%02x (PAL)\n", I2C_NAME(client),
|
||||
status);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x (PAL)\n", status);
|
||||
return VIDEO_MODE_PAL;
|
||||
}
|
||||
|
||||
@ -286,8 +256,8 @@ saa7110_command (struct i2c_client *client,
|
||||
VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO;
|
||||
dc->inputs = SAA7110_MAX_INPUT;
|
||||
dc->outputs = SAA7110_MAX_OUTPUT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_STATUS:
|
||||
{
|
||||
@ -295,8 +265,8 @@ saa7110_command (struct i2c_client *client,
|
||||
int res = 0;
|
||||
|
||||
status = saa7110_read(client);
|
||||
dprintk(1, KERN_INFO "%s: status=0x%02x norm=%d\n",
|
||||
I2C_NAME(client), status, decoder->norm);
|
||||
v4l_dbg(1, debug, client, "status=0x%02x norm=%d\n",
|
||||
status, decoder->norm);
|
||||
if (!(status & 0x40))
|
||||
res |= DECODER_STATUS_GOOD;
|
||||
if (status & 0x03)
|
||||
@ -314,8 +284,8 @@ saa7110_command (struct i2c_client *client,
|
||||
break;
|
||||
}
|
||||
*(int *) arg = res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_NORM:
|
||||
v = *(int *) arg;
|
||||
@ -328,34 +298,24 @@ saa7110_command (struct i2c_client *client,
|
||||
saa7110_write(client, 0x0F, 0x50);
|
||||
saa7110_write(client, 0x11, 0x2C);
|
||||
//saa7110_write(client, 0x2E, 0x81);
|
||||
dprintk(1,
|
||||
KERN_INFO "%s: switched to NTSC\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "switched to NTSC\n");
|
||||
break;
|
||||
case VIDEO_MODE_PAL:
|
||||
saa7110_write(client, 0x0D, 0x86);
|
||||
saa7110_write(client, 0x0F, 0x10);
|
||||
saa7110_write(client, 0x11, 0x59);
|
||||
//saa7110_write(client, 0x2E, 0x9A);
|
||||
dprintk(1,
|
||||
KERN_INFO "%s: switched to PAL\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "switched to PAL\n");
|
||||
break;
|
||||
case VIDEO_MODE_SECAM:
|
||||
saa7110_write(client, 0x0D, 0x87);
|
||||
saa7110_write(client, 0x0F, 0x10);
|
||||
saa7110_write(client, 0x11, 0x59);
|
||||
//saa7110_write(client, 0x2E, 0x9A);
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s: switched to SECAM\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "switched to SECAM\n");
|
||||
break;
|
||||
case VIDEO_MODE_AUTO:
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s: TV standard detection...\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "switched to AUTO\n");
|
||||
decoder->norm = determine_norm(client);
|
||||
*(int *) arg = decoder->norm;
|
||||
break;
|
||||
@ -368,15 +328,12 @@ saa7110_command (struct i2c_client *client,
|
||||
case DECODER_SET_INPUT:
|
||||
v = *(int *) arg;
|
||||
if (v < 0 || v > SAA7110_MAX_INPUT) {
|
||||
dprintk(1,
|
||||
KERN_INFO "%s: input=%d not available\n",
|
||||
I2C_NAME(client), v);
|
||||
v4l_dbg(1, debug, client, "input=%d not available\n", v);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (decoder->input != v) {
|
||||
saa7110_selmux(client, v);
|
||||
dprintk(1, KERN_INFO "%s: switched to input=%d\n",
|
||||
I2C_NAME(client), v);
|
||||
v4l_dbg(1, debug, client, "switched to input=%d\n", v);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -392,8 +349,7 @@ saa7110_command (struct i2c_client *client,
|
||||
if (decoder->enable != v) {
|
||||
decoder->enable = v;
|
||||
saa7110_write(client, 0x0E, v ? 0x18 : 0x80);
|
||||
dprintk(1, KERN_INFO "%s: YUV %s\n", I2C_NAME(client),
|
||||
v ? "on" : "off");
|
||||
v4l_dbg(1, debug, client, "YUV %s\n", v ? "on" : "off");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -423,23 +379,23 @@ saa7110_command (struct i2c_client *client,
|
||||
saa7110_write(client, 0x07,
|
||||
(decoder->hue >> 8) - 128);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_DUMP:
|
||||
if (!debug)
|
||||
break;
|
||||
for (v = 0; v < SAA7110_NR_REG; v += 16) {
|
||||
int j;
|
||||
dprintk(1, KERN_DEBUG "%s: %02x:", I2C_NAME(client),
|
||||
v);
|
||||
v4l_dbg(1, debug, client, "%02x:", v);
|
||||
for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++)
|
||||
dprintk(1, " %02x", decoder->reg[v + j]);
|
||||
dprintk(1, "\n");
|
||||
printk(KERN_CONT " %02x", decoder->reg[v + j]);
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk(1, KERN_INFO "unknown saa7110_command??(%d)\n",
|
||||
cmd);
|
||||
v4l_dbg(1, debug, client, "unknown command %08x\n", cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
@ -451,55 +407,28 @@ saa7110_command (struct i2c_client *client,
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = {
|
||||
I2C_SAA7110 >> 1,
|
||||
(I2C_SAA7110 >> 1) + 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
static unsigned short normal_i2c[] = { 0x9c >> 1, 0x9e >> 1, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7110;
|
||||
|
||||
static int
|
||||
saa7110_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int saa7110_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct saa7110 *decoder;
|
||||
int rv;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7110.c: detecting saa7110 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality
|
||||
(adapter,
|
||||
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_saa7110;
|
||||
strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
|
||||
if (!decoder) {
|
||||
kfree(client);
|
||||
if (!decoder)
|
||||
return -ENOMEM;
|
||||
}
|
||||
decoder->norm = VIDEO_MODE_PAL;
|
||||
decoder->input = 0;
|
||||
decoder->enable = 1;
|
||||
@ -510,18 +439,10 @@ saa7110_detect_client (struct i2c_adapter *adapter,
|
||||
init_waitqueue_head(&decoder->wq);
|
||||
i2c_set_clientdata(client, decoder);
|
||||
|
||||
rv = i2c_attach_client(client);
|
||||
if (rv) {
|
||||
kfree(client);
|
||||
kfree(decoder);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = saa7110_write_block(client, initseq, sizeof(initseq));
|
||||
if (rv < 0)
|
||||
dprintk(1, KERN_ERR "%s_attach: init status %d\n",
|
||||
I2C_NAME(client), rv);
|
||||
else {
|
||||
if (rv < 0) {
|
||||
v4l_dbg(1, debug, client, "init status %d\n", rv);
|
||||
} else {
|
||||
int ver, status;
|
||||
saa7110_write(client, 0x21, 0x10);
|
||||
saa7110_write(client, 0x0e, 0x18);
|
||||
@ -530,10 +451,8 @@ saa7110_detect_client (struct i2c_adapter *adapter,
|
||||
saa7110_write(client, 0x0D, 0x06);
|
||||
//mdelay(150);
|
||||
status = saa7110_read(client);
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s_attach: SAA7110A version %x at 0x%02x, status=0x%02x\n",
|
||||
I2C_NAME(client), ver, client->addr << 1, status);
|
||||
v4l_dbg(1, debug, client, "version %x, status=0x%02x\n",
|
||||
ver, status);
|
||||
saa7110_write(client, 0x0D, 0x86);
|
||||
saa7110_write(client, 0x0F, 0x10);
|
||||
saa7110_write(client, 0x11, 0x59);
|
||||
@ -547,58 +466,25 @@ saa7110_detect_client (struct i2c_adapter *adapter,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
saa7110_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int saa7110_remove(struct i2c_client *client)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7110.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &saa7110_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7110_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct saa7110 *decoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7110 = {
|
||||
.driver = {
|
||||
.name = "saa7110",
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_SAA7110,
|
||||
|
||||
.attach_adapter = saa7110_attach_adapter,
|
||||
.detach_client = saa7110_detach_client,
|
||||
.command = saa7110_command,
|
||||
static const struct i2c_device_id saa7110_id[] = {
|
||||
{ "saa7110", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, saa7110_id);
|
||||
|
||||
static int __init
|
||||
saa7110_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_saa7110);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
saa7110_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_saa7110);
|
||||
}
|
||||
|
||||
module_init(saa7110_init);
|
||||
module_exit(saa7110_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "saa7110",
|
||||
.driverid = I2C_DRIVERID_SAA7110,
|
||||
.command = saa7110_command,
|
||||
.probe = saa7110_probe,
|
||||
.remove = saa7110_remove,
|
||||
.id_table = saa7110_id,
|
||||
};
|
||||
|
@ -28,43 +28,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_decoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
|
||||
MODULE_AUTHOR("Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(s) (s)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define SAA7111_NR_REG 0x18
|
||||
@ -77,14 +58,9 @@ struct saa7111 {
|
||||
int enable;
|
||||
};
|
||||
|
||||
#define I2C_SAA7111 0x48
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
saa7111_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static inline int saa7111_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct saa7111 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -92,8 +68,7 @@ saa7111_write (struct i2c_client *client,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline void
|
||||
saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
|
||||
static inline void saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct saa7111 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -103,10 +78,7 @@ saa7111_write_if_changed(struct i2c_client *client, u8 reg, u8 value)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
saa7111_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int saa7111_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
@ -127,18 +99,17 @@ saa7111_write_block (struct i2c_client *client,
|
||||
decoder->reg[reg++] = data[1];
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg &&
|
||||
block_len < 32);
|
||||
if ((ret = i2c_master_send(client, block_data,
|
||||
block_len)) < 0)
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
if ((ret = saa7111_write(client, reg,
|
||||
*data++)) < 0)
|
||||
ret = saa7111_write(client, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
@ -147,16 +118,13 @@ saa7111_write_block (struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
saa7111_init_decoder (struct i2c_client *client,
|
||||
struct video_decoder_init *init)
|
||||
static int saa7111_init_decoder(struct i2c_client *client,
|
||||
struct video_decoder_init *init)
|
||||
{
|
||||
return saa7111_write_block(client, init->data, init->len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
saa7111_read (struct i2c_client *client,
|
||||
u8 reg)
|
||||
static inline int saa7111_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
@ -203,28 +171,23 @@ static const unsigned char saa7111_i2c_init[] = {
|
||||
0x17, 0x00, /* 17 - VBI */
|
||||
};
|
||||
|
||||
static int
|
||||
saa7111_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int saa7111_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct saa7111 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
break;
|
||||
case DECODER_INIT:
|
||||
{
|
||||
struct video_decoder_init *init = arg;
|
||||
struct video_decoder_init vdi;
|
||||
|
||||
if (NULL != init)
|
||||
return saa7111_init_decoder(client, init);
|
||||
else {
|
||||
struct video_decoder_init vdi;
|
||||
vdi.data = saa7111_i2c_init;
|
||||
vdi.len = sizeof(saa7111_i2c_init);
|
||||
return saa7111_init_decoder(client, &vdi);
|
||||
}
|
||||
vdi.data = saa7111_i2c_init;
|
||||
vdi.len = sizeof(saa7111_i2c_init);
|
||||
return saa7111_init_decoder(client, &vdi);
|
||||
}
|
||||
|
||||
case DECODER_DUMP:
|
||||
@ -234,15 +197,15 @@ saa7111_command (struct i2c_client *client,
|
||||
for (i = 0; i < SAA7111_NR_REG; i += 16) {
|
||||
int j;
|
||||
|
||||
printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
|
||||
v4l_info(client, "%03x", i);
|
||||
for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) {
|
||||
printk(" %02x",
|
||||
printk(KERN_CONT " %02x",
|
||||
saa7111_read(client, i + j));
|
||||
}
|
||||
printk("\n");
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_CAPABILITIES:
|
||||
{
|
||||
@ -255,8 +218,8 @@ saa7111_command (struct i2c_client *client,
|
||||
VIDEO_DECODER_CCIR;
|
||||
cap->inputs = 8;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_STATUS:
|
||||
{
|
||||
@ -265,8 +228,7 @@ saa7111_command (struct i2c_client *client,
|
||||
int res;
|
||||
|
||||
status = saa7111_read(client, 0x1f);
|
||||
dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
|
||||
status);
|
||||
v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
|
||||
res = 0;
|
||||
if ((status & (1 << 6)) == 0) {
|
||||
res |= DECODER_STATUS_GOOD;
|
||||
@ -294,8 +256,8 @@ saa7111_command (struct i2c_client *client,
|
||||
res |= DECODER_STATUS_COLOR;
|
||||
}
|
||||
*iarg = res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_GPIO:
|
||||
{
|
||||
@ -362,8 +324,8 @@ saa7111_command (struct i2c_client *client,
|
||||
|
||||
}
|
||||
decoder->norm = *iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_INPUT:
|
||||
{
|
||||
@ -387,8 +349,8 @@ saa7111_command (struct i2c_client *client,
|
||||
3) ? 0x80 :
|
||||
0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_OUTPUT:
|
||||
{
|
||||
@ -398,8 +360,8 @@ saa7111_command (struct i2c_client *client,
|
||||
if (*iarg != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_ENABLE_OUTPUT:
|
||||
{
|
||||
@ -439,8 +401,8 @@ saa7111_command (struct i2c_client *client,
|
||||
(decoder->reg[0x11] & 0xf3));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_PICTURE:
|
||||
{
|
||||
@ -454,8 +416,8 @@ saa7111_command (struct i2c_client *client,
|
||||
saa7111_write(client, 0x0c, pic->colour >> 9);
|
||||
/* We want -128 to 127 we get 0-65535 */
|
||||
saa7111_write(client, 0x0d, (pic->hue - 32768) >> 8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -466,48 +428,23 @@ saa7111_command (struct i2c_client *client,
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c[] = { 0x48 >> 1, I2C_CLIENT_END };
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7111;
|
||||
|
||||
static int
|
||||
saa7111_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int saa7111_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *client;
|
||||
struct saa7111 *decoder;
|
||||
struct video_decoder_init vdi;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7111.c: detecting saa7111 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_saa7111;
|
||||
strlcpy(I2C_NAME(client), "saa7111", sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
decoder = kzalloc(sizeof(struct saa7111), GFP_KERNEL);
|
||||
if (decoder == NULL) {
|
||||
@ -519,82 +456,37 @@ saa7111_detect_client (struct i2c_adapter *adapter,
|
||||
decoder->enable = 1;
|
||||
i2c_set_clientdata(client, decoder);
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(decoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
vdi.data = saa7111_i2c_init;
|
||||
vdi.len = sizeof(saa7111_i2c_init);
|
||||
i = saa7111_init_decoder(client, &vdi);
|
||||
if (i < 0) {
|
||||
dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
|
||||
I2C_NAME(client), i);
|
||||
v4l_dbg(1, debug, client, "init status %d\n", i);
|
||||
} else {
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s_attach: chip version %x at address 0x%x\n",
|
||||
I2C_NAME(client), saa7111_read(client, 0x00) >> 4,
|
||||
client->addr << 1);
|
||||
v4l_dbg(1, debug, client, "revision %x\n",
|
||||
saa7111_read(client, 0x00) >> 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
saa7111_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int saa7111_remove(struct i2c_client *client)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7111.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &saa7111_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7111_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct saa7111 *decoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7111 = {
|
||||
.driver = {
|
||||
.name = "saa7111",
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_SAA7111A,
|
||||
|
||||
.attach_adapter = saa7111_attach_adapter,
|
||||
.detach_client = saa7111_detach_client,
|
||||
.command = saa7111_command,
|
||||
static const struct i2c_device_id saa7111_id[] = {
|
||||
{ "saa7111_old", 0 }, /* "saa7111" maps to the saa7115 driver */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, saa7111_id);
|
||||
|
||||
static int __init
|
||||
saa7111_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_saa7111);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
saa7111_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_saa7111);
|
||||
}
|
||||
|
||||
module_init(saa7111_init);
|
||||
module_exit(saa7111_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "saa7111",
|
||||
.driverid = I2C_DRIVERID_SAA7111A,
|
||||
.command = saa7111_command,
|
||||
.probe = saa7111_probe,
|
||||
.remove = saa7111_remove,
|
||||
.id_table = saa7111_id,
|
||||
};
|
||||
|
@ -29,43 +29,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_decoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
|
||||
MODULE_AUTHOR("Maxim Yevtyushkin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(x) (x)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct saa7114 {
|
||||
@ -81,9 +62,6 @@ struct saa7114 {
|
||||
int playback;
|
||||
};
|
||||
|
||||
#define I2C_SAA7114 0x42
|
||||
#define I2C_SAA7114A 0x40
|
||||
|
||||
#define I2C_DELAY 10
|
||||
|
||||
|
||||
@ -129,18 +107,12 @@ struct saa7114 {
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
saa7114_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static inline int saa7114_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7114_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int saa7114_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
@ -160,18 +132,17 @@ saa7114_write_block (struct i2c_client *client,
|
||||
reg++;
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg &&
|
||||
block_len < 32);
|
||||
if ((ret = i2c_master_send(client, block_data,
|
||||
block_len)) < 0)
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
if ((ret = saa7114_write(client, reg,
|
||||
*data++)) < 0)
|
||||
ret = saa7114_write(client, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
@ -180,9 +151,7 @@ saa7114_write_block (struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
saa7114_read (struct i2c_client *client,
|
||||
u8 reg)
|
||||
static inline int saa7114_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
@ -452,15 +421,11 @@ static const unsigned char init[] = {
|
||||
0xef, 0x00
|
||||
};
|
||||
|
||||
static int
|
||||
saa7114_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int saa7114_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct saa7114 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
//dprintk(1, KERN_INFO "%s: writing init\n", I2C_NAME(client));
|
||||
//saa7114_write_block(client, init, sizeof(init));
|
||||
@ -470,27 +435,28 @@ saa7114_command (struct i2c_client *client,
|
||||
{
|
||||
int i;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: decoder dump\n", I2C_NAME(client));
|
||||
if (!debug)
|
||||
break;
|
||||
v4l_info(client, "decoder dump\n");
|
||||
|
||||
for (i = 0; i < 32; i += 16) {
|
||||
int j;
|
||||
|
||||
printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
|
||||
v4l_info(client, "%03x", i);
|
||||
for (j = 0; j < 16; ++j) {
|
||||
printk(" %02x",
|
||||
printk(KERN_CONT " %02x",
|
||||
saa7114_read(client, i + j));
|
||||
}
|
||||
printk("\n");
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_CAPABILITIES:
|
||||
{
|
||||
struct video_decoder_capability *cap = arg;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: decoder get capabilities\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "get capabilities\n");
|
||||
|
||||
cap->flags = VIDEO_DECODER_PAL |
|
||||
VIDEO_DECODER_NTSC |
|
||||
@ -498,8 +464,8 @@ saa7114_command (struct i2c_client *client,
|
||||
VIDEO_DECODER_CCIR;
|
||||
cap->inputs = 8;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_STATUS:
|
||||
{
|
||||
@ -509,8 +475,7 @@ saa7114_command (struct i2c_client *client,
|
||||
|
||||
status = saa7114_read(client, 0x1f);
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
|
||||
status);
|
||||
v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
|
||||
res = 0;
|
||||
if ((status & (1 << 6)) == 0) {
|
||||
res |= DECODER_STATUS_GOOD;
|
||||
@ -538,8 +503,8 @@ saa7114_command (struct i2c_client *client,
|
||||
res |= DECODER_STATUS_COLOR;
|
||||
}
|
||||
*iarg = res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_NORM:
|
||||
{
|
||||
@ -547,12 +512,11 @@ saa7114_command (struct i2c_client *client,
|
||||
|
||||
short int hoff = 0, voff = 0, w = 0, h = 0;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: decoder set norm ",
|
||||
I2C_NAME(client));
|
||||
switch (*iarg) {
|
||||
v4l_dbg(1, debug, client, "set norm\n");
|
||||
|
||||
switch (*iarg) {
|
||||
case VIDEO_MODE_NTSC:
|
||||
dprintk(1, "NTSC\n");
|
||||
v4l_dbg(1, debug, client, "NTSC\n");
|
||||
decoder->reg[REG_ADDR(0x06)] =
|
||||
SAA_7114_NTSC_HSYNC_START;
|
||||
decoder->reg[REG_ADDR(0x07)] =
|
||||
@ -571,7 +535,7 @@ saa7114_command (struct i2c_client *client,
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_PAL:
|
||||
dprintk(1, "PAL\n");
|
||||
v4l_dbg(1, debug, client, "PAL\n");
|
||||
decoder->reg[REG_ADDR(0x06)] =
|
||||
SAA_7114_PAL_HSYNC_START;
|
||||
decoder->reg[REG_ADDR(0x07)] =
|
||||
@ -590,9 +554,8 @@ saa7114_command (struct i2c_client *client,
|
||||
break;
|
||||
|
||||
default:
|
||||
dprintk(1, " Unknown video mode!!!\n");
|
||||
v4l_dbg(1, debug, client, "Unknown video mode\n");
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -644,22 +607,20 @@ saa7114_command (struct i2c_client *client,
|
||||
saa7114_write(client, 0x80, 0x36); // i-port and scaler back end clock selection
|
||||
|
||||
decoder->norm = *iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_INPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: decoder set input (%d)\n",
|
||||
I2C_NAME(client), *iarg);
|
||||
v4l_dbg(1, debug, client, "set input (%d)\n", *iarg);
|
||||
if (*iarg < 0 || *iarg > 7) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (decoder->input != *iarg) {
|
||||
dprintk(1, KERN_DEBUG "%s: now setting %s input\n",
|
||||
I2C_NAME(client),
|
||||
v4l_dbg(1, debug, client, "now setting %s input\n",
|
||||
*iarg >= 6 ? "S-Video" : "Composite");
|
||||
decoder->input = *iarg;
|
||||
|
||||
@ -690,30 +651,29 @@ saa7114_command (struct i2c_client *client,
|
||||
saa7114_write(client, 0x0e,
|
||||
decoder->reg[REG_ADDR(0x0e)]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: decoder set output\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "set output\n");
|
||||
|
||||
/* not much choice of outputs */
|
||||
if (*iarg != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_ENABLE_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
int enable = (*iarg != 0);
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: decoder %s output\n",
|
||||
I2C_NAME(client), enable ? "enable" : "disable");
|
||||
v4l_dbg(1, debug, client, "%s output\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
decoder->playback = !enable;
|
||||
|
||||
@ -754,18 +714,16 @@ saa7114_command (struct i2c_client *client,
|
||||
saa7114_write(client, 0x80, 0x36);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_PICTURE:
|
||||
{
|
||||
struct video_picture *pic = arg;
|
||||
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s: decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
|
||||
I2C_NAME(client), pic->brightness, pic->contrast,
|
||||
pic->colour, pic->hue);
|
||||
v4l_dbg(1, debug, client,
|
||||
"decoder set picture bright=%d contrast=%d saturation=%d hue=%d\n",
|
||||
pic->brightness, pic->contrast, pic->colour, pic->hue);
|
||||
|
||||
if (decoder->bright != pic->brightness) {
|
||||
/* We want 0 to 255 we get 0-65535 */
|
||||
@ -789,8 +747,8 @@ saa7114_command (struct i2c_client *client,
|
||||
saa7114_write(client, 0x0d,
|
||||
(decoder->hue - 32768) >> 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -801,58 +759,30 @@ saa7114_command (struct i2c_client *client,
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] =
|
||||
{ I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7114;
|
||||
|
||||
static int
|
||||
saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int saa7114_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i, err[30];
|
||||
short int hoff = SAA_7114_NTSC_HOFFSET;
|
||||
short int voff = SAA_7114_NTSC_VOFFSET;
|
||||
short int w = SAA_7114_NTSC_WIDTH;
|
||||
short int h = SAA_7114_NTSC_HEIGHT;
|
||||
struct i2c_client *client;
|
||||
struct saa7114 *decoder;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7114.c: detecting saa7114 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_saa7114;
|
||||
strlcpy(I2C_NAME(client), "saa7114", sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
decoder = kzalloc(sizeof(struct saa7114), GFP_KERNEL);
|
||||
if (decoder == NULL) {
|
||||
kfree(client);
|
||||
if (decoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
decoder->norm = VIDEO_MODE_NTSC;
|
||||
decoder->input = -1;
|
||||
decoder->enable = 1;
|
||||
@ -937,8 +867,7 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
decoder->reg[REG_ADDR(0x0e)] |= 1; // combfilter on
|
||||
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s_attach: starting decoder init\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "starting init\n");
|
||||
|
||||
err[0] =
|
||||
saa7114_write_block(client, decoder->reg + (0x20 << 1),
|
||||
@ -962,28 +891,23 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
for (i = 0; i <= 5; i++) {
|
||||
if (err[i] < 0) {
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"%s_attach: init error %d at stage %d, leaving attach.\n",
|
||||
I2C_NAME(client), i, err[i]);
|
||||
v4l_dbg(1, debug, client,
|
||||
"init error %d at stage %d, leaving attach.\n",
|
||||
i, err[i]);
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
return 0;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 6; i < 8; i++) {
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
I2C_NAME(client), i, saa7114_read(client, i),
|
||||
v4l_dbg(1, debug, client,
|
||||
"reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
i, saa7114_read(client, i),
|
||||
decoder->reg[REG_ADDR(i)]);
|
||||
}
|
||||
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: performing decoder reset sequence\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client,
|
||||
"performing decoder reset sequence\n");
|
||||
|
||||
err[6] = saa7114_write(client, 0x80, 0x06); // i-port and scaler backend clock selection, task A&B off
|
||||
err[7] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler
|
||||
@ -991,19 +915,15 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
for (i = 6; i <= 8; i++) {
|
||||
if (err[i] < 0) {
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"%s_attach: init error %d at stage %d, leaving attach.\n",
|
||||
I2C_NAME(client), i, err[i]);
|
||||
v4l_dbg(1, debug, client,
|
||||
"init error %d at stage %d, leaving attach.\n",
|
||||
i, err[i]);
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
return 0;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk(1, KERN_INFO "%s_attach: performing the rest of init\n",
|
||||
I2C_NAME(client));
|
||||
|
||||
v4l_dbg(1, debug, client, "performing the rest of init\n");
|
||||
|
||||
err[9] = saa7114_write(client, 0x01, decoder->reg[REG_ADDR(0x01)]);
|
||||
err[10] = saa7114_write_block(client, decoder->reg + (0x03 << 1), (0x1e + 1 - 0x03) << 1); // big seq
|
||||
@ -1039,37 +959,32 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
for (i = 9; i <= 18; i++) {
|
||||
if (err[i] < 0) {
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"%s_attach: init error %d at stage %d, leaving attach.\n",
|
||||
I2C_NAME(client), i, err[i]);
|
||||
v4l_dbg(1, debug, client,
|
||||
"init error %d at stage %d, leaving attach.\n",
|
||||
i, err[i]);
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
return 0;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 6; i < 8; i++) {
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
I2C_NAME(client), i, saa7114_read(client, i),
|
||||
v4l_dbg(1, debug, client,
|
||||
"reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
i, saa7114_read(client, i),
|
||||
decoder->reg[REG_ADDR(i)]);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0x11; i <= 0x13; i++) {
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
I2C_NAME(client), i, saa7114_read(client, i),
|
||||
v4l_dbg(1, debug, client,
|
||||
"reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
i, saa7114_read(client, i),
|
||||
decoder->reg[REG_ADDR(i)]);
|
||||
}
|
||||
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s_attach: setting video input\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "setting video input\n");
|
||||
|
||||
err[19] =
|
||||
saa7114_write(client, 0x02, decoder->reg[REG_ADDR(0x02)]);
|
||||
@ -1080,20 +995,15 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
for (i = 19; i <= 21; i++) {
|
||||
if (err[i] < 0) {
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"%s_attach: init error %d at stage %d, leaving attach.\n",
|
||||
I2C_NAME(client), i, err[i]);
|
||||
v4l_dbg(1, debug, client,
|
||||
"init error %d at stage %d, leaving attach.\n",
|
||||
i, err[i]);
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
return 0;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: performing decoder reset sequence\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "performing decoder reset sequence\n");
|
||||
|
||||
err[22] = saa7114_write(client, 0x88, 0xd8); // sw reset scaler
|
||||
err[23] = saa7114_write(client, 0x88, 0xf8); // sw reset scaler release
|
||||
@ -1102,13 +1012,11 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
|
||||
for (i = 22; i <= 24; i++) {
|
||||
if (err[i] < 0) {
|
||||
dprintk(1,
|
||||
KERN_ERR
|
||||
"%s_attach: init error %d at stage %d, leaving attach.\n",
|
||||
I2C_NAME(client), i, err[i]);
|
||||
v4l_dbg(1, debug, client,
|
||||
"init error %d at stage %d, leaving attach.\n",
|
||||
i, err[i]);
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
return 0;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1116,101 +1024,45 @@ saa7114_detect_client (struct i2c_adapter *adapter,
|
||||
err[26] = saa7114_write(client, 0x07, init[REG_ADDR(0x07)]);
|
||||
err[27] = saa7114_write(client, 0x10, init[REG_ADDR(0x10)]);
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s_attach: chip version %x, decoder status 0x%02x\n",
|
||||
I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
|
||||
v4l_dbg(1, debug, client, "chip version %x, decoder status 0x%02x\n",
|
||||
saa7114_read(client, 0x00) >> 4,
|
||||
saa7114_read(client, 0x1f));
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: power save control: 0x%02x, scaler status: 0x%02x\n",
|
||||
I2C_NAME(client), saa7114_read(client, 0x88),
|
||||
v4l_dbg(1, debug, client,
|
||||
"power save control: 0x%02x, scaler status: 0x%02x\n",
|
||||
saa7114_read(client, 0x88),
|
||||
saa7114_read(client, 0x8f));
|
||||
|
||||
|
||||
for (i = 0x94; i < 0x96; i++) {
|
||||
dprintk(1,
|
||||
KERN_DEBUG
|
||||
"%s_attach: reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
I2C_NAME(client), i, saa7114_read(client, i),
|
||||
v4l_dbg(1, debug, client,
|
||||
"reg[0x%02x] = 0x%02x (0x%02x)\n",
|
||||
i, saa7114_read(client, i),
|
||||
decoder->reg[REG_ADDR(i)]);
|
||||
}
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(decoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
//i = saa7114_write_block(client, init, sizeof(init));
|
||||
i = 0;
|
||||
if (i < 0) {
|
||||
dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
|
||||
I2C_NAME(client), i);
|
||||
} else {
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s_attach: chip version %x at address 0x%x\n",
|
||||
I2C_NAME(client), saa7114_read(client, 0x00) >> 4,
|
||||
client->addr << 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
saa7114_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int saa7114_remove(struct i2c_client *client)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7114.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &saa7114_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7114_detach_client (struct i2c_client *client)
|
||||
{
|
||||
struct saa7114 *decoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7114 = {
|
||||
.driver = {
|
||||
.name = "saa7114",
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_SAA7114,
|
||||
|
||||
.attach_adapter = saa7114_attach_adapter,
|
||||
.detach_client = saa7114_detach_client,
|
||||
.command = saa7114_command,
|
||||
static const struct i2c_device_id saa7114_id[] = {
|
||||
{ "saa7114_old", 0 }, /* "saa7114" maps to the saa7115 driver */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, saa7114_id);
|
||||
|
||||
static int __init
|
||||
saa7114_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_saa7114);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
saa7114_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_saa7114);
|
||||
}
|
||||
|
||||
module_init(saa7114_init);
|
||||
module_exit(saa7114_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "saa7114",
|
||||
.driverid = I2C_DRIVERID_SAA7114,
|
||||
.command = saa7114_command,
|
||||
.probe = saa7114_probe,
|
||||
.remove = saa7114_remove,
|
||||
.id_table = saa7114_id,
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -535,11 +535,16 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
|
||||
struct tda1004x_config *cdec_conf,
|
||||
struct tda827x_config *tuner_conf)
|
||||
{
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
|
||||
/* Get the first frontend */
|
||||
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
|
||||
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
|
||||
if (fe0->dvb.frontend) {
|
||||
if (cdec_conf->i2c_gate)
|
||||
dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
|
||||
if (dvb_attach(tda827x_attach, dev->dvb.frontend,
|
||||
fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
|
||||
if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
|
||||
cdec_conf->tuner_address,
|
||||
&dev->i2c_adap, tuner_conf))
|
||||
return 0;
|
||||
@ -944,12 +949,30 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
int attach_xc3028 = 0;
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
|
||||
/* FIXME: add support for multi-frontend */
|
||||
mutex_init(&dev->frontends.lock);
|
||||
INIT_LIST_HEAD(&dev->frontends.felist);
|
||||
dev->frontends.active_fe_id = 0;
|
||||
|
||||
printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
|
||||
|
||||
if (videobuf_dvb_alloc_frontend(&dev->frontends, 1) == NULL) {
|
||||
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;
|
||||
dev->dvb.name = dev->name;
|
||||
videobuf_queue_sg_init(&dev->dvb.dvbq, &saa7134_ts_qops,
|
||||
fe0->dvb.name = dev->name;
|
||||
videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
|
||||
&dev->pci->dev, &dev->slock,
|
||||
V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
V4L2_FIELD_ALTERNATE,
|
||||
@ -959,47 +982,47 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
switch (dev->board) {
|
||||
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
|
||||
dprintk("pinnacle 300i dvb setup\n");
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
|
||||
if (fe0->dvb.frontend) {
|
||||
fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_AVERMEDIA_777:
|
||||
case SAA7134_BOARD_AVERMEDIA_A16AR:
|
||||
dprintk("avertv 777 dvb setup\n");
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend) {
|
||||
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, 0x61,
|
||||
TUNER_PHILIPS_TD1316);
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_AVERMEDIA_A16D:
|
||||
dprintk("AverMedia A16D dvb setup\n");
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&avermedia_xc3028_mt352_dev,
|
||||
&dev->i2c_adap);
|
||||
attach_xc3028 = 1;
|
||||
break;
|
||||
case SAA7134_BOARD_MD7134:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&medion_cardbus,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend) {
|
||||
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, medion_cardbus.tuner_address,
|
||||
TUNER_PHILIPS_FMD1216ME_MK3);
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_PHILIPS_TOUGH:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&philips_tu1216_60_config,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
|
||||
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
|
||||
if (fe0->dvb.frontend) {
|
||||
fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
|
||||
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_FLYDVBTDUO:
|
||||
@ -1010,24 +1033,24 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
break;
|
||||
case SAA7134_BOARD_PHILIPS_EUROPA:
|
||||
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&philips_europa_config,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
|
||||
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
|
||||
dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
|
||||
dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
|
||||
dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
|
||||
if (fe0->dvb.frontend) {
|
||||
dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
|
||||
fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
|
||||
fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
|
||||
fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
|
||||
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&philips_tu1216_61_config,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
|
||||
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
|
||||
if (fe0->dvb.frontend) {
|
||||
fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
|
||||
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_KWORLD_DVBT_210:
|
||||
@ -1066,14 +1089,14 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
&tda827x_cfg_0) < 0)
|
||||
goto dettach_frontend;
|
||||
} else { /* satellite */
|
||||
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
|
||||
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
|
||||
if (fe0->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
|
||||
&dev->i2c_adap, 0) == NULL) {
|
||||
wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
}
|
||||
if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
|
||||
if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
|
||||
0x08, 0, 0) == NULL) {
|
||||
wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
@ -1083,11 +1106,11 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
break;
|
||||
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
|
||||
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&ads_tech_duo_config,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (dvb_attach(tda827x_attach,dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend) {
|
||||
if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
|
||||
ads_tech_duo_config.tuner_address, &dev->i2c_adap,
|
||||
&ads_duo_cfg) == NULL) {
|
||||
wprintk("no tda827x tuner found at addr: %02x\n",
|
||||
@ -1108,15 +1131,15 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
&tda827x_cfg_0) < 0)
|
||||
goto dettach_frontend;
|
||||
} else { /* satellite */
|
||||
dev->dvb.frontend = dvb_attach(tda10086_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10086_attach,
|
||||
&flydvbs, &dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
struct dvb_frontend *fe = dev->dvb.frontend;
|
||||
if (fe0->dvb.frontend) {
|
||||
struct dvb_frontend *fe = fe0->dvb.frontend;
|
||||
u8 dev_id = dev->eedata[2];
|
||||
u8 data = 0xc4;
|
||||
struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
|
||||
|
||||
if (dvb_attach(tda826x_attach, dev->dvb.frontend,
|
||||
if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
|
||||
0x60, &dev->i2c_adap, 0) == NULL) {
|
||||
wprintk("%s: Medion Quadro, no tda826x "
|
||||
"found !\n", __func__);
|
||||
@ -1150,31 +1173,31 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
|
||||
dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
|
||||
fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend)
|
||||
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
|
||||
if (fe0->dvb.frontend)
|
||||
dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
|
||||
NULL, DVB_PLL_TDHU2);
|
||||
break;
|
||||
case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
|
||||
case SAA7134_BOARD_KWORLD_ATSC110:
|
||||
dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
|
||||
fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend)
|
||||
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
if (fe0->dvb.frontend)
|
||||
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, 0x61,
|
||||
TUNER_PHILIPS_TUV1236D);
|
||||
break;
|
||||
case SAA7134_BOARD_FLYDVBS_LR300:
|
||||
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
|
||||
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
|
||||
if (fe0->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
|
||||
&dev->i2c_adap, 0) == NULL) {
|
||||
wprintk("%s: No tda826x found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
}
|
||||
if (dvb_attach(isl6421_attach, dev->dvb.frontend,
|
||||
if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
|
||||
wprintk("%s: No ISL6421 found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
@ -1182,25 +1205,25 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&medion_cardbus,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
|
||||
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
|
||||
if (fe0->dvb.frontend) {
|
||||
dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
|
||||
fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
|
||||
|
||||
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
|
||||
dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, medion_cardbus.tuner_address,
|
||||
TUNER_PHILIPS_FMD1216ME_MK3);
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
|
||||
dev->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10046_attach,
|
||||
&philips_europa_config,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
|
||||
dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
|
||||
if (fe0->dvb.frontend) {
|
||||
fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
|
||||
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
|
||||
@ -1239,15 +1262,15 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
goto dettach_frontend;
|
||||
break;
|
||||
case SAA7134_BOARD_PHILIPS_SNAKE:
|
||||
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
|
||||
fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
|
||||
&dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
|
||||
if (fe0->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
|
||||
&dev->i2c_adap, 0) == NULL) {
|
||||
wprintk("%s: No tda826x found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
}
|
||||
if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
|
||||
if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, 0, 0) == NULL) {
|
||||
wprintk("%s: No lnbp21 found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
@ -1269,24 +1292,24 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
saa7134_set_gpio(dev, 25, 0);
|
||||
msleep(10);
|
||||
saa7134_set_gpio(dev, 25, 1);
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&avermedia_xc3028_mt352_dev,
|
||||
&dev->i2c_adap);
|
||||
attach_xc3028 = 1;
|
||||
break;
|
||||
case SAA7134_BOARD_MD7134_BRIDGE_2:
|
||||
dev->dvb.frontend = dvb_attach(tda10086_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10086_attach,
|
||||
&sd1878_4m, &dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (fe0->dvb.frontend) {
|
||||
struct dvb_frontend *fe;
|
||||
if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
|
||||
if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
|
||||
&dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
|
||||
wprintk("%s: MD7134 DVB-S, no SD1878 "
|
||||
"found !\n", __func__);
|
||||
goto dettach_frontend;
|
||||
}
|
||||
/* we need to open the i2c gate (we know it exists) */
|
||||
fe = dev->dvb.frontend;
|
||||
fe = fe0->dvb.frontend;
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (dvb_attach(isl6405_attach, fe,
|
||||
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
|
||||
@ -1305,7 +1328,7 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
saa7134_set_gpio(dev, 25, 0);
|
||||
msleep(10);
|
||||
saa7134_set_gpio(dev, 25, 1);
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach,
|
||||
fe0->dvb.frontend = dvb_attach(mt352_attach,
|
||||
&avermedia_xc3028_mt352_dev,
|
||||
&dev->i2c_adap);
|
||||
attach_xc3028 = 1;
|
||||
@ -1316,17 +1339,17 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
&tda827x_cfg_2) < 0)
|
||||
goto dettach_frontend;
|
||||
} else { /* satellite */
|
||||
dev->dvb.frontend = dvb_attach(tda10086_attach,
|
||||
fe0->dvb.frontend = dvb_attach(tda10086_attach,
|
||||
&flydvbs, &dev->i2c_adap);
|
||||
if (dev->dvb.frontend) {
|
||||
if (fe0->dvb.frontend) {
|
||||
if (dvb_attach(tda826x_attach,
|
||||
dev->dvb.frontend, 0x60,
|
||||
fe0->dvb.frontend, 0x60,
|
||||
&dev->i2c_adap, 0) == NULL) {
|
||||
wprintk("%s: Asus Tiger 3in1, no "
|
||||
"tda826x found!\n", __func__);
|
||||
goto dettach_frontend;
|
||||
}
|
||||
if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
|
||||
if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
|
||||
&dev->i2c_adap, 0, 0) == NULL) {
|
||||
wprintk("%s: Asus Tiger 3in1, no lnbp21"
|
||||
" found!\n", __func__);
|
||||
@ -1352,10 +1375,10 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
.i2c_addr = 0x61,
|
||||
};
|
||||
|
||||
if (!dev->dvb.frontend)
|
||||
if (!fe0->dvb.frontend)
|
||||
return -1;
|
||||
|
||||
fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
|
||||
fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
|
||||
if (!fe) {
|
||||
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
|
||||
dev->name);
|
||||
@ -1363,40 +1386,47 @@ static int dvb_init(struct saa7134_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == dev->dvb.frontend) {
|
||||
if (NULL == fe0->dvb.frontend) {
|
||||
printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
/* define general-purpose callback pointer */
|
||||
dev->dvb.frontend->callback = saa7134_tuner_callback;
|
||||
fe0->dvb.frontend->callback = saa7134_tuner_callback;
|
||||
|
||||
/* register everything else */
|
||||
ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
|
||||
adapter_nr);
|
||||
ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
|
||||
&dev->pci->dev, adapter_nr, 0);
|
||||
|
||||
/* this sequence is necessary to make the tda1004x load its firmware
|
||||
* and to enter analog mode of hybrid boards
|
||||
*/
|
||||
if (!ret) {
|
||||
if (dev->dvb.frontend->ops.init)
|
||||
dev->dvb.frontend->ops.init(dev->dvb.frontend);
|
||||
if (dev->dvb.frontend->ops.sleep)
|
||||
dev->dvb.frontend->ops.sleep(dev->dvb.frontend);
|
||||
if (dev->dvb.frontend->ops.tuner_ops.sleep)
|
||||
dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
|
||||
if (fe0->dvb.frontend->ops.init)
|
||||
fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
|
||||
if (fe0->dvb.frontend->ops.sleep)
|
||||
fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
|
||||
if (fe0->dvb.frontend->ops.tuner_ops.sleep)
|
||||
fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
|
||||
}
|
||||
return ret;
|
||||
|
||||
dettach_frontend:
|
||||
if (dev->dvb.frontend)
|
||||
dvb_frontend_detach(dev->dvb.frontend);
|
||||
dev->dvb.frontend = NULL;
|
||||
if (fe0->dvb.frontend)
|
||||
dvb_frontend_detach(fe0->dvb.frontend);
|
||||
fe0->dvb.frontend = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dvb_fini(struct saa7134_dev *dev)
|
||||
{
|
||||
struct videobuf_dvb_frontend *fe0;
|
||||
|
||||
/* Get the first frontend */
|
||||
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
|
||||
if (!fe0)
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: I suspect that this code is bogus, since the entry for
|
||||
Pinnacle 300I DVB-T PAL already defines the proper init to allow
|
||||
the detection of mt2032 (TDA9887_PORT2_INACTIVE)
|
||||
@ -1416,7 +1446,7 @@ static int dvb_fini(struct saa7134_dev *dev)
|
||||
u8 data = 0x80;
|
||||
struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
|
||||
struct dvb_frontend *fe;
|
||||
fe = dev->dvb.frontend;
|
||||
fe = fe0->dvb.frontend;
|
||||
if (fe->ops.i2c_gate_ctrl) {
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(&dev->i2c_adap, &msg, 1);
|
||||
@ -1424,8 +1454,8 @@ static int dvb_fini(struct saa7134_dev *dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dev->dvb.frontend)
|
||||
videobuf_dvb_unregister(&dev->dvb);
|
||||
if (fe0->dvb.frontend)
|
||||
videobuf_dvb_unregister_bus(&dev->frontends);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -581,7 +581,7 @@ struct saa7134_dev {
|
||||
|
||||
#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
|
||||
/* SAA7134_MPEG_DVB only */
|
||||
struct videobuf_dvb dvb;
|
||||
struct videobuf_dvb_frontends frontends;
|
||||
int (*original_demod_sleep)(struct dvb_frontend *fe);
|
||||
int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
|
||||
int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
|
||||
|
@ -25,43 +25,25 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_encoder.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
|
||||
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
|
||||
MODULE_AUTHOR("Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define I2C_NAME(s) (s)->name
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct saa7185 {
|
||||
@ -75,32 +57,24 @@ struct saa7185 {
|
||||
int sat;
|
||||
};
|
||||
|
||||
#define I2C_SAA7185 0x88
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int
|
||||
saa7185_read (struct i2c_client *client)
|
||||
static inline int saa7185_read(struct i2c_client *client)
|
||||
{
|
||||
return i2c_smbus_read_byte(client);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7185_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
static int saa7185_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct saa7185 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
dprintk(1, KERN_DEBUG "SAA7185: %02x set to %02x\n", reg, value);
|
||||
v4l_dbg(1, debug, client, "%02x set to %02x\n", reg, value);
|
||||
encoder->reg[reg] = value;
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7185_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int saa7185_write_block(struct i2c_client *client,
|
||||
const u8 *data, unsigned int len)
|
||||
{
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
@ -121,18 +95,17 @@ saa7185_write_block (struct i2c_client *client,
|
||||
encoder->reg[reg++] = data[1];
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg &&
|
||||
block_len < 32);
|
||||
if ((ret = i2c_master_send(client, block_data,
|
||||
block_len)) < 0)
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
if ((ret = saa7185_write(client, reg,
|
||||
*data++)) < 0)
|
||||
ret = saa7185_write(client, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
@ -240,15 +213,11 @@ static const unsigned char init_ntsc[] = {
|
||||
0x66, 0x21, /* FSC3 */
|
||||
};
|
||||
|
||||
static int
|
||||
saa7185_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct saa7185 *encoder = i2c_get_clientdata(client);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case 0:
|
||||
saa7185_write_block(client, init_common,
|
||||
sizeof(init_common));
|
||||
@ -264,7 +233,6 @@ saa7185_command (struct i2c_client *client,
|
||||
sizeof(init_pal));
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ENCODER_GET_CAPABILITIES:
|
||||
@ -276,8 +244,8 @@ saa7185_command (struct i2c_client *client,
|
||||
VIDEO_ENCODER_SECAM | VIDEO_ENCODER_CCIR;
|
||||
cap->inputs = 1;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_NORM:
|
||||
{
|
||||
@ -286,7 +254,6 @@ saa7185_command (struct i2c_client *client,
|
||||
//saa7185_write_block(client, init_common, sizeof(init_common));
|
||||
|
||||
switch (*iarg) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
saa7185_write_block(client, init_ntsc,
|
||||
sizeof(init_ntsc));
|
||||
@ -300,11 +267,10 @@ saa7185_command (struct i2c_client *client,
|
||||
case VIDEO_MODE_SECAM:
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
encoder->norm = *iarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_INPUT:
|
||||
{
|
||||
@ -314,7 +280,6 @@ saa7185_command (struct i2c_client *client,
|
||||
*iarg = 1: input is from ZR36060 */
|
||||
|
||||
switch (*iarg) {
|
||||
|
||||
case 0:
|
||||
/* Switch RTCE to 1 */
|
||||
saa7185_write(client, 0x61,
|
||||
@ -332,21 +297,19 @@ saa7185_command (struct i2c_client *client,
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_SET_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
/* not much choice of outputs */
|
||||
if (*iarg != 0) {
|
||||
if (*iarg != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ENCODER_ENABLE_OUTPUT:
|
||||
{
|
||||
@ -356,8 +319,8 @@ saa7185_command (struct i2c_client *client,
|
||||
saa7185_write(client, 0x61,
|
||||
(encoder->reg[0x61] & 0xbf) |
|
||||
(encoder->enable ? 0x00 : 0x40));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -368,138 +331,65 @@ saa7185_command (struct i2c_client *client,
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7185;
|
||||
|
||||
static int
|
||||
saa7185_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
static int saa7185_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *client;
|
||||
struct saa7185 *encoder;
|
||||
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7185.c: detecting saa7185 client on address 0x%x\n",
|
||||
address << 1);
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &i2c_driver_saa7185;
|
||||
strlcpy(I2C_NAME(client), "saa7185", sizeof(I2C_NAME(client)));
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
|
||||
if (encoder == NULL) {
|
||||
kfree(client);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
encoder->norm = VIDEO_MODE_NTSC;
|
||||
encoder->enable = 1;
|
||||
i2c_set_clientdata(client, encoder);
|
||||
|
||||
i = i2c_attach_client(client);
|
||||
if (i) {
|
||||
kfree(client);
|
||||
kfree(encoder);
|
||||
return i;
|
||||
}
|
||||
|
||||
i = saa7185_write_block(client, init_common, sizeof(init_common));
|
||||
if (i >= 0) {
|
||||
i = saa7185_write_block(client, init_ntsc,
|
||||
sizeof(init_ntsc));
|
||||
}
|
||||
if (i < 0) {
|
||||
dprintk(1, KERN_ERR "%s_attach: init error %d\n",
|
||||
I2C_NAME(client), i);
|
||||
} else {
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s_attach: chip version %d at address 0x%x\n",
|
||||
I2C_NAME(client), saa7185_read(client) >> 5,
|
||||
client->addr << 1);
|
||||
}
|
||||
|
||||
if (i >= 0)
|
||||
i = saa7185_write_block(client, init_ntsc, sizeof(init_ntsc));
|
||||
if (i < 0)
|
||||
v4l_dbg(1, debug, client, "init error %d\n", i);
|
||||
else
|
||||
v4l_dbg(1, debug, client, "revision 0x%x\n",
|
||||
saa7185_read(client) >> 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
saa7185_attach_adapter (struct i2c_adapter *adapter)
|
||||
{
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"saa7185.c: starting probe for adapter %s (0x%x)\n",
|
||||
I2C_NAME(adapter), adapter->id);
|
||||
return i2c_probe(adapter, &addr_data, &saa7185_detect_client);
|
||||
}
|
||||
|
||||
static int
|
||||
saa7185_detach_client (struct i2c_client *client)
|
||||
static int saa7185_remove(struct i2c_client *client)
|
||||
{
|
||||
struct saa7185 *encoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */
|
||||
//saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */
|
||||
|
||||
kfree(encoder);
|
||||
kfree(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7185 = {
|
||||
.driver = {
|
||||
.name = "saa7185", /* name */
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_SAA7185B,
|
||||
|
||||
.attach_adapter = saa7185_attach_adapter,
|
||||
.detach_client = saa7185_detach_client,
|
||||
.command = saa7185_command,
|
||||
static const struct i2c_device_id saa7185_id[] = {
|
||||
{ "saa7185", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, saa7185_id);
|
||||
|
||||
static int __init
|
||||
saa7185_init (void)
|
||||
{
|
||||
return i2c_add_driver(&i2c_driver_saa7185);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
saa7185_exit (void)
|
||||
{
|
||||
i2c_del_driver(&i2c_driver_saa7185);
|
||||
}
|
||||
|
||||
module_init(saa7185_init);
|
||||
module_exit(saa7185_exit);
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "saa7185",
|
||||
.driverid = I2C_DRIVERID_SAA7185B,
|
||||
.command = saa7185_command,
|
||||
.probe = saa7185_probe,
|
||||
.remove = saa7185_remove,
|
||||
.id_table = saa7185_id,
|
||||
};
|
||||
|
@ -40,39 +40,39 @@
|
||||
|
||||
/* 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 +165,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 +237,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 +324,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 +404,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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kref.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/mm.h>
|
||||
@ -560,7 +559,7 @@ static void stk_clean_iso(struct stk_camera *dev)
|
||||
|
||||
urb = dev->isobufs[i].urb;
|
||||
if (urb) {
|
||||
if (atomic_read(&dev->urbs_used))
|
||||
if (atomic_read(&dev->urbs_used) && is_present(dev))
|
||||
usb_kill_urb(urb);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
@ -689,18 +688,14 @@ static int v4l_stk_release(struct inode *inode, struct file *fp)
|
||||
{
|
||||
struct stk_camera *dev = fp->private_data;
|
||||
|
||||
if (dev->owner != fp) {
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
return 0;
|
||||
if (dev->owner == fp) {
|
||||
stk_stop_stream(dev);
|
||||
stk_free_buffers(dev);
|
||||
dev->owner = NULL;
|
||||
}
|
||||
|
||||
stk_stop_stream(dev);
|
||||
|
||||
stk_free_buffers(dev);
|
||||
|
||||
dev->owner = NULL;
|
||||
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
if(is_present(dev))
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -714,9 +709,6 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
|
||||
struct stk_sio_buffer *sbuf;
|
||||
struct stk_camera *dev = fp->private_data;
|
||||
|
||||
if (dev == NULL)
|
||||
return -EIO;
|
||||
|
||||
if (!is_present(dev))
|
||||
return -EIO;
|
||||
if (dev->owner && dev->owner != fp)
|
||||
@ -773,9 +765,6 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
|
||||
{
|
||||
struct stk_camera *dev = fp->private_data;
|
||||
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
poll_wait(fp, &dev->wait_frame, wait);
|
||||
|
||||
if (!is_present(dev))
|
||||
@ -1436,7 +1425,7 @@ static void stk_camera_disconnect(struct usb_interface *interface)
|
||||
wake_up_interruptible(&dev->wait_frame);
|
||||
stk_remove_sysfs_files(&dev->vdev);
|
||||
|
||||
STK_INFO("Syntek USB2.0 Camera release resources"
|
||||
STK_INFO("Syntek USB2.0 Camera release resources "
|
||||
"video device /dev/video%d\n", dev->vdev.minor);
|
||||
|
||||
video_unregister_device(&dev->vdev);
|
||||
|
@ -122,7 +122,6 @@ struct stk_camera {
|
||||
|
||||
#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
|
||||
|
||||
void stk_camera_delete(struct kref *);
|
||||
int stk_camera_write_reg(struct stk_camera *, u16, u8);
|
||||
int stk_camera_read_reg(struct stk_camera *, u16, int *);
|
||||
|
||||
|
@ -242,7 +242,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"},
|
||||
|
@ -126,7 +126,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;
|
||||
}
|
||||
@ -134,30 +133,38 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int videobuf_dvb_register(struct videobuf_dvb *dvb,
|
||||
static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe,
|
||||
struct module *module,
|
||||
void *adapter_priv,
|
||||
struct device *device,
|
||||
short *adapter_nr)
|
||||
char *adapter_name,
|
||||
short *adapter_nr,
|
||||
int mfe_shared)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_init(&dvb->lock);
|
||||
mutex_init(&fe->lock);
|
||||
|
||||
/* register adapter */
|
||||
result = dvb_register_adapter(&dvb->adapter, dvb->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",
|
||||
dvb->name, result);
|
||||
goto fail_adapter;
|
||||
adapter_name, result);
|
||||
}
|
||||
dvb->adapter.priv = adapter_priv;
|
||||
fe->adapter.priv = adapter_priv;
|
||||
fe->adapter.mfe_shared = mfe_shared;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
|
||||
struct videobuf_dvb *dvb)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* register frontend */
|
||||
result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
|
||||
result = dvb_register_frontend(adapter, dvb->frontend);
|
||||
if (result < 0) {
|
||||
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
|
||||
dvb->name, result);
|
||||
@ -183,7 +190,8 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
|
||||
dvb->dmxdev.filternum = 256;
|
||||
dvb->dmxdev.demux = &dvb->demux.dmx;
|
||||
dvb->dmxdev.capabilities = 0;
|
||||
result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
|
||||
result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
|
||||
|
||||
if (result < 0) {
|
||||
printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
|
||||
dvb->name, result);
|
||||
@ -214,7 +222,11 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
|
||||
}
|
||||
|
||||
/* register network adapter */
|
||||
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
|
||||
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:
|
||||
@ -229,30 +241,151 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
|
||||
dvb_unregister_frontend(dvb->frontend);
|
||||
fail_frontend:
|
||||
dvb_frontend_detach(dvb->frontend);
|
||||
dvb_unregister_adapter(&dvb->adapter);
|
||||
fail_adapter:
|
||||
dvb->frontend = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
|
||||
{
|
||||
dvb_net_release(&dvb->net);
|
||||
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
|
||||
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
|
||||
dvb_dmxdev_release(&dvb->dmxdev);
|
||||
dvb_dmx_release(&dvb->demux);
|
||||
dvb_unregister_frontend(dvb->frontend);
|
||||
dvb_frontend_detach(dvb->frontend);
|
||||
dvb_unregister_adapter(&dvb->adapter);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(videobuf_dvb_register);
|
||||
EXPORT_SYMBOL(videobuf_dvb_unregister);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* compile-command: "make DVB=1"
|
||||
* End:
|
||||
*/
|
||||
/* 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;
|
||||
|
||||
fe = videobuf_dvb_get_frontend(f, 1);
|
||||
if (!fe) {
|
||||
printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
kfree(fe);
|
||||
}
|
||||
mutex_unlock(&f->lock);
|
||||
|
||||
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 list_head *list, *q;
|
||||
struct videobuf_dvb_frontend *fe, *ret = NULL;
|
||||
|
||||
mutex_lock(&f->lock);
|
||||
|
||||
list_for_each_safe(list, q, &f->felist) {
|
||||
fe = list_entry(list, struct videobuf_dvb_frontend, felist);
|
||||
if (fe->id == id) {
|
||||
ret = fe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&f->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(videobuf_dvb_get_frontend);
|
||||
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&f->lock);
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&f->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(videobuf_dvb_find_frontend);
|
||||
|
||||
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);
|
||||
if (fe == NULL)
|
||||
goto fail_alloc;
|
||||
|
||||
fe->id = id;
|
||||
mutex_init(&fe->dvb.lock);
|
||||
|
||||
mutex_lock(&f->lock);
|
||||
list_add_tail(&fe->felist, &f->felist);
|
||||
mutex_unlock(&f->lock);
|
||||
|
||||
fail_alloc:
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL(videobuf_dvb_alloc_frontend);
|
||||
|
@ -128,12 +128,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;
|
||||
@ -190,6 +234,7 @@ struct vivi_fh {
|
||||
struct videobuf_queue vb_vidq;
|
||||
|
||||
enum v4l2_buf_type type;
|
||||
unsigned char bars[8][3];
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
@ -234,13 +279,107 @@ 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,
|
||||
static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
|
||||
{
|
||||
unsigned char r_y, g_u, b_v;
|
||||
unsigned char *p;
|
||||
int color;
|
||||
|
||||
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 */
|
||||
|
||||
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 = r_y;
|
||||
break;
|
||||
case 1:
|
||||
*p = g_u;
|
||||
break;
|
||||
case 3:
|
||||
*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;
|
||||
}
|
||||
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, y;
|
||||
int w, i, j;
|
||||
int pos = inipos;
|
||||
char *p, *s;
|
||||
u8 chr, r, g, b, color;
|
||||
char *s;
|
||||
u8 chr;
|
||||
|
||||
/* We will just duplicate the second pixel at the packet */
|
||||
wmax /= 2;
|
||||
@ -248,27 +387,9 @@ static void gen_line(char *basep, int inipos, int wmax,
|
||||
/* 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;
|
||||
|
||||
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++;
|
||||
}
|
||||
gen_twopix(fh, basep + pos, colorpos);
|
||||
pos += 4; /* only 16 bpp supported for now */
|
||||
}
|
||||
|
||||
/* Checks if it is possible to show timestamp */
|
||||
@ -283,38 +404,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++;
|
||||
}
|
||||
}
|
||||
@ -324,8 +419,9 @@ static void gen_line(char *basep, int inipos, int wmax,
|
||||
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;
|
||||
@ -341,7 +437,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;
|
||||
@ -410,7 +506,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);
|
||||
@ -636,11 +732,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;
|
||||
}
|
||||
|
||||
@ -670,13 +770,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;
|
||||
|
||||
@ -714,6 +813,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)
|
||||
@ -727,12 +828,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);
|
||||
@ -886,8 +1024,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);
|
||||
@ -936,7 +1072,7 @@ static int vivi_open(struct inode *inode, struct file *file)
|
||||
fh->dev = dev;
|
||||
|
||||
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fh->fmt = &format;
|
||||
fh->fmt = &formats[0];
|
||||
fh->width = 640;
|
||||
fh->height = 480;
|
||||
|
||||
|
@ -22,32 +22,21 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define I2C_NAME(x) (x)->name
|
||||
|
||||
#include <linux/videodev.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-i2c-drv-legacy.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/video_decoder.h>
|
||||
|
||||
#define I2C_VPX3220 0x86
|
||||
#define VPX3220_DEBUG KERN_DEBUG "vpx3220: "
|
||||
MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
|
||||
MODULE_AUTHOR("Laurent Pinchart");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define dprintk(num, format, args...) \
|
||||
do { \
|
||||
if (debug >= num) \
|
||||
printk(format, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define VPX_TIMEOUT_COUNT 10
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
@ -67,10 +56,8 @@ struct vpx3220 {
|
||||
static char *inputs[] = { "internal", "composite", "svideo" };
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
static inline int
|
||||
vpx3220_write (struct i2c_client *client,
|
||||
u8 reg,
|
||||
u8 value)
|
||||
|
||||
static inline int vpx3220_write(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
struct vpx3220 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -78,15 +65,12 @@ vpx3220_write (struct i2c_client *client,
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int
|
||||
vpx3220_read (struct i2c_client *client,
|
||||
u8 reg)
|
||||
static inline int vpx3220_read(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_fp_status (struct i2c_client *client)
|
||||
static int vpx3220_fp_status(struct i2c_client *client)
|
||||
{
|
||||
unsigned char status;
|
||||
unsigned int i;
|
||||
@ -106,14 +90,11 @@ vpx3220_fp_status (struct i2c_client *client)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_fp_write (struct i2c_client *client,
|
||||
u8 fpaddr,
|
||||
u16 data)
|
||||
static int vpx3220_fp_write(struct i2c_client *client, u8 fpaddr, u16 data)
|
||||
{
|
||||
/* Write the 16-bit address to the FPWR register */
|
||||
if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) {
|
||||
dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
|
||||
v4l_dbg(1, debug, client, "%s: failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -122,22 +103,20 @@ vpx3220_fp_write (struct i2c_client *client,
|
||||
|
||||
/* Write the 16-bit data to the FPDAT register */
|
||||
if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) {
|
||||
dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
|
||||
v4l_dbg(1, debug, client, "%s: failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16
|
||||
vpx3220_fp_read (struct i2c_client *client,
|
||||
u16 fpaddr)
|
||||
static u16 vpx3220_fp_read(struct i2c_client *client, u16 fpaddr)
|
||||
{
|
||||
s16 data;
|
||||
|
||||
/* Write the 16-bit address to the FPRD register */
|
||||
if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) {
|
||||
dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
|
||||
v4l_dbg(1, debug, client, "%s: failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -147,25 +126,22 @@ vpx3220_fp_read (struct i2c_client *client,
|
||||
/* Read the 16-bit data from the FPDAT register */
|
||||
data = i2c_smbus_read_word_data(client, 0x28);
|
||||
if (data == -1) {
|
||||
dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__);
|
||||
v4l_dbg(1, debug, client, "%s: failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return swab16(data);
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_write_block (struct i2c_client *client,
|
||||
const u8 *data,
|
||||
unsigned int len)
|
||||
static int vpx3220_write_block(struct i2c_client *client, const u8 *data, unsigned int len)
|
||||
{
|
||||
u8 reg;
|
||||
int ret = -1;
|
||||
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
if ((ret =
|
||||
vpx3220_write(client, reg, *data++)) < 0)
|
||||
ret = vpx3220_write(client, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
@ -173,10 +149,8 @@ vpx3220_write_block (struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_write_fp_block (struct i2c_client *client,
|
||||
const u16 *data,
|
||||
unsigned int len)
|
||||
static int vpx3220_write_fp_block(struct i2c_client *client,
|
||||
const u16 *data, unsigned int len)
|
||||
{
|
||||
u8 reg;
|
||||
int ret = 0;
|
||||
@ -285,25 +259,20 @@ static const unsigned short init_fp[] = {
|
||||
0x4b, 0x298, /* PLL gain */
|
||||
};
|
||||
|
||||
static void
|
||||
vpx3220_dump_i2c (struct i2c_client *client)
|
||||
static void vpx3220_dump_i2c(struct i2c_client *client)
|
||||
{
|
||||
int len = sizeof(init_common);
|
||||
const unsigned char *data = init_common;
|
||||
|
||||
while (len > 1) {
|
||||
dprintk(1,
|
||||
KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n",
|
||||
v4l_dbg(1, debug, client, "i2c reg 0x%02x data 0x%02x\n",
|
||||
*data, vpx3220_read(client, *data));
|
||||
data += 2;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_command (struct i2c_client *client,
|
||||
unsigned int cmd,
|
||||
void *arg)
|
||||
static int vpx3220_command(struct i2c_client *client, unsigned cmd, void *arg)
|
||||
{
|
||||
struct vpx3220 *decoder = i2c_get_clientdata(client);
|
||||
|
||||
@ -315,7 +284,6 @@ vpx3220_command (struct i2c_client *client,
|
||||
vpx3220_write_fp_block(client, init_fp,
|
||||
sizeof(init_fp) >> 1);
|
||||
switch (decoder->norm) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
vpx3220_write_fp_block(client, init_ntsc,
|
||||
sizeof(init_ntsc) >> 1);
|
||||
@ -334,21 +302,20 @@ vpx3220_command (struct i2c_client *client,
|
||||
sizeof(init_pal) >> 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_DUMP:
|
||||
{
|
||||
vpx3220_dump_i2c(client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_CAPABILITIES:
|
||||
{
|
||||
struct video_decoder_capability *cap = arg;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "DECODER_GET_CAPABILITIES\n");
|
||||
|
||||
cap->flags = VIDEO_DECODER_PAL |
|
||||
VIDEO_DECODER_NTSC |
|
||||
@ -357,20 +324,18 @@ vpx3220_command (struct i2c_client *client,
|
||||
VIDEO_DECODER_CCIR;
|
||||
cap->inputs = 3;
|
||||
cap->outputs = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_GET_STATUS:
|
||||
{
|
||||
int res = 0, status;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "DECODER_GET_STATUS\n");
|
||||
|
||||
status = vpx3220_fp_read(client, 0x0f3);
|
||||
|
||||
dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client),
|
||||
status);
|
||||
v4l_dbg(1, debug, client, "status: 0x%04x\n", status);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
@ -379,7 +344,6 @@ vpx3220_command (struct i2c_client *client,
|
||||
res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR;
|
||||
|
||||
switch (status & 0x18) {
|
||||
|
||||
case 0x00:
|
||||
case 0x10:
|
||||
case 0x14:
|
||||
@ -400,8 +364,8 @@ vpx3220_command (struct i2c_client *client,
|
||||
}
|
||||
|
||||
*(int *) arg = res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_NORM:
|
||||
{
|
||||
@ -413,50 +377,43 @@ vpx3220_command (struct i2c_client *client,
|
||||
choosen video norm */
|
||||
temp_input = vpx3220_fp_read(client, 0xf2);
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n",
|
||||
I2C_NAME(client), *iarg);
|
||||
v4l_dbg(1, debug, client, "DECODER_SET_NORM %d\n", *iarg);
|
||||
switch (*iarg) {
|
||||
|
||||
case VIDEO_MODE_NTSC:
|
||||
vpx3220_write_fp_block(client, init_ntsc,
|
||||
sizeof(init_ntsc) >> 1);
|
||||
dprintk(1, KERN_INFO "%s: norm switched to NTSC\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "norm switched to NTSC\n");
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_PAL:
|
||||
vpx3220_write_fp_block(client, init_pal,
|
||||
sizeof(init_pal) >> 1);
|
||||
dprintk(1, KERN_INFO "%s: norm switched to PAL\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "norm switched to PAL\n");
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_SECAM:
|
||||
vpx3220_write_fp_block(client, init_secam,
|
||||
sizeof(init_secam) >> 1);
|
||||
dprintk(1, KERN_INFO "%s: norm switched to SECAM\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "norm switched to SECAM\n");
|
||||
break;
|
||||
|
||||
case VIDEO_MODE_AUTO:
|
||||
/* FIXME This is only preliminary support */
|
||||
data = vpx3220_fp_read(client, 0xf2) & 0x20;
|
||||
vpx3220_fp_write(client, 0xf2, 0x00c0 | data);
|
||||
dprintk(1, KERN_INFO "%s: norm switched to Auto\n",
|
||||
I2C_NAME(client));
|
||||
v4l_dbg(1, debug, client, "norm switched to AUTO\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
decoder->norm = *iarg;
|
||||
|
||||
/* And here we set the backed up video input again */
|
||||
vpx3220_fp_write(client, 0xf2, temp_input | 0x0010);
|
||||
udelay(10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_INPUT:
|
||||
{
|
||||
@ -475,8 +432,7 @@ vpx3220_command (struct i2c_client *client,
|
||||
if (*iarg < 0 || *iarg > 2)
|
||||
return -EINVAL;
|
||||
|
||||
dprintk(1, KERN_INFO "%s: input switched to %s\n",
|
||||
I2C_NAME(client), inputs[*iarg]);
|
||||
v4l_dbg(1, debug, client, "input switched to %s\n", inputs[*iarg]);
|
||||
|
||||
vpx3220_write(client, 0x33, input[*iarg][0]);
|
||||
|
||||
@ -488,8 +444,8 @@ vpx3220_command (struct i2c_client *client,
|
||||
data | (input[*iarg][1] << 5) | 0x0010);
|
||||
|
||||
udelay(10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_OUTPUT:
|
||||
{
|
||||
@ -499,19 +455,18 @@ vpx3220_command (struct i2c_client *client,
|
||||
if (*iarg != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_ENABLE_OUTPUT:
|
||||
{
|
||||
int *iarg = arg;
|
||||
|
||||
dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n",
|
||||
I2C_NAME(client), *iarg);
|
||||
v4l_dbg(1, debug, client, "DECODER_ENABLE_OUTPUT %d\n", *iarg);
|
||||
|
||||
vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODER_SET_PICTURE:
|
||||
{
|
||||
@ -542,8 +497,8 @@ vpx3220_command (struct i2c_client *client,
|
||||
vpx3220_fp_write(client, 0x1c,
|
||||
((decoder->hue - 32768) >> 6) & 0xFFF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -552,8 +507,7 @@ vpx3220_command (struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_init_client (struct i2c_client *client)
|
||||
static int vpx3220_init_client(struct i2c_client *client)
|
||||
{
|
||||
vpx3220_write_block(client, init_common, sizeof(init_common));
|
||||
vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1);
|
||||
@ -567,115 +521,26 @@ vpx3220_init_client (struct i2c_client *client)
|
||||
* Client management code
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] =
|
||||
{ I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
static unsigned short normal_i2c[] = { 0x86 >> 1, 0x8e >> 1, I2C_CLIENT_END };
|
||||
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver vpx3220_i2c_driver;
|
||||
|
||||
static int
|
||||
vpx3220_detach_client (struct i2c_client *client)
|
||||
static int vpx3220_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct vpx3220 *decoder = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(decoder);
|
||||
kfree(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_detect_client (struct i2c_adapter *adapter,
|
||||
int address,
|
||||
int kind)
|
||||
{
|
||||
int err;
|
||||
struct i2c_client *client;
|
||||
struct vpx3220 *decoder;
|
||||
|
||||
dprintk(1, VPX3220_DEBUG "%s\n", __func__);
|
||||
const char *name = NULL;
|
||||
u8 ver;
|
||||
u16 pn;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality
|
||||
(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return 0;
|
||||
|
||||
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (client == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &vpx3220_i2c_driver;
|
||||
|
||||
/* Check for manufacture ID and part number */
|
||||
if (kind < 0) {
|
||||
u8 id;
|
||||
u16 pn;
|
||||
|
||||
id = vpx3220_read(client, 0x00);
|
||||
if (id != 0xec) {
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"vpx3220_attach: Wrong manufacturer ID (0x%02x)\n",
|
||||
id);
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pn = (vpx3220_read(client, 0x02) << 8) +
|
||||
vpx3220_read(client, 0x01);
|
||||
switch (pn) {
|
||||
case 0x4680:
|
||||
strlcpy(I2C_NAME(client), "vpx3220a",
|
||||
sizeof(I2C_NAME(client)));
|
||||
break;
|
||||
case 0x4260:
|
||||
strlcpy(I2C_NAME(client), "vpx3216b",
|
||||
sizeof(I2C_NAME(client)));
|
||||
break;
|
||||
case 0x4280:
|
||||
strlcpy(I2C_NAME(client), "vpx3214c",
|
||||
sizeof(I2C_NAME(client)));
|
||||
break;
|
||||
default:
|
||||
dprintk(1,
|
||||
KERN_INFO
|
||||
"%s: Wrong part number (0x%04x)\n",
|
||||
__func__, pn);
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
strlcpy(I2C_NAME(client), "forced vpx32xx",
|
||||
sizeof(I2C_NAME(client)));
|
||||
}
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL);
|
||||
if (decoder == NULL) {
|
||||
kfree(client);
|
||||
if (decoder == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
decoder->norm = VIDEO_MODE_PAL;
|
||||
decoder->input = 0;
|
||||
decoder->enable = 1;
|
||||
@ -685,63 +550,52 @@ vpx3220_detect_client (struct i2c_adapter *adapter,
|
||||
decoder->sat = 32768;
|
||||
i2c_set_clientdata(client, decoder);
|
||||
|
||||
err = i2c_attach_client(client);
|
||||
if (err) {
|
||||
kfree(client);
|
||||
kfree(decoder);
|
||||
return err;
|
||||
ver = i2c_smbus_read_byte_data(client, 0x00);
|
||||
pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
|
||||
i2c_smbus_read_byte_data(client, 0x01);
|
||||
if (ver == 0xec) {
|
||||
switch (pn) {
|
||||
case 0x4680:
|
||||
name = "vpx3220a";
|
||||
break;
|
||||
case 0x4260:
|
||||
name = "vpx3216b";
|
||||
break;
|
||||
case 0x4280:
|
||||
name = "vpx3214c";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n",
|
||||
I2C_NAME(client), client->addr << 1);
|
||||
if (name)
|
||||
v4l_info(client, "%s found @ 0x%x (%s)\n", name,
|
||||
client->addr << 1, client->adapter->name);
|
||||
else
|
||||
v4l_info(client, "chip (%02x:%04x) found @ 0x%x (%s)\n",
|
||||
ver, pn, client->addr << 1, client->adapter->name);
|
||||
|
||||
vpx3220_init_client(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vpx3220_attach_adapter (struct i2c_adapter *adapter)
|
||||
static int vpx3220_remove(struct i2c_client *client)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client);
|
||||
dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* Driver initialization and cleanup code
|
||||
*/
|
||||
|
||||
static struct i2c_driver vpx3220_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "vpx3220",
|
||||
},
|
||||
|
||||
.id = I2C_DRIVERID_VPX3220,
|
||||
|
||||
.attach_adapter = vpx3220_attach_adapter,
|
||||
.detach_client = vpx3220_detach_client,
|
||||
.command = vpx3220_command,
|
||||
static const struct i2c_device_id vpx3220_id[] = {
|
||||
{ "vpx3220a", 0 },
|
||||
{ "vpx3216b", 0 },
|
||||
{ "vpx3214c", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, vpx3220_id);
|
||||
|
||||
static int __init
|
||||
vpx3220_init (void)
|
||||
{
|
||||
return i2c_add_driver(&vpx3220_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
vpx3220_cleanup (void)
|
||||
{
|
||||
i2c_del_driver(&vpx3220_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(vpx3220_init);
|
||||
module_exit(vpx3220_cleanup);
|
||||
|
||||
MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
|
||||
MODULE_AUTHOR("Laurent Pinchart");
|
||||
MODULE_LICENSE("GPL");
|
||||
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
|
||||
.name = "vpx3220",
|
||||
.driverid = I2C_DRIVERID_VPX3220,
|
||||
.command = vpx3220_command,
|
||||
.probe = vpx3220_probe,
|
||||
.remove = vpx3220_remove,
|
||||
.id_table = vpx3220_id,
|
||||
};
|
||||
|
@ -817,6 +817,7 @@ zoran_register_i2c (struct zoran *zr)
|
||||
memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
|
||||
sizeof(struct i2c_algo_bit_data));
|
||||
zr->i2c_algo.data = zr;
|
||||
zr->i2c_adapter.class = I2C_CLASS_TV_ANALOG;
|
||||
zr->i2c_adapter.id = I2C_HW_B_ZR36067;
|
||||
zr->i2c_adapter.client_register = zoran_i2c_client_register;
|
||||
zr->i2c_adapter.client_unregister = zoran_i2c_client_unregister;
|
||||
|
@ -2996,7 +2996,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",
|
||||
|
@ -166,6 +166,7 @@ typedef enum fe_modulation {
|
||||
VSB_16,
|
||||
PSK_8,
|
||||
APSK_16,
|
||||
APSK_32,
|
||||
DQPSK,
|
||||
} fe_modulation_t;
|
||||
|
||||
@ -295,6 +296,7 @@ typedef enum fe_delivery_system {
|
||||
SYS_DVBC_ANNEX_AC,
|
||||
SYS_DVBC_ANNEX_B,
|
||||
SYS_DVBT,
|
||||
SYS_DSS,
|
||||
SYS_DVBS,
|
||||
SYS_DVBS2,
|
||||
SYS_DVBH,
|
||||
|
@ -60,7 +60,7 @@
|
||||
#define I2C_DRIVERID_WM8775 69 /* wm8775 audio processor */
|
||||
#define I2C_DRIVERID_CS53L32A 70 /* cs53l32a audio processor */
|
||||
#define I2C_DRIVERID_CX25840 71 /* cx2584x video encoder */
|
||||
#define I2C_DRIVERID_SAA7127 72 /* saa7124 video encoder */
|
||||
#define I2C_DRIVERID_SAA7127 72 /* saa7127 video encoder */
|
||||
#define I2C_DRIVERID_SAA711X 73 /* saa711x video encoders */
|
||||
#define I2C_DRIVERID_AKITAIOEXP 74 /* IO Expander on Sharp SL-C1000 */
|
||||
#define I2C_DRIVERID_INFRARED 75 /* I2C InfraRed on Video boards */
|
||||
|
@ -1,3 +1,13 @@
|
||||
/*
|
||||
* Generic Platform Camera Driver Header
|
||||
*
|
||||
* Copyright (C) 2008 Magnus Damm
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __SOC_CAMERA_H__
|
||||
#define __SOC_CAMERA_H__
|
||||
|
||||
@ -9,6 +19,7 @@ struct soc_camera_platform_info {
|
||||
unsigned long format_depth;
|
||||
struct v4l2_pix_format format;
|
||||
unsigned long bus_param;
|
||||
void (*power)(int);
|
||||
int (*set_capture)(struct soc_camera_platform_info *info, int enable);
|
||||
};
|
||||
|
||||
|
@ -123,6 +123,7 @@
|
||||
#define TUNER_TEA5761 75 /* Only FM Radio Tuner */
|
||||
#define TUNER_XC5000 76 /* Xceive Silicon Tuner */
|
||||
#define TUNER_TCL_MF02GIP_5N 77 /* TCL MF02GIP_5N */
|
||||
#define TUNER_PHILIPS_FMD1216MEX_MK3 78
|
||||
|
||||
/* tv card specific */
|
||||
#define TDA9887_PRESENT (1<<0)
|
||||
|
@ -21,6 +21,17 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* NOTE: the full version of this header is in the v4l-dvb repository
|
||||
* and allows v4l i2c drivers to be compiled on older kernels as well.
|
||||
* The version of this header as it appears in the kernel is a stripped
|
||||
* version (without all the backwards compatibility stuff) and so it
|
||||
* looks a bit odd.
|
||||
*
|
||||
* If you look at the full version then you will understand the reason
|
||||
* for introducing this header since you really don't want to have all
|
||||
* the tricky backwards compatibility code in each and every i2c driver.
|
||||
*/
|
||||
|
||||
struct v4l2_i2c_driver_data {
|
||||
const char * const name;
|
||||
int driverid;
|
||||
|
@ -21,6 +21,17 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* NOTE: the full version of this header is in the v4l-dvb repository
|
||||
* and allows v4l i2c drivers to be compiled on older kernels as well.
|
||||
* The version of this header as it appears in the kernel is a stripped
|
||||
* version (without all the backwards compatibility stuff) and so it
|
||||
* looks a bit odd.
|
||||
*
|
||||
* If you look at the full version then you will understand the reason
|
||||
* for introducing this header since you really don't want to have all
|
||||
* the tricky backwards compatibility code in each and every i2c driver.
|
||||
*/
|
||||
|
||||
#ifndef __V4L2_I2C_DRV_H__
|
||||
#define __V4L2_I2C_DRV_H__
|
||||
|
||||
|
@ -16,7 +16,6 @@ struct videobuf_dvb {
|
||||
int nfeeds;
|
||||
|
||||
/* videobuf_dvb_(un)register manges this */
|
||||
struct dvb_adapter adapter;
|
||||
struct dvb_demux demux;
|
||||
struct dmxdev dmxdev;
|
||||
struct dmx_frontend fe_hw;
|
||||
@ -24,12 +23,34 @@ struct videobuf_dvb {
|
||||
struct dvb_net net;
|
||||
};
|
||||
|
||||
int videobuf_dvb_register(struct videobuf_dvb *dvb,
|
||||
struct videobuf_dvb_frontend {
|
||||
struct list_head felist;
|
||||
int id;
|
||||
struct videobuf_dvb dvb;
|
||||
};
|
||||
|
||||
struct videobuf_dvb_frontends {
|
||||
struct list_head felist;
|
||||
struct mutex lock;
|
||||
struct dvb_adapter adapter;
|
||||
int active_fe_id; /* Indicates which frontend in the felist is in use */
|
||||
int gate; /* Frontend with gate control 0=!MFE,1=fe0,2=fe1 etc */
|
||||
};
|
||||
|
||||
int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
|
||||
struct module *module,
|
||||
void *adapter_priv,
|
||||
struct device *device,
|
||||
short *adapter_nr);
|
||||
void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
|
||||
short *adapter_nr,
|
||||
int mfe_shared);
|
||||
|
||||
void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f);
|
||||
|
||||
struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(struct videobuf_dvb_frontends *f, int id);
|
||||
|
||||
struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id);
|
||||
int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p);
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
Loading…
Reference in New Issue
Block a user