2008/1/31 Muppet Man <muppetman4662@xxxxxxxxx>:
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
Greeting Chaogui,----- Original Message ----
From: Chaogui Zhang <czhang1974@xxxxxxxxx>
To: linux-dvb@xxxxxxxxxxx
Sent: Monday, January 28, 2008 11:20:10 AM
Subject: Re: [PATCH] XC5000 tuner improvement/clean up
On Jan 27, 2008 6:50 PM, Chaogui Zhang <czhang1974@xxxxxxxxx> 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@xxxxxxxxx>
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@xxxxxxxxxxxxx>
+ * Copyright (c) 2007, 2008 Chaogui Zhang <czhang1974@xxxxxxxxx>
*
* 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
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@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
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@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb