Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
de3fe21b
Commit
de3fe21b
authored
Oct 24, 2007
by
Mauro Carvalho Chehab
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
V4L/DVB (6431): Improve firmware format
Signed-off-by:
Mauro Carvalho Chehab
<
mchehab@infradead.org
>
parent
215b95ba
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
455 additions
and
111 deletions
+455
-111
drivers/media/video/tuner-xc2028-types.h
drivers/media/video/tuner-xc2028-types.h
+99
-0
drivers/media/video/tuner-xc2028.c
drivers/media/video/tuner-xc2028.c
+344
-108
drivers/media/video/tuner-xc2028.h
drivers/media/video/tuner-xc2028.h
+12
-3
No files found.
drivers/media/video/tuner-xc2028-types.h
0 → 100644
View file @
de3fe21b
/* tuner-xc2028_types
*
* Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License v2
*/
/* xc3028 firmware types */
/* BASE firmware should be loaded before any other firmware */
#define BASE (1<<0)
/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
#define F8MHZ (1<<1)
/* Multichannel Television Sound (MTS)
Those firmwares are capable of using xc2038 DSP to decode audio and
produce a baseband audio output on some pins of the chip.
There are MTS firmwares for the most used video standards. It should be
required to use MTS firmwares, depending on the way audio is routed into
the bridge chip
*/
#define MTS (1<<2)
/* FIXME: I have no idea what's the difference between
D2620 and D2633 firmwares
*/
#define D2620 (1<<3)
#define D2633 (1<<4)
/* DTV firmwares for 6, 7 and 8 MHz
DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
DTV8 - 8MHz - DVB-C/DVB-T
*/
#define DTV6_ATSC (1<<5)
#define DTV6_QAM (1<<6)
#define DTV7 (1<<7)
#define DTV78 (1<<8)
#define DTV8 (1<<9)
/* There's a FM | BASE firmware + FM specific firmware (std=0) */
#define FM (1<<10)
/* Applies only for FM firmware
Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
*/
#define INPUT1 (1<<11)
/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
There are variants both with and without NOGD
*/
#define LCD (1<<12)
/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
*/
#define NOGD (1<<13)
/* Old firmwares were broken into init0 and init1 */
#define INIT1 (1<<14)
/* Newer types to be moved to videodev2.h */
#define V4L2_STD_SECAM_K3 (0x02000000)
/* Audio types */
#define V4L2_STD_A2_A (1L<<32)
#define V4L2_STD_A2_B (1L<<33)
#define V4L2_STD_NICAM_A (1L<<34)
#define V4L2_STD_NICAM_B (1L<<35)
#define V4L2_STD_AM (1L<<36)
#define V4L2_STD_BTSC (1L<<37)
#define V4L2_STD__EIAJ (1L<<38)
#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B)
#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
/* To preserve backward compatibilty,
(std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
*/
#define V4L2_STD_AUDIO (V4L2_STD_A2 | \
V4L2_STD_NICAM | \
V4L2_STD_AM | \
V4L2_STD_BTSC | \
V4L2_STD_EIAJ)
/* Used standards with audio restrictions */
#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A)
#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B)
#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2)
#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM)
#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM)
#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM)
drivers/media/video/tuner-xc2028.c
View file @
de3fe21b
...
...
@@ -15,6 +15,7 @@
#include <linux/mutex.h>
#include "tuner-i2c.h"
#include "tuner-xc2028.h"
#include "tuner-xc2028-types.h"
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
...
...
@@ -22,21 +23,13 @@
#define PREFIX "xc2028 "
static
LIST_HEAD
(
xc2028_list
);
/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */
/* Generic firmwares */
static
const
char
*
firmware_INIT0
=
"tm_xc3028_MTS_init0.fw"
;
static
const
char
*
firmware_8MHZ_INIT0
=
"tm_xc3028_8M_MTS_init0.fw"
;
static
const
char
*
firmware_INIT1
=
"tm_xc3028_68M_MTS_init1.fw"
;
/* Standard-specific firmwares */
static
const
char
*
firmware_6M
=
"tm_xc3028_DTV_6M.fw"
;
static
const
char
*
firmware_7M
=
"tm_xc3028_DTV_7M.fw"
;
static
const
char
*
firmware_8M
=
"tm_xc3028_DTV_8M.fw"
;
static
const
char
*
firmware_B
=
"tm_xc3028_B_PAL.fw"
;
static
const
char
*
firmware_DK
=
"tm_xc3028_DK_PAL_MTS.fw"
;
static
const
char
*
firmware_MN
=
"tm_xc3028_MN_BTSC.fw"
;
/* struct for storing firmware table */
struct
firmware_description
{
unsigned
int
type
;
v4l2_std_id
id
;
unsigned
char
*
ptr
;
unsigned
int
size
;
};
struct
xc2028_data
{
struct
list_head
xc2028_list
;
...
...
@@ -46,7 +39,14 @@ struct xc2028_data {
struct
device
*
dev
;
void
*
video_dev
;
int
count
;
u32
frequency
;
__u32
frequency
;
struct
firmware_description
*
firm
;
int
firm_size
;
__u16
version
;
struct
xc2028_ctrl
ctrl
;
v4l2_std_id
firm_type
;
/* video stds supported
by current firmware */
...
...
@@ -54,6 +54,9 @@ struct xc2028_data {
6M, 7M or 8M */
int
need_load_generic
;
/* The generic firmware
were loaded? */
int
max_len
;
/* Max firmware chunk */
enum
tuner_mode
mode
;
struct
i2c_client
*
i2c_client
;
...
...
@@ -102,92 +105,263 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
return
(
buf
[
1
])
|
(
buf
[
0
]
<<
8
);
}
static
int
load_firmware
(
struct
dvb_frontend
*
fe
,
const
char
*
name
)
static
void
free_firmware
(
struct
xc2028_data
*
priv
)
{
int
i
;
if
(
!
priv
->
firm
)
return
;
for
(
i
=
0
;
i
<
priv
->
firm_size
;
i
++
)
{
if
(
priv
->
firm
[
i
].
ptr
)
kfree
(
priv
->
firm
[
i
].
ptr
);
}
kfree
(
priv
->
firm
);
priv
->
firm
=
NULL
;
priv
->
need_load_generic
=
1
;
}
static
int
load_all_firmwares
(
struct
dvb_frontend
*
fe
)
{
struct
xc2028_data
*
priv
=
fe
->
tuner_priv
;
const
struct
firmware
*
fw
=
NULL
;
unsigned
char
*
p
,
*
endp
;
int
len
=
0
,
rc
=
0
;
static
const
char
firmware_ver
[]
=
"tm6000/xcv v1"
;
int
rc
=
0
,
n
,
n_array
;
char
name
[
33
]
;
tuner_info
(
"%s called
\n
"
,
__FUNCTION__
);
tuner_info
(
"Loading firmware %s
\n
"
,
name
);
rc
=
request_firmware
(
&
fw
,
name
,
priv
->
dev
);
tuner_info
(
"Loading firmware %s
\n
"
,
priv
->
ctrl
.
f
name
);
rc
=
request_firmware
(
&
fw
,
priv
->
ctrl
.
f
name
,
priv
->
dev
);
if
(
rc
<
0
)
{
if
(
rc
==-
ENOENT
)
tuner_info
(
"Error: firmware %s not found.
\n
"
,
name
);
tuner_info
(
"Error: firmware %s not found.
\n
"
,
priv
->
ctrl
.
fname
);
else
tuner_info
(
"Error %d while requesting firmware %s
\n
"
,
rc
,
name
);
tuner_info
(
"Error %d while requesting firmware %s
\n
"
,
rc
,
priv
->
ctrl
.
fname
);
return
rc
;
}
p
=
fw
->
data
;
endp
=
p
+
fw
->
size
;
if
(
fw
->
size
==
0
)
{
if
(
fw
->
size
<
sizeof
(
name
)
-
1
+
2
)
{
tuner_info
(
"Error: firmware size is zero!
\n
"
);
rc
=-
EINVAL
;
goto
err
;
goto
done
;
}
if
(
fw
->
size
<
sizeof
(
firmware_ver
)
-
1
)
{
/* Firmware is incorrect */
tuner_info
(
"Error: firmware size is less than header (%d<%d)!
\n
"
,
(
int
)
fw
->
size
,(
int
)
sizeof
(
firmware_ver
)
-
1
);
rc
=-
EINVAL
;
memcpy
(
name
,
p
,
sizeof
(
name
)
-
1
);
name
[
sizeof
(
name
)
-
1
]
=
0
;
p
+=
sizeof
(
name
)
-
1
;
priv
->
version
=
le16_to_cpu
(
*
(
__u16
*
)
p
);
p
+=
2
;
tuner_info
(
"firmware: %s, ver %d.%d
\n
"
,
name
,
priv
->
version
>>
8
,
priv
->
version
&
0xff
);
if
(
p
+
2
>
endp
)
goto
corrupt
;
n_array
=
le16_to_cpu
(
*
(
__u16
*
)
p
);
p
+=
2
;
tuner_info
(
"there are %d firmwares at %s
\n
"
,
n_array
,
priv
->
ctrl
.
fname
);
priv
->
firm
=
kzalloc
(
sizeof
(
*
priv
->
firm
)
*
n_array
,
GFP_KERNEL
);
if
(
!
fw
)
{
tuner_info
(
"Not enough memory for loading firmware.
\n
"
);
rc
=-
ENOMEM
;
goto
done
;
}
priv
->
firm_size
=
n_array
;
n
=-
1
;
while
(
p
<
endp
)
{
__u32
type
,
size
;
v4l2_std_id
id
;
n
++
;
if
(
n
>=
n_array
)
{
tuner_info
(
"Too much firmwares at the file
\n
"
);
goto
corrupt
;
}
/* Checks if there's enough bytes to read */
if
(
p
+
sizeof
(
type
)
+
sizeof
(
id
)
+
sizeof
(
size
)
>
endp
)
{
tuner_info
(
"Lost firmware!
\n
"
);
goto
corrupt
;
}
type
=
le32_to_cpu
(
*
(
__u32
*
)
p
);
p
+=
sizeof
(
type
);
id
=
le64_to_cpu
(
*
(
v4l2_std_id
*
)
p
);
p
+=
sizeof
(
id
);
size
=
le32_to_cpu
(
*
(
v4l2_std_id
*
)
p
);
p
+=
sizeof
(
size
);
if
((
!
size
)
||
(
size
+
p
>
endp
))
{
tuner_info
(
"Firmware type %x, id %lx corrupt
\n
"
,
type
,
(
unsigned
long
)
id
);
goto
corrupt
;
}
priv
->
firm
[
n
].
ptr
=
kzalloc
(
size
,
GFP_KERNEL
);
if
(
!
priv
->
firm
[
n
].
ptr
)
{
tuner_info
(
"Not enough memory.
\n
"
);
rc
=-
ENOMEM
;
goto
err
;
}
tuner_info
(
"Loading firmware type %x, id %lx, size=%d.
\n
"
,
type
,
(
unsigned
long
)
id
,
size
);
memcpy
(
priv
->
firm
[
n
].
ptr
,
p
,
size
);
priv
->
firm
[
n
].
type
=
type
;
priv
->
firm
[
n
].
id
=
id
;
priv
->
firm
[
n
].
size
=
size
;
p
+=
size
;
}
if
(
memcmp
(
p
,
firmware_ver
,
sizeof
(
firmware_ver
)
-
1
))
{
/* Firmware is incorrect */
tuner_info
(
"Error: firmware is not for tm5600/6000 + Xcv2028/3028!
\n
"
);
if
(
n
+
1
!=
priv
->
firm_size
)
{
tuner_info
(
"Firmware file is incomplete!
\n
"
);
goto
corrupt
;
}
goto
done
;
corrupt:
rc
=-
EINVAL
;
goto
err
;
tuner_info
(
"Error: firmware file is corrupted!
\n
"
);
err:
tuner_info
(
"Releasing loaded firmware file.
\n
"
);
free_firmware
(
priv
);
done:
release_firmware
(
fw
);
tuner_info
(
"Firmware files loaded.
\n
"
);
return
rc
;
}
static
int
load_firmware
(
struct
dvb_frontend
*
fe
,
unsigned
int
type
,
v4l2_std_id
*
id
)
{
struct
xc2028_data
*
priv
=
fe
->
tuner_priv
;
int
i
,
rc
;
unsigned
char
*
p
,
*
endp
,
buf
[
priv
->
max_len
];
tuner_info
(
"%s called
\n
"
,
__FUNCTION__
);
if
(
!
priv
->
firm
)
{
printk
(
KERN_ERR
PREFIX
"Error! firmware not loaded
\n
"
);
return
-
EINVAL
;
}
p
+=
sizeof
(
firmware_ver
)
-
1
;
while
(
p
<
endp
)
{
if
((
*
p
)
&
0x80
)
{
if
((
type
==
0
)
&&
(
*
id
==
0
))
*
id
=
V4L2_STD_PAL
;
/* Seek for exact match */
for
(
i
=
0
;
i
<
priv
->
firm_size
;
i
++
)
{
if
(
(
type
==
priv
->
firm
[
i
].
type
)
&&
(
*
id
==
priv
->
firm
[
i
].
id
))
goto
found
;
}
/* Seek for generic video standard match */
for
(
i
=
0
;
i
<
priv
->
firm_size
;
i
++
)
{
if
(
(
type
==
priv
->
firm
[
i
].
type
)
&&
(
*
id
&
priv
->
firm
[
i
].
id
))
goto
found
;
}
/*FIXME: Would make sense to seek for type "hint" match ? */
tuner_info
(
"Can't find firmware for type=%x, id=%lx
\n
"
,
type
,
(
long
int
)
*
id
);
return
-
EINVAL
;
found:
*
id
=
priv
->
firm
[
i
].
id
;
tuner_info
(
"Found firmware for type=%x, id=%lx
\n
"
,
type
,
(
long
int
)
*
id
);
p
=
priv
->
firm
[
i
].
ptr
;
if
(
!
p
)
{
printk
(
KERN_ERR
PREFIX
"Firmware pointer were freed!"
);
return
-
EINVAL
;
}
endp
=
p
+
priv
->
firm
[
i
].
size
;
while
(
p
<
endp
)
{
__u16
size
;
/* Checks if there's enough bytes to read */
if
(
p
+
sizeof
(
size
)
>
endp
)
{
tuner_info
(
"missing bytes
\n
"
);
return
-
EINVAL
;
}
size
=
le16_to_cpu
(
*
(
__u16
*
)
p
);
p
+=
sizeof
(
size
);
if
(
size
==
0xffff
)
return
0
;
if
(
!
size
)
{
/* Special callback command received */
rc
=
priv
->
tuner_callback
(
priv
->
video_dev
,
XC2028_TUNER_RESET
,
(
*
p
)
&
0x7f
);
XC2028_TUNER_RESET
,
0
);
if
(
rc
<
0
)
{
tuner_info
(
"Error at RESET code %d
\n
"
,
(
*
p
)
&
0x7f
);
goto
err
;
return
-
EINVAL
;
}
p
++
;
continue
;
}
len
=*
p
;
p
++
;
if
(
p
+
len
+
1
>
endp
)
{
/* Firmware is incorrect */
tuner_info
(
"Error: firmware is truncated!
\n
"
);
rc
=-
EINVAL
;
goto
err
;
}
if
(
len
<=
0
)
{
tuner_info
(
"Error: firmware file is corrupted!
\n
"
);
rc
=-
EINVAL
;
goto
err
;
/* Checks for a sleep command */
if
(
size
&
0x8000
)
{
msleep
(
size
&
0x7fff
);
continue
;
}
i2c_send
(
rc
,
priv
,
p
,
len
);
if
(
rc
<
0
)
goto
err
;
p
+=
len
;
if
((
size
+
p
>
endp
))
{
tuner_info
(
"missing bytes: need %d, have %d
\n
"
,
size
,
(
int
)(
endp
-
p
));
return
-
EINVAL
;
}
if
(
*
p
)
msleep
(
*
p
);
buf
[
0
]
=
*
p
;
p
++
;
}
size
--
;
/* Sends message chunks */
while
(
size
>
0
)
{
int
len
=
(
size
<
priv
->
max_len
-
1
)
?
size
:
priv
->
max_len
-
1
;
err:
release_firmware
(
fw
);
memcpy
(
buf
+
1
,
p
,
len
);
return
rc
;
i2c_send
(
rc
,
priv
,
buf
,
len
+
1
);
if
(
rc
<
0
)
{
tuner_info
(
"%d returned from send
\n
"
,
rc
);
return
-
EINVAL
;
}
p
+=
len
;
size
-=
len
;
}
}
return
-
EINVAL
;
}
static
int
check_firmware
(
struct
dvb_frontend
*
fe
,
enum
tuner_mode
new_mode
,
...
...
@@ -196,11 +370,21 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
{
struct
xc2028_data
*
priv
=
fe
->
tuner_priv
;
int
rc
,
version
;
const
char
*
name
;
v4l2_std_id
std0
=
0
;
unsigned
int
type0
=
0
,
type
=
0
;
int
change_digital_bandwidth
;
tuner_info
(
"%s called
\n
"
,
__FUNCTION__
);
if
(
!
priv
->
firm
)
{
if
(
!
priv
->
ctrl
.
fname
)
return
-
EINVAL
;
rc
=
load_all_firmwares
(
fe
);
if
(
rc
<
0
)
return
rc
;
}
tuner_info
(
"I am in mode %u and I should switch to mode %i
\n
"
,
priv
->
mode
,
new_mode
);
...
...
@@ -216,20 +400,28 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
bandwidth
);
if
(
priv
->
need_load_generic
)
{
if
(
priv
->
bandwidth
==
8
)
name
=
firmware_8MHZ_INIT0
;
else
name
=
firmware_INIT0
;
/* Reset is needed before loading firmware */
rc
=
priv
->
tuner_callback
(
priv
->
video_dev
,
XC2028_TUNER_RESET
,
0
);
if
(
rc
<
0
)
return
rc
;
rc
=
load_firmware
(
fe
,
name
);
if
(
rc
<
0
)
type0
=
BASE
;
if
(
priv
->
ctrl
.
type
==
XC2028_FIRM_MTS
)
type0
|=
MTS
;
if
(
priv
->
bandwidth
==
8
)
type0
|=
F8MHZ
;
/* FIXME: How to load FM and FM|INPUT1 firmwares? */
rc
=
load_firmware
(
fe
,
type0
,
&
std0
);
if
(
rc
<
0
)
{
tuner_info
(
"Error %d while loading generic firmware
\n
"
,
rc
);
return
rc
;
}
priv
->
need_load_generic
=
0
;
priv
->
firm_type
=
0
;
...
...
@@ -241,19 +433,23 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
tuner_info
(
"I should change bandwidth %u
\n
"
,
change_digital_bandwidth
);
/* FIXME: t->std makes no sense here */
if
(
change_digital_bandwidth
)
{
/*FIXME: Should allow selecting between D2620 and D2633 */
type
|=
D2620
;
/* FIXME: When should select a DTV78 firmware?
*/
switch
(
bandwidth
)
{
case
BANDWIDTH_8_MHZ
:
std
=
V4L2_STD_DTV_8MHZ
;
type
|=
DTV8
;
break
;
case
BANDWIDTH_7_MHZ
:
std
=
V4L2_STD_DTV_7MHZ
;
type
|=
DTV7
;
break
;
case
BANDWIDTH_6_MHZ
:
std
=
V4L2_STD_DTV_6MHZ
;
/* FIXME: Should allow select also ATSC */
type
|=
DTV6_QAM
;
break
;
default:
...
...
@@ -262,28 +458,28 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
priv
->
bandwidth
=
bandwidth
;
}
/* Load INIT1, if needed */
tuner_info
(
"Trying to load init1 firmware
\n
"
);
type0
=
BASE
|
INIT1
|
priv
->
ctrl
.
type
;
if
(
priv
->
ctrl
.
type
==
XC2028_FIRM_MTS
)
type0
|=
MTS
;
/* FIXME: Should handle errors - if INIT1 found */
rc
=
load_firmware
(
fe
,
type0
,
&
std0
);
/* FIXME: Should add support for FM radio
*/
if
(
priv
->
ctrl
.
type
==
XC2028_FIRM_MTS
)
type
|=
MTS
;
tuner_info
(
"firmware standard to load: %08lx
\n
"
,(
unsigned
long
)
std
);
if
(
priv
->
firm_type
&
std
)
{
tuner_info
(
"
xc3028:
no need to load a std-specific firmware.
\n
"
);
tuner_info
(
"no need to load a std-specific firmware.
\n
"
);
return
0
;
}
rc
=
load_firmware
(
fe
,
firmware_INIT1
);
if
(
std
&
V4L2_STD_MN
)
name
=
firmware_MN
;
else
if
(
std
&
V4L2_STD_DTV_6MHZ
)
name
=
firmware_6M
;
else
if
(
std
&
V4L2_STD_DTV_7MHZ
)
name
=
firmware_7M
;
else
if
(
std
&
V4L2_STD_DTV_8MHZ
)
name
=
firmware_8M
;
else
if
(
std
&
V4L2_STD_PAL_B
)
name
=
firmware_B
;
else
name
=
firmware_DK
;
tuner_info
(
"loading firmware named %s.
\n
"
,
name
);
rc
=
load_firmware
(
fe
,
name
);
rc
=
load_firmware
(
fe
,
type
,
&
std
);
if
(
rc
<
0
)
return
rc
;
...
...
@@ -341,11 +537,11 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
tuner_info
(
"%s called
\n
"
,
__FUNCTION__
);
mutex_lock
(
&
priv
->
lock
);
/* HACK: It seems that specific firmware need to be reloaded
when freq is changed */
mutex_lock
(
&
priv
->
lock
);
priv
->
firm_type
=
0
;
/* Reset GPIO 1 */
...
...
@@ -365,7 +561,13 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
div
=
(
freq
-
offset
+
DIV
/
2
)
/
DIV
;
/* CMD= Set frequency */
if
(
priv
->
version
<
0x0202
)
{
send_seq
(
priv
,
{
0x00
,
0x02
,
0x00
,
0x00
});
}
else
{
send_seq
(
priv
,
{
0x80
,
0x02
,
0x00
,
0x00
});
}
rc
=
priv
->
tuner_callback
(
priv
->
video_dev
,
XC2028_RESET_CLK
,
1
);
if
(
rc
<
0
)
goto
ret
;
...
...
@@ -436,8 +638,13 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
priv
->
count
--
;
if
(
!
priv
->
count
)
if
(
!
priv
->
count
)
{
if
(
priv
->
ctrl
.
fname
)
kfree
(
priv
->
ctrl
.
fname
);
free_firmware
(
priv
);
kfree
(
priv
);
}
return
0
;
}
...
...
@@ -453,6 +660,32 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
return
0
;
}
static
int
xc2028_set_config
(
struct
dvb_frontend
*
fe
,
void
*
priv_cfg
)
{
struct
xc2028_data
*
priv
=
fe
->
tuner_priv
;
struct
xc2028_ctrl
*
p
=
priv_cfg
;
tuner_info
(
"%s called
\n
"
,
__FUNCTION__
);
priv
->
ctrl
.
type
=
p
->
type
;
if
(
p
->
fname
)
{
if
(
priv
->
ctrl
.
fname
)
kfree
(
priv
->
ctrl
.
fname
);
priv
->
ctrl
.
fname
=
kmalloc
(
strlen
(
p
->
fname
)
+
1
,
GFP_KERNEL
);
if
(
!
priv
->
ctrl
.
fname
)
return
-
ENOMEM
;
free_firmware
(
priv
);
strcpy
(
priv
->
ctrl
.
fname
,
p
->
fname
);
}
tuner_info
(
"%s OK
\n
"
,
__FUNCTION__
);
return
0
;
}
static
const
struct
dvb_tuner_ops
xc2028_dvb_tuner_ops
=
{
.
info
=
{
.
name
=
"Xceive XC3028"
,
...
...
@@ -461,6 +694,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.
frequency_step
=
50000
,
},
.
set_config
=
xc2028_set_config
,
.
set_analog_params
=
xc2028_set_tv_freq
,
.
release
=
xc2028_dvb_release
,
.
get_frequency
=
xc2028_get_frequency
,
...
...
@@ -513,6 +747,8 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
priv
->
dev
=
dev
;
priv
->
video_dev
=
video_dev
;
priv
->
tuner_callback
=
tuner_callback
;
priv
->
max_len
=
13
;
mutex_init
(
&
priv
->
lock
);
...
...
drivers/media/video/tuner-xc2028.h
View file @
de3fe21b
...
...
@@ -9,13 +9,22 @@
#include "dvb_frontend.h"
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
enum
xc2028_firm_type
{
XC2028_FIRM_NORMAL
,
XC2028_FIRM_MTS
,
};
struct
xc2028_ctrl
{
enum
xc2028_firm_type
type
;
char
*
fname
;
};
/* xc2028 commands for callback */
#define XC2028_TUNER_RESET 0
#define XC2028_RESET_CLK 1
struct
dvb_frontend
;
struct
i2c_client
;
#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
int
xc2028_attach
(
struct
dvb_frontend
*
fe
,
struct
i2c_adapter
*
i2c_adap
,
u8
i2c_addr
,
struct
device
*
dev
,
void
*
video_dev
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment