[linux-dvb] [PATCH] XC5000 tuner improvement/clean up

John Massengale johnrobertmassengale at gmail.com
Thu Jan 31 18:41:47 CET 2008


2008/1/31 Muppet Man <muppetman4662 at yahoo.com>:

>
>
> ----- Original Message ----
> From: Chaogui Zhang <czhang1974 at gmail.com>
> To: linux-dvb at 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 <czhang1974 at gmail.com> 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 <czhang1974 at gmail.com>
>
> 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 <stoth at hauppauge.com>
> + *  Copyright (c) 2007, 2008 Chaogui Zhang <czhang1974 at gmail.com>
>   *
>   *  This program is free software; you can redistribute it and/or modify
>   *  it under the terms of the GNU General Public License as published by
> @@ -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 at 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 at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.linuxtv.org/pipermail/linux-dvb/attachments/20080131/d1b87179/attachment-0001.htm 


More information about the linux-dvb mailing list