2008/1/31 Muppet Man <[EMAIL PROTECTED]>: > > > ----- Original Message ---- > From: Chaogui Zhang <[EMAIL PROTECTED]> > To: linux-dvb@linuxtv.org > Sent: Monday, January 28, 2008 11:20:10 AM > Subject: Re: [linux-dvb] [PATCH] XC5000 tuner improvement/clean up > > On Jan 27, 2008 6:50 PM, Chaogui Zhang <[EMAIL PROTECTED]> wrote: > > > > Download the newest v4l-dvb tree from http://linuxtv.org/hg/v4l-dvb > > and apply the patch against it. > > > > I just noticed that the previous patch that fixed the kernel oops has > been merged into the master tree, which conflicts with the patch for > tuner performance improvement(which contains the oops fixes too). I > regenerated the patch against the master tree and it is below. Please > use this one instead. > > -- > Chaogui Zhang > > Signed-off-by: Chaogui Zhang <[EMAIL PROTECTED]> > > diff -r ed7daeb29425 linux/drivers/media/dvb/frontends/xc5000.c > --- a/linux/drivers/media/dvb/frontends/xc5000.c Mon Jan 28 10:01:11 > 2008 -0200 > +++ b/linux/drivers/media/dvb/frontends/xc5000.c Sun Jan 27 19:36:07 > 2008 -0500 > @@ -3,6 +3,7 @@ > * > * Copyright (c) 2007 Xceive Corporation > * Copyright (c) 2007 Steven Toth <[EMAIL PROTECTED]> > + * Copyright (c) 2007, 2008 Chaogui Zhang <[EMAIL PROTECTED]> > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -38,6 +39,13 @@ MODULE_PARM_DESC(debug, "Turn on/off deb > > #define dprintk(level,fmt, arg...) if (debug >= level) \ > printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) > + > +static int allow_shutdown; > +module_param(allow_shutdown, int, 0644); > +MODULE_PARM_DESC(allow_shutdown, "Allow the XC5000 tuner to be shutdown > (default: no)."); > + > +static LIST_HEAD(xc5000_list); > +static DEFINE_MUTEX(xc5000_list_lock); > > #define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" > #define XC5000_DEFAULT_FIRMWARE_SIZE 12332 > @@ -179,7 +187,6 @@ XC_TV_STANDARD XC5000_Standard[MAX_TV_ST > > static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); > static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); > -static void xc5000_TunerReset(struct dvb_frontend *fe); > > static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) > { > @@ -195,29 +202,21 @@ static int xc_read_i2c_data(struct xc500 > > static int xc_reset(struct dvb_frontend *fe) > { > - xc5000_TunerReset(fe); > - return XC_RESULT_SUCCESS; > -} > - > -static void xc_wait(int wait_ms) > -{ > - msleep(wait_ms); > -} > - > -static void xc5000_TunerReset(struct dvb_frontend *fe) > -{ > struct xc5000_priv *priv = fe->tuner_priv; > int ret; > > dprintk(1, "%s()\n", __FUNCTION__); > > - if (priv->cfg->tuner_callback) { > - ret = priv->cfg->tuner_callback(priv->cfg->priv, > - XC5000_TUNER_RESET, 0); > - if (ret) > - printk(KERN_ERR "xc5000: reset failed\n"); > - } else > - printk(KERN_ERR "xc5000: no tuner reset callback function, > fatal\n"); > + if (!priv->cfg->tuner_callback) { > + printk(KERN_ERR > + "xc5000: no tuner reset callback function, fatal\n"); > + return XC_RESULT_RESET_FAILURE; > + } > + > + ret = priv->cfg->tuner_callback(priv->cfg->priv, > + XC5000_TUNER_RESET, 0); > + if (ret) printk(KERN_ERR "xc5000: reset failed\n"); > + return ret; > } > > static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 > i2cData) > @@ -245,7 +244,7 @@ static int xc_write_reg(struct xc5000_pr > /* busy flag cleared */ > break; > } else { > - xc_wait(100); /* wait 5 ms */ > + msleep(5); /* wait 5 ms */ > WatchDogTimer--; > } > } > @@ -296,7 +295,7 @@ static int xc_load_i2c_sequence(struct d > return result; > } else if (len & 0x8000) { > /* WAIT command */ > - xc_wait(len & 0x7FFF); > + msleep(len & 0x7FFF); > index += 2; > } else { > /* Send i2c data whilst ensuring individual transactions > @@ -352,11 +351,10 @@ static int xc_SetTVStandard(struct xc500 > > static int xc_shutdown(struct xc5000_priv *priv) > { > - return 0; > - /* Fixme: cannot bring tuner back alive once shutdown > - * without reloading the driver modules. > - * return xc_write_reg(priv, XREG_POWER_DOWN, 0); > - */ > + if(allow_shutdown) > + return xc_write_reg(priv, XREG_POWER_DOWN, 0); > + else > + return 0; > } > > static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) > @@ -496,7 +494,7 @@ static u16 WaitForLock(struct xc5000_pri > while ((lockState == 0) && (watchDogCount > 0)) { > xc_get_lock_status(priv, &lockState); > if (lockState != 1) { > - xc_wait(5); > + msleep(5); > watchDogCount--; > } > } > @@ -612,7 +610,7 @@ static void xc_debug_dump(struct xc5000_ > * Frame Lines needs two frame times after initial lock > * before it is valid. > */ > - xc_wait(100); > + msleep(100); > > xc_get_ADC_Envelope(priv, &adc_envelope); > dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); > @@ -640,13 +638,32 @@ static void xc_debug_dump(struct xc5000_ > dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); > } > > +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); > + > static int xc5000_set_params(struct dvb_frontend *fe, > struct dvb_frontend_parameters *params) > { > struct xc5000_priv *priv = fe->tuner_priv; > - int ret; > + int ret=0; > > dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, > params->frequency); > + > + mutex_lock(&priv->lock); > + > + if(priv->fwloaded == 0) { > + ret = xc_load_fw_and_init_tuner(fe); > + } > +#if 0 > + else { > + ret = xc_initialize(priv); > + msleep(100); > + } > +#endif > + if(ret != XC_RESULT_SUCCESS) { > + printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); > + mutex_unlock(&priv->lock); > + return -EREMOTEIO; > + } > > switch(params->u.vsb.modulation) { > case VSB_8: > @@ -667,6 +684,7 @@ static int xc5000_set_params(struct dvb_ > priv->video_standard = DTV6; > break; > default: > + mutex_unlock(&priv->lock); > return -EINVAL; > } > > @@ -678,6 +696,7 @@ static int xc5000_set_params(struct dvb_ > printk(KERN_ERR > "xc5000: xc_SetSignalSource(%d) failed\n", > priv->rf_mode); > + mutex_unlock(&priv->lock); > return -EREMOTEIO; > } > > @@ -686,6 +705,7 @@ static int xc5000_set_params(struct dvb_ > XC5000_Standard[priv->video_standard].AudioMode); > if (ret != XC_RESULT_SUCCESS) { > printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); > + mutex_unlock(&priv->lock); > return -EREMOTEIO; > } > > @@ -693,6 +713,7 @@ static int xc5000_set_params(struct dvb_ > if (ret != XC_RESULT_SUCCESS) { > printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", > priv->cfg->if_khz); > + mutex_unlock(&priv->lock); > return -EIO; > } > > @@ -701,22 +722,36 @@ static int xc5000_set_params(struct dvb_ > if (debug) > xc_debug_dump(priv); > > - return 0; > -} > - > -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); > + mutex_unlock(&priv->lock); > + return 0; > +} > > static int xc5000_set_analog_params(struct dvb_frontend *fe, > struct analog_parameters *params) > { > struct xc5000_priv *priv = fe->tuner_priv; > - int ret; > - > - if(priv->fwloaded == 0) > - xc_load_fw_and_init_tuner(fe); > + int ret=0; > > dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", > __FUNCTION__, params->frequency); > + > + mutex_lock(&priv->lock); > + > + if(priv->fwloaded == 0) { > + ret = xc_load_fw_and_init_tuner(fe); > + } > +#if 0 > + else { > + ret = xc_initialize(priv); > + msleep(100); > + } > +#endif > + > + if(ret != XC_RESULT_SUCCESS) { > + printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); > + mutex_unlock(&priv->lock); > + return -EREMOTEIO; > + } > > priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */ > > @@ -769,9 +804,10 @@ tune_channel: > 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); > + mutex_unlock(&priv->lock); > return -EREMOTEIO; > } > > @@ -780,6 +816,7 @@ tune_channel: > XC5000_Standard[priv->video_standard].AudioMode); > if (ret != XC_RESULT_SUCCESS) { > printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); > + mutex_unlock(&priv->lock); > return -EREMOTEIO; > } > > @@ -788,6 +825,7 @@ tune_channel: > if (debug) > xc_debug_dump(priv); > > + mutex_unlock(&priv->lock); > return 0; > } > > @@ -827,12 +865,11 @@ static int xc_load_fw_and_init_tuner(str > struct xc5000_priv *priv = fe->tuner_priv; > int ret = 0; > > - if (priv->fwloaded == 0) { > - ret = xc5000_fwupload(fe); > - if (ret != XC_RESULT_SUCCESS) > - return ret; > - priv->fwloaded = 1; > - } > + ret = xc5000_fwupload(fe); > + if (ret != XC_RESULT_SUCCESS) { > + return ret; > + } > + priv->fwloaded = 1; > > /* Start the tuner self-calibration process */ > ret |= xc_initialize(priv); > @@ -842,7 +879,7 @@ static int xc_load_fw_and_init_tuner(str > * I2C transactions until calibration is complete. This way we > * don't have to rely on clock stretching working. > */ > - xc_wait( 100 ); > + msleep( 100 ); > > /* Default to "CABLE" mode */ > ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); > @@ -857,21 +894,20 @@ static int xc5000_sleep(struct dvb_front > > dprintk(1, "%s()\n", __FUNCTION__); > > - /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized > - * once shutdown without reloading the driver. Maybe I am not > - * doing something right. > - * > - */ > + mutex_lock(&priv->lock); > > ret = xc_shutdown(priv); > if(ret != XC_RESULT_SUCCESS) { > printk(KERN_ERR > "xc5000: %s() unable to shutdown tuner\n", > __FUNCTION__); > + mutex_unlock(&priv->lock); > return -EREMOTEIO; > } > else { > - /* priv->fwloaded = 0; */ > + if(allow_shutdown) > + priv->fwloaded = 0; /* was indeed shutdown */ > + mutex_unlock(&priv->lock); > return XC_RESULT_SUCCESS; > } > } > @@ -879,24 +915,51 @@ static int xc5000_init(struct dvb_fronte > static int xc5000_init(struct dvb_frontend *fe) > { > struct xc5000_priv *priv = fe->tuner_priv; > + int ret; > + > dprintk(1, "%s()\n", __FUNCTION__); > > - if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { > + mutex_lock(&priv->lock); > + > + if(priv->fwloaded == 0) { > + ret = xc_load_fw_and_init_tuner(fe); > + } > + else { /* Firmware has been loaded previously, just initialize */ > + ret = xc_initialize(priv); > + msleep(100); > + ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); > + } > + > + if(ret != XC_RESULT_SUCCESS) { > printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); > + mutex_unlock(&priv->lock); > return -EREMOTEIO; > } > > if (debug) > xc_debug_dump(priv); > > + mutex_unlock(&priv->lock); > return 0; > } > > static int xc5000_release(struct dvb_frontend *fe) > { > + struct xc5000_priv *priv = fe->tuner_priv; > + > dprintk(1, "%s()\n", __FUNCTION__); > - kfree(fe->tuner_priv); > + > + mutex_lock(&xc5000_list_lock); > + > + priv->count--; > + if(priv->count == 0) { > + list_del(&priv->xc5000_list); > + kfree(priv); > + } > fe->tuner_priv = NULL; > + > + mutex_unlock(&xc5000_list_lock); > + > return 0; > } > > @@ -924,23 +987,49 @@ struct dvb_frontend * xc5000_attach(stru > struct xc5000_config *cfg) > { > struct xc5000_priv *priv = NULL; > + void *cfg_priv; > u16 id = 0; > > dprintk(1, "%s()\n", __FUNCTION__); > > - priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); > - if (priv == NULL) > + if (NULL == cfg || NULL == cfg->priv || NULL == fe) > return NULL; > > - priv->cfg = cfg; > - priv->bandwidth = BANDWIDTH_6_MHZ; > - priv->i2c = i2c; > + cfg_priv = cfg->priv; > + > + mutex_lock(&xc5000_list_lock); > + > + list_for_each_entry(priv, &xc5000_list, xc5000_list) { > + if (priv->cfg->priv == cfg->priv) { > + cfg_priv = NULL; > + break; > + } > + } > + > + if(cfg_priv) { > + priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); > + if (priv == NULL) { > + mutex_unlock(&xc5000_list_lock); > + return NULL; > + } > + > + priv->cfg = cfg; > + priv->bandwidth = BANDWIDTH_6_MHZ; > + priv->i2c = i2c; > + priv->fwloaded = 0; > + priv->count = 0; > + > + mutex_init(&priv->lock); > + list_add_tail(&priv->xc5000_list, &xc5000_list); > + } > + > > /* Check if firmware has been loaded. It is possible that another > instance of the driver has loaded the firmware. > */ > if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { > kfree(priv); > + mutex_unlock(&xc5000_list_lock); > return NULL; > } > > @@ -966,6 +1055,7 @@ struct dvb_frontend * xc5000_attach(stru > "xc5000: Device not found at addr 0x%02x (0x%x)\n", > cfg->i2c_address, id); > kfree(priv); > + mutex_unlock(&xc5000_list_lock); > return NULL; > } > > @@ -973,11 +1063,14 @@ struct dvb_frontend * xc5000_attach(stru > sizeof(struct dvb_tuner_ops)); > > fe->tuner_priv = priv; > - > + priv->count++; > + > + mutex_unlock(&xc5000_list_lock); > return fe; > } > EXPORT_SYMBOL(xc5000_attach); > > MODULE_AUTHOR("Steven Toth"); > +MODULE_AUTHOR("Chaogui Zhang"); > MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); > MODULE_LICENSE("GPL"); > diff -r ed7daeb29425 linux/drivers/media/dvb/frontends/xc5000_priv.h > --- a/linux/drivers/media/dvb/frontends/xc5000_priv.h Mon Jan 28 > 10:01:11 2008 -0200 > +++ b/linux/drivers/media/dvb/frontends/xc5000_priv.h Fri Jan 25 > 11:46:34 2008 -0500 > @@ -23,6 +23,7 @@ > #define XC5000_PRIV_H > > struct xc5000_priv { > + struct list_head xc5000_list; > struct xc5000_config *cfg; > struct i2c_adapter *i2c; > > @@ -31,6 +32,14 @@ struct xc5000_priv { > u8 video_standard; > u8 rf_mode; > u8 fwloaded; > + > + int count; > + > +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16) > + struct mutex lock; > +#else > + struct semaphore lock; > +#endif > }; > > #endif > > Greeting Chaogui, > I have been reading about the patch clean up for the xc5000 tuner. I am > still new to the whole driver making and the like. My question is how do I > apply this clean up? I have a pinnicale 800i card, and had to get this in > order to get my tuner card working. Any assistance would be greatly > appreciated. > Thanks, > Ed > _______________________________________________ > linux-dvb mailing list > linux-dvb@linuxtv.org > http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb > > > ------------------------------ > Looking for last minute shopping deals? Find them fast with Yahoo! > Search.<http://us.rd.yahoo.com/evt=51734/*http://tools.search.yahoo.com/newsearch/category.php?category=shopping> > > _______________________________________________ > linux-dvb mailing list > linux-dvb@linuxtv.org > http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb
Chaogui was kind enough to explain to me how to do this. You download the latest version of the source from http://linuxtv.org/hg/v4l-dvb and extract it save the patch in chaogui's email to a text file called "patchfile" and put it in the folder you extracted open a terminal and change to that folder, then do this: ln -s . a ln -s . b patch -p0 < patchfile you should see 2 lines if the patch is successful, if you get errors, let me know. assuming it is successful , then you: make sudo make install Regards, John
_______________________________________________ linux-dvb mailing list linux-dvb@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb