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:
Linus Torvalds 2008-10-17 15:08:47 -07:00
commit 5564da7e9d
92 changed files with 4098 additions and 4200 deletions

View file

@ -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]

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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",

View file

@ -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

View file

@ -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,

View file

@ -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 @@ err2:
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,

View file

@ -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,

View file

@ -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);

View file

@ -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 */
};

View file

@ -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,

View file

@ -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 @@ error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(cx22702_attach);
static struct dvb_frontend_ops cx22702_ops = {
@ -525,11 +636,6 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_ucblocks = cx22702_read_ucblocks,
};
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(cx22702_attach);

View file

@ -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

View file

@ -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 */

View file

@ -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 @@ error:
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);

View file

@ -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 */

View file

@ -30,10 +30,10 @@
struct s5h1409_state {
struct i2c_adapter* i2c;
struct i2c_adapter *i2c;
/* configuration settings */
const struct s5h1409_config* config;
const struct s5h1409_config *config;
struct dvb_frontend frontend;
@ -48,6 +48,9 @@ struct s5h1409_state {
};
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
#define dprintk if (debug) printk
/* Register values to initialise the demod, this will set VSB by default */
@ -299,10 +302,10 @@ static struct qam256_snr_tab {
};
/* 8 bit registers, 16 bit values */
static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
{
int ret;
u8 buf [] = { reg, data >> 8, data & 0xff };
u8 buf[] = { reg, data >> 8, data & 0xff };
struct i2c_msg msg = { .addr = state->config->demod_address,
.flags = 0, .buf = buf, .len = 3 };
@ -310,19 +313,19 @@ static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, "
"ret == %i)\n", __func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
{
int ret;
u8 b0 [] = { reg };
u8 b1 [] = { 0, 0 };
u8 b0[] = { reg };
u8 b1[] = { 0, 0 };
struct i2c_msg msg [] = {
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0,
.buf = b0, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
@ -335,9 +338,9 @@ static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
return (b1[0] << 8) | b1[1];
}
static int s5h1409_softreset(struct dvb_frontend* fe)
static int s5h1409_softreset(struct dvb_frontend *fe)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
@ -349,11 +352,11 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
}
#define S5H1409_VSB_IF_FREQ 5380
#define S5H1409_QAM_IF_FREQ state->config->qam_if
#define S5H1409_QAM_IF_FREQ (state->config->qam_if)
static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d KHz)\n", __func__, KHz);
@ -376,26 +379,26 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
return 0;
}
static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, inverted);
if(inverted == 1)
if (inverted == 1)
return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
else
return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
}
static int s5h1409_enable_modulation(struct dvb_frontend* fe,
static int s5h1409_enable_modulation(struct dvb_frontend *fe,
fe_modulation_t m)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(0x%08x)\n", __func__, m);
switch(m) {
switch (m) {
case VSB_8:
dprintk("%s() VSB_8\n", __func__);
if (state->if_freq != S5H1409_VSB_IF_FREQ)
@ -422,9 +425,9 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
return 0;
}
static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
@ -434,9 +437,9 @@ static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
return s5h1409_writereg(state, 0xf3, 0);
}
static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
@ -448,18 +451,18 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
s5h1409_readreg(state, 0xe3) & 0xfeff);
}
static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(%d)\n", __func__, enable);
return s5h1409_writereg(state, 0xf2, enable);
}
static int s5h1409_register_reset(struct dvb_frontend* fe)
static int s5h1409_register_reset(struct dvb_frontend *fe)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
@ -483,7 +486,7 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
reg &= 0xff;
s5h1409_writereg(state, 0x96, 0x00c);
if ((reg < 0x38) || (reg > 0x68) ) {
if ((reg < 0x38) || (reg > 0x68)) {
s5h1409_writereg(state, 0x93, 0x3332);
s5h1409_writereg(state, 0x9e, 0x2c37);
} else {
@ -514,7 +517,7 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
s5h1409_writereg(state, 0x96, 0x20);
s5h1409_writereg(state, 0xad,
( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
s5h1409_writereg(state, 0xab,
s5h1409_readreg(state, 0xab) & 0xeffe);
}
@ -529,10 +532,10 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
static int s5h1409_set_frontend (struct dvb_frontend* fe,
static int s5h1409_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s(frequency=%d)\n", __func__, p->frequency);
@ -546,9 +549,11 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
msleep(100);
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
fe->ops.tuner_ops.set_params(fe, p);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
/* Optimize the demod for QAM */
@ -592,17 +597,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
/* Reset the demod hardware and reset all of the configuration registers
to a default state. */
static int s5h1409_init (struct dvb_frontend* fe)
static int s5h1409_init(struct dvb_frontend *fe)
{
int i;
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
dprintk("%s()\n", __func__);
s5h1409_sleep(fe, 0);
s5h1409_register_reset(fe);
for (i=0; i < ARRAY_SIZE(init_tab); i++)
for (i = 0; i < ARRAY_SIZE(init_tab); i++)
s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
/* The datasheet says that after initialisation, VSB is default */
@ -627,9 +632,9 @@ static int s5h1409_init (struct dvb_frontend* fe)
return 0;
}
static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
u16 reg;
u32 tuner_status = 0;
@ -637,12 +642,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* Get the demodulator status */
reg = s5h1409_readreg(state, 0xf1);
if(reg & 0x1000)
if (reg & 0x1000)
*status |= FE_HAS_VITERBI;
if(reg & 0x8000)
if (reg & 0x8000)
*status |= FE_HAS_LOCK | FE_HAS_SYNC;
switch(state->config->status_mode) {
switch (state->config->status_mode) {
case S5H1409_DEMODLOCKING:
if (*status & FE_HAS_VITERBI)
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
@ -668,12 +673,12 @@ static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
return 0;
}
static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
if (v < qam256_snr_tab[i].val) {
*snr = qam256_snr_tab[i].data;
ret = 0;
@ -683,12 +688,12 @@ static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
return ret;
}
static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
if (v < qam64_snr_tab[i].val) {
*snr = qam64_snr_tab[i].data;
ret = 0;
@ -698,12 +703,12 @@ static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
return ret;
}
static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
{
int i, ret = -EINVAL;
dprintk("%s()\n", __func__);
for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
if (v > vsb_snr_tab[i].val) {
*snr = vsb_snr_tab[i].data;
ret = 0;
@ -714,13 +719,13 @@ static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
return ret;
}
static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
u16 reg;
dprintk("%s()\n", __func__);
switch(state->current_modulation) {
switch (state->current_modulation) {
case QAM_64:
reg = s5h1409_readreg(state, 0xf0) & 0xff;
return s5h1409_qam64_lookup_snr(fe, snr, reg);
@ -737,30 +742,30 @@ static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
return -EINVAL;
}
static int s5h1409_read_signal_strength(struct dvb_frontend* fe,
u16* signal_strength)
static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
return s5h1409_read_snr(fe, signal_strength);
}
static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
*ucblocks = s5h1409_readreg(state, 0xb5);
return 0;
}
static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
{
return s5h1409_read_ucblocks(fe, ber);
}
static int s5h1409_get_frontend(struct dvb_frontend* fe,
static int s5h1409_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
p->frequency = state->current_frequency;
p->u.vsb.modulation = state->current_modulation;
@ -768,25 +773,25 @@ static int s5h1409_get_frontend(struct dvb_frontend* fe,
return 0;
}
static int s5h1409_get_tune_settings(struct dvb_frontend* fe,
static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
return 0;
}
static void s5h1409_release(struct dvb_frontend* fe)
static void s5h1409_release(struct dvb_frontend *fe)
{
struct s5h1409_state* state = fe->demodulator_priv;
struct s5h1409_state *state = fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops s5h1409_ops;
struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
struct i2c_adapter* i2c)
struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
struct i2c_adapter *i2c)
{
struct s5h1409_state* state = NULL;
struct s5h1409_state *state = NULL;
u16 reg;
/* allocate memory for the internal state */
@ -825,6 +830,7 @@ error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(s5h1409_attach);
static struct dvb_frontend_ops s5h1409_ops = {
@ -850,14 +856,10 @@ static struct dvb_frontend_ops s5h1409_ops = {
.release = s5h1409_release,
};
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(s5h1409_attach);
/*
* Local variables:

View file

@ -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;

View file

@ -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 } };

View file

@ -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;

View file

@ -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

View file

@ -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),

View file

@ -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"

View file

@ -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 @@ done:
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 @@ done:
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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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),

View file

@ -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);

View file

@ -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,

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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
*/

View file

@ -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
*/

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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,

View file

@ -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
*/

View file

@ -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];

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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();

View file

@ -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);

View file

@ -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;

View file

@ -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>

View file

@ -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

View file

@ -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, "

View file

@ -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]);
}

View file

@ -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
}
},

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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},

View file

@ -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;

View file

@ -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);

View file

@ -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]);
}

View file

@ -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);

View file

@ -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>
*

View file

@ -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,
};

View file

@ -600,13 +600,14 @@ retry:
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);

View file

@ -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;

View file

@ -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), &reg},
{c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
{ c->addr, 0, sizeof(reg), &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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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,
};

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);

View file

@ -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 *);

View file

@ -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"},

View file

@ -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 @@ fail_dmx:
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);

View file

@ -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 @@ end:
return;
}
static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
{
struct vivi_dev *dev = fh->dev;
int h , pos = 0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
@ -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 @@ unlock:
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->fmt = &format;
fh->fmt = &formats[0];
fh->width = 640;
fh->height = 480;

View file

@ -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,
};

View file

@ -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;

View file

@ -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",

View file

@ -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,

View file

@ -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 */

View file

@ -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);
};

View file

@ -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)

View file

@ -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;

View file

@ -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__

View file

@ -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: