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