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
ca583a3c
Commit
ca583a3c
authored
Jan 22, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://lia64.bkbits.net/linux-ia64-release-2.6.11
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
97231034
47d3a8f9
Changes
54
Show whitespace changes
Inline
Side-by-side
Showing
54 changed files
with
4848 additions
and
2273 deletions
+4848
-2273
Documentation/dvb/README.dibusb
Documentation/dvb/README.dibusb
+44
-16
Documentation/dvb/get_dvb_firmware
Documentation/dvb/get_dvb_firmware
+19
-1
arch/ppc64/kernel/signal.c
arch/ppc64/kernel/signal.c
+2
-2
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_core.c
+2
-2
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/b2c2/Kconfig
+4
-2
drivers/media/dvb/b2c2/b2c2-usb-core.c
drivers/media/dvb/b2c2/b2c2-usb-core.c
+12
-2
drivers/media/dvb/b2c2/skystar2.c
drivers/media/dvb/b2c2/skystar2.c
+194
-160
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/Kconfig
+2
-3
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
+80
-2
drivers/media/dvb/bt8xx/dvb-bt8xx.h
drivers/media/dvb/bt8xx/dvb-bt8xx.h
+6
-0
drivers/media/dvb/dibusb/Kconfig
drivers/media/dvb/dibusb/Kconfig
+9
-5
drivers/media/dvb/dibusb/Makefile
drivers/media/dvb/dibusb/Makefile
+8
-0
drivers/media/dvb/dibusb/dvb-dibusb-core.c
drivers/media/dvb/dibusb/dvb-dibusb-core.c
+471
-0
drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
+205
-0
drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
+598
-0
drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
+85
-0
drivers/media/dvb/dibusb/dvb-dibusb-pid.c
drivers/media/dvb/dibusb/dvb-dibusb-pid.c
+80
-0
drivers/media/dvb/dibusb/dvb-dibusb-remote.c
drivers/media/dvb/dibusb/dvb-dibusb-remote.c
+197
-0
drivers/media/dvb/dibusb/dvb-dibusb-usb.c
drivers/media/dvb/dibusb/dvb-dibusb-usb.c
+259
-0
drivers/media/dvb/dibusb/dvb-dibusb.c
drivers/media/dvb/dibusb/dvb-dibusb.c
+0
-1032
drivers/media/dvb/dibusb/dvb-dibusb.h
drivers/media/dvb/dibusb/dvb-dibusb.h
+228
-258
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_demux.c
+40
-18
drivers/media/dvb/dvb-core/dvb_demux.h
drivers/media/dvb/dvb-core/dvb_demux.h
+1
-0
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.c
+198
-147
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_frontend.h
+1
-22
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvb_net.c
+10
-4
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Kconfig
+12
-0
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/Makefile
+2
-0
drivers/media/dvb/frontends/dib3000-common.c
drivers/media/dvb/frontends/dib3000-common.c
+1
-63
drivers/media/dvb/frontends/dib3000-common.h
drivers/media/dvb/frontends/dib3000-common.h
+11
-27
drivers/media/dvb/frontends/dib3000.h
drivers/media/dvb/frontends/dib3000.h
+10
-11
drivers/media/dvb/frontends/dib3000mb.c
drivers/media/dvb/frontends/dib3000mb.c
+27
-25
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dib3000mc.c
+300
-229
drivers/media/dvb/frontends/dib3000mc_priv.h
drivers/media/dvb/frontends/dib3000mc_priv.h
+23
-34
drivers/media/dvb/frontends/mt352.c
drivers/media/dvb/frontends/mt352.c
+18
-6
drivers/media/dvb/frontends/mt352.h
drivers/media/dvb/frontends/mt352.h
+1
-0
drivers/media/dvb/frontends/nxt2002.c
drivers/media/dvb/frontends/nxt2002.c
+670
-0
drivers/media/dvb/frontends/nxt2002.h
drivers/media/dvb/frontends/nxt2002.h
+23
-0
drivers/media/dvb/frontends/stv0297.c
drivers/media/dvb/frontends/stv0297.c
+63
-31
drivers/media/dvb/frontends/stv0297.h
drivers/media/dvb/frontends/stv0297.h
+3
-0
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda10021.c
+1
-1
drivers/media/dvb/frontends/tda10021.h
drivers/media/dvb/frontends/tda10021.h
+1
-1
drivers/media/dvb/frontends/tda80xx.c
drivers/media/dvb/frontends/tda80xx.c
+1
-1
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.c
+507
-85
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110.h
+13
-1
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_hw.c
+62
-30
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/av7110_v4l.c
+2
-2
drivers/media/dvb/ttpci/budget-core.c
drivers/media/dvb/ttpci/budget-core.c
+13
-4
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget-patch.c
+311
-35
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttpci/budget.c
+3
-3
drivers/media/dvb/ttusb-dec/ttusb_dec.c
drivers/media/dvb/ttusb-dec/ttusb_dec.c
+3
-3
include/linux/dvb/frontend.h
include/linux/dvb/frontend.h
+8
-3
include/linux/dvb/version.h
include/linux/dvb/version.h
+1
-0
mm/memory.c
mm/memory.c
+3
-2
No files found.
Documentation/dvb/README.dibusb
View file @
ca583a3c
...
...
@@ -26,7 +26,7 @@ Produced and reselled by Twinhan:
- HAMA DVB-T USB device
http://www.hama.de/portal/articleId*110620/action*2598
- CTS Portable (Chinese Television System)
- CTS Portable (Chinese Television System)
(2)
http://www.2cts.tv/ctsportable/
- Unknown USB DVB-T device with vendor ID Hyper-Paltek
...
...
@@ -46,16 +46,16 @@ Produced and reselled by KWorld:
Others:
-------
- Ultima Electronic/Artec T1 USB TVBOX (AN2135
and AN2235)
- Ultima Electronic/Artec T1 USB TVBOX (AN2135
, AN2235, AN2235 with Panasonic Tuner)
http://82.161.246.249/products-tvbox.html
- Compro Videomate DVB-U2000 - DVB-T USB
- Compro Videomate DVB-U2000 - DVB-T USB
(2)
http://www.comprousa.com/products/vmu2000.htm
- Grandtec USB DVB-T
http://www.grand.com.tw/
- Avermedia AverTV DVBT USB
- Avermedia AverTV DVBT USB
(2)
http://www.avermedia.com/
- DiBcom USB DVB-T reference device (non-public)
...
...
@@ -63,16 +63,33 @@ Others:
Supported devices USB2.0
========================
- Twinhan MagicBox II
- Twinhan MagicBox II
(2)
http://www.twinhan.com/product_terrestrial_7.asp
- Yakumo DVB-T mobile
- Hanftek UMT-010 (1)
http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
- Typhoon/Yakumo/HAMA DVB-T mobile USB2.0 (1)
http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
- Artec T1 USB TVBOX (FX2) (2)
- DiBcom USB2.0 DVB-T reference device (non-public)
1) It is working almost.
2) No test reports received yet.
0. NEWS:
2004-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
- first almost working version for HanfTek UMT-010
- found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek
2004-01-10 - refactoring completed, now everything is very delightful
- tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
2004-12-26 - refactored the dibusb-driver, splitted into separate files
- i2c-probing enabled
2004-12-06 - possibility for demod i2c-address probing
- new usb IDs (Compro,Artec)
2004-11-23 - merged changes from DiB3000MC_ver2.1
...
...
@@ -115,13 +132,15 @@ Supported devices USB2.0
1. How to use?
NOTE: This driver was developed using Linux 2.6.6.,
it is working with 2.6.7
, 2.6.8.1, 2.6.9
.
it is working with 2.6.7
and above
.
Linux 2.4.x support is not planned, but patches are very welcome.
NOTE: I'm using Debian testing, so the following explaination (especially
the hotplug-path) needn't match your system, but probably it will :).
The driver is included in the kernel since Linux 2.6.10.
1.1. Firmware
The USB driver needs to download a firmware to start working.
...
...
@@ -155,9 +174,13 @@ from withing the dvb-kernel cvs repository.
first have a look, which debug level are available:
modinfo dib3000mb
modinfo dib3000-common
modinfo dib3000mc
modinfo dvb-dibusb
modprobe dib3000-common debug=<level>
modprobe dib3000mb debug=<level>
modprobe dib3000mc debug=<level>
modprobe dvb-dibusb debug=<level>
should do the trick.
...
...
@@ -168,13 +191,11 @@ turned on.
At this point you should be able to start a dvb-capable application. For myself
I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device
as a slave device in vdr, was not working for me. Some work has to be done
(patches and comments are very welcome).
in vdr (at least the USB2.0 one) is working.
2. Known problems and bugs
TODO:
- signal-quality and strength calculations
- none this time
2.1. Adding support for devices
...
...
@@ -202,9 +223,10 @@ Most of the current supported devices are USB1.1 and thus they have a
maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
This is not enough for receiving the complete transport stream of a
DVB-T channel (which can be about 16 MBit/s). Normally this is not a
problem, if you only want to watch TV, but watching a channel while
recording another channel on the same frequency simply does not work.
This applies to all USB1.1 DVB-T devices.
problem, if you only want to watch TV (this does not apply for HDTV),
but watching a channel while recording another channel on the same
frequency simply does not work. This applies to all USB1.1 DVB-T
devices, not only dibusb)
A special problem of the dibusb for the USB1.1 is, that the USB control
IC has a problem with write accesses while having MPEG2-streaming
...
...
@@ -218,14 +240,20 @@ due the automatic scanning (introduced in 1.3.x, afaik) and epg-scan. Disabling
these features is maybe a solution. Additionally this behaviour of VDR exceeds
the USB1.1 bandwidth.
Update:
For the USB1.1 and VDR some work has been done (patches and comments are still
very welcome). Maybe the problem is solved in the meantime because I now use
the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
linux-dvb software filter is able to get the best of the garbled TS.
2.3. Comments
Patches, comments and suggestions are very very welcome
3. Acknowledgements
Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
providing specs, code and help, on which the dvb-dibusb and dib3000mb are
based.
providing specs, code and help, on which the dvb-dibusb, dib3000mb and
dib3000mc are
based.
David Matthews for identifying a new device type (Artec T1 with AN2235)
and for extending dibusb with remote control event handling. Thank you.
...
...
Documentation/dvb/get_dvb_firmware
View file @
ca583a3c
...
...
@@ -21,7 +21,8 @@
use
File::
Temp
qw/ tempdir /
;
use
IO::
Handle
;
@components
=
(
"
sp8870
",
"
sp887x
",
"
tda10045
",
"
tda10046
",
"
av7110
",
"
dec2000t
",
"
dec2540t
",
"
dec3000s
",
"
vp7041
",
"
dibusb
"
);
@components
=
(
"
sp8870
",
"
sp887x
",
"
tda10045
",
"
tda10046
",
"
av7110
",
"
dec2000t
",
"
dec2540t
",
"
dec3000s
",
"
vp7041
",
"
dibusb
",
"
nxt2002
"
);
# Check args
syntax
()
if
(
scalar
(
@ARGV
)
!=
1
);
...
...
@@ -233,6 +234,23 @@ sub dibusb {
$outfile
;
}
sub
nxt2002
{
my
$sourcefile
=
"
Broadband4PC_4_2_11.zip
";
my
$url
=
"
http://www.bbti.us/download/windows/
$sourcefile
";
my
$hash
=
"
c6d2ea47a8f456d887ada0cfb718ff2a
";
my
$outfile
=
"
dvb-fe-nxt2002.fw
";
my
$tmpdir
=
tempdir
(
DIR
=>
"
/tmp
",
CLEANUP
=>
1
);
checkstandard
();
wgetfile
(
$sourcefile
,
$url
);
unzip
(
$sourcefile
,
$tmpdir
);
verify
("
$tmpdir
/SkyNETU.sys
",
$hash
);
extract
("
$tmpdir
/SkyNETU.sys
",
375832
,
5908
,
$outfile
);
$outfile
;
}
# ---------------------------------------------------------------
# Utilities
...
...
arch/ppc64/kernel/signal.c
View file @
ca583a3c
...
...
@@ -67,7 +67,7 @@ struct rt_sigframe {
struct
siginfo
info
;
/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
char
abigap
[
288
];
};
}
__attribute__
((
aligned
(
16
)))
;
/*
...
...
@@ -254,7 +254,7 @@ static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs
newsp
=
(
current
->
sas_ss_sp
+
current
->
sas_ss_size
);
}
return
(
void
__user
*
)((
newsp
-
frame_size
)
&
-
8
ul
);
return
(
void
__user
*
)((
newsp
-
frame_size
)
&
-
16
ul
);
}
/*
...
...
drivers/media/common/saa7146_core.c
View file @
ca583a3c
...
...
@@ -380,8 +380,8 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
/* disable all irqs */
saa7146_write
(
dev
,
IER
,
0
);
/* shut down all dma transfers */
saa7146_write
(
dev
,
MC1
,
0x
0
0ff0000
);
/* shut down all dma transfers
and rps tasks
*/
saa7146_write
(
dev
,
MC1
,
0x
3
0ff0000
);
/* clear out any rps-signals pending */
saa7146_write
(
dev
,
MC2
,
0xf8000000
);
...
...
drivers/media/dvb/b2c2/Kconfig
View file @
ca583a3c
...
...
@@ -4,9 +4,11 @@ config DVB_B2C2_SKYSTAR
select DVB_STV0299
select DVB_MT352
select DVB_MT312
select DVB_NXT2002
help
Support for the Skystar2 PCI DVB card by Technisat, which
is equipped with the FlexCopII chipset by B2C2.
is equipped with the FlexCopII chipset by B2C2, and
for the B2C2/BBTI Air2PC-ATSC card.
Say Y if you own such a device and want to use it.
...
...
@@ -17,7 +19,7 @@ config DVB_B2C2_USB
select DVB_MT352
help
Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently
th
is does nothing, but providing basic function for the used usb
th
e does nothing, but providing basic function for the used usb
protocol.
Say Y if you own such a device and want to use it.
...
...
drivers/media/dvb/b2c2/b2c2-usb-core.c
View file @
ca583a3c
...
...
@@ -33,7 +33,7 @@
}
static
int
debug
;
module_param
(
debug
,
int
,
0
x
644
);
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,ts=2,ctrl=4 (or-able))."
);
#define deb_info(args...) dprintk(0x01,args)
...
...
@@ -89,8 +89,18 @@ struct usb_b2c2_usb {
/* request types */
typedef
enum
{
/* something is wrong with this part
RTYPE_READ_DW = (1 << 6),
RTYPE_WRITE_DW_1 = (3 << 6),
RTYPE_READ_V8_MEMORY = (6 << 6),
RTYPE_WRITE_V8_MEMORY = (7 << 6),
RTYPE_WRITE_V8_FLASH = (8 << 6),
RTYPE_GENERIC = (9 << 6),
*/
RTYPE_READ_DW
=
(
3
<<
6
),
RTYPE_WRITE_DW_1
=
(
1
<<
6
),
RTYPE_READ_V8_MEMORY
=
(
6
<<
6
),
RTYPE_WRITE_V8_MEMORY
=
(
7
<<
6
),
RTYPE_WRITE_V8_FLASH
=
(
8
<<
6
),
...
...
@@ -391,9 +401,9 @@ static int b2c2_init_usb(struct usb_b2c2_usb *b2c2)
}
/* initialising and submitting iso urbs */
for
(
i
=
0
;
i
<
B2C2_USB_NUM_ISO_URB
;
i
++
)
{
deb_info
(
"initializing and submitting urb no. %d (buf_offset: %d).
\n
"
,
i
,
buffer_offset
);
int
frame_offset
=
0
;
struct
urb
*
urb
=
b2c2
->
iso_urb
[
i
];
deb_info
(
"initializing and submitting urb no. %d (buf_offset: %d).
\n
"
,
i
,
buffer_offset
);
urb
->
dev
=
b2c2
->
udev
;
urb
->
context
=
b2c2
;
...
...
drivers/media/dvb/b2c2/skystar2.c
View file @
ca583a3c
...
...
@@ -53,7 +53,7 @@
#include "stv0299.h"
#include "mt352.h"
#include "mt312.h"
#include "nxt2002.h"
static
int
debug
;
static
int
enable_hw_filters
=
2
;
...
...
@@ -1379,10 +1379,7 @@ static int dma_init_dma(struct adapter *adapter, u32 dma_channel)
write_reg_dw
(
adapter
,
0x008
,
adapter
->
dmaq1
.
bus_addr
&
0xfffffffc
);
udelay
(
1000
);
if
(
subbuffers
==
0
)
dma_enable_disable_irq
(
adapter
,
0
,
1
,
0
);
else
dma_enable_disable_irq
(
adapter
,
0
,
1
,
1
);
dma_enable_disable_irq
(
adapter
,
0
,
1
,
subbuffers
?
1
:
0
);
irq_dma_enable_disable_irq
(
adapter
,
1
);
...
...
@@ -1681,84 +1678,80 @@ static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs)
return
IRQ_HANDLED
;
}
static
void
init_dma_queue
(
struct
adapter
*
adapter
)
static
int
init_dma_queue_one
(
struct
adapter
*
adapter
,
struct
dmaq
*
dmaq
,
int
size
,
int
dmaq_offset
)
{
struct
pci_dev
*
pdev
=
adapter
->
pdev
;
dma_addr_t
dma_addr
;
if
(
adapter
->
dmaq1
.
buffer
!=
0
)
return
;
adapter
->
dmaq1
.
head
=
0
;
adapter
->
dmaq1
.
tail
=
0
;
adapter
->
dmaq1
.
buffer
=
NULL
;
adapter
->
dmaq1
.
buffer
=
pci_alloc_consistent
(
adapter
->
pdev
,
SIZE_OF_BUF_DMA1
+
0x80
,
&
dma_addr
);
if
(
adapter
->
dmaq1
.
buffer
!=
0
)
{
memset
(
adapter
->
dmaq1
.
buffer
,
0
,
SIZE_OF_BUF_DMA1
);
dmaq
->
head
=
0
;
dmaq
->
tail
=
0
;
adapter
->
dmaq1
.
bus_addr
=
dma_addr
;
adapter
->
dmaq1
.
buffer_size
=
SIZE_OF_BUF_DMA1
;
dma_init_dma
(
adapter
,
0
);
dmaq
->
buffer
=
pci_alloc_consistent
(
pdev
,
size
+
0x80
,
&
dma_addr
);
if
(
!
dmaq
->
buffer
)
return
-
ENOMEM
;
adapter
->
dma_status
=
adapter
->
dma_status
|
0x10000000
;
dmaq
->
bus_addr
=
dma_addr
;
dmaq
->
buffer_size
=
size
;
ddprintk
(
"%s: allocated dma buffer at 0x%p, length=%d
\n
"
,
__FUNCTION__
,
adapter
->
dmaq1
.
buffer
,
SIZE_OF_BUF_DMA1
);
dma_init_dma
(
adapter
,
dmaq_offset
);
}
else
{
ddprintk
(
"%s: allocated dma buffer at 0x%p, length=%d
\n
"
,
__FUNCTION__
,
dmaq
->
buffer
,
size
);
adapter
->
dma_status
=
adapter
->
dma_status
&
~
0x1000000
0
;
return
0
;
}
if
(
adapter
->
dmaq2
.
buffer
!=
0
)
return
;
adapter
->
dmaq2
.
head
=
0
;
adapter
->
dmaq2
.
tail
=
0
;
adapter
->
dmaq2
.
buffer
=
NULL
;
adapter
->
dmaq2
.
buffer
=
pci_alloc_consistent
(
adapter
->
pdev
,
SIZE_OF_BUF_DMA2
+
0x80
,
&
dma_addr
);
if
(
adapter
->
dmaq2
.
buffer
!=
0
)
{
memset
(
adapter
->
dmaq2
.
buffer
,
0
,
SIZE_OF_BUF_DMA2
);
adapter
->
dmaq2
.
bus_addr
=
dma_addr
;
adapter
->
dmaq2
.
buffer_size
=
SIZE_OF_BUF_DMA2
;
dma_init_dma
(
adapter
,
1
);
adapter
->
dma_status
=
adapter
->
dma_status
|
0x20000000
;
ddprintk
(
"%s: allocated dma buffer at 0x%p, length=%d
\n
"
,
__FUNCTION__
,
adapter
->
dmaq2
.
buffer
,
(
int
)
SIZE_OF_BUF_DMA2
);
static
int
init_dma_queue
(
struct
adapter
*
adapter
)
{
struct
{
struct
dmaq
*
dmaq
;
u32
dma_status
;
int
size
;
}
dmaq_desc
[]
=
{
{
&
adapter
->
dmaq1
,
0x10000000
,
SIZE_OF_BUF_DMA1
},
{
&
adapter
->
dmaq2
,
0x20000000
,
SIZE_OF_BUF_DMA2
}
},
*
p
=
dmaq_desc
;
int
i
;
}
else
{
for
(
i
=
0
;
i
<
2
;
i
++
,
p
++
)
{
if
(
init_dma_queue_one
(
adapter
,
p
->
dmaq
,
p
->
size
,
i
)
<
0
)
adapter
->
dma_status
&=
~
p
->
dma_status
;
else
adapter
->
dma_status
|=
p
->
dma_status
;
}
return
(
adapter
->
dma_status
&
0x30000000
)
?
0
:
-
ENOMEM
;
}
adapter
->
dma_status
=
adapter
->
dma_status
&
~
0x20000000
;
static
void
free_dma_queue_one
(
struct
adapter
*
adapter
,
struct
dmaq
*
dmaq
)
{
if
(
dmaq
->
buffer
)
{
pci_free_consistent
(
adapter
->
pdev
,
dmaq
->
buffer_size
+
0x80
,
dmaq
->
buffer
,
dmaq
->
bus_addr
);
memset
(
dmaq
,
0
,
sizeof
(
*
dmaq
));
}
}
static
void
free_dma_queue
(
struct
adapter
*
adapter
)
{
if
(
adapter
->
dmaq1
.
buffer
!=
0
)
{
pci_free_consistent
(
adapter
->
pdev
,
SIZE_OF_BUF_DMA1
+
0x80
,
adapter
->
dmaq1
.
buffer
,
adapter
->
dmaq1
.
bus_addr
);
struct
dmaq
*
dmaq
[]
=
{
&
adapter
->
dmaq1
,
&
adapter
->
dmaq2
,
NULL
},
**
p
;
adapter
->
dmaq1
.
bus_addr
=
0
;
adapter
->
dmaq1
.
head
=
0
;
adapter
->
dmaq1
.
tail
=
0
;
adapter
->
dmaq1
.
buffer_size
=
0
;
adapter
->
dmaq1
.
buffer
=
NULL
;
for
(
p
=
dmaq
;
*
p
;
p
++
)
free_dma_queue_one
(
adapter
,
*
p
);
}
if
(
adapter
->
dmaq2
.
buffer
!=
0
)
{
pci_free_consistent
(
adapter
->
pdev
,
SIZE_OF_BUF_DMA2
+
0x80
,
adapter
->
dmaq2
.
buffer
,
adapter
->
dmaq2
.
bus_addr
);
static
void
release_adapter
(
struct
adapter
*
adapter
)
{
struct
pci_dev
*
pdev
=
adapter
->
pdev
;
adapter
->
dmaq2
.
bus_addr
=
0
;
adapter
->
dmaq2
.
head
=
0
;
adapter
->
dmaq2
.
tail
=
0
;
adapter
->
dmaq2
.
buffer_size
=
0
;
adapter
->
dmaq2
.
buffer
=
NULL
;
}
iounmap
(
adapter
->
io_mem
);
pci_disable_device
(
pdev
);
pci_release_region
(
pdev
,
0
);
pci_release_region
(
pdev
,
1
);
}
static
void
free_adapter_object
(
struct
adapter
*
adapter
)
...
...
@@ -1766,16 +1759,9 @@ static void free_adapter_object(struct adapter *adapter)
dprintk
(
"%s:
\n
"
,
__FUNCTION__
);
close_stream
(
adapter
,
0
);
if
(
adapter
->
irq
!=
0
)
free_irq
(
adapter
->
irq
,
adapter
);
free_dma_queue
(
adapter
);
if
(
adapter
->
io_mem
)
iounmap
(
adapter
->
io_mem
);
if
(
adapter
!=
0
)
release_adapter
(
adapter
);
kfree
(
adapter
);
}
...
...
@@ -1784,21 +1770,24 @@ static struct pci_driver skystar2_pci_driver;
static
int
claim_adapter
(
struct
adapter
*
adapter
)
{
struct
pci_dev
*
pdev
=
adapter
->
pdev
;
u16
var
;
int
ret
;
if
(
!
request_region
(
pci_resource_start
(
pdev
,
1
),
pci_resource_len
(
pdev
,
1
),
skystar2_pci_driver
.
name
))
return
-
EBUSY
;
ret
=
pci_request_region
(
pdev
,
1
,
skystar2_pci_driver
.
name
);
if
(
ret
<
0
)
goto
out
;
if
(
!
request_mem_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
),
skystar2_pci_driver
.
name
))
return
-
EBUSY
;
ret
=
pci_request_region
(
pdev
,
0
,
skystar2_pci_driver
.
name
);
if
(
ret
<
0
)
goto
err_pci_release_1
;
pci_read_config_byte
(
pdev
,
PCI_CLASS_REVISION
,
&
adapter
->
card_revision
);
dprintk
(
"%s: card revision %x
\n
"
,
__FUNCTION__
,
adapter
->
card_revision
);
if
(
pci_enable_device
(
pdev
))
return
-
EIO
;
ret
=
pci_enable_device
(
pdev
);
if
(
ret
<
0
)
goto
err_pci_release_0
;
pci_read_config_word
(
pdev
,
4
,
&
var
);
...
...
@@ -1811,13 +1800,23 @@ static int claim_adapter(struct adapter *adapter)
if
(
!
adapter
->
io_mem
)
{
dprintk
(
"%s: can not map io memory
\n
"
,
__FUNCTION__
);
return
2
;
ret
=
-
EIO
;
goto
err_pci_disable
;
}
dprintk
(
"%s: io memory maped at %p
\n
"
,
__FUNCTION__
,
adapter
->
io_mem
);
return
1
;
ret
=
1
;
out:
return
ret
;
err_pci_disable:
pci_disable_device
(
pdev
);
err_pci_release_0:
pci_release_region
(
pdev
,
0
);
err_pci_release_1:
pci_release_region
(
pdev
,
1
);
goto
out
;
}
/*
...
...
@@ -1873,11 +1872,12 @@ static int driver_initialize(struct pci_dev *pdev)
{
struct
adapter
*
adapter
;
u32
tmp
;
int
ret
=
-
ENOMEM
;
if
(
!
(
adapter
=
kmalloc
(
sizeof
(
struct
adapter
),
GFP_KERNEL
)))
{
adapter
=
kmalloc
(
sizeof
(
struct
adapter
),
GFP_KERNEL
);
if
(
!
adapter
)
{
dprintk
(
"%s: out of memory!
\n
"
,
__FUNCTION__
);
return
-
ENOMEM
;
goto
out
;
}
memset
(
adapter
,
0
,
sizeof
(
struct
adapter
));
...
...
@@ -1887,20 +1887,16 @@ static int driver_initialize(struct pci_dev *pdev)
adapter
->
pdev
=
pdev
;
adapter
->
irq
=
pdev
->
irq
;
if
((
claim_adapter
(
adapter
))
!=
1
)
{
free_adapter_object
(
adapter
);
return
-
ENODEV
;
}
ret
=
claim_adapter
(
adapter
);
if
(
ret
<
0
)
goto
err_kfree
;
irq_dma_enable_disable_irq
(
adapter
,
0
);
if
(
request_irq
(
pdev
->
irq
,
isr
,
0x4000000
,
"Skystar2"
,
adapter
)
!=
0
)
{
ret
=
request_irq
(
pdev
->
irq
,
isr
,
0x4000000
,
"Skystar2"
,
adapter
);
if
(
ret
<
0
)
{
dprintk
(
"%s: unable to allocate irq=%d !
\n
"
,
__FUNCTION__
,
pdev
->
irq
);
free_adapter_object
(
adapter
);
return
-
ENODEV
;
goto
err_release_adapter
;
}
read_reg_dw
(
adapter
,
0x208
);
...
...
@@ -1908,13 +1904,9 @@ static int driver_initialize(struct pci_dev *pdev)
write_reg_dw
(
adapter
,
0x210
,
0xb2ff
);
write_reg_dw
(
adapter
,
0x208
,
0x40
);
init_dma_queue
(
adapter
);
if
((
adapter
->
dma_status
&
0x30000000
)
==
0
)
{
free_adapter_object
(
adapter
);
return
-
ENODEV
;
}
ret
=
init_dma_queue
(
adapter
);
if
(
ret
<
0
)
goto
err_free_irq
;
adapter
->
b2c2_revision
=
(
read_reg_dw
(
adapter
,
0x204
)
>>
0x18
);
...
...
@@ -1931,11 +1923,8 @@ static int driver_initialize(struct pci_dev *pdev)
default:
printk
(
"%s: The revision of the FlexCop chip on your card is %d
\n
"
,
__FILE__
,
adapter
->
b2c2_revision
);
printk
(
"%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).
\n
"
,
__FILE__
);
free_adapter_object
(
adapter
);
pci_set_drvdata
(
pdev
,
NULL
);
release_region
(
pci_resource_start
(
pdev
,
1
),
pci_resource_len
(
pdev
,
1
));
release_mem_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
));
return
-
ENODEV
;
ret
=
-
ENODEV
;
goto
err_free_dma_queue
;
}
decide_how_many_hw_filters
(
adapter
);
...
...
@@ -1979,16 +1968,26 @@ static int driver_initialize(struct pci_dev *pdev)
ctrl_enable_mac
(
adapter
,
1
);
}
spin_lock_init
(
&
adapter
->
lock
)
;
adapter
->
lock
=
SPIN_LOCK_UNLOCKED
;
return
0
;
out:
return
ret
;
err_free_dma_queue:
free_dma_queue
(
adapter
);
err_free_irq:
free_irq
(
pdev
->
irq
,
adapter
);
err_release_adapter:
release_adapter
(
adapter
);
err_kfree:
pci_set_drvdata
(
pdev
,
NULL
);
kfree
(
adapter
);
goto
out
;
}
static
void
driver_halt
(
struct
pci_dev
*
pdev
)
{
struct
adapter
*
adapter
;
adapter
=
pci_get_drvdata
(
pdev
);
struct
adapter
*
adapter
=
pci_get_drvdata
(
pdev
);
irq_dma_enable_disable_irq
(
adapter
,
0
);
...
...
@@ -1998,9 +1997,9 @@ static void driver_halt(struct pci_dev *pdev)
pci_set_drvdata
(
pdev
,
NULL
);
release_region
(
pci_resource_start
(
pdev
,
1
),
pci_resource_len
(
pdev
,
1
)
);
release_mem_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
)
);
pci_disable_device
(
pdev
);
pci_release_region
(
pdev
,
1
);
pci_release_region
(
pdev
,
0
);
}
static
int
dvb_start_feed
(
struct
dvb_demux_feed
*
dvbdmxfeed
)
...
...
@@ -2325,11 +2324,22 @@ static struct stv0299_config samsung_tbmu24112_config = {
static
int
nxt2002_request_firmware
(
struct
dvb_frontend
*
fe
,
const
struct
firmware
**
fw
,
char
*
name
)
{
struct
adapter
*
adapter
=
(
struct
adapter
*
)
fe
->
dvb
->
priv
;
return
request_firmware
(
fw
,
name
,
&
adapter
->
pdev
->
dev
);
}
static
struct
nxt2002_config
samsung_tbmv_config
=
{
.
demod_address
=
0x0A
,
.
request_firmware
=
nxt2002_request_firmware
,
};
static
int
samsung_tdtc9251dh0_demod_init
(
struct
dvb_frontend
*
fe
)
{
static
u8
mt352_clock_config
[]
=
{
0x89
,
0x1
0
,
0x2d
};
static
u8
mt352_clock_config
[]
=
{
0x89
,
0x1
8
,
0x2d
};
static
u8
mt352_reset
[]
=
{
0x50
,
0x80
};
static
u8
mt352_adc_ctl_1_cfg
[]
=
{
0x8E
,
0x40
};
static
u8
mt352_agc_cfg
[]
=
{
0x67
,
0x28
,
0xa1
};
...
...
@@ -2407,7 +2417,15 @@ static struct mt312_config skystar23_samsung_tbdu18132_config = {
static
void
frontend_init
(
struct
adapter
*
skystar2
)
{
switch
(
skystar2
->
pdev
->
device
)
{
case
0x2103
:
// Technisat Skystar2 OR Technisat Airstar2
case
0x2103
:
// Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC)
// Attempt to load the Nextwave nxt2002 for ATSC support
skystar2
->
fe
=
nxt2002_attach
(
&
samsung_tbmv_config
,
&
skystar2
->
i2c_adap
);
if
(
skystar2
->
fe
!=
NULL
)
{
skystar2
->
fe_sleep
=
skystar2
->
fe
->
ops
->
sleep
;
skystar2
->
fe
->
ops
->
sleep
=
flexcop_sleep
;
break
;
}
// try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935))
skystar2
->
fe
=
stv0299_attach
(
&
samsung_tbmu24112_config
,
&
skystar2
->
i2c_adap
);
...
...
@@ -2462,26 +2480,24 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct
adapter
*
adapter
;
struct
dvb_adapter
*
dvb_adapter
;
struct
dvb_demux
*
dvbdemux
;
struct
dmx_demux
*
dmx
;
int
ret
=
-
ENODEV
;
int
ret
;
if
(
pdev
==
NULL
)
return
-
ENODEV
;
if
(
!
pdev
)
goto
out
;
if
(
driver_initialize
(
pdev
)
!=
0
)
return
-
ENODEV
;
dvb_register_adapter
(
&
dvb_adapter
,
skystar2_pci_driver
.
name
,
THIS_MODULE
);
ret
=
driver_initialize
(
pdev
);
if
(
ret
<
0
)
goto
out
;
if
(
dvb_adapter
==
NULL
)
{
ret
=
dvb_register_adapter
(
&
dvb_adapter
,
skystar2_pci_driver
.
name
,
THIS_MODULE
);
if
(
ret
<
0
)
{
printk
(
"%s: Error registering DVB adapter
\n
"
,
__FUNCTION__
);
driver_halt
(
pdev
);
return
-
ENODEV
;
goto
err_halt
;
}
adapter
=
(
struct
adapter
*
)
pci_get_drvdata
(
pdev
);
adapter
=
pci_get_drvdata
(
pdev
);
dvb_adapter
->
priv
=
adapter
;
adapter
->
dvb_adapter
=
dvb_adapter
;
...
...
@@ -2504,14 +2520,13 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter
->
i2c_adap
.
algo_data
=
NULL
;
adapter
->
i2c_adap
.
id
=
I2C_ALGO_BIT
;
if
(
i2c_add_adapter
(
&
adapter
->
i2c_adap
)
<
0
)
{
dvb_unregister_adapter
(
adapter
->
dvb_adapter
);
return
-
ENOMEM
;
}
ret
=
i2c_add_adapter
(
&
adapter
->
i2c_adap
);
if
(
ret
<
0
)
goto
err_dvb_unregister
;
dvbdemux
=
&
adapter
->
demux
;
dvbdemux
->
priv
=
(
void
*
)
adapter
;
dvbdemux
->
priv
=
adapter
;
dvbdemux
->
filternum
=
N_PID_SLOTS
;
dvbdemux
->
feednum
=
N_PID_SLOTS
;
dvbdemux
->
start_feed
=
dvb_start_feed
;
...
...
@@ -2519,68 +2534,87 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dvbdemux
->
write_to_decoder
=
NULL
;
dvbdemux
->
dmx
.
capabilities
=
(
DMX_TS_FILTERING
|
DMX_SECTION_FILTERING
|
DMX_MEMORY_BASED_FILTERING
);
dvb_dmx_init
(
&
adapter
->
demux
);
ret
=
dvb_dmx_init
(
&
adapter
->
demux
);
if
(
ret
<
0
)
goto
err_i2c_del
;
dmx
=
&
dvbdemux
->
dmx
;
adapter
->
hw_frontend
.
source
=
DMX_FRONTEND_0
;
adapter
->
dmxdev
.
filternum
=
N_PID_SLOTS
;
adapter
->
dmxdev
.
demux
=
&
dvbdemux
->
dmx
;
adapter
->
dmxdev
.
demux
=
dmx
;
adapter
->
dmxdev
.
capabilities
=
0
;
dvb_dmxdev_init
(
&
adapter
->
dmxdev
,
adapter
->
dvb_adapter
);
ret
=
dvb_dmxdev_init
(
&
adapter
->
dmxdev
,
adapter
->
dvb_adapter
);
if
(
ret
<
0
)
goto
err_dmx_release
;
ret
=
d
vbdemux
->
dmx
.
add_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
hw_frontend
);
ret
=
d
mx
->
add_frontend
(
dmx
,
&
adapter
->
hw_frontend
);
if
(
ret
<
0
)
return
ret
;
goto
err_dmxdev_release
;
adapter
->
mem_frontend
.
source
=
DMX_MEMORY_FE
;
ret
=
d
vbdemux
->
dmx
.
add_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
mem_frontend
);
ret
=
d
mx
->
add_frontend
(
dmx
,
&
adapter
->
mem_frontend
);
if
(
ret
<
0
)
return
ret
;
goto
err_remove_hw_frontend
;
ret
=
d
vbdemux
->
dmx
.
connect_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
hw_frontend
);
ret
=
d
mx
->
connect_frontend
(
dmx
,
&
adapter
->
hw_frontend
);
if
(
ret
<
0
)
return
ret
;
goto
err_remove_mem_frontend
;
dvb_net_init
(
adapter
->
dvb_adapter
,
&
adapter
->
dvbnet
,
&
dvbdemux
->
dmx
);
frontend_init
(
adapter
);
out:
return
ret
;
return
0
;
err_remove_mem_frontend:
dvbdemux
->
dmx
.
remove_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
mem_frontend
);
err_remove_hw_frontend:
dvbdemux
->
dmx
.
remove_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
hw_frontend
);
err_dmxdev_release:
dvb_dmxdev_release
(
&
adapter
->
dmxdev
);
err_dmx_release:
dvb_dmx_release
(
&
adapter
->
demux
);
err_i2c_del:
i2c_del_adapter
(
&
adapter
->
i2c_adap
);
err_dvb_unregister:
dvb_unregister_adapter
(
adapter
->
dvb_adapter
);
err_halt:
driver_halt
(
pdev
);
goto
out
;
}
static
void
skystar2_remove
(
struct
pci_dev
*
pdev
)
{
struct
adapter
*
adapter
;
struct
adapter
*
adapter
=
pci_get_drvdata
(
pdev
)
;
struct
dvb_demux
*
dvbdemux
;
struct
dmx_demux
*
dmx
;
if
(
pdev
==
NULL
)
if
(
!
adapter
)
return
;
adapter
=
pci_get_drvdata
(
pdev
);
if
(
adapter
!=
NULL
)
{
dvb_net_release
(
&
adapter
->
dvbnet
);
dvbdemux
=
&
adapter
->
demux
;
dmx
=
&
dvbdemux
->
dmx
;
dvbdemux
->
dmx
.
close
(
&
dvbdemux
->
dmx
);
dvbdemux
->
dmx
.
remove_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
hw_frontend
);
dvbdemux
->
dmx
.
remove_frontend
(
&
dvbdemux
->
dmx
,
&
adapter
->
mem_frontend
);
dmx
->
close
(
dmx
);
dmx
->
remove_frontend
(
dmx
,
&
adapter
->
hw_frontend
);
dmx
->
remove_frontend
(
dmx
,
&
adapter
->
mem_frontend
);
dvb_dmxdev_release
(
&
adapter
->
dmxdev
);
dvb_dmx_release
(
&
adapter
->
demux
);
dvb_dmx_release
(
dvbdemux
);
if
(
adapter
->
fe
!=
NULL
)
dvb_unregister_frontend
(
adapter
->
fe
);
if
(
adapter
->
fe
!=
NULL
)
dvb_unregister_frontend
(
adapter
->
fe
);
dvb_unregister_adapter
(
adapter
->
dvb_adapter
);
if
(
adapter
->
dvb_adapter
!=
NULL
)
{
i2c_del_adapter
(
&
adapter
->
i2c_adap
);
dvb_unregister_adapter
(
adapter
->
dvb_adapter
);
}
driver_halt
(
pdev
);
}
}
static
struct
pci_device_id
skystar2_pci_tbl
[]
=
{
{
0x000013d0
,
0x00002103
,
0xffffffff
,
0xffffffff
,
0x00000000
,
0x00000000
,
0x00000000
},
...
...
drivers/media/dvb/bt8xx/Kconfig
View file @
ca583a3c
...
...
@@ -3,6 +3,8 @@ config DVB_BT8XX
depends on DVB_CORE && PCI && VIDEO_BT848
select DVB_MT352
select DVB_SP887X
select DVB_NXT6000
select DVB_CX24110
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
...
...
@@ -11,8 +13,5 @@ config DVB_BT8XX
only compressed MPEG data over the PCI bus, so you need
an external software decoder to watch TV on your computer.
If you have a Twinhan card, don't forget to select
"Twinhan DST based DVB-S/-T frontend".
Say Y if you own such a device and want to use it.
drivers/media/dvb/bt8xx/dvb-bt8xx.c
View file @
ca583a3c
...
...
@@ -181,6 +181,70 @@ static struct mt352_config thomson_dtt7579_config = {
.
pll_set
=
thomson_dtt7579_pll_set
,
};
static
int
cx24108_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
)
{
u32
freq
=
params
->
frequency
;
int
i
,
a
,
n
,
pump
;
u32
band
,
pll
;
u32
osci
[]
=
{
950000
,
1019000
,
1075000
,
1178000
,
1296000
,
1432000
,
1576000
,
1718000
,
1856000
,
2036000
,
2150000
};
u32
bandsel
[]
=
{
0
,
0x00020000
,
0x00040000
,
0x00100800
,
0x00101000
,
0x00102000
,
0x00104000
,
0x00108000
,
0x00110000
,
0x00120000
,
0x00140000
};
#define XTAL 1011100
/* Hz, really 1.0111 MHz and a /10 prescaler */
printk
(
"cx24108 debug: entering SetTunerFreq, freq=%d
\n
"
,
freq
);
/* This is really the bit driving the tuner chip cx24108 */
if
(
freq
<
950000
)
freq
=
950000
;
/* kHz */
if
(
freq
>
2150000
)
freq
=
2150000
;
/* satellite IF is 950..2150MHz */
/* decide which VCO to use for the input frequency */
for
(
i
=
1
;(
i
<
sizeof
(
osci
)
/
sizeof
(
osci
[
0
]))
&&
(
osci
[
i
]
<
freq
);
i
++
);
printk
(
"cx24108 debug: select vco #%d (f=%d)
\n
"
,
i
,
freq
);
band
=
bandsel
[
i
];
/* the gain values must be set by SetSymbolrate */
/* compute the pll divider needed, from Conexant data sheet,
resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
depending on the divider bit. It is set to /4 on the 2 lowest
bands */
n
=
((
i
<=
2
?
2
:
1
)
*
freq
*
10L
)
/
(
XTAL
/
100
);
a
=
n
%
32
;
n
/=
32
;
if
(
a
==
0
)
n
--
;
pump
=
(
freq
<
(
osci
[
i
-
1
]
+
osci
[
i
])
/
2
);
pll
=
0xf8000000
|
((
pump
?
1
:
2
)
<<
(
14
+
11
))
|
((
n
&
0x1ff
)
<<
(
5
+
11
))
|
((
a
&
0x1f
)
<<
11
);
/* everything is shifted left 11 bits to left-align the bits in the
32bit word. Output to the tuner goes MSB-aligned, after all */
printk
(
"cx24108 debug: pump=%d, n=%d, a=%d
\n
"
,
pump
,
n
,
a
);
cx24110_pll_write
(
fe
,
band
);
/* set vga and vca to their widest-band settings, as a precaution.
SetSymbolrate might not be called to set this up */
cx24110_pll_write
(
fe
,
0x500c0000
);
cx24110_pll_write
(
fe
,
0x83f1f800
);
cx24110_pll_write
(
fe
,
pll
);
/* writereg(client,0x56,0x7f);*/
return
0
;
}
static
int
pinnsat_pll_init
(
struct
dvb_frontend
*
fe
)
{
return
0
;
}
static
struct
cx24110_config
pctvsat_config
=
{
.
demod_address
=
0x55
,
.
pll_init
=
pinnsat_pll_init
,
.
pll_set
=
cx24108_pll_set
,
};
static
int
microtune_mt7202dtf_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
)
...
...
@@ -220,7 +284,7 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s
return
request_firmware
(
fw
,
name
,
&
bt
->
bt
->
dev
->
dev
);
}
struct
sp887x_config
microtune_mt7202dtf_config
=
{
st
atic
st
ruct
sp887x_config
microtune_mt7202dtf_config
=
{
.
demod_address
=
0x70
,
.
pll_set
=
microtune_mt7202dtf_pll_set
,
...
...
@@ -387,6 +451,13 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
break
;
}
break
;
case
BTTV_PINNACLESAT
:
card
->
fe
=
cx24110_attach
(
&
pctvsat_config
,
card
->
i2c_adapter
);
if
(
card
->
fe
!=
NULL
)
{
break
;
}
break
;
}
if
(
card
->
fe
==
NULL
)
{
...
...
@@ -510,7 +581,14 @@ static int dvb_bt8xx_probe(struct device *dev)
switch
(
sub
->
core
->
type
)
{
/* case BTTV_PINNACLESAT: UNDEFINED HARDWARE */
case
BTTV_PINNACLESAT
:
card
->
gpio_mode
=
0x0400c060
;
/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
card
->
op_sync_orin
=
0
;
card
->
irq_err_ignore
=
0
;
break
;
#ifdef BTTV_DVICO_DVBT_LITE
case
BTTV_DVICO_DVBT_LITE
:
#endif
...
...
drivers/media/dvb/bt8xx/dvb-bt8xx.h
View file @
ca583a3c
...
...
@@ -22,6 +22,9 @@
*
*/
#ifndef DVB_BT8XX_H
#define DVB_BT8XX_H
#include <linux/i2c.h>
#include "dvbdev.h"
#include "dvb_net.h"
...
...
@@ -30,6 +33,7 @@
#include "sp887x.h"
#include "dst.h"
#include "nxt6000.h"
#include "cx24110.h"
struct
dvb_bt8xx_card
{
struct
semaphore
lock
;
...
...
@@ -50,3 +54,5 @@ struct dvb_bt8xx_card {
struct
dvb_frontend
*
fe
;
};
#endif
/* DVB_BT8XX_H */
drivers/media/dvb/dibusb/Kconfig
View file @
ca583a3c
config DVB_DIBUSB
tristate "DiBcom USB DVB-T devices (see help for device list)"
tristate "DiBcom USB DVB-T devices (see help for
a complete
device list)"
depends on DVB_CORE && USB
select FW_LOADER
select DVB_DIB3000MB
select DVB_DIB3000MC
select DVB_MT352
help
Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
DiBcom (
<http://www.dibcom.fr>)
.
DiBcom (
http://www.dibcom.fr) and C&E
.
Devices supported by this driver:
...
...
@@ -14,12 +15,14 @@ config DVB_DIBUSB
TwinhanDTV Magic Box (VP7041e)
KWorld V-Stream XPERT DTV - DVB-T USB
Hama DVB-T USB-Box
DiBcom reference device (non-public)
DiBcom reference device
s
(non-public)
Ultima Electronic/Artec T1 USB TVBOX
Compro Videomate DVB-U2000 - DVB-T USB
Grandtec DVB-T USB
Avermedia AverTV DVBT USB
Yakumo DVB-T mobile USB2.0
Artec T1 USB1.1 and USB2.0 boxes
Yakumo/Typhoon DVB-T USB2.0
Hanftek UMT-010 USB2.0
The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System).
...
...
@@ -27,7 +30,7 @@ config DVB_DIBUSB
These devices can be understood as budget ones, they "only" deliver
(a part of) the MPEG2 transport stream.
A firmware is needed to get the device working. See
<file:Documentation/dvb/README.dibusb>
A firmware is needed to get the device working. See
Documentation/dvb/README.dibusb
details.
Say Y if you own such a device and want to use it. You should build it as
...
...
@@ -46,6 +49,7 @@ config DVB_DIBUSB_MISDESIGNED_DEVICES
0x0574:0x2235 (Artec T1 USB1.1, cold)
0x04b4:0x8613 (Artec T1 USB2.0, cold)
0x0574:0x1002 (Artec T1 USB2.0, warm)
0x0574:0x2131 (aged DiBcom USB1.1 test device)
Say Y if your device has one of the mentioned IDs.
...
...
drivers/media/dvb/dibusb/Makefile
View file @
ca583a3c
dvb-dibusb-objs
=
dvb-dibusb-core.o
\
dvb-dibusb-dvb.o
\
dvb-dibusb-fe-i2c.o
\
dvb-dibusb-firmware.o
\
dvb-dibusb-remote.o
\
dvb-dibusb-usb.o
\
dvb-dibusb-pid.o
obj-$(CONFIG_DVB_DIBUSB)
+=
dvb-dibusb.o
EXTRA_CFLAGS
=
-Idrivers
/media/dvb/dvb-core/
-Idrivers
/media/dvb/frontends/
drivers/media/dvb/dibusb/dvb-dibusb-core.c
0 → 100644
View file @
ca583a3c
/*
* Driver for mobile USB Budget DVB-T devices based on reference
* design made by DiBcom (http://www.dibcom.fr/)
*
* dvb-dibusb-core.c
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DiBcom, which has
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
*
* Remote control code added by David Matthews (dm@prolingua.co.uk)
*
* 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 the Free Software Foundation, version 2.
*
* Acknowledgements
*
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
*
* see Documentation/dvb/README.dibusb for more information
*/
#include "dvb-dibusb.h"
#include <linux/moduleparam.h>
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
int
debug
;
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))."
);
#endif
int
pid_parse
;
module_param
(
pid_parse
,
int
,
0644
);
MODULE_PARM_DESC
(
pid_parse
,
"enable pid parsing (filtering) when running at USB2.0"
);
int
rc_query_interval
;
module_param
(
rc_query_interval
,
int
,
0644
);
MODULE_PARM_DESC
(
rc_query_interval
,
"interval in msecs for remote control query (default: 100; min: 40)"
);
/* Vendor IDs */
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA 0x14aa
#define USB_VID_COMPRO 0x185b
#define USB_VID_COMPRO_UNK 0x145f
#define USB_VID_CYPRESS 0x04b4
#define USB_VID_DIBCOM 0x10b8
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GRANDTEC 0x5032
#define USB_VID_HYPER_PALTEK 0x1025
#define USB_VID_HANFTEK 0x15f4
#define USB_VID_IMC_NETWORKS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
/* Product IDs */
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
#define USB_PID_HANFTEK_UMT_010_WARM 0x0025
#define USB_PID_YAKUMO_DTT200U_COLD 0x0201
#define USB_PID_YAKUMO_DTT200U_WARM 0x0301
/* USB Driver stuff
* table of devices that this driver is working with
*
* ATTENTION: Never ever change the order of this table, the particular
* devices depend on this order
*
* Each entry is used as a reference in the device_struct. Currently this is
* the only non-redundant way of assigning USB ids to actual devices I'm aware
* of, because there is only one place in the code where the assignment of
* vendor and product id is done, here.
*/
static
struct
usb_device_id
dib_table
[]
=
{
/* 00 */
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_AVERMEDIA_DVBT_USB_COLD
)},
/* 01 */
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_AVERMEDIA_DVBT_USB_WARM
)},
/* 02 */
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_YAKUMO_DTT200U_COLD
)
},
/* the following device is actually not supported, but when loading the
* correct firmware (ie. its usb ids will change) everything works fine then
*/
/* 03 */
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_YAKUMO_DTT200U_WARM
)
},
/* 04 */
{
USB_DEVICE
(
USB_VID_COMPRO
,
USB_PID_COMPRO_DVBU2000_COLD
)
},
/* 05 */
{
USB_DEVICE
(
USB_VID_COMPRO
,
USB_PID_COMPRO_DVBU2000_WARM
)
},
/* 06 */
{
USB_DEVICE
(
USB_VID_COMPRO_UNK
,
USB_PID_COMPRO_DVBU2000_UNK_COLD
)
},
/* 07 */
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3000_COLD
)
},
/* 08 */
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3000_WARM
)
},
/* 09 */
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3001_COLD
)
},
/* 10 */
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3001_WARM
)
},
/* 11 */
{
USB_DEVICE
(
USB_VID_EMPIA
,
USB_PID_KWORLD_VSTREAM_COLD
)
},
/* 12 */
{
USB_DEVICE
(
USB_VID_EMPIA
,
USB_PID_KWORLD_VSTREAM_WARM
)
},
/* 13 */
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_GRANDTEC_DVBT_USB_COLD
)
},
/* 14 */
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_GRANDTEC_DVBT_USB_WARM
)
},
/* 15 */
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_DIBCOM_MOD3000_COLD
)
},
/* 16 */
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_DIBCOM_MOD3000_WARM
)
},
/* 17 */
{
USB_DEVICE
(
USB_VID_HYPER_PALTEK
,
USB_PID_UNK_HYPER_PALTEK_COLD
)
},
/* 18 */
{
USB_DEVICE
(
USB_VID_HYPER_PALTEK
,
USB_PID_UNK_HYPER_PALTEK_WARM
)
},
/* 19 */
{
USB_DEVICE
(
USB_VID_IMC_NETWORKS
,
USB_PID_TWINHAN_VP7041_COLD
)
},
/* 20 */
{
USB_DEVICE
(
USB_VID_IMC_NETWORKS
,
USB_PID_TWINHAN_VP7041_WARM
)
},
/* 21 */
{
USB_DEVICE
(
USB_VID_TWINHAN
,
USB_PID_TWINHAN_VP7041_COLD
)
},
/* 22 */
{
USB_DEVICE
(
USB_VID_TWINHAN
,
USB_PID_TWINHAN_VP7041_WARM
)
},
/* 23 */
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_COLD
)
},
/* 24 */
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_WARM
)
},
/* 25 */
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_AN2235_COLD
)
},
/* 26 */
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_AN2235_WARM
)
},
/* 27 */
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_USB2_COLD
)
},
/* 28 */
{
USB_DEVICE
(
USB_VID_HANFTEK
,
USB_PID_HANFTEK_UMT_010_COLD
)
},
/* 29 */
{
USB_DEVICE
(
USB_VID_HANFTEK
,
USB_PID_HANFTEK_UMT_010_WARM
)
},
/*
* activate the following define when you have one of the devices and want to
* build it from build-2.6 in dvb-kernel
*/
// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
/* 30 */
{
USB_DEVICE
(
USB_VID_ANCHOR
,
USB_PID_ULTIMA_TVBOX_ANCHOR_COLD
)
},
/* 31 */
{
USB_DEVICE
(
USB_VID_CYPRESS
,
USB_PID_ULTIMA_TVBOX_USB2_FX_COLD
)
},
/* 32 */
{
USB_DEVICE
(
USB_VID_ANCHOR
,
USB_PID_ULTIMA_TVBOX_USB2_FX_WARM
)
},
/* 33 */
{
USB_DEVICE
(
USB_VID_ANCHOR
,
USB_PID_DIBCOM_ANCHOR_2135_COLD
)
},
#endif
{
}
/* Terminating entry */
};
MODULE_DEVICE_TABLE
(
usb
,
dib_table
);
static
struct
dibusb_usb_controller
dibusb_usb_ctrl
[]
=
{
{
.
name
=
"Cypress AN2135"
,
.
cpu_cs_register
=
0x7f92
},
{
.
name
=
"Cypress AN2235"
,
.
cpu_cs_register
=
0x7f92
},
{
.
name
=
"Cypress FX2"
,
.
cpu_cs_register
=
0xe600
},
};
struct
dibusb_tuner
dibusb_tuner
[]
=
{
{
DIBUSB_TUNER_CABLE_THOMSON
,
0x61
},
{
DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5
,
0x60
},
{
DIBUSB_TUNER_CABLE_LG_TDTP_E102P
,
0x61
},
{
DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5
,
0x60
},
};
static
struct
dibusb_demod
dibusb_demod
[]
=
{
{
DIBUSB_DIB3000MB
,
16
,
{
0x8
,
0
},
},
{
DIBUSB_DIB3000MC
,
32
,
{
0x9
,
0xa
,
0xb
,
0xc
},
},
{
DIBUSB_MT352
,
254
,
{
0xf
,
0
},
},
};
static
struct
dibusb_device_class
dibusb_device_classes
[]
=
{
{
.
id
=
DIBUSB1_1
,
.
usb_ctrl
=
&
dibusb_usb_ctrl
[
0
],
.
firmware
=
"dvb-dibusb-5.0.0.11.fw"
,
.
pipe_cmd
=
0x01
,
.
pipe_data
=
0x02
,
.
urb_count
=
3
,
.
urb_buffer_size
=
4096
,
DIBUSB_RC_NEC_PROTOCOL
,
&
dibusb_demod
[
DIBUSB_DIB3000MB
],
&
dibusb_tuner
[
DIBUSB_TUNER_CABLE_THOMSON
],
},
{
DIBUSB1_1_AN2235
,
&
dibusb_usb_ctrl
[
1
],
"dvb-dibusb-an2235-1.fw"
,
0x01
,
0x02
,
3
,
4096
,
DIBUSB_RC_NEC_PROTOCOL
,
&
dibusb_demod
[
DIBUSB_DIB3000MB
],
&
dibusb_tuner
[
DIBUSB_TUNER_CABLE_THOMSON
],
},
{
DIBUSB2_0
,
&
dibusb_usb_ctrl
[
2
],
"dvb-dibusb-6.0.0.5.fw"
,
0x01
,
0x06
,
3
,
188
*
210
,
DIBUSB_RC_NEC_PROTOCOL
,
&
dibusb_demod
[
DIBUSB_DIB3000MC
],
&
dibusb_tuner
[
DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5
],
},
{
UMT2_0
,
&
dibusb_usb_ctrl
[
2
],
"dvb-dibusb-umt-1.fw"
,
0x01
,
0x02
,
15
,
188
*
21
,
DIBUSB_RC_NO
,
&
dibusb_demod
[
DIBUSB_MT352
],
// &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5],
&
dibusb_tuner
[
DIBUSB_TUNER_CABLE_LG_TDTP_E102P
],
},
};
static
struct
dibusb_usb_device
dibusb_devices
[]
=
{
{
"TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
19
],
&
dib_table
[
21
],
NULL
},
{
&
dib_table
[
20
],
&
dib_table
[
22
],
NULL
},
},
{
"KWorld V-Stream XPERT DTV - DVB-T USB1.1"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
11
],
NULL
},
{
&
dib_table
[
12
],
NULL
},
},
{
"Grandtec USB1.1 DVB-T"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
13
],
&
dib_table
[
15
],
NULL
},
{
&
dib_table
[
14
],
&
dib_table
[
16
],
NULL
},
},
{
"DiBcom USB1.1 DVB-T reference design (MOD3000)"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
7
],
NULL
},
{
&
dib_table
[
8
],
NULL
},
},
{
"Artec T1 USB1.1 TVBOX with AN2135"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
23
],
NULL
},
{
&
dib_table
[
24
],
NULL
},
},
{
"Artec T1 USB1.1 TVBOX with AN2235"
,
&
dibusb_device_classes
[
DIBUSB1_1_AN2235
],
{
&
dib_table
[
25
],
NULL
},
{
&
dib_table
[
26
],
NULL
},
},
{
"Avermedia AverTV DVBT USB1.1"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
0
],
NULL
},
{
&
dib_table
[
1
],
NULL
},
},
{
"Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
4
],
&
dib_table
[
6
],
NULL
},
{
&
dib_table
[
5
],
NULL
},
},
{
"Unkown USB1.1 DVB-T device ???? please report the name to the author"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
17
],
NULL
},
{
&
dib_table
[
18
],
NULL
},
},
{
"DiBcom USB2.0 DVB-T reference design (MOD3000P)"
,
&
dibusb_device_classes
[
DIBUSB2_0
],
{
&
dib_table
[
9
],
NULL
},
{
&
dib_table
[
10
],
NULL
},
},
{
"Artec T1 USB2.0 TVBOX (please report the warm ID)"
,
&
dibusb_device_classes
[
DIBUSB2_0
],
{
&
dib_table
[
27
],
NULL
},
{
NULL
},
},
{
"AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0"
,
&
dibusb_device_classes
[
UMT2_0
],
{
&
dib_table
[
2
],
NULL
},
{
NULL
},
},
{
"Hanftek UMT-010 DVB-T USB2.0"
,
&
dibusb_device_classes
[
UMT2_0
],
{
&
dib_table
[
28
],
NULL
},
{
&
dib_table
[
29
],
NULL
},
},
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
{
"Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)"
,
&
dibusb_device_classes
[
DIBUSB1_1_AN2235
],
{
&
dib_table
[
30
],
NULL
},
{
NULL
},
},
{
"Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)"
,
&
dibusb_device_classes
[
DIBUSB2_0
],
{
&
dib_table
[
31
],
NULL
},
{
&
dib_table
[
32
],
NULL
},
/* undefined, it could be that the device will get another USB ID in warm state */
},
{
"DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs"
,
&
dibusb_device_classes
[
DIBUSB1_1
],
{
&
dib_table
[
33
],
NULL
},
{
NULL
},
},
#endif
};
static
int
dibusb_exit
(
struct
usb_dibusb
*
dib
)
{
deb_info
(
"init_state before exiting everything: %x
\n
"
,
dib
->
init_state
);
dibusb_remote_exit
(
dib
);
dibusb_fe_exit
(
dib
);
dibusb_i2c_exit
(
dib
);
dibusb_pid_list_exit
(
dib
);
dibusb_dvb_exit
(
dib
);
dibusb_urb_exit
(
dib
);
deb_info
(
"init_state should be zero now: %x
\n
"
,
dib
->
init_state
);
dib
->
init_state
=
DIBUSB_STATE_INIT
;
kfree
(
dib
);
return
0
;
}
static
int
dibusb_init
(
struct
usb_dibusb
*
dib
)
{
int
ret
=
0
;
sema_init
(
&
dib
->
usb_sem
,
1
);
sema_init
(
&
dib
->
i2c_sem
,
1
);
dib
->
init_state
=
DIBUSB_STATE_INIT
;
if
((
ret
=
dibusb_urb_init
(
dib
))
||
(
ret
=
dibusb_dvb_init
(
dib
))
||
(
ret
=
dibusb_pid_list_init
(
dib
))
||
(
ret
=
dibusb_i2c_init
(
dib
)))
{
dibusb_exit
(
dib
);
return
ret
;
}
if
((
ret
=
dibusb_fe_init
(
dib
)))
err
(
"could not initialize a frontend."
);
if
((
ret
=
dibusb_remote_init
(
dib
)))
err
(
"could not initialize remote control."
);
return
0
;
}
static
struct
dibusb_usb_device
*
dibusb_find_device
(
struct
usb_device
*
udev
,
int
*
cold
)
{
int
i
,
j
;
*
cold
=
-
1
;
for
(
i
=
0
;
i
<
sizeof
(
dibusb_devices
)
/
sizeof
(
struct
dibusb_usb_device
);
i
++
)
{
for
(
j
=
0
;
j
<
DIBUSB_ID_MAX_NUM
&&
dibusb_devices
[
i
].
cold_ids
[
j
]
!=
NULL
;
j
++
)
{
deb_info
(
"check for cold %x %x
\n
"
,
dibusb_devices
[
i
].
cold_ids
[
j
]
->
idVendor
,
dibusb_devices
[
i
].
cold_ids
[
j
]
->
idProduct
);
if
(
dibusb_devices
[
i
].
cold_ids
[
j
]
->
idVendor
==
udev
->
descriptor
.
idVendor
&&
dibusb_devices
[
i
].
cold_ids
[
j
]
->
idProduct
==
udev
->
descriptor
.
idProduct
)
{
*
cold
=
1
;
return
&
dibusb_devices
[
i
];
}
}
for
(
j
=
0
;
j
<
DIBUSB_ID_MAX_NUM
&&
dibusb_devices
[
i
].
warm_ids
[
j
]
!=
NULL
;
j
++
)
{
deb_info
(
"check for warm %x %x
\n
"
,
dibusb_devices
[
i
].
warm_ids
[
j
]
->
idVendor
,
dibusb_devices
[
i
].
warm_ids
[
j
]
->
idProduct
);
if
(
dibusb_devices
[
i
].
warm_ids
[
j
]
->
idVendor
==
udev
->
descriptor
.
idVendor
&&
dibusb_devices
[
i
].
warm_ids
[
j
]
->
idProduct
==
udev
->
descriptor
.
idProduct
)
{
*
cold
=
0
;
return
&
dibusb_devices
[
i
];
}
}
}
return
NULL
;
}
/*
* USB
*/
static
int
dibusb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
struct
usb_dibusb
*
dib
=
NULL
;
struct
dibusb_usb_device
*
dibdev
=
NULL
;
int
ret
=
-
ENOMEM
,
cold
=
0
;
if
((
dibdev
=
dibusb_find_device
(
udev
,
&
cold
))
==
NULL
)
{
err
(
"something went very wrong, "
"unknown product ID: %.4x"
,
udev
->
descriptor
.
idProduct
);
return
-
ENODEV
;
}
if
(
cold
==
1
)
{
info
(
"found a '%s' in cold state, will try to load a firmware"
,
dibdev
->
name
);
ret
=
dibusb_loadfirmware
(
udev
,
dibdev
);
}
else
{
info
(
"found a '%s' in warm state."
,
dibdev
->
name
);
dib
=
kmalloc
(
sizeof
(
struct
usb_dibusb
),
GFP_KERNEL
);
if
(
dib
==
NULL
)
{
err
(
"no memory"
);
return
ret
;
}
memset
(
dib
,
0
,
sizeof
(
struct
usb_dibusb
));
dib
->
udev
=
udev
;
dib
->
dibdev
=
dibdev
;
usb_set_intfdata
(
intf
,
dib
);
ret
=
dibusb_init
(
dib
);
}
if
(
ret
==
0
)
info
(
"%s successfully initialized and connected."
,
dibdev
->
name
);
else
info
(
"%s error while loading driver (%d)"
,
dibdev
->
name
,
ret
);
return
ret
;
}
static
void
dibusb_disconnect
(
struct
usb_interface
*
intf
)
{
struct
usb_dibusb
*
dib
=
usb_get_intfdata
(
intf
);
const
char
*
name
=
DRIVER_DESC
;
usb_set_intfdata
(
intf
,
NULL
);
if
(
dib
!=
NULL
&&
dib
->
dibdev
!=
NULL
)
{
name
=
dib
->
dibdev
->
name
;
dibusb_exit
(
dib
);
}
info
(
"%s successfully deinitialized and disconnected."
,
name
);
}
/* usb specific object needed to register this driver with the usb subsystem */
struct
usb_driver
dibusb_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
DRIVER_DESC
,
.
probe
=
dibusb_probe
,
.
disconnect
=
dibusb_disconnect
,
.
id_table
=
dib_table
,
};
/* module stuff */
static
int
__init
usb_dibusb_init
(
void
)
{
int
result
;
if
((
result
=
usb_register
(
&
dibusb_driver
)))
{
err
(
"usb_register failed. Error number %d"
,
result
);
return
result
;
}
return
0
;
}
static
void
__exit
usb_dibusb_exit
(
void
)
{
/* deregister this driver from the USB subsystem */
usb_deregister
(
&
dibusb_driver
);
}
module_init
(
usb_dibusb_init
);
module_exit
(
usb_dibusb_exit
);
MODULE_AUTHOR
(
DRIVER_AUTHOR
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
0 → 100644
View file @
ca583a3c
/*
* dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for initializing and handling the
* linux-dvb API.
*/
#include "dvb-dibusb.h"
#include <linux/usb.h>
#include <linux/version.h>
static
u32
urb_compl_count
;
/*
* MPEG2 TS DVB stuff
*/
void
dibusb_urb_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
ptregs
)
{
struct
usb_dibusb
*
dib
=
urb
->
context
;
int
ret
;
deb_ts
(
"urb complete feedcount: %d, status: %d, length: %d
\n
"
,
dib
->
feedcount
,
urb
->
status
,
urb
->
actual_length
);
urb_compl_count
++
;
if
(
urb_compl_count
%
500
==
0
)
deb_info
(
"%d urbs completed so far.
\n
"
,
urb_compl_count
);
switch
(
urb
->
status
)
{
case
0
:
/* success */
case
-
ETIMEDOUT
:
/* NAK */
break
;
case
-
ECONNRESET
:
/* unlink */
case
-
ENOENT
:
case
-
ESHUTDOWN
:
return
;
default:
/* error */
warn
(
"urb completition error %d."
,
urb
->
status
);
}
if
(
dib
->
feedcount
>
0
)
{
deb_ts
(
"URB return len: %d
\n
"
,
urb
->
actual_length
);
if
(
urb
->
actual_length
%
188
)
deb_ts
(
"TS Packets: %d, %d
\n
"
,
urb
->
actual_length
/
188
,
urb
->
actual_length
%
188
);
/* Francois recommends to drop not full-filled packets, even if they may
* contain valid TS packets, at least for USB1.1
*
* if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready) */
if
(
dib
->
init_state
&
DIBUSB_STATE_DVB
)
dvb_dmx_swfilter
(
&
dib
->
demux
,
(
u8
*
)
urb
->
transfer_buffer
,
urb
->
actual_length
);
else
deb_ts
(
"URB dropped because of the "
"actual_length or !dvb_is_ready (%d).
\n
"
,
dib
->
init_state
&
DIBUSB_STATE_DVB
);
}
else
deb_ts
(
"URB dropped because of feedcount.
\n
"
);
ret
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
deb_ts
(
"urb resubmitted, (%d)
\n
"
,
ret
);
}
static
int
dibusb_ctrl_feed
(
struct
dvb_demux_feed
*
dvbdmxfeed
,
int
onoff
)
{
struct
usb_dibusb
*
dib
=
dvbdmxfeed
->
demux
->
priv
;
int
newfeedcount
;
if
(
dib
==
NULL
)
return
-
ENODEV
;
newfeedcount
=
dib
->
feedcount
+
(
onoff
?
1
:
-
1
);
/*
* stop feed before setting a new pid if there will be no pid anymore
*/
// if ((dib->dibdev->parm->firmware_bug && dib->feedcount) ||
if
(
newfeedcount
==
0
)
{
deb_ts
(
"stop feeding
\n
"
);
if
(
dib
->
xfer_ops
.
fifo_ctrl
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
fifo_ctrl
(
dib
->
fe
,
0
))
{
err
(
"error while inhibiting fifo."
);
return
-
ENODEV
;
}
}
}
dib
->
feedcount
=
newfeedcount
;
/* get a free pid from the list and activate it on the device
* specific pid_filter
*/
if
(
dib
->
pid_parse
)
dibusb_ctrl_pid
(
dib
,
dvbdmxfeed
,
onoff
);
/*
* start the feed, either if there is the firmware bug or
* if this was the first pid to set and there is still a pid for
* reception.
*/
// if ((dib->dibdev->parm->firmware_bug)
if
(
dib
->
feedcount
==
onoff
&&
dib
->
feedcount
>
0
)
{
deb_ts
(
"controlling pid parser
\n
"
);
if
(
dib
->
xfer_ops
.
pid_parse
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
pid_parse
(
dib
->
fe
,
dib
->
pid_parse
)
<
0
)
{
err
(
"could not handle pid_parser"
);
}
}
deb_ts
(
"start feeding
\n
"
);
if
(
dib
->
xfer_ops
.
fifo_ctrl
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
fifo_ctrl
(
dib
->
fe
,
1
))
{
err
(
"error while enabling fifo."
);
return
-
ENODEV
;
}
}
dibusb_streaming
(
dib
,
1
);
}
return
0
;
}
static
int
dibusb_start_feed
(
struct
dvb_demux_feed
*
dvbdmxfeed
)
{
deb_ts
(
"start pid: 0x%04x, feedtype: %d
\n
"
,
dvbdmxfeed
->
pid
,
dvbdmxfeed
->
type
);
return
dibusb_ctrl_feed
(
dvbdmxfeed
,
1
);
}
static
int
dibusb_stop_feed
(
struct
dvb_demux_feed
*
dvbdmxfeed
)
{
deb_ts
(
"stop pid: 0x%04x, feedtype: %d
\n
"
,
dvbdmxfeed
->
pid
,
dvbdmxfeed
->
type
);
return
dibusb_ctrl_feed
(
dvbdmxfeed
,
0
);
}
int
dibusb_dvb_init
(
struct
usb_dibusb
*
dib
)
{
int
ret
;
urb_compl_count
=
0
;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4)
if
((
ret
=
dvb_register_adapter
(
&
dib
->
adapter
,
DRIVER_DESC
))
<
0
)
{
#else
if
((
ret
=
dvb_register_adapter
(
&
dib
->
adapter
,
DRIVER_DESC
,
THIS_MODULE
))
<
0
)
{
#endif
deb_info
(
"dvb_register_adapter failed: error %d"
,
ret
);
goto
err
;
}
dib
->
adapter
->
priv
=
dib
;
/* i2c is done in dibusb_i2c_init */
dib
->
demux
.
dmx
.
capabilities
=
DMX_TS_FILTERING
|
DMX_SECTION_FILTERING
;
dib
->
demux
.
priv
=
(
void
*
)
dib
;
/* get pidcount from demod */
dib
->
demux
.
feednum
=
dib
->
demux
.
filternum
=
255
;
dib
->
demux
.
start_feed
=
dibusb_start_feed
;
dib
->
demux
.
stop_feed
=
dibusb_stop_feed
;
dib
->
demux
.
write_to_decoder
=
NULL
;
if
((
ret
=
dvb_dmx_init
(
&
dib
->
demux
))
<
0
)
{
err
(
"dvb_dmx_init failed: error %d"
,
ret
);
goto
err_dmx
;
}
dib
->
dmxdev
.
filternum
=
dib
->
demux
.
filternum
;
dib
->
dmxdev
.
demux
=
&
dib
->
demux
.
dmx
;
dib
->
dmxdev
.
capabilities
=
0
;
if
((
ret
=
dvb_dmxdev_init
(
&
dib
->
dmxdev
,
dib
->
adapter
))
<
0
)
{
err
(
"dvb_dmxdev_init failed: error %d"
,
ret
);
goto
err_dmx_dev
;
}
dvb_net_init
(
dib
->
adapter
,
&
dib
->
dvb_net
,
&
dib
->
demux
.
dmx
);
goto
success
;
err_dmx_dev:
dvb_dmx_release
(
&
dib
->
demux
);
err_dmx:
dvb_unregister_adapter
(
dib
->
adapter
);
err:
return
ret
;
success:
dib
->
init_state
|=
DIBUSB_STATE_DVB
;
return
0
;
}
int
dibusb_dvb_exit
(
struct
usb_dibusb
*
dib
)
{
if
(
dib
->
init_state
&
DIBUSB_STATE_DVB
)
{
dib
->
init_state
&=
~
DIBUSB_STATE_DVB
;
deb_info
(
"unregistering DVB part
\n
"
);
dvb_net_release
(
&
dib
->
dvb_net
);
dib
->
demux
.
dmx
.
close
(
&
dib
->
demux
.
dmx
);
dvb_dmxdev_release
(
&
dib
->
dmxdev
);
dvb_dmx_release
(
&
dib
->
demux
);
dvb_unregister_adapter
(
dib
->
adapter
);
}
return
0
;
}
drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
0 → 100644
View file @
ca583a3c
/*
* dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for attaching, initializing of an appropriate
* demodulator/frontend. I2C-stuff is also located here.
*
*/
#include "dvb-dibusb.h"
#include <linux/usb.h>
int
dibusb_i2c_msg
(
struct
usb_dibusb
*
dib
,
u8
addr
,
u8
*
wbuf
,
u16
wlen
,
u8
*
rbuf
,
u16
rlen
)
{
u8
sndbuf
[
wlen
+
4
];
/* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
/* write only ? */
int
wo
=
(
rbuf
==
NULL
||
rlen
==
0
),
len
=
2
+
wlen
+
(
wo
?
0
:
2
);
sndbuf
[
0
]
=
wo
?
DIBUSB_REQ_I2C_WRITE
:
DIBUSB_REQ_I2C_READ
;
sndbuf
[
1
]
=
(
addr
<<
1
)
|
(
wo
?
0
:
1
);
memcpy
(
&
sndbuf
[
2
],
wbuf
,
wlen
);
if
(
!
wo
)
{
sndbuf
[
wlen
+
2
]
=
(
rlen
>>
8
)
&
0xff
;
sndbuf
[
wlen
+
3
]
=
rlen
&
0xff
;
}
return
dibusb_readwrite_usb
(
dib
,
sndbuf
,
len
,
rbuf
,
rlen
);
}
/*
* I2C master xfer function
*/
static
int
dibusb_i2c_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
msg
[],
int
num
)
{
struct
usb_dibusb
*
dib
=
i2c_get_adapdata
(
adap
);
int
i
;
if
(
down_interruptible
(
&
dib
->
i2c_sem
)
<
0
)
return
-
EAGAIN
;
if
(
num
>
2
)
warn
(
"more than 2 i2c messages at a time is not handled yet. TODO."
);
for
(
i
=
0
;
i
<
num
;
i
++
)
{
/* write/read request */
if
(
i
+
1
<
num
&&
(
msg
[
i
+
1
].
flags
&
I2C_M_RD
))
{
if
(
dibusb_i2c_msg
(
dib
,
msg
[
i
].
addr
,
msg
[
i
].
buf
,
msg
[
i
].
len
,
msg
[
i
+
1
].
buf
,
msg
[
i
+
1
].
len
)
<
0
)
break
;
i
++
;
}
else
if
(
dibusb_i2c_msg
(
dib
,
msg
[
i
].
addr
,
msg
[
i
].
buf
,
msg
[
i
].
len
,
NULL
,
0
)
<
0
)
break
;
}
up
(
&
dib
->
i2c_sem
);
return
i
;
}
static
u32
dibusb_i2c_func
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_I2C
;
}
static
struct
i2c_algorithm
dibusb_algo
=
{
.
name
=
"DiBcom USB i2c algorithm"
,
.
id
=
I2C_ALGO_BIT
,
.
master_xfer
=
dibusb_i2c_xfer
,
.
functionality
=
dibusb_i2c_func
,
};
static
int
dibusb_general_demod_init
(
struct
dvb_frontend
*
fe
);
static
u8
dibusb_general_pll_addr
(
struct
dvb_frontend
*
fe
);
static
int
dibusb_general_pll_init
(
struct
dvb_frontend
*
fe
,
u8
pll_buf
[
5
]);
static
int
dibusb_general_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
,
u8
pll_buf
[
5
]);
static
struct
mt352_config
mt352_hanftek_umt_010_config
=
{
.
demod_address
=
0x1e
,
.
demod_init
=
dibusb_general_demod_init
,
.
pll_set
=
dibusb_general_pll_set
,
};
static
int
dibusb_tuner_quirk
(
struct
usb_dibusb
*
dib
)
{
switch
(
dib
->
dibdev
->
dev_cl
->
id
)
{
case
DIBUSB1_1
:
/* some these device have the ENV77H11D5 and some the THOMSON CABLE */
case
DIBUSB1_1_AN2235
:
{
/* actually its this device, but in warm state they are indistinguishable */
struct
dibusb_tuner
*
t
;
u8
b
[
2
]
=
{
0
,
0
}
,
b2
[
1
];
struct
i2c_msg
msg
[
2
]
=
{
{
.
flags
=
0
,
.
buf
=
b
,
.
len
=
2
},
{
.
flags
=
I2C_M_RD
,
.
buf
=
b2
,
.
len
=
1
},
};
t
=
&
dibusb_tuner
[
DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5
];
msg
[
0
].
addr
=
msg
[
1
].
addr
=
t
->
pll_addr
;
if
(
dib
->
xfer_ops
.
tuner_pass_ctrl
!=
NULL
)
dib
->
xfer_ops
.
tuner_pass_ctrl
(
dib
->
fe
,
1
,
t
->
pll_addr
);
dibusb_i2c_xfer
(
&
dib
->
i2c_adap
,
msg
,
2
);
if
(
dib
->
xfer_ops
.
tuner_pass_ctrl
!=
NULL
)
dib
->
xfer_ops
.
tuner_pass_ctrl
(
dib
->
fe
,
0
,
t
->
pll_addr
);
if
(
b2
[
0
]
==
0xfe
)
info
(
"this device has the Thomson Cable onboard. Which is default."
);
else
{
dib
->
tuner
=
t
;
info
(
"this device has the Panasonic ENV77H11D5 onboard."
);
}
break
;
}
default:
break
;
}
return
0
;
}
/* there is a ugly pid_filter in the firmware of the umt devices, it is accessible
* by i2c address 0x8. Don't know how to deactivate it and how many rows it has.
*/
static
int
dibusb_umt_pid_control
(
struct
dvb_frontend
*
fe
,
int
index
,
int
pid
,
int
onoff
)
{
struct
usb_dibusb
*
dib
=
fe
->
dvb
->
priv
;
u8
b
[
3
];
b
[
0
]
=
index
;
if
(
onoff
)
{
b
[
1
]
=
(
pid
>>
8
)
&
0xff
;
b
[
2
]
=
pid
&
0xff
;
}
else
{
b
[
1
]
=
0
;
b
[
2
]
=
0
;
}
dibusb_i2c_msg
(
dib
,
0x8
,
b
,
3
,
NULL
,
0
);
dibusb_set_streaming_mode
(
dib
,
0
);
dibusb_set_streaming_mode
(
dib
,
1
);
return
0
;
}
int
dibusb_fe_init
(
struct
usb_dibusb
*
dib
)
{
struct
dib3000_config
demod_cfg
;
int
i
;
if
(
dib
->
init_state
&
DIBUSB_STATE_I2C
)
{
for
(
i
=
0
;
i
<
sizeof
(
dib
->
dibdev
->
dev_cl
->
demod
->
i2c_addrs
)
/
sizeof
(
unsigned
char
)
&&
dib
->
dibdev
->
dev_cl
->
demod
->
i2c_addrs
[
i
]
!=
0
;
i
++
)
{
demod_cfg
.
demod_address
=
dib
->
dibdev
->
dev_cl
->
demod
->
i2c_addrs
[
i
];
demod_cfg
.
pll_addr
=
dibusb_general_pll_addr
;
demod_cfg
.
pll_set
=
dibusb_general_pll_set
;
demod_cfg
.
pll_init
=
dibusb_general_pll_init
;
switch
(
dib
->
dibdev
->
dev_cl
->
demod
->
id
)
{
case
DIBUSB_DIB3000MB
:
dib
->
fe
=
dib3000mb_attach
(
&
demod_cfg
,
&
dib
->
i2c_adap
,
&
dib
->
xfer_ops
);
break
;
case
DIBUSB_DIB3000MC
:
dib
->
fe
=
dib3000mc_attach
(
&
demod_cfg
,
&
dib
->
i2c_adap
,
&
dib
->
xfer_ops
);
break
;
case
DIBUSB_MT352
:
mt352_hanftek_umt_010_config
.
demod_address
=
dib
->
dibdev
->
dev_cl
->
demod
->
i2c_addrs
[
i
];
dib
->
fe
=
mt352_attach
(
&
mt352_hanftek_umt_010_config
,
&
dib
->
i2c_adap
);
dib
->
xfer_ops
.
pid_ctrl
=
dibusb_umt_pid_control
;
break
;
}
if
(
dib
->
fe
!=
NULL
)
{
info
(
"found demodulator at i2c address 0x%x"
,
dib
->
dibdev
->
dev_cl
->
demod
->
i2c_addrs
[
i
]);
break
;
}
}
if
(
dib
->
fe
->
ops
->
sleep
!=
NULL
)
dib
->
fe_sleep
=
dib
->
fe
->
ops
->
sleep
;
dib
->
fe
->
ops
->
sleep
=
dibusb_hw_sleep
;
if
(
dib
->
fe
->
ops
->
init
!=
NULL
)
dib
->
fe_init
=
dib
->
fe
->
ops
->
init
;
dib
->
fe
->
ops
->
init
=
dibusb_hw_wakeup
;
/* setting the default tuner */
dib
->
tuner
=
dib
->
dibdev
->
dev_cl
->
tuner
;
/* check which tuner is mounted on this device, in case this is unsure */
dibusb_tuner_quirk
(
dib
);
}
if
(
dib
->
fe
==
NULL
)
{
err
(
"A frontend driver was not found for device '%s'."
,
dib
->
dibdev
->
name
);
return
-
ENODEV
;
}
else
{
if
(
dvb_register_frontend
(
dib
->
adapter
,
dib
->
fe
))
{
err
(
"Frontend registration failed."
);
if
(
dib
->
fe
->
ops
->
release
)
dib
->
fe
->
ops
->
release
(
dib
->
fe
);
dib
->
fe
=
NULL
;
return
-
ENODEV
;
}
}
return
0
;
}
int
dibusb_fe_exit
(
struct
usb_dibusb
*
dib
)
{
if
(
dib
->
fe
!=
NULL
)
dvb_unregister_frontend
(
dib
->
fe
);
return
0
;
}
int
dibusb_i2c_init
(
struct
usb_dibusb
*
dib
)
{
int
ret
=
0
;
dib
->
adapter
->
priv
=
dib
;
strncpy
(
dib
->
i2c_adap
.
name
,
dib
->
dibdev
->
name
,
I2C_NAME_SIZE
);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
dib
->
i2c_adap
.
class
=
I2C_ADAP_CLASS_TV_DIGITAL
,
#else
dib
->
i2c_adap
.
class
=
I2C_CLASS_TV_DIGITAL
,
#endif
dib
->
i2c_adap
.
algo
=
&
dibusb_algo
;
dib
->
i2c_adap
.
algo_data
=
NULL
;
dib
->
i2c_adap
.
id
=
I2C_ALGO_BIT
;
i2c_set_adapdata
(
&
dib
->
i2c_adap
,
dib
);
if
((
ret
=
i2c_add_adapter
(
&
dib
->
i2c_adap
))
<
0
)
err
(
"could not add i2c adapter"
);
dib
->
init_state
|=
DIBUSB_STATE_I2C
;
return
ret
;
}
int
dibusb_i2c_exit
(
struct
usb_dibusb
*
dib
)
{
if
(
dib
->
init_state
&
DIBUSB_STATE_I2C
)
i2c_del_adapter
(
&
dib
->
i2c_adap
);
dib
->
init_state
&=
~
DIBUSB_STATE_I2C
;
return
0
;
}
/* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */
static
int
thomson_cable_eu_pll_set
(
struct
dvb_frontend_parameters
*
fep
,
u8
pllbuf
[
4
])
{
u32
tfreq
=
(
fep
->
frequency
+
36125000
)
/
62500
;
int
vu
,
p0
,
p1
,
p2
;
if
(
fep
->
frequency
>
403250000
)
vu
=
1
,
p2
=
1
,
p1
=
0
,
p0
=
1
;
else
if
(
fep
->
frequency
>
115750000
)
vu
=
0
,
p2
=
1
,
p1
=
1
,
p0
=
0
;
else
if
(
fep
->
frequency
>
44250000
)
vu
=
0
,
p2
=
0
,
p1
=
1
,
p0
=
1
;
else
return
-
EINVAL
;
pllbuf
[
0
]
=
(
tfreq
>>
8
)
&
0x7f
;
pllbuf
[
1
]
=
tfreq
&
0xff
;
pllbuf
[
2
]
=
0x8e
;
pllbuf
[
3
]
=
(
vu
<<
7
)
|
(
p2
<<
2
)
|
(
p1
<<
1
)
|
p0
;
return
0
;
}
static
int
panasonic_cofdm_env57h1xd5_pll_set
(
struct
dvb_frontend_parameters
*
fep
,
u8
pllbuf
[
4
])
{
u32
freq
=
fep
->
frequency
;
u32
tfreq
=
((
freq
+
36125000
)
*
6
+
500000
)
/
1000000
;
u8
TA
,
T210
,
R210
,
ctrl1
,
cp210
,
p4321
;
if
(
freq
>
858000000
)
{
err
(
"frequency cannot be larger than 858 MHz."
);
return
-
EINVAL
;
}
// contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
TA
=
1
;
T210
=
0
;
R210
=
0x2
;
ctrl1
=
(
1
<<
7
)
|
(
TA
<<
6
)
|
(
T210
<<
3
)
|
R210
;
// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES *****************
if
(
freq
<
470000000
)
cp210
=
2
;
// VHF Low and High band ch E12 to E4 to E12
else
if
(
freq
<
526000000
)
cp210
=
4
;
// UHF band Ch E21 to E27
else
// if (freq < 862000000)
cp210
=
5
;
// UHF band ch E28 to E69
//********************* BW select *******************************
if
(
freq
<
153000000
)
p4321
=
1
;
// BW selected for VHF low
else
if
(
freq
<
470000000
)
p4321
=
2
;
// BW selected for VHF high E5 to E12
else
// if (freq < 862000000)
p4321
=
4
;
// BW selection for UHF E21 to E69
pllbuf
[
0
]
=
(
tfreq
>>
8
)
&
0xff
;
pllbuf
[
1
]
=
(
tfreq
>>
0
)
&
0xff
;
pllbuf
[
2
]
=
0xff
&
ctrl1
;
pllbuf
[
3
]
=
(
cp210
<<
5
)
|
(
p4321
);
return
0
;
}
/*
* 7 6 5 4 3 2 1 0
* Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0
*
* Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8
* Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0
*
* Control byte 1 1 T/A=1 T2 T1 T0 R2 R1 R0
* 1 T/A=0 0 0 ATC AL2 AL1 AL0
*
* Control byte 2 CP2 CP1 CP0 BS5 BS4 BS3 BS2 BS1
*
* MA0/1 = programmable address bits
* R/~W = read/write bit (0 for writing)
* N14-0 = programmable LO frequency
*
* T/A = test AGC bit (0 = next 6 bits AGC setting,
* 1 = next 6 bits test and reference divider ratio settings)
* T2-0 = test bits
* R2-0 = reference divider ratio and programmable frequency step
* ATC = AGC current setting and time constant
* ATC = 0: AGC current = 220nA, AGC time constant = 2s
* ATC = 1: AGC current = 9uA, AGC time constant = 50ms
* AL2-0 = AGC take-over point bits
* CP2-0 = charge pump current
* BS5-1 = PMOS ports control bits;
* BSn = 0 corresponding port is off, high-impedance state (at power-on)
* BSn = 1 corresponding port is on
*/
static
int
panasonic_cofdm_env77h11d5_tda6650_init
(
struct
dvb_frontend
*
fe
,
u8
pllbuf
[
4
])
{
pllbuf
[
0
]
=
0x0b
;
pllbuf
[
1
]
=
0xf5
;
pllbuf
[
2
]
=
0x85
;
pllbuf
[
3
]
=
0xab
;
return
0
;
}
static
int
panasonic_cofdm_env77h11d5_tda6650_set
(
struct
dvb_frontend_parameters
*
fep
,
u8
pllbuf
[
4
])
{
int
tuner_frequency
=
0
;
u8
band
,
cp
,
filter
;
// determine charge pump
tuner_frequency
=
fep
->
frequency
+
36166000
;
if
(
tuner_frequency
<
87000000
)
return
-
EINVAL
;
else
if
(
tuner_frequency
<
130000000
)
cp
=
3
;
else
if
(
tuner_frequency
<
160000000
)
cp
=
5
;
else
if
(
tuner_frequency
<
200000000
)
cp
=
6
;
else
if
(
tuner_frequency
<
290000000
)
cp
=
3
;
else
if
(
tuner_frequency
<
420000000
)
cp
=
5
;
else
if
(
tuner_frequency
<
480000000
)
cp
=
6
;
else
if
(
tuner_frequency
<
620000000
)
cp
=
3
;
else
if
(
tuner_frequency
<
830000000
)
cp
=
5
;
else
if
(
tuner_frequency
<
895000000
)
cp
=
7
;
else
return
-
EINVAL
;
// determine band
if
(
fep
->
frequency
<
49000000
)
return
-
EINVAL
;
else
if
(
fep
->
frequency
<
161000000
)
band
=
1
;
else
if
(
fep
->
frequency
<
444000000
)
band
=
2
;
else
if
(
fep
->
frequency
<
861000000
)
band
=
4
;
else
return
-
EINVAL
;
// setup PLL filter
switch
(
fep
->
u
.
ofdm
.
bandwidth
)
{
case
BANDWIDTH_6_MHZ
:
case
BANDWIDTH_7_MHZ
:
filter
=
0
;
break
;
case
BANDWIDTH_8_MHZ
:
filter
=
1
;
break
;
default:
return
-
EINVAL
;
}
// calculate divisor
// ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
tuner_frequency
=
(((
fep
->
frequency
/
1000
)
*
6
)
+
217496
)
/
1000
;
// setup tuner buffer
pllbuf
[
0
]
=
(
tuner_frequency
>>
8
)
&
0x7f
;
pllbuf
[
1
]
=
tuner_frequency
&
0xff
;
pllbuf
[
2
]
=
0xca
;
pllbuf
[
3
]
=
(
cp
<<
5
)
|
(
filter
<<
3
)
|
band
;
return
0
;
}
/*
* 7 6 5 4 3 2 1 0
* Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0
*
* Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8
* Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0
*
* Control byte 1 CP T2 T1 T0 RSA RSB OS
*
* Band Switch byte X X X P4 P3 P2 P1 P0
*
* Auxiliary byte ATC AL2 AL1 AL0 0 0 0 0
*
* Address: MA1 MA0 Address
* 0 0 c0
* 0 1 c2 (always valid)
* 1 0 c4
* 1 1 c6
*
*
*
*/
static
int
lg_tdtp_e102p_tua6034
(
struct
dvb_frontend_parameters
*
fep
,
u8
pllbuf
[
4
])
{
u32
div
;
u8
p3210
,
p4
;
#define TUNER_MUL 62500
div
=
(
fep
->
frequency
+
36125000
+
TUNER_MUL
/
2
)
/
TUNER_MUL
;
if
(
fep
->
frequency
<
174500000
)
p3210
=
1
;
// not supported by the tdtp_e102p
else
if
(
fep
->
frequency
<
230000000
)
// VHF
p3210
=
2
;
else
p3210
=
4
;
if
(
fep
->
u
.
ofdm
.
bandwidth
==
BANDWIDTH_7_MHZ
)
p4
=
0
;
else
p4
=
1
;
pllbuf
[
0
]
=
(
div
>>
8
)
&
0x7f
;
pllbuf
[
1
]
=
div
&
0xff
;
pllbuf
[
2
]
=
0xce
;
pllbuf
[
3
]
=
(
p4
<<
4
)
|
p3210
;
return
0
;
}
static
int
lg_tdtp_e102p_mt352_demod_init
(
struct
dvb_frontend
*
fe
)
{
static
u8
mt352_clock_config
[]
=
{
0x89
,
0xb0
,
0x2d
};
static
u8
mt352_reset
[]
=
{
0x50
,
0x80
};
static
u8
mt352_mclk_ratio
[]
=
{
0x8b
,
0x00
};
static
u8
mt352_adc_ctl_1_cfg
[]
=
{
0x8E
,
0x40
};
static
u8
mt352_agc_cfg
[]
=
{
0x67
,
0x14
,
0x22
};
static
u8
mt352_sec_agc_cfg
[]
=
{
0x69
,
0x00
,
0xff
,
0xff
,
0x00
,
0xff
,
0x00
,
0x40
,
0x40
};
static
u8
mt352_unk
[]
=
{
0xb5
,
0x7a
};
static
u8
mt352_acq_ctl
[]
=
{
0x53
,
0x5f
};
static
u8
mt352_input_freq_1
[]
=
{
0x56
,
0xf1
,
0x05
};
// static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write
(
fe
,
mt352_clock_config
,
sizeof
(
mt352_clock_config
));
udelay
(
2000
);
mt352_write
(
fe
,
mt352_reset
,
sizeof
(
mt352_reset
));
mt352_write
(
fe
,
mt352_mclk_ratio
,
sizeof
(
mt352_mclk_ratio
));
mt352_write
(
fe
,
mt352_adc_ctl_1_cfg
,
sizeof
(
mt352_adc_ctl_1_cfg
));
mt352_write
(
fe
,
mt352_agc_cfg
,
sizeof
(
mt352_agc_cfg
));
mt352_write
(
fe
,
mt352_sec_agc_cfg
,
sizeof
(
mt352_sec_agc_cfg
));
mt352_write
(
fe
,
mt352_unk
,
sizeof
(
mt352_unk
));
mt352_write
(
fe
,
mt352_acq_ctl
,
sizeof
(
mt352_acq_ctl
));
mt352_write
(
fe
,
mt352_input_freq_1
,
sizeof
(
mt352_input_freq_1
));
// mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
return
0
;
}
static
int
dibusb_general_demod_init
(
struct
dvb_frontend
*
fe
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
switch
(
dib
->
dibdev
->
dev_cl
->
id
)
{
case
UMT2_0
:
return
lg_tdtp_e102p_mt352_demod_init
(
fe
);
default:
/* other device classes do not have device specific demod inits */
break
;
}
return
0
;
}
static
u8
dibusb_general_pll_addr
(
struct
dvb_frontend
*
fe
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
return
dib
->
tuner
->
pll_addr
;
}
static
int
dibusb_pll_i2c_helper
(
struct
usb_dibusb
*
dib
,
u8
pll_buf
[
5
],
u8
buf
[
4
])
{
if
(
pll_buf
==
NULL
)
{
struct
i2c_msg
msg
=
{
.
addr
=
dib
->
tuner
->
pll_addr
,
.
flags
=
0
,
.
buf
=
buf
,
.
len
=
sizeof
(
buf
)
};
if
(
i2c_transfer
(
&
dib
->
i2c_adap
,
&
msg
,
1
)
!=
1
)
return
-
EIO
;
msleep
(
1
);
}
else
{
pll_buf
[
0
]
=
dib
->
tuner
->
pll_addr
<<
1
;
memcpy
(
&
pll_buf
[
1
],
buf
,
4
);
}
return
0
;
}
static
int
dibusb_general_pll_init
(
struct
dvb_frontend
*
fe
,
u8
pll_buf
[
5
])
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
u8
buf
[
4
];
int
ret
=
0
;
switch
(
dib
->
tuner
->
id
)
{
case
DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5
:
ret
=
panasonic_cofdm_env77h11d5_tda6650_init
(
fe
,
buf
);
break
;
default:
break
;
}
if
(
ret
)
return
ret
;
return
dibusb_pll_i2c_helper
(
dib
,
pll_buf
,
buf
);
}
static
int
dibusb_general_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
fep
,
u8
pll_buf
[
5
])
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
u8
buf
[
4
];
int
ret
=
0
;
switch
(
dib
->
tuner
->
id
)
{
case
DIBUSB_TUNER_CABLE_THOMSON
:
ret
=
thomson_cable_eu_pll_set
(
fep
,
buf
);
break
;
case
DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5
:
ret
=
panasonic_cofdm_env57h1xd5_pll_set
(
fep
,
buf
);
break
;
case
DIBUSB_TUNER_CABLE_LG_TDTP_E102P
:
ret
=
lg_tdtp_e102p_tua6034
(
fep
,
buf
);
break
;
case
DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5
:
ret
=
panasonic_cofdm_env77h11d5_tda6650_set
(
fep
,
buf
);
break
;
default:
warn
(
"no pll programming routine found for tuner %d.
\n
"
,
dib
->
tuner
->
id
);
ret
=
-
ENODEV
;
break
;
}
if
(
ret
)
return
ret
;
return
dibusb_pll_i2c_helper
(
dib
,
pll_buf
,
buf
);
}
drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
0 → 100644
View file @
ca583a3c
/*
* dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for downloading the firmware to the device.
*/
#include "dvb-dibusb.h"
#include <linux/firmware.h>
#include <linux/usb.h>
/*
* load a firmware packet to the device
*/
static
int
dibusb_writemem
(
struct
usb_device
*
udev
,
u16
addr
,
u8
*
data
,
u8
len
)
{
return
usb_control_msg
(
udev
,
usb_sndctrlpipe
(
udev
,
0
),
0xa0
,
USB_TYPE_VENDOR
,
addr
,
0x00
,
data
,
len
,
5
*
HZ
);
}
int
dibusb_loadfirmware
(
struct
usb_device
*
udev
,
struct
dibusb_usb_device
*
dibdev
)
{
const
struct
firmware
*
fw
=
NULL
;
u16
addr
;
u8
*
b
,
*
p
;
int
ret
=
0
,
i
;
if
((
ret
=
request_firmware
(
&
fw
,
dibdev
->
dev_cl
->
firmware
,
&
udev
->
dev
))
!=
0
)
{
err
(
"did not find a valid firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details on firmware-problems."
,
dibdev
->
dev_cl
->
firmware
);
return
ret
;
}
p
=
kmalloc
(
fw
->
size
,
GFP_KERNEL
);
if
(
p
!=
NULL
)
{
u8
reset
;
/*
* you cannot use the fw->data as buffer for
* usb_control_msg, a new buffer has to be
* created
*/
memcpy
(
p
,
fw
->
data
,
fw
->
size
);
/* stop the CPU */
reset
=
1
;
if
((
ret
=
dibusb_writemem
(
udev
,
dibdev
->
dev_cl
->
usb_ctrl
->
cpu_cs_register
,
&
reset
,
1
))
!=
1
)
err
(
"could not stop the USB controller CPU."
);
for
(
i
=
0
;
p
[
i
+
3
]
==
0
&&
i
<
fw
->
size
;
)
{
b
=
(
u8
*
)
&
p
[
i
];
addr
=
*
((
u16
*
)
&
b
[
1
]);
ret
=
dibusb_writemem
(
udev
,
addr
,
&
b
[
4
],
b
[
0
]);
if
(
ret
!=
b
[
0
])
{
err
(
"error while transferring firmware "
"(transferred size: %d, block size: %d)"
,
ret
,
b
[
0
]);
ret
=
-
EINVAL
;
break
;
}
i
+=
5
+
b
[
0
];
}
/* length in ret */
if
(
ret
>
0
)
ret
=
0
;
/* restart the CPU */
reset
=
0
;
if
(
ret
||
dibusb_writemem
(
udev
,
dibdev
->
dev_cl
->
usb_ctrl
->
cpu_cs_register
,
&
reset
,
1
)
!=
1
)
{
err
(
"could not restart the USB controller CPU."
);
ret
=
-
EINVAL
;
}
kfree
(
p
);
}
else
{
ret
=
-
ENOMEM
;
}
release_firmware
(
fw
);
return
ret
;
}
drivers/media/dvb/dibusb/dvb-dibusb-pid.c
0 → 100644
View file @
ca583a3c
/*
* dvb-dibusb-pid.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for initializing and handling the internal
* pid-list. This pid-list mirrors the information currently stored in the
* devices pid-list.
*/
#include "dvb-dibusb.h"
int
dibusb_pid_list_init
(
struct
usb_dibusb
*
dib
)
{
int
i
;
dib
->
pid_list
=
kmalloc
(
sizeof
(
struct
dibusb_pid
)
*
dib
->
dibdev
->
dev_cl
->
demod
->
pid_filter_count
,
GFP_KERNEL
);
if
(
dib
->
pid_list
==
NULL
)
return
-
ENOMEM
;
deb_xfer
(
"initializing %d pids for the pid_list.
\n
"
,
dib
->
dibdev
->
dev_cl
->
demod
->
pid_filter_count
);
dib
->
pid_list_lock
=
SPIN_LOCK_UNLOCKED
;
memset
(
dib
->
pid_list
,
0
,
dib
->
dibdev
->
dev_cl
->
demod
->
pid_filter_count
*
(
sizeof
(
struct
dibusb_pid
)));
for
(
i
=
0
;
i
<
dib
->
dibdev
->
dev_cl
->
demod
->
pid_filter_count
;
i
++
)
{
dib
->
pid_list
[
i
].
index
=
i
;
dib
->
pid_list
[
i
].
pid
=
0
;
dib
->
pid_list
[
i
].
active
=
0
;
}
dib
->
init_state
|=
DIBUSB_STATE_PIDLIST
;
return
0
;
}
void
dibusb_pid_list_exit
(
struct
usb_dibusb
*
dib
)
{
if
(
dib
->
init_state
&
DIBUSB_STATE_PIDLIST
)
kfree
(
dib
->
pid_list
);
dib
->
init_state
&=
~
DIBUSB_STATE_PIDLIST
;
}
/* fetch a pid from pid_list and set it on or off */
int
dibusb_ctrl_pid
(
struct
usb_dibusb
*
dib
,
struct
dvb_demux_feed
*
dvbdmxfeed
,
int
onoff
)
{
int
i
,
ret
=
-
1
;
unsigned
long
flags
;
u16
pid
=
dvbdmxfeed
->
pid
;
if
(
onoff
)
{
spin_lock_irqsave
(
&
dib
->
pid_list_lock
,
flags
);
for
(
i
=
0
;
i
<
dib
->
dibdev
->
dev_cl
->
demod
->
pid_filter_count
;
i
++
)
if
(
!
dib
->
pid_list
[
i
].
active
)
{
dib
->
pid_list
[
i
].
pid
=
pid
;
dib
->
pid_list
[
i
].
active
=
1
;
ret
=
i
;
break
;
}
dvbdmxfeed
->
priv
=
&
dib
->
pid_list
[
ret
];
spin_unlock_irqrestore
(
&
dib
->
pid_list_lock
,
flags
);
if
(
dib
->
xfer_ops
.
pid_ctrl
!=
NULL
)
dib
->
xfer_ops
.
pid_ctrl
(
dib
->
fe
,
dib
->
pid_list
[
ret
].
index
,
dib
->
pid_list
[
ret
].
pid
,
1
);
}
else
{
struct
dibusb_pid
*
dpid
=
dvbdmxfeed
->
priv
;
if
(
dib
->
xfer_ops
.
pid_ctrl
!=
NULL
)
dib
->
xfer_ops
.
pid_ctrl
(
dib
->
fe
,
dpid
->
index
,
0
,
0
);
dpid
->
pid
=
0
;
dpid
->
active
=
0
;
ret
=
dpid
->
index
;
}
/* a free pid from the list */
deb_info
(
"setting pid: %5d %04x at index %d '%s'
\n
"
,
pid
,
pid
,
ret
,
onoff
?
"on"
:
"off"
);
return
ret
;
}
drivers/media/dvb/dibusb/dvb-dibusb-remote.c
0 → 100644
View file @
ca583a3c
/*
* dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for handling the event device on the software
* side and the remote control on the hardware side.
*/
#include "dvb-dibusb.h"
/* Table to map raw key codes to key events. This should not be hard-wired
into the kernel. */
static
const
struct
{
u8
c0
,
c1
,
c2
;
uint32_t
key
;
}
rc_keys
[]
=
{
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{
0x00
,
0xff
,
0x16
,
KEY_POWER
},
{
0x00
,
0xff
,
0x10
,
KEY_MUTE
},
{
0x00
,
0xff
,
0x03
,
KEY_1
},
{
0x00
,
0xff
,
0x01
,
KEY_2
},
{
0x00
,
0xff
,
0x06
,
KEY_3
},
{
0x00
,
0xff
,
0x09
,
KEY_4
},
{
0x00
,
0xff
,
0x1d
,
KEY_5
},
{
0x00
,
0xff
,
0x1f
,
KEY_6
},
{
0x00
,
0xff
,
0x0d
,
KEY_7
},
{
0x00
,
0xff
,
0x19
,
KEY_8
},
{
0x00
,
0xff
,
0x1b
,
KEY_9
},
{
0x00
,
0xff
,
0x15
,
KEY_0
},
{
0x00
,
0xff
,
0x05
,
KEY_CHANNELUP
},
{
0x00
,
0xff
,
0x02
,
KEY_CHANNELDOWN
},
{
0x00
,
0xff
,
0x1e
,
KEY_VOLUMEUP
},
{
0x00
,
0xff
,
0x0a
,
KEY_VOLUMEDOWN
},
{
0x00
,
0xff
,
0x11
,
KEY_RECORD
},
{
0x00
,
0xff
,
0x17
,
KEY_FAVORITES
},
/* Heart symbol - Channel list. */
{
0x00
,
0xff
,
0x14
,
KEY_PLAY
},
{
0x00
,
0xff
,
0x1a
,
KEY_STOP
},
{
0x00
,
0xff
,
0x40
,
KEY_REWIND
},
{
0x00
,
0xff
,
0x12
,
KEY_FASTFORWARD
},
{
0x00
,
0xff
,
0x0e
,
KEY_PREVIOUS
},
/* Recall - Previous channel. */
{
0x00
,
0xff
,
0x4c
,
KEY_PAUSE
},
{
0x00
,
0xff
,
0x4d
,
KEY_SCREEN
},
/* Full screen mode. */
{
0x00
,
0xff
,
0x54
,
KEY_AUDIO
},
/* MTS - Switch to secondary audio. */
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
{
0x00
,
0xff
,
0x0c
,
KEY_CANCEL
},
/* Cancel */
{
0x00
,
0xff
,
0x1c
,
KEY_EPG
},
/* EPG */
{
0x00
,
0xff
,
0x00
,
KEY_TAB
},
/* Tab */
{
0x00
,
0xff
,
0x48
,
KEY_INFO
},
/* Preview */
{
0x00
,
0xff
,
0x04
,
KEY_LIST
},
/* RecordList */
{
0x00
,
0xff
,
0x0f
,
KEY_TEXT
},
/* Teletext */
/* Key codes for the KWorld/ADSTech/JetWay remote. */
{
0x86
,
0x6b
,
0x12
,
KEY_POWER
},
{
0x86
,
0x6b
,
0x0f
,
KEY_SELECT
},
/* source */
{
0x86
,
0x6b
,
0x0c
,
KEY_UNKNOWN
},
/* scan */
{
0x86
,
0x6b
,
0x0b
,
KEY_EPG
},
{
0x86
,
0x6b
,
0x10
,
KEY_MUTE
},
{
0x86
,
0x6b
,
0x01
,
KEY_1
},
{
0x86
,
0x6b
,
0x02
,
KEY_2
},
{
0x86
,
0x6b
,
0x03
,
KEY_3
},
{
0x86
,
0x6b
,
0x04
,
KEY_4
},
{
0x86
,
0x6b
,
0x05
,
KEY_5
},
{
0x86
,
0x6b
,
0x06
,
KEY_6
},
{
0x86
,
0x6b
,
0x07
,
KEY_7
},
{
0x86
,
0x6b
,
0x08
,
KEY_8
},
{
0x86
,
0x6b
,
0x09
,
KEY_9
},
{
0x86
,
0x6b
,
0x0a
,
KEY_0
},
{
0x86
,
0x6b
,
0x18
,
KEY_ZOOM
},
{
0x86
,
0x6b
,
0x1c
,
KEY_UNKNOWN
},
/* preview */
{
0x86
,
0x6b
,
0x13
,
KEY_UNKNOWN
},
/* snap */
{
0x86
,
0x6b
,
0x00
,
KEY_UNDO
},
{
0x86
,
0x6b
,
0x1d
,
KEY_RECORD
},
{
0x86
,
0x6b
,
0x0d
,
KEY_STOP
},
{
0x86
,
0x6b
,
0x0e
,
KEY_PAUSE
},
{
0x86
,
0x6b
,
0x16
,
KEY_PLAY
},
{
0x86
,
0x6b
,
0x11
,
KEY_BACK
},
{
0x86
,
0x6b
,
0x19
,
KEY_FORWARD
},
{
0x86
,
0x6b
,
0x14
,
KEY_UNKNOWN
},
/* pip */
{
0x86
,
0x6b
,
0x15
,
KEY_ESC
},
{
0x86
,
0x6b
,
0x1a
,
KEY_UP
},
{
0x86
,
0x6b
,
0x1e
,
KEY_DOWN
},
{
0x86
,
0x6b
,
0x1f
,
KEY_LEFT
},
{
0x86
,
0x6b
,
0x1b
,
KEY_RIGHT
},
};
/*
* Read the remote control and feed the appropriate event.
* NEC protocol is used for remote controls
*/
static
int
dibusb_read_remote_control
(
struct
usb_dibusb
*
dib
)
{
u8
b
[
1
]
=
{
DIBUSB_REQ_POLL_REMOTE
},
rb
[
5
];
int
ret
;
int
i
;
if
((
ret
=
dibusb_readwrite_usb
(
dib
,
b
,
1
,
rb
,
5
)))
return
ret
;
switch
(
rb
[
0
])
{
case
DIBUSB_RC_NEC_KEY_PRESSED
:
/* rb[1-3] is the actual key, rb[4] is a checksum */
deb_rc
(
"raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x
\n
"
,
rb
[
1
],
rb
[
2
],
rb
[
3
],
rb
[
4
]);
if
((
0xff
-
rb
[
3
])
!=
rb
[
4
])
{
deb_rc
(
"remote control checksum failed.
\n
"
);
break
;
}
/* See if we can match the raw key code. */
for
(
i
=
0
;
i
<
sizeof
(
rc_keys
)
/
sizeof
(
rc_keys
[
0
]);
i
++
)
{
if
(
rc_keys
[
i
].
c0
==
rb
[
1
]
&&
rc_keys
[
i
].
c1
==
rb
[
2
]
&&
rc_keys
[
i
].
c2
==
rb
[
3
])
{
dib
->
rc_input_event
=
rc_keys
[
i
].
key
;
deb_rc
(
"Translated key 0x%04x
\n
"
,
dib
->
rc_input_event
);
/* Signal down and up events for this key. */
input_report_key
(
&
dib
->
rc_input_dev
,
dib
->
rc_input_event
,
1
);
input_report_key
(
&
dib
->
rc_input_dev
,
dib
->
rc_input_event
,
0
);
input_sync
(
&
dib
->
rc_input_dev
);
break
;
}
}
break
;
case
DIBUSB_RC_NEC_EMPTY
:
/* No (more) remote control keys. */
break
;
case
DIBUSB_RC_NEC_KEY_REPEATED
:
/* rb[1]..rb[4] are always zero.*/
/* Repeats often seem to occur so for the moment just ignore this. */
deb_rc
(
"Key repeat
\n
"
);
break
;
default:
break
;
}
return
0
;
}
/* Remote-control poll function - called every dib->rc_query_interval ms to see
whether the remote control has received anything. */
static
void
dibusb_remote_query
(
void
*
data
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
data
;
/* TODO: need a lock here. We can simply skip checking for the remote control
if we're busy. */
dibusb_read_remote_control
(
dib
);
schedule_delayed_work
(
&
dib
->
rc_query_work
,
msecs_to_jiffies
(
rc_query_interval
));
}
int
dibusb_remote_init
(
struct
usb_dibusb
*
dib
)
{
int
i
;
if
(
dib
->
dibdev
->
dev_cl
->
remote_type
==
DIBUSB_RC_NO
)
return
0
;
/* Initialise the remote-control structures.*/
init_input_dev
(
&
dib
->
rc_input_dev
);
dib
->
rc_input_dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
);
dib
->
rc_input_dev
.
keycodesize
=
sizeof
(
unsigned
char
);
dib
->
rc_input_dev
.
keycodemax
=
KEY_MAX
;
dib
->
rc_input_dev
.
name
=
DRIVER_DESC
" remote control"
;
for
(
i
=
0
;
i
<
sizeof
(
rc_keys
)
/
sizeof
(
rc_keys
[
0
]);
i
++
)
set_bit
(
rc_keys
[
i
].
key
,
dib
->
rc_input_dev
.
keybit
);
input_register_device
(
&
dib
->
rc_input_dev
);
dib
->
rc_input_event
=
KEY_MAX
;
INIT_WORK
(
&
dib
->
rc_query_work
,
dibusb_remote_query
,
dib
);
/* Start the remote-control polling. */
if
(
rc_query_interval
<
40
)
rc_query_interval
=
100
;
/* default */
info
(
"schedule remote query interval to %d msecs."
,
rc_query_interval
);
schedule_delayed_work
(
&
dib
->
rc_query_work
,
msecs_to_jiffies
(
rc_query_interval
));
dib
->
init_state
|=
DIBUSB_STATE_REMOTE
;
return
0
;
}
int
dibusb_remote_exit
(
struct
usb_dibusb
*
dib
)
{
if
(
dib
->
dibdev
->
dev_cl
->
remote_type
==
DIBUSB_RC_NO
)
return
0
;
if
(
dib
->
init_state
&
DIBUSB_STATE_REMOTE
)
{
cancel_delayed_work
(
&
dib
->
rc_query_work
);
flush_scheduled_work
();
input_unregister_device
(
&
dib
->
rc_input_dev
);
}
dib
->
init_state
&=
~
DIBUSB_STATE_REMOTE
;
return
0
;
}
drivers/media/dvb/dibusb/dvb-dibusb-usb.c
0 → 100644
View file @
ca583a3c
/*
* dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for initializing and handling the
* usb specific stuff.
*/
#include "dvb-dibusb.h"
#include <linux/version.h>
#include <linux/pci.h>
int
dibusb_readwrite_usb
(
struct
usb_dibusb
*
dib
,
u8
*
wbuf
,
u16
wlen
,
u8
*
rbuf
,
u16
rlen
)
{
int
actlen
,
ret
=
-
ENOMEM
;
if
(
wbuf
==
NULL
||
wlen
==
0
)
return
-
EINVAL
;
if
((
ret
=
down_interruptible
(
&
dib
->
usb_sem
)))
return
ret
;
if
(
dib
->
feedcount
&&
wbuf
[
0
]
==
DIBUSB_REQ_I2C_WRITE
&&
dib
->
dibdev
->
dev_cl
->
id
==
DIBUSB1_1
)
deb_err
(
"BUG: writing to i2c, while TS-streaming destroys the stream."
"(%x reg: %x %x)
\n
"
,
wbuf
[
0
],
wbuf
[
2
],
wbuf
[
3
]);
debug_dump
(
wbuf
,
wlen
);
ret
=
usb_bulk_msg
(
dib
->
udev
,
usb_sndbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
dev_cl
->
pipe_cmd
),
wbuf
,
wlen
,
&
actlen
,
DIBUSB_I2C_TIMEOUT
);
if
(
ret
)
err
(
"bulk message failed: %d (%d/%d)"
,
ret
,
wlen
,
actlen
);
else
ret
=
actlen
!=
wlen
?
-
1
:
0
;
/* an answer is expected, and no error before */
if
(
!
ret
&&
rbuf
&&
rlen
)
{
ret
=
usb_bulk_msg
(
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
dev_cl
->
pipe_cmd
),
rbuf
,
rlen
,
&
actlen
,
DIBUSB_I2C_TIMEOUT
);
if
(
ret
)
err
(
"recv bulk message failed: %d"
,
ret
);
else
{
deb_alot
(
"rlen: %d
\n
"
,
rlen
);
debug_dump
(
rbuf
,
actlen
);
}
}
up
(
&
dib
->
usb_sem
);
return
ret
;
}
/*
* Cypress controls
*/
#if 0
/*
* #if 0'ing the following functions as they are not in use _now_,
* but probably will be sometime.
*/
/*
* do not use this, just a workaround for a bug,
* which will hopefully never occur :).
*/
int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_REQ_INTR_READ };
return dibusb_write_usb(dib,b,1);
}
#endif
static
int
dibusb_write_usb
(
struct
usb_dibusb
*
dib
,
u8
*
buf
,
u16
len
)
{
return
dibusb_readwrite_usb
(
dib
,
buf
,
len
,
NULL
,
0
);
}
/*
* ioctl for the firmware
*/
static
int
dibusb_ioctl_cmd
(
struct
usb_dibusb
*
dib
,
u8
cmd
,
u8
*
param
,
int
plen
)
{
u8
b
[
34
];
int
size
=
plen
>
32
?
32
:
plen
;
memset
(
b
,
0
,
34
);
b
[
0
]
=
DIBUSB_REQ_SET_IOCTL
;
b
[
1
]
=
cmd
;
if
(
size
>
0
)
memcpy
(
&
b
[
2
],
param
,
size
);
return
dibusb_write_usb
(
dib
,
b
,
34
);
//2+size);
}
/*
* ioctl for power control
*/
int
dibusb_hw_wakeup
(
struct
dvb_frontend
*
fe
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
u8
b
[
1
]
=
{
DIBUSB_IOCTL_POWER_WAKEUP
};
deb_info
(
"dibusb-device is getting up.
\n
"
);
dibusb_ioctl_cmd
(
dib
,
DIBUSB_IOCTL_CMD_POWER_MODE
,
b
,
1
);
if
(
dib
->
fe_init
)
return
dib
->
fe_init
(
fe
);
return
0
;
}
int
dibusb_hw_sleep
(
struct
dvb_frontend
*
fe
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
u8
b
[
1
]
=
{
DIBUSB_IOCTL_POWER_SLEEP
};
deb_info
(
"dibusb-device is going to bed.
\n
"
);
dibusb_ioctl_cmd
(
dib
,
DIBUSB_IOCTL_CMD_POWER_MODE
,
b
,
1
);
if
(
dib
->
fe_sleep
)
return
dib
->
fe_sleep
(
fe
);
return
0
;
}
int
dibusb_set_streaming_mode
(
struct
usb_dibusb
*
dib
,
u8
mode
)
{
u8
b
[
2
]
=
{
DIBUSB_REQ_SET_STREAMING_MODE
,
mode
};
return
dibusb_readwrite_usb
(
dib
,
b
,
2
,
NULL
,
0
);
}
int
dibusb_streaming
(
struct
usb_dibusb
*
dib
,
int
onoff
)
{
switch
(
dib
->
dibdev
->
dev_cl
->
id
)
{
case
DIBUSB2_0
:
if
(
onoff
)
return
dibusb_ioctl_cmd
(
dib
,
DIBUSB_IOCTL_CMD_ENABLE_STREAM
,
NULL
,
0
);
else
return
dibusb_ioctl_cmd
(
dib
,
DIBUSB_IOCTL_CMD_DISABLE_STREAM
,
NULL
,
0
);
break
;
case
UMT2_0
:
return
dibusb_set_streaming_mode
(
dib
,
onoff
);
break
;
default:
break
;
}
return
0
;
}
int
dibusb_urb_init
(
struct
usb_dibusb
*
dib
)
{
int
ret
,
i
,
bufsize
;
/*
* when reloading the driver w/o replugging the device
* a timeout occures, this helps
*/
usb_clear_halt
(
dib
->
udev
,
usb_sndbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
dev_cl
->
pipe_cmd
));
usb_clear_halt
(
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
dev_cl
->
pipe_cmd
));
usb_clear_halt
(
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
dev_cl
->
pipe_data
));
/* allocate the array for the data transfer URBs */
dib
->
urb_list
=
kmalloc
(
dib
->
dibdev
->
dev_cl
->
urb_count
*
sizeof
(
struct
urb
*
),
GFP_KERNEL
);
if
(
dib
->
urb_list
==
NULL
)
return
-
ENOMEM
;
memset
(
dib
->
urb_list
,
0
,
dib
->
dibdev
->
dev_cl
->
urb_count
*
sizeof
(
struct
urb
*
));
dib
->
init_state
|=
DIBUSB_STATE_URB_LIST
;
bufsize
=
dib
->
dibdev
->
dev_cl
->
urb_count
*
dib
->
dibdev
->
dev_cl
->
urb_buffer_size
;
deb_info
(
"allocate %d bytes as buffersize for all URBs
\n
"
,
bufsize
);
/* allocate the actual buffer for the URBs */
if
((
dib
->
buffer
=
pci_alloc_consistent
(
NULL
,
bufsize
,
&
dib
->
dma_handle
))
==
NULL
)
{
deb_info
(
"not enough memory.
\n
"
);
return
-
ENOMEM
;
}
deb_info
(
"allocation complete
\n
"
);
memset
(
dib
->
buffer
,
0
,
bufsize
);
dib
->
init_state
|=
DIBUSB_STATE_URB_BUF
;
/* allocate and submit the URBs */
for
(
i
=
0
;
i
<
dib
->
dibdev
->
dev_cl
->
urb_count
;
i
++
)
{
if
(
!
(
dib
->
urb_list
[
i
]
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
{
return
-
ENOMEM
;
}
deb_info
(
"submitting URB no. %d
\n
"
,
i
);
usb_fill_bulk_urb
(
dib
->
urb_list
[
i
],
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
dev_cl
->
pipe_data
),
&
dib
->
buffer
[
i
*
dib
->
dibdev
->
dev_cl
->
urb_buffer_size
],
dib
->
dibdev
->
dev_cl
->
urb_buffer_size
,
dibusb_urb_complete
,
dib
);
dib
->
urb_list
[
i
]
->
transfer_flags
=
0
;
if
((
ret
=
usb_submit_urb
(
dib
->
urb_list
[
i
],
GFP_ATOMIC
)))
{
err
(
"could not submit buffer urb no. %d
\n
"
,
i
);
return
ret
;
}
dib
->
init_state
|=
DIBUSB_STATE_URB_SUBMIT
;
}
dib
->
pid_parse
=
1
;
switch
(
dib
->
dibdev
->
dev_cl
->
id
)
{
case
DIBUSB2_0
:
if
(
dib
->
udev
->
speed
==
USB_SPEED_HIGH
&&
!
pid_parse
)
{
dib
->
pid_parse
=
0
;
info
(
"running at HIGH speed, will deliver the complete TS."
);
}
else
info
(
"will use pid_parsing."
);
break
;
default:
break
;
}
return
0
;
}
int
dibusb_urb_exit
(
struct
usb_dibusb
*
dib
)
{
int
i
;
if
(
dib
->
init_state
&
DIBUSB_STATE_URB_LIST
)
{
for
(
i
=
0
;
i
<
dib
->
dibdev
->
dev_cl
->
urb_count
;
i
++
)
{
if
(
dib
->
urb_list
[
i
]
!=
NULL
)
{
deb_info
(
"killing URB no. %d.
\n
"
,
i
);
/* stop the URBs */
usb_kill_urb
(
dib
->
urb_list
[
i
]);
deb_info
(
"freeing URB no. %d.
\n
"
,
i
);
/* free the URBs */
usb_free_urb
(
dib
->
urb_list
[
i
]);
}
}
/* free the urb array */
kfree
(
dib
->
urb_list
);
dib
->
init_state
&=
~
DIBUSB_STATE_URB_SUBMIT
;
dib
->
init_state
&=
~
DIBUSB_STATE_URB_LIST
;
}
if
(
dib
->
init_state
&
DIBUSB_STATE_URB_BUF
)
pci_free_consistent
(
NULL
,
dib
->
dibdev
->
dev_cl
->
urb_buffer_size
*
dib
->
dibdev
->
dev_cl
->
urb_count
,
dib
->
buffer
,
dib
->
dma_handle
);
dib
->
init_state
&=
~
DIBUSB_STATE_URB_BUF
;
return
0
;
}
drivers/media/dvb/dibusb/dvb-dibusb.c
deleted
100644 → 0
View file @
97231034
/*
* Driver for mobile USB Budget DVB-T devices based on reference
* design made by DiBcom (http://www.dibcom.fr/)
*
* dvb-dibusb.c
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DiBcom, which has
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
*
* Remote control code added by David Matthews (dm@prolingua.co.uk)
*
* 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 the Free Software Foundation, version 2.
*
* Acknowledgements
*
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
*
* see Documentation/dvb/README.dibusb for more information
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/input.h>
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_filter.h"
#include "dvb_net.h"
#include "dvb_frontend.h"
#include "dib3000.h"
#include "dvb-dibusb.h"
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) { printk(args); } } while (0)
#define debug_dump(b,l) if (debug) {\
int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
deb_xfer("\n");\
}
static
int
debug
;
module_param
(
debug
,
int
,
0x644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))."
);
#else
#define dprintk(args...)
#define debug_dump(b,l)
#endif
#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_alot(args...) dprintk(0x04,args)
#define deb_ts(args...) dprintk(0x08,args)
#define deb_err(args...) dprintk(0x10,args)
#define deb_rc(args...) dprintk(0x20,args)
static
int
pid_parse
;
module_param
(
pid_parse
,
int
,
0x644
);
MODULE_PARM_DESC
(
pid_parse
,
"enable pid parsing (filtering) when running at USB2.0"
);
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
static
int
dibusb_readwrite_usb
(
struct
usb_dibusb
*
dib
,
u8
*
wbuf
,
u16
wlen
,
u8
*
rbuf
,
u16
rlen
)
{
int
actlen
,
ret
=
-
ENOMEM
;
if
(
wbuf
==
NULL
||
wlen
==
0
)
return
-
EINVAL
;
if
((
ret
=
down_interruptible
(
&
dib
->
usb_sem
)))
return
ret
;
if
(
dib
->
feedcount
&&
wbuf
[
0
]
==
DIBUSB_REQ_I2C_WRITE
&&
dib
->
dibdev
->
parm
->
type
==
DIBUSB1_1
)
deb_err
(
"BUG: writing to i2c, while TS-streaming destroys the stream."
"(%x reg: %x %x)
\n
"
,
wbuf
[
0
],
wbuf
[
2
],
wbuf
[
3
]);
debug_dump
(
wbuf
,
wlen
);
ret
=
usb_bulk_msg
(
dib
->
udev
,
usb_sndbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
parm
->
cmd_pipe
),
wbuf
,
wlen
,
&
actlen
,
DIBUSB_I2C_TIMEOUT
);
if
(
ret
)
err
(
"bulk message failed: %d (%d/%d)"
,
ret
,
wlen
,
actlen
);
else
ret
=
actlen
!=
wlen
?
-
1
:
0
;
/* an answer is expected, and no error before */
if
(
!
ret
&&
rbuf
&&
rlen
)
{
ret
=
usb_bulk_msg
(
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
parm
->
result_pipe
),
rbuf
,
rlen
,
&
actlen
,
DIBUSB_I2C_TIMEOUT
);
if
(
ret
)
err
(
"recv bulk message failed: %d"
,
ret
);
else
{
deb_alot
(
"rlen: %d
\n
"
,
rlen
);
debug_dump
(
rbuf
,
actlen
);
}
}
up
(
&
dib
->
usb_sem
);
return
ret
;
}
static
int
dibusb_i2c_msg
(
struct
usb_dibusb
*
dib
,
u8
addr
,
u8
*
wbuf
,
u16
wlen
,
u8
*
rbuf
,
u16
rlen
)
{
u8
sndbuf
[
wlen
+
4
];
/* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
/* write only ? */
int
wo
=
(
rbuf
==
NULL
||
rlen
==
0
),
len
=
2
+
wlen
+
(
wo
?
0
:
2
);
deb_alot
(
"wo: %d, wlen: %d, len: %d
\n
"
,
wo
,
wlen
,
len
);
sndbuf
[
0
]
=
wo
?
DIBUSB_REQ_I2C_WRITE
:
DIBUSB_REQ_I2C_READ
;
sndbuf
[
1
]
=
(
addr
&
0xfe
)
|
(
wo
?
0
:
1
);
memcpy
(
&
sndbuf
[
2
],
wbuf
,
wlen
);
if
(
!
wo
)
{
sndbuf
[
wlen
+
2
]
=
(
rlen
>>
8
)
&
0xff
;
sndbuf
[
wlen
+
3
]
=
rlen
&
0xff
;
}
return
dibusb_readwrite_usb
(
dib
,
sndbuf
,
len
,
rbuf
,
rlen
);
}
/*
* DVB stuff
*/
static
void
dibusb_urb_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
ptregs
)
{
struct
usb_dibusb
*
dib
=
urb
->
context
;
deb_ts
(
"urb complete feedcount: %d, status: %d
\n
"
,
dib
->
feedcount
,
urb
->
status
);
if
(
dib
->
feedcount
>
0
&&
urb
->
status
==
0
)
{
deb_ts
(
"URB return len: %d
\n
"
,
urb
->
actual_length
);
if
(
urb
->
actual_length
%
188
)
deb_ts
(
"TS Packets: %d, %d
\n
"
,
urb
->
actual_length
/
188
,
urb
->
actual_length
%
188
);
/* Francois recommends to drop not full-filled packets, even if they may
* contain valid TS packets
*/
if
(
urb
->
actual_length
==
dib
->
dibdev
->
parm
->
default_size
&&
dib
->
dvb_is_ready
)
dvb_dmx_swfilter_packets
(
&
dib
->
demux
,
(
u8
*
)
urb
->
transfer_buffer
,
urb
->
actual_length
/
188
);
else
deb_ts
(
"URB dropped because of the "
"actual_length or !dvb_is_ready (%d).
\n
"
,
dib
->
dvb_is_ready
);
}
else
deb_ts
(
"URB dropped because of feedcount or status.
\n
"
);
usb_submit_urb
(
urb
,
GFP_KERNEL
);
}
static
int
dibusb_ctrl_feed
(
struct
usb_dibusb
*
dib
,
int
pid
,
int
onoff
)
{
if
(
dib
->
dibdev
->
parm
->
firmware_bug
&&
dib
->
feedcount
)
{
deb_ts
(
"stop feeding
\n
"
);
if
(
dib
->
xfer_ops
.
fifo_ctrl
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
fifo_ctrl
(
dib
->
fe
,
0
))
{
err
(
"error while inhibiting fifo."
);
return
-
ENODEV
;
}
}
else
{
err
(
"fifo_ctrl is not set."
);
return
-
ENODEV
;
}
}
dib
->
feedcount
+=
onoff
?
1
:
-
1
;
if
(
dib
->
pid_parse
)
{
if
(
dib
->
xfer_ops
.
pid_ctrl
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
pid_ctrl
(
dib
->
fe
,
pid
,
onoff
)
<
0
)
{
err
(
"no free pid in list."
);
return
-
ENODEV
;
}
}
else
{
err
(
"no pid ctrl callback."
);
return
-
ENODEV
;
}
}
/*
* start the feed, either if there is the firmware bug or
* if this was the first pid to set.
*/
if
(
dib
->
dibdev
->
parm
->
firmware_bug
||
dib
->
feedcount
==
onoff
)
{
deb_ts
(
"controlling pid parser
\n
"
);
if
(
dib
->
xfer_ops
.
pid_parse
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
pid_parse
(
dib
->
fe
,
dib
->
pid_parse
)
<
0
)
{
err
(
"could not handle pid_parser"
);
}
}
deb_ts
(
"start feeding
\n
"
);
if
(
dib
->
xfer_ops
.
fifo_ctrl
!=
NULL
)
{
if
(
dib
->
xfer_ops
.
fifo_ctrl
(
dib
->
fe
,
1
))
{
err
(
"error while enabling fifo."
);
return
-
ENODEV
;
}
}
else
{
err
(
"fifo_ctrl is not set."
);
return
-
ENODEV
;
}
}
return
0
;
}
static
int
dibusb_start_feed
(
struct
dvb_demux_feed
*
dvbdmxfeed
)
{
struct
usb_dibusb
*
dib
=
dvbdmxfeed
->
demux
->
priv
;
deb_ts
(
"pid: 0x%04x, feedtype: %d
\n
"
,
dvbdmxfeed
->
pid
,
dvbdmxfeed
->
type
);
dvbdmxfeed
->
priv
=
dib
;
return
dibusb_ctrl_feed
(
dib
,
dvbdmxfeed
->
pid
,
1
);
}
static
int
dibusb_stop_feed
(
struct
dvb_demux_feed
*
dvbdmxfeed
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
dvbdmxfeed
->
priv
;
if
(
dib
==
NULL
)
{
err
(
"dib in dmxfeed->priv was NULL"
);
return
-
EINVAL
;
}
deb_ts
(
"dvbdmxfeed pid: 0x%04x, feedtype: %d
\n
"
,
dvbdmxfeed
->
pid
,
dvbdmxfeed
->
type
);
return
dibusb_ctrl_feed
(
dib
,
dvbdmxfeed
->
pid
,
0
);
}
/* Table to map raw key codes to key events. This should not be hard-wired
into the kernel. */
static
const
struct
{
u8
c0
,
c1
,
c2
;
uint32_t
key
;
}
rc_keys
[]
=
{
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{
0x00
,
0xff
,
0x16
,
KEY_POWER
},
{
0x00
,
0xff
,
0x10
,
KEY_MUTE
},
{
0x00
,
0xff
,
0x03
,
KEY_1
},
{
0x00
,
0xff
,
0x01
,
KEY_2
},
{
0x00
,
0xff
,
0x06
,
KEY_3
},
{
0x00
,
0xff
,
0x09
,
KEY_4
},
{
0x00
,
0xff
,
0x1d
,
KEY_5
},
{
0x00
,
0xff
,
0x1f
,
KEY_6
},
{
0x00
,
0xff
,
0x0d
,
KEY_7
},
{
0x00
,
0xff
,
0x19
,
KEY_8
},
{
0x00
,
0xff
,
0x1b
,
KEY_9
},
{
0x00
,
0xff
,
0x15
,
KEY_0
},
{
0x00
,
0xff
,
0x05
,
KEY_CHANNELUP
},
{
0x00
,
0xff
,
0x02
,
KEY_CHANNELDOWN
},
{
0x00
,
0xff
,
0x1e
,
KEY_VOLUMEUP
},
{
0x00
,
0xff
,
0x0a
,
KEY_VOLUMEDOWN
},
{
0x00
,
0xff
,
0x11
,
KEY_RECORD
},
{
0x00
,
0xff
,
0x17
,
KEY_FAVORITES
},
/* Heart symbol - Channel list. */
{
0x00
,
0xff
,
0x14
,
KEY_PLAY
},
{
0x00
,
0xff
,
0x1a
,
KEY_STOP
},
{
0x00
,
0xff
,
0x40
,
KEY_REWIND
},
{
0x00
,
0xff
,
0x12
,
KEY_FASTFORWARD
},
{
0x00
,
0xff
,
0x0e
,
KEY_PREVIOUS
},
/* Recall - Previous channel. */
{
0x00
,
0xff
,
0x4c
,
KEY_PAUSE
},
{
0x00
,
0xff
,
0x4d
,
KEY_SCREEN
},
/* Full screen mode. */
{
0x00
,
0xff
,
0x54
,
KEY_AUDIO
},
/* MTS - Switch to secondary audio. */
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
{
0x00
,
0xff
,
0x0c
,
KEY_CANCEL
},
/* Cancel */
{
0x00
,
0xff
,
0x1c
,
KEY_EPG
},
/* EPG */
{
0x00
,
0xff
,
0x00
,
KEY_TAB
},
/* Tab */
{
0x00
,
0xff
,
0x48
,
KEY_INFO
},
/* Preview */
{
0x00
,
0xff
,
0x04
,
KEY_LIST
},
/* RecordList */
{
0x00
,
0xff
,
0x0f
,
KEY_TEXT
},
/* Teletext */
/* Key codes for the KWorld/ADSTech/JetWay remote. */
{
0x86
,
0x6b
,
0x12
,
KEY_POWER
},
{
0x86
,
0x6b
,
0x0f
,
KEY_SELECT
},
/* source */
{
0x86
,
0x6b
,
0x0c
,
KEY_UNKNOWN
},
/* scan */
{
0x86
,
0x6b
,
0x0b
,
KEY_EPG
},
{
0x86
,
0x6b
,
0x10
,
KEY_MUTE
},
{
0x86
,
0x6b
,
0x01
,
KEY_1
},
{
0x86
,
0x6b
,
0x02
,
KEY_2
},
{
0x86
,
0x6b
,
0x03
,
KEY_3
},
{
0x86
,
0x6b
,
0x04
,
KEY_4
},
{
0x86
,
0x6b
,
0x05
,
KEY_5
},
{
0x86
,
0x6b
,
0x06
,
KEY_6
},
{
0x86
,
0x6b
,
0x07
,
KEY_7
},
{
0x86
,
0x6b
,
0x08
,
KEY_8
},
{
0x86
,
0x6b
,
0x09
,
KEY_9
},
{
0x86
,
0x6b
,
0x0a
,
KEY_0
},
{
0x86
,
0x6b
,
0x18
,
KEY_ZOOM
},
{
0x86
,
0x6b
,
0x1c
,
KEY_UNKNOWN
},
/* preview */
{
0x86
,
0x6b
,
0x13
,
KEY_UNKNOWN
},
/* snap */
{
0x86
,
0x6b
,
0x00
,
KEY_UNDO
},
{
0x86
,
0x6b
,
0x1d
,
KEY_RECORD
},
{
0x86
,
0x6b
,
0x0d
,
KEY_STOP
},
{
0x86
,
0x6b
,
0x0e
,
KEY_PAUSE
},
{
0x86
,
0x6b
,
0x16
,
KEY_PLAY
},
{
0x86
,
0x6b
,
0x11
,
KEY_BACK
},
{
0x86
,
0x6b
,
0x19
,
KEY_FORWARD
},
{
0x86
,
0x6b
,
0x14
,
KEY_UNKNOWN
},
/* pip */
{
0x86
,
0x6b
,
0x15
,
KEY_ESC
},
{
0x86
,
0x6b
,
0x1a
,
KEY_UP
},
{
0x86
,
0x6b
,
0x1e
,
KEY_DOWN
},
{
0x86
,
0x6b
,
0x1f
,
KEY_LEFT
},
{
0x86
,
0x6b
,
0x1b
,
KEY_RIGHT
},
};
/*
* Read the remote control and feed the appropriate event.
* NEC protocol is used for remote controls
*/
static
int
dibusb_read_remote_control
(
struct
usb_dibusb
*
dib
)
{
u8
b
[
1
]
=
{
DIBUSB_REQ_POLL_REMOTE
},
rb
[
5
];
int
ret
;
int
i
;
if
((
ret
=
dibusb_readwrite_usb
(
dib
,
b
,
1
,
rb
,
5
)))
return
ret
;
switch
(
rb
[
0
])
{
case
DIBUSB_RC_NEC_KEY_PRESSED
:
/* rb[1-3] is the actual key, rb[4] is a checksum */
deb_rc
(
"raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x
\n
"
,
rb
[
1
],
rb
[
2
],
rb
[
3
],
rb
[
4
]);
if
((
0xff
-
rb
[
3
])
!=
rb
[
4
])
{
deb_rc
(
"remote control checksum failed.
\n
"
);
break
;
}
/* See if we can match the raw key code. */
for
(
i
=
0
;
i
<
sizeof
(
rc_keys
)
/
sizeof
(
rc_keys
[
0
]);
i
++
)
{
if
(
rc_keys
[
i
].
c0
==
rb
[
1
]
&&
rc_keys
[
i
].
c1
==
rb
[
2
]
&&
rc_keys
[
i
].
c2
==
rb
[
3
])
{
dib
->
rc_input_event
=
rc_keys
[
i
].
key
;
deb_rc
(
"Translated key 0x%04x
\n
"
,
dib
->
rc_input_event
);
/* Signal down and up events for this key. */
input_report_key
(
&
dib
->
rc_input_dev
,
dib
->
rc_input_event
,
1
);
input_report_key
(
&
dib
->
rc_input_dev
,
dib
->
rc_input_event
,
0
);
input_sync
(
&
dib
->
rc_input_dev
);
break
;
}
}
break
;
case
DIBUSB_RC_NEC_EMPTY
:
/* No (more) remote control keys. */
break
;
case
DIBUSB_RC_NEC_KEY_REPEATED
:
/* rb[1]..rb[4] are always zero.*/
/* Repeats often seem to occur so for the moment just ignore this. */
deb_rc
(
"Key repeat
\n
"
);
break
;
default:
break
;
}
return
0
;
}
#define RC_QUERY_INTERVAL (100)
/* milliseconds */
/* Remote-control poll function - called every RC_QUERY_INTERVAL ms to see
whether the remote control has received anything. */
static
void
dibusb_query_rc
(
void
*
data
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
data
;
/* TODO: need a lock here. We can simply skip checking for the remote control
if we're busy. */
dibusb_read_remote_control
(
dib
);
schedule_delayed_work
(
&
dib
->
rc_query_work
,
msecs_to_jiffies
(
RC_QUERY_INTERVAL
));
}
/*
* Cypress controls
*/
#if 0
/*
* #if 0'ing the following functions as they are not in use _now_,
* but probably will be sometime.
*/
/*
* do not use this, just a workaround for a bug,
* which will hopefully never occur :).
*/
static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_REQ_INTR_READ };
return dibusb_write_usb(dib,b,1);
}
/*
* ioctl for power control
*/
static int dibusb_hw_sleep(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
}
#endif
static
int
dibusb_write_usb
(
struct
usb_dibusb
*
dib
,
u8
*
buf
,
u16
len
)
{
return
dibusb_readwrite_usb
(
dib
,
buf
,
len
,
NULL
,
0
);
}
/*
* ioctl for the firmware
*/
static
int
dibusb_ioctl_cmd
(
struct
usb_dibusb
*
dib
,
u8
cmd
,
u8
*
param
,
int
plen
)
{
u8
b
[
34
];
int
size
=
plen
>
32
?
32
:
plen
;
b
[
0
]
=
DIBUSB_REQ_SET_IOCTL
;
b
[
1
]
=
cmd
;
memcpy
(
&
b
[
2
],
param
,
size
);
return
dibusb_write_usb
(
dib
,
b
,
2
+
size
);
}
static
int
dibusb_hw_wakeup
(
struct
usb_dibusb
*
dib
)
{
u8
b
[
1
]
=
{
DIBUSB_IOCTL_POWER_WAKEUP
};
return
dibusb_ioctl_cmd
(
dib
,
DIBUSB_IOCTL_CMD_POWER_MODE
,
b
,
1
);
}
/*
* I2C
*/
static
int
dibusb_i2c_xfer
(
struct
i2c_adapter
*
adap
,
struct
i2c_msg
msg
[],
int
num
)
{
struct
usb_dibusb
*
dib
=
i2c_get_adapdata
(
adap
);
int
i
;
if
(
down_interruptible
(
&
dib
->
i2c_sem
)
<
0
)
return
-
EAGAIN
;
for
(
i
=
0
;
i
<
num
;
i
++
)
{
/* write/read request */
if
(
i
+
1
<
num
&&
(
msg
[
i
+
1
].
flags
&
I2C_M_RD
))
{
if
(
dibusb_i2c_msg
(
dib
,
msg
[
i
].
addr
,
msg
[
i
].
buf
,
msg
[
i
].
len
,
msg
[
i
+
1
].
buf
,
msg
[
i
+
1
].
len
)
<
0
)
break
;
i
++
;
}
else
if
(
dibusb_i2c_msg
(
dib
,
msg
[
i
].
addr
,
msg
[
i
].
buf
,
msg
[
i
].
len
,
NULL
,
0
)
<
0
)
break
;
}
up
(
&
dib
->
i2c_sem
);
return
i
;
}
static
u32
dibusb_i2c_func
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_I2C
;
}
static
int
thomson_cable_eu_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
);
static
struct
dib3000_config
thomson_cable_eu_config
=
{
.
demod_address
=
0x10
,
.
pll_addr
=
194
,
.
pll_set
=
thomson_cable_eu_pll_set
,
};
static
int
thomson_cable_eu_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
u8
buf
[
4
];
struct
i2c_msg
msg
=
{
.
addr
=
thomson_cable_eu_config
.
pll_addr
,
.
flags
=
0
,
.
buf
=
buf
,
.
len
=
sizeof
(
buf
)
};
u32
tfreq
=
(
params
->
frequency
+
36125000
)
/
62500
;
int
vu
,
p0
,
p1
,
p2
;
if
(
params
->
frequency
>
403250000
)
vu
=
1
,
p2
=
1
,
p1
=
0
,
p0
=
1
;
else
if
(
params
->
frequency
>
115750000
)
vu
=
0
,
p2
=
1
,
p1
=
1
,
p0
=
0
;
else
if
(
params
->
frequency
>
44250000
)
vu
=
0
,
p2
=
0
,
p1
=
1
,
p0
=
1
;
else
return
-
EINVAL
;
buf
[
0
]
=
(
tfreq
>>
8
)
&
0x7f
;
buf
[
1
]
=
tfreq
&
0xff
;
buf
[
2
]
=
0x8e
;
buf
[
3
]
=
(
vu
<<
7
)
|
(
p2
<<
2
)
|
(
p1
<<
1
)
|
p0
;
if
(
i2c_transfer
(
&
dib
->
i2c_adap
,
&
msg
,
1
)
!=
1
)
return
-
EIO
;
msleep
(
1
);
return
0
;
}
static
int
panasonic_cofdm_env57h1xd5_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
);
static
struct
dib3000_config
panasonic_cofdm_env57h1xd5
=
{
.
demod_address
=
0x18
,
.
pll_addr
=
192
,
.
pll_set
=
panasonic_cofdm_env57h1xd5_pll_set
,
};
static
int
panasonic_cofdm_env57h1xd5_pll_set
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
)
{
struct
usb_dibusb
*
dib
=
(
struct
usb_dibusb
*
)
fe
->
dvb
->
priv
;
u8
buf
[
4
];
u32
freq
=
params
->
frequency
;
u32
tfreq
=
(
freq
+
36125000
)
/
1000000
*
6
+
1
;
u8
TA
,
T210
,
R210
,
ctrl1
,
cp210
,
p4321
;
struct
i2c_msg
msg
=
{
.
addr
=
panasonic_cofdm_env57h1xd5
.
pll_addr
,
.
flags
=
0
,
.
buf
=
buf
,
.
len
=
sizeof
(
buf
)
};
if
(
freq
>
858000000
)
{
err
(
"frequency cannot be larger than 858 MHz."
);
return
-
EINVAL
;
}
// contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
TA
=
1
;
T210
=
0
;
R210
=
0x2
;
ctrl1
=
(
1
<<
7
)
|
(
TA
<<
6
)
|
(
T210
<<
3
)
|
R210
;
// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES *****************
if
(
freq
<
470000000
)
cp210
=
2
;
// VHF Low and High band ch E12 to E4 to E12
else
if
(
freq
<
526000000
)
cp210
=
4
;
// UHF band Ch E21 to E27
else
// if (freq < 862000000)
cp210
=
5
;
// UHF band ch E28 to E69
//********************* BW select *******************************
if
(
freq
<
153000000
)
p4321
=
1
;
// BW selected for VHF low
else
if
(
freq
<
470000000
)
p4321
=
2
;
// BW selected for VHF high E5 to E12
else
// if (freq < 862000000)
p4321
=
4
;
// BW selection for UHF E21 to E69
buf
[
0
]
=
(
tfreq
>>
8
)
&
0xff
;
buf
[
1
]
=
(
tfreq
>>
0
)
&
0xff
;
buf
[
2
]
=
0xff
&
ctrl1
;
buf
[
3
]
=
(
cp210
<<
5
)
|
(
p4321
);
if
(
i2c_transfer
(
&
dib
->
i2c_adap
,
&
msg
,
1
)
!=
1
)
return
-
EIO
;
msleep
(
1
);
return
0
;
}
static
struct
i2c_algorithm
dibusb_algo
=
{
.
name
=
"DiBcom USB i2c algorithm"
,
.
id
=
I2C_ALGO_BIT
,
.
master_xfer
=
dibusb_i2c_xfer
,
.
functionality
=
dibusb_i2c_func
,
};
static
void
frontend_init
(
struct
usb_dibusb
*
dib
)
{
switch
(
dib
->
dibdev
->
parm
->
type
)
{
case
DIBUSB1_1
:
case
DIBUSB1_1_AN2235
:
dib
->
fe
=
dib3000mb_attach
(
&
thomson_cable_eu_config
,
&
dib
->
i2c_adap
,
&
dib
->
xfer_ops
);
break
;
case
DIBUSB2_0
:
dib
->
fe
=
dib3000mc_attach
(
&
panasonic_cofdm_env57h1xd5
,
&
dib
->
i2c_adap
,
&
dib
->
xfer_ops
);
break
;
}
if
(
dib
->
fe
==
NULL
)
{
printk
(
"dvb-dibusb: A frontend driver was not found for device %04x/%04x
\n
"
,
le16_to_cpu
(
dib
->
udev
->
descriptor
.
idVendor
),
le16_to_cpu
(
dib
->
udev
->
descriptor
.
idProduct
));
}
else
{
if
(
dvb_register_frontend
(
dib
->
adapter
,
dib
->
fe
))
{
printk
(
"dvb-dibusb: Frontend registration failed!
\n
"
);
if
(
dib
->
fe
->
ops
->
release
)
dib
->
fe
->
ops
->
release
(
dib
->
fe
);
dib
->
fe
=
NULL
;
}
}
}
static
int
dibusb_dvb_init
(
struct
usb_dibusb
*
dib
)
{
int
ret
;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4)
if
((
ret
=
dvb_register_adapter
(
&
dib
->
adapter
,
DRIVER_DESC
))
<
0
)
{
#else
if
((
ret
=
dvb_register_adapter
(
&
dib
->
adapter
,
DRIVER_DESC
,
THIS_MODULE
))
<
0
)
{
#endif
deb_info
(
"dvb_register_adapter failed: error %d"
,
ret
);
goto
err
;
}
dib
->
adapter
->
priv
=
dib
;
strncpy
(
dib
->
i2c_adap
.
name
,
dib
->
dibdev
->
name
,
I2C_NAME_SIZE
);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
dib
->
i2c_adap
.
class
=
I2C_ADAP_CLASS_TV_DIGITAL
,
#else
dib
->
i2c_adap
.
class
=
I2C_CLASS_TV_DIGITAL
,
#endif
dib
->
i2c_adap
.
algo
=
&
dibusb_algo
;
dib
->
i2c_adap
.
algo_data
=
NULL
;
dib
->
i2c_adap
.
id
=
I2C_ALGO_BIT
;
i2c_set_adapdata
(
&
dib
->
i2c_adap
,
dib
);
if
((
i2c_add_adapter
(
&
dib
->
i2c_adap
)
<
0
))
{
err
(
"could not add i2c adapter"
);
goto
err_i2c
;
}
dib
->
demux
.
dmx
.
capabilities
=
DMX_TS_FILTERING
|
DMX_SECTION_FILTERING
;
dib
->
demux
.
priv
=
(
void
*
)
dib
;
/* get pidcount from demod */
dib
->
demux
.
feednum
=
dib
->
demux
.
filternum
=
16
;
dib
->
demux
.
start_feed
=
dibusb_start_feed
;
dib
->
demux
.
stop_feed
=
dibusb_stop_feed
;
dib
->
demux
.
write_to_decoder
=
NULL
;
if
((
ret
=
dvb_dmx_init
(
&
dib
->
demux
))
<
0
)
{
err
(
"dvb_dmx_init failed: error %d"
,
ret
);
goto
err_dmx
;
}
dib
->
dmxdev
.
filternum
=
dib
->
demux
.
filternum
;
dib
->
dmxdev
.
demux
=
&
dib
->
demux
.
dmx
;
dib
->
dmxdev
.
capabilities
=
0
;
if
((
ret
=
dvb_dmxdev_init
(
&
dib
->
dmxdev
,
dib
->
adapter
))
<
0
)
{
err
(
"dvb_dmxdev_init failed: error %d"
,
ret
);
goto
err_dmx_dev
;
}
dvb_net_init
(
dib
->
adapter
,
&
dib
->
dvb_net
,
&
dib
->
demux
.
dmx
);
frontend_init
(
dib
);
/* Start the remote-control polling. */
schedule_delayed_work
(
&
dib
->
rc_query_work
,
msecs_to_jiffies
(
RC_QUERY_INTERVAL
));
goto
success
;
err_dmx_dev:
dvb_dmx_release
(
&
dib
->
demux
);
err_dmx:
i2c_del_adapter
(
&
dib
->
i2c_adap
);
err_i2c:
dvb_unregister_adapter
(
dib
->
adapter
);
err:
return
ret
;
success:
dib
->
dvb_is_ready
=
1
;
return
0
;
}
static
int
dibusb_dvb_exit
(
struct
usb_dibusb
*
dib
)
{
cancel_delayed_work
(
&
dib
->
rc_query_work
);
flush_scheduled_work
();
input_unregister_device
(
&
dib
->
rc_input_dev
);
dib
->
dvb_is_ready
=
0
;
deb_info
(
"unregistering DVB part
\n
"
);
dvb_net_release
(
&
dib
->
dvb_net
);
dib
->
demux
.
dmx
.
close
(
&
dib
->
demux
.
dmx
);
dvb_dmxdev_release
(
&
dib
->
dmxdev
);
dvb_dmx_release
(
&
dib
->
demux
);
if
(
dib
->
fe
!=
NULL
)
dvb_unregister_frontend
(
dib
->
fe
);
i2c_del_adapter
(
&
dib
->
i2c_adap
);
dvb_unregister_adapter
(
dib
->
adapter
);
return
0
;
}
static
int
dibusb_exit
(
struct
usb_dibusb
*
dib
)
{
int
i
;
if
(
dib
->
urb_list
!=
NULL
)
{
for
(
i
=
0
;
i
<
dib
->
dibdev
->
parm
->
num_urbs
;
i
++
)
{
if
(
dib
->
urb_list
[
i
]
!=
NULL
)
{
deb_info
(
"killing URB no. %d.
\n
"
,
i
);
/* stop the URBs */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
usb_unlink_urb
(
dib
->
urb_list
[
i
]);
#else
usb_kill_urb
(
dib
->
urb_list
[
i
]);
#endif
deb_info
(
"freeing URB no. %d.
\n
"
,
i
);
/* free the URBs */
usb_free_urb
(
dib
->
urb_list
[
i
]);
}
}
/* free the urb array */
kfree
(
dib
->
urb_list
);
}
pci_free_consistent
(
NULL
,
dib
->
dibdev
->
parm
->
urb_buf_size
*
dib
->
dibdev
->
parm
->
num_urbs
,
dib
->
buffer
,
dib
->
dma_handle
);
return
0
;
}
static
int
dibusb_init
(
struct
usb_dibusb
*
dib
)
{
int
ret
,
i
,
bufsize
;
sema_init
(
&
dib
->
usb_sem
,
1
);
sema_init
(
&
dib
->
i2c_sem
,
1
);
/*
* when reloading the driver w/o replugging the device
* a timeout occures, this helps
*/
usb_clear_halt
(
dib
->
udev
,
usb_sndbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
parm
->
cmd_pipe
));
usb_clear_halt
(
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
parm
->
result_pipe
));
usb_clear_halt
(
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
parm
->
data_pipe
));
/* allocate the array for the data transfer URBs */
dib
->
urb_list
=
kmalloc
(
dib
->
dibdev
->
parm
->
num_urbs
*
sizeof
(
struct
urb
*
),
GFP_KERNEL
);
if
(
dib
->
urb_list
==
NULL
)
return
-
ENOMEM
;
memset
(
dib
->
urb_list
,
0
,
dib
->
dibdev
->
parm
->
num_urbs
*
sizeof
(
struct
urb
*
));
bufsize
=
dib
->
dibdev
->
parm
->
num_urbs
*
dib
->
dibdev
->
parm
->
urb_buf_size
;
deb_info
(
"allocate %d bytes as buffersize for all URBs
\n
"
,
bufsize
);
/* allocate the actual buffer for the URBs */
if
((
dib
->
buffer
=
pci_alloc_consistent
(
NULL
,
bufsize
,
&
dib
->
dma_handle
))
==
NULL
)
{
deb_info
(
"not enough memory.
\n
"
);
dibusb_exit
(
dib
);
return
-
ENOMEM
;
}
deb_info
(
"allocation complete
\n
"
);
memset
(
dib
->
buffer
,
0
,
bufsize
);
/* allocate and submit the URBs */
for
(
i
=
0
;
i
<
dib
->
dibdev
->
parm
->
num_urbs
;
i
++
)
{
if
(
!
(
dib
->
urb_list
[
i
]
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
dibusb_exit
(
dib
);
return
-
ENOMEM
;
}
deb_info
(
"submitting URB no. %d
\n
"
,
i
);
usb_fill_bulk_urb
(
dib
->
urb_list
[
i
],
dib
->
udev
,
usb_rcvbulkpipe
(
dib
->
udev
,
dib
->
dibdev
->
parm
->
data_pipe
),
&
dib
->
buffer
[
i
*
dib
->
dibdev
->
parm
->
urb_buf_size
],
dib
->
dibdev
->
parm
->
urb_buf_size
,
dibusb_urb_complete
,
dib
);
dib
->
urb_list
[
i
]
->
transfer_flags
=
0
;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
dib
->
urb_list
[
i
]
->
timeout
=
0
;
#endif
if
((
ret
=
usb_submit_urb
(
dib
->
urb_list
[
i
],
GFP_KERNEL
)))
{
err
(
"could not submit buffer urb no. %d
\n
"
,
i
);
dibusb_exit
(
dib
);
return
ret
;
}
}
dib
->
dvb_is_ready
=
0
;
/* Initialise the remote-control structures.*/
init_input_dev
(
&
dib
->
rc_input_dev
);
dib
->
rc_input_dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
);
dib
->
rc_input_dev
.
keycodesize
=
sizeof
(
unsigned
char
);
dib
->
rc_input_dev
.
keycodemax
=
KEY_MAX
;
dib
->
rc_input_dev
.
name
=
DRIVER_DESC
" remote control"
;
for
(
i
=
0
;
i
<
sizeof
(
rc_keys
)
/
sizeof
(
rc_keys
[
0
]);
i
++
)
set_bit
(
rc_keys
[
i
].
key
,
dib
->
rc_input_dev
.
keybit
);
input_register_device
(
&
dib
->
rc_input_dev
);
dib
->
rc_input_event
=
KEY_MAX
;
INIT_WORK
(
&
dib
->
rc_query_work
,
dibusb_query_rc
,
dib
);
dibusb_hw_wakeup
(
dib
);
if
((
ret
=
dibusb_dvb_init
(
dib
)))
{
dibusb_exit
(
dib
);
return
ret
;
}
return
0
;
}
/*
* load a firmware packet to the device
*/
static
int
dibusb_writemem
(
struct
usb_device
*
udev
,
u16
addr
,
u8
*
data
,
u8
len
)
{
return
usb_control_msg
(
udev
,
usb_sndctrlpipe
(
udev
,
0
),
0xa0
,
USB_TYPE_VENDOR
,
addr
,
0x00
,
data
,
len
,
5
*
HZ
);
}
static
int
dibusb_loadfirmware
(
struct
usb_device
*
udev
,
struct
dibusb_device
*
dibdev
)
{
const
struct
firmware
*
fw
=
NULL
;
const
char
**
fws
;
u16
addr
;
u8
*
b
,
*
p
;
int
ret
=
0
,
i
;
fws
=
dibdev
->
parm
->
fw_filenames
;
for
(
i
=
0
;
i
<
sizeof
(
fws
)
/
sizeof
(
const
char
*
);
i
++
)
{
if
((
ret
=
request_firmware
(
&
fw
,
fws
[
i
],
&
udev
->
dev
))
==
0
)
{
info
(
"using firmware file (%s)."
,
fws
[
i
]);
break
;
}
deb_info
(
"tried to find '%s' firmware - unsuccessful. (%d)
\n
"
,
fws
[
i
],
ret
);
}
if
(
fw
==
NULL
)
{
err
(
"did not find a valid firmware file. "
"Please see linux/Documentation/dvb/ for more details on firmware-problems."
);
return
-
EINVAL
;
}
p
=
kmalloc
(
fw
->
size
,
GFP_KERNEL
);
if
(
p
!=
NULL
)
{
u8
reset
;
/*
* you cannot use the fw->data as buffer for
* usb_control_msg, a new buffer has to be
* created
*/
memcpy
(
p
,
fw
->
data
,
fw
->
size
);
/* stop the CPU */
reset
=
1
;
if
((
ret
=
dibusb_writemem
(
udev
,
dibdev
->
parm
->
usb_cpu_csreg
,
&
reset
,
1
))
!=
1
)
err
(
"could not stop the USB controller CPU."
);
for
(
i
=
0
;
p
[
i
+
3
]
==
0
&&
i
<
fw
->
size
;
)
{
b
=
(
u8
*
)
&
p
[
i
];
addr
=
*
((
u16
*
)
&
b
[
1
]);
ret
=
dibusb_writemem
(
udev
,
addr
,
&
b
[
4
],
b
[
0
]);
if
(
ret
!=
b
[
0
])
{
err
(
"error while transferring firmware "
"(transferred size: %d, block size: %d)"
,
ret
,
b
[
0
]);
ret
=
-
EINVAL
;
break
;
}
i
+=
5
+
b
[
0
];
}
/* length in ret */
if
(
ret
>
0
)
ret
=
0
;
/* restart the CPU */
reset
=
0
;
if
(
ret
||
dibusb_writemem
(
udev
,
dibdev
->
parm
->
usb_cpu_csreg
,
&
reset
,
1
)
!=
1
)
{
err
(
"could not restart the USB controller CPU."
);
ret
=
-
EINVAL
;
}
kfree
(
p
);
}
else
{
ret
=
-
ENOMEM
;
}
release_firmware
(
fw
);
return
ret
;
}
/*
* USB
*/
static
int
dibusb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
struct
usb_dibusb
*
dib
=
NULL
;
struct
dibusb_device
*
dibdev
=
NULL
;
int
ret
=
-
ENOMEM
,
i
,
cold
=
0
;
for
(
i
=
0
;
i
<
DIBUSB_SUPPORTED_DEVICES
;
i
++
)
if
(
dibusb_devices
[
i
].
cold_product_id
==
le16_to_cpu
(
udev
->
descriptor
.
idProduct
)
||
dibusb_devices
[
i
].
warm_product_id
==
le16_to_cpu
(
udev
->
descriptor
.
idProduct
))
{
dibdev
=
&
dibusb_devices
[
i
];
cold
=
dibdev
->
cold_product_id
==
le16_to_cpu
(
udev
->
descriptor
.
idProduct
);
if
(
cold
)
info
(
"found a '%s' in cold state, will try to load a firmware"
,
dibdev
->
name
);
else
info
(
"found a '%s' in warm state."
,
dibdev
->
name
);
}
if
(
dibdev
==
NULL
)
{
err
(
"something went very wrong, "
"unknown product ID: %.4x"
,
le16_to_cpu
(
udev
->
descriptor
.
idProduct
));
return
-
ENODEV
;
}
if
(
cold
)
ret
=
dibusb_loadfirmware
(
udev
,
dibdev
);
else
{
dib
=
kmalloc
(
sizeof
(
struct
usb_dibusb
),
GFP_KERNEL
);
if
(
dib
==
NULL
)
{
err
(
"no memory"
);
return
ret
;
}
memset
(
dib
,
0
,
sizeof
(
struct
usb_dibusb
));
dib
->
pid_parse
=
1
;
switch
(
udev
->
speed
)
{
case
USB_SPEED_LOW
:
err
(
"cannot handle USB speed because it is to sLOW."
);
break
;
case
USB_SPEED_FULL
:
info
(
"running at FULL speed, will use pid parsing."
);
break
;
case
USB_SPEED_HIGH
:
if
(
!
pid_parse
)
{
dib
->
pid_parse
=
0
;
info
(
"running at HIGH speed, will deliver the complete TS."
);
}
else
info
(
"running at HIGH speed, will use pid_parsing anyway."
);
break
;
case
USB_SPEED_UNKNOWN
:
/* fall through */
default:
err
(
"cannot handle USB speed because it is unkown."
);
break
;
}
dib
->
udev
=
udev
;
dib
->
dibdev
=
dibdev
;
usb_set_intfdata
(
intf
,
dib
);
ret
=
dibusb_init
(
dib
);
}
if
(
ret
==
0
)
info
(
"%s successfully initialized and connected."
,
dibdev
->
name
);
else
info
(
"%s error while loading driver (%d)"
,
dibdev
->
name
,
ret
);
return
ret
;
}
static
void
dibusb_disconnect
(
struct
usb_interface
*
intf
)
{
struct
usb_dibusb
*
dib
=
usb_get_intfdata
(
intf
);
const
char
*
name
=
DRIVER_DESC
;
usb_set_intfdata
(
intf
,
NULL
);
if
(
dib
!=
NULL
)
{
name
=
dib
->
dibdev
->
name
;
dibusb_dvb_exit
(
dib
);
dibusb_exit
(
dib
);
kfree
(
dib
);
}
info
(
"%s successfully deinitialized and disconnected."
,
name
);
}
/* usb specific object needed to register this driver with the usb subsystem */
static
struct
usb_driver
dibusb_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"dvb_dibusb"
,
.
probe
=
dibusb_probe
,
.
disconnect
=
dibusb_disconnect
,
.
id_table
=
dibusb_table
,
};
/* module stuff */
static
int
__init
usb_dibusb_init
(
void
)
{
int
result
;
if
((
result
=
usb_register
(
&
dibusb_driver
)))
{
err
(
"usb_register failed. Error number %d"
,
result
);
return
result
;
}
return
0
;
}
static
void
__exit
usb_dibusb_exit
(
void
)
{
/* deregister this driver from the USB subsystem */
usb_deregister
(
&
dibusb_driver
);
}
module_init
(
usb_dibusb_init
);
module_exit
(
usb_dibusb_exit
);
MODULE_AUTHOR
(
DRIVER_AUTHOR
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
drivers/media/dvb/dibusb/dvb-dibusb.h
View file @
ca583a3c
/*
* dvb-dibusb.h
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
* Copyright (C) 2004
-5
Patrick Boettcher (patrick.boettcher@desy.de)
*
* 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 the Free Software Foundation, version 2.
*
* for more information see dvb-dibusb.c .
* for more information see dvb-dibusb
-core
.c .
*/
#ifndef __DVB_DIBUSB_H__
#define __DVB_DIBUSB_H__
#include <linux/input.h>
#include <linux/config.h>
#include <linux/usb.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
#include "dvb_net.h"
#include "dmxdev.h"
#include "dib3000.h"
#include "mt352.h"
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) { printk(args); } } while (0)
#define debug_dump(b,l) if (debug) {\
int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
deb_xfer("\n");\
}
/* module parameters - declared in -core.c */
extern
int
debug
;
#else
#define dprintk(args...)
#define debug_dump(b,l)
#endif
/* Version information */
#define DRIVER_VERSION "0.3"
#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
/* module parameters - declared in -core.c */
extern
int
pid_parse
;
extern
int
rc_query_interval
;
#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_alot(args...) dprintk(0x04,args)
#define deb_ts(args...) dprintk(0x08,args)
#define deb_err(args...) dprintk(0x10,args)
#define deb_rc(args...) dprintk(0x20,args)
/* generic log methods - taken from usb.h */
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
struct
dibusb_usb_controller
{
const
char
*
name
;
/* name of the usb controller */
u16
cpu_cs_register
;
/* needs to be restarted, when the firmware has been downloaded. */
};
typedef
enum
{
DIBUSB1_1
=
0
,
DIBUSB2_0
,
DIBUSB1_1_AN2235
,
}
dibusb_type
;
DIBUSB2_0
,
UMT2_0
,
}
dibusb_class_t
;
static
const
char
*
dibusb_fw_filenames1_1
[]
=
{
"dvb-dibusb-5.0.0.11.fw"
};
typedef
enum
{
DIBUSB_TUNER_CABLE_THOMSON
=
0
,
DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5
,
DIBUSB_TUNER_CABLE_LG_TDTP_E102P
,
DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5
,
}
dibusb_tuner_t
;
static
const
char
*
dibusb_fw_filenames1_1_an2235
[]
=
{
"dvb-dibusb-an2235-1.fw"
};
typedef
enum
{
DIBUSB_DIB3000MB
=
0
,
DIBUSB_DIB3000MC
,
DIBUSB_MT352
,
}
dibusb_demodulator_t
;
static
const
char
*
dibusb_fw_filenames2_0
[]
=
{
"dvb-dibusb-6.0.0.5.fw"
};
typedef
enum
{
DIBUSB_RC_NO
=
0
,
DIBUSB_RC_NEC_PROTOCOL
=
1
,
}
dibusb_remote_t
;
struct
dibusb_device_parameter
{
dibusb_type
type
;
u8
demod_addr
;
const
char
**
fw_filenames
;
const
char
*
usb_controller
;
u16
usb_cpu_csreg
;
int
num_urbs
;
int
urb_buf_size
;
int
default_size
;
int
firmware_bug
;
int
cmd_pipe
;
int
result_pipe
;
int
data_pipe
;
};
struct
dibusb_tuner
{
dibusb_tuner_t
id
;
static
struct
dibusb_device_parameter
dibusb_dev_parm
[
3
]
=
{
{
.
type
=
DIBUSB1_1
,
.
demod_addr
=
0x10
,
.
fw_filenames
=
dibusb_fw_filenames1_1
,
.
usb_controller
=
"Cypress AN2135"
,
.
usb_cpu_csreg
=
0x7f92
,
.
num_urbs
=
3
,
.
urb_buf_size
=
4096
,
.
default_size
=
188
*
21
,
.
firmware_bug
=
1
,
.
cmd_pipe
=
0x01
,
.
result_pipe
=
0x81
,
.
data_pipe
=
0x82
,
},
{
.
type
=
DIBUSB2_0
,
.
demod_addr
=
0x18
,
.
fw_filenames
=
dibusb_fw_filenames2_0
,
.
usb_controller
=
"Cypress FX2"
,
.
usb_cpu_csreg
=
0xe600
,
.
num_urbs
=
3
,
.
urb_buf_size
=
40960
,
.
default_size
=
188
*
210
,
.
firmware_bug
=
0
,
.
cmd_pipe
=
0x01
,
.
result_pipe
=
0x81
,
.
data_pipe
=
0x86
,
},
{
.
type
=
DIBUSB1_1_AN2235
,
.
demod_addr
=
0x10
,
.
fw_filenames
=
dibusb_fw_filenames1_1_an2235
,
.
usb_controller
=
"Cypress CY7C64613 (AN2235)"
,
.
usb_cpu_csreg
=
0x7f92
,
.
num_urbs
=
3
,
.
urb_buf_size
=
4096
,
.
default_size
=
188
*
21
,
.
firmware_bug
=
1
,
.
cmd_pipe
=
0x01
,
.
result_pipe
=
0x81
,
.
data_pipe
=
0x82
,
}
u8
pll_addr
;
/* tuner i2c address */
};
extern
struct
dibusb_tuner
dibusb_tuner
[];
struct
dibusb_device
{
const
char
*
name
;
u16
cold_product_id
;
u16
warm_product_id
;
struct
dibusb_device_parameter
*
parm
;
};
#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4
struct
dibusb_demod
{
dibusb_demodulator_t
id
;
/* Vendor IDs */
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA 0x14aa
#define USB_VID_COMPRO 0x185b
#define USB_VID_COMPRO_UNK 0x145f
#define USB_VID_CYPRESS 0x04b4
#define USB_VID_DIBCOM 0x10b8
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GRANDTEC 0x5032
#define USB_VID_HYPER_PALTEK 0x1025
#define USB_VID_IMC_NETWORKS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
/* Product IDs */
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
#define USB_PID_YAKUMO_DTT200U_COLD 0x0201
#define USB_PID_YAKUMO_DTT200U_WARM 0x0301
#define DIBUSB_SUPPORTED_DEVICES 15
/* USB Driver stuff */
static
struct
dibusb_device
dibusb_devices
[
DIBUSB_SUPPORTED_DEVICES
]
=
{
{
.
name
=
"TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device"
,
.
cold_product_id
=
USB_PID_TWINHAN_VP7041_COLD
,
.
warm_product_id
=
USB_PID_TWINHAN_VP7041_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"KWorld V-Stream XPERT DTV - DVB-T USB1.1"
,
.
cold_product_id
=
USB_PID_KWORLD_VSTREAM_COLD
,
.
warm_product_id
=
USB_PID_KWORLD_VSTREAM_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Grandtec USB1.1 DVB-T/DiBcom USB1.1 DVB-T reference design (MOD3000)"
,
.
cold_product_id
=
USB_PID_DIBCOM_MOD3000_COLD
,
.
warm_product_id
=
USB_PID_DIBCOM_MOD3000_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Artec T1 USB1.1 TVBOX with AN2135"
,
.
cold_product_id
=
USB_PID_ULTIMA_TVBOX_COLD
,
.
warm_product_id
=
USB_PID_ULTIMA_TVBOX_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Artec T1 USB1.1 TVBOX with AN2235"
,
.
cold_product_id
=
USB_PID_ULTIMA_TVBOX_AN2235_COLD
,
.
warm_product_id
=
USB_PID_ULTIMA_TVBOX_AN2235_WARM
,
.
parm
=
&
dibusb_dev_parm
[
2
],
},
{
.
name
=
"Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)"
,
.
cold_product_id
=
USB_PID_ULTIMA_TVBOX_ANCHOR_COLD
,
.
warm_product_id
=
0
,
/* undefined, this design becomes USB_PID_DIBCOM_MOD3000_WARM in warm state */
.
parm
=
&
dibusb_dev_parm
[
2
],
},
{
.
name
=
"Artec T1 USB2.0 TVBOX (please report the warm ID)"
,
.
cold_product_id
=
USB_PID_ULTIMA_TVBOX_USB2_COLD
,
.
warm_product_id
=
0
,
/* don't know, it is most likely that the device will get another USB ID in warm state */
.
parm
=
&
dibusb_dev_parm
[
1
],
},
{
.
name
=
"Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)"
,
.
cold_product_id
=
USB_PID_ULTIMA_TVBOX_USB2_FX_COLD
,
.
warm_product_id
=
USB_PID_ULTIMA_TVBOX_USB2_FX_WARM
,
/* undefined, it could be that the device will get another USB ID in warm state */
.
parm
=
&
dibusb_dev_parm
[
1
],
},
{
.
name
=
"Compro Videomate DVB-U2000 - DVB-T USB1.1"
,
.
cold_product_id
=
USB_PID_COMPRO_DVBU2000_COLD
,
.
warm_product_id
=
USB_PID_COMPRO_DVBU2000_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Compro Videomate DVB-U2000 - DVB-T USB1.1 (really ?? please report the name!)"
,
.
cold_product_id
=
USB_PID_COMPRO_DVBU2000_UNK_COLD
,
.
warm_product_id
=
USB_PID_COMPRO_DVBU2000_UNK_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Unkown USB1.1 DVB-T device ???? please report the name to the author"
,
.
cold_product_id
=
USB_PID_UNK_HYPER_PALTEK_COLD
,
.
warm_product_id
=
USB_PID_UNK_HYPER_PALTEK_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"DiBcom USB2.0 DVB-T reference design (MOD3000P)"
,
.
cold_product_id
=
USB_PID_DIBCOM_MOD3001_COLD
,
.
warm_product_id
=
USB_PID_DIBCOM_MOD3001_WARM
,
.
parm
=
&
dibusb_dev_parm
[
1
],
},
{
.
name
=
"Grandtec DVB-T USB1.1"
,
.
cold_product_id
=
USB_PID_GRANDTEC_DVBT_USB_COLD
,
.
warm_product_id
=
USB_PID_GRANDTEC_DVBT_USB_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Avermedia AverTV DVBT USB1.1"
,
.
cold_product_id
=
USB_PID_AVERMEDIA_DVBT_USB_COLD
,
.
warm_product_id
=
USB_PID_AVERMEDIA_DVBT_USB_WARM
,
.
parm
=
&
dibusb_dev_parm
[
0
],
},
{
.
name
=
"Yakumo DVB-T mobile USB2.0"
,
.
cold_product_id
=
USB_PID_YAKUMO_DTT200U_COLD
,
.
warm_product_id
=
USB_PID_YAKUMO_DTT200U_WARM
,
.
parm
=
&
dibusb_dev_parm
[
1
],
}
int
pid_filter_count
;
/* counter of the internal pid_filter */
u8
i2c_addrs
[
DIBUSB_POSSIBLE_I2C_ADDR_NUM
];
/* list of possible i2c addresses of the demod */
};
/* USB Driver stuff */
/* table of devices that work with this driver */
static
struct
usb_device_id
dibusb_table
[]
=
{
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_AVERMEDIA_DVBT_USB_COLD
)},
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_AVERMEDIA_DVBT_USB_WARM
)},
{
USB_DEVICE
(
USB_VID_COMPRO
,
USB_PID_COMPRO_DVBU2000_COLD
)
},
{
USB_DEVICE
(
USB_VID_COMPRO
,
USB_PID_COMPRO_DVBU2000_WARM
)
},
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3000_COLD
)
},
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3000_WARM
)
},
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3001_COLD
)
},
{
USB_DEVICE
(
USB_VID_DIBCOM
,
USB_PID_DIBCOM_MOD3001_WARM
)
},
{
USB_DEVICE
(
USB_VID_EMPIA
,
USB_PID_KWORLD_VSTREAM_COLD
)
},
{
USB_DEVICE
(
USB_VID_EMPIA
,
USB_PID_KWORLD_VSTREAM_WARM
)
},
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_GRANDTEC_DVBT_USB_COLD
)
},
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_GRANDTEC_DVBT_USB_WARM
)
},
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_DIBCOM_MOD3000_COLD
)
},
{
USB_DEVICE
(
USB_VID_GRANDTEC
,
USB_PID_DIBCOM_MOD3000_WARM
)
},
{
USB_DEVICE
(
USB_VID_HYPER_PALTEK
,
USB_PID_UNK_HYPER_PALTEK_COLD
)
},
{
USB_DEVICE
(
USB_VID_HYPER_PALTEK
,
USB_PID_UNK_HYPER_PALTEK_WARM
)
},
{
USB_DEVICE
(
USB_VID_IMC_NETWORKS
,
USB_PID_TWINHAN_VP7041_COLD
)
},
{
USB_DEVICE
(
USB_VID_IMC_NETWORKS
,
USB_PID_TWINHAN_VP7041_WARM
)
},
{
USB_DEVICE
(
USB_VID_TWINHAN
,
USB_PID_TWINHAN_VP7041_COLD
)
},
{
USB_DEVICE
(
USB_VID_TWINHAN
,
USB_PID_TWINHAN_VP7041_WARM
)
},
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_COLD
)
},
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_WARM
)
},
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_AN2235_COLD
)
},
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_AN2235_WARM
)
},
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_YAKUMO_DTT200U_COLD
)
},
{
USB_DEVICE
(
USB_VID_AVERMEDIA
,
USB_PID_YAKUMO_DTT200U_WARM
)
},
{
USB_DEVICE
(
USB_PID_COMPRO_DVBU2000_UNK_COLD
,
USB_VID_COMPRO_UNK
)
},
{
USB_DEVICE
(
USB_VID_ULTIMA_ELECTRONIC
,
USB_PID_ULTIMA_TVBOX_USB2_COLD
)
},
#define DIBUSB_MAX_TUNER_NUM 2
struct
dibusb_device_class
{
dibusb_class_t
id
;
/*
* activate the following define when you have one of the devices and want to
* build it from build-2.6 in dvb-kernel
*/
// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
{
USB_DEVICE
(
USB_VID_ANCHOR
,
USB_PID_ULTIMA_TVBOX_ANCHOR_COLD
)
},
{
USB_DEVICE
(
USB_VID_CYPRESS
,
USB_PID_ULTIMA_TVBOX_USB2_FX_COLD
)
},
{
USB_DEVICE
(
USB_VID_ANCHOR
,
USB_PID_ULTIMA_TVBOX_USB2_FX_WARM
)
},
#endif
{
}
/* Terminating entry */
const
struct
dibusb_usb_controller
*
usb_ctrl
;
/* usb controller */
const
char
*
firmware
;
/* valid firmware filenames */
int
pipe_cmd
;
/* command pipe (read/write) */
int
pipe_data
;
/* data pipe */
int
urb_count
;
/* number of data URBs to be submitted */
int
urb_buffer_size
;
/* the size of the buffer for each URB */
dibusb_remote_t
remote_type
;
/* does this device have a ir-receiver */
struct
dibusb_demod
*
demod
;
/* which demodulator is mount */
struct
dibusb_tuner
*
tuner
;
/* which tuner can be found here */
};
MODULE_DEVICE_TABLE
(
usb
,
dibusb_table
);
#define DIBUSB_ID_MAX_NUM 15
struct
dibusb_usb_device
{
const
char
*
name
;
/* real name of the box */
struct
dibusb_device_class
*
dev_cl
;
/* which dibusb_device_class is this device part of */
#define DIBUSB_I2C_TIMEOUT HZ*5
struct
usb_device_id
*
cold_ids
[
DIBUSB_ID_MAX_NUM
];
/* list of USB ids when this device is at pre firmware state */
struct
usb_device_id
*
warm_ids
[
DIBUSB_ID_MAX_NUM
];
/* list of USB ids when this device is at post firmware state */
};
/* a PID for the pid_filter list, when in use */
struct
dibusb_pid
{
int
index
;
u16
pid
;
int
active
;
};
struct
usb_dibusb
{
/* usb */
struct
usb_device
*
udev
;
struct
dibusb_device
*
dibdev
;
struct
dibusb_usb_device
*
dibdev
;
#define DIBUSB_STATE_INIT 0x000
#define DIBUSB_STATE_URB_LIST 0x001
#define DIBUSB_STATE_URB_BUF 0x002
#define DIBUSB_STATE_URB_SUBMIT 0x004
#define DIBUSB_STATE_DVB 0x008
#define DIBUSB_STATE_I2C 0x010
#define DIBUSB_STATE_REMOTE 0x020
#define DIBUSB_STATE_PIDLIST 0x040
int
init_state
;
int
feedcount
;
int
pid_parse
;
struct
dib3000_xfer_ops
xfer_ops
;
struct
dib_fe_xfer_ops
xfer_ops
;
struct
dibusb_tuner
*
tuner
;
struct
urb
**
urb_list
;
u8
*
buffer
;
...
...
@@ -295,49 +173,137 @@ struct usb_dibusb {
/* I2C */
struct
i2c_adapter
i2c_adap
;
struct
i2c_client
i2c_client
;
/* locking */
struct
semaphore
usb_sem
;
struct
semaphore
i2c_sem
;
/* pid filtering */
spinlock_t
pid_list_lock
;
struct
dibusb_pid
*
pid_list
;
/* dvb */
int
dvb_is_ready
;
struct
dvb_adapter
*
adapter
;
struct
dmxdev
dmxdev
;
struct
dvb_demux
demux
;
struct
dvb_net
dvb_net
;
struct
dvb_frontend
*
fe
;
int
(
*
fe_sleep
)
(
struct
dvb_frontend
*
);
int
(
*
fe_init
)
(
struct
dvb_frontend
*
);
/* remote control */
struct
input_dev
rc_input_dev
;
struct
work_struct
rc_query_work
;
int
rc_input_event
;
};
/* commonly used functions in the separated files */
/* dvb-dibusb-firmware.c */
int
dibusb_loadfirmware
(
struct
usb_device
*
udev
,
struct
dibusb_usb_device
*
dibdev
);
/* dvb-dibusb-remote.c */
int
dibusb_remote_exit
(
struct
usb_dibusb
*
dib
);
int
dibusb_remote_init
(
struct
usb_dibusb
*
dib
);
/* dvb-dibusb-fe-i2c.c */
int
dibusb_i2c_msg
(
struct
usb_dibusb
*
dib
,
u8
addr
,
u8
*
wbuf
,
u16
wlen
,
u8
*
rbuf
,
u16
rlen
);
int
dibusb_fe_init
(
struct
usb_dibusb
*
dib
);
int
dibusb_fe_exit
(
struct
usb_dibusb
*
dib
);
int
dibusb_i2c_init
(
struct
usb_dibusb
*
dib
);
int
dibusb_i2c_exit
(
struct
usb_dibusb
*
dib
);
/* dvb-dibusb-dvb.c */
void
dibusb_urb_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
ptregs
);
int
dibusb_dvb_init
(
struct
usb_dibusb
*
dib
);
int
dibusb_dvb_exit
(
struct
usb_dibusb
*
dib
);
/* dvb-dibusb-usb.c */
int
dibusb_readwrite_usb
(
struct
usb_dibusb
*
dib
,
u8
*
wbuf
,
u16
wlen
,
u8
*
rbuf
,
u16
rlen
);
int
dibusb_hw_wakeup
(
struct
dvb_frontend
*
);
int
dibusb_hw_sleep
(
struct
dvb_frontend
*
);
int
dibusb_set_streaming_mode
(
struct
usb_dibusb
*
,
u8
);
int
dibusb_streaming
(
struct
usb_dibusb
*
,
int
);
int
dibusb_urb_init
(
struct
usb_dibusb
*
);
int
dibusb_urb_exit
(
struct
usb_dibusb
*
);
/* dvb-dibusb-pid.c */
int
dibusb_pid_list_init
(
struct
usb_dibusb
*
dib
);
void
dibusb_pid_list_exit
(
struct
usb_dibusb
*
dib
);
int
dibusb_ctrl_pid
(
struct
usb_dibusb
*
dib
,
struct
dvb_demux_feed
*
dvbdmxfeed
,
int
onoff
);
/* types of first byte of each buffer */
/* i2c and transfer stuff */
#define DIBUSB_I2C_TIMEOUT HZ*5
/*
* protocol of all dibusb related devices
*/
/*
* bulk msg to/from endpoint 0x01
*
* general structure:
* request_byte parameter_bytes
*/
#define DIBUSB_REQ_START_READ 0x00
#define DIBUSB_REQ_START_DEMOD 0x01
/*
* i2c read
* bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
* bulk read: byte_buffer (length_word bytes)
*/
#define DIBUSB_REQ_I2C_READ 0x02
/*
* i2c write
* bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
*/
#define DIBUSB_REQ_I2C_WRITE 0x03
/* prefix for reading the current RC key */
/*
* polling the value of the remote control
* bulk write: 0x04
* bulk read: byte_buffer (5 bytes)
*
* first byte of byte_buffer shows the status (0x00, 0x01, 0x02)
*/
#define DIBUSB_REQ_POLL_REMOTE 0x04
#define DIBUSB_RC_NEC_EMPTY 0x00
#define DIBUSB_RC_NEC_KEY_PRESSED 0x01
#define DIBUSB_RC_NEC_KEY_REPEATED 0x02
/* 0x05 0xXX */
/* streaming mode:
* bulk write: 0x05 mode_byte
*
* mode_byte is mostly 0x00
*/
#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
/* interrupt the internal read loop, when blocking */
#define DIBUSB_REQ_INTR_READ 0x06
/* IO control
* 0x07 <cmd 1 byte> <param 32 bytes>
/* io control
* 0x07 cmd_byte param_bytes
*
* param_bytes can be up to 32 bytes
*
* cmd_byte function parameter name
* 0x00 power mode
* 0x00 sleep
* 0x01 wakeup
*
* 0x01 enable streaming
* 0x02 disable streaming
*
*
*/
#define DIBUSB_REQ_SET_IOCTL 0x07
...
...
@@ -348,4 +314,8 @@ struct usb_dibusb {
#define DIBUSB_IOCTL_POWER_SLEEP 0x00
#define DIBUSB_IOCTL_POWER_WAKEUP 0x01
/* modify streaming of the FX2 */
#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02
#endif
drivers/media/dvb/dvb-core/dvb_demux.c
View file @
ca583a3c
...
...
@@ -247,7 +247,22 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
}
/*
** Losless Section Demux 1.4 by Emard
** Losless Section Demux 1.4.1 by Emard
** Valsecchi Patrick:
** - middle of section A (no PUSI)
** - end of section A and start of section B
** (with PUSI pointing to the start of the second section)
**
** In this case, without feed->pusi_seen you'll receive a garbage section
** consisting of the end of section A. Basically because tsfeedp
** is incemented and the use=0 condition is not raised
** when the second packet arrives.
**
** Fix:
** when demux is started, let feed->pusi_seen = 0 to
** prevent initial feeding of garbage from the end of
** previous section. When you for the first time see PUSI=1
** then set feed->pusi_seen = 1
*/
static
int
dvb_dmx_swfilter_section_copy_dump
(
struct
dvb_demux_feed
*
feed
,
const
u8
*
buf
,
u8
len
)
{
...
...
@@ -293,7 +308,12 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const
sec
->
seclen
=
seclen
;
sec
->
crc_val
=
~
0
;
/* dump [secbuf .. secbuf+seclen) */
if
(
feed
->
pusi_seen
)
dvb_dmx_swfilter_section_feed
(
feed
);
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
else
printk
(
"dvb_demux.c pusi not seen, discarding section data
\n
"
);
#endif
sec
->
secbufp
+=
seclen
;
/* secbufp and secbuf moving together is */
sec
->
secbuf
+=
seclen
;
/* redundand but saves pointer arithmetic */
}
...
...
@@ -305,7 +325,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const
static
int
dvb_dmx_swfilter_section_packet
(
struct
dvb_demux_feed
*
feed
,
const
u8
*
buf
)
{
u8
p
,
count
;
int
ccok
;
int
ccok
,
dc_i
=
0
;
u8
cc
;
count
=
payload
(
buf
);
...
...
@@ -316,31 +336,41 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8
p
=
188
-
count
;
/* payload start */
cc
=
buf
[
3
]
&
0x0f
;
ccok
=
((
feed
->
cc
+
1
)
&
0x0f
)
==
cc
?
1
:
0
;
ccok
=
((
feed
->
cc
+
1
)
&
0x0f
)
==
cc
;
feed
->
cc
=
cc
;
if
(
ccok
==
0
)
{
if
(
buf
[
3
]
&
0x20
)
{
/* adaption field present, check for discontinuity_indicator */
if
((
buf
[
4
]
>
0
)
&&
(
buf
[
5
]
&
0x80
))
dc_i
=
1
;
}
if
(
!
ccok
||
dc_i
)
{
#ifdef DVB_DEMUX_SECTION_LOSS_LOG
printk
(
"dvb_demux.c discontinuity detected %d bytes lost
\n
"
,
count
);
/* those bytes under sume circumstances will again be reported
** in the following dvb_dmx_swfilter_section_new
*/
#endif
/* Discontinuity detected. Reset pusi_seen = 0 to
** stop feeding of suspicious data until next PUSI=1 arrives
*/
feed
->
pusi_seen
=
0
;
dvb_dmx_swfilter_section_new
(
feed
);
return
0
;
}
if
(
buf
[
1
]
&
0x40
)
{
if
(
buf
[
1
]
&
0x40
)
{
// PUSI=1 (is set), section boundary is here
if
(
count
>
1
&&
buf
[
p
]
<
count
)
{
if
(
count
>
1
&&
buf
[
p
]
<
count
)
{
const
u8
*
before
=
buf
+
p
+
1
;
u8
before_len
=
buf
[
p
];
const
u8
*
after
=
before
+
before_len
;
u8
after_len
=
count
-
1
-
before_len
;
dvb_dmx_swfilter_section_copy_dump
(
feed
,
before
,
before_len
);
/* before start of new section, set pusi_seen = 1 */
feed
->
pusi_seen
=
1
;
dvb_dmx_swfilter_section_new
(
feed
);
dvb_dmx_swfilter_section_copy_dump
(
feed
,
after
,
after_len
);
}
...
...
@@ -349,9 +379,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8
if
(
count
>
0
)
printk
(
"dvb_demux.c PUSI=1 but %d bytes lost
\n
"
,
count
);
#endif
}
else
{
}
else
{
// PUSI=0 (is not set), no section boundary
const
u8
*
entire
=
buf
+
p
;
u8
entire_len
=
count
;
...
...
@@ -784,10 +812,8 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_
}
#ifndef NOBUFS
if
(
feed
->
buffer
)
{
vfree
(
feed
->
buffer
);
feed
->
buffer
=
0
;
}
#endif
feed
->
state
=
DMX_STATE_FREE
;
...
...
@@ -1055,10 +1081,8 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
return
-
EINVAL
;
}
#ifndef NOBUFS
if
(
dvbdmxfeed
->
buffer
)
{
vfree
(
dvbdmxfeed
->
buffer
);
dvbdmxfeed
->
buffer
=
0
;
}
#endif
dvbdmxfeed
->
state
=
DMX_STATE_FREE
;
...
...
@@ -1269,9 +1293,7 @@ int dvb_dmx_release(struct dvb_demux *dvbdemux)
struct
dmx_demux
*
dmx
=
&
dvbdemux
->
dmx
;
dmx_unregister_demux
(
dmx
);
if
(
dvbdemux
->
filter
)
vfree
(
dvbdemux
->
filter
);
if
(
dvbdemux
->
feed
)
vfree
(
dvbdemux
->
feed
);
return
0
;
}
...
...
drivers/media/dvb/dvb-core/dvb_demux.h
View file @
ca583a3c
...
...
@@ -93,6 +93,7 @@ struct dvb_demux_feed {
enum
dmx_ts_pes
pes_type
;
int
cc
;
int
pusi_seen
;
/* prevents feeding of garbage from previous section */
u16
peslen
;
...
...
drivers/media/dvb/dvb-core/dvb_frontend.c
View file @
ca583a3c
...
...
@@ -89,9 +89,36 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
static
DECLARE_MUTEX
(
frontend_mutex
);
struct
dvb_frontend_private
{
struct
dvb_device
*
dvbdev
;
struct
dvb_frontend_parameters
parameters
;
struct
dvb_fe_events
events
;
struct
semaphore
sem
;
struct
list_head
list_head
;
wait_queue_head_t
wait_queue
;
pid_t
thread_pid
;
unsigned
long
release_jiffies
;
int
state
;
int
bending
;
int
lnb_drift
;
int
inversion
;
int
auto_step
;
int
auto_sub_step
;
int
started_auto_step
;
int
min_delay
;
int
max_drift
;
int
step_size
;
int
exit
;
int
wakeup
;
fe_status_t
status
;
};
static
void
dvb_frontend_add_event
(
struct
dvb_frontend
*
fe
,
fe_status_t
status
)
{
struct
dvb_fe_events
*
events
=
&
fe
->
events
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
struct
dvb_fe_events
*
events
=
&
fepriv
->
events
;
struct
dvb_frontend_event
*
e
;
int
wp
;
...
...
@@ -109,7 +136,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
e
=
&
events
->
events
[
events
->
eventw
];
memcpy
(
&
e
->
parameters
,
&
fe
->
parameters
,
memcpy
(
&
e
->
parameters
,
&
fe
priv
->
parameters
,
sizeof
(
struct
dvb_frontend_parameters
));
if
(
status
&
FE_HAS_LOCK
)
...
...
@@ -128,7 +155,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
static
int
dvb_frontend_get_event
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_event
*
event
,
int
flags
)
{
struct
dvb_fe_events
*
events
=
&
fe
->
events
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
struct
dvb_fe_events
*
events
=
&
fepriv
->
events
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
...
...
@@ -143,12 +171,12 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
if
(
flags
&
O_NONBLOCK
)
return
-
EWOULDBLOCK
;
up
(
&
fe
->
sem
);
up
(
&
fe
priv
->
sem
);
ret
=
wait_event_interruptible
(
events
->
wait_queue
,
events
->
eventw
!=
events
->
eventr
);
if
(
down_interruptible
(
&
fe
->
sem
))
if
(
down_interruptible
(
&
fepriv
->
sem
))
return
-
ERESTARTSYS
;
if
(
ret
<
0
)
...
...
@@ -206,27 +234,28 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
{
int
autoinversion
;
int
ready
=
0
;
int
original_inversion
=
fe
->
parameters
.
inversion
;
u32
original_frequency
=
fe
->
parameters
.
frequency
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
int
original_inversion
=
fepriv
->
parameters
.
inversion
;
u32
original_frequency
=
fepriv
->
parameters
.
frequency
;
/* are we using autoinversion? */
autoinversion
=
((
!
(
fe
->
ops
->
info
.
caps
&
FE_CAN_INVERSION_AUTO
))
&&
(
fe
->
parameters
.
inversion
==
INVERSION_AUTO
));
(
fe
priv
->
parameters
.
inversion
==
INVERSION_AUTO
));
/* setup parameters correctly */
while
(
!
ready
)
{
/* calculate the lnb_drift */
fe
->
lnb_drift
=
fe
->
auto_step
*
fe
->
step_size
;
fe
priv
->
lnb_drift
=
fepriv
->
auto_step
*
fepriv
->
step_size
;
/* wrap the auto_step if we've exceeded the maximum drift */
if
(
fe
->
lnb_drift
>
fe
->
max_drift
)
{
fe
->
auto_step
=
0
;
fe
->
auto_sub_step
=
0
;
fe
->
lnb_drift
=
0
;
if
(
fe
priv
->
lnb_drift
>
fepriv
->
max_drift
)
{
fe
priv
->
auto_step
=
0
;
fe
priv
->
auto_sub_step
=
0
;
fe
priv
->
lnb_drift
=
0
;
}
/* perform inversion and +/- zigzag */
switch
(
fe
->
auto_sub_step
)
{
switch
(
fe
priv
->
auto_sub_step
)
{
case
0
:
/* try with the current inversion and current drift setting */
ready
=
1
;
...
...
@@ -235,68 +264,70 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
case
1
:
if
(
!
autoinversion
)
break
;
fe
->
inversion
=
(
fe
->
inversion
==
INVERSION_OFF
)
?
INVERSION_ON
:
INVERSION_OFF
;
fe
priv
->
inversion
=
(
fepriv
->
inversion
==
INVERSION_OFF
)
?
INVERSION_ON
:
INVERSION_OFF
;
ready
=
1
;
break
;
case
2
:
if
(
fe
->
lnb_drift
==
0
)
break
;
if
(
fe
priv
->
lnb_drift
==
0
)
break
;
fe
->
lnb_drift
=
-
fe
->
lnb_drift
;
fe
priv
->
lnb_drift
=
-
fepriv
->
lnb_drift
;
ready
=
1
;
break
;
case
3
:
if
(
fe
->
lnb_drift
==
0
)
break
;
if
(
fe
priv
->
lnb_drift
==
0
)
break
;
if
(
!
autoinversion
)
break
;
fe
->
inversion
=
(
fe
->
inversion
==
INVERSION_OFF
)
?
INVERSION_ON
:
INVERSION_OFF
;
fe
->
lnb_drift
=
-
fe
->
lnb_drift
;
fe
priv
->
inversion
=
(
fepriv
->
inversion
==
INVERSION_OFF
)
?
INVERSION_ON
:
INVERSION_OFF
;
fe
priv
->
lnb_drift
=
-
fepriv
->
lnb_drift
;
ready
=
1
;
break
;
default:
fe
->
auto_step
++
;
fe
->
auto_sub_step
=
-
1
;
/* it'll be incremented to 0 in a moment */
fe
priv
->
auto_step
++
;
fe
priv
->
auto_sub_step
=
-
1
;
/* it'll be incremented to 0 in a moment */
break
;
}
if
(
!
ready
)
fe
->
auto_sub_step
++
;
if
(
!
ready
)
fe
priv
->
auto_sub_step
++
;
}
/* if this attempt would hit where we started, indicate a complete
* iteration has occurred */
if
((
fe
->
auto_step
==
fe
->
started_auto_step
)
&&
(
fe
->
auto_sub_step
==
0
)
&&
check_wrapped
)
{
if
((
fe
priv
->
auto_step
==
fepriv
->
started_auto_step
)
&&
(
fe
priv
->
auto_sub_step
==
0
)
&&
check_wrapped
)
{
return
1
;
}
dprintk
(
"%s: drift:%i inversion:%i auto_step:%i "
"auto_sub_step:%i started_auto_step:%i
\n
"
,
__FUNCTION__
,
fe
->
lnb_drift
,
fe
->
inversion
,
fe
->
auto_step
,
fe
->
auto_sub_step
,
fe
->
started_auto_step
);
__FUNCTION__
,
fe
priv
->
lnb_drift
,
fepriv
->
inversion
,
fe
priv
->
auto_step
,
fepriv
->
auto_sub_step
,
fepriv
->
started_auto_step
);
/* set the frontend itself */
fe
->
parameters
.
frequency
+=
fe
->
lnb_drift
;
fe
priv
->
parameters
.
frequency
+=
fepriv
->
lnb_drift
;
if
(
autoinversion
)
fe
->
parameters
.
inversion
=
fe
->
inversion
;
fe
priv
->
parameters
.
inversion
=
fepriv
->
inversion
;
if
(
fe
->
ops
->
set_frontend
)
fe
->
ops
->
set_frontend
(
fe
,
&
fe
->
parameters
);
fe
->
ops
->
set_frontend
(
fe
,
&
fe
priv
->
parameters
);
fe
->
parameters
.
frequency
=
original_frequency
;
fe
->
parameters
.
inversion
=
original_inversion
;
fe
priv
->
parameters
.
frequency
=
original_frequency
;
fe
priv
->
parameters
.
inversion
=
original_inversion
;
fe
->
auto_sub_step
++
;
fe
priv
->
auto_sub_step
++
;
return
0
;
}
static
int
dvb_frontend_is_exiting
(
struct
dvb_frontend
*
fe
)
{
if
(
fe
->
exit
)
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
if
(
fepriv
->
exit
)
return
1
;
if
(
fe
->
dvbdev
->
writers
==
1
)
if
(
jiffies
-
fe
->
release_jiffies
>
dvb_shutdown_timeout
*
HZ
)
if
(
fe
priv
->
dvbdev
->
writers
==
1
)
if
(
jiffies
-
fe
priv
->
release_jiffies
>
dvb_shutdown_timeout
*
HZ
)
return
1
;
return
0
;
...
...
@@ -304,8 +335,10 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
static
int
dvb_frontend_should_wakeup
(
struct
dvb_frontend
*
fe
)
{
if
(
fe
->
wakeup
)
{
fe
->
wakeup
=
0
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
if
(
fepriv
->
wakeup
)
{
fepriv
->
wakeup
=
0
;
return
1
;
}
return
dvb_frontend_is_exiting
(
fe
);
...
...
@@ -313,8 +346,10 @@ static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
static
void
dvb_frontend_wakeup
(
struct
dvb_frontend
*
fe
)
{
fe
->
wakeup
=
1
;
wake_up_interruptible
(
&
fe
->
wait_queue
);
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
fepriv
->
wakeup
=
1
;
wake_up_interruptible
(
&
fepriv
->
wait_queue
);
}
/*
...
...
@@ -323,6 +358,7 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
static
int
dvb_frontend_thread
(
void
*
data
)
{
struct
dvb_frontend
*
fe
=
(
struct
dvb_frontend
*
)
data
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
unsigned
long
timeout
;
char
name
[
15
];
int
quality
=
0
,
delay
=
3
*
HZ
;
...
...
@@ -338,14 +374,14 @@ static int dvb_frontend_thread (void *data)
sigfillset
(
&
current
->
blocked
);
unlock_kernel
();
fe
->
status
=
0
;
fe
priv
->
status
=
0
;
dvb_frontend_init
(
fe
);
fe
->
wakeup
=
0
;
fe
priv
->
wakeup
=
0
;
while
(
1
)
{
up
(
&
fe
->
sem
);
/* is locked when we enter the thread... */
up
(
&
fepriv
->
sem
);
/* is locked when we enter the thread... */
timeout
=
wait_event_interruptible_timeout
(
fe
->
wait_queue
,
timeout
=
wait_event_interruptible_timeout
(
fe
priv
->
wait_queue
,
dvb_frontend_should_wakeup
(
fe
),
delay
);
if
(
0
!=
dvb_frontend_is_exiting
(
fe
))
{
...
...
@@ -356,44 +392,43 @@ static int dvb_frontend_thread (void *data)
if
(
current
->
flags
&
PF_FREEZE
)
refrigerator
(
PF_FREEZE
);
if
(
down_interruptible
(
&
fe
->
sem
))
if
(
down_interruptible
(
&
fepriv
->
sem
))
break
;
/* if we've got no parameters, just keep idling */
if
(
fe
->
state
&
FESTATE_IDLE
)
{
if
(
fe
priv
->
state
&
FESTATE_IDLE
)
{
delay
=
3
*
HZ
;
quality
=
0
;
continue
;
}
retune:
/* get the frontend status */
if
(
fe
->
state
&
FESTATE_RETUNE
)
{
if
(
fe
priv
->
state
&
FESTATE_RETUNE
)
{
s
=
0
;
}
else
{
if
(
fe
->
ops
->
read_status
)
fe
->
ops
->
read_status
(
fe
,
&
s
);
if
(
s
!=
fe
->
status
)
{
if
(
s
!=
fe
priv
->
status
)
{
dvb_frontend_add_event
(
fe
,
s
);
fe
->
status
=
s
;
fe
priv
->
status
=
s
;
}
}
/* if we're not tuned, and we have a lock, move to the TUNED state */
if
((
fe
->
state
&
FESTATE_WAITFORLOCK
)
&&
(
s
&
FE_HAS_LOCK
))
{
update_delay
(
&
quality
,
&
delay
,
fe
->
min_delay
,
s
&
FE_HAS_LOCK
);
fe
->
state
=
FESTATE_TUNED
;
if
((
fe
priv
->
state
&
FESTATE_WAITFORLOCK
)
&&
(
s
&
FE_HAS_LOCK
))
{
update_delay
(
&
quality
,
&
delay
,
fe
priv
->
min_delay
,
s
&
FE_HAS_LOCK
);
fe
priv
->
state
=
FESTATE_TUNED
;
/* if we're tuned, then we have determined the correct inversion */
if
((
!
(
fe
->
ops
->
info
.
caps
&
FE_CAN_INVERSION_AUTO
))
&&
(
fe
->
parameters
.
inversion
==
INVERSION_AUTO
))
{
fe
->
parameters
.
inversion
=
fe
->
inversion
;
(
fe
priv
->
parameters
.
inversion
==
INVERSION_AUTO
))
{
fe
priv
->
parameters
.
inversion
=
fepriv
->
inversion
;
}
continue
;
}
/* if we are tuned already, check we're still locked */
if
(
fe
->
state
&
FESTATE_TUNED
)
{
update_delay
(
&
quality
,
&
delay
,
fe
->
min_delay
,
s
&
FE_HAS_LOCK
);
if
(
fe
priv
->
state
&
FESTATE_TUNED
)
{
update_delay
(
&
quality
,
&
delay
,
fe
priv
->
min_delay
,
s
&
FE_HAS_LOCK
);
/* we're tuned, and the lock is still good... */
if
(
s
&
FE_HAS_LOCK
)
...
...
@@ -401,49 +436,49 @@ static int dvb_frontend_thread (void *data)
else
{
/* if we _WERE_ tuned, but now don't have a lock,
* need to zigzag */
fe
->
state
=
FESTATE_ZIGZAG_FAST
;
fe
->
started_auto_step
=
fe
->
auto_step
;
fe
priv
->
state
=
FESTATE_ZIGZAG_FAST
;
fe
priv
->
started_auto_step
=
fepriv
->
auto_step
;
check_wrapped
=
0
;
}
}
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if
((
fe
->
state
&
FESTATE_LOSTLOCK
)
&&
(
fe
->
ops
->
info
.
caps
&
FE_CAN_RECOVER
)
&&
(
fe
->
max_drift
==
0
))
{
update_delay
(
&
quality
,
&
delay
,
fe
->
min_delay
,
s
&
FE_HAS_LOCK
);
if
((
fe
priv
->
state
&
FESTATE_LOSTLOCK
)
&&
(
fe
->
ops
->
info
.
caps
&
FE_CAN_RECOVER
)
&&
(
fe
priv
->
max_drift
==
0
))
{
update_delay
(
&
quality
,
&
delay
,
fe
priv
->
min_delay
,
s
&
FE_HAS_LOCK
);
continue
;
}
/* don't do anything if we're in the DISEQC state, since this
* might be someone with a motorized dish controlled by DISEQC.
* If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
if
(
fe
->
state
&
FESTATE_DISEQC
)
{
update_delay
(
&
quality
,
&
delay
,
fe
->
min_delay
,
s
&
FE_HAS_LOCK
);
if
(
fe
priv
->
state
&
FESTATE_DISEQC
)
{
update_delay
(
&
quality
,
&
delay
,
fe
priv
->
min_delay
,
s
&
FE_HAS_LOCK
);
continue
;
}
/* if we're in the RETUNE state, set everything up for a brand
* new scan, keeping the current inversion setting, as the next
* tune is _very_ likely to require the same */
if
(
fe
->
state
&
FESTATE_RETUNE
)
{
fe
->
lnb_drift
=
0
;
fe
->
auto_step
=
0
;
fe
->
auto_sub_step
=
0
;
fe
->
started_auto_step
=
0
;
if
(
fe
priv
->
state
&
FESTATE_RETUNE
)
{
fe
priv
->
lnb_drift
=
0
;
fe
priv
->
auto_step
=
0
;
fe
priv
->
auto_sub_step
=
0
;
fe
priv
->
started_auto_step
=
0
;
check_wrapped
=
0
;
}
/* fast zigzag. */
if
((
fe
->
state
&
FESTATE_SEARCHING_FAST
)
||
(
fe
->
state
&
FESTATE_RETUNE
))
{
delay
=
fe
->
min_delay
;
if
((
fe
priv
->
state
&
FESTATE_SEARCHING_FAST
)
||
(
fepriv
->
state
&
FESTATE_RETUNE
))
{
delay
=
fe
priv
->
min_delay
;
/* peform a tune */
if
(
dvb_frontend_autotune
(
fe
,
check_wrapped
))
{
/* OK, if we've run out of trials at the fast speed.
* Drop back to slow for the _next_ attempt */
fe
->
state
=
FESTATE_SEARCHING_SLOW
;
fe
->
started_auto_step
=
fe
->
auto_step
;
fe
priv
->
state
=
FESTATE_SEARCHING_SLOW
;
fe
priv
->
started_auto_step
=
fepriv
->
auto_step
;
continue
;
}
check_wrapped
=
1
;
...
...
@@ -452,15 +487,14 @@ static int dvb_frontend_thread (void *data)
* This ensures we cannot return from an
* FE_SET_FRONTEND ioctl before the first frontend tune
* occurs */
if
(
fe
->
state
&
FESTATE_RETUNE
)
{
fe
->
state
=
FESTATE_TUNING_FAST
;
goto
retune
;
if
(
fepriv
->
state
&
FESTATE_RETUNE
)
{
fepriv
->
state
=
FESTATE_TUNING_FAST
;
}
}
/* slow zigzag */
if
(
fe
->
state
&
FESTATE_SEARCHING_SLOW
)
{
update_delay
(
&
quality
,
&
delay
,
fe
->
min_delay
,
s
&
FE_HAS_LOCK
);
if
(
fe
priv
->
state
&
FESTATE_SEARCHING_SLOW
)
{
update_delay
(
&
quality
,
&
delay
,
fe
priv
->
min_delay
,
s
&
FE_HAS_LOCK
);
/* Note: don't bother checking for wrapping; we stay in this
* state until we get a lock */
...
...
@@ -476,7 +510,7 @@ static int dvb_frontend_thread (void *data)
fe
->
ops
->
sleep
(
fe
);
}
fe
->
thread_pid
=
0
;
fe
priv
->
thread_pid
=
0
;
mb
();
dvb_frontend_wakeup
(
fe
);
...
...
@@ -486,21 +520,22 @@ static int dvb_frontend_thread (void *data)
static
void
dvb_frontend_stop
(
struct
dvb_frontend
*
fe
)
{
unsigned
long
ret
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
fe
->
exit
=
1
;
fepriv
->
exit
=
1
;
mb
();
if
(
!
fe
->
thread_pid
)
if
(
!
fe
priv
->
thread_pid
)
return
;
/* check if the thread is really alive */
if
(
kill_proc
(
fe
->
thread_pid
,
0
,
1
)
==
-
ESRCH
)
{
if
(
kill_proc
(
fe
priv
->
thread_pid
,
0
,
1
)
==
-
ESRCH
)
{
printk
(
"dvb_frontend_stop: thread PID %d already died
\n
"
,
fe
->
thread_pid
);
fe
priv
->
thread_pid
);
/* make sure the mutex was not held by the thread */
init_MUTEX
(
&
fe
->
sem
);
init_MUTEX
(
&
fe
priv
->
sem
);
return
;
}
...
...
@@ -508,27 +543,28 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
dvb_frontend_wakeup
(
fe
);
/* wait until the frontend thread has exited */
ret
=
wait_event_interruptible
(
fe
->
wait_queue
,
0
==
fe
->
thread_pid
);
ret
=
wait_event_interruptible
(
fe
priv
->
wait_queue
,
0
==
fepriv
->
thread_pid
);
if
(
-
ERESTARTSYS
!=
ret
)
{
fe
->
state
=
FESTATE_IDLE
;
fe
priv
->
state
=
FESTATE_IDLE
;
return
;
}
fe
->
state
=
FESTATE_IDLE
;
fe
priv
->
state
=
FESTATE_IDLE
;
/* paranoia check in case a signal arrived */
if
(
fe
->
thread_pid
)
if
(
fe
priv
->
thread_pid
)
printk
(
"dvb_frontend_stop: warning: thread PID %d won't exit
\n
"
,
fe
->
thread_pid
);
fe
priv
->
thread_pid
);
}
static
int
dvb_frontend_start
(
struct
dvb_frontend
*
fe
)
{
int
ret
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
if
(
fe
->
thread_pid
)
{
if
(
!
fe
->
exit
)
if
(
fe
priv
->
thread_pid
)
{
if
(
!
fe
priv
->
exit
)
return
0
;
else
dvb_frontend_stop
(
fe
);
...
...
@@ -536,21 +572,22 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
if
(
signal_pending
(
current
))
return
-
EINTR
;
if
(
down_interruptible
(
&
fe
->
sem
))
if
(
down_interruptible
(
&
fe
priv
->
sem
))
return
-
EINTR
;
fe
->
state
=
FESTATE_IDLE
;
fe
->
exit
=
0
;
fe
->
thread_pid
=
0
;
fe
priv
->
state
=
FESTATE_IDLE
;
fe
priv
->
exit
=
0
;
fe
priv
->
thread_pid
=
0
;
mb
();
ret
=
kernel_thread
(
dvb_frontend_thread
,
fe
,
0
);
if
(
ret
<
0
)
{
printk
(
"dvb_frontend_start: failed to start kernel_thread (%d)
\n
"
,
ret
);
up
(
&
fe
->
sem
);
up
(
&
fe
priv
->
sem
);
return
ret
;
}
fe
->
thread_pid
=
ret
;
fe
priv
->
thread_pid
=
ret
;
return
0
;
}
...
...
@@ -561,11 +598,12 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
{
struct
dvb_device
*
dvbdev
=
file
->
private_data
;
struct
dvb_frontend
*
fe
=
dvbdev
->
priv
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
int
err
=
-
EOPNOTSUPP
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
if
(
!
fe
||
fe
->
exit
)
if
(
!
fe
||
fe
priv
->
exit
)
return
-
ENODEV
;
if
((
file
->
f_flags
&
O_ACCMODE
)
==
O_RDONLY
&&
...
...
@@ -573,7 +611,7 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
cmd
==
FE_DISEQC_RECV_SLAVE_REPLY
))
return
-
EPERM
;
if
(
down_interruptible
(
&
fe
->
sem
))
if
(
down_interruptible
(
&
fe
priv
->
sem
))
return
-
ERESTARTSYS
;
switch
(
cmd
)
{
...
...
@@ -617,48 +655,48 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
case
FE_DISEQC_RESET_OVERLOAD
:
if
(
fe
->
ops
->
diseqc_reset_overload
)
{
err
=
fe
->
ops
->
diseqc_reset_overload
(
fe
);
fe
->
state
=
FESTATE_DISEQC
;
fe
->
status
=
0
;
fe
priv
->
state
=
FESTATE_DISEQC
;
fe
priv
->
status
=
0
;
}
break
;
case
FE_DISEQC_SEND_MASTER_CMD
:
if
(
fe
->
ops
->
diseqc_send_master_cmd
)
{
err
=
fe
->
ops
->
diseqc_send_master_cmd
(
fe
,
(
struct
dvb_diseqc_master_cmd
*
)
parg
);
fe
->
state
=
FESTATE_DISEQC
;
fe
->
status
=
0
;
fe
priv
->
state
=
FESTATE_DISEQC
;
fe
priv
->
status
=
0
;
}
break
;
case
FE_DISEQC_SEND_BURST
:
if
(
fe
->
ops
->
diseqc_send_burst
)
{
err
=
fe
->
ops
->
diseqc_send_burst
(
fe
,
(
fe_sec_mini_cmd_t
)
parg
);
fe
->
state
=
FESTATE_DISEQC
;
fe
->
status
=
0
;
fe
priv
->
state
=
FESTATE_DISEQC
;
fe
priv
->
status
=
0
;
}
break
;
case
FE_SET_TONE
:
if
(
fe
->
ops
->
set_tone
)
{
err
=
fe
->
ops
->
set_tone
(
fe
,
(
fe_sec_tone_mode_t
)
parg
);
fe
->
state
=
FESTATE_DISEQC
;
fe
->
status
=
0
;
fe
priv
->
state
=
FESTATE_DISEQC
;
fe
priv
->
status
=
0
;
}
break
;
case
FE_SET_VOLTAGE
:
if
(
fe
->
ops
->
set_voltage
)
{
err
=
fe
->
ops
->
set_voltage
(
fe
,
(
fe_sec_voltage_t
)
parg
);
fe
->
state
=
FESTATE_DISEQC
;
fe
->
status
=
0
;
fepriv
->
state
=
FESTATE_DISEQC
;
fe
priv
->
status
=
0
;
}
break
;
case
FE_DISHNETWORK_SEND_LEGACY_CMD
:
if
(
fe
->
ops
->
dishnetwork_send_legacy_command
)
{
err
=
fe
->
ops
->
dishnetwork_send_legacy_command
(
fe
,
(
unsigned
int
)
parg
);
fe
->
state
=
FESTATE_DISEQC
;
fe
->
status
=
0
;
fe
priv
->
state
=
FESTATE_DISEQC
;
fe
priv
->
status
=
0
;
}
break
;
...
...
@@ -668,14 +706,14 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
break
;
case
FE_ENABLE_HIGH_LNB_VOLTAGE
:
if
(
fe
->
ops
->
enable_high_lnb_voltage
)
;
if
(
fe
->
ops
->
enable_high_lnb_voltage
)
err
=
fe
->
ops
->
enable_high_lnb_voltage
(
fe
,
(
int
)
parg
);
break
;
case
FE_SET_FRONTEND
:
{
struct
dvb_frontend_tune_settings
fetunesettings
;
memcpy
(
&
fe
->
parameters
,
parg
,
memcpy
(
&
fe
priv
->
parameters
,
parg
,
sizeof
(
struct
dvb_frontend_parameters
));
memset
(
&
fetunesettings
,
0
,
sizeof
(
struct
dvb_frontend_tune_settings
));
...
...
@@ -684,41 +722,41 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
/* force auto frequency inversion if requested */
if
(
dvb_force_auto_inversion
)
{
fe
->
parameters
.
inversion
=
INVERSION_AUTO
;
fe
priv
->
parameters
.
inversion
=
INVERSION_AUTO
;
fetunesettings
.
parameters
.
inversion
=
INVERSION_AUTO
;
}
if
(
fe
->
ops
->
info
.
type
==
FE_OFDM
)
{
/* without hierachical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if
(
fe
->
parameters
.
u
.
ofdm
.
hierarchy_information
==
HIERARCHY_NONE
&&
fe
->
parameters
.
u
.
ofdm
.
code_rate_LP
==
FEC_NONE
)
fe
->
parameters
.
u
.
ofdm
.
code_rate_LP
=
FEC_AUTO
;
if
(
fe
priv
->
parameters
.
u
.
ofdm
.
hierarchy_information
==
HIERARCHY_NONE
&&
fe
priv
->
parameters
.
u
.
ofdm
.
code_rate_LP
==
FEC_NONE
)
fe
priv
->
parameters
.
u
.
ofdm
.
code_rate_LP
=
FEC_AUTO
;
}
/* get frontend-specific tuning settings */
if
(
fe
->
ops
->
get_tune_settings
&&
(
fe
->
ops
->
get_tune_settings
(
fe
,
&
fetunesettings
)
==
0
))
{
fe
->
min_delay
=
(
fetunesettings
.
min_delay_ms
*
HZ
)
/
1000
;
fe
->
max_drift
=
fetunesettings
.
max_drift
;
fe
->
step_size
=
fetunesettings
.
step_size
;
fe
priv
->
min_delay
=
(
fetunesettings
.
min_delay_ms
*
HZ
)
/
1000
;
fe
priv
->
max_drift
=
fetunesettings
.
max_drift
;
fe
priv
->
step_size
=
fetunesettings
.
step_size
;
}
else
{
/* default values */
switch
(
fe
->
ops
->
info
.
type
)
{
case
FE_QPSK
:
fe
->
min_delay
=
HZ
/
20
;
fe
->
step_size
=
fe
->
parameters
.
u
.
qpsk
.
symbol_rate
/
16000
;
fe
->
max_drift
=
fe
->
parameters
.
u
.
qpsk
.
symbol_rate
/
2000
;
fe
priv
->
min_delay
=
HZ
/
20
;
fe
priv
->
step_size
=
fepriv
->
parameters
.
u
.
qpsk
.
symbol_rate
/
16000
;
fe
priv
->
max_drift
=
fepriv
->
parameters
.
u
.
qpsk
.
symbol_rate
/
2000
;
break
;
case
FE_QAM
:
fe
->
min_delay
=
HZ
/
20
;
fe
->
step_size
=
0
;
/* no zigzag */
fe
->
max_drift
=
0
;
fe
priv
->
min_delay
=
HZ
/
20
;
fe
priv
->
step_size
=
0
;
/* no zigzag */
fe
priv
->
max_drift
=
0
;
break
;
case
FE_OFDM
:
fe
->
min_delay
=
HZ
/
20
;
fe
->
step_size
=
fe
->
ops
->
info
.
frequency_stepsize
*
2
;
fe
->
max_drift
=
(
fe
->
ops
->
info
.
frequency_stepsize
*
2
)
+
1
;
fe
priv
->
min_delay
=
HZ
/
20
;
fe
priv
->
step_size
=
fe
->
ops
->
info
.
frequency_stepsize
*
2
;
fe
priv
->
max_drift
=
(
fe
->
ops
->
info
.
frequency_stepsize
*
2
)
+
1
;
break
;
case
FE_ATSC
:
printk
(
"dvb-core: FE_ATSC not handled yet.
\n
"
);
...
...
@@ -726,12 +764,12 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
}
}
if
(
dvb_override_tune_delay
>
0
)
fe
->
min_delay
=
(
dvb_override_tune_delay
*
HZ
)
/
1000
;
fepriv
->
min_delay
=
(
dvb_override_tune_delay
*
HZ
)
/
1000
;
fe
->
state
=
FESTATE_RETUNE
;
fe
priv
->
state
=
FESTATE_RETUNE
;
dvb_frontend_wakeup
(
fe
);
dvb_frontend_add_event
(
fe
,
0
);
fe
->
status
=
0
;
fe
priv
->
status
=
0
;
err
=
0
;
break
;
}
...
...
@@ -742,13 +780,13 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
case
FE_GET_FRONTEND
:
if
(
fe
->
ops
->
get_frontend
)
{
memcpy
(
parg
,
&
fe
->
parameters
,
sizeof
(
struct
dvb_frontend_parameters
));
memcpy
(
parg
,
&
fe
priv
->
parameters
,
sizeof
(
struct
dvb_frontend_parameters
));
err
=
fe
->
ops
->
get_frontend
(
fe
,
(
struct
dvb_frontend_parameters
*
)
parg
);
}
break
;
};
up
(
&
fe
->
sem
);
up
(
&
fe
priv
->
sem
);
return
err
;
}
...
...
@@ -757,12 +795,13 @@ static unsigned int dvb_frontend_poll (struct file *file, struct poll_table_stru
{
struct
dvb_device
*
dvbdev
=
file
->
private_data
;
struct
dvb_frontend
*
fe
=
dvbdev
->
priv
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
poll_wait
(
file
,
&
fe
->
events
.
wait_queue
,
wait
);
poll_wait
(
file
,
&
fe
priv
->
events
.
wait_queue
,
wait
);
if
(
fe
->
events
.
eventw
!=
fe
->
events
.
eventr
)
if
(
fe
priv
->
events
.
eventw
!=
fepriv
->
events
.
eventr
)
return
(
POLLIN
|
POLLRDNORM
|
POLLPRI
);
return
0
;
...
...
@@ -773,6 +812,7 @@ static int dvb_frontend_open (struct inode *inode, struct file *file)
{
struct
dvb_device
*
dvbdev
=
file
->
private_data
;
struct
dvb_frontend
*
fe
=
dvbdev
->
priv
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
int
ret
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
...
...
@@ -786,7 +826,7 @@ static int dvb_frontend_open (struct inode *inode, struct file *file)
dvb_generic_release
(
inode
,
file
);
/* empty event queue */
fe
->
events
.
eventr
=
fe
->
events
.
eventw
=
0
;
fe
priv
->
events
.
eventr
=
fepriv
->
events
.
eventw
=
0
;
}
return
ret
;
...
...
@@ -797,11 +837,12 @@ static int dvb_frontend_release (struct inode *inode, struct file *file)
{
struct
dvb_device
*
dvbdev
=
file
->
private_data
;
struct
dvb_frontend
*
fe
=
dvbdev
->
priv
;
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
if
((
file
->
f_flags
&
O_ACCMODE
)
!=
O_RDONLY
)
fe
->
release_jiffies
=
jiffies
;
fe
priv
->
release_jiffies
=
jiffies
;
return
dvb_generic_release
(
inode
,
file
);
}
...
...
@@ -818,6 +859,7 @@ static struct file_operations dvb_frontend_fops = {
int
dvb_register_frontend
(
struct
dvb_adapter
*
dvb
,
struct
dvb_frontend
*
fe
)
{
struct
dvb_frontend_private
*
fepriv
;
static
const
struct
dvb_device
dvbdev_template
=
{
.
users
=
~
0
,
.
writers
=
1
,
...
...
@@ -831,20 +873,26 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
if
(
down_interruptible
(
&
frontend_mutex
))
return
-
ERESTARTSYS
;
init_MUTEX
(
&
fe
->
sem
);
init_waitqueue_head
(
&
fe
->
wait_queue
);
init_waitqueue_head
(
&
fe
->
events
.
wait_queue
);
init_MUTEX
(
&
fe
->
events
.
sem
);
fe
->
events
.
eventw
=
fe
->
events
.
eventr
=
0
;
fe
->
events
.
overflow
=
0
;
fe
->
frontend_priv
=
kmalloc
(
sizeof
(
struct
dvb_frontend_private
),
GFP_KERNEL
);
if
(
fe
->
frontend_priv
==
NULL
)
{
up
(
&
frontend_mutex
);
return
-
ENOMEM
;
}
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
memset
(
fe
->
frontend_priv
,
0
,
sizeof
(
struct
dvb_frontend_private
));
init_MUTEX
(
&
fepriv
->
sem
);
init_waitqueue_head
(
&
fepriv
->
wait_queue
);
init_waitqueue_head
(
&
fepriv
->
events
.
wait_queue
);
init_MUTEX
(
&
fepriv
->
events
.
sem
);
fe
->
dvb
=
dvb
;
fe
->
inversion
=
INVERSION_OFF
;
fe
priv
->
inversion
=
INVERSION_OFF
;
printk
(
"DVB: registering frontend %i (%s)...
\n
"
,
fe
->
dvb
->
num
,
fe
->
ops
->
info
.
name
);
dvb_register_device
(
fe
->
dvb
,
&
fe
->
dvbdev
,
&
dvbdev_template
,
dvb_register_device
(
fe
->
dvb
,
&
fe
priv
->
dvbdev
,
&
dvbdev_template
,
fe
,
DVB_DEVICE_FRONTEND
);
up
(
&
frontend_mutex
);
...
...
@@ -854,15 +902,18 @@ EXPORT_SYMBOL(dvb_register_frontend);
int
dvb_unregister_frontend
(
struct
dvb_frontend
*
fe
)
{
struct
dvb_frontend_private
*
fepriv
=
(
struct
dvb_frontend_private
*
)
fe
->
frontend_priv
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
down
(
&
frontend_mutex
);
dvb_unregister_device
(
fe
->
dvbdev
);
dvb_unregister_device
(
fepriv
->
dvbdev
);
dvb_frontend_stop
(
fe
);
if
(
fe
->
ops
->
release
)
fe
->
ops
->
release
(
fe
);
else
printk
(
"dvb_frontend: Demodulator (%s) does not have a release callback!
\n
"
,
fe
->
ops
->
info
.
name
);
if
(
fe
->
frontend_priv
)
kfree
(
fe
->
frontend_priv
);
up
(
&
frontend_mutex
);
return
0
;
}
...
...
drivers/media/dvb/dvb-core/dvb_frontend.h
View file @
ca583a3c
...
...
@@ -115,28 +115,7 @@ struct dvb_frontend {
struct
dvb_frontend_ops
*
ops
;
struct
dvb_adapter
*
dvb
;
void
*
demodulator_priv
;
struct
dvb_device
*
dvbdev
;
struct
dvb_frontend_parameters
parameters
;
struct
dvb_fe_events
events
;
struct
semaphore
sem
;
struct
list_head
list_head
;
wait_queue_head_t
wait_queue
;
pid_t
thread_pid
;
unsigned
long
release_jiffies
;
int
state
;
int
bending
;
int
lnb_drift
;
int
inversion
;
int
auto_step
;
int
auto_sub_step
;
int
started_auto_step
;
int
min_delay
;
int
max_drift
;
int
step_size
;
int
exit
;
int
wakeup
;
fe_status_t
status
;
void
*
frontend_priv
;
};
extern
int
dvb_register_frontend
(
struct
dvb_adapter
*
dvb
,
...
...
drivers/media/dvb/dvb-core/dvb_net.c
View file @
ca583a3c
...
...
@@ -123,7 +123,6 @@ static void hexdump( const unsigned char *buf, unsigned short len )
struct
dvb_net_priv
{
int
in_use
;
struct
net_device_stats
stats
;
char
name
[
6
];
u16
pid
;
struct
dvb_net
*
host
;
struct
dmx_demux
*
demux
;
...
...
@@ -1165,12 +1164,17 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
if
((
if_num
=
get_if
(
dvbnet
))
<
0
)
return
-
EINVAL
;
net
=
alloc_netdev
(
sizeof
(
struct
dvb_net_priv
),
"dvb"
,
dvb_net_setup
);
net
=
alloc_netdev
(
sizeof
(
struct
dvb_net_priv
),
"dvb"
,
dvb_net_setup
);
if
(
!
net
)
return
-
ENOMEM
;
sprintf
(
net
->
name
,
"dvb%d_%d"
,
dvbnet
->
dvbdev
->
adapter
->
num
,
if_num
);
if
(
dvbnet
->
dvbdev
->
id
)
snprintf
(
net
->
name
,
IFNAMSIZ
,
"dvb%d%u%d"
,
dvbnet
->
dvbdev
->
adapter
->
num
,
dvbnet
->
dvbdev
->
id
,
if_num
);
else
/* compatibility fix to keep dvb0_0 format */
snprintf
(
net
->
name
,
IFNAMSIZ
,
"dvb%d_%d"
,
dvbnet
->
dvbdev
->
adapter
->
num
,
if_num
);
net
->
addr_len
=
6
;
memcpy
(
net
->
dev_addr
,
dvbnet
->
dvbdev
->
adapter
->
proposed_mac
,
6
);
...
...
@@ -1196,6 +1200,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
free_netdev
(
net
);
return
result
;
}
printk
(
"dvb_net: created network interface %s
\n
"
,
net
->
name
);
return
if_num
;
}
...
...
@@ -1214,6 +1219,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num)
dvb_net_stop
(
net
);
flush_scheduled_work
();
printk
(
"dvb_net: removed network interface %s
\n
"
,
net
->
name
);
unregister_netdev
(
net
);
dvbnet
->
state
[
num
]
=
0
;
dvbnet
->
device
[
num
]
=
NULL
;
...
...
drivers/media/dvb/frontends/Kconfig
View file @
ca583a3c
...
...
@@ -46,6 +46,7 @@ comment "DVB-T (terrestrial) frontends"
config DVB_SP8870
tristate "Spase sp8870 based"
depends on DVB_CORE
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
...
...
@@ -56,6 +57,7 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
depends on DVB_CORE
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
...
...
@@ -84,6 +86,7 @@ config DVB_L64781
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
depends on DVB_CORE
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
...
...
@@ -145,4 +148,13 @@ config DVB_STV0297
help
A DVB-C tuner module. Say Y when you want to support this frontend.
comment "ATSC (North American/Korean Terresterial DTV) frontends"
depends on DVB_CORE
config DVB_NXT2002
tristate "Nxt2002 based"
depends on DVB_CORE
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
endmenu
drivers/media/dvb/frontends/Makefile
View file @
ca583a3c
...
...
@@ -24,3 +24,5 @@ obj-$(CONFIG_DVB_CX22702) += cx22702.o
obj-$(CONFIG_DVB_TDA80XX)
+=
tda80xx.o
obj-$(CONFIG_DVB_TDA10021)
+=
tda10021.o
obj-$(CONFIG_DVB_STV0297)
+=
stv0297.o
obj-$(CONFIG_DVB_NXT2002)
+=
nxt2002.o
drivers/media/dvb/frontends/dib3000-common.c
View file @
ca583a3c
...
...
@@ -2,7 +2,7 @@
#ifdef CONFIG_DVB_DIBCOM_DEBUG
static
int
debug
;
module_param
(
debug
,
int
,
0
x
644
);
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,2=i2c,4=srch (|-able))."
);
#endif
#define deb_info(args...) dprintk(0x01,args)
...
...
@@ -42,65 +42,6 @@ int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
return
i2c_transfer
(
state
->
i2c
,
msg
,
1
)
!=
1
?
-
EREMOTEIO
:
0
;
}
int
dib3000_init_pid_list
(
struct
dib3000_state
*
state
,
int
num
)
{
int
i
;
if
(
state
!=
NULL
)
{
state
->
pid_list
=
kmalloc
(
sizeof
(
struct
dib3000_pid
)
*
num
,
GFP_KERNEL
);
if
(
state
->
pid_list
==
NULL
)
return
-
ENOMEM
;
deb_info
(
"initializing %d pids for the pid_list.
\n
"
,
num
);
spin_lock_init
(
&
state
->
pid_list_lock
);
memset
(
state
->
pid_list
,
0
,
num
*
(
sizeof
(
struct
dib3000_pid
)));
for
(
i
=
0
;
i
<
num
;
i
++
)
{
state
->
pid_list
[
i
].
pid
=
0
;
state
->
pid_list
[
i
].
active
=
0
;
}
state
->
feedcount
=
0
;
}
else
return
-
EINVAL
;
return
0
;
}
void
dib3000_dealloc_pid_list
(
struct
dib3000_state
*
state
)
{
if
(
state
!=
NULL
&&
state
->
pid_list
!=
NULL
)
kfree
(
state
->
pid_list
);
}
/* fetch a pid from pid_list */
int
dib3000_get_pid_index
(
struct
dib3000_pid
pid_list
[],
int
num_pids
,
int
pid
,
spinlock_t
*
pid_list_lock
,
int
onoff
)
{
int
i
,
ret
=
-
1
;
unsigned
long
flags
;
spin_lock_irqsave
(
pid_list_lock
,
flags
);
for
(
i
=
0
;
i
<
num_pids
;
i
++
)
if
(
onoff
)
{
if
(
!
pid_list
[
i
].
active
)
{
pid_list
[
i
].
pid
=
pid
;
pid_list
[
i
].
active
=
1
;
ret
=
i
;
break
;
}
}
else
{
if
(
pid_list
[
i
].
active
&&
pid_list
[
i
].
pid
==
pid
)
{
pid_list
[
i
].
pid
=
0
;
pid_list
[
i
].
active
=
0
;
ret
=
i
;
break
;
}
}
deb_info
(
"setting pid: %5d %04x at index %d '%s'
\n
"
,
pid
,
pid
,
ret
,
onoff
?
"on"
:
"off"
);
spin_unlock_irqrestore
(
pid_list_lock
,
flags
);
return
ret
;
}
int
dib3000_search_status
(
u16
irq
,
u16
lock
)
{
if
(
irq
&
0x02
)
{
...
...
@@ -139,7 +80,4 @@ EXPORT_SYMBOL(dib3000_seq);
EXPORT_SYMBOL
(
dib3000_read_reg
);
EXPORT_SYMBOL
(
dib3000_write_reg
);
EXPORT_SYMBOL
(
dib3000_init_pid_list
);
EXPORT_SYMBOL
(
dib3000_dealloc_pid_list
);
EXPORT_SYMBOL
(
dib3000_get_pid_index
);
EXPORT_SYMBOL
(
dib3000_search_status
);
drivers/media/dvb/frontends/dib3000-common.h
View file @
ca583a3c
...
...
@@ -4,7 +4,7 @@
*
* DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
* Copyright (C) 2004
-5
Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DibCom, which has
*
...
...
@@ -29,19 +29,10 @@
#include "dvb_frontend.h"
#include "dib3000.h"
/* info and err, taken from usb.h, if there is anything available like by default,
* please change !
*/
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
/* a PID for the pid_filter list, when in use */
struct
dib3000_pid
{
u16
pid
;
int
active
;
};
/* info and err, taken from usb.h, if there is anything available like by default. */
#define err(format, arg...) printk(KERN_ERR "dib3000mX: " format "\n" , ## arg)
#define info(format, arg...) printk(KERN_INFO "dib3000mX: " format "\n" , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "dib3000mX: " format "\n" , ## arg)
/* frontend state */
struct
dib3000_state
{
...
...
@@ -52,25 +43,18 @@ struct dib3000_state {
/* configuration settings */
struct
dib3000_config
config
;
spinlock_t
pid_list_lock
;
struct
dib3000_pid
*
pid_list
;
int
feedcount
;
struct
dvb_frontend
frontend
;
int
timing_offset
;
int
timing_offset_comp_done
;
fe_bandwidth_t
last_tuned_bw
;
u32
last_tuned_freq
;
};
/* commonly used methods by the dib3000mb/mc/p frontend */
extern
int
dib3000_read_reg
(
struct
dib3000_state
*
state
,
u16
reg
);
extern
int
dib3000_write_reg
(
struct
dib3000_state
*
state
,
u16
reg
,
u16
val
);
extern
int
dib3000_init_pid_list
(
struct
dib3000_state
*
state
,
int
num
);
extern
void
dib3000_dealloc_pid_list
(
struct
dib3000_state
*
state
);
extern
int
dib3000_get_pid_index
(
struct
dib3000_pid
pid_list
[],
int
num_pids
,
int
pid
,
spinlock_t
*
pid_list_lock
,
int
onoff
);
extern
int
dib3000_search_status
(
u16
irq
,
u16
lock
);
/* handy shortcuts */
...
...
@@ -81,7 +65,7 @@ extern int dib3000_search_status(u16 irq,u16 lock);
#define wr_foreach(a,v) { int i; \
if (sizeof(a) != sizeof(v)) \
err("sizeof: %
zd %z
d is different",sizeof(a),sizeof(v));\
err("sizeof: %
d %
d is different",sizeof(a),sizeof(v));\
for (i=0; i < sizeof(a)/sizeof(u16); i++) \
wr(a[i],v[i]); \
}
...
...
@@ -136,8 +120,8 @@ extern int dib3000_search_status(u16 irq,u16 lock);
#define DIB3000_DDS_INVERSION_OFF ( 0)
#define DIB3000_DDS_INVERSION_ON ( 1)
#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a <<
7
))
#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a <<
7
) | (1 << 7)))
#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a <<
8
))
#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a <<
8
) | (1 << 7)))
/* for auto search */
extern
u16
dib3000_seq
[
2
][
2
][
2
];
...
...
drivers/media/dvb/frontends/dib3000.h
View file @
ca583a3c
...
...
@@ -2,7 +2,7 @@
* public header file of the frontend drivers for mobile DVB-T demodulators
* DiBcom 3000-MB and DiBcom 3000-MC/P (http://www.dibcom.fr/)
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
* Copyright (C) 2004
-5
Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DibCom, which has
*
...
...
@@ -31,25 +31,24 @@ struct dib3000_config
/* the demodulator's i2c address */
u8
demod_address
;
/* The i2c address of the PLL */
u8
pll_addr
;
/* PLL maintenance */
int
(
*
pll_init
)(
struct
dvb_frontend
*
fe
);
int
(
*
pll_set
)(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
);
/* PLL maintenance and the i2c address of the PLL */
u8
(
*
pll_addr
)(
struct
dvb_frontend
*
fe
);
int
(
*
pll_init
)(
struct
dvb_frontend
*
fe
,
u8
pll_buf
[
5
]);
int
(
*
pll_set
)(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
,
u8
pll_buf
[
5
]);
};
struct
dib
3000
_xfer_ops
struct
dib
_fe
_xfer_ops
{
/* pid and transfer handling is done in the demodulator */
int
(
*
pid_parse
)(
struct
dvb_frontend
*
fe
,
int
onoff
);
int
(
*
fifo_ctrl
)(
struct
dvb_frontend
*
fe
,
int
onoff
);
int
(
*
pid_ctrl
)(
struct
dvb_frontend
*
fe
,
int
pid
,
int
onoff
);
int
(
*
pid_ctrl
)(
struct
dvb_frontend
*
fe
,
int
index
,
int
pid
,
int
onoff
);
int
(
*
tuner_pass_ctrl
)(
struct
dvb_frontend
*
fe
,
int
onoff
,
u8
pll_ctrl
);
};
extern
struct
dvb_frontend
*
dib3000mb_attach
(
const
struct
dib3000_config
*
config
,
struct
i2c_adapter
*
i2c
,
struct
dib
3000
_xfer_ops
*
xfer_ops
);
struct
i2c_adapter
*
i2c
,
struct
dib
_fe
_xfer_ops
*
xfer_ops
);
extern
struct
dvb_frontend
*
dib3000mc_attach
(
const
struct
dib3000_config
*
config
,
struct
i2c_adapter
*
i2c
,
struct
dib
3000
_xfer_ops
*
xfer_ops
);
struct
i2c_adapter
*
i2c
,
struct
dib
_fe
_xfer_ops
*
xfer_ops
);
#endif // DIB3000_H
drivers/media/dvb/frontends/dib3000mb.c
View file @
ca583a3c
...
...
@@ -2,7 +2,7 @@
* Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
* DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
* Copyright (C) 2004
-5
Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DibCom, which has
*
...
...
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "dib3000-common.h"
#include "dib3000mb_priv.h"
#include "dib3000.h"
...
...
@@ -41,7 +40,7 @@
#ifdef CONFIG_DVB_DIBCOM_DEBUG
static
int
debug
;
module_param
(
debug
,
int
,
0
x
644
);
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."
);
#endif
#define deb_info(args...) dprintk(0x01,args)
...
...
@@ -49,6 +48,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
static
int
dib3000mb_tuner_pass_ctrl
(
struct
dvb_frontend
*
fe
,
int
onoff
,
u8
pll_addr
);
static
int
dib3000mb_get_frontend
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
fep
);
...
...
@@ -61,11 +62,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
int
search_state
,
seq
;
if
(
tuner
)
{
wr
(
DIB3000MB_REG_TUNER
,
DIB3000_TUNER_WRITE_ENABLE
(
state
->
config
.
pll_addr
));
state
->
config
.
pll_set
(
fe
,
fep
);
wr
(
DIB3000MB_REG_TUNER
,
DIB3000_TUNER_WRITE_DISABLE
(
state
->
config
.
pll_addr
));
dib3000mb_tuner_pass_ctrl
(
fe
,
1
,
state
->
config
.
pll_addr
(
fe
));
state
->
config
.
pll_set
(
fe
,
fep
,
NULL
);
dib3000mb_tuner_pass_ctrl
(
fe
,
0
,
state
->
config
.
pll_addr
(
fe
));
deb_setf
(
"bandwidth: "
);
switch
(
ofdm
->
bandwidth
)
{
...
...
@@ -390,11 +389,9 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr
(
DIB3000MB_REG_DATA_IN_DIVERSITY
,
DIB3000MB_DATA_DIVERSITY_IN_OFF
);
if
(
state
->
config
.
pll_init
)
{
wr
(
DIB3000MB_REG_TUNER
,
DIB3000_TUNER_WRITE_ENABLE
(
state
->
config
.
pll_addr
));
state
->
config
.
pll_init
(
fe
);
wr
(
DIB3000MB_REG_TUNER
,
DIB3000_TUNER_WRITE_DISABLE
(
state
->
config
.
pll_addr
));
dib3000mb_tuner_pass_ctrl
(
fe
,
1
,
state
->
config
.
pll_addr
(
fe
));
state
->
config
.
pll_init
(
fe
,
NULL
);
dib3000mb_tuner_pass_ctrl
(
fe
,
0
,
state
->
config
.
pll_addr
(
fe
));
}
return
0
;
...
...
@@ -414,6 +411,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
return
0
;
dds_val
=
((
rd
(
DIB3000MB_REG_DDS_VALUE_MSB
)
&
0xff
)
<<
16
)
+
rd
(
DIB3000MB_REG_DDS_VALUE_LSB
);
deb_getf
(
"DDS_VAL: %x %x %x"
,
dds_val
,
rd
(
DIB3000MB_REG_DDS_VALUE_MSB
),
rd
(
DIB3000MB_REG_DDS_VALUE_LSB
));
if
(
dds_val
<
threshold
)
inv_test1
=
0
;
else
if
(
dds_val
==
threshold
)
...
...
@@ -422,6 +420,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
inv_test1
=
2
;
dds_val
=
((
rd
(
DIB3000MB_REG_DDS_FREQ_MSB
)
&
0xff
)
<<
16
)
+
rd
(
DIB3000MB_REG_DDS_FREQ_LSB
);
deb_getf
(
"DDS_FREQ: %x %x %x"
,
dds_val
,
rd
(
DIB3000MB_REG_DDS_FREQ_MSB
),
rd
(
DIB3000MB_REG_DDS_FREQ_LSB
));
if
(
dds_val
<
threshold
)
inv_test2
=
0
;
else
if
(
dds_val
==
threshold
)
...
...
@@ -714,18 +713,11 @@ static void dib3000mb_release(struct dvb_frontend* fe)
}
/* pid filter and transfer stuff */
static
int
dib3000mb_pid_control
(
struct
dvb_frontend
*
fe
,
int
pid
,
int
onoff
)
static
int
dib3000mb_pid_control
(
struct
dvb_frontend
*
fe
,
int
index
,
int
pid
,
int
onoff
)
{
struct
dib3000_state
*
state
=
fe
->
demodulator_priv
;
int
index
=
dib3000_get_pid_index
(
state
->
pid_list
,
DIB3000MB_NUM_PIDS
,
pid
,
&
state
->
pid_list_lock
,
onoff
);
pid
=
(
onoff
?
pid
|
DIB3000_ACTIVATE_PID_FILTERING
:
0
);
if
(
index
>=
0
)
{
wr
(
index
+
DIB3000MB_REG_FIRST_PID
,
pid
);
}
else
{
err
(
"no more pids for filtering."
);
return
-
ENOMEM
;
}
return
0
;
}
...
...
@@ -749,10 +741,21 @@ static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
return
0
;
}
static
int
dib3000mb_tuner_pass_ctrl
(
struct
dvb_frontend
*
fe
,
int
onoff
,
u8
pll_addr
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
if
(
onoff
)
{
wr
(
DIB3000MB_REG_TUNER
,
DIB3000_TUNER_WRITE_ENABLE
(
pll_addr
));
}
else
{
wr
(
DIB3000MB_REG_TUNER
,
DIB3000_TUNER_WRITE_DISABLE
(
pll_addr
));
}
return
0
;
}
static
struct
dvb_frontend_ops
dib3000mb_ops
;
struct
dvb_frontend
*
dib3000mb_attach
(
const
struct
dib3000_config
*
config
,
struct
i2c_adapter
*
i2c
,
struct
dib
3000
_xfer_ops
*
xfer_ops
)
struct
i2c_adapter
*
i2c
,
struct
dib
_fe
_xfer_ops
*
xfer_ops
)
{
struct
dib3000_state
*
state
=
NULL
;
...
...
@@ -773,9 +776,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
if
(
rd
(
DIB3000_REG_DEVICE_ID
)
!=
DIB3000MB_DEVICE_ID
)
goto
error
;
if
(
dib3000_init_pid_list
(
state
,
DIB3000MB_NUM_PIDS
))
goto
error
;
/* create dvb_frontend */
state
->
frontend
.
ops
=
&
state
->
ops
;
state
->
frontend
.
demodulator_priv
=
state
;
...
...
@@ -784,6 +784,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
xfer_ops
->
pid_parse
=
dib3000mb_pid_parse
;
xfer_ops
->
fifo_ctrl
=
dib3000mb_fifo_control
;
xfer_ops
->
pid_ctrl
=
dib3000mb_pid_control
;
xfer_ops
->
tuner_pass_ctrl
=
dib3000mb_tuner_pass_ctrl
;
return
&
state
->
frontend
;
...
...
@@ -807,6 +808,7 @@ static struct dvb_frontend_ops dib3000mb_ops = {
FE_CAN_QPSK
|
FE_CAN_QAM_16
|
FE_CAN_QAM_64
|
FE_CAN_QAM_AUTO
|
FE_CAN_TRANSMISSION_MODE_AUTO
|
FE_CAN_GUARD_INTERVAL_AUTO
|
FE_CAN_RECOVER
|
FE_CAN_HIERARCHY_AUTO
,
},
...
...
drivers/media/dvb/frontends/dib3000mc.c
View file @
ca583a3c
...
...
@@ -2,9 +2,9 @@
* Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P
* DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
* Copyright (C) 2004
-5
Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from Di
b
Com, which has
* based on GPL code from Di
B
Com, which has
*
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
*
...
...
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "dib3000-common.h"
#include "dib3000mc_priv.h"
#include "dib3000.h"
...
...
@@ -40,14 +39,16 @@
#ifdef CONFIG_DVB_DIBCOM_DEBUG
static
int
debug
;
module_param
(
debug
,
int
,
0
x
644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."
);
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"set debugging level (1=info,2=xfer,4=setfe,8=getfe
,16=stat
(|-able))."
);
#endif
#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
#define deb_stat(args...) dprintk(0x10,args)
static
int
dib3000mc_tuner_pass_ctrl
(
struct
dvb_frontend
*
fe
,
int
onoff
,
u8
pll_addr
);
static
int
dib3000mc_set_impulse_noise
(
struct
dib3000_state
*
state
,
int
mode
,
fe_transmit_mode_t
transmission_mode
,
fe_bandwidth_t
bandwidth
)
...
...
@@ -185,46 +186,33 @@ static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t
return
0
;
}
static
int
dib3000mc_get_frontend
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
fep
);
static
int
dib3000mc_set_adp_cfg
(
struct
dib3000_state
*
state
,
fe_modulation_t
con
)
{
switch
(
con
)
{
case
QAM_64
:
wr_foreach
(
dib3000mc_reg_adp_cfg
,
dib3000mc_adp_cfg
[
2
]);
break
;
case
QAM_16
:
wr_foreach
(
dib3000mc_reg_adp_cfg
,
dib3000mc_adp_cfg
[
1
]);
break
;
case
QPSK
:
wr_foreach
(
dib3000mc_reg_adp_cfg
,
dib3000mc_adp_cfg
[
0
]);
break
;
case
QAM_AUTO
:
break
;
default:
warn
(
"unkown constellation."
);
break
;
}
return
0
;
}
static
int
dib3000mc_set_frontend
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
fep
,
int
tuner
)
static
int
dib3000mc_set_general_cfg
(
struct
dib3000_state
*
state
,
struct
dvb_frontend_parameters
*
fep
,
int
*
auto_val
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
struct
dvb_ofdm_parameters
*
ofdm
=
&
fep
->
u
.
ofdm
;
fe_code_rate_t
fe_cr
=
FEC_NONE
;
int
search_state
,
seq
;
u16
val
;
u8
fft
=
0
,
guard
=
0
,
qam
=
0
,
alpha
=
0
,
sel_hp
=
0
,
cr
=
0
,
hrch
=
0
;
if
(
tuner
)
{
wr
(
DIB3000MC_REG_TUNER
,
DIB3000_TUNER_WRITE_ENABLE
(
state
->
config
.
pll_addr
));
state
->
config
.
pll_set
(
fe
,
fep
);
wr
(
DIB3000MC_REG_TUNER
,
DIB3000_TUNER_WRITE_DISABLE
(
state
->
config
.
pll_addr
));
}
dib3000mc_set_timing
(
state
,
0
,
ofdm
->
transmission_mode
,
ofdm
->
bandwidth
);
dib3000mc_init_auto_scan
(
state
,
ofdm
->
bandwidth
,
0
);
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_AGC
);
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_OFF
);
/* Default cfg isi offset adp */
wr_foreach
(
dib3000mc_reg_offset
,
dib3000mc_offset
[
0
]);
wr
(
DIB3000MC_REG_ISI
,
DIB3000MC_ISI_DEFAULT
|
DIB3000MC_ISI_INHIBIT
);
wr_foreach
(
dib3000mc_reg_adp_cfg
,
dib3000mc_adp_cfg
[
1
]);
wr
(
DIB3000MC_REG_UNK_133
,
DIB3000MC_UNK_133
);
wr_foreach
(
dib3000mc_reg_bandwidth_general
,
dib3000mc_bandwidth_general
);
if
(
ofdm
->
bandwidth
==
BANDWIDTH_8_MHZ
)
{
wr_foreach
(
dib3000mc_reg_bw
,
dib3000mc_bw
[
3
]);
}
else
{
wr_foreach
(
dib3000mc_reg_bw
,
dib3000mc_bw
[
0
]);
}
int
seq
;
switch
(
ofdm
->
transmission_mode
)
{
case
TRANSMISSION_MODE_2K
:
fft
=
DIB3000_TRANSMISSION_MODE_2K
;
break
;
...
...
@@ -282,8 +270,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
case
INVERSION_OFF
:
wr
(
DIB3000MC_REG_SET_DDS_FREQ_MSB
,
DIB3000MC_DDS_FREQ_MSB_INV_OFF
);
break
;
case
INVERSION_AUTO
:
break
;
case
INVERSION_AUTO
:
/* fall through */
case
INVERSION_ON
:
wr
(
DIB3000MC_REG_SET_DDS_FREQ_MSB
,
DIB3000MC_DDS_FREQ_MSB_INV_ON
);
break
;
...
...
@@ -298,168 +285,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
deb_setf
(
"seq? %d
\n
"
,
seq
);
wr
(
DIB3000MC_REG_SEQ_TPS
,
DIB3000MC_SEQ_TPS
(
seq
,
1
));
dib3000mc_set_impulse_noise
(
state
,
0
,
ofdm
->
constellation
,
ofdm
->
bandwidth
);
val
=
rd
(
DIB3000MC_REG_DEMOD_PARM
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
|
DIB3000MC_DEMOD_RST_DEMOD_ON
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
);
msleep
(
70
);
wr_foreach
(
dib3000mc_reg_agc_bandwidth
,
dib3000mc_agc_bandwidth
);
/* something has to be auto searched */
if
(
ofdm
->
constellation
==
QAM_AUTO
||
*
auto_val
=
ofdm
->
constellation
==
QAM_AUTO
||
ofdm
->
hierarchy_information
==
HIERARCHY_AUTO
||
ofdm
->
guard_interval
==
GUARD_INTERVAL_AUTO
||
ofdm
->
transmission_mode
==
TRANSMISSION_MODE_AUTO
||
fe_cr
==
FEC_AUTO
||
fep
->
inversion
==
INVERSION_AUTO
)
{
int
as_count
=
0
;
deb_setf
(
"autosearch enabled.
\n
"
);
val
=
rd
(
DIB3000MC_REG_DEMOD_PARM
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
|
DIB3000MC_DEMOD_RST_AUTO_SRCH_ON
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
);
while
((
search_state
=
dib3000_search_status
(
rd
(
DIB3000MC_REG_AS_IRQ
),
1
))
<
0
&&
as_count
++
<
100
)
msleep
(
10
);
deb_info
(
"search_state after autosearch %d after %d checks
\n
"
,
search_state
,
as_count
);
if
(
search_state
==
1
)
{
struct
dvb_frontend_parameters
feps
;
feps
.
u
.
ofdm
.
bandwidth
=
ofdm
->
bandwidth
;
/* bw is not auto searched */
;
if
(
dib3000mc_get_frontend
(
fe
,
&
feps
)
==
0
)
{
deb_setf
(
"reading tuning data from frontend succeeded.
\n
"
);
return
dib3000mc_set_frontend
(
fe
,
&
feps
,
0
);
}
}
}
else
{
wr
(
DIB3000MC_REG_ISI
,
DIB3000MC_ISI_DEFAULT
|
DIB3000MC_ISI_ACTIVATE
);
wr_foreach
(
dib3000mc_reg_adp_cfg
,
dib3000mc_adp_cfg
[
qam
]);
/* set_offset_cfg */
wr_foreach
(
dib3000mc_reg_offset
,
dib3000mc_offset
[(
ofdm
->
transmission_mode
==
TRANSMISSION_MODE_8K
)
+
1
]);
// dib3000mc_set_timing(1,ofdm->transmission_mode,ofdm->bandwidth);
// wr(DIB3000MC_REG_LOCK_MASK,DIB3000MC_ACTIVATE_LOCK_MASK); /* activates some locks if needed */
/* set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF);
wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_ON);
wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_OFF);*/
}
return
0
;
}
static
int
dib3000mc_fe_init
(
struct
dvb_frontend
*
fe
,
int
mobile_mode
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
state
->
timing_offset
=
0
;
state
->
timing_offset_comp_done
=
0
;
wr
(
DIB3000MC_REG_ELEC_OUT
,
DIB3000MC_ELEC_OUT_DIV_OUT_ON
);
wr
(
DIB3000MC_REG_OUTMODE
,
DIB3000MC_OM_PAR_CONT_CLK
);
wr
(
DIB3000MC_REG_RST_I2C_ADDR
,
DIB3000MC_DEMOD_ADDR
(
state
->
config
.
demod_address
)
|
DIB3000MC_DEMOD_ADDR_ON
);
wr
(
DIB3000MC_REG_RST_I2C_ADDR
,
DIB3000MC_DEMOD_ADDR
(
state
->
config
.
demod_address
));
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_CONFIG
);
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_OFF
);
wr
(
DIB3000MC_REG_CLK_CFG_1
,
DIB3000MC_CLK_CFG_1_POWER_UP
);
wr
(
DIB3000MC_REG_CLK_CFG_2
,
DIB3000MC_CLK_CFG_2_PUP_MOBILE
);
wr
(
DIB3000MC_REG_CLK_CFG_3
,
DIB3000MC_CLK_CFG_3_POWER_UP
);
wr
(
DIB3000MC_REG_CLK_CFG_7
,
DIB3000MC_CLK_CFG_7_INIT
);
wr
(
DIB3000MC_REG_RST_UNC
,
DIB3000MC_RST_UNC_OFF
);
wr
(
DIB3000MC_REG_UNK_19
,
DIB3000MC_UNK_19
);
wr
(
33
,
5
);
wr
(
36
,
81
);
wr
(
DIB3000MC_REG_UNK_88
,
DIB3000MC_UNK_88
);
wr
(
DIB3000MC_REG_UNK_99
,
DIB3000MC_UNK_99
);
wr
(
DIB3000MC_REG_UNK_111
,
DIB3000MC_UNK_111_PH_N_MODE_0
);
/* phase noise algo off */
/* mobile mode - portable reception */
wr_foreach
(
dib3000mc_reg_mobile_mode
,
dib3000mc_mobile_mode
[
1
]);
/* TUNER_PANASONIC_ENV57H12D5: */
wr_foreach
(
dib3000mc_reg_agc_bandwidth
,
dib3000mc_agc_bandwidth
);
wr_foreach
(
dib3000mc_reg_agc_bandwidth_general
,
dib3000mc_agc_bandwidth_general
);
wr_foreach
(
dib3000mc_reg_agc
,
dib3000mc_agc_tuner
[
1
]);
wr
(
DIB3000MC_REG_UNK_110
,
DIB3000MC_UNK_110
);
wr
(
26
,
0x6680
);
wr
(
DIB3000MC_REG_UNK_1
,
DIB3000MC_UNK_1
);
wr
(
DIB3000MC_REG_UNK_2
,
DIB3000MC_UNK_2
);
wr
(
DIB3000MC_REG_UNK_3
,
DIB3000MC_UNK_3
);
wr
(
DIB3000MC_REG_SEQ_TPS
,
DIB3000MC_SEQ_TPS_DEFAULT
);
wr_foreach
(
dib3000mc_reg_bandwidth_general
,
dib3000mc_bandwidth_general
);
wr_foreach
(
dib3000mc_reg_bandwidth
,
dib3000mc_bandwidth_8mhz
);
wr
(
DIB3000MC_REG_UNK_4
,
DIB3000MC_UNK_4
);
wr
(
DIB3000MC_REG_SET_DDS_FREQ_MSB
,
DIB3000MC_DDS_FREQ_MSB_INV_OFF
);
wr
(
DIB3000MC_REG_SET_DDS_FREQ_LSB
,
DIB3000MC_DDS_FREQ_LSB
);
dib3000mc_set_timing
(
state
,
0
,
TRANSMISSION_MODE_2K
,
BANDWIDTH_8_MHZ
);
// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
wr
(
DIB3000MC_REG_UNK_120
,
DIB3000MC_UNK_120
);
wr
(
DIB3000MC_REG_UNK_134
,
DIB3000MC_UNK_134
);
wr
(
DIB3000MC_REG_FEC_CFG
,
DIB3000MC_FEC_CFG
);
dib3000mc_set_impulse_noise
(
state
,
0
,
TRANSMISSION_MODE_8K
,
BANDWIDTH_8_MHZ
);
/* output mode control, just the MPEG2_SLAVE */
set_or
(
DIB3000MC_REG_OUTMODE
,
DIB3000MC_OM_SLAVE
);
wr
(
DIB3000MC_REG_SMO_MODE
,
DIB3000MC_SMO_MODE_SLAVE
);
wr
(
DIB3000MC_REG_FIFO_THRESHOLD
,
DIB3000MC_FIFO_THRESHOLD_SLAVE
);
wr
(
DIB3000MC_REG_ELEC_OUT
,
DIB3000MC_ELEC_OUT_SLAVE
);
/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
wr(DIB3000MC_REG_OUTMODE,
DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
rd(DIB3000MC_REG_OUTMODE)));
wr(DIB3000MC_REG_SMO_MODE,
DIB3000MC_SMO_MODE_DEFAULT |
DIB3000MC_SMO_MODE_188);
wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
*/
/* diversity */
wr
(
DIB3000MC_REG_DIVERSITY1
,
DIB3000MC_DIVERSITY1_DEFAULT
);
wr
(
DIB3000MC_REG_DIVERSITY2
,
DIB3000MC_DIVERSITY2_DEFAULT
);
wr
(
DIB3000MC_REG_DIVERSITY3
,
DIB3000MC_DIVERSITY3_IN_OFF
);
set_or
(
DIB3000MC_REG_CLK_CFG_7
,
DIB3000MC_CLK_CFG_7_DIV_IN_OFF
);
/* if (state->config->pll_init) {
wr(DIB3000MC_REG_TUNER,
DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
state->config->pll_init(fe);
wr(DIB3000MC_REG_TUNER,
DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr));
}*/
fep
->
inversion
==
INVERSION_AUTO
;
return
0
;
}
...
...
@@ -476,7 +307,8 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe,
if
(
!
(
rd
(
DIB3000MC_REG_LOCK_507
)
&
DIB3000MC_LOCK_507
))
return
0
;
dds_val
=
((
rd
(
DIB3000MC_REG_DDS_FREQ_MSB
)
&
0xff
)
<<
16
)
+
rd
(
DIB3000MC_REG_DDS_FREQ_LSB
);
dds_val
=
(
rd
(
DIB3000MC_REG_DDS_FREQ_MSB
)
<<
16
)
+
rd
(
DIB3000MC_REG_DDS_FREQ_LSB
);
deb_getf
(
"DDS_FREQ: %6x
\n
"
,
dds_val
);
if
(
dds_val
<
threshold
)
inv_test1
=
0
;
else
if
(
dds_val
==
threshold
)
...
...
@@ -484,7 +316,8 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe,
else
inv_test1
=
2
;
dds_val
=
((
rd
(
DIB3000MC_REG_SET_DDS_FREQ_MSB
)
&
0xff
)
<<
16
)
+
rd
(
DIB3000MC_REG_SET_DDS_FREQ_LSB
);
dds_val
=
(
rd
(
DIB3000MC_REG_SET_DDS_FREQ_MSB
)
<<
16
)
+
rd
(
DIB3000MC_REG_SET_DDS_FREQ_LSB
);
deb_getf
(
"DDS_SET_FREQ: %6x
\n
"
,
dds_val
);
if
(
dds_val
<
threshold
)
inv_test2
=
0
;
else
if
(
dds_val
==
threshold
)
...
...
@@ -499,6 +332,9 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe,
deb_getf
(
"inversion %d %d, %d
\n
"
,
inv_test2
,
inv_test1
,
fep
->
inversion
);
fep
->
frequency
=
state
->
last_tuned_freq
;
fep
->
u
.
ofdm
.
bandwidth
=
state
->
last_tuned_bw
;
tps_val
=
rd
(
DIB3000MC_REG_TUNING_PARM
);
switch
(
DIB3000MC_TP_QAM
(
tps_val
))
{
...
...
@@ -614,9 +450,211 @@ static int dib3000mc_get_frontend(struct dvb_frontend* fe,
err
(
"unexpected transmission mode return by TPS (%d)"
,
tps_val
);
break
;
}
deb_getf
(
"
\n
"
);
return
0
;
}
static
int
dib3000mc_set_frontend
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
fep
,
int
tuner
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
struct
dvb_ofdm_parameters
*
ofdm
=
&
fep
->
u
.
ofdm
;
int
search_state
,
auto_val
;
u16
val
;
if
(
tuner
)
{
/* initial call from dvb */
dib3000mc_tuner_pass_ctrl
(
fe
,
1
,
state
->
config
.
pll_addr
(
fe
));
state
->
config
.
pll_set
(
fe
,
fep
,
NULL
);
dib3000mc_tuner_pass_ctrl
(
fe
,
0
,
state
->
config
.
pll_addr
(
fe
));
state
->
last_tuned_freq
=
fep
->
frequency
;
// if (!scanboost) {
dib3000mc_set_timing
(
state
,
0
,
ofdm
->
transmission_mode
,
ofdm
->
bandwidth
);
dib3000mc_init_auto_scan
(
state
,
ofdm
->
bandwidth
,
0
);
state
->
last_tuned_bw
=
ofdm
->
bandwidth
;
wr_foreach
(
dib3000mc_reg_agc_bandwidth
,
dib3000mc_agc_bandwidth
);
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_AGC
);
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_OFF
);
/* Default cfg isi offset adp */
wr_foreach
(
dib3000mc_reg_offset
,
dib3000mc_offset
[
0
]);
wr
(
DIB3000MC_REG_ISI
,
DIB3000MC_ISI_DEFAULT
|
DIB3000MC_ISI_INHIBIT
);
dib3000mc_set_adp_cfg
(
state
,
ofdm
->
constellation
);
wr
(
DIB3000MC_REG_UNK_133
,
DIB3000MC_UNK_133
);
wr_foreach
(
dib3000mc_reg_bandwidth_general
,
dib3000mc_bandwidth_general
);
/* power smoothing */
if
(
ofdm
->
bandwidth
!=
BANDWIDTH_8_MHZ
)
{
wr_foreach
(
dib3000mc_reg_bw
,
dib3000mc_bw
[
0
]);
}
else
{
wr_foreach
(
dib3000mc_reg_bw
,
dib3000mc_bw
[
3
]);
}
auto_val
=
0
;
dib3000mc_set_general_cfg
(
state
,
fep
,
&
auto_val
);
dib3000mc_set_impulse_noise
(
state
,
0
,
ofdm
->
constellation
,
ofdm
->
bandwidth
);
val
=
rd
(
DIB3000MC_REG_DEMOD_PARM
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
|
DIB3000MC_DEMOD_RST_DEMOD_ON
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
);
// }
msleep
(
70
);
/* something has to be auto searched */
if
(
auto_val
)
{
int
as_count
=
0
;
deb_setf
(
"autosearch enabled.
\n
"
);
val
=
rd
(
DIB3000MC_REG_DEMOD_PARM
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
|
DIB3000MC_DEMOD_RST_AUTO_SRCH_ON
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
);
while
((
search_state
=
dib3000_search_status
(
rd
(
DIB3000MC_REG_AS_IRQ
),
1
))
<
0
&&
as_count
++
<
100
)
msleep
(
10
);
deb_info
(
"search_state after autosearch %d after %d checks
\n
"
,
search_state
,
as_count
);
if
(
search_state
==
1
)
{
struct
dvb_frontend_parameters
feps
;
if
(
dib3000mc_get_frontend
(
fe
,
&
feps
)
==
0
)
{
deb_setf
(
"reading tuning data from frontend succeeded.
\n
"
);
return
dib3000mc_set_frontend
(
fe
,
&
feps
,
0
);
}
}
}
else
{
dib3000mc_set_impulse_noise
(
state
,
0
,
ofdm
->
transmission_mode
,
ofdm
->
bandwidth
);
wr
(
DIB3000MC_REG_ISI
,
DIB3000MC_ISI_DEFAULT
|
DIB3000MC_ISI_ACTIVATE
);
dib3000mc_set_adp_cfg
(
state
,
ofdm
->
constellation
);
/* set_offset_cfg */
wr_foreach
(
dib3000mc_reg_offset
,
dib3000mc_offset
[(
ofdm
->
transmission_mode
==
TRANSMISSION_MODE_8K
)
+
1
]);
}
}
else
{
/* second call, after autosearch (fka: set_WithKnownParams) */
// dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth);
auto_val
=
0
;
dib3000mc_set_general_cfg
(
state
,
fep
,
&
auto_val
);
if
(
auto_val
)
deb_info
(
"auto_val is true, even though an auto search was already performed.
\n
"
);
dib3000mc_set_impulse_noise
(
state
,
0
,
ofdm
->
constellation
,
ofdm
->
bandwidth
);
val
=
rd
(
DIB3000MC_REG_DEMOD_PARM
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
|
DIB3000MC_DEMOD_RST_AUTO_SRCH_ON
);
wr
(
DIB3000MC_REG_DEMOD_PARM
,
val
);
msleep
(
30
);
wr
(
DIB3000MC_REG_ISI
,
DIB3000MC_ISI_DEFAULT
|
DIB3000MC_ISI_ACTIVATE
);
dib3000mc_set_adp_cfg
(
state
,
ofdm
->
constellation
);
wr_foreach
(
dib3000mc_reg_offset
,
dib3000mc_offset
[(
ofdm
->
transmission_mode
==
TRANSMISSION_MODE_8K
)
+
1
]);
}
return
0
;
}
static
int
dib3000mc_fe_init
(
struct
dvb_frontend
*
fe
,
int
mobile_mode
)
{
deb_info
(
"init start
\n
"
);
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
state
->
timing_offset
=
0
;
state
->
timing_offset_comp_done
=
0
;
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_CONFIG
);
wr
(
DIB3000MC_REG_RESTART
,
DIB3000MC_RESTART_OFF
);
wr
(
DIB3000MC_REG_CLK_CFG_1
,
DIB3000MC_CLK_CFG_1_POWER_UP
);
wr
(
DIB3000MC_REG_CLK_CFG_2
,
DIB3000MC_CLK_CFG_2_PUP_MOBILE
);
wr
(
DIB3000MC_REG_CLK_CFG_3
,
DIB3000MC_CLK_CFG_3_POWER_UP
);
wr
(
DIB3000MC_REG_CLK_CFG_7
,
DIB3000MC_CLK_CFG_7_INIT
);
wr
(
DIB3000MC_REG_RST_UNC
,
DIB3000MC_RST_UNC_OFF
);
wr
(
DIB3000MC_REG_UNK_19
,
DIB3000MC_UNK_19
);
wr
(
33
,
5
);
wr
(
36
,
81
);
wr
(
DIB3000MC_REG_UNK_88
,
DIB3000MC_UNK_88
);
wr
(
DIB3000MC_REG_UNK_99
,
DIB3000MC_UNK_99
);
wr
(
DIB3000MC_REG_UNK_111
,
DIB3000MC_UNK_111_PH_N_MODE_0
);
/* phase noise algo off */
/* mobile mode - portable reception */
wr_foreach
(
dib3000mc_reg_mobile_mode
,
dib3000mc_mobile_mode
[
1
]);
/* TUNER_PANASONIC_ENV57H12D5: */
wr_foreach
(
dib3000mc_reg_agc_bandwidth
,
dib3000mc_agc_bandwidth
);
wr_foreach
(
dib3000mc_reg_agc_bandwidth_general
,
dib3000mc_agc_bandwidth_general
);
wr_foreach
(
dib3000mc_reg_agc
,
dib3000mc_agc_tuner
[
1
]);
wr
(
DIB3000MC_REG_UNK_110
,
DIB3000MC_UNK_110
);
wr
(
26
,
0x6680
);
wr
(
DIB3000MC_REG_UNK_1
,
DIB3000MC_UNK_1
);
wr
(
DIB3000MC_REG_UNK_2
,
DIB3000MC_UNK_2
);
wr
(
DIB3000MC_REG_UNK_3
,
DIB3000MC_UNK_3
);
wr
(
DIB3000MC_REG_SEQ_TPS
,
DIB3000MC_SEQ_TPS_DEFAULT
);
wr_foreach
(
dib3000mc_reg_bandwidth
,
dib3000mc_bandwidth_8mhz
);
wr_foreach
(
dib3000mc_reg_bandwidth_general
,
dib3000mc_bandwidth_general
);
wr
(
DIB3000MC_REG_UNK_4
,
DIB3000MC_UNK_4
);
wr
(
DIB3000MC_REG_SET_DDS_FREQ_MSB
,
DIB3000MC_DDS_FREQ_MSB_INV_OFF
);
wr
(
DIB3000MC_REG_SET_DDS_FREQ_LSB
,
DIB3000MC_DDS_FREQ_LSB
);
dib3000mc_set_timing
(
state
,
0
,
TRANSMISSION_MODE_8K
,
BANDWIDTH_8_MHZ
);
// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
wr
(
DIB3000MC_REG_UNK_120
,
DIB3000MC_UNK_120
);
wr
(
DIB3000MC_REG_UNK_134
,
DIB3000MC_UNK_134
);
wr
(
DIB3000MC_REG_FEC_CFG
,
DIB3000MC_FEC_CFG
);
wr
(
DIB3000MC_REG_DIVERSITY3
,
DIB3000MC_DIVERSITY3_IN_OFF
);
dib3000mc_set_impulse_noise
(
state
,
0
,
TRANSMISSION_MODE_8K
,
BANDWIDTH_8_MHZ
);
/* output mode control, just the MPEG2_SLAVE */
// set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
wr
(
DIB3000MC_REG_OUTMODE
,
DIB3000MC_OM_SLAVE
);
wr
(
DIB3000MC_REG_SMO_MODE
,
DIB3000MC_SMO_MODE_SLAVE
);
wr
(
DIB3000MC_REG_FIFO_THRESHOLD
,
DIB3000MC_FIFO_THRESHOLD_SLAVE
);
wr
(
DIB3000MC_REG_ELEC_OUT
,
DIB3000MC_ELEC_OUT_SLAVE
);
/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
wr(DIB3000MC_REG_OUTMODE,
DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
rd(DIB3000MC_REG_OUTMODE)));
wr(DIB3000MC_REG_SMO_MODE,
DIB3000MC_SMO_MODE_DEFAULT |
DIB3000MC_SMO_MODE_188);
wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
*/
/* diversity */
wr
(
DIB3000MC_REG_DIVERSITY1
,
DIB3000MC_DIVERSITY1_DEFAULT
);
wr
(
DIB3000MC_REG_DIVERSITY2
,
DIB3000MC_DIVERSITY2_DEFAULT
);
set_and
(
DIB3000MC_REG_DIVERSITY3
,
DIB3000MC_DIVERSITY3_IN_OFF
);
set_or
(
DIB3000MC_REG_CLK_CFG_7
,
DIB3000MC_CLK_CFG_7_DIV_IN_OFF
);
/* if (state->config->pll_init) {
dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
state->config->pll_init(fe,NULL);
dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
}*/
deb_info
(
"init end
\n
"
);
return
0
;
}
static
int
dib3000mc_read_status
(
struct
dvb_frontend
*
fe
,
fe_status_t
*
stat
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
...
...
@@ -627,12 +665,12 @@ static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
*
stat
|=
FE_HAS_SIGNAL
;
if
(
DIB3000MC_CARRIER_LOCK
(
lock
))
*
stat
|=
FE_HAS_CARRIER
;
if
(
DIB3000MC_TPS_LOCK
(
lock
))
/* VIT_LOCK ? */
if
(
DIB3000MC_TPS_LOCK
(
lock
))
*
stat
|=
FE_HAS_VITERBI
;
if
(
DIB3000MC_MPEG_SYNC_LOCK
(
lock
))
*
stat
|=
(
FE_HAS_SYNC
|
FE_HAS_LOCK
);
deb_
info
(
"actual status is %2x
\n
"
,
*
stat
);
deb_
stat
(
"actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x
\n
"
,
*
stat
,
rd
(
510
),
rd
(
244
),
rd
(
206
),
rd
(
207
),
rd
(
1040
)
);
return
0
;
}
...
...
@@ -659,7 +697,7 @@ static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength
u16
val
=
rd
(
DIB3000MC_REG_SIGNAL_NOISE_LSB
);
*
strength
=
(((
val
>>
6
)
&
0xff
)
<<
8
)
+
(
val
&
0x3f
);
deb_
info
(
"signal: mantisse = %d, exponent = %d
\n
"
,(
*
strength
>>
8
)
&
0xff
,
*
strength
&
0xff
);
deb_
stat
(
"signal: mantisse = %d, exponent = %d
\n
"
,(
*
strength
>>
8
)
&
0xff
,
*
strength
&
0xff
);
return
0
;
}
...
...
@@ -667,9 +705,8 @@ static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength
static
int
dib3000mc_read_snr
(
struct
dvb_frontend
*
fe
,
u16
*
snr
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
u16
val
=
rd
(
DIB3000MC_REG_SIGNAL_NOISE_MSB
),
val2
=
rd
(
DIB3000MC_REG_SIGNAL_NOISE_LSB
);
u16
val
=
rd
(
DIB3000MC_REG_SIGNAL_NOISE_LSB
),
val2
=
rd
(
DIB3000MC_REG_SIGNAL_NOISE_MSB
);
u16
sig
,
noise
;
sig
=
(((
val
>>
6
)
&
0xff
)
<<
8
)
+
(
val
&
0x3f
);
...
...
@@ -679,9 +716,9 @@ static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
else
*
snr
=
(
u16
)
sig
/
noise
;
deb_
info
(
"signal: mantisse = %d, exponent = %d
\n
"
,(
sig
>>
8
)
&
0xff
,
sig
&
0xff
);
deb_
info
(
"noise: mantisse = %d, exponent = %d
\n
"
,(
noise
>>
8
)
&
0xff
,
noise
&
0xff
);
deb_
info
(
"snr: %d
\n
"
,
*
snr
);
deb_
stat
(
"signal: mantisse = %d, exponent = %d
\n
"
,(
sig
>>
8
)
&
0xff
,
sig
&
0xff
);
deb_
stat
(
"noise: mantisse = %d, exponent = %d
\n
"
,(
noise
>>
8
)
&
0xff
,
noise
&
0xff
);
deb_
stat
(
"snr: %d
\n
"
,
*
snr
);
return
0
;
}
...
...
@@ -698,7 +735,7 @@ static int dib3000mc_sleep(struct dvb_frontend* fe)
static
int
dib3000mc_fe_get_tune_settings
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_tune_settings
*
tune
)
{
tune
->
min_delay_ms
=
8
00
;
tune
->
min_delay_ms
=
20
00
;
tune
->
step_size
=
166667
;
tune
->
max_drift
=
166667
*
2
;
...
...
@@ -718,23 +755,15 @@ static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_
static
void
dib3000mc_release
(
struct
dvb_frontend
*
fe
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
dib3000_dealloc_pid_list
(
state
);
kfree
(
state
);
}
/* pid filter and transfer stuff */
static
int
dib3000mc_pid_control
(
struct
dvb_frontend
*
fe
,
int
pid
,
int
onoff
)
static
int
dib3000mc_pid_control
(
struct
dvb_frontend
*
fe
,
int
index
,
int
pid
,
int
onoff
)
{
struct
dib3000_state
*
state
=
fe
->
demodulator_priv
;
int
index
=
dib3000_get_pid_index
(
state
->
pid_list
,
DIB3000MC_NUM_PIDS
,
pid
,
&
state
->
pid_list_lock
,
onoff
);
pid
=
(
onoff
?
pid
|
DIB3000_ACTIVATE_PID_FILTERING
:
0
);
if
(
index
>=
0
)
{
wr
(
index
+
DIB3000MC_REG_FIRST_PID
,
pid
);
}
else
{
err
(
"no more pids for filtering."
);
return
-
ENOMEM
;
}
return
0
;
}
...
...
@@ -742,10 +771,14 @@ static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
u16
tmp
=
rd
(
DIB3000MC_REG_SMO_MODE
);
deb_xfer
(
"%s fifo"
,
onoff
?
"enabling"
:
"disabling"
);
deb_xfer
(
"%s fifo
\n
"
,
onoff
?
"enabling"
:
"disabling"
);
if
(
onoff
)
{
deb_xfer
(
"%d %x
\n
"
,
tmp
&
DIB3000MC_SMO_MODE_FIFO_UNFLUSH
,
tmp
&
DIB3000MC_SMO_MODE_FIFO_UNFLUSH
);
wr
(
DIB3000MC_REG_SMO_MODE
,
tmp
&
DIB3000MC_SMO_MODE_FIFO_UNFLUSH
);
}
else
{
deb_xfer
(
"%d %x
\n
"
,
tmp
|
DIB3000MC_SMO_MODE_FIFO_FLUSH
,
tmp
|
DIB3000MC_SMO_MODE_FIFO_FLUSH
);
wr
(
DIB3000MC_REG_SMO_MODE
,
tmp
|
DIB3000MC_SMO_MODE_FIFO_FLUSH
);
}
return
0
;
...
...
@@ -755,19 +788,57 @@ static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
{
struct
dib3000_state
*
state
=
fe
->
demodulator_priv
;
u16
tmp
=
rd
(
DIB3000MC_REG_SMO_MODE
);
deb_xfer
(
"%s pid parsing"
,
onoff
?
"enabling"
:
"disabling"
);
deb_xfer
(
"%s pid parsing
\n
"
,
onoff
?
"enabling"
:
"disabling"
);
if
(
onoff
)
{
deb_xfer
(
"%d %x
\n
"
,
tmp
|
DIB3000MC_SMO_MODE_PID_PARSE
,
tmp
|
DIB3000MC_SMO_MODE_PID_PARSE
);
wr
(
DIB3000MC_REG_SMO_MODE
,
tmp
|
DIB3000MC_SMO_MODE_PID_PARSE
);
}
else
{
deb_xfer
(
"%d %x
\n
"
,
tmp
&
DIB3000MC_SMO_MODE_NO_PID_PARSE
,
tmp
&
DIB3000MC_SMO_MODE_NO_PID_PARSE
);
wr
(
DIB3000MC_REG_SMO_MODE
,
tmp
&
DIB3000MC_SMO_MODE_NO_PID_PARSE
);
}
return
0
;
}
static
int
dib3000mc_tuner_pass_ctrl
(
struct
dvb_frontend
*
fe
,
int
onoff
,
u8
pll_addr
)
{
struct
dib3000_state
*
state
=
(
struct
dib3000_state
*
)
fe
->
demodulator_priv
;
if
(
onoff
)
{
wr
(
DIB3000MC_REG_TUNER
,
DIB3000_TUNER_WRITE_ENABLE
(
pll_addr
));
}
else
{
wr
(
DIB3000MC_REG_TUNER
,
DIB3000_TUNER_WRITE_DISABLE
(
pll_addr
));
}
return
0
;
}
static
int
dib3000mc_demod_init
(
struct
dib3000_state
*
state
)
{
u16
default_addr
=
0x0a
;
/* first init */
if
(
state
->
config
.
demod_address
!=
default_addr
)
{
deb_info
(
"initializing the demod the first time. Setting demod addr to 0x%x
\n
"
,
default_addr
);
wr
(
DIB3000MC_REG_ELEC_OUT
,
DIB3000MC_ELEC_OUT_DIV_OUT_ON
);
wr
(
DIB3000MC_REG_OUTMODE
,
DIB3000MC_OM_PAR_CONT_CLK
);
wr
(
DIB3000MC_REG_RST_I2C_ADDR
,
DIB3000MC_DEMOD_ADDR
(
default_addr
)
|
DIB3000MC_DEMOD_ADDR_ON
);
state
->
config
.
demod_address
=
default_addr
;
wr
(
DIB3000MC_REG_RST_I2C_ADDR
,
DIB3000MC_DEMOD_ADDR
(
default_addr
));
}
else
deb_info
(
"demod is already initialized. Demod addr: 0x%x
\n
"
,
state
->
config
.
demod_address
);
return
0
;
}
static
struct
dvb_frontend_ops
dib3000mc_ops
;
struct
dvb_frontend
*
dib3000mc_attach
(
const
struct
dib3000_config
*
config
,
struct
i2c_adapter
*
i2c
,
struct
dib
3000
_xfer_ops
*
xfer_ops
)
struct
i2c_adapter
*
i2c
,
struct
dib
_fe
_xfer_ops
*
xfer_ops
)
{
struct
dib3000_state
*
state
=
NULL
;
u16
devid
;
...
...
@@ -790,19 +861,15 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
if
(
devid
!=
DIB3000MC_DEVICE_ID
&&
devid
!=
DIB3000P_DEVICE_ID
)
goto
error
;
switch
(
devid
)
{
case
DIB3000MC_DEVICE_ID
:
info
(
"Found a DiBcom 3000-MC."
);
info
(
"Found a DiBcom 3000-MC
, interesting..
."
);
break
;
case
DIB3000P_DEVICE_ID
:
info
(
"Found a DiBcom 3000-P."
);
break
;
}
if
(
dib3000_init_pid_list
(
state
,
DIB3000MC_NUM_PIDS
))
goto
error
;
/* create dvb_frontend */
state
->
frontend
.
ops
=
&
state
->
ops
;
state
->
frontend
.
demodulator_priv
=
state
;
...
...
@@ -811,6 +878,9 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
xfer_ops
->
pid_parse
=
dib3000mc_pid_parse
;
xfer_ops
->
fifo_ctrl
=
dib3000mc_fifo_control
;
xfer_ops
->
pid_ctrl
=
dib3000mc_pid_control
;
xfer_ops
->
tuner_pass_ctrl
=
dib3000mc_tuner_pass_ctrl
;
dib3000mc_demod_init
(
state
);
return
&
state
->
frontend
;
...
...
@@ -834,6 +904,7 @@ static struct dvb_frontend_ops dib3000mc_ops = {
FE_CAN_QPSK
|
FE_CAN_QAM_16
|
FE_CAN_QAM_64
|
FE_CAN_QAM_AUTO
|
FE_CAN_TRANSMISSION_MODE_AUTO
|
FE_CAN_GUARD_INTERVAL_AUTO
|
FE_CAN_RECOVER
|
FE_CAN_HIERARCHY_AUTO
,
},
...
...
drivers/media/dvb/frontends/dib3000mc_priv.h
View file @
ca583a3c
...
...
@@ -13,31 +13,6 @@
#ifndef __DIB3000MC_PRIV_H__
#define __DIB3000MC_PRIV_H__
/* info and err, taken from usb.h, if there is anything available like by default,
* please change !
*/
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
// defines the phase noise algorithm to be used (O:Inhib, 1:CPE on)
#define DEF_PHASE_NOISE_MODE 0
// define Mobille algorithms
#define DEF_MOBILE_MODE Auto_Reception
// defines the tuner type
#define DEF_TUNER_TYPE TUNER_PANASONIC_ENV57H13D5
// defines the impule noise algorithm to be used
#define DEF_IMPULSE_NOISE_MODE 0
// defines the MPEG2 data output format
#define DEF_MPEG2_OUTPUT_188 0
// defines the MPEG2 data output format
#define DEF_OUTPUT_MODE MPEG2_PARALLEL_CONTINUOUS_CLOCK
/*
* Demodulator parameters
* reg: 0 1 1 1 11 11 111
...
...
@@ -115,7 +90,7 @@ static u16 dib3000mc_bandwidth_7mhz[] =
{
0x1c
,
0xfba5
,
0x60
,
0x9c25
,
0x1e3
,
0x0cb7
,
0x1
,
0xb0d0
};
static
u16
dib3000mc_bandwidth_8mhz
[]
=
{
0x19
,
0x5c30
,
0x54
,
0x88a0
,
0x1a6
,
0xab20
,
0x1
,
0xb0
b
0
};
{
0x19
,
0x5c30
,
0x54
,
0x88a0
,
0x1a6
,
0xab20
,
0x1
,
0xb0
d
0
};
static
u16
dib3000mc_reg_bandwidth_general
[]
=
{
12
,
13
,
14
,
15
};
static
u16
dib3000mc_bandwidth_general
[]
=
{
0x0000
,
0x03e8
,
0x0000
,
0x03f2
};
...
...
@@ -173,11 +148,11 @@ static u16 dib3000mc_offset[][2] = {
static
u16
dib3000mc_reg_imp_noise_ctl
[]
=
{
34
,
35
};
static
u16
dib3000mc_imp_noise_ctl
[][
2
]
=
{
{
0x1294
,
0x
f
ff8
},
/* mode 0 */
{
0x1294
,
0x
f
ff8
},
/* mode 1 */
{
0x1294
,
0x
f
ff8
},
/* mode 2 */
{
0x1294
,
0x
f
ff8
},
/* mode 3 */
{
0x1294
,
0x
f
ff8
},
/* mode 4 */
{
0x1294
,
0x
1
ff8
},
/* mode 0 */
{
0x1294
,
0x
1
ff8
},
/* mode 1 */
{
0x1294
,
0x
1
ff8
},
/* mode 2 */
{
0x1294
,
0x
1
ff8
},
/* mode 3 */
{
0x1294
,
0x
1
ff8
},
/* mode 4 */
};
/* AGC registers */
...
...
@@ -314,12 +289,26 @@ static u16 dib3000mc_mobile_mode[][5] = {
#define DIB3000MC_REG_FEC_CFG ( 195)
#define DIB3000MC_FEC_CFG ( 0x10)
/*
* reg 206, output mode
* 1111 1111
* |||| ||||
* |||| |||+- unk
* |||| ||+-- unk
* |||| |+--- unk (on by default)
* |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed))
* |||+------ pid_parse (1 = enabled, 0 = disabled)
* ||+------- outp_188 (1 = TS packet size 188, 0 = packet size 204)
* |+-------- unk
* +--------- unk
*/
#define DIB3000MC_REG_SMO_MODE ( 206)
#define DIB3000MC_SMO_MODE_DEFAULT (1 << 2)
#define DIB3000MC_SMO_MODE_FIFO_FLUSH (1 << 3)
#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH
~DIB3000MC_SMO_MODE_FIFO_FLUSH
#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH
(0xfff7)
#define DIB3000MC_SMO_MODE_PID_PARSE (1 << 4)
#define DIB3000MC_SMO_MODE_NO_PID_PARSE
~DIB3000MC_SMO_MODE_PID_PARSE
#define DIB3000MC_SMO_MODE_NO_PID_PARSE
(0xffef)
#define DIB3000MC_SMO_MODE_188 (1 << 5)
#define DIB3000MC_SMO_MODE_SLAVE (DIB3000MC_SMO_MODE_DEFAULT | \
DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
...
...
@@ -392,7 +381,7 @@ static u16 dib3000mc_mobile_mode[][5] = {
#define DIB3000MC_REG_RST_I2C_ADDR ( 1024)
#define DIB3000MC_DEMOD_ADDR_ON ( 1)
#define DIB3000MC_DEMOD_ADDR(a) ((a <<
3
) & 0x03F0)
#define DIB3000MC_DEMOD_ADDR(a) ((a <<
4
) & 0x03F0)
#define DIB3000MC_REG_RESTART ( 1027)
#define DIB3000MC_RESTART_OFF (0x0000)
...
...
drivers/media/dvb/frontends/mt352.c
View file @
ca583a3c
...
...
@@ -58,16 +58,26 @@ do { \
if (debug) printk(KERN_DEBUG "mt352: " args); \
} while (0)
int
mt352_write
(
struct
dvb_frontend
*
fe
,
u8
*
ibuf
,
int
ilen
)
static
int
mt352_single_write
(
struct
dvb_frontend
*
fe
,
u8
reg
,
u8
val
)
{
struct
mt352_state
*
state
=
(
struct
mt352_state
*
)
fe
->
demodulator_priv
;
u8
buf
[
2
]
=
{
reg
,
val
};
struct
i2c_msg
msg
=
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
0
,
.
buf
=
ibuf
,
.
len
=
ilen
};
.
buf
=
buf
,
.
len
=
2
};
int
err
=
i2c_transfer
(
state
->
i2c
,
&
msg
,
1
);
if
(
err
!=
1
)
{
dprintk
(
"mt352_write()
failed (err = %d)!
\n
"
,
err
);
dprintk
(
"mt352_write()
to reg %x failed (err = %d)!
\n
"
,
reg
,
err
);
return
err
;
}
return
0
;
}
int
mt352_write
(
struct
dvb_frontend
*
fe
,
u8
*
ibuf
,
int
ilen
)
{
int
err
,
i
;
for
(
i
=
0
;
i
<
ilen
-
1
;
i
++
)
if
((
err
=
mt352_single_write
(
fe
,
ibuf
[
0
]
+
i
,
ibuf
[
i
+
1
])))
return
err
;
return
0
;
}
...
...
@@ -92,9 +102,10 @@ static u8 mt352_read_register(struct mt352_state* state, u8 reg)
return
b1
[
0
];
}
u8
mt352_read
(
struct
dvb_frontend
*
fe
,
u8
reg
)
{
return
mt352_read_register
(
fe
->
demodulator_priv
,
reg
);
}
...
...
@@ -556,3 +567,4 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL
(
mt352_attach
);
EXPORT_SYMBOL
(
mt352_write
);
EXPORT_SYMBOL
(
mt352_read
);
drivers/media/dvb/frontends/mt352.h
View file @
ca583a3c
...
...
@@ -54,5 +54,6 @@ extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct
i2c_adapter
*
i2c
);
extern
int
mt352_write
(
struct
dvb_frontend
*
fe
,
u8
*
ibuf
,
int
ilen
);
extern
u8
mt352_read
(
struct
dvb_frontend
*
fe
,
u8
reg
);
#endif // MT352_H
drivers/media/dvb/frontends/nxt2002.c
0 → 100644
View file @
ca583a3c
/*
Support for B2C2/BBTI Technisat Air2PC - ATSC
Copyright (C) 2004 Taylor Jacob <rtjacob@earthlink.net>
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware.
*/
#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
#define CRC_CCIT_MASK 0x1021
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include "dvb_frontend.h"
#include "nxt2002.h"
struct
nxt2002_state
{
struct
i2c_adapter
*
i2c
;
struct
dvb_frontend_ops
ops
;
const
struct
nxt2002_config
*
config
;
struct
dvb_frontend
frontend
;
/* demodulator private data */
u8
initialised
:
1
;
};
static
int
debug
;
#define dprintk(args...) \
do { \
if (debug) printk(KERN_DEBUG "nxt2002: " args); \
} while (0)
static
int
i2c_writebytes
(
struct
nxt2002_state
*
state
,
u8
reg
,
u8
*
buf
,
u8
len
)
{
/* probbably a much better way or doing this */
u8
buf2
[
256
],
x
;
int
err
;
struct
i2c_msg
msg
=
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
0
,
.
buf
=
buf2
,
.
len
=
len
+
1
};
buf2
[
0
]
=
reg
;
for
(
x
=
0
;
x
<
len
;
x
++
)
buf2
[
x
+
1
]
=
buf
[
x
];
if
((
err
=
i2c_transfer
(
state
->
i2c
,
&
msg
,
1
))
!=
1
)
{
printk
(
"%s: i2c write error (addr %02x, err == %i)
\n
"
,
__FUNCTION__
,
state
->
config
->
demod_address
,
err
);
return
-
EREMOTEIO
;
}
return
0
;
}
static
u8
i2c_readbytes
(
struct
nxt2002_state
*
state
,
u8
reg
,
u8
*
buf
,
u8
len
)
{
u8
reg2
[]
=
{
reg
};
struct
i2c_msg
msg
[]
=
{
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
0
,
.
buf
=
reg2
,
.
len
=
1
},
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
I2C_M_RD
,
.
buf
=
buf
,
.
len
=
len
}
};
int
err
;
if
((
err
=
i2c_transfer
(
state
->
i2c
,
msg
,
2
))
!=
2
)
{
printk
(
"%s: i2c read error (addr %02x, err == %i)
\n
"
,
__FUNCTION__
,
state
->
config
->
demod_address
,
err
);
return
-
EREMOTEIO
;
}
return
0
;
}
static
u16
nxt2002_crc
(
u16
crc
,
u8
c
)
{
u8
i
;
u16
input
=
(
u16
)
c
&
0xFF
;
input
<<=
8
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
((
crc
^
input
)
&
0x8000
)
crc
=
(
crc
<<
1
)
^
CRC_CCIT_MASK
;
else
crc
<<=
1
;
input
<<=
1
;
}
return
crc
;
}
static
int
nxt2002_writereg_multibyte
(
struct
nxt2002_state
*
state
,
u8
reg
,
u8
*
data
,
u8
len
)
{
u8
buf
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
/* set multi register length */
i2c_writebytes
(
state
,
0x34
,
&
len
,
1
);
/* set mutli register register */
i2c_writebytes
(
state
,
0x35
,
&
reg
,
1
);
/* send the actual data */
i2c_writebytes
(
state
,
0x36
,
data
,
len
);
/* toggle the multireg write bit*/
buf
=
0x02
;
i2c_writebytes
(
state
,
0x21
,
&
buf
,
1
);
i2c_readbytes
(
state
,
0x21
,
&
buf
,
1
);
if
((
buf
&
0x02
)
==
0
)
return
0
;
dprintk
(
"Error writing multireg register %02X
\n
"
,
reg
);
return
0
;
}
static
int
nxt2002_readreg_multibyte
(
struct
nxt2002_state
*
state
,
u8
reg
,
u8
*
data
,
u8
len
)
{
u8
len2
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
/* set multi register length */
len2
=
len
&
0x80
;
i2c_writebytes
(
state
,
0x34
,
&
len2
,
1
);
/* set mutli register register */
i2c_writebytes
(
state
,
0x35
,
&
reg
,
1
);
/* send the actual data */
i2c_readbytes
(
state
,
reg
,
data
,
len
);
return
0
;
}
static
void
nxt2002_microcontroller_stop
(
struct
nxt2002_state
*
state
)
{
u8
buf
[
2
],
counter
=
0
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
buf
[
0
]
=
0x80
;
i2c_writebytes
(
state
,
0x22
,
buf
,
1
);
while
(
counter
<
20
)
{
i2c_readbytes
(
state
,
0x31
,
buf
,
1
);
if
(
buf
[
0
]
&
0x40
)
return
;
msleep
(
10
);
counter
++
;
}
dprintk
(
"Timeout waiting for micro to stop.. This is ok after firmware upload
\n
"
);
return
;
}
static
void
nxt2002_microcontroller_start
(
struct
nxt2002_state
*
state
)
{
u8
buf
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
buf
=
0x00
;
i2c_writebytes
(
state
,
0x22
,
&
buf
,
1
);
}
static
int
nxt2002_writetuner
(
struct
nxt2002_state
*
state
,
u8
*
data
)
{
u8
buf
,
count
=
0
;
dprintk
(
"Tuner Bytes: %02X %02X %02X %02X
\n
"
,
data
[
0
],
data
[
1
],
data
[
2
],
data
[
3
]);
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
/* stop the micro first */
nxt2002_microcontroller_stop
(
state
);
/* set the i2c transfer speed to the tuner */
buf
=
0x03
;
i2c_writebytes
(
state
,
0x20
,
&
buf
,
1
);
/* setup to transfer 4 bytes via i2c */
buf
=
0x04
;
i2c_writebytes
(
state
,
0x34
,
&
buf
,
1
);
/* write actual tuner bytes */
i2c_writebytes
(
state
,
0x36
,
data
,
4
);
/* set tuner i2c address */
buf
=
0xC2
;
i2c_writebytes
(
state
,
0x35
,
&
buf
,
1
);
/* write UC Opmode to begin transfer */
buf
=
0x80
;
i2c_writebytes
(
state
,
0x21
,
&
buf
,
1
);
while
(
count
<
20
)
{
i2c_readbytes
(
state
,
0x21
,
&
buf
,
1
);
if
((
buf
&
0x80
)
==
0x00
)
return
0
;
msleep
(
100
);
count
++
;
}
printk
(
"nxt2002: timeout error writing tuner
\n
"
);
return
0
;
}
static
void
nxt2002_agc_reset
(
struct
nxt2002_state
*
state
)
{
u8
buf
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
buf
=
0x08
;
i2c_writebytes
(
state
,
0x08
,
&
buf
,
1
);
buf
=
0x00
;
i2c_writebytes
(
state
,
0x08
,
&
buf
,
1
);
return
;
}
static
int
nxt2002_load_firmware
(
struct
dvb_frontend
*
fe
,
const
struct
firmware
*
fw
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u8
buf
[
256
],
written
=
0
,
chunkpos
=
0
;
u16
rambase
,
position
,
crc
=
0
;
dprintk
(
"%s
\n
"
,
__FUNCTION__
);
dprintk
(
"Firmware is %d bytes
\n
"
,
fw
->
size
);
/* Get the RAM base for this nxt2002 */
i2c_readbytes
(
state
,
0x10
,
buf
,
1
);
if
(
buf
[
0
]
&
0x10
)
rambase
=
0x1000
;
else
rambase
=
0x0000
;
dprintk
(
"rambase on this nxt2002 is %04X
\n
"
,
rambase
);
/* Hold the micro in reset while loading firmware */
buf
[
0
]
=
0x80
;
i2c_writebytes
(
state
,
0x2B
,
buf
,
1
);
for
(
position
=
0
;
position
<
fw
->
size
;
position
++
)
{
if
(
written
==
0
)
{
crc
=
0
;
chunkpos
=
0x28
;
buf
[
0
]
=
((
rambase
+
position
)
>>
8
);
buf
[
1
]
=
(
rambase
+
position
)
&
0xFF
;
buf
[
2
]
=
0x81
;
/* write starting address */
i2c_writebytes
(
state
,
0x29
,
buf
,
3
);
}
written
++
;
chunkpos
++
;
if
((
written
%
4
)
==
0
)
i2c_writebytes
(
state
,
chunkpos
,
&
fw
->
data
[
position
-
3
],
4
);
crc
=
nxt2002_crc
(
crc
,
fw
->
data
[
position
]);
if
((
written
==
255
)
||
(
position
+
1
==
fw
->
size
))
{
/* write remaining bytes of firmware */
i2c_writebytes
(
state
,
chunkpos
+
4
-
(
written
%
4
),
&
fw
->
data
[
position
-
(
written
%
4
)
+
1
],
written
%
4
);
buf
[
0
]
=
crc
<<
8
;
buf
[
1
]
=
crc
&
0xFF
;
/* write crc */
i2c_writebytes
(
state
,
0x2C
,
buf
,
2
);
/* do a read to stop things */
i2c_readbytes
(
state
,
0x2A
,
buf
,
1
);
/* set transfer mode to complete */
buf
[
0
]
=
0x80
;
i2c_writebytes
(
state
,
0x2B
,
buf
,
1
);
written
=
0
;
}
}
printk
(
"done.
\n
"
);
return
0
;
};
static
int
nxt2002_setup_frontend_parameters
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
p
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u32
freq
=
0
;
u16
tunerfreq
=
0
;
u8
buf
[
4
];
freq
=
44000
+
(
p
->
frequency
/
1000
);
dprintk
(
"freq = %d p->frequency = %d
\n
"
,
freq
,
p
->
frequency
);
tunerfreq
=
freq
*
24
/
4000
;
buf
[
0
]
=
(
tunerfreq
>>
8
)
&
0x7F
;
buf
[
1
]
=
(
tunerfreq
&
0xFF
);
if
(
p
->
frequency
<=
214000000
)
{
buf
[
2
]
=
0x84
+
(
0x06
<<
3
);
buf
[
3
]
=
(
p
->
frequency
<=
172000000
)
?
0x01
:
0x02
;
}
else
if
(
p
->
frequency
<=
721000000
)
{
buf
[
2
]
=
0x84
+
(
0x07
<<
3
);
buf
[
3
]
=
(
p
->
frequency
<=
467000000
)
?
0x02
:
0x08
;
}
else
if
(
p
->
frequency
<=
841000000
)
{
buf
[
2
]
=
0x84
+
(
0x0E
<<
3
);
buf
[
3
]
=
0x08
;
}
else
{
buf
[
2
]
=
0x84
+
(
0x0F
<<
3
);
buf
[
3
]
=
0x02
;
}
/* write frequency information */
nxt2002_writetuner
(
state
,
buf
);
/* reset the agc now that tuning has been completed */
nxt2002_agc_reset
(
state
);
/* set target power level */
buf
[
0
]
=
0x70
;
i2c_writebytes
(
state
,
0x42
,
buf
,
1
);
/* configure sdm */
buf
[
0
]
=
0x87
;
i2c_writebytes
(
state
,
0x57
,
buf
,
1
);
/* write sdm1 input */
buf
[
0
]
=
0x10
;
buf
[
1
]
=
0x00
;
nxt2002_writereg_multibyte
(
state
,
0x58
,
buf
,
2
);
/* write sdmx input */
buf
[
0
]
=
0x60
;
buf
[
1
]
=
0x00
;
nxt2002_writereg_multibyte
(
state
,
0x5C
,
buf
,
2
);
/* write adc power lpf fc */
buf
[
0
]
=
0x05
;
i2c_writebytes
(
state
,
0x43
,
buf
,
1
);
/* write adc power lpf fc */
buf
[
0
]
=
0x05
;
i2c_writebytes
(
state
,
0x43
,
buf
,
1
);
/* write accumulator2 input */
buf
[
0
]
=
0x80
;
buf
[
1
]
=
0x00
;
nxt2002_writereg_multibyte
(
state
,
0x4B
,
buf
,
2
);
/* write kg1 */
buf
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0x4D
,
buf
,
1
);
/* write sdm12 lpf fc */
buf
[
0
]
=
0x44
;
i2c_writebytes
(
state
,
0x55
,
buf
,
1
);
/* write agc control reg */
buf
[
0
]
=
0x04
;
i2c_writebytes
(
state
,
0x41
,
buf
,
1
);
/* write agc ucgp0 */
buf
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0x30
,
buf
,
1
);
/* write agc control reg */
buf
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0x41
,
buf
,
1
);
/* write accumulator2 input */
buf
[
0
]
=
0x80
;
buf
[
1
]
=
0x00
;
nxt2002_writereg_multibyte
(
state
,
0x49
,
buf
,
2
);
nxt2002_writereg_multibyte
(
state
,
0x4B
,
buf
,
2
);
/* write agc control reg */
buf
[
0
]
=
0x04
;
i2c_writebytes
(
state
,
0x41
,
buf
,
1
);
nxt2002_microcontroller_start
(
state
);
/* adjacent channel detection should be done here, but I don't
have any stations with this need so I cannot test it */
return
0
;
}
static
int
nxt2002_read_status
(
struct
dvb_frontend
*
fe
,
fe_status_t
*
status
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u8
lock
;
i2c_readbytes
(
state
,
0x31
,
&
lock
,
1
);
*
status
=
0
;
if
(
lock
&
0x20
)
{
*
status
|=
FE_HAS_SIGNAL
;
*
status
|=
FE_HAS_CARRIER
;
*
status
|=
FE_HAS_VITERBI
;
*
status
|=
FE_HAS_SYNC
;
*
status
|=
FE_HAS_LOCK
;
}
return
0
;
}
static
int
nxt2002_read_ber
(
struct
dvb_frontend
*
fe
,
u32
*
ber
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u8
b
[
3
];
nxt2002_readreg_multibyte
(
state
,
0xE6
,
b
,
3
);
*
ber
=
((
b
[
0
]
<<
8
)
+
b
[
1
])
*
8
;
return
0
;
}
static
int
nxt2002_read_signal_strength
(
struct
dvb_frontend
*
fe
,
u16
*
strength
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u8
b
[
2
];
u16
temp
=
0
;
/* setup to read cluster variance */
b
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0xA1
,
b
,
1
);
/* get multreg val */
nxt2002_readreg_multibyte
(
state
,
0xA6
,
b
,
2
);
temp
=
(
b
[
0
]
<<
8
)
|
b
[
1
];
*
strength
=
((
0x7FFF
-
temp
)
&
0x0FFF
)
*
16
;
return
0
;
}
static
int
nxt2002_read_snr
(
struct
dvb_frontend
*
fe
,
u16
*
snr
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u8
b
[
2
];
u16
temp
=
0
,
temp2
;
u32
snrdb
=
0
;
/* setup to read cluster variance */
b
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0xA1
,
b
,
1
);
/* get multreg val from 0xA6 */
nxt2002_readreg_multibyte
(
state
,
0xA6
,
b
,
2
);
temp
=
(
b
[
0
]
<<
8
)
|
b
[
1
];
temp2
=
0x7FFF
-
temp
;
/* snr will be in db */
if
(
temp2
>
0x7F00
)
snrdb
=
1000
*
24
+
(
1000
*
(
30
-
24
)
*
(
temp2
-
0x7F00
)
/
(
0x7FFF
-
0x7F00
)
);
else
if
(
temp2
>
0x7EC0
)
snrdb
=
1000
*
18
+
(
1000
*
(
24
-
18
)
*
(
temp2
-
0x7EC0
)
/
(
0x7F00
-
0x7EC0
)
);
else
if
(
temp2
>
0x7C00
)
snrdb
=
1000
*
12
+
(
1000
*
(
18
-
12
)
*
(
temp2
-
0x7C00
)
/
(
0x7EC0
-
0x7C00
)
);
else
snrdb
=
1000
*
0
+
(
1000
*
(
12
-
0
)
*
(
temp2
-
0
)
/
(
0x7C00
-
0
)
);
/* the value reported back from the frontend will be FFFF=32db 0000=0db */
*
snr
=
snrdb
*
(
0xFFFF
/
32000
);
return
0
;
}
static
int
nxt2002_read_ucblocks
(
struct
dvb_frontend
*
fe
,
u32
*
ucblocks
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
u8
b
[
3
];
nxt2002_readreg_multibyte
(
state
,
0xE6
,
b
,
3
);
*
ucblocks
=
b
[
2
];
return
0
;
}
static
int
nxt2002_sleep
(
struct
dvb_frontend
*
fe
)
{
return
0
;
}
static
int
nxt2002_init
(
struct
dvb_frontend
*
fe
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
const
struct
firmware
*
fw
;
int
ret
;
u8
buf
[
2
];
if
(
!
state
->
initialised
)
{
/* request the firmware, this will block until someone uploads it */
printk
(
"nxt2002: Waiting for firmware upload...
\n
"
);
ret
=
state
->
config
->
request_firmware
(
fe
,
&
fw
,
NXT2002_DEFAULT_FIRMWARE
);
printk
(
"nxt2002: Waiting for firmware upload(2)...
\n
"
);
if
(
ret
)
{
printk
(
"nxt2002: no firmware upload (timeout or file not found?)
\n
"
);
return
ret
;
}
ret
=
nxt2002_load_firmware
(
fe
,
fw
);
if
(
ret
)
{
printk
(
"nxt2002: writing firmware to device failed
\n
"
);
release_firmware
(
fw
);
return
ret
;
}
/* Put the micro into reset */
nxt2002_microcontroller_stop
(
state
);
/* ensure transfer is complete */
buf
[
0
]
=
0
;
i2c_writebytes
(
state
,
0x2B
,
buf
,
1
);
/* Put the micro into reset for real this time */
nxt2002_microcontroller_stop
(
state
);
/* soft reset everything (agc,frontend,eq,fec)*/
buf
[
0
]
=
0x0F
;
i2c_writebytes
(
state
,
0x08
,
buf
,
1
);
buf
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0x08
,
buf
,
1
);
/* write agc sdm configure */
buf
[
0
]
=
0xF1
;
i2c_writebytes
(
state
,
0x57
,
buf
,
1
);
/* write mod output format */
buf
[
0
]
=
0x20
;
i2c_writebytes
(
state
,
0x09
,
buf
,
1
);
/* write fec mpeg mode */
buf
[
0
]
=
0x7E
;
buf
[
1
]
=
0x00
;
i2c_writebytes
(
state
,
0xE9
,
buf
,
2
);
/* write mux selection */
buf
[
0
]
=
0x00
;
i2c_writebytes
(
state
,
0xCC
,
buf
,
1
);
state
->
initialised
=
1
;
}
return
0
;
}
static
int
nxt2002_get_tune_settings
(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_tune_settings
*
fesettings
)
{
fesettings
->
min_delay_ms
=
500
;
fesettings
->
step_size
=
0
;
fesettings
->
max_drift
=
0
;
return
0
;
}
static
void
nxt2002_release
(
struct
dvb_frontend
*
fe
)
{
struct
nxt2002_state
*
state
=
(
struct
nxt2002_state
*
)
fe
->
demodulator_priv
;
kfree
(
state
);
}
static
struct
dvb_frontend_ops
nxt2002_ops
;
struct
dvb_frontend
*
nxt2002_attach
(
const
struct
nxt2002_config
*
config
,
struct
i2c_adapter
*
i2c
)
{
struct
nxt2002_state
*
state
=
NULL
;
u8
buf
[]
=
{
0
,
0
,
0
,
0
,
0
};
/* allocate memory for the internal state */
state
=
(
struct
nxt2002_state
*
)
kmalloc
(
sizeof
(
struct
nxt2002_state
),
GFP_KERNEL
);
if
(
state
==
NULL
)
goto
error
;
/* setup the state */
state
->
config
=
config
;
state
->
i2c
=
i2c
;
memcpy
(
&
state
->
ops
,
&
nxt2002_ops
,
sizeof
(
struct
dvb_frontend_ops
));
state
->
initialised
=
0
;
/* Check the first 5 registers to ensure this a revision we can handle */
i2c_readbytes
(
state
,
0x00
,
buf
,
5
);
if
(
buf
[
0
]
!=
0x04
)
goto
error
;
/* device id */
if
(
buf
[
1
]
!=
0x02
)
goto
error
;
/* fab id */
if
(
buf
[
2
]
!=
0x11
)
goto
error
;
/* month */
if
(
buf
[
3
]
!=
0x20
)
goto
error
;
/* year msb */
if
(
buf
[
4
]
!=
0x00
)
goto
error
;
/* year lsb */
/* create dvb_frontend */
state
->
frontend
.
ops
=
&
state
->
ops
;
state
->
frontend
.
demodulator_priv
=
state
;
return
&
state
->
frontend
;
error:
if
(
state
)
kfree
(
state
);
return
NULL
;
}
static
struct
dvb_frontend_ops
nxt2002_ops
=
{
.
info
=
{
.
name
=
"Nextwave nxt2002 VSB/QAM frontend"
,
.
type
=
FE_ATSC
,
.
frequency_min
=
54000000
,
.
frequency_max
=
803000000
,
/* stepsize is just a guess */
.
frequency_stepsize
=
166666
,
.
caps
=
FE_CAN_FEC_1_2
|
FE_CAN_FEC_2_3
|
FE_CAN_FEC_3_4
|
FE_CAN_FEC_5_6
|
FE_CAN_FEC_7_8
|
FE_CAN_FEC_AUTO
|
FE_CAN_8VSB
},
.
release
=
nxt2002_release
,
.
init
=
nxt2002_init
,
.
sleep
=
nxt2002_sleep
,
.
set_frontend
=
nxt2002_setup_frontend_parameters
,
.
get_tune_settings
=
nxt2002_get_tune_settings
,
.
read_status
=
nxt2002_read_status
,
.
read_ber
=
nxt2002_read_ber
,
.
read_signal_strength
=
nxt2002_read_signal_strength
,
.
read_snr
=
nxt2002_read_snr
,
.
read_ucblocks
=
nxt2002_read_ucblocks
,
};
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"Turn on/off frontend debugging (default:off)."
);
MODULE_DESCRIPTION
(
"NXT2002 ATSC (8VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"
);
MODULE_AUTHOR
(
"Taylor Jacob"
);
MODULE_LICENSE
(
"GPL"
);
EXPORT_SYMBOL
(
nxt2002_attach
);
drivers/media/dvb/frontends/nxt2002.h
0 → 100644
View file @
ca583a3c
/*
Driver for the Nxt2002 demodulator
*/
#ifndef NXT2002_H
#define NXT2002_H
#include <linux/dvb/frontend.h>
#include <linux/firmware.h>
struct
nxt2002_config
{
/* the demodulator's i2c address */
u8
demod_address
;
/* request firmware for device */
int
(
*
request_firmware
)(
struct
dvb_frontend
*
fe
,
const
struct
firmware
**
fw
,
char
*
name
);
};
extern
struct
dvb_frontend
*
nxt2002_attach
(
const
struct
nxt2002_config
*
config
,
struct
i2c_adapter
*
i2c
);
#endif // NXT2002_H
drivers/media/dvb/frontends/stv0297.c
View file @
ca583a3c
...
...
@@ -38,10 +38,7 @@ struct stv0297_state {
struct
dvb_frontend
frontend
;
int
freq_off
;
unsigned
long
base_freq
;
u8
pwm
;
};
...
...
@@ -162,8 +159,10 @@ static int stv0297_readreg (struct stv0297_state* state, u8 reg)
int
ret
;
u8
b0
[]
=
{
reg
};
u8
b1
[]
=
{
0
};
struct
i2c_msg
msg
[]
=
{
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
0
,
.
buf
=
b0
,
.
len
=
1
},
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
I2C_M_RD
,
.
buf
=
b1
,
.
len
=
1
}
};
struct
i2c_msg
msg
[]
=
{
{.
addr
=
state
->
config
->
demod_address
,.
flags
=
0
,.
buf
=
b0
,.
len
=
1
},
{.
addr
=
state
->
config
->
demod_address
,.
flags
=
I2C_M_RD
,.
buf
=
b1
,.
len
=
1
}
};
// this device needs a STOP between the register and data
if
((
ret
=
i2c_transfer
(
state
->
i2c
,
&
msg
[
0
],
1
))
!=
1
)
{
...
...
@@ -193,8 +192,10 @@ static int stv0297_writereg_mask (struct stv0297_state* state, u8 reg, u8 mask,
static
int
stv0297_readregs
(
struct
stv0297_state
*
state
,
u8
reg1
,
u8
*
b
,
u8
len
)
{
int
ret
;
struct
i2c_msg
msg
[]
=
{
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
0
,
.
buf
=
&
reg1
,
.
len
=
1
},
{
.
addr
=
state
->
config
->
demod_address
,
.
flags
=
I2C_M_RD
,
.
buf
=
b
,
.
len
=
len
}
};
struct
i2c_msg
msg
[]
=
{
{.
addr
=
state
->
config
->
demod_address
,.
flags
=
0
,.
buf
=
&
reg1
,.
len
=
1
},
{.
addr
=
state
->
config
->
demod_address
,.
flags
=
I2C_M_RD
,.
buf
=
b
,.
len
=
len
}
};
// this device needs a STOP between the register and data
if
((
ret
=
i2c_transfer
(
state
->
i2c
,
&
msg
[
0
],
1
))
!=
1
)
{
...
...
@@ -209,6 +210,21 @@ static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len
return
0
;
}
static
u32
stv0297_get_symbolrate
(
struct
stv0297_state
*
state
)
{
u64
tmp
;
tmp
=
stv0297_readreg
(
state
,
0x55
);
tmp
|=
stv0297_readreg
(
state
,
0x56
)
<<
8
;
tmp
|=
stv0297_readreg
(
state
,
0x57
)
<<
16
;
tmp
|=
stv0297_readreg
(
state
,
0x58
)
<<
24
;
tmp
*=
STV0297_CLOCK_KHZ
;
tmp
>>=
32
;
return
(
u32
)
tmp
;
}
static
void
stv0297_set_symbolrate
(
struct
stv0297_state
*
state
,
u32
srate
)
{
long
tmp
;
...
...
@@ -259,39 +275,40 @@ static void stv0297_set_carrieroffset(struct stv0297_state* state, long offset)
stv0297_writereg_mask
(
state
,
0x69
,
0x0F
,
(
tmp
>>
24
)
&
0x0f
);
}
/*
static long stv0297_get_carrieroffset(struct stv0297_state* state)
{
s32
raw
;
long
tmp
;
s64 tmp;
stv0297_writereg(state,0x6B, 0x00);
raw
=
stv0297_readreg
(
state
,
0x66
);
raw
|=
(
stv0297_readreg
(
state
,
0x67
)
<<
8
);
raw
|=
(
stv0297_readreg
(
state
,
0x68
)
<<
16
);
raw
|=
(
stv0297_readreg
(
state
,
0x69
)
&
0x0F
)
<<
24
;
tmp = stv0297_readreg(state,
0x66);
tmp |= (stv0297_readreg(state,
0x67) << 8);
tmp |= (stv0297_readreg(state,
0x68) << 16);
tmp |= (stv0297_readreg(state,
0x69) & 0x0F) << 24;
tmp
=
raw
;
tmp
/=
26844L
;
tmp *= stv0297_get_symbolrate(state)
;
tmp
>>= 28
;
return
tmp
;
return
(s32)
tmp;
}
*/
static
void
stv0297_set_initialdemodfreq
(
struct
stv0297_state
*
state
,
long
freq
)
{
/*
s64 tmp;
s32
tmp
;
if (freq > 10000) freq -= STV0297_CLOCK_KHZ;
if
(
freq
>
10000
)
freq
-=
STV0297_CLOCK_KHZ
;
tmp = freq << 16;
do_div(tmp, STV0297_CLOCK_KHZ);
if (tmp > 0xffff) tmp = 0xffff; // check this calculation
tmp
=
(
STV0297_CLOCK_KHZ
*
1000
)
/
(
1
<<
16
);
tmp
=
(
freq
*
1000
)
/
tmp
;
if
(
tmp
>
0xffff
)
tmp
=
0xffff
;
stv0297_writereg_mask
(
state
,
0x25
,
0x80
,
0x80
);
stv0297_writereg
(
state
,
0x21
,
tmp
>>
8
);
stv0297_writereg
(
state
,
0x20
,
tmp
);
*/
}
static
int
stv0297_set_qam
(
struct
stv0297_state
*
state
,
fe_modulation_t
modulation
)
...
...
@@ -413,6 +430,15 @@ static int stv0297_init (struct dvb_frontend* fe)
return
0
;
}
static
int
stv0297_sleep
(
struct
dvb_frontend
*
fe
)
{
struct
stv0297_state
*
state
=
(
struct
stv0297_state
*
)
fe
->
demodulator_priv
;
stv0297_writereg_mask
(
state
,
0x80
,
1
,
1
);
return
0
;
}
static
int
stv0297_read_status
(
struct
dvb_frontend
*
fe
,
fe_status_t
*
status
)
{
struct
stv0297_state
*
state
=
(
struct
stv0297_state
*
)
fe
->
demodulator_priv
;
...
...
@@ -484,6 +510,7 @@ static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
int
carrieroffset
;
unsigned
long
starttime
;
unsigned
long
timeout
;
fe_spectral_inversion_t
inversion
;
switch
(
p
->
u
.
qam
.
modulation
)
{
case
QAM_16
:
...
...
@@ -508,8 +535,11 @@ static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
}
// determine inversion dependant parameters
inversion
=
p
->
inversion
;
if
(
state
->
config
->
invert
)
inversion
=
(
inversion
==
INVERSION_ON
)
?
INVERSION_OFF
:
INVERSION_ON
;
carrieroffset
=
-
330
;
switch
(
p
->
inversion
)
{
switch
(
inversion
)
{
case
INVERSION_OFF
:
break
;
...
...
@@ -522,13 +552,14 @@ static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return
-
EINVAL
;
}
stv0297_init
(
fe
);
state
->
config
->
pll_set
(
fe
,
p
);
/* clear software interrupts */
stv0297_writereg
(
state
,
0x82
,
0x0
);
/* set initial demodulation frequency */
stv0297_set_initialdemodfreq
(
state
,
state
->
freq_off
+
7250
);
stv0297_set_initialdemodfreq
(
state
,
7250
);
/* setup AGC */
stv0297_writereg_mask
(
state
,
0x43
,
0x10
,
0x00
);
...
...
@@ -588,7 +619,7 @@ static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
stv0297_set_symbolrate
(
state
,
p
->
u
.
qam
.
symbol_rate
/
1000
);
stv0297_set_sweeprate
(
state
,
sweeprate
,
p
->
u
.
qam
.
symbol_rate
/
1000
);
stv0297_set_carrieroffset
(
state
,
carrieroffset
);
stv0297_set_inversion
(
state
,
p
->
inversion
);
stv0297_set_inversion
(
state
,
inversion
);
/* kick off lock */
stv0297_writereg_mask
(
state
,
0x88
,
0x08
,
0x08
);
...
...
@@ -664,7 +695,6 @@ static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
/* success!! */
stv0297_writereg_mask
(
state
,
0x5a
,
0x40
,
0x00
);
state
->
freq_off
=
stv0297_get_carrieroffset
(
state
);
state
->
base_freq
=
p
->
frequency
;
return
0
;
...
...
@@ -681,10 +711,12 @@ static int stv0297_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
reg_00
=
stv0297_readreg
(
state
,
0x00
);
reg_83
=
stv0297_readreg
(
state
,
0x83
);
p
->
frequency
=
state
->
base_freq
+
state
->
freq_off
;
p
->
frequency
=
state
->
base_freq
;
p
->
inversion
=
(
reg_83
&
0x08
)
?
INVERSION_ON
:
INVERSION_OFF
;
p
->
u
.
qam
.
symbol_rate
=
0
;
p
->
u
.
qam
.
fec_inner
=
0
;
if
(
state
->
config
->
invert
)
p
->
inversion
=
(
p
->
inversion
==
INVERSION_ON
)
?
INVERSION_OFF
:
INVERSION_ON
;
p
->
u
.
qam
.
symbol_rate
=
stv0297_get_symbolrate
(
state
)
*
1000
;
p
->
u
.
qam
.
fec_inner
=
FEC_NONE
;
switch
((
reg_00
>>
4
)
&
0x7
)
{
case
0
:
...
...
@@ -729,7 +761,6 @@ struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
state
->
config
=
config
;
state
->
i2c
=
i2c
;
memcpy
(
&
state
->
ops
,
&
stv0297_ops
,
sizeof
(
struct
dvb_frontend_ops
));
state
->
freq_off
=
0
;
state
->
base_freq
=
0
;
state
->
pwm
=
pwm
;
...
...
@@ -764,6 +795,7 @@ static struct dvb_frontend_ops stv0297_ops = {
.
release
=
stv0297_release
,
.
init
=
stv0297_init
,
.
sleep
=
stv0297_sleep
,
.
set_frontend
=
stv0297_set_frontend
,
.
get_frontend
=
stv0297_get_frontend
,
...
...
drivers/media/dvb/frontends/stv0297.h
View file @
ca583a3c
...
...
@@ -29,6 +29,9 @@ struct stv0297_config
/* the demodulator's i2c address */
u8
demod_address
;
/* does the "inversion" need inverted? */
u8
invert
:
1
;
/* PLL maintenance */
int
(
*
pll_init
)(
struct
dvb_frontend
*
fe
);
int
(
*
pll_set
)(
struct
dvb_frontend
*
fe
,
struct
dvb_frontend_parameters
*
params
);
...
...
drivers/media/dvb/frontends/tda10021.c
View file @
ca583a3c
...
...
@@ -4,7 +4,7 @@
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
Supp
p
ort for TDA10021
Support for TDA10021
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
...
...
drivers/media/dvb/frontends/tda10021.h
View file @
ca583a3c
...
...
@@ -4,7 +4,7 @@
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
Supp
p
ort for TDA10021
Support for TDA10021
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
...
...
drivers/media/dvb/frontends/tda80xx.c
View file @
ca583a3c
...
...
@@ -27,10 +27,10 @@
#include <linux/spinlock.h>
#include <linux/threads.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
...
...
drivers/media/dvb/ttpci/av7110.c
View file @
ca583a3c
...
...
@@ -67,6 +67,12 @@
#include "av7110_ca.h"
#include "av7110_ipack.h"
#define TS_WIDTH 376
#define TS_HEIGHT 512
#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)
int
av7110_debug
;
static
int
vidmode
=
CVBS_RGB_OUT
;
...
...
@@ -75,6 +81,7 @@ static int adac=DVB_ADAC_TI;
static
int
hw_sections
;
static
int
rgb_on
;
static
int
volume
=
255
;
static
int
budgetpatch
=
0
;
module_param_named
(
debug
,
av7110_debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"debug level (bitmask, default 0)"
);
...
...
@@ -91,6 +98,8 @@ MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control"
" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"
);
module_param
(
volume
,
int
,
0444
);
MODULE_PARM_DESC
(
volume
,
"initial volume: default 255 (range 0-255)"
);
module_param
(
budgetpatch
,
int
,
0444
);
MODULE_PARM_DESC
(
budgetpatch
,
"use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"
);
static
void
restart_feeds
(
struct
av7110
*
av7110
);
...
...
@@ -349,27 +358,42 @@ static inline void print_time(char *s)
#endif
}
#define DEBI_READ 0
#define DEBI_WRITE 1
static
inline
void
start_debi_dma
(
struct
av7110
*
av7110
,
int
dir
,
unsigned
long
addr
,
unsigned
int
len
)
{
dprintk
(
8
,
"%c %08lx %u
\n
"
,
dir
==
DEBI_READ
?
'R'
:
'W'
,
addr
,
len
);
if
(
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
))
{
printk
(
KERN_ERR
"%s: saa7146_wait_for_debi_done timed out
\n
"
,
__FUNCTION__
);
return
;
}
SAA7146_ISR_CLEAR
(
av7110
->
dev
,
MASK_19
);
/* for good measure */
SAA7146_IER_ENABLE
(
av7110
->
dev
,
MASK_19
);
if
(
len
<
5
)
len
=
5
;
/* we want a real DEBI DMA */
if
(
dir
==
DEBI_WRITE
)
iwdebi
(
av7110
,
DEBISWAB
,
addr
,
0
,
(
len
+
3
)
&
~
3
);
else
irdebi
(
av7110
,
DEBISWAB
,
addr
,
0
,
len
);
}
static
void
debiirq
(
unsigned
long
data
)
{
struct
av7110
*
av7110
=
(
struct
av7110
*
)
data
;
int
type
=
av7110
->
debitype
;
int
handle
=
(
type
>>
8
)
&
0x1f
;
// dprintk(4, "%p\n",av7110);
unsigned
int
xfer
=
0
;
print_time
(
"debi"
);
SAA7146_IER_DISABLE
(
av7110
->
dev
,
MASK_19
);
SAA7146_ISR_CLEAR
(
av7110
->
dev
,
MASK_19
);
dprintk
(
4
,
"type 0x%04x
\n
"
,
type
);
if
(
type
==-
1
)
{
printk
(
"DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x
\n
"
,
jiffies
,
saa7146_read
(
av7110
->
dev
,
PSR
),
saa7146_read
(
av7110
->
dev
,
SSR
));
spin_lock
(
&
av7110
->
debilock
);
ARM_ClearMailBox
(
av7110
);
ARM_ClearIrq
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
goto
debi_done
;
}
av7110
->
debitype
=-
1
;
...
...
@@ -379,22 +403,16 @@ static void debiirq (unsigned long data)
dvb_dmx_swfilter_packets
(
&
av7110
->
demux
,
(
const
u8
*
)
av7110
->
debi_virt
,
av7110
->
debilen
/
188
);
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
xfer
=
RX_BUFF
;
break
;
case
DATA_PES_RECORD
:
if
(
av7110
->
demux
.
recording
)
av7110_record_cb
(
&
av7110
->
p2t
[
handle
],
(
u8
*
)
av7110
->
debi_virt
,
av7110
->
debilen
);
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
xfer
=
RX_BUFF
;
break
;
case
DATA_IPMPE
:
case
DATA_FSECTION
:
...
...
@@ -404,11 +422,8 @@ static void debiirq (unsigned long data)
av7110
->
debilen
,
NULL
,
0
,
av7110
->
handle2filter
[
handle
],
DMX_OK
,
av7110
);
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
xfer
=
RX_BUFF
;
break
;
case
DATA_CI_GET
:
{
...
...
@@ -425,11 +440,8 @@ static void debiirq (unsigned long data)
ci_get_data
(
&
av7110
->
ci_rbuffer
,
av7110
->
debi_virt
,
av7110
->
debilen
);
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
xfer
=
RX_BUFF
;
break
;
}
case
DATA_COMMON_INTERFACE
:
...
...
@@ -449,37 +461,35 @@ static void debiirq (unsigned long data)
printk("\n");
}
#endif
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
xfer
=
RX_BUFF
;
break
;
case
DATA_DEBUG_MESSAGE
:
((
s8
*
)
av7110
->
debi_virt
)[
Reserved_SIZE
-
1
]
=
0
;
printk
(
"%s
\n
"
,
(
s8
*
)
av7110
->
debi_virt
);
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
xfer
=
RX_BUFF
;
break
;
case
DATA_CI_PUT
:
dprintk
(
4
,
"debi DATA_CI_PUT
\n
"
);
case
DATA_MPEG_PLAY
:
dprintk
(
4
,
"debi DATA_MPEG_PLAY
\n
"
);
case
DATA_BMP_LOAD
:
spin_lock
(
&
av7110
->
debilock
);
iwdebi
(
av7110
,
DEBINOSWAP
,
TX_BUFF
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
dprintk
(
4
,
"debi DATA_BMP_LOAD
\n
"
);
xfer
=
TX_BUFF
;
break
;
default:
break
;
}
debi_done:
spin_lock
(
&
av7110
->
debilock
);
if
(
xfer
)
iwdebi
(
av7110
,
DEBINOSWAP
,
xfer
,
0
,
2
);
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
}
/* irq from av7110 firmware writing the mailbox register in the DPRAM */
static
void
gpioirq
(
unsigned
long
data
)
{
struct
av7110
*
av7110
=
(
struct
av7110
*
)
data
;
...
...
@@ -487,27 +497,29 @@ static void gpioirq (unsigned long data)
int
len
;
if
(
av7110
->
debitype
!=-
1
)
/* we shouldn't get any irq while a debi xfer is running */
printk
(
"dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x
\n
"
,
jiffies
,
saa7146_read
(
av7110
->
dev
,
PSR
),
saa7146_read
(
av7110
->
dev
,
SSR
));
spin_lock
(
&
av7110
->
debilock
);
if
(
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
))
{
printk
(
KERN_ERR
"%s: saa7146_wait_for_debi_done timed out
\n
"
,
__FUNCTION__
);
BUG
();
/* maybe we should try resetting the debi? */
}
spin_lock
(
&
av7110
->
debilock
);
ARM_ClearIrq
(
av7110
);
SAA7146_IER_DISABLE
(
av7110
->
dev
,
MASK_19
);
SAA7146_ISR_CLEAR
(
av7110
->
dev
,
MASK_19
);
/* see what the av7110 wants */
av7110
->
debitype
=
irdebi
(
av7110
,
DEBINOSWAP
,
IRQ_STATE
,
0
,
2
);
av7110
->
debilen
=
irdebi
(
av7110
,
DEBINOSWAP
,
IRQ_STATE_EXT
,
0
,
2
);
rxbuf
=
irdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
txbuf
=
irdebi
(
av7110
,
DEBINOSWAP
,
TX_BUFF
,
0
,
2
);
len
=
(
av7110
->
debilen
+
3
)
&
~
3
;
// dprintk(8, "GPIO0 irq %d %d\n", av7110->debitype, av7110->debilen);
print_time
(
"gpio"
);
dprintk
(
8
,
"GPIO0 irq 0x%04x %d
\n
"
,
av7110
->
debitype
,
av7110
->
debilen
);
// dprintk(8, "GPIO0 irq %02x\n", av7110->debitype&0xff);
switch
(
av7110
->
debitype
&
0xff
)
{
case
DATA_TS_PLAY
:
...
...
@@ -579,16 +591,12 @@ static void gpioirq (unsigned long data)
dvb_ringbuffer_read
(
cibuf
,
av7110
->
debi_virt
,
len
,
0
);
wake_up
(
&
cibuf
->
queue
);
iwdebi
(
av7110
,
DEBINOSWAP
,
TX_LEN
,
len
,
2
);
iwdebi
(
av7110
,
DEBINOSWAP
,
IRQ_STATE_EXT
,
len
,
2
);
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
);
saa7146_write
(
av7110
->
dev
,
IER
,
saa7146_read
(
av7110
->
dev
,
IER
)
|
MASK_19
);
if
(
len
<
5
)
len
=
5
;
/* we want a real DEBI DMA */
iwdebi
(
av7110
,
DEBISWAB
,
DPRAM_BASE
+
txbuf
,
0
,
(
len
+
3
)
&~
3
);
dprintk
(
8
,
"DMA: CI
\n
"
);
start_debi_dma
(
av7110
,
DEBI_WRITE
,
DPRAM_BASE
+
txbuf
,
len
);
spin_unlock
(
&
av7110
->
debilock
);
wake_up
(
&
cibuf
->
queue
);
return
;
}
...
...
@@ -620,22 +628,21 @@ static void gpioirq (unsigned long data)
dprintk
(
8
,
"GPIO0 PES_PLAY len=%04x
\n
"
,
len
);
iwdebi
(
av7110
,
DEBINOSWAP
,
TX_LEN
,
len
,
2
);
iwdebi
(
av7110
,
DEBINOSWAP
,
IRQ_STATE_EXT
,
len
,
2
);
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
);
saa7146_write
(
av7110
->
dev
,
IER
,
saa7146_read
(
av7110
->
dev
,
IER
)
|
MASK_19
);
iwdebi
(
av7110
,
DEBISWAB
,
DPRAM_BASE
+
txbuf
,
0
,
(
len
+
3
)
&~
3
);
dprintk
(
8
,
"DMA: MPEG_PLAY
\n
"
);
start_debi_dma
(
av7110
,
DEBI_WRITE
,
DPRAM_BASE
+
txbuf
,
len
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
case
DATA_BMP_LOAD
:
len
=
av7110
->
debilen
;
dprintk
(
8
,
"gpio DATA_BMP_LOAD len %d
\n
"
,
len
);
if
(
!
len
)
{
av7110
->
bmp_state
=
BMP_LOADED
;
iwdebi
(
av7110
,
DEBINOSWAP
,
IRQ_STATE_EXT
,
0
,
2
);
iwdebi
(
av7110
,
DEBINOSWAP
,
TX_LEN
,
0
,
2
);
iwdebi
(
av7110
,
DEBINOSWAP
,
TX_BUFF
,
0
,
2
);
wake_up
(
&
av7110
->
bmpq
);
dprintk
(
8
,
"gpio DATA_BMP_LOAD done
\n
"
);
break
;
}
if
(
len
>
av7110
->
bmplen
)
...
...
@@ -647,12 +654,8 @@ static void gpioirq (unsigned long data)
memcpy
(
av7110
->
debi_virt
,
av7110
->
bmpbuf
+
av7110
->
bmpp
,
len
);
av7110
->
bmpp
+=
len
;
av7110
->
bmplen
-=
len
;
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
);
saa7146_write
(
av7110
->
dev
,
IER
,
saa7146_read
(
av7110
->
dev
,
IER
)
|
MASK_19
);
if
(
len
<
5
)
len
=
5
;
/* we want a real DEBI DMA */
iwdebi
(
av7110
,
DEBISWAB
,
DPRAM_BASE
+
txbuf
,
0
,
(
len
+
3
)
&~
3
);
dprintk
(
8
,
"gpio DATA_BMP_LOAD DMA len %d
\n
"
,
len
);
start_debi_dma
(
av7110
,
DEBI_WRITE
,
DPRAM_BASE
+
txbuf
,
len
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
...
...
@@ -669,22 +672,17 @@ static void gpioirq (unsigned long data)
case
DATA_TS_RECORD
:
case
DATA_PES_RECORD
:
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
);
saa7146_write
(
av7110
->
dev
,
IER
,
saa7146_read
(
av7110
->
dev
,
IER
)
|
MASK_19
);
irdebi
(
av7110
,
DEBISWAB
,
DPRAM_BASE
+
rxbuf
,
0
,
len
);
dprintk
(
8
,
"DMA: TS_REC etc.
\n
"
);
start_debi_dma
(
av7110
,
DEBI_READ
,
DPRAM_BASE
+
rxbuf
,
len
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
case
DATA_DEBUG_MESSAGE
:
saa7146_wait_for_debi_done
(
av7110
->
dev
,
0
);
if
(
!
len
||
len
>
0xff
)
{
iwdebi
(
av7110
,
DEBINOSWAP
,
RX_BUFF
,
0
,
2
);
break
;
}
saa7146_write
(
av7110
->
dev
,
IER
,
saa7146_read
(
av7110
->
dev
,
IER
)
|
MASK_19
);
irdebi
(
av7110
,
DEBISWAB
,
Reserved
,
0
,
len
);
start_debi_dma
(
av7110
,
DEBI_READ
,
Reserved
,
len
);
spin_unlock
(
&
av7110
->
debilock
);
return
;
...
...
@@ -699,8 +697,8 @@ static void gpioirq (unsigned long data)
av7110
->
debitype
,
av7110
->
debilen
);
break
;
}
ARM_ClearMailBox
(
av7110
);
av7110
->
debitype
=-
1
;
ARM_ClearMailBox
(
av7110
);
spin_unlock
(
&
av7110
->
debilock
);
}
...
...
@@ -1145,11 +1143,107 @@ static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
return
0
;
}
/* simplified code from budget-core.c */
static
int
stop_ts_capture
(
struct
av7110
*
budget
)
{
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
if
(
--
budget
->
feeding1
)
return
budget
->
feeding1
;
saa7146_write
(
budget
->
dev
,
MC1
,
MASK_20
);
/* DMA3 off */
SAA7146_IER_DISABLE
(
budget
->
dev
,
MASK_10
);
SAA7146_ISR_CLEAR
(
budget
->
dev
,
MASK_10
);
return
0
;
}
static
int
start_ts_capture
(
struct
av7110
*
budget
)
{
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
if
(
budget
->
feeding1
)
return
++
budget
->
feeding1
;
memset
(
budget
->
grabbing
,
0x00
,
TS_HEIGHT
*
TS_WIDTH
);
budget
->
tsf
=
0xff
;
budget
->
ttbp
=
0
;
SAA7146_IER_ENABLE
(
budget
->
dev
,
MASK_10
);
/* VPE */
saa7146_write
(
budget
->
dev
,
MC1
,
(
MASK_04
|
MASK_20
));
/* DMA3 on */
return
++
budget
->
feeding1
;
}
static
int
budget_start_feed
(
struct
dvb_demux_feed
*
feed
)
{
struct
dvb_demux
*
demux
=
feed
->
demux
;
struct
av7110
*
budget
=
(
struct
av7110
*
)
demux
->
priv
;
int
status
;
dprintk
(
2
,
"av7110: %p
\n
"
,
budget
);
spin_lock
(
&
budget
->
feedlock1
);
feed
->
pusi_seen
=
0
;
/* have a clean section start */
status
=
start_ts_capture
(
budget
);
spin_unlock
(
&
budget
->
feedlock1
);
return
status
;
}
static
int
budget_stop_feed
(
struct
dvb_demux_feed
*
feed
)
{
struct
dvb_demux
*
demux
=
feed
->
demux
;
struct
av7110
*
budget
=
(
struct
av7110
*
)
demux
->
priv
;
int
status
;
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
spin_lock
(
&
budget
->
feedlock1
);
status
=
stop_ts_capture
(
budget
);
spin_unlock
(
&
budget
->
feedlock1
);
return
status
;
}
static
void
vpeirq
(
unsigned
long
data
)
{
struct
av7110
*
budget
=
(
struct
av7110
*
)
data
;
u8
*
mem
=
(
u8
*
)
(
budget
->
grabbing
);
u32
olddma
=
budget
->
ttbp
;
u32
newdma
=
saa7146_read
(
budget
->
dev
,
PCI_VDP3
);
if
(
!
budgetpatch
)
{
printk
(
"av7110.c: vpeirq() called while budgetpatch disabled!"
" check saa7146 IER register
\n
"
);
BUG
();
}
/* nearest lower position divisible by 188 */
newdma
-=
newdma
%
188
;
if
(
newdma
>=
TS_BUFLEN
)
return
;
budget
->
ttbp
=
newdma
;
if
(
!
budget
->
feeding1
||
(
newdma
==
olddma
))
return
;
#if 0
/* track rps1 activity */
printk("vpeirq: %02x Event Counter 1 0x%04x\n",
mem[olddma],
saa7146_read(budget->dev, EC1R) & 0x3fff);
#endif
if
(
newdma
>
olddma
)
/* no wraparound, dump olddma..newdma */
dvb_dmx_swfilter_packets
(
&
budget
->
demux1
,
mem
+
olddma
,
(
newdma
-
olddma
)
/
188
);
else
{
/* wraparound, dump olddma..buflen and 0..newdma */
dvb_dmx_swfilter_packets
(
&
budget
->
demux1
,
mem
+
olddma
,
(
TS_BUFLEN
-
olddma
)
/
188
);
dvb_dmx_swfilter_packets
(
&
budget
->
demux1
,
mem
,
newdma
/
188
);
}
}
static
int
av7110_register
(
struct
av7110
*
av7110
)
{
int
ret
,
i
;
struct
dvb_demux
*
dvbdemux
=&
av7110
->
demux
;
struct
dvb_demux
*
dvbdemux1
=
&
av7110
->
demux1
;
dprintk
(
4
,
"%p
\n
"
,
av7110
);
...
...
@@ -1209,6 +1303,32 @@ static int av7110_register(struct av7110 *av7110)
dvb_net_init
(
av7110
->
dvb_adapter
,
&
av7110
->
dvb_net
,
&
dvbdemux
->
dmx
);
if
(
budgetpatch
)
{
/* initialize software demux1 without its own frontend
* demux1 hardware is connected to frontend0 of demux0
*/
dvbdemux1
->
priv
=
(
void
*
)
av7110
;
dvbdemux1
->
filternum
=
256
;
dvbdemux1
->
feednum
=
256
;
dvbdemux1
->
start_feed
=
budget_start_feed
;
dvbdemux1
->
stop_feed
=
budget_stop_feed
;
dvbdemux1
->
write_to_decoder
=
NULL
;
dvbdemux1
->
dmx
.
capabilities
=
(
DMX_TS_FILTERING
|
DMX_SECTION_FILTERING
|
DMX_MEMORY_BASED_FILTERING
);
dvb_dmx_init
(
&
av7110
->
demux1
);
av7110
->
dmxdev1
.
filternum
=
256
;
av7110
->
dmxdev1
.
demux
=
&
dvbdemux1
->
dmx
;
av7110
->
dmxdev1
.
capabilities
=
0
;
dvb_dmxdev_init
(
&
av7110
->
dmxdev1
,
av7110
->
dvb_adapter
);
dvb_net_init
(
av7110
->
dvb_adapter
,
&
av7110
->
dvb_net1
,
&
dvbdemux1
->
dmx
);
printk
(
"dvb-ttpci: additional demux1 for budget-patch registered
\n
"
);
}
return
0
;
}
...
...
@@ -1216,12 +1336,20 @@ static int av7110_register(struct av7110 *av7110)
static
void
dvb_unregister
(
struct
av7110
*
av7110
)
{
struct
dvb_demux
*
dvbdemux
=&
av7110
->
demux
;
struct
dvb_demux
*
dvbdemux1
=
&
av7110
->
demux1
;
dprintk
(
4
,
"%p
\n
"
,
av7110
);
if
(
!
av7110
->
registered
)
return
;
if
(
budgetpatch
)
{
dvb_net_release
(
&
av7110
->
dvb_net1
);
dvbdemux
->
dmx
.
close
(
&
dvbdemux1
->
dmx
);
dvb_dmxdev_release
(
&
av7110
->
dmxdev1
);
dvb_dmx_release
(
&
av7110
->
demux1
);
}
dvb_net_release
(
&
av7110
->
dvb_net
);
dvbdemux
->
dmx
.
close
(
&
dvbdemux
->
dmx
);
...
...
@@ -1700,6 +1828,7 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
static
struct
stv0297_config
nexusca_stv0297_config
=
{
.
demod_address
=
0x1C
,
.
invert
=
1
,
.
pll_set
=
nexusca_stv0297_pll_set
,
};
...
...
@@ -1899,12 +2028,22 @@ static void frontend_init(struct av7110 *av7110)
av7110
->
fe
=
ves1820_attach
(
&
alps_tdbe2_config
,
&
av7110
->
i2c_adap
,
read_pwm
(
av7110
));
break
;
case
0x0006
:
/* Fujitsu-Siemens DVB-S rev 1.6 */
/* Grundig 29504-451 */
av7110
->
fe
=
tda8083_attach
(
&
grundig_29504_451_config
,
&
av7110
->
i2c_adap
);
if
(
av7110
->
fe
)
{
av7110
->
fe
->
ops
->
diseqc_send_master_cmd
=
av7110_diseqc_send_master_cmd
;
av7110
->
fe
->
ops
->
diseqc_send_burst
=
av7110_diseqc_send_burst
;
av7110
->
fe
->
ops
->
set_tone
=
av7110_set_tone
;
}
break
;
case
0x000A
:
// Hauppauge/TT Nexus-CA rev1.X
av7110
->
fe
=
stv0297_attach
(
&
nexusca_stv0297_config
,
&
av7110
->
i2c_adap
,
0x7b
);
if
(
av7110
->
fe
)
{
/* set TDA9819 into DVB mode */
saa7146_setgpio
(
av7110
->
dev
,
1
,
SAA7146_GPIO_OUT
HI
);
// TDA9198 pin9(STD)
saa7146_setgpio
(
av7110
->
dev
,
1
,
SAA7146_GPIO_OUT
LO
);
// TDA9198 pin9(STD)
saa7146_setgpio
(
av7110
->
dev
,
3
,
SAA7146_GPIO_OUTLO
);
// TDA9198 pin30(VIF)
/* tuner on this needs a slower i2c bus speed */
...
...
@@ -1940,13 +2079,169 @@ static void frontend_init(struct av7110 *av7110)
}
}
/* Budgetpatch note:
* Original hardware design by Roberto Deza:
* There is a DVB_Wiki at
* http://212.227.36.83/linuxtv/wiki/index.php/Main_Page
* where is described this 'DVB TT Budget Patch', on Card Modding:
* http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch
* On the short description there is also a link to a external file,
* with more details:
* http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip
*
* New software triggering design by Emard that works on
* original Roberto Deza's hardware:
*
* rps1 code for budgetpatch will copy internal HS event to GPIO3 pin.
* GPIO3 is in budget-patch hardware connectd to port B VSYNC
* HS is an internal event of 7146, accessible with RPS
* and temporarily raised high every n lines
* (n in defined in the RPS_THRESH1 counter threshold)
* I think HS is raised high on the beginning of the n-th line
* and remains high until this n-th line that triggered
* it is completely received. When the receiption of n-th line
* ends, HS is lowered.
*
* To transmit data over DMA, 7146 needs changing state at
* port B VSYNC pin. Any changing of port B VSYNC will
* cause some DMA data transfer, with more or less packets loss.
* It depends on the phase and frequency of VSYNC and
* the way of 7146 is instructed to trigger on port B (defined
* in DD1_INIT register, 3rd nibble from the right valid
* numbers are 0-7, see datasheet)
*
* The correct triggering can minimize packet loss,
* dvbtraffic should give this stable bandwidths:
* 22k transponder = 33814 kbit/s
* 27.5k transponder = 38045 kbit/s
* by experiment it is found that the best results
* (stable bandwidths and almost no packet loss)
* are obtained using DD1_INIT triggering number 2
* (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
* and a VSYNC phase that occurs in the middle of DMA transfer
* (about byte 188*512=96256 in the DMA window).
*
* Phase of HS is still not clear to me how to control,
* It just happens to be so. It can be seen if one enables
* RPS_IRQ and print Event Counter 1 in vpeirq(). Every
* time RPS_INTERRUPT is called, the Event Counter 1 will
* increment. That's how the 7146 is programmed to do event
* counting in this budget-patch.c
* I *think* HPS setting has something to do with the phase
* of HS but I cant be 100% sure in that.
*
* hardware debug note: a working budget card (including budget patch)
* with vpeirq() interrupt setup in mode "0x90" (every 64K) will
* generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
* and that means 3*25=75 Hz of interrupt freqency, as seen by
* watch cat /proc/interrupts
*
* If this frequency is 3x lower (and data received in the DMA
* buffer don't start with 0x47, but in the middle of packets,
* whose lengths appear to be like 188 292 188 104 etc.
* this means VSYNC line is not connected in the hardware.
* (check soldering pcb and pins)
* The same behaviour of missing VSYNC can be duplicated on budget
* cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
*/
static
int
av7110_attach
(
struct
saa7146_dev
*
dev
,
struct
saa7146_pci_extension_data
*
pci_ext
)
{
struct
av7110
*
av7110
=
NULL
;
int
length
=
TS_WIDTH
*
TS_HEIGHT
;
int
ret
=
0
;
int
count
=
0
;
dprintk
(
4
,
"dev: %p
\n
"
,
dev
);
/* Set RPS_IRQ to 1 to track rps1 activity.
* Enabling this won't send any interrupt to PC CPU.
*/
#define RPS_IRQ 0
if
(
budgetpatch
==
1
)
{
budgetpatch
=
0
;
/* autodetect the presence of budget patch
* this only works if saa7146 has been recently
* reset with with MASK_31 to MC1
*
* will wait for VBI_B event (vertical blank at port B)
* and will reset GPIO3 after VBI_B is detected.
* (GPIO3 should be raised high by CPU to
* test if GPIO3 will generate vertical blank signal
* in budget patch GPIO3 is connected to VSYNC_B
*/
/* RESET SAA7146 */
saa7146_write
(
dev
,
MC1
,
MASK_31
);
/* autodetection success seems to be time-dependend after reset */
/* Fix VSYNC level */
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
/* set vsync_b triggering */
saa7146_write
(
dev
,
DD1_STREAM_B
,
0
);
/* port B VSYNC at rising edge */
saa7146_write
(
dev
,
DD1_INIT
,
0x00000200
);
saa7146_write
(
dev
,
BRS_CTRL
,
0x00000000
);
// VBI
saa7146_write
(
dev
,
MC2
,
1
*
(
MASK_08
|
MASK_24
)
|
// BRS control
0
*
(
MASK_09
|
MASK_25
)
|
// a
1
*
(
MASK_10
|
MASK_26
)
|
// b
0
*
(
MASK_06
|
MASK_22
)
|
// HPS_CTRL1
0
*
(
MASK_05
|
MASK_21
)
|
// HPS_CTRL2
0
*
(
MASK_01
|
MASK_15
)
// DEBI
);
/* start writing RPS1 code from beginning */
count
=
0
;
/* Disable RPS1 */
saa7146_write
(
dev
,
MC1
,
MASK_29
);
/* RPS1 timeout disable */
saa7146_write
(
dev
,
RPS_TOV1
,
0
);
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
EVT_VBI_B
));
WRITE_RPS1
(
cpu_to_le32
(
CMD_WR_REG_MASK
|
(
GPIO_CTRL
>>
2
)));
WRITE_RPS1
(
cpu_to_le32
(
GPIO3_MSK
));
WRITE_RPS1
(
cpu_to_le32
(
SAA7146_GPIO_OUTLO
<<
24
));
#if RPS_IRQ
/* issue RPS1 interrupt to increment counter */
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
#endif
WRITE_RPS1
(
cpu_to_le32
(
CMD_STOP
));
/* Jump to begin of RPS program as safety measure (p37) */
WRITE_RPS1
(
cpu_to_le32
(
CMD_JUMP
));
WRITE_RPS1
(
cpu_to_le32
(
dev
->
d_rps1
.
dma_handle
));
#if RPS_IRQ
/* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
* use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
*/
saa7146_write
(
dev
,
EC1SSR
,
(
0x03
<<
2
)
|
3
);
/* set event counter 1 treshold to maximum allowed value (rEC p55) */
saa7146_write
(
dev
,
ECT1R
,
0x3fff
);
#endif
/* Set RPS1 Address register to point to RPS code (r108 p42) */
saa7146_write
(
dev
,
RPS_ADDR1
,
dev
->
d_rps1
.
dma_handle
);
/* Enable RPS1, (rFC p33) */
saa7146_write
(
dev
,
MC1
,
(
MASK_13
|
MASK_29
));
mdelay
(
10
);
/* now send VSYNC_B to rps1 by rising GPIO3 */
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTHI
);
mdelay
(
10
);
/* if rps1 responded by lowering the GPIO3,
* then we have budgetpatch hardware
*/
if
((
saa7146_read
(
dev
,
GPIO_CTRL
)
&
0x10000000
)
==
0
)
{
budgetpatch
=
1
;
printk
(
"dvb-ttpci: BUDGET-PATCH DETECTED.
\n
"
);
}
/* Disable RPS1 */
saa7146_write
(
dev
,
MC1
,
(
MASK_29
));
#if RPS_IRQ
printk
(
"dvb-ttpci: Event Counter 1 0x%04x
\n
"
,
saa7146_read
(
dev
,
EC1R
)
&
0x3fff
);
#endif
}
/* prepare the av7110 device struct */
if
(
!
(
av7110
=
kmalloc
(
sizeof
(
struct
av7110
),
GFP_KERNEL
)))
{
dprintk
(
1
,
"out of memory
\n
"
);
...
...
@@ -1980,6 +2275,7 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
saa7146_i2c_adapter_prepare
(
dev
,
&
av7110
->
i2c_adap
,
SAA7146_I2C_BUS_BIT_RATE_120
);
/* 275 kHz */
if
(
i2c_add_adapter
(
&
av7110
->
i2c_adap
)
<
0
)
{
err_no_mem:
dvb_unregister_adapter
(
av7110
->
dvb_adapter
);
kfree
(
av7110
);
return
-
ENOMEM
;
...
...
@@ -1987,6 +2283,86 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
ttpci_eeprom_parse_mac
(
&
av7110
->
i2c_adap
,
av7110
->
dvb_adapter
->
proposed_mac
);
if
(
budgetpatch
)
{
spin_lock_init
(
&
av7110
->
feedlock1
);
av7110
->
grabbing
=
saa7146_vmalloc_build_pgtable
(
dev
->
pci
,
length
,
&
av7110
->
pt
);
if
(
!
av7110
->
grabbing
)
goto
err_no_mem
;
saa7146_write
(
dev
,
PCI_BT_V1
,
0x1c1f101f
);
saa7146_write
(
dev
,
BCS_CTRL
,
0x80400040
);
/* set dd1 stream a & b */
saa7146_write
(
dev
,
DD1_STREAM_B
,
0x00000000
);
saa7146_write
(
dev
,
DD1_INIT
,
0x03000200
);
saa7146_write
(
dev
,
MC2
,
(
MASK_09
|
MASK_25
|
MASK_10
|
MASK_26
));
saa7146_write
(
dev
,
BRS_CTRL
,
0x60000000
);
saa7146_write
(
dev
,
BASE_ODD3
,
0
);
saa7146_write
(
dev
,
BASE_EVEN3
,
0
);
saa7146_write
(
dev
,
PROT_ADDR3
,
TS_WIDTH
*
TS_HEIGHT
);
saa7146_write
(
dev
,
BASE_PAGE3
,
av7110
->
pt
.
dma
|
ME1
|
0x90
);
saa7146_write
(
dev
,
PITCH3
,
TS_WIDTH
);
saa7146_write
(
dev
,
NUM_LINE_BYTE3
,
(
TS_HEIGHT
<<
16
)
|
TS_WIDTH
);
/* upload all */
saa7146_write
(
dev
,
MC2
,
0x077c077c
);
saa7146_write
(
dev
,
GPIO_CTRL
,
0x000000
);
#if RPS_IRQ
/* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
* use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
*/
saa7146_write
(
dev
,
EC1SSR
,
(
0x03
<<
2
)
|
3
);
/* set event counter 1 treshold to maximum allowed value (rEC p55) */
saa7146_write
(
dev
,
ECT1R
,
0x3fff
);
#endif
/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
count
=
0
;
/* Wait Source Line Counter Threshold (p36) */
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
EVT_HS
));
/* Set GPIO3=1 (p42) */
WRITE_RPS1
(
cpu_to_le32
(
CMD_WR_REG_MASK
|
(
GPIO_CTRL
>>
2
)));
WRITE_RPS1
(
cpu_to_le32
(
GPIO3_MSK
));
WRITE_RPS1
(
cpu_to_le32
(
SAA7146_GPIO_OUTHI
<<
24
));
#if RPS_IRQ
/* issue RPS1 interrupt */
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
#endif
/* Wait reset Source Line Counter Threshold (p36) */
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
RPS_INV
|
EVT_HS
));
/* Set GPIO3=0 (p42) */
WRITE_RPS1
(
cpu_to_le32
(
CMD_WR_REG_MASK
|
(
GPIO_CTRL
>>
2
)));
WRITE_RPS1
(
cpu_to_le32
(
GPIO3_MSK
));
WRITE_RPS1
(
cpu_to_le32
(
SAA7146_GPIO_OUTLO
<<
24
));
#if RPS_IRQ
/* issue RPS1 interrupt */
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
#endif
/* Jump to begin of RPS program (p37) */
WRITE_RPS1
(
cpu_to_le32
(
CMD_JUMP
));
WRITE_RPS1
(
cpu_to_le32
(
dev
->
d_rps1
.
dma_handle
));
/* Fix VSYNC level */
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
/* Set RPS1 Address register to point to RPS code (r108 p42) */
saa7146_write
(
dev
,
RPS_ADDR1
,
dev
->
d_rps1
.
dma_handle
);
/* Set Source Line Counter Threshold, using BRS (rCC p43)
* It generates HS event every TS_HEIGHT lines
* this is related to TS_WIDTH set in register
* NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits
* are set to TS_WIDTH bytes (TS_WIDTH=2*188),
* then RPS_THRESH1 should be set to trigger
* every TS_HEIGHT (512) lines.
*/
saa7146_write
(
dev
,
RPS_THRESH1
,
(
TS_HEIGHT
*
1
)
|
MASK_12
);
/* Enable RPS1 (rFC p33) */
saa7146_write
(
dev
,
MC1
,
(
MASK_13
|
MASK_29
));
/* end of budgetpatch register initialization */
tasklet_init
(
&
av7110
->
vpe_tasklet
,
vpeirq
,
(
unsigned
long
)
av7110
);
}
else
{
saa7146_write
(
dev
,
PCI_BT_V1
,
0x1c00101f
);
saa7146_write
(
dev
,
BCS_CTRL
,
0x80400040
);
...
...
@@ -1998,6 +2374,7 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
/* upload all */
saa7146_write
(
dev
,
MC2
,
0x077c077c
);
saa7146_write
(
dev
,
GPIO_CTRL
,
0x000000
);
}
tasklet_init
(
&
av7110
->
debi_tasklet
,
debiirq
,
(
unsigned
long
)
av7110
);
tasklet_init
(
&
av7110
->
gpio_tasklet
,
gpioirq
,
(
unsigned
long
)
av7110
);
...
...
@@ -2109,10 +2486,21 @@ static int av7110_detach (struct saa7146_dev* saa)
struct
av7110
*
av7110
=
(
struct
av7110
*
)
saa
->
ext_priv
;
dprintk
(
4
,
"%p
\n
"
,
av7110
);
if
(
0
==
av7110
->
device_initialized
)
{
if
(
!
av7110
->
device_initialized
)
return
0
;
}
if
(
budgetpatch
)
{
/* Disable RPS1 */
saa7146_write
(
saa
,
MC1
,
MASK_29
);
/* VSYNC LOW (inactive) */
saa7146_setgpio
(
saa
,
3
,
SAA7146_GPIO_OUTLO
);
saa7146_write
(
saa
,
MC1
,
MASK_20
);
/* DMA3 off */
SAA7146_IER_DISABLE
(
saa
,
MASK_10
);
SAA7146_ISR_CLEAR
(
saa
,
MASK_10
);
msleep
(
50
);
tasklet_kill
(
&
av7110
->
vpe_tasklet
);
saa7146_pgtable_free
(
saa
->
pci
,
&
av7110
->
pt
);
}
av7110_exit_v4l
(
av7110
);
av7110
->
arm_rmmod
=
1
;
...
...
@@ -2121,6 +2509,9 @@ static int av7110_detach (struct saa7146_dev* saa)
while
(
av7110
->
arm_thread
)
msleep
(
1
);
tasklet_kill
(
&
av7110
->
debi_tasklet
);
tasklet_kill
(
&
av7110
->
gpio_tasklet
);
dvb_unregister
(
av7110
);
SAA7146_IER_DISABLE
(
saa
,
MASK_19
|
MASK_03
);
...
...
@@ -2153,13 +2544,43 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
{
struct
av7110
*
av7110
=
dev
->
ext_priv
;
if
(
*
isr
&
MASK_19
)
//print_time("av7110_irq");
/* Note: Don't try to handle the DEBI error irq (MASK_18), in
* intel mode the timeout is asserted all the time...
*/
if
(
*
isr
&
MASK_19
)
{
//printk("av7110_irq: DEBI\n");
/* Note 1: The DEBI irq is level triggered: We must enable it
* only after we started a DMA xfer, and disable it here
* immediately, or it will be signalled all the time while
* DEBI is idle.
* Note 2: You would think that an irq which is masked is
* not signalled by the hardware. Not so for the SAA7146:
* An irq is signalled as long as the corresponding bit
* in the ISR is set, and disabling irqs just prevents the
* hardware from setting the ISR bit. This means a) that we
* must clear the ISR *after* disabling the irq (which is why
* we must do it here even though saa7146_core did it already),
* and b) that if we were to disable an edge triggered irq
* (like the gpio irqs sadly are) temporarily we would likely
* loose some. This sucks :-(
*/
SAA7146_IER_DISABLE
(
av7110
->
dev
,
MASK_19
);
SAA7146_ISR_CLEAR
(
av7110
->
dev
,
MASK_19
);
tasklet_schedule
(
&
av7110
->
debi_tasklet
);
}
if
(
*
isr
&
MASK_03
)
if
(
*
isr
&
MASK_03
)
{
//printk("av7110_irq: GPIO\n");
tasklet_schedule
(
&
av7110
->
gpio_tasklet
);
}
if
((
*
isr
&
MASK_10
)
&&
budgetpatch
)
tasklet_schedule
(
&
av7110
->
vpe_tasklet
);
}
static
struct
saa7146_extension
av7110_extension
;
...
...
@@ -2173,8 +2594,9 @@ MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X");
MAKE_AV7110_INFO
(
ttc_1_X
,
"Technotrend/Hauppauge WinTV Nexus-CA rev1.X"
);
MAKE_AV7110_INFO
(
ttc_2_X
,
"Technotrend/Hauppauge WinTV DVB-C rev2.X"
);
MAKE_AV7110_INFO
(
tts_2_X
,
"Technotrend/Hauppauge WinTV Nexus-S rev2.X"
);
MAKE_AV7110_INFO
(
tts_1_3se
,
"Technotrend/Hauppauge WinTV
Nexus-S rev1.3
"
);
MAKE_AV7110_INFO
(
tts_1_3se
,
"Technotrend/Hauppauge WinTV
DVB-S rev1.3 SE
"
);
MAKE_AV7110_INFO
(
fsc
,
"Fujitsu Siemens DVB-C"
);
MAKE_AV7110_INFO
(
fss
,
"Fujitsu Siemens DVB-S rev1.6"
);
static
struct
pci_device_id
pci_tbl
[]
=
{
MAKE_EXTENSION_PCI
(
tts_1_X
,
0x13c2
,
0x0000
),
...
...
@@ -2184,10 +2606,10 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI
(
tts_1_3se
,
0x13c2
,
0x1002
),
MAKE_EXTENSION_PCI
(
fsc
,
0x110a
,
0x0000
),
MAKE_EXTENSION_PCI
(
ttc_1_X
,
0x13c2
,
0x000a
),
MAKE_EXTENSION_PCI
(
fss
,
0x13c2
,
0x0006
),
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */
// Galaxis DVB PC-Sat-Carte
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */
// Technisat SkyStar1
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */
// TT/Hauppauge WinTV Nexus-S v????
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */
// TT/Hauppauge WinTV DVB-T v????
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */
// TT/Hauppauge WinTV Nexus-CA v????
...
...
@@ -2208,7 +2630,7 @@ static struct saa7146_extension av7110_extension = {
.
attach
=
av7110_attach
,
.
detach
=
av7110_detach
,
.
irq_mask
=
MASK_19
|
MASK_03
,
.
irq_mask
=
MASK_19
|
MASK_03
|
MASK_10
,
.
irq_func
=
av7110_irq
,
};
...
...
drivers/media/dvb/ttpci/av7110.h
View file @
ca583a3c
...
...
@@ -115,7 +115,7 @@ struct av7110 {
int
bmpp
;
int
bmplen
;
int
bmp_state
;
volatile
int
bmp_state
;
#define BMP_NONE 0
#define BMP_LOADING 1
#define BMP_LOADINGS 2
...
...
@@ -158,6 +158,18 @@ struct av7110 {
struct
dmx_frontend
hw_frontend
;
struct
dmx_frontend
mem_frontend
;
/* for budget mode demux1 */
struct
dmxdev
dmxdev1
;
struct
dvb_demux
demux1
;
struct
dvb_net
dvb_net1
;
spinlock_t
feedlock1
;
int
feeding1
;
u8
tsf
;
u32
ttbp
;
unsigned
char
*
grabbing
;
struct
saa7146_pgtable
pt
;
struct
tasklet_struct
vpe_tasklet
;
int
fe_synced
;
struct
semaphore
pid_mutex
;
...
...
drivers/media/dvb/ttpci/av7110_hw.c
View file @
ca583a3c
...
...
@@ -153,8 +153,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
base
=
DRAM_START_CODE
;
for
(
i
=
0
;
i
<
blocks
;
i
++
)
{
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BUFFER_EMPTY
)
<
0
)
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BUFFER_EMPTY
)
<
0
)
{
printk
(
KERN_ERR
"dvb-ttpci: load_dram(): timeout at block %d
\n
"
,
i
);
return
-
1
;
}
dprintk
(
4
,
"writing DRAM block %d
\n
"
,
i
);
mwdebi
(
av7110
,
DEBISWAB
,
bootblock
,
((
char
*
)
data
)
+
i
*
BOOT_MAX_SIZE
,
BOOT_MAX_SIZE
);
...
...
@@ -166,8 +168,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
if
(
rest
>
0
)
{
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BUFFER_EMPTY
)
<
0
)
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BUFFER_EMPTY
)
<
0
)
{
printk
(
KERN_ERR
"dvb-ttpci: load_dram(): timeout at last block
\n
"
);
return
-
1
;
}
if
(
rest
>
4
)
mwdebi
(
av7110
,
DEBISWAB
,
bootblock
,
((
char
*
)
data
)
+
i
*
BOOT_MAX_SIZE
,
rest
);
...
...
@@ -179,12 +183,16 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
iwdebi
(
av7110
,
DEBINOSWAP
,
BOOT_SIZE
,
rest
,
2
);
iwdebi
(
av7110
,
DEBINOSWAP
,
BOOT_STATE
,
BOOTSTATE_BUFFER_FULL
,
2
);
}
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BUFFER_EMPTY
)
<
0
)
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BUFFER_EMPTY
)
<
0
)
{
printk
(
KERN_ERR
"dvb-ttpci: load_dram(): timeout after last block
\n
"
);
return
-
1
;
}
iwdebi
(
av7110
,
DEBINOSWAP
,
BOOT_SIZE
,
0
,
2
);
iwdebi
(
av7110
,
DEBINOSWAP
,
BOOT_STATE
,
BOOTSTATE_BUFFER_FULL
,
2
);
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BOOT_COMPLETE
)
<
0
)
if
(
waitdebi
(
av7110
,
BOOT_STATE
,
BOOTSTATE_BOOT_COMPLETE
)
<
0
)
{
printk
(
KERN_ERR
"dvb-ttpci: load_dram(): final handshake timeout
\n
"
);
return
-
1
;
}
return
0
;
}
...
...
@@ -261,8 +269,11 @@ int av7110_bootarm(struct av7110 *av7110)
mdelay
(
1
);
dprintk
(
1
,
"load dram code
\n
"
);
if
(
load_dram
(
av7110
,
(
u32
*
)
av7110
->
bin_root
,
av7110
->
size_root
)
<
0
)
if
(
load_dram
(
av7110
,
(
u32
*
)
av7110
->
bin_root
,
av7110
->
size_root
)
<
0
)
{
printk
(
KERN_ERR
"dvb-ttpci: av7110_bootarm(): "
"load_dram() failed
\n
"
);
return
-
1
;
}
saa7146_setgpio
(
dev
,
RESET_LINE
,
SAA7146_GPIO_OUTLO
);
mdelay
(
1
);
...
...
@@ -336,7 +347,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if
(
!
av7110
->
arm_ready
)
{
dprintk
(
1
,
"arm not ready.
\n
"
);
return
-
1
;
return
-
ENXIO
;
}
start
=
jiffies
;
...
...
@@ -344,7 +355,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
msleep
(
1
);
if
(
time_after
(
jiffies
,
start
+
ARM_WAIT_FREE
))
{
printk
(
KERN_ERR
"dvb-ttpci: %s(): timeout waiting for COMMAND idle
\n
"
,
__FUNCTION__
);
return
-
1
;
return
-
ETIMEDOUT
;
}
}
...
...
@@ -356,7 +367,7 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
msleep
(
1
);
if
(
time_after
(
jiffies
,
start
+
ARM_WAIT_SHAKE
))
{
printk
(
KERN_ERR
"dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG
\n
"
,
__FUNCTION__
);
return
-
1
;
return
-
ETIMEDOUT
;
}
}
#endif
...
...
@@ -375,6 +386,13 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
flags
[
0
]
=
OSDQOver
;
flags
[
1
]
=
OSDQFull
;
break
;
case
COMTYPE_MISC
:
if
(
FW_VERSION
(
av7110
->
arm_app
)
>=
0x261d
)
{
type
=
"MSG"
;
flags
[
0
]
=
GPMQOver
;
flags
[
1
]
=
GPMQBusy
;
}
break
;
default:
break
;
}
...
...
@@ -419,18 +437,18 @@ int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if
(
time_after
(
jiffies
,
start
+
ARM_WAIT_FREE
))
{
printk
(
KERN_ERR
"dvb-ttpci: %s(): timeout waiting for COMMAND to complete
\n
"
,
__FUNCTION__
);
return
-
1
;
return
-
ETIMEDOUT
;
}
}
stat
=
rdebi
(
av7110
,
DEBINOSWAP
,
MSGSTATE
,
0
,
2
);
if
(
stat
&
GPMQOver
)
{
printk
(
KERN_ERR
"dvb-ttpci: %s(): GPMQOver
\n
"
,
__FUNCTION__
);
return
-
1
;
return
-
ENOSPC
;
}
else
if
(
stat
&
OSDQOver
)
{
printk
(
KERN_ERR
"dvb-ttpci: %s(): OSDQOver
\n
"
,
__FUNCTION__
);
return
-
1
;
return
-
ENOSPC
;
}
#endif
...
...
@@ -453,7 +471,8 @@ int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
ret
=
__av7110_send_fw_cmd
(
av7110
,
buf
,
length
);
up
(
&
av7110
->
dcomlock
);
if
(
ret
)
printk
(
"dvb-ttpci: %s(): av7110_send_fw_cmd error
\n
"
,
__FUNCTION__
);
printk
(
KERN_ERR
"dvb-ttpci: %s(): av7110_send_fw_cmd error %d
\n
"
,
__FUNCTION__
,
ret
);
return
ret
;
}
...
...
@@ -477,7 +496,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
ret
=
av7110_send_fw_cmd
(
av7110
,
buf
,
num
+
2
);
if
(
ret
)
printk
(
"dvb-ttpci: av7110_fw_cmd error
\n
"
);
printk
(
KERN_ERR
"dvb-ttpci: av7110_fw_cmd error %d
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -499,7 +518,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
ret
=
av7110_send_fw_cmd
(
av7110
,
cmd
,
18
);
if
(
ret
)
printk
(
"dvb-ttpci: av7110_send_ci_cmd error
\n
"
);
printk
(
KERN_ERR
"dvb-ttpci: av7110_send_ci_cmd error %d
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -525,7 +544,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
if
((
err
=
__av7110_send_fw_cmd
(
av7110
,
request_buf
,
request_buf_len
))
<
0
)
{
up
(
&
av7110
->
dcomlock
);
printk
(
"dvb-ttpci: av7110_fw_request error
\n
"
);
printk
(
KERN_ERR
"dvb-ttpci: av7110_fw_request error %d
\n
"
,
err
);
return
err
;
}
...
...
@@ -579,7 +598,7 @@ int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
int
ret
;
ret
=
av7110_fw_request
(
av7110
,
&
tag
,
0
,
buf
,
length
);
if
(
ret
)
printk
(
"dvb-ttpci: av7110_fw_query error
\n
"
);
printk
(
KERN_ERR
"dvb-ttpci: av7110_fw_query error %d
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -626,7 +645,7 @@ int av7110_firmversion(struct av7110 *av7110)
int
av7110_diseqc_send
(
struct
av7110
*
av7110
,
int
len
,
u8
*
msg
,
unsigned
long
burst
)
{
int
i
;
int
i
,
ret
;
u16
buf
[
18
]
=
{
((
COMTYPE_AUDIODAC
<<
8
)
+
SendDiSEqC
),
16
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
...
...
@@ -646,8 +665,8 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu
for
(
i
=
0
;
i
<
len
;
i
++
)
buf
[
i
+
4
]
=
msg
[
i
];
if
(
av7110_send_fw_cmd
(
av7110
,
buf
,
18
))
printk
(
"dvb-ttpci: av7110_diseqc_send error
\n
"
);
if
(
(
ret
=
av7110_send_fw_cmd
(
av7110
,
buf
,
18
)
))
printk
(
KERN_ERR
"dvb-ttpci: av7110_diseqc_send error %d
\n
"
,
ret
);
return
0
;
}
...
...
@@ -741,7 +760,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
ret
=
__av7110_send_fw_cmd
(
av7110
,
cbuf
,
5
);
up
(
&
av7110
->
dcomlock
);
if
(
ret
)
printk
(
"dvb-ttpci: WriteText error
\n
"
);
printk
(
KERN_ERR
"dvb-ttpci: WriteText error %d
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -808,7 +827,8 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
ret
=
wait_event_interruptible_timeout
(
av7110
->
bmpq
,
av7110
->
bmp_state
!=
BMP_LOADING
,
HZ
);
if
(
ret
==
-
ERESTARTSYS
||
ret
==
0
)
{
printk
(
"dvb-ttpci: warning: timeout waiting in %s()
\n
"
,
__FUNCTION__
);
printk
(
"dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d
\n
"
,
ret
,
av7110
->
bmp_state
);
av7110
->
bmp_state
=
BMP_NONE
;
return
-
1
;
}
...
...
@@ -850,6 +870,7 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
}
}
av7110
->
bmplen
+=
1024
;
dprintk
(
4
,
"av7110_fw_cmd: LoadBmp size %d
\n
"
,
av7110
->
bmplen
);
return
av7110_fw_cmd
(
av7110
,
COMTYPE_OSD
,
LoadBmp
,
3
,
format
,
dx
,
dy
);
}
...
...
@@ -861,11 +882,13 @@ static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
BUG_ON
(
av7110
->
bmp_state
==
BMP_NONE
);
ret
=
wait_event_interruptible_timeout
(
av7110
->
bmpq
,
av7110
->
bmp_state
!=
BMP_LOADING
,
HZ
);
ret
=
wait_event_interruptible_timeout
(
av7110
->
bmpq
,
av7110
->
bmp_state
!=
BMP_LOADING
,
10
*
HZ
);
if
(
ret
==
-
ERESTARTSYS
||
ret
==
0
)
{
printk
(
"dvb-ttpci: warning: timeout waiting in %s()
\n
"
,
__FUNCTION__
);
printk
(
"dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d
\n
"
,
ret
,
av7110
->
bmp_state
);
av7110
->
bmp_state
=
BMP_NONE
;
return
-
1
;
return
(
ret
==
0
)
?
-
ETIMEDOUT
:
ret
;
}
BUG_ON
(
av7110
->
bmp_state
!=
BMP_LOADED
);
...
...
@@ -943,6 +966,7 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
{
uint
w
,
h
,
bpp
,
bpl
,
size
,
lpb
,
bnum
,
brest
;
int
i
;
int
rc
;
w
=
x1
-
x0
+
1
;
h
=
y1
-
y0
+
1
;
...
...
@@ -958,15 +982,23 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
brest
=
size
-
bnum
*
lpb
*
bpl
;
for
(
i
=
0
;
i
<
bnum
;
i
++
)
{
LoadBitmap
(
av7110
,
bpp2bit
[
av7110
->
osdbpp
[
av7110
->
osdwin
]],
rc
=
LoadBitmap
(
av7110
,
bpp2bit
[
av7110
->
osdbpp
[
av7110
->
osdwin
]],
w
,
lpb
,
inc
,
data
);
BlitBitmap
(
av7110
,
av7110
->
osdwin
,
x0
,
y0
+
i
*
lpb
,
0
);
if
(
rc
)
return
rc
;
rc
=
BlitBitmap
(
av7110
,
av7110
->
osdwin
,
x0
,
y0
+
i
*
lpb
,
0
);
if
(
rc
)
return
rc
;
data
+=
lpb
*
inc
;
}
if
(
brest
)
{
LoadBitmap
(
av7110
,
bpp2bit
[
av7110
->
osdbpp
[
av7110
->
osdwin
]],
rc
=
LoadBitmap
(
av7110
,
bpp2bit
[
av7110
->
osdbpp
[
av7110
->
osdwin
]],
w
,
brest
/
bpl
,
inc
,
data
);
BlitBitmap
(
av7110
,
av7110
->
osdwin
,
x0
,
y0
+
bnum
*
lpb
,
0
);
if
(
rc
)
return
rc
;
rc
=
BlitBitmap
(
av7110
,
av7110
->
osdwin
,
x0
,
y0
+
bnum
*
lpb
,
0
);
if
(
rc
)
return
rc
;
}
ReleaseBitmap
(
av7110
);
return
0
;
...
...
@@ -1019,7 +1051,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
goto
out
;
}
else
{
int
i
,
len
=
dc
->
x0
-
dc
->
color
+
1
;
u8
__user
*
colors
=
(
u8
__user
*
)
dc
->
data
;
u8
__user
*
colors
=
(
u8
*
)
dc
->
data
;
u8
r
,
g
,
b
,
blend
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
...
...
@@ -1048,7 +1080,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
dc
->
y1
=
dc
->
y0
;
/* fall through */
case
OSD_SetBlock
:
OSDSetBlock
(
av7110
,
dc
->
x0
,
dc
->
y0
,
dc
->
x1
,
dc
->
y1
,
dc
->
color
,
dc
->
data
);
ret
=
OSDSetBlock
(
av7110
,
dc
->
x0
,
dc
->
y0
,
dc
->
x1
,
dc
->
y1
,
dc
->
color
,
dc
->
data
);
goto
out
;
case
OSD_FillRow
:
DrawBlock
(
av7110
,
av7110
->
osdwin
,
dc
->
x0
,
dc
->
y0
,
...
...
drivers/media/dvb/ttpci/av7110_v4l.c
View file @
ca583a3c
...
...
@@ -250,7 +250,7 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
if
(
ves1820_writereg
(
dev
,
0x09
,
0x0f
,
0x20
))
dprintk
(
1
,
"setting band in demodulator failed.
\n
"
);
}
else
if
(
av7110
->
analog_tuner_flags
&
ANALOG_TUNER_STV0297
)
{
saa7146_setgpio
(
dev
,
1
,
SAA7146_GPIO_OUT
HI
);
// TDA9198 pin9(STD)
saa7146_setgpio
(
dev
,
1
,
SAA7146_GPIO_OUT
LO
);
// TDA9198 pin9(STD)
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
// TDA9198 pin30(VIF)
}
}
...
...
@@ -591,7 +591,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
if
(
ves1820_writereg
(
av7110
->
dev
,
0x09
,
0x0f
,
0x20
))
dprintk
(
1
,
"setting band in demodulator failed.
\n
"
);
}
else
if
(
av7110
->
analog_tuner_flags
&
ANALOG_TUNER_STV0297
)
{
saa7146_setgpio
(
av7110
->
dev
,
1
,
SAA7146_GPIO_OUT
HI
);
// TDA9198 pin9(STD)
saa7146_setgpio
(
av7110
->
dev
,
1
,
SAA7146_GPIO_OUT
LO
);
// TDA9198 pin9(STD)
saa7146_setgpio
(
av7110
->
dev
,
3
,
SAA7146_GPIO_OUTLO
);
// TDA9198 pin30(VIF)
}
...
...
drivers/media/dvb/ttpci/budget-core.c
View file @
ca583a3c
...
...
@@ -89,11 +89,18 @@ static int start_ts_capture (struct budget *budget)
* Pitch: 188, NumBytes3: 188, NumLines3: 1024
*/
if
(
budget
->
card
->
type
==
BUDGET_FS_ACTIVY
)
{
switch
(
budget
->
card
->
type
)
{
case
BUDGET_FS_ACTIVY
:
saa7146_write
(
dev
,
DD1_INIT
,
0x04000000
);
saa7146_write
(
dev
,
MC2
,
(
MASK_09
|
MASK_25
));
saa7146_write
(
dev
,
BRS_CTRL
,
0x00000000
);
}
else
{
break
;
case
BUDGET_PATCH
:
saa7146_write
(
dev
,
DD1_INIT
,
0x00000200
);
saa7146_write
(
dev
,
MC2
,
(
MASK_10
|
MASK_26
));
saa7146_write
(
dev
,
BRS_CTRL
,
0x60000000
);
break
;
default:
if
(
budget
->
video_port
==
BUDGET_VIDEO_PORTA
)
{
saa7146_write
(
dev
,
DD1_INIT
,
0x06000200
);
saa7146_write
(
dev
,
MC2
,
(
MASK_09
|
MASK_25
|
MASK_10
|
MASK_26
));
...
...
@@ -122,9 +129,10 @@ static int start_ts_capture (struct budget *budget)
}
saa7146_write
(
dev
,
MC2
,
(
MASK_04
|
MASK_20
));
saa7146_write
(
dev
,
MC1
,
(
MASK_04
|
MASK_20
));
// DMA3 on
SAA7146_IER_ENABLE
(
budget
->
dev
,
MASK_10
);
// VPE
SAA7146_ISR_CLEAR
(
budget
->
dev
,
MASK_10
);
/* VPE */
SAA7146_IER_ENABLE
(
budget
->
dev
,
MASK_10
);
/* VPE */
saa7146_write
(
dev
,
MC1
,
(
MASK_04
|
MASK_20
));
/* DMA3 on */
return
++
budget
->
feeding
;
}
...
...
@@ -249,6 +257,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
return
-
EINVAL
;
spin_lock
(
&
budget
->
feedlock
);
feed
->
pusi_seen
=
0
;
/* have a clean section start */
status
=
start_ts_capture
(
budget
);
spin_unlock
(
&
budget
->
feedlock
);
return
status
;
...
...
drivers/media/dvb/ttpci/budget-patch.c
View file @
ca583a3c
...
...
@@ -41,34 +41,127 @@
static
struct
saa7146_extension
budget_extension
;
MAKE_BUDGET_INFO
(
fs_1_3
,
"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch"
,
BUDGET_PATCH
);
MAKE_BUDGET_INFO
(
ttbp
,
"TT-Budget/Patch DVB-S 1.x PCI"
,
BUDGET_PATCH
);
//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
static
struct
pci_device_id
pci_tbl
[]
=
{
MAKE_EXTENSION_PCI
(
fs_1_3
,
0x13c2
,
0x0000
),
MAKE_EXTENSION_PCI
(
ttbp
,
0x13c2
,
0x0000
),
// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
{
.
vendor
=
0
,
}
};
static
int
budget_wdebi
(
struct
budget_patch
*
budget
,
u32
config
,
int
addr
,
u32
val
,
int
count
)
/* those lines are for budget-patch to be tried
** on a true budget card and observe the
** behaviour of VSYNC generated by rps1.
** this code was shamelessly copy/pasted from budget.c
*/
static
void
gpio_Set22K
(
struct
budget
*
budget
,
int
state
)
{
struct
saa7146_dev
*
dev
=
budget
->
dev
;
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
saa7146_setgpio
(
dev
,
3
,
(
state
?
SAA7146_GPIO_OUTHI
:
SAA7146_GPIO_OUTLO
));
}
/* Diseqc functions only for TT Budget card */
/* taken from the Skyvision DVB driver by
Ralph Metzler <rjkm@metzlerbros.de> */
static
void
DiseqcSendBit
(
struct
budget
*
budget
,
int
data
)
{
struct
saa7146_dev
*
dev
=
budget
->
dev
;
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
if
(
count
<=
0
||
count
>
4
)
return
-
1
;
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTHI
);
udelay
(
data
?
500
:
1000
);
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
udelay
(
data
?
1000
:
500
);
}
static
void
DiseqcSendByte
(
struct
budget
*
budget
,
int
data
)
{
int
i
,
par
=
1
,
d
;
saa7146_write
(
dev
,
DEBI_CONFIG
,
config
);
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
saa7146_write
(
dev
,
DEBI_AD
,
val
);
saa7146_write
(
dev
,
DEBI_COMMAND
,
(
count
<<
17
)
|
(
addr
&
0xffff
));
saa7146_write
(
dev
,
MC2
,
(
2
<<
16
)
|
2
);
mdelay
(
5
);
for
(
i
=
7
;
i
>=
0
;
i
--
)
{
d
=
(
data
>>
i
)
&
1
;
par
^=
d
;
DiseqcSendBit
(
budget
,
d
);
}
DiseqcSendBit
(
budget
,
par
);
}
static
int
SendDiSEqCMsg
(
struct
budget
*
budget
,
int
len
,
u8
*
msg
,
unsigned
long
burst
)
{
struct
saa7146_dev
*
dev
=
budget
->
dev
;
int
i
;
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
mdelay
(
16
);
for
(
i
=
0
;
i
<
len
;
i
++
)
DiseqcSendByte
(
budget
,
msg
[
i
]);
mdelay
(
16
);
if
(
burst
!=-
1
)
{
if
(
burst
)
DiseqcSendByte
(
budget
,
0xff
);
else
{
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTHI
);
udelay
(
12500
);
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
}
msleep
(
20
);
}
return
0
;
}
/* shamelessly copy/pasted from budget.c
*/
static
int
budget_set_tone
(
struct
dvb_frontend
*
fe
,
fe_sec_tone_mode_t
tone
)
{
struct
budget
*
budget
=
(
struct
budget
*
)
fe
->
dvb
->
priv
;
switch
(
tone
)
{
case
SEC_TONE_ON
:
gpio_Set22K
(
budget
,
1
);
break
;
case
SEC_TONE_OFF
:
gpio_Set22K
(
budget
,
0
);
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
static
int
budget_diseqc_send_master_cmd
(
struct
dvb_frontend
*
fe
,
struct
dvb_diseqc_master_cmd
*
cmd
)
{
struct
budget
*
budget
=
(
struct
budget
*
)
fe
->
dvb
->
priv
;
SendDiSEqCMsg
(
budget
,
cmd
->
msg_len
,
cmd
->
msg
,
0
);
return
0
;
}
static
int
budget_diseqc_send_burst
(
struct
dvb_frontend
*
fe
,
fe_sec_mini_cmd_t
minicmd
)
{
struct
budget
*
budget
=
(
struct
budget
*
)
fe
->
dvb
->
priv
;
SendDiSEqCMsg
(
budget
,
0
,
NULL
,
minicmd
);
return
0
;
}
static
int
budget_av7110_send_fw_cmd
(
struct
budget_patch
*
budget
,
u16
*
buf
,
int
length
)
{
...
...
@@ -77,14 +170,17 @@ static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
for
(
i
=
2
;
i
<
length
;
i
++
)
budget_wdebi
(
budget
,
DEBINOSWAP
,
COMMAND
+
2
*
i
,
(
u32
)
buf
[
i
],
2
);
{
ttpci_budget_debiwrite
(
budget
,
DEBINOSWAP
,
COMMAND
+
2
*
i
,
2
,
(
u32
)
buf
[
i
],
0
,
0
);
msleep
(
5
);
}
if
(
length
)
budget_wdebi
(
budget
,
DEBINOSWAP
,
COMMAND
+
2
,
(
u32
)
buf
[
1
],
2
);
ttpci_budget_debiwrite
(
budget
,
DEBINOSWAP
,
COMMAND
+
2
,
2
,
(
u32
)
buf
[
1
],
0
,
0
);
else
budget_wdebi
(
budget
,
DEBINOSWAP
,
COMMAND
+
2
,
0
,
2
);
budget_wdebi
(
budget
,
DEBINOSWAP
,
COMMAND
,
(
u32
)
buf
[
0
],
2
);
ttpci_budget_debiwrite
(
budget
,
DEBINOSWAP
,
COMMAND
+
2
,
2
,
0
,
0
,
0
);
msleep
(
5
);
ttpci_budget_debiwrite
(
budget
,
DEBINOSWAP
,
COMMAND
,
2
,
(
u32
)
buf
[
0
],
0
,
0
);
msleep
(
5
);
return
0
;
}
...
...
@@ -319,6 +415,7 @@ static void frontend_init(struct budget_patch* budget)
{
switch
(
budget
->
dev
->
pci
->
subsystem_device
)
{
case
0x0000
:
// Hauppauge/TT WinTV DVB-S rev1.X
case
0x1013
:
// SATELCO Multimedia PCI
// try the ALPS BSRV2 first of all
budget
->
dvb_frontend
=
ves1x93_attach
(
&
alps_bsrv2_config
,
&
budget
->
i2c_adap
);
...
...
@@ -332,18 +429,18 @@ static void frontend_init(struct budget_patch* budget)
// try the ALPS BSRU6 now
budget
->
dvb_frontend
=
stv0299_attach
(
&
alps_bsru6_config
,
&
budget
->
i2c_adap
);
if
(
budget
->
dvb_frontend
)
{
budget
->
dvb_frontend
->
ops
->
diseqc_send_master_cmd
=
budget_
patch_
diseqc_send_master_cmd
;
budget
->
dvb_frontend
->
ops
->
diseqc_send_burst
=
budget_
patch_
diseqc_send_burst
;
budget
->
dvb_frontend
->
ops
->
set_tone
=
budget_
patch_
set_tone
;
budget
->
dvb_frontend
->
ops
->
diseqc_send_master_cmd
=
budget_diseqc_send_master_cmd
;
budget
->
dvb_frontend
->
ops
->
diseqc_send_burst
=
budget_diseqc_send_burst
;
budget
->
dvb_frontend
->
ops
->
set_tone
=
budget_set_tone
;
break
;
}
// Try the grundig 29504-451
budget
->
dvb_frontend
=
tda8083_attach
(
&
grundig_29504_451_config
,
&
budget
->
i2c_adap
);
if
(
budget
->
dvb_frontend
)
{
budget
->
dvb_frontend
->
ops
->
diseqc_send_master_cmd
=
budget_
patch_
diseqc_send_master_cmd
;
budget
->
dvb_frontend
->
ops
->
diseqc_send_burst
=
budget_
patch_
diseqc_send_burst
;
budget
->
dvb_frontend
->
ops
->
set_tone
=
budget_
patch_
set_tone
;
budget
->
dvb_frontend
->
ops
->
diseqc_send_master_cmd
=
budget_diseqc_send_master_cmd
;
budget
->
dvb_frontend
->
ops
->
diseqc_send_burst
=
budget_diseqc_send_burst
;
budget
->
dvb_frontend
->
ops
->
set_tone
=
budget_set_tone
;
break
;
}
break
;
...
...
@@ -365,23 +462,120 @@ static void frontend_init(struct budget_patch* budget)
}
}
/* written by Emard */
static
int
budget_patch_attach
(
struct
saa7146_dev
*
dev
,
struct
saa7146_pci_extension_data
*
info
)
{
struct
budget_patch
*
budget
;
int
err
;
int
count
=
0
;
int
detected
=
0
;
#define PATCH_RESET 0
#define RPS_IRQ 0
#define HPS_SETUP 0
#if PATCH_RESET
saa7146_write
(
dev
,
MC1
,
MASK_31
);
msleep
(
40
);
#endif
#if HPS_SETUP
// initialize registers. Better to have it like this
// than leaving something unconfigured
saa7146_write
(
dev
,
DD1_STREAM_B
,
0
);
// port B VSYNC at rising edge
saa7146_write
(
dev
,
DD1_INIT
,
0x00000200
);
// have this in budget-core too!
saa7146_write
(
dev
,
BRS_CTRL
,
0x00000000
);
// VBI
// debi config
// saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
// zero all HPS registers
saa7146_write
(
dev
,
HPS_H_PRESCALE
,
0
);
// r68
saa7146_write
(
dev
,
HPS_H_SCALE
,
0
);
// r6c
saa7146_write
(
dev
,
BCS_CTRL
,
0
);
// r70
saa7146_write
(
dev
,
HPS_V_SCALE
,
0
);
// r60
saa7146_write
(
dev
,
HPS_V_GAIN
,
0
);
// r64
saa7146_write
(
dev
,
CHROMA_KEY_RANGE
,
0
);
// r74
saa7146_write
(
dev
,
CLIP_FORMAT_CTRL
,
0
);
// r78
// Set HPS prescaler for port B input
saa7146_write
(
dev
,
HPS_CTRL
,
(
1
<<
30
)
|
(
0
<<
29
)
|
(
1
<<
28
)
|
(
0
<<
12
)
);
saa7146_write
(
dev
,
MC2
,
0
*
(
MASK_08
|
MASK_24
)
|
// BRS control
0
*
(
MASK_09
|
MASK_25
)
|
// a
0
*
(
MASK_10
|
MASK_26
)
|
// b
1
*
(
MASK_06
|
MASK_22
)
|
// HPS_CTRL1
1
*
(
MASK_05
|
MASK_21
)
|
// HPS_CTRL2
0
*
(
MASK_01
|
MASK_15
)
// DEBI
);
#endif
// Disable RPS1 and RPS0
saa7146_write
(
dev
,
MC1
,
(
MASK_29
|
MASK_28
));
// RPS1 timeout disable
saa7146_write
(
dev
,
RPS_TOV1
,
0
);
// code for autodetection
// will wait for VBI_B event (vertical blank at port B)
// and will reset GPIO3 after VBI_B is detected.
// (GPIO3 should be raised high by CPU to
// test if GPIO3 will generate vertical blank signal
// in budget patch GPIO3 is connected to VSYNC_B
count
=
0
;
#if 0
WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
#endif
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
EVT_VBI_B
));
WRITE_RPS1
(
cpu_to_le32
(
CMD_WR_REG_MASK
|
(
GPIO_CTRL
>>
2
)));
WRITE_RPS1
(
cpu_to_le32
(
GPIO3_MSK
));
WRITE_RPS1
(
cpu_to_le32
(
SAA7146_GPIO_OUTLO
<<
24
));
#if RPS_IRQ
// issue RPS1 interrupt to increment counter
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
// at least a NOP is neede between two interrupts
WRITE_RPS1
(
cpu_to_le32
(
CMD_NOP
));
// interrupt again
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
#endif
WRITE_RPS1
(
cpu_to_le32
(
CMD_STOP
));
#if RPS_IRQ
// set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
// use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
// use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
saa7146_write
(
dev
,
EC1SSR
,
(
0x03
<<
2
)
|
3
);
// set event counter 1 treshold to maximum allowed value (rEC p55)
saa7146_write
(
dev
,
ECT1R
,
0x3fff
);
#endif
// Fix VSYNC level
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTLO
);
// Set RPS1 Address register to point to RPS code (r108 p42)
saa7146_write
(
dev
,
RPS_ADDR1
,
dev
->
d_rps1
.
dma_handle
);
// Enable RPS1, (rFC p33)
saa7146_write
(
dev
,
MC1
,
(
MASK_13
|
MASK_29
));
if
(
!
(
budget
=
kmalloc
(
sizeof
(
struct
budget_patch
),
GFP_KERNEL
)))
return
-
ENOMEM
;
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
mdelay
(
50
);
saa7146_setgpio
(
dev
,
3
,
SAA7146_GPIO_OUTHI
);
mdelay
(
150
);
if
((
err
=
ttpci_budget_init
(
budget
,
dev
,
info
,
THIS_MODULE
)))
{
kfree
(
budget
);
return
err
;
}
/*
if
(
(
saa7146_read
(
dev
,
GPIO_CTRL
)
&
0x10000000
)
==
0
)
detected
=
1
;
#if RPS_IRQ
printk
(
"Event Counter 1 0x%04x
\n
"
,
saa7146_read
(
dev
,
EC1R
)
&
0x3fff
);
#endif
// Disable RPS1
saa7146_write
(
dev
,
MC1
,
(
MASK_29
));
if
(
detected
==
0
)
printk
(
"budget-patch not detected or saa7146 in non-default state.
\n
"
"try enabling ressetting of 7146 with MASK_31 in MC1 register
\n
"
);
else
printk
(
"BUDGET-PATCH DETECTED.
\n
"
);
/* OLD (Original design by Roberto Deza):
** This code will setup the SAA7146_RPS1 to generate a square
** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
** TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
...
...
@@ -391,26 +585,87 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
** Currently, the TT_budget / WinTV_Nova cards have two ICs
** (74HCT4040, LVC74) for the generation of this VSYNC signal,
** which seems that can be done perfectly without this :-)).
*/
/* New design (By Emard)
** this rps1 code will copy internal HS event to GPIO3 pin.
** GPIO3 is in budget-patch hardware connectd to port B VSYNC
** HS is an internal event of 7146, accessible with RPS
** and temporarily raised high every n lines
** (n in defined in the RPS_THRESH1 counter threshold)
** I think HS is raised high on the beginning of the n-th line
** and remains high until this n-th line that triggered
** it is completely received. When the receiption of n-th line
** ends, HS is lowered.
** To transmit data over DMA, 7146 needs changing state at
** port B VSYNC pin. Any changing of port B VSYNC will
** cause some DMA data transfer, with more or less packets loss.
** It depends on the phase and frequency of VSYNC and
** the way of 7146 is instructed to trigger on port B (defined
** in DD1_INIT register, 3rd nibble from the right valid
** numbers are 0-7, see datasheet)
**
** The correct triggering can minimize packet loss,
** dvbtraffic should give this stable bandwidths:
** 22k transponder = 33814 kbit/s
** 27.5k transponder = 38045 kbit/s
** by experiment it is found that the best results
** (stable bandwidths and almost no packet loss)
** are obtained using DD1_INIT triggering number 2
** (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
** and a VSYNC phase that occurs in the middle of DMA transfer
** (about byte 188*512=96256 in the DMA window).
**
** Phase of HS is still not clear to me how to control,
** It just happens to be so. It can be seen if one enables
** RPS_IRQ and print Event Counter 1 in vpeirq(). Every
** time RPS_INTERRUPT is called, the Event Counter 1 will
** increment. That's how the 7146 is programmed to do event
** counting in this budget-patch.c
** I *think* HPS setting has something to do with the phase
** of HS but I cant be 100% sure in that.
** hardware debug note: a working budget card (including budget patch)
** with vpeirq() interrupt setup in mode "0x90" (every 64K) will
** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
** and that means 3*25=75 Hz of interrupt freqency, as seen by
** watch cat /proc/interrupts
**
** If this frequency is 3x lower (and data received in the DMA
** buffer don't start with 0x47, but in the middle of packets,
** whose lengths appear to be like 188 292 188 104 etc.
** this means VSYNC line is not connected in the hardware.
** (check soldering pcb and pins)
** The same behaviour of missing VSYNC can be duplicated on budget
** cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
*/
// Setup RPS1 "program" (p35)
count
=
0
;
// Wait reset Source Line Counter Threshold (p36)
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
RPS_INV
|
EVT_HS
));
// Wait Source Line Counter Threshold (p36)
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
EVT_HS
));
// Set GPIO3=1 (p42)
WRITE_RPS1
(
cpu_to_le32
(
CMD_WR_REG_MASK
|
(
GPIO_CTRL
>>
2
)));
WRITE_RPS1
(
cpu_to_le32
(
GPIO3_MSK
));
WRITE_RPS1
(
cpu_to_le32
(
SAA7146_GPIO_OUTHI
<<
24
));
#if RPS_IRQ
// issue RPS1 interrupt
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
#endif
// Wait reset Source Line Counter Threshold (p36)
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
RPS_INV
|
EVT_HS
));
// Wait Source Line Counter Threshold
WRITE_RPS1
(
cpu_to_le32
(
CMD_PAUSE
|
EVT_HS
));
// Set GPIO3=0 (p42)
WRITE_RPS1
(
cpu_to_le32
(
CMD_WR_REG_MASK
|
(
GPIO_CTRL
>>
2
)));
WRITE_RPS1
(
cpu_to_le32
(
GPIO3_MSK
));
WRITE_RPS1
(
cpu_to_le32
(
SAA7146_GPIO_OUTLO
<<
24
));
#if RPS_IRQ
// issue RPS1 interrupt
WRITE_RPS1
(
cpu_to_le32
(
CMD_INTERRUPT
));
#endif
// Jump to begin of RPS program (p37)
WRITE_RPS1
(
cpu_to_le32
(
CMD_JUMP
));
WRITE_RPS1
(
cpu_to_le32
(
dev
->
d_rps1
.
dma_handle
));
...
...
@@ -420,10 +675,31 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
// Set RPS1 Address register to point to RPS code (r108 p42)
saa7146_write
(
dev
,
RPS_ADDR1
,
dev
->
d_rps1
.
dma_handle
);
// Set Source Line Counter Threshold, using BRS (rCC p43)
saa7146_write
(
dev
,
RPS_THRESH1
,
((
TS_HEIGHT
/
2
)
|
MASK_12
));
// It generates HS event every TS_HEIGHT lines
// this is related to TS_WIDTH set in register
// NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
// low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
//,then RPS_THRESH1
// should be set to trigger every TS_HEIGHT (512) lines.
//
saa7146_write
(
dev
,
RPS_THRESH1
,
(
TS_HEIGHT
*
1
)
|
MASK_12
);
// saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
// Enable RPS1 (rFC p33)
saa7146_write
(
dev
,
MC1
,
(
MASK_13
|
MASK_29
));
if
(
!
(
budget
=
kmalloc
(
sizeof
(
struct
budget_patch
),
GFP_KERNEL
)))
return
-
ENOMEM
;
dprintk
(
2
,
"budget: %p
\n
"
,
budget
);
if
((
err
=
ttpci_budget_init
(
budget
,
dev
,
info
,
THIS_MODULE
)))
{
kfree
(
budget
);
return
err
;
}
dev
->
ext_priv
=
budget
;
budget
->
dvb_adapter
->
priv
=
budget
;
...
...
drivers/media/dvb/ttpci/budget.c
View file @
ca583a3c
...
...
@@ -414,7 +414,7 @@ static void frontend_init(struct budget *budget)
{
switch
(
budget
->
dev
->
pci
->
subsystem_device
)
{
case
0x1003
:
// Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
case
0x1013
:
// try the ALPS BSRV2 first of all
budget
->
dvb_frontend
=
ves1x93_attach
(
&
alps_bsrv2_config
,
&
budget
->
i2c_adap
);
if
(
budget
->
dvb_frontend
)
{
...
...
@@ -522,14 +522,14 @@ static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO
(
ttbs
,
"TT-Budget/WinTV-NOVA-S PCI"
,
BUDGET_TT
);
MAKE_BUDGET_INFO
(
ttbc
,
"TT-Budget/WinTV-NOVA-C PCI"
,
BUDGET_TT
);
MAKE_BUDGET_INFO
(
ttbt
,
"TT-Budget/WinTV-NOVA-T PCI"
,
BUDGET_TT
);
/* MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */
MAKE_BUDGET_INFO
(
satel
,
"SATELCO Multimedia PCI"
,
BUDGET_TT_HW_DISEQC
);
MAKE_BUDGET_INFO
(
fsacs
,
"Fujitsu Siemens Activy Budget-S PCI"
,
BUDGET_FS_ACTIVY
);
static
struct
pci_device_id
pci_tbl
[]
=
{
MAKE_EXTENSION_PCI
(
ttbs
,
0x13c2
,
0x1003
),
MAKE_EXTENSION_PCI
(
ttbc
,
0x13c2
,
0x1004
),
MAKE_EXTENSION_PCI
(
ttbt
,
0x13c2
,
0x1005
),
/* MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */
MAKE_EXTENSION_PCI
(
satel
,
0x13c2
,
0x1013
),
MAKE_EXTENSION_PCI
(
fsacs
,
0x1131
,
0x4f61
),
{
.
vendor
=
0
,
...
...
drivers/media/dvb/ttusb-dec/ttusb_dec.c
View file @
ca583a3c
...
...
@@ -756,7 +756,7 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
if
(
!
dec
->
iso_stream_count
)
{
for
(
i
=
0
;
i
<
ISO_BUF_COUNT
;
i
++
)
usb_
unlink
_urb
(
dec
->
iso_urb
[
i
]);
usb_
kill
_urb
(
dec
->
iso_urb
[
i
]);
}
up
(
&
dec
->
iso_sem
);
...
...
@@ -821,7 +821,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
"error %d
\n
"
,
__FUNCTION__
,
i
,
result
);
while
(
i
)
{
usb_
unlink
_urb
(
dec
->
iso_urb
[
i
-
1
]);
usb_
kill
_urb
(
dec
->
iso_urb
[
i
-
1
]);
i
--
;
}
...
...
@@ -1379,7 +1379,7 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
dec
->
iso_stream_count
=
0
;
for
(
i
=
0
;
i
<
ISO_BUF_COUNT
;
i
++
)
usb_
unlink
_urb
(
dec
->
iso_urb
[
i
]);
usb_
kill
_urb
(
dec
->
iso_urb
[
i
]);
ttusb_dec_free_iso_urbs
(
dec
);
}
...
...
include/linux/dvb/frontend.h
View file @
ca583a3c
...
...
@@ -158,10 +158,11 @@ typedef enum fe_modulation {
QAM_64
,
QAM_128
,
QAM_256
,
QAM_AUTO
QAM_AUTO
,
VSB_8
,
VSB_16
}
fe_modulation_t
;
typedef
enum
fe_transmit_mode
{
TRANSMISSION_MODE_2K
,
TRANSMISSION_MODE_8K
,
...
...
@@ -206,6 +207,9 @@ struct dvb_qam_parameters {
fe_modulation_t
modulation
;
/* modulation type (see above) */
};
struct
dvb_vsb_parameters
{
fe_modulation_t
modulation
;
/* modulation type (see above) */
};
struct
dvb_ofdm_parameters
{
fe_bandwidth_t
bandwidth
;
...
...
@@ -219,13 +223,14 @@ struct dvb_ofdm_parameters {
struct
dvb_frontend_parameters
{
__u32
frequency
;
/* (absolute) frequency in Hz for QAM/OFDM
*/
__u32
frequency
;
/* (absolute) frequency in Hz for QAM/OFDM/ATSC
*/
/* intermediate frequency in kHz for QPSK */
fe_spectral_inversion_t
inversion
;
union
{
struct
dvb_qpsk_parameters
qpsk
;
struct
dvb_qam_parameters
qam
;
struct
dvb_ofdm_parameters
ofdm
;
struct
dvb_vsb_parameters
vsb
;
}
u
;
};
...
...
include/linux/dvb/version.h
View file @
ca583a3c
...
...
@@ -24,6 +24,7 @@
#define _DVBVERSION_H_
#define DVB_API_VERSION 3
#define DVB_API_VERSION_MINOR 1
#endif
/*_DVBVERSION_H_*/
mm/memory.c
View file @
ca583a3c
...
...
@@ -442,17 +442,18 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
if
(
next
>
end
||
next
<=
addr
)
next
=
end
;
if
(
pgd_none
(
*
src_pgd
))
continue
;
goto
next_pgd
;
if
(
pgd_bad
(
*
src_pgd
))
{
pgd_ERROR
(
*
src_pgd
);
pgd_clear
(
src_pgd
);
continue
;
goto
next_pgd
;
}
err
=
copy_pud_range
(
dst
,
src
,
dst_pgd
,
src_pgd
,
vma
,
addr
,
next
);
if
(
err
)
break
;
next_pgd:
src_pgd
++
;
dst_pgd
++
;
addr
=
next
;
...
...
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