Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (583 commits)
  V4L/DVB (10130): use USB API functions rather than constants
  V4L/DVB (10129): dvb: remove deprecated use of RW_LOCK_UNLOCKED in frontends
  V4L/DVB (10128): modify V4L documentation to be a valid XHTML
  V4L/DVB (10127): stv06xx: Avoid having y unitialized
  V4L/DVB (10125): em28xx: Don't do AC97 vendor detection for i2s audio devices
  V4L/DVB (10124): em28xx: expand output formats available
  V4L/DVB (10123): em28xx: fix reversed definitions of I2S audio modes
  V4L/DVB (10122): em28xx: don't load em28xx-alsa for em2870 based devices
  V4L/DVB (10121): em28xx: remove worthless Pinnacle PCTV HD Mini 80e device profile
  V4L/DVB (10120): em28xx: remove redundant Pinnacle Dazzle DVC 100 profile
  V4L/DVB (10119): em28xx: fix corrupted XCLK value
  V4L/DVB (10118): zoran: fix warning for a variable not used
  V4L/DVB (10116): af9013: Fix gcc false warnings
  V4L/DVB (10111a): usbvideo.h: remove an useless blank line
  V4L/DVB (10111): quickcam_messenger.c: fix a warning
  V4L/DVB (10110): v4l2-ioctl: Fix warnings when using .unlocked_ioctl = __video_ioctl2
  V4L/DVB (10109): anysee: Fix usage of an unitialized function
  V4L/DVB (10104): uvcvideo: Add support for video output devices
  V4L/DVB (10102): uvcvideo: Ignore interrupt endpoint for built-in iSight webcams.
  V4L/DVB (10101): uvcvideo: Fix bulk URB processing when the header is erroneous
  ...
This commit is contained in:
Linus Torvalds 2008-12-30 17:41:32 -08:00
commit f54a6ec0fd
326 changed files with 38310 additions and 11281 deletions

View file

@ -0,0 +1,69 @@
How to set up the Technisat devices
===================================
1) Find out what device you have
================================
First start your linux box with a shipped kernel:
lspci -vvv for a PCI device (lsusb -vvv for an USB device) will show you for example:
02:0b.0 Network controller: Techsan Electronics Co Ltd B2C2 FlexCopII DVB chip / Technisat SkyStar2 DVB card (rev 02)
dmesg | grep frontend may show you for example:
DVB: registering frontend 0 (Conexant CX24123/CX24109)...
2) Kernel compilation:
======================
If the Technisat is the only TV device in your box get rid of unnecessary modules and check this one:
"Multimedia devices" => "Customise analog and hybrid tuner modules to build"
In this directory uncheck every driver which is activated there.
Then please activate:
2a) Main module part:
a.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters"
b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card OR
c.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC USB" in case of an USB 1.1 adapter
d.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Enable debug for the B2C2 FlexCop drivers"
Notice: d.) is helpful for troubleshooting
2b) Frontend module part:
1.) Revision 2.3:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink VP310/MT312/ZL10313 based"
2.) Revision 2.6:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0299 based"
3.) Revision 2.7:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "Samsung S5H1420 based"
c.)"Multimedia devices" => "Customise DVB frontends" => "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
4.) Revision 2.8:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
c.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24123 based"
d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
5.) DVB-T card:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink MT352 based"
6.) DVB-C card:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0297 based"
7.) ATSC card 1st generation:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "Broadcom BCM3510"
8.) ATSC card 2nd generation:
a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
b.)"Multimedia devices" => "Customise DVB frontends" => "NxtWave Communications NXT2002/NXT2004 based"
c.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based"
Author: Uwe Bugla <uwe.bugla@gmx.de> December 2008

View file

@ -1,16 +1,27 @@
<TITLE>V4L API</TITLE>
<H1>Video For Linux APIs</H1>
<table border=0>
<tr>
<td>
<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html>
V4L original API</a>
</td><td>
Obsoleted by V4L2 API
</td></tr><tr><td>
<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API>
V4L2 API</a>
</td><td>
Should be used for new projects
</td></tr>
</table>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta content="text/html;charset=ISO-8859-2" http-equiv="Content-Type" />
<title>V4L API</title>
</head>
<body>
<h1>Video For Linux APIs</h1>
<table border="0">
<tr>
<td>
<a href="http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html">V4L original API</a>
</td>
<td>
Obsoleted by V4L2 API
</td>
</tr>
<tr>
<td>
<a href="http://www.linuxtv.org/downloads/video4linux/API/V4L2_API">V4L2 API</a>
</td>
<td>Should be used for new projects
</td>
</tr>
</table>
</body>
</html>

View file

@ -104,8 +104,8 @@
103 -> Grand X-Guard / Trust 814PCI [0304:0102]
104 -> Nebula Electronics DigiTV [0071:0101]
105 -> ProVideo PV143 [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
106 -> PHYTEC VD-009-X1 MiniDIN (bt878)
107 -> PHYTEC VD-009-X1 Combi (bt878)
106 -> PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)
107 -> PHYTEC VD-009-X1 VD-011 Combi (bt878)
108 -> PHYTEC VD-009 MiniDIN (bt878)
109 -> PHYTEC VD-009 Combi (bt878)
110 -> IVC-100 [ff00:a132]
@ -151,3 +151,6 @@
150 -> Geovision GV-600 [008a:763c]
151 -> Kozumi KTV-01C
152 -> Encore ENL TV-FM-2 [1000:1801]
153 -> PHYTEC VD-012 (bt878)
154 -> PHYTEC VD-012-X1 (bt878)
155 -> PHYTEC VD-012-X2 (bt878)

View file

@ -11,3 +11,4 @@
10 -> DViCO FusionHDTV7 Dual Express [18ac:d618]
11 -> DViCO FusionHDTV DVB-T Dual Express [18ac:db78]
12 -> Leadtek Winfast PxDVR3200 H [107d:6681]
13 -> Compro VideoMate E650F [185b:e800]

View file

@ -2,7 +2,7 @@
1 -> Hauppauge WinTV 34xxx models [0070:3400,0070:3401]
2 -> GDI Black Gold [14c7:0106,14c7:0107]
3 -> PixelView [1554:4811]
4 -> ATI TV Wonder Pro [1002:00f8]
4 -> ATI TV Wonder Pro [1002:00f8,1002:00f9]
5 -> Leadtek Winfast 2000XP Expert [107d:6611,107d:6613]
6 -> AverTV Studio 303 (M126) [1461:000b]
7 -> MSI TV-@nywhere Master [1462:8606]
@ -74,3 +74,6 @@
73 -> TeVii S420 DVB-S [d420:9022]
74 -> Prolink Pixelview Global Extreme [1554:4976]
75 -> PROF 7300 DVB-S/S2 [B033:3033]
76 -> SATTRADE ST4200 DVB-S/S2 [b200:4200]
77 -> TBS 8910 DVB-S [8910:8888]
78 -> Prof 6200 DVB-S [b022:3022]

View file

@ -1,5 +1,5 @@
0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800]
1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2820,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036]
3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208]
4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200,2040:4201]
@ -12,9 +12,9 @@
11 -> Terratec Hybrid XS (em2880) [0ccd:0042]
12 -> Kworld PVR TV 2800 RF (em2820/em2840)
13 -> Terratec Prodigy XS (em2880) [0ccd:0047]
14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) [eb1a:2821]
14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840)
15 -> V-Gear PocketTV (em2800)
16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b,2040:651f]
16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b]
17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227]
18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502]
19 -> PointNix Intra-Oral Camera (em2860)
@ -27,7 +27,6 @@
26 -> Hercules Smart TV USB 2.0 (em2820/em2840)
27 -> Pinnacle PCTV USB 2 (Philips FM1216ME) (em2820/em2840)
28 -> Leadtek Winfast USB II Deluxe (em2820/em2840)
29 -> Pinnacle Dazzle DVC 100 (em2820/em2840)
30 -> Videology 20K14XUSB USB2.0 (em2820/em2840)
31 -> Usbgear VD204v9 (em2821)
32 -> Supercomp USB 2.0 TV (em2821)
@ -57,3 +56,5 @@
56 -> Pinnacle Hybrid Pro (2) (em2882) [2304:0226]
57 -> Kworld PlusTV HD Hybrid 330 (em2883) [eb1a:a316]
58 -> Compro VideoMate ForYou/Stereo (em2820/em2840) [185b:2041]
60 -> Hauppauge WinTV HVR 850 (em2883) [2040:651f]
61 -> Pixelview PlayTV Box 4 USB 2.0 (em2820/em2840)

View file

@ -10,7 +10,7 @@
9 -> Medion 5044
10 -> Kworld/KuroutoShikou SAA7130-TVPCI
11 -> Terratec Cinergy 600 TV [153b:1143]
12 -> Medion 7134 [16be:0003]
12 -> Medion 7134 [16be:0003,16be:5000]
13 -> Typhoon TV+Radio 90031
14 -> ELSA EX-VISION 300TV [1048:226b]
15 -> ELSA EX-VISION 500TV [1048:226a]
@ -151,3 +151,4 @@
150 -> Zogis Real Angel 220
151 -> ADS Tech Instant HDTV [1421:0380]
152 -> Asus Tiger Rev:1.00 [1043:4857]
153 -> Kworld Plus TV Analog Lite PCI [17de:7128]

View file

@ -1,4 +1,3 @@
cx8800 release notes
====================
@ -10,21 +9,20 @@ current status
video
- Basically works.
- Some minor image quality glitches.
- For now only capture, overlay support isn't completed yet.
- For now, only capture and read(). Overlay isn't supported.
audio
- The chip specs for the on-chip TV sound decoder are next
to useless :-/
- Neverless the builtin TV sound decoder starts working now,
at least for PAL-BG. Other TV norms need other code ...
at least for some standards.
FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
USING.
- Most tuner chips do provide mono sound, which may or may not
be useable depending on the board design. With the Hauppauge
cards it works, so there is mono sound available as fallback.
- audio data dma (i.e. recording without loopback cable to the
sound card) should be possible, but there is no code yet ...
sound card) is supported via cx88-alsa.
vbi
- Code present. Works for NTSC closed caption. PAL and other

View file

@ -50,9 +50,14 @@ ov519 045e:028c Micro$oft xbox cam
spca508 0461:0815 Micro Innovation IC200
sunplus 0461:0821 Fujifilm MV-1
zc3xx 0461:0a00 MicroInnovation WebCam320
stv06xx 046d:0840 QuickCam Express
stv06xx 046d:0850 LEGO cam / QuickCam Web
stv06xx 046d:0870 Dexxa WebCam USB
spca500 046d:0890 Logitech QuickCam traveler
vc032x 046d:0892 Logitech Orbicam
vc032x 046d:0896 Logitech Orbicam
vc032x 046d:0897 Logitech QuickCam for Dell notebooks
zc3xx 046d:089d Logitech QuickCam E2500
zc3xx 046d:08a0 Logitech QC IM
zc3xx 046d:08a1 Logitech QC IM 0x08A1 +sound
zc3xx 046d:08a2 Labtec Webcam Pro
@ -169,6 +174,9 @@ spca500 06bd:0404 Agfa CL20
spca500 06be:0800 Optimedia
sunplus 06d6:0031 Trust 610 LCD PowerC@m Zoom
spca506 06e1:a190 ADS Instant VCD
ov534 06f8:3002 Hercules Blog Webcam
ov534 06f8:3003 Hercules Dualpix HD Weblog
sonixj 06f8:3004 Hercules Classic Silver
spca508 0733:0110 ViewQuest VQ110
spca508 0130:0130 Clone Digital Webcam 11043
spca501 0733:0401 Intel Create and Share
@ -199,7 +207,8 @@ sunplus 08ca:2050 Medion MD 41437
sunplus 08ca:2060 Aiptek PocketDV5300
tv8532 0923:010f ICM532 cams
mars 093a:050f Mars-Semi Pc-Camera
pac207 093a:2460 PAC207 Qtec Webcam 100
pac207 093a:2460 Qtec Webcam 100
pac207 093a:2461 HP Webcam
pac207 093a:2463 Philips SPC 220 NC
pac207 093a:2464 Labtec Webcam 1200
pac207 093a:2468 PAC207
@ -213,10 +222,13 @@ pac7311 093a:2603 PAC7312
pac7311 093a:2608 Trust WB-3300p
pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
pac7311 093a:260f SnakeCam
pac7311 093a:2620 Apollo AC-905
pac7311 093a:2621 PAC731x
pac7311 093a:2622 Genius Eye 312
pac7311 093a:2624 PAC7302
pac7311 093a:2626 Labtec 2200
pac7311 093a:262a Webcam 300k
pac7311 093a:262c Philips SPC 230 NC
zc3xx 0ac8:0302 Z-star Vimicro zc0302
vc032x 0ac8:0321 Vimicro generic vc0321
vc032x 0ac8:0323 Vimicro Vc0323
@ -249,11 +261,13 @@ sonixj 0c45:60c0 Sangha Sn535
sonixj 0c45:60ec SN9C105+MO4000
sonixj 0c45:60fb Surfer NoName
sonixj 0c45:60fc LG-LIC300
sonixj 0c45:60fe Microdia Audio
sonixj 0c45:6128 Microdia/Sonix SNP325
sonixj 0c45:612a Avant Camera
sonixj 0c45:612c Typhoon Rasy Cam 1.3MPix
sonixj 0c45:6130 Sonix Pccam
sonixj 0c45:6138 Sn9c120 Mo4000
sonixj 0c45:613a Microdia Sonix PC Camera
sonixj 0c45:613b Surfer SN-206
sonixj 0c45:613c Sonix Pccam168
sonixj 0c45:6143 Sonix Pccam168
@ -263,6 +277,9 @@ etoms 102c:6251 Qcam xxxxxx VGA
zc3xx 10fd:0128 Typhoon Webshot II USB 300k 0x0128
spca561 10fd:7e50 FlyCam Usb 100
zc3xx 10fd:8050 Typhoon Webshot II USB 300k
ov534 1415:2000 Sony HD Eye for PS3 (SLEH 00201)
pac207 145f:013a Trust WB-1300N
vc032x 15b8:6002 HP 2.0 Megapixel rz406aa
spca501 1776:501c Arowana 300K CMOS Camera
t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops
vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC

View file

@ -0,0 +1,520 @@
Overview of the V4L2 driver framework
=====================================
This text documents the various structures provided by the V4L2 framework and
their relationships.
Introduction
------------
The V4L2 drivers tend to be very complex due to the complexity of the
hardware: most devices have multiple ICs, export multiple device nodes in
/dev, and create also non-V4L2 devices such as DVB, ALSA, FB, I2C and input
(IR) devices.
Especially the fact that V4L2 drivers have to setup supporting ICs to
do audio/video muxing/encoding/decoding makes it more complex than most.
Usually these ICs are connected to the main bridge driver through one or
more I2C busses, but other busses can also be used. Such devices are
called 'sub-devices'.
For a long time the framework was limited to the video_device struct for
creating V4L device nodes and video_buf for handling the video buffers
(note that this document does not discuss the video_buf framework).
This meant that all drivers had to do the setup of device instances and
connecting to sub-devices themselves. Some of this is quite complicated
to do right and many drivers never did do it correctly.
There is also a lot of common code that could never be refactored due to
the lack of a framework.
So this framework sets up the basic building blocks that all drivers
need and this same framework should make it much easier to refactor
common code into utility functions shared by all drivers.
Structure of a driver
---------------------
All drivers have the following structure:
1) A struct for each device instance containing the device state.
2) A way of initializing and commanding sub-devices (if any).
3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
/dev/vtxX) and keeping track of device-node specific data.
4) Filehandle-specific structs containing per-filehandle data.
This is a rough schematic of how it all relates:
device instances
|
+-sub-device instances
|
\-V4L2 device nodes
|
\-filehandle instances
Structure of the framework
--------------------------
The framework closely resembles the driver structure: it has a v4l2_device
struct for the device instance data, a v4l2_subdev struct to refer to
sub-device instances, the video_device struct stores V4L2 device node data
and in the future a v4l2_fh struct will keep track of filehandle instances
(this is not yet implemented).
struct v4l2_device
------------------
Each device instance is represented by a struct v4l2_device (v4l2-device.h).
Very simple devices can just allocate this struct, but most of the time you
would embed this struct inside a larger struct.
You must register the device instance:
v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
Registration will initialize the v4l2_device struct and link dev->driver_data
to v4l2_dev. Registration will also set v4l2_dev->name to a value derived from
dev (driver name followed by the bus_id, to be precise). You may change the
name after registration if you want.
The first 'dev' argument is normally the struct device pointer of a pci_dev,
usb_device or platform_device.
You unregister with:
v4l2_device_unregister(struct v4l2_device *v4l2_dev);
Unregistering will also automatically unregister all subdevs from the device.
Sometimes you need to iterate over all devices registered by a specific
driver. This is usually the case if multiple device drivers use the same
hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
hardware. The same is true for alsa drivers for example.
You can iterate over all registered devices as follows:
static int callback(struct device *dev, void *p)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
/* test if this device was inited */
if (v4l2_dev == NULL)
return 0;
...
return 0;
}
int iterate(void *p)
{
struct device_driver *drv;
int err;
/* Find driver 'ivtv' on the PCI bus.
pci_bus_type is a global. For USB busses use usb_bus_type. */
drv = driver_find("ivtv", &pci_bus_type);
/* iterate over all ivtv device instances */
err = driver_for_each_device(drv, NULL, p, callback);
put_driver(drv);
return err;
}
Sometimes you need to keep a running counter of the device instance. This is
commonly used to map a device instance to an index of a module option array.
The recommended approach is as follows:
static atomic_t drv_instance = ATOMIC_INIT(0);
static int __devinit drv_probe(struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
...
state->instance = atomic_inc_return(&drv_instance) - 1;
}
struct v4l2_subdev
------------------
Many drivers need to communicate with sub-devices. These devices can do all
sort of tasks, but most commonly they handle audio and/or video muxing,
encoding or decoding. For webcams common sub-devices are sensors and camera
controllers.
Usually these are I2C devices, but not necessarily. In order to provide the
driver with a consistent interface to these sub-devices the v4l2_subdev struct
(v4l2-subdev.h) was created.
Each sub-device driver must have a v4l2_subdev struct. This struct can be
stand-alone for simple sub-devices or it might be embedded in a larger struct
if more state information needs to be stored. Usually there is a low-level
device struct (e.g. i2c_client) that contains the device data as setup
by the kernel. It is recommended to store that pointer in the private
data of v4l2_subdev using v4l2_set_subdevdata(). That makes it easy to go
from a v4l2_subdev to the actual low-level bus-specific device data.
You also need a way to go from the low-level struct to v4l2_subdev. For the
common i2c_client struct the i2c_set_clientdata() call is used to store a
v4l2_subdev pointer, for other busses you may have to use other methods.
From the bridge driver perspective you load the sub-device module and somehow
obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
i2c_get_clientdata(). For other busses something similar needs to be done.
Helper functions exists for sub-devices on an I2C bus that do most of this
tricky work for you.
Each v4l2_subdev contains function pointers that sub-device drivers can
implement (or leave NULL if it is not applicable). Since sub-devices can do
so many different things and you do not want to end up with a huge ops struct
of which only a handful of ops are commonly implemented, the function pointers
are sorted according to category and each category has its own ops struct.
The top-level ops struct contains pointers to the category ops structs, which
may be NULL if the subdev driver does not support anything from that category.
It looks like this:
struct v4l2_subdev_core_ops {
int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip);
int (*log_status)(struct v4l2_subdev *sd);
int (*init)(struct v4l2_subdev *sd, u32 val);
...
};
struct v4l2_subdev_tuner_ops {
...
};
struct v4l2_subdev_audio_ops {
...
};
struct v4l2_subdev_video_ops {
...
};
struct v4l2_subdev_ops {
const struct v4l2_subdev_core_ops *core;
const struct v4l2_subdev_tuner_ops *tuner;
const struct v4l2_subdev_audio_ops *audio;
const struct v4l2_subdev_video_ops *video;
};
The core ops are common to all subdevs, the other categories are implemented
depending on the sub-device. E.g. a video device is unlikely to support the
audio ops and vice versa.
This setup limits the number of function pointers while still making it easy
to add new ops and categories.
A sub-device driver initializes the v4l2_subdev struct using:
v4l2_subdev_init(subdev, &ops);
Afterwards you need to initialize subdev->name with a unique name and set the
module owner. This is done for you if you use the i2c helper functions.
A device (bridge) driver needs to register the v4l2_subdev with the
v4l2_device:
int err = v4l2_device_register_subdev(device, subdev);
This can fail if the subdev module disappeared before it could be registered.
After this function was called successfully the subdev->dev field points to
the v4l2_device.
You can unregister a sub-device using:
v4l2_device_unregister_subdev(subdev);
Afterwards the subdev module can be unloaded and subdev->dev == NULL.
You can call an ops function either directly:
err = subdev->ops->core->g_chip_ident(subdev, &chip);
but it is better and easier to use this macro:
err = v4l2_subdev_call(subdev, core, g_chip_ident, &chip);
The macro will to the right NULL pointer checks and returns -ENODEV if subdev
is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_chip_ident is
NULL, or the actual result of the subdev->ops->core->g_chip_ident ops.
It is also possible to call all or a subset of the sub-devices:
v4l2_device_call_all(dev, 0, core, g_chip_ident, &chip);
Any subdev that does not support this ops is skipped and error results are
ignored. If you want to check for errors use this:
err = v4l2_device_call_until_err(dev, 0, core, g_chip_ident, &chip);
Any error except -ENOIOCTLCMD will exit the loop with that error. If no
errors (except -ENOIOCTLCMD) occured, then 0 is returned.
The second argument to both calls is a group ID. If 0, then all subdevs are
called. If non-zero, then only those whose group ID match that value will
be called. Before a bridge driver registers a subdev it can set subdev->grp_id
to whatever value it wants (it's 0 by default). This value is owned by the
bridge driver and the sub-device driver will never modify or use it.
The group ID gives the bridge driver more control how callbacks are called.
For example, there may be multiple audio chips on a board, each capable of
changing the volume. But usually only one will actually be used when the
user want to change the volume. You can set the group ID for that subdev to
e.g. AUDIO_CONTROLLER and specify that as the group ID value when calling
v4l2_device_call_all(). That ensures that it will only go to the subdev
that needs it.
The advantage of using v4l2_subdev is that it is a generic struct and does
not contain any knowledge about the underlying hardware. So a driver might
contain several subdevs that use an I2C bus, but also a subdev that is
controlled through GPIO pins. This distinction is only relevant when setting
up the device, but once the subdev is registered it is completely transparent.
I2C sub-device drivers
----------------------
Since these drivers are so common, special helper functions are available to
ease the use of these drivers (v4l2-common.h).
The recommended method of adding v4l2_subdev support to an I2C driver is to
embed the v4l2_subdev struct into the state struct that is created for each
I2C device instance. Very simple devices have no state struct and in that case
you can just create a v4l2_subdev directly.
A typical state struct would look like this (where 'chipname' is replaced by
the name of the chip):
struct chipname_state {
struct v4l2_subdev sd;
... /* additional state fields */
};
Initialize the v4l2_subdev struct as follows:
v4l2_i2c_subdev_init(&state->sd, client, subdev_ops);
This function will fill in all the fields of v4l2_subdev and ensure that the
v4l2_subdev and i2c_client both point to one another.
You should also add a helper inline function to go from a v4l2_subdev pointer
to a chipname_state struct:
static inline struct chipname_state *to_state(struct v4l2_subdev *sd)
{
return container_of(sd, struct chipname_state, sd);
}
Use this to go from the v4l2_subdev struct to the i2c_client struct:
struct i2c_client *client = v4l2_get_subdevdata(sd);
And this to go from an i2c_client to a v4l2_subdev struct:
struct v4l2_subdev *sd = i2c_get_clientdata(client);
Finally you need to make a command function to make driver->command()
call the right subdev_ops functions:
static int subdev_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
If driver->command is never used then you can leave this out. Eventually the
driver->command usage should be removed from v4l.
Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
is called. This will unregister the sub-device from the bridge driver. It is
safe to call this even if the sub-device was never registered.
The bridge driver also has some helper functions it can use:
struct v4l2_subdev *sd = v4l2_i2c_new_subdev(adapter, "module_foo", "chipid", 0x36);
This loads the given module (can be NULL if no module needs to be loaded) and
calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
If all goes well, then it registers the subdev with the v4l2_device. It gets
the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
that adapdata is set to v4l2_device when you setup the i2c_adapter in your
driver.
You can also use v4l2_i2c_new_probed_subdev() which is very similar to
v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
that it should probe. Internally it calls i2c_new_probed_device().
Both functions return NULL if something went wrong.
struct video_device
-------------------
The actual device nodes in the /dev directory are created using the
video_device struct (v4l2-dev.h). This struct can either be allocated
dynamically or embedded in a larger struct.
To allocate it dynamically use:
struct video_device *vdev = video_device_alloc();
if (vdev == NULL)
return -ENOMEM;
vdev->release = video_device_release;
If you embed it in a larger struct, then you must set the release()
callback to your own function:
struct video_device *vdev = &my_vdev->vdev;
vdev->release = my_vdev_release;
The release callback must be set and it is called when the last user
of the video device exits.
The default video_device_release() callback just calls kfree to free the
allocated memory.
You should also set these fields:
- parent: set to the parent device (same device as was used to register
v4l2_device).
- name: set to something descriptive and unique.
- fops: set to the file_operations struct.
- ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
(highly recommended to use this and it might become compulsory in the
future!), then set this to your v4l2_ioctl_ops struct.
If you use v4l2_ioctl_ops, then you should set .unlocked_ioctl to
__video_ioctl2 or .ioctl to video_ioctl2 in your file_operations struct.
video_device registration
-------------------------
Next you register the video device: this will create the character device
for you.
err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (err) {
video_device_release(vdev); // or kfree(my_vdev);
return err;
}
Which device is registered depends on the type argument. The following
types exist:
VFL_TYPE_GRABBER: videoX for video input/output devices
VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
VFL_TYPE_RADIO: radioX for radio tuners
VFL_TYPE_VTX: vtxX for teletext devices (deprecated, don't use)
The last argument gives you a certain amount of control over the device
kernel number used (i.e. the X in videoX). Normally you will pass -1 to
let the v4l2 framework pick the first free number. But if a driver creates
many devices, then it can be useful to have different video devices in
separate ranges. For example, video capture devices start at 0, video
output devices start at 16.
So you can use the last argument to specify a minimum kernel number and
the v4l2 framework will try to pick the first free number that is equal
or higher to what you passed. If that fails, then it will just pick the
first free number.
Whenever a device node is created some attributes are also created for you.
If you look in /sys/class/video4linux you see the devices. Go into e.g.
video0 and you will see 'name' and 'index' attributes. The 'name' attribute
is the 'name' field of the video_device struct. The 'index' attribute is
a device node index that can be assigned by the driver, or that is calculated
for you.
If you call video_register_device(), then the index is just increased by
1 for each device node you register. The first video device node you register
always starts off with 0.
Alternatively you can call video_register_device_index() which is identical
to video_register_device(), but with an extra index argument. Here you can
pass a specific index value (between 0 and 31) that should be used.
Users can setup udev rules that utilize the index attribute to make fancy
device names (e.g. 'mpegX' for MPEG video capture device nodes).
After the device was successfully registered, then you can use these fields:
- vfl_type: the device type passed to video_register_device.
- minor: the assigned device minor number.
- num: the device kernel number (i.e. the X in videoX).
- index: the device index number (calculated or set explicitly using
video_register_device_index).
If the registration failed, then you need to call video_device_release()
to free the allocated video_device struct, or free your own struct if the
video_device was embedded in it. The vdev->release() callback will never
be called if the registration failed, nor should you ever attempt to
unregister the device if the registration failed.
video_device cleanup
--------------------
When the video device nodes have to be removed, either during the unload
of the driver or because the USB device was disconnected, then you should
unregister them:
video_unregister_device(vdev);
This will remove the device nodes from sysfs (causing udev to remove them
from /dev).
After video_unregister_device() returns no new opens can be done.
However, in the case of USB devices some application might still have one
of these device nodes open. You should block all new accesses to read,
write, poll, etc. except possibly for certain ioctl operations like
queueing buffers.
When the last user of the video device node exits, then the vdev->release()
callback is called and you can do the final cleanup there.
video_device helper functions
-----------------------------
There are a few useful helper functions:
You can set/get driver private data in the video_device struct using:
void *video_get_drvdata(struct video_device *dev);
void video_set_drvdata(struct video_device *dev, void *data);
Note that you can safely call video_set_drvdata() before calling
video_register_device().
And this function:
struct video_device *video_devdata(struct file *file);
returns the video_device belonging to the file struct.
The final helper function combines video_get_drvdata with
video_devdata:
void *video_drvdata(struct file *file);
You can go from a video_device struct to the v4l2_device struct using:
struct v4l2_device *v4l2_dev = dev_get_drvdata(vdev->parent);

View file

@ -2391,6 +2391,67 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
/* Kworld Plus TV Analog Lite PCI IR
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
[0x0c] = KEY_PROG1, /* Kworld key */
[0x16] = KEY_CLOSECD, /* -> ) */
[0x1d] = KEY_POWER2,
[0x00] = KEY_1,
[0x01] = KEY_2,
[0x02] = KEY_3, /* Two keys have the same code: 3 and left */
[0x03] = KEY_4, /* Two keys have the same code: 3 and right */
[0x04] = KEY_5,
[0x05] = KEY_6,
[0x06] = KEY_7,
[0x07] = KEY_8,
[0x08] = KEY_9,
[0x0a] = KEY_0,
[0x09] = KEY_AGAIN,
[0x14] = KEY_MUTE,
[0x20] = KEY_UP,
[0x21] = KEY_DOWN,
[0x0b] = KEY_ENTER,
[0x10] = KEY_CHANNELUP,
[0x11] = KEY_CHANNELDOWN,
/* Couldn't map key left/key right since those
conflict with '3' and '4' scancodes
I dunno what the original driver does
*/
[0x13] = KEY_VOLUMEUP,
[0x12] = KEY_VOLUMEDOWN,
/* The lower part of the IR
There are several duplicated keycodes there.
Most of them conflict with digits.
Add mappings just to the unused scancodes.
Somehow, the original driver has a way to know,
but this doesn't seem to be on some GPIO.
Also, it is not related to the time between keyup
and keydown.
*/
[0x19] = KEY_PAUSE, /* Timeshift */
[0x1a] = KEY_STOP,
[0x1b] = KEY_RECORD,
[0x22] = KEY_TEXT,
[0x15] = KEY_AUDIO, /* ((*)) */
[0x0f] = KEY_ZOOM,
[0x1c] = KEY_SHUFFLE, /* snapshot */
[0x18] = KEY_RED, /* B */
[0x23] = KEY_GREEN, /* C */
};
EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
[0x20] = KEY_LIST,
[0x00] = KEY_POWER,
@ -2511,3 +2572,35 @@ IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
/* ATI TV Wonder HD 600 USB
Devin Heitmueller <devin.heitmueller@gmail.com>
*/
IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
[0x00] = KEY_RECORD, /* Row 1 */
[0x01] = KEY_PLAYPAUSE,
[0x02] = KEY_STOP,
[0x03] = KEY_POWER,
[0x04] = KEY_PREVIOUS, /* Row 2 */
[0x05] = KEY_REWIND,
[0x06] = KEY_FORWARD,
[0x07] = KEY_NEXT,
[0x08] = KEY_EPG, /* Row 3 */
[0x09] = KEY_HOME,
[0x0a] = KEY_MENU,
[0x0b] = KEY_CHANNELUP,
[0x0c] = KEY_BACK, /* Row 4 */
[0x0d] = KEY_UP,
[0x0e] = KEY_INFO,
[0x0f] = KEY_CHANNELDOWN,
[0x10] = KEY_LEFT, /* Row 5 */
[0x11] = KEY_SELECT,
[0x12] = KEY_RIGHT,
[0x13] = KEY_VOLUMEUP,
[0x14] = KEY_LAST, /* Row 6 */
[0x15] = KEY_DOWN,
[0x16] = KEY_MUTE,
[0x17] = KEY_VOLUMEDOWN,
};
EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);

View file

@ -313,7 +313,7 @@ static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
/*
DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg));
*/
return video_usercopy(inode, file, cmd, arg, saa7146_video_do_ioctl);
return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
}
static int fops_mmap(struct file *file, struct vm_area_struct * vma)

View file

@ -834,7 +834,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
* copying is done already, arg is a kernel pointer.
*/
static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
@ -1216,17 +1216,11 @@ static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *a
#endif
default:
return v4l_compat_translate_ioctl(file, cmd, arg,
__saa7146_video_do_ioctl);
saa7146_video_do_ioctl);
}
return 0;
}
int saa7146_video_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
return __saa7146_video_do_ioctl(file, cmd, arg);
}
/*********************************************************************************/
/* buffer handling functions */

View file

@ -3598,7 +3598,7 @@ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
76, 77, 91, 134, 135, 137, 147,
156, 166, 167, 168, 25 };
*count = sizeof(RegAddr) / sizeof(u8);
*count = ARRAY_SIZE(RegAddr);
status += MXL_BlockInit(fe);
@ -3630,7 +3630,7 @@ static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
*/
#endif
*count = sizeof(RegAddr) / sizeof(u8);
*count = ARRAY_SIZE(RegAddr);
for (i = 0 ; i < *count; i++) {
RegNum[i] = RegAddr[i];
@ -3648,7 +3648,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
u8 RegAddr[] = {43, 136};
*count = sizeof(RegAddr) / sizeof(u8);
*count = ARRAY_SIZE(RegAddr);
for (i = 0; i < *count; i++) {
RegNum[i] = RegAddr[i];

View file

@ -80,10 +80,11 @@ static void tda827x_set_std(struct dvb_frontend *fe,
mode = "xx";
}
if (params->mode == V4L2_TUNER_RADIO)
if (params->mode == V4L2_TUNER_RADIO) {
priv->sgIF = 88; /* if frequency is 5.5 MHz */
dprintk("setting tda827x to system %s\n", mode);
dprintk("setting tda827x to radio FM\n");
} else
dprintk("setting tda827x to system %s\n", mode);
}
@ -199,7 +200,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
priv->frequency = tuner_freq - if_freq; // FIXME
priv->frequency = params->frequency;
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
@ -304,7 +305,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
reg2[1] = 0x08; /* Vsync en */
i2c_transfer(priv->i2c_adap, &msg, 1);
priv->frequency = freq * 62500;
priv->frequency = params->frequency;
return 0;
}
@ -591,7 +592,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
priv->frequency = tuner_freq - if_freq; // FIXME
priv->frequency = params->frequency;
priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
@ -691,7 +692,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
tuner_reg[1] = 0x19 + (priv->lpsel << 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
priv->frequency = freq * 62500;
priv->frequency = params->frequency;
return 0;
}

View file

@ -32,6 +32,9 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
static int deemphasis_50;
MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
/* ---------------------------------------------------------------------- */
struct tda8290_priv {
@ -139,9 +142,34 @@ static void set_audio(struct dvb_frontend *fe,
mode = "xx";
}
tuner_dbg("setting tda829x to system %s\n", mode);
if (params->mode == V4L2_TUNER_RADIO) {
priv->tda8290_easy_mode = 0x01; /* Start with MN values */
tuner_dbg("setting to radio FM\n");
} else {
tuner_dbg("setting tda829x to system %s\n", mode);
}
}
struct {
unsigned char seq[2];
} fm_mode[] = {
{ { 0x01, 0x81} }, /* Put device into expert mode */
{ { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */
{ { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */
{ { 0x05, 0x04} }, /* ADC headroom */
{ { 0x06, 0x10} }, /* group delay flat */
{ { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */
{ { 0x08, 0x00} },
{ { 0x09, 0x80} },
{ { 0x0a, 0xda} },
{ { 0x0b, 0x4b} },
{ { 0x0c, 0x68} },
{ { 0x0d, 0x00} }, /* PLL off, no video carrier detect */
{ { 0x14, 0x00} }, /* disable auto mute if no video */
};
static void tda8290_set_params(struct dvb_frontend *fe,
struct analog_parameters *params)
{
@ -178,15 +206,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
msleep(1);
expert_mode[1] = priv->tda8290_easy_mode + 0x80;
tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
if (priv->tda8290_easy_mode & 0x60)
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
else
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
if (params->mode == V4L2_TUNER_RADIO) {
int i;
unsigned char deemphasis[] = { 0x13, 1 };
/* FIXME: allow using a different deemphasis */
if (deemphasis_50)
deemphasis[1] = 2;
for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
} else {
expert_mode[1] = priv->tda8290_easy_mode + 0x80;
tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
if (priv->tda8290_easy_mode & 0x60)
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
else
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
}
tda8290_i2c_bridge(fe, 1);

View file

@ -180,11 +180,10 @@ static struct tvnorm tvnorms[] = {
},{
.std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
.name = "SECAM-BGH",
.b = ( cPositiveAmTV |
.b = ( cNegativeFmTV |
cQSS ),
.c = ( cTopDefault),
.e = ( cGating_36 |
cAudioIF_5_5 |
.e = ( cAudioIF_5_5 |
cVideoIF_38_90 ),
},{
.std = V4L2_STD_SECAM_L,

View file

@ -28,6 +28,12 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
static int no_poweroff;
module_param(no_poweroff, int, 0644);
MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
"1 keep device energized and with tuner ready all the times.\n"
" Faster, but consumes more power and keeps the device hotter\n");
static char audio_std[8];
module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
MODULE_PARM_DESC(audio_std,
@ -1091,6 +1097,34 @@ static int xc2028_set_params(struct dvb_frontend *fe,
T_DIGITAL_TV, type, 0, demod);
}
static int xc2028_sleep(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc = 0;
/* Avoid firmware reload on slow devices */
if (no_poweroff)
return 0;
tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
if (debug > 1) {
tuner_dbg("Printing sleep stack trace:\n");
dump_stack();
}
mutex_lock(&priv->lock);
if (priv->firm_version < 0x0202)
rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
else
rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
priv->cur_fw.type = 0; /* need firmware reload */
mutex_unlock(&priv->lock);
return rc;
}
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
@ -1171,6 +1205,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
.sleep = xc2028_sleep,
};
struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,

View file

@ -36,10 +36,6 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
static int xc5000_load_fw_on_attach;
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
static DEFINE_MUTEX(xc5000_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
@ -1017,9 +1013,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
sizeof(struct dvb_tuner_ops));
if (xc5000_load_fw_on_attach)
xc5000_init(fe);
return fe;
fail:
mutex_unlock(&xc5000_list_mutex);

View file

@ -2,6 +2,19 @@
# DVB device configuration
#
config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation"
depends on DVB_CORE
default n
help
If you say Y here, the DVB subsystem will use dynamic minor
allocation for any device that uses the DVB major number.
This means that you can have more than 4 of a single type
of device (like demuxes and frontends) per adapter, but udev
will be required to manage the device nodes.
If you are unsure about this, say N here.
menuconfig DVB_CAPTURE_DRIVERS
bool "DVB/ATSC adapters"
depends on DVB_CORE

View file

@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
help
Support for the digital TV receiver chip made by B2C2 Inc. included in
Technisats PCI cards and USB boxes.

View file

@ -19,7 +19,6 @@
*
*/
#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
@ -368,7 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
{
dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);
return !dm1105dvb->ts_buf;
}
static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)

View file

@ -128,6 +128,7 @@ struct dvb_frontend_private {
unsigned int step_size;
int quality;
unsigned int check_wrapped;
enum dvbfe_search algo_status;
};
static void dvb_frontend_wakeup(struct dvb_frontend *fe);
@ -516,6 +517,8 @@ static int dvb_frontend_thread(void *data)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
fe_status_t s;
enum dvbfe_algo algo;
struct dvb_frontend_parameters *params;
dprintk("%s\n", __func__);
@ -562,23 +565,80 @@ static int dvb_frontend_thread(void *data)
/* do an iteration of the tuning loop */
if (fe->ops.get_frontend_algo) {
if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
/* have we been asked to retune? */
params = NULL;
algo = fe->ops.get_frontend_algo(fe);
switch (algo) {
case DVBFE_ALGO_HW:
dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
params = NULL; /* have we been asked to RETUNE ? */
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
params = &fepriv->parameters;
fepriv->state = FESTATE_TUNED;
}
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status) {
if (fe->ops.tune)
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
dprintk("%s: state changed, adding current state\n", __func__);
dvb_frontend_add_event(fe, s);
fepriv->status = s;
}
} else
break;
case DVBFE_ALGO_SW:
dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
dvb_frontend_swzigzag(fe);
} else
break;
case DVBFE_ALGO_CUSTOM:
params = NULL; /* have we been asked to RETUNE ? */
dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
params = &fepriv->parameters;
fepriv->state = FESTATE_TUNED;
}
/* Case where we are going to search for a carrier
* User asked us to retune again for some reason, possibly
* requesting a search with a new set of parameters
*/
if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
if (fe->ops.search) {
fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
/* We did do a search as was requested, the flags are
* now unset as well and has the flags wrt to search.
*/
} else {
fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
}
}
/* Track the carrier if the search was successful */
if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
if (fe->ops.track)
fe->ops.track(fe, &fepriv->parameters);
} else {
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
fepriv->status = s;
if (!(s & FE_HAS_LOCK)) {
fepriv->delay = HZ / 10;
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
} else {
fepriv->delay = 60 * HZ;
}
}
break;
default:
dprintk("%s: UNDEFINED ALGO !\n", __func__);
break;
}
} else {
dvb_frontend_swzigzag(fe);
}
}
if (dvb_powerdown_on_sleep) {
@ -1226,6 +1286,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
dprintk("%s() Finalised property cache\n", __func__);
dtv_property_cache_submit(fe);
/* Request the search algorithm to search */
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
&fepriv->parameters);
break;

View file

@ -69,6 +69,125 @@ struct analog_parameters {
u64 std;
};
enum dvbfe_modcod {
DVBFE_MODCOD_DUMMY_PLFRAME = 0,
DVBFE_MODCOD_QPSK_1_4,
DVBFE_MODCOD_QPSK_1_3,
DVBFE_MODCOD_QPSK_2_5,
DVBFE_MODCOD_QPSK_1_2,
DVBFE_MODCOD_QPSK_3_5,
DVBFE_MODCOD_QPSK_2_3,
DVBFE_MODCOD_QPSK_3_4,
DVBFE_MODCOD_QPSK_4_5,
DVBFE_MODCOD_QPSK_5_6,
DVBFE_MODCOD_QPSK_8_9,
DVBFE_MODCOD_QPSK_9_10,
DVBFE_MODCOD_8PSK_3_5,
DVBFE_MODCOD_8PSK_2_3,
DVBFE_MODCOD_8PSK_3_4,
DVBFE_MODCOD_8PSK_5_6,
DVBFE_MODCOD_8PSK_8_9,
DVBFE_MODCOD_8PSK_9_10,
DVBFE_MODCOD_16APSK_2_3,
DVBFE_MODCOD_16APSK_3_4,
DVBFE_MODCOD_16APSK_4_5,
DVBFE_MODCOD_16APSK_5_6,
DVBFE_MODCOD_16APSK_8_9,
DVBFE_MODCOD_16APSK_9_10,
DVBFE_MODCOD_32APSK_3_4,
DVBFE_MODCOD_32APSK_4_5,
DVBFE_MODCOD_32APSK_5_6,
DVBFE_MODCOD_32APSK_8_9,
DVBFE_MODCOD_32APSK_9_10,
DVBFE_MODCOD_RESERVED_1,
DVBFE_MODCOD_BPSK_1_3,
DVBFE_MODCOD_BPSK_1_4,
DVBFE_MODCOD_RESERVED_2
};
enum tuner_param {
DVBFE_TUNER_FREQUENCY = (1 << 0),
DVBFE_TUNER_TUNERSTEP = (1 << 1),
DVBFE_TUNER_IFFREQ = (1 << 2),
DVBFE_TUNER_BANDWIDTH = (1 << 3),
DVBFE_TUNER_REFCLOCK = (1 << 4),
DVBFE_TUNER_IQSENSE = (1 << 5),
DVBFE_TUNER_DUMMY = (1 << 31)
};
/*
* ALGO_HW: (Hardware Algorithm)
* ----------------------------------------------------------------
* Devices that support this algorithm do everything in hardware
* and no software support is needed to handle them.
* Requesting these devices to LOCK is the only thing required,
* device is supposed to do everything in the hardware.
*
* ALGO_SW: (Software Algorithm)
* ----------------------------------------------------------------
* These are dumb devices, that require software to do everything
*
* ALGO_CUSTOM: (Customizable Agorithm)
* ----------------------------------------------------------------
* Devices having this algorithm can be customized to have specific
* algorithms in the frontend driver, rather than simply doing a
* software zig-zag. In this case the zigzag maybe hardware assisted
* or it maybe completely done in hardware. In all cases, usage of
* this algorithm, in conjunction with the search and track
* callbacks, utilizes the driver specific algorithm.
*
* ALGO_RECOVERY: (Recovery Algorithm)
* ----------------------------------------------------------------
* These devices have AUTO recovery capabilities from LOCK failure
*/
enum dvbfe_algo {
DVBFE_ALGO_HW = (1 << 0),
DVBFE_ALGO_SW = (1 << 1),
DVBFE_ALGO_CUSTOM = (1 << 2),
DVBFE_ALGO_RECOVERY = (1 << 31)
};
struct tuner_state {
u32 frequency;
u32 tunerstep;
u32 ifreq;
u32 bandwidth;
u32 iqsense;
u32 refclock;
};
/*
* search callback possible return status
*
* DVBFE_ALGO_SEARCH_SUCCESS
* The frontend search algorithm completed and returned succesfully
*
* DVBFE_ALGO_SEARCH_ASLEEP
* The frontend search algorithm is sleeping
*
* DVBFE_ALGO_SEARCH_FAILED
* The frontend search for a signal failed
*
* DVBFE_ALGO_SEARCH_INVALID
* The frontend search algorith was probably supplied with invalid
* parameters and the search is an invalid one
*
* DVBFE_ALGO_SEARCH_ERROR
* The frontend search algorithm failed due to some error
*
* DVBFE_ALGO_SEARCH_AGAIN
* The frontend search algorithm was requested to search again
*/
enum dvbfe_search {
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
};
struct dvb_tuner_ops {
struct dvb_tuner_info info;
@ -99,6 +218,13 @@ struct dvb_tuner_ops {
* tuners which require sophisticated tuning loops, controlling each parameter seperately. */
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
/*
* These are provided seperately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter seperately.
*/
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
};
struct analog_demod_info {
@ -142,7 +268,7 @@ struct dvb_frontend_ops {
unsigned int *delay,
fe_status_t *status);
/* get frontend tuning algorithm from the module */
int (*get_frontend_algo)(struct dvb_frontend *fe);
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
/* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@ -167,6 +293,12 @@ struct dvb_frontend_ops {
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
/* These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple swzigzag
*/
enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
struct dvb_tuner_ops tuner_ops;
struct analog_demod_ops analog_ops;

View file

@ -50,33 +50,27 @@ static const char * const dnames[] = {
"net", "osd"
};
#ifdef CONFIG_DVB_DYNAMIC_MINORS
#define MAX_DVB_MINORS 256
#define DVB_MAX_IDS MAX_DVB_MINORS
#else
#define DVB_MAX_IDS 4
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
#endif
static struct class *dvb_class;
static struct dvb_device* dvbdev_find_device (int minor)
{
struct dvb_adapter *adap;
list_for_each_entry(adap, &dvb_adapter_list, list_head) {
struct dvb_device *dev;
list_for_each_entry(dev, &adap->device_list, list_head)
if (nums2minor(adap->num, dev->type, dev->id) == minor)
return dev;
}
return NULL;
}
static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev;
lock_kernel();
dvbdev = dvbdev_find_device (iminor(inode));
down_read(&minor_rwsem);
dvbdev = dvb_minors[iminor(inode)];
if (dvbdev && dvbdev->fops) {
int err = 0;
@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
up_read(&minor_rwsem);
unlock_kernel();
return err;
}
up_read(&minor_rwsem);
unlock_kernel();
return -ENODEV;
}
@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
struct device *clsdev;
int minor;
int id;
mutex_lock(&dvbdev_register_lock);
@ -231,11 +228,31 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
list_add_tail (&dvbdev->list_head, &adap->device_list);
down_write(&minor_rwsem);
#ifdef CONFIG_DVB_DYNAMIC_MINORS
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (dvb_minors[minor] == NULL)
break;
if (minor == MAX_DVB_MINORS) {
kfree(dvbdevfops);
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -EINVAL;
}
#else
minor = nums2minor(adap->num, type, id);
#endif
dvbdev->minor = minor;
dvb_minors[minor] = dvbdev;
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock);
clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
}
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
nums2minor(adap->num, type, id));
adap->num, dnames[type], id, minor, minor);
return 0;
}
@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
if (!dvbdev)
return;
device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
dvbdev->type, dvbdev->id)));
down_write(&minor_rwsem);
dvb_minors[dvbdev->minor] = NULL;
up_write(&minor_rwsem);
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head);
kfree (dvbdev->fops);
@ -413,6 +432,15 @@ int dvb_usercopy(struct inode *inode, struct file *file,
return err;
}
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct dvb_device *dvbdev = dev_get_drvdata(dev);
add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
return 0;
}
static int __init init_dvbdev(void)
{
int retval;
@ -434,6 +462,7 @@ static int __init init_dvbdev(void)
retval = PTR_ERR(dvb_class);
goto error;
}
dvb_class->dev_uevent = dvb_uevent;
return 0;
error:

View file

@ -74,6 +74,7 @@ struct dvb_device {
struct file_operations *fops;
struct dvb_adapter *adapter;
int type;
int minor;
u32 id;
/* in theory, 'users' can vanish now,

View file

@ -733,9 +733,19 @@ static int af9015_read_config(struct usb_device *udev)
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_mygictv);
break;
case AF9015_REMOTE_DIGITTRADE_DVB_T:
af9015_properties[i].rc_key_map =
af9015_rc_keys_digittrade;
af9015_properties[i].rc_key_map_size =
ARRAY_SIZE(af9015_rc_keys_digittrade);
af9015_config.ir_table =
af9015_ir_table_digittrade;
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_digittrade);
break;
}
} else {
switch (udev->descriptor.idVendor) {
switch (le16_to_cpu(udev->descriptor.idVendor)) {
case USB_VID_LEADTEK:
af9015_properties[i].rc_key_map =
af9015_rc_keys_leadtek;
@ -748,7 +758,7 @@ static int af9015_read_config(struct usb_device *udev)
break;
case USB_VID_VISIONPLUS:
if (udev->descriptor.idProduct ==
USB_PID_AZUREWAVE_AD_TU700) {
cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) {
af9015_properties[i].rc_key_map =
af9015_rc_keys_twinhan;
af9015_properties[i].rc_key_map_size =
@ -800,6 +810,16 @@ static int af9015_read_config(struct usb_device *udev)
ARRAY_SIZE(af9015_ir_table_msi);
}
break;
case USB_VID_AVERMEDIA:
af9015_properties[i].rc_key_map =
af9015_rc_keys_avermedia;
af9015_properties[i].rc_key_map_size =
ARRAY_SIZE(af9015_rc_keys_avermedia);
af9015_config.ir_table =
af9015_ir_table_avermedia;
af9015_config.ir_table_size =
ARRAY_SIZE(af9015_ir_table_avermedia);
break;
}
}
}
@ -1191,6 +1211,7 @@ static struct usb_device_id af9015_usb_table[] = {
{USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)},
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@ -1343,7 +1364,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 6,
.num_device_descs = 7,
.devices = {
{
.name = "Xtensions XD-380",
@ -1375,6 +1396,12 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[15], NULL},
.warm_ids = {NULL},
},
{
.name = "KWorld USB DVB-T TV Stick II " \
"(VS-DVB-T 395U)",
.cold_ids = {&af9015_usb_table[16], NULL},
.warm_ids = {NULL},
},
}
}
};

View file

@ -123,6 +123,7 @@ enum af9015_remote {
AF9015_REMOTE_A_LINK_DTU_M,
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
AF9015_REMOTE_MYGICTV_U718,
AF9015_REMOTE_DIGITTRADE_DVB_T,
};
/* Leadtek WinFast DTV Dongle Gold */
@ -520,4 +521,143 @@ static u8 af9015_ir_table_kworld[] = {
0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
};
/* AverMedia Volar X */
static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
{ 0x05, 0x3d, KEY_PROG1 }, /* SOURCE */
{ 0x05, 0x12, KEY_POWER }, /* POWER */
{ 0x05, 0x1e, KEY_1 }, /* 1 */
{ 0x05, 0x1f, KEY_2 }, /* 2 */
{ 0x05, 0x20, KEY_3 }, /* 3 */
{ 0x05, 0x21, KEY_4 }, /* 4 */
{ 0x05, 0x22, KEY_5 }, /* 5 */
{ 0x05, 0x23, KEY_6 }, /* 6 */
{ 0x05, 0x24, KEY_7 }, /* 7 */
{ 0x05, 0x25, KEY_8 }, /* 8 */
{ 0x05, 0x26, KEY_9 }, /* 9 */
{ 0x05, 0x3f, KEY_LEFT }, /* L / DISPLAY */
{ 0x05, 0x27, KEY_0 }, /* 0 */
{ 0x05, 0x0f, KEY_RIGHT }, /* R / CH RTN */
{ 0x05, 0x18, KEY_PROG2 }, /* SNAP SHOT */
{ 0x05, 0x1c, KEY_PROG3 }, /* 16-CH PREV */
{ 0x05, 0x2d, KEY_VOLUMEDOWN }, /* VOL DOWN */
{ 0x05, 0x3e, KEY_ZOOM }, /* FULL SCREEN */
{ 0x05, 0x2e, KEY_VOLUMEUP }, /* VOL UP */
{ 0x05, 0x10, KEY_MUTE }, /* MUTE */
{ 0x05, 0x04, KEY_AUDIO }, /* AUDIO */
{ 0x05, 0x15, KEY_RECORD }, /* RECORD */
{ 0x05, 0x11, KEY_PLAY }, /* PLAY */
{ 0x05, 0x16, KEY_STOP }, /* STOP */
{ 0x05, 0x0c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
{ 0x05, 0x05, KEY_BACK }, /* << / RED */
{ 0x05, 0x09, KEY_FORWARD }, /* >> / YELLOW */
{ 0x05, 0x17, KEY_TEXT }, /* TELETEXT */
{ 0x05, 0x0a, KEY_EPG }, /* EPG */
{ 0x05, 0x13, KEY_MENU }, /* MENU */
{ 0x05, 0x0e, KEY_CHANNELUP }, /* CH UP */
{ 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */
{ 0x05, 0x19, KEY_FIRST }, /* |<< / GREEN */
{ 0x05, 0x08, KEY_LAST }, /* >>| / BLUE */
};
static u8 af9015_ir_table_avermedia[] = {
0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
};
/* Digittrade DVB-T USB Stick */
static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
{ 0x01, 0x0f, KEY_LAST }, /* RETURN */
{ 0x05, 0x17, KEY_TEXT }, /* TELETEXT */
{ 0x01, 0x08, KEY_EPG }, /* EPG */
{ 0x05, 0x13, KEY_POWER }, /* POWER */
{ 0x01, 0x09, KEY_ZOOM }, /* FULLSCREEN */
{ 0x00, 0x40, KEY_AUDIO }, /* DUAL SOUND */
{ 0x00, 0x2c, KEY_PRINT }, /* SNAPSHOT */
{ 0x05, 0x16, KEY_SUBTITLE }, /* SUBTITLE */
{ 0x00, 0x52, KEY_CHANNELUP }, /* CH Up */
{ 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */
{ 0x00, 0x57, KEY_VOLUMEUP }, /* Vol Up */
{ 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */
{ 0x01, 0x10, KEY_MUTE }, /* MUTE */
{ 0x00, 0x27, KEY_0 },
{ 0x00, 0x1e, KEY_1 },
{ 0x00, 0x1f, KEY_2 },
{ 0x00, 0x20, KEY_3 },
{ 0x00, 0x21, KEY_4 },
{ 0x00, 0x22, KEY_5 },
{ 0x00, 0x23, KEY_6 },
{ 0x00, 0x24, KEY_7 },
{ 0x00, 0x25, KEY_8 },
{ 0x00, 0x26, KEY_9 },
{ 0x01, 0x17, KEY_PLAYPAUSE }, /* TIMESHIFT */
{ 0x01, 0x15, KEY_RECORD }, /* RECORD */
{ 0x03, 0x13, KEY_PLAY }, /* PLAY */
{ 0x01, 0x16, KEY_STOP }, /* STOP */
{ 0x01, 0x13, KEY_PAUSE }, /* PAUSE */
};
static u8 af9015_ir_table_digittrade[] = {
0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
};
#endif

View file

@ -153,7 +153,7 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int ret, inc, i = 0;
int ret = 0, inc, i = 0;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;

View file

@ -32,7 +32,6 @@
/* debug */
int dvb_usb_cinergyt2_debug;
int disable_remote;
module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
@ -45,7 +44,7 @@ struct cinergyt2_state {
};
/* We are missing a release hook with usb_device data */
struct dvb_usb_device *cinergyt2_usb_device;
static struct dvb_usb_device *cinergyt2_usb_device;
static struct dvb_usb_device_properties cinergyt2_properties;

View file

@ -70,11 +70,11 @@ struct dvbt_get_status_msg {
uint8_t bandwidth;
uint16_t tps;
uint8_t flags;
uint16_t gain;
__le16 gain;
uint8_t snr;
uint32_t viterbi_error_rate;
__le32 viterbi_error_rate;
uint32_t rs_error_rate;
uint32_t uncorrected_block_count;
__le32 uncorrected_block_count;
uint8_t lock_bits;
uint8_t prev_lock_bits;
} __attribute__((packed));
@ -82,9 +82,9 @@ struct dvbt_get_status_msg {
struct dvbt_set_parameters_msg {
uint8_t cmd;
uint32_t freq;
__le32 freq;
uint8_t bandwidth;
uint16_t tps;
__le16 tps;
uint8_t flags;
} __attribute__((packed));

View file

@ -96,6 +96,7 @@
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_399U 0xe399
#define USB_PID_KWORLD_395U 0xe396
#define USB_PID_KWORLD_PC160_2T 0xc160
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df

View file

@ -9,7 +9,6 @@
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include <linux/version.h>
#include "dw2102.h"
#include "si21xx.h"
#include "stv0299.h"
@ -27,6 +26,10 @@
#define USB_PID_DW2104 0x2104
#endif
#ifndef USB_PID_CINERGY_S
#define USB_PID_CINERGY_S 0x0064
#endif
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@ -578,6 +581,7 @@ static struct usb_device_id dw2102_table[] = {
{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
{USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
{USB_DEVICE(0x9022, 0xd650)},
{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
{ }
};
@ -647,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
DW210X_WRITE_MSG);
break;
case USB_PID_CINERGY_S:
case USB_PID_DW2102:
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
DW210X_WRITE_MSG);
@ -655,7 +660,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* check STV0299 frontend */
dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
DW210X_READ_MSG);
if (reset16[0] == 0xa1) {
if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
break;
@ -726,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
},
}
},
.num_device_descs = 2,
.num_device_descs = 3,
.devices = {
{"DVBWorld DVB-S 2102 USB2.0",
{&dw2102_table[0], NULL},
@ -736,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = {
{&dw2102_table[1], NULL},
{NULL},
},
{"TerraTec Cinergy S USB",
{&dw2102_table[4], NULL},
{NULL},
},
}
};

View file

@ -25,6 +25,20 @@ struct gp8psk_fe_state {
unsigned long status_check_interval;
};
static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
{
struct gp8psk_fe_state *st = fe->demodulator_priv;
u8 status;
gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
return status & bmDCtuned;
}
static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
{
struct gp8psk_fe_state *state = fe->demodulator_priv;
return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
}
static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
{
u8 buf[6];
@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
return 0;
}
static int gp8psk_fe_set_property(struct dvb_frontend *fe,
struct dtv_property *tvp)
{
deb_fe("%s(..)\n", __func__);
return 0;
}
static int gp8psk_fe_get_property(struct dvb_frontend *fe,
struct dtv_property *tvp)
{
deb_fe("%s(..)\n", __func__);
return 0;
}
static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct gp8psk_fe_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u8 cmd[10];
u32 freq = fep->frequency * 1000;
int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
deb_fe("%s()\n", __func__);
cmd[4] = freq & 0xff;
cmd[5] = (freq >> 8) & 0xff;
cmd[6] = (freq >> 16) & 0xff;
cmd[7] = (freq >> 24) & 0xff;
switch(fe->ops.info.type) {
case FE_QPSK:
cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
cmd[8] = ADV_MOD_DVB_QPSK;
cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
switch (c->delivery_system) {
case SYS_DVBS:
/* Only QPSK is supported for DVB-S */
if (c->modulation != QPSK) {
deb_fe("%s: unsupported modulation selected (%d)\n",
__func__, c->modulation);
return -EOPNOTSUPP;
}
c->fec_inner = FEC_AUTO;
break;
case SYS_DVBS2:
deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
break;
default:
// other modes are unsuported right now
cmd[0] = 0;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[8] = 0;
cmd[9] = 0;
break;
deb_fe("%s: unsupported delivery system selected (%d)\n",
__func__, c->delivery_system);
return -EOPNOTSUPP;
}
gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
cmd[0] = c->symbol_rate & 0xff;
cmd[1] = (c->symbol_rate >> 8) & 0xff;
cmd[2] = (c->symbol_rate >> 16) & 0xff;
cmd[3] = (c->symbol_rate >> 24) & 0xff;
switch (c->modulation) {
case QPSK:
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
if (gp8psk_tuned_to_DCII(fe))
gp8psk_bcm4500_reload(state->d);
switch (c->fec_inner) {
case FEC_1_2:
cmd[9] = 0; break;
case FEC_2_3:
cmd[9] = 1; break;
case FEC_3_4:
cmd[9] = 2; break;
case FEC_5_6:
cmd[9] = 3; break;
case FEC_7_8:
cmd[9] = 4; break;
case FEC_AUTO:
cmd[9] = 5; break;
default:
cmd[9] = 5; break;
}
cmd[8] = ADV_MOD_DVB_QPSK;
break;
case PSK_8: /* PSK_8 is for compatibility with DN */
cmd[8] = ADV_MOD_TURBO_8PSK;
switch (c->fec_inner) {
case FEC_2_3:
cmd[9] = 0; break;
case FEC_3_4:
cmd[9] = 1; break;
case FEC_3_5:
cmd[9] = 2; break;
case FEC_5_6:
cmd[9] = 3; break;
case FEC_8_9:
cmd[9] = 4; break;
default:
cmd[9] = 0; break;
}
break;
case QAM_16: /* QAM_16 is for compatibility with DN */
cmd[8] = ADV_MOD_TURBO_16QAM;
cmd[9] = 0;
break;
default: /* Unknown modulation */
deb_fe("%s: unsupported modulation selected (%d)\n",
__func__, c->modulation);
return -EOPNOTSUPP;
}
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
gp8psk_set_tuner_mode(fe, 0);
gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
state->lock = 0;
state->next_status_check = jiffies;
@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
return 0;
}
static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
return 0;
}
static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.symbol_rate_max = 45000000,
.symbol_rate_tolerance = 500, /* ppm */
.caps = FE_CAN_INVERSION_AUTO |
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_QPSK
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_QAM_16 is for compatibility
* (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
*/
FE_CAN_QPSK | FE_CAN_QAM_16
},
.release = gp8psk_fe_release,
@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.init = NULL,
.sleep = NULL,
.set_property = gp8psk_fe_set_property,
.get_property = gp8psk_fe_get_property,
.set_frontend = gp8psk_fe_set_frontend,
.get_frontend = gp8psk_fe_get_frontend,
.get_tune_settings = gp8psk_fe_get_tune_settings,
.read_status = gp8psk_fe_read_status,

View file

@ -174,6 +174,22 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
{
u8 buf;
int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
/* Turn off 8psk power */
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
return -EINVAL;
/* Turn On 8psk power */
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
return -EINVAL;
/* load BCM4500 firmware */
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
if (gp8psk_load_bcm4500fw(d))
return EINVAL;
return 0;
}
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{

View file

@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen);
extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
#endif

View file

@ -156,7 +156,8 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
stream->props.u.bulk.buffersize,
usb_urb_complete, stream);
stream->urb_list[i]->transfer_flags = 0;
stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
stream->urbs_initialized++;
}
return 0;

View file

@ -12,6 +12,25 @@ config DVB_FE_CUSTOMISE
If unsure say N.
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
config DVB_STB0899
tristate "STB0899 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
to support this demodulator based frontends
config DVB_STB6100
tristate "STB6100 based tuners"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A Silicon tuner from ST used in conjunction with the STB0899
demodulator. Say Y when you want to support this tuner.
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
@ -78,6 +97,13 @@ config DVB_TDA10086
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA8261
tristate "Philips TDA8261 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_VES1X93
tristate "VLSI VES1893 or VES1993 based"
depends on DVB_CORE && I2C
@ -92,6 +118,14 @@ config DVB_TUNER_ITD1000
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TUNER_CX24113
tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA826X
tristate "Philips TDA826X silicon tuner"
depends on DVB_CORE && I2C
@ -345,6 +379,14 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_LGDT3304
tristate "LG Electronics LGDT3304"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_S5H1409
tristate "Samsung S5H1409 based"
depends on DVB_CORE && I2C
@ -369,6 +411,17 @@ config DVB_S5H1411
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
comment "ISDB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_S921
tristate "Sharp S921 tuner"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
Say Y when you want to support this frontend.
comment "Digital terrestrial only tuners/PLL"
depends on DVB_CORE

View file

@ -5,8 +5,13 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
s921-objs := s921_module.o s921_core.o
stb0899-objs = stb0899_drv.o stb0899_algo.o
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
obj-$(CONFIG_DVB_STB0899) += stb0899.o
obj-$(CONFIG_DVB_STB6100) += stb6100.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
@ -35,18 +40,21 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TDA8261) += tda8261.o
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@ -55,3 +63,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
obj-$(CONFIG_DVB_STV0288) += stv0288.o
obj-$(CONFIG_DVB_STB6000) += stb6000.o
obj-$(CONFIG_DVB_S921) += s921.o

View file

@ -223,12 +223,12 @@ static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
int ret = 0;
u8 i = 0;
u8 buf[24];
u32 ns_coeff1_2048nu;
u32 ns_coeff1_8191nu;
u32 ns_coeff1_8192nu;
u32 ns_coeff1_8193nu;
u32 ns_coeff2_2k;
u32 ns_coeff2_8k;
u32 uninitialized_var(ns_coeff1_2048nu);
u32 uninitialized_var(ns_coeff1_8191nu);
u32 uninitialized_var(ns_coeff1_8192nu);
u32 uninitialized_var(ns_coeff1_8193nu);
u32 uninitialized_var(ns_coeff2_2k);
u32 uninitialized_var(ns_coeff2_8k);
deb_info("%s: adc_clock:%d bw:%d\n", __func__,
state->config.adc_clock, bw);
@ -1009,7 +1009,7 @@ static int af9013_update_snr(struct dvb_frontend *fe)
int ret;
u8 buf[3], i, len;
u32 quant = 0;
struct snr_table *snr_table;
struct snr_table *uninitialized_var(snr_table);
/* check if quantizer ready (for snr) */
ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);

View file

@ -0,0 +1,616 @@
/*
* Driver for Conexant CX24113/CX24128 Tuner (Satellite)
*
* Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
*
* Developed for BBTI / Technisat
*
* 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.
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include "dvb_frontend.h"
#include "cx24113.h"
static int debug;
#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
#define err(args...) do { printk(KERN_ERR "CX24113: " args); } while (0)
#define dprintk(args...) \
do { \
if (debug) { \
printk(KERN_DEBUG "CX24113: %s: ", __func__); \
printk(args); \
} \
} while (0)
struct cx24113_state {
struct i2c_adapter *i2c;
const struct cx24113_config *config;
#define REV_CX24113 0x23
u8 rev;
u8 ver;
u8 icp_mode:1;
#define ICP_LEVEL1 0
#define ICP_LEVEL2 1
#define ICP_LEVEL3 2
#define ICP_LEVEL4 3
u8 icp_man:2;
u8 icp_auto_low:2;
u8 icp_auto_mlow:2;
u8 icp_auto_mhi:2;
u8 icp_auto_hi:2;
u8 icp_dig;
#define LNA_MIN_GAIN 0
#define LNA_MID_GAIN 1
#define LNA_MAX_GAIN 2
u8 lna_gain:2;
u8 acp_on:1;
u8 vco_mode:2;
u8 vco_shift:1;
#define VCOBANDSEL_6 0x80
#define VCOBANDSEL_5 0x01
#define VCOBANDSEL_4 0x02
#define VCOBANDSEL_3 0x04
#define VCOBANDSEL_2 0x08
#define VCOBANDSEL_1 0x10
u8 vco_band;
#define VCODIV4 4
#define VCODIV2 2
u8 vcodiv;
u8 bs_delay:4;
u16 bs_freqcnt:13;
u16 bs_rdiv;
u8 prescaler_mode:1;
u8 rfvga_bias_ctrl;
s16 tuner_gain_thres;
u8 gain_level;
u32 frequency;
u8 refdiv;
u8 Fwindow_enabled;
};
static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = state->config->i2c_addr,
.flags = 0, .buf = buf, .len = 2 };
int err = i2c_transfer(state->i2c, &msg, 1);
if (err != 1) {
printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __func__, err, reg, data);
return err;
}
return 0;
}
static int cx24113_readreg(struct cx24113_state *state, u8 reg)
{
int ret;
u8 b;
struct i2c_msg msg[] = {
{ .addr = state->config->i2c_addr,
.flags = 0, .buf = &reg, .len = 1 },
{ .addr = state->config->i2c_addr,
.flags = I2C_M_RD, .buf = &b, .len = 1 }
};
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
__func__, reg, ret);
return ret;
}
return b;
}
static void cx24113_set_parameters(struct cx24113_state *state)
{
u8 r;
r = cx24113_readreg(state, 0x10) & 0x82;
r |= state->icp_mode;
r |= state->icp_man << 4;
r |= state->icp_dig << 2;
r |= state->prescaler_mode << 5;
cx24113_writereg(state, 0x10, r);
r = (state->icp_auto_low << 0) | (state->icp_auto_mlow << 2)
| (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
cx24113_writereg(state, 0x11, r);
if (state->rev == REV_CX24113) {
r = cx24113_readreg(state, 0x20) & 0xec;
r |= state->lna_gain;
r |= state->rfvga_bias_ctrl << 4;
cx24113_writereg(state, 0x20, r);
}
r = cx24113_readreg(state, 0x12) & 0x03;
r |= state->acp_on << 2;
r |= state->bs_delay << 4;
cx24113_writereg(state, 0x12, r);
r = cx24113_readreg(state, 0x18) & 0x40;
r |= state->vco_shift;
if (state->vco_band == VCOBANDSEL_6)
r |= (1 << 7);
else
r |= (state->vco_band << 1);
cx24113_writereg(state, 0x18, r);
r = cx24113_readreg(state, 0x14) & 0x20;
r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
cx24113_writereg(state, 0x14, r);
cx24113_writereg(state, 0x15, (state->bs_freqcnt & 0xff));
cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
r = (cx24113_readreg(state, 0x17) & 0x0f) |
((state->bs_rdiv & 0x0f) << 4);
cx24113_writereg(state, 0x17, r);
}
#define VGA_0 0x00
#define VGA_1 0x04
#define VGA_2 0x02
#define VGA_3 0x06
#define VGA_4 0x01
#define VGA_5 0x05
#define VGA_6 0x03
#define VGA_7 0x07
#define RFVGA_0 0x00
#define RFVGA_1 0x01
#define RFVGA_2 0x02
#define RFVGA_3 0x03
static int cx24113_set_gain_settings(struct cx24113_state *state,
s16 power_estimation)
{
u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
vga = cx24113_readreg(state, 0x1f) & 0x3f,
rfvga = cx24113_readreg(state, 0x20) & 0xf3;
u8 gain_level = power_estimation >= state->tuner_gain_thres;
dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
power_estimation, state->tuner_gain_thres,
state->gain_level, gain_level);
if (gain_level == state->gain_level)
return 0; /* nothing to be done */
ampout |= 0xf;
if (gain_level) {
rfvga |= RFVGA_0 << 2;
vga |= (VGA_7 << 3) | VGA_7;
} else {
rfvga |= RFVGA_2 << 2;
vga |= (VGA_6 << 3) | VGA_2;
}
state->gain_level = gain_level;
cx24113_writereg(state, 0x1d, ampout);
cx24113_writereg(state, 0x1f, vga);
cx24113_writereg(state, 0x20, rfvga);
return 1; /* did something */
}
static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
{
u8 xtal = cx24113_readreg(state, 0x02);
if (state->rev == 0x43 && state->vcodiv == VCODIV4)
high = 1;
xtal &= ~0x2;
if (high)
xtal |= high << 1;
return cx24113_writereg(state, 0x02, xtal);
}
static int cx24113_enable(struct cx24113_state *state, u8 enable)
{
u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
if (state->rev == REV_CX24113)
r21 |= (1 << 1);
return cx24113_writereg(state, 0x21, r21);
}
static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
{
u8 r;
if (bandwidth_khz <= 19000)
r = 0x03 << 6;
else if (bandwidth_khz <= 25000)
r = 0x02 << 6;
else
r = 0x01 << 6;
dprintk("bandwidth to be set: %d\n", bandwidth_khz);
bandwidth_khz *= 10;
bandwidth_khz -= 10000;
bandwidth_khz /= 1000;
bandwidth_khz += 5;
bandwidth_khz /= 10;
dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
r |= bandwidth_khz & 0x3f;
return cx24113_writereg(state, 0x1e, r);
}
static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
{
u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
return cx24113_writereg(state, 0x10, r);
}
static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
{
struct cx24113_state *state = fe->tuner_priv;
u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
if (r)
*status |= TUNER_STATUS_LOCKED;
dprintk("PLL locked: %d\n", r);
return 0;
}
static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
{
if (state->rev == 0x43 && state->vcodiv == VCODIV4)
refdiv = 2;
return state->refdiv = refdiv;
}
static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
{
s32 N;
s64 F;
u8 R, r;
u8 vcodiv;
u8 factor;
s32 freq_hz = state->frequency * 1000;
if (state->config->xtal_khz < 20000)
factor = 1;
else
factor = 2;
if (state->rev == REV_CX24113) {
if (state->frequency >= 1100000)
vcodiv = VCODIV2;
else
vcodiv = VCODIV4;
} else {
if (state->frequency >= 1165000)
vcodiv = VCODIV2;
else
vcodiv = VCODIV4;
}
state->vcodiv = vcodiv;
dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
R = 0;
do {
R = cx24113_set_ref_div(state, R + 1);
/* calculate tuner PLL settings: */
N = (freq_hz / 100 * vcodiv) * R;
N /= (state->config->xtal_khz) * factor * 2;
N += 5; /* For round up. */
N /= 10;
N -= 32;
} while (N < 6 && R < 3);
if (N < 6) {
err("strange frequency: N < 6\n");
return;
}
F = freq_hz;
F *= (u64) (R * vcodiv * 262144);
dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
do_div(F, state->config->xtal_khz*1000 * factor * 2);
dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
F -= (N + 32) * 262144;
dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
if (state->Fwindow_enabled) {
if (F > (262144 / 2 - 1638))
F = 262144 / 2 - 1638;
if (F < (-262144 / 2 + 1638))
F = -262144 / 2 + 1638;
if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
F = 0;
r = cx24113_readreg(state, 0x10);
cx24113_writereg(state, 0x10, r | (1 << 6));
}
}
dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
*n = (u16) N;
*f = (s32) F;
}
static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
{
u8 reg;
cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
cx24113_writereg(state, 0x1a, reg);
cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
reg = cx24113_readreg(state, 0x1c) & 0x1f;
cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
cx24113_set_Fref(state, r - 1);
}
static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
{
u8 r = 1; /* or 2 */
u16 n = 6;
s32 f = 0;
r = cx24113_readreg(state, 0x14);
cx24113_writereg(state, 0x14, r & 0x3f);
r = cx24113_readreg(state, 0x10);
cx24113_writereg(state, 0x10, r & 0xbf);
state->frequency = frequency;
dprintk("tuning to frequency: %d\n", frequency);
cx24113_calc_pll_nf(state, &n, &f);
cx24113_set_nfr(state, n, f, state->refdiv);
r = cx24113_readreg(state, 0x18) & 0xbf;
if (state->vcodiv != VCODIV2)
r |= 1 << 6;
cx24113_writereg(state, 0x18, r);
/* The need for this sleep is not clear. But helps in some cases */
msleep(5);
r = cx24113_readreg(state, 0x1c) & 0xef;
cx24113_writereg(state, 0x1c, r | (1 << 4));
return 0;
}
static int cx24113_init(struct dvb_frontend *fe)
{
struct cx24113_state *state = fe->tuner_priv;
int ret;
state->tuner_gain_thres = -50;
state->gain_level = 255; /* to force a gain-setting initialization */
state->icp_mode = 0;
if (state->config->xtal_khz < 11000) {
state->icp_auto_hi = ICP_LEVEL4;
state->icp_auto_mhi = ICP_LEVEL4;
state->icp_auto_mlow = ICP_LEVEL3;
state->icp_auto_low = ICP_LEVEL3;
} else {
state->icp_auto_hi = ICP_LEVEL4;
state->icp_auto_mhi = ICP_LEVEL4;
state->icp_auto_mlow = ICP_LEVEL3;
state->icp_auto_low = ICP_LEVEL2;
}
state->icp_dig = ICP_LEVEL3;
state->icp_man = ICP_LEVEL1;
state->acp_on = 1;
state->vco_mode = 0;
state->vco_shift = 0;
state->vco_band = VCOBANDSEL_1;
state->bs_delay = 8;
state->bs_freqcnt = 0x0fff;
state->bs_rdiv = 0x0fff;
state->prescaler_mode = 0;
state->lna_gain = LNA_MAX_GAIN;
state->rfvga_bias_ctrl = 1;
state->Fwindow_enabled = 1;
cx24113_set_Fref(state, 0);
cx24113_enable(state, 0x3d);
cx24113_set_parameters(state);
cx24113_set_gain_settings(state, -30);
cx24113_set_bandwidth(state, 18025);
cx24113_set_clk_inversion(state, 1);
if (state->config->xtal_khz >= 40000)
ret = cx24113_writereg(state, 0x02,
(cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
else
ret = cx24113_writereg(state, 0x02,
(cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
return ret;
}
static int cx24113_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct cx24113_state *state = fe->tuner_priv;
/* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
u32 roll_off = 675;
u32 bw;
bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
bw += (10000000/100) + 5;
bw /= 10;
bw += 1000;
cx24113_set_bandwidth(state, bw);
cx24113_set_frequency(state, p->frequency);
msleep(5);
return cx24113_get_status(fe, &bw);
}
static s8 cx24113_agc_table[2][10] = {
{-54, -41, -35, -30, -25, -21, -16, -10, -6, -2},
{-39, -35, -30, -25, -19, -15, -11, -5, 1, 9},
};
void cx24113_agc_callback(struct dvb_frontend *fe)
{
struct cx24113_state *state = fe->tuner_priv;
s16 s, i;
if (!fe->ops.read_signal_strength)
return;
do {
/* this only works with the current CX24123 implementation */
fe->ops.read_signal_strength(fe, (u16 *) &s);
s >>= 8;
dprintk("signal strength: %d\n", s);
for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
if (cx24113_agc_table[state->gain_level][i] > s)
break;
s = -25 - i*5;
} while (cx24113_set_gain_settings(state, s));
}
EXPORT_SYMBOL(cx24113_agc_callback);
static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct cx24113_state *state = fe->tuner_priv;
*frequency = state->frequency;
return 0;
}
static int cx24113_release(struct dvb_frontend *fe)
{
struct cx24113_state *state = fe->tuner_priv;
dprintk("\n");
fe->tuner_priv = NULL;
kfree(state);
return 0;
}
static const struct dvb_tuner_ops cx24113_tuner_ops = {
.info = {
.name = "Conexant CX24113",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 125,
},
.release = cx24113_release,
.init = cx24113_init,
.sleep = NULL,
.set_params = cx24113_set_params,
.get_frequency = cx24113_get_frequency,
.get_bandwidth = NULL,
.get_status = cx24113_get_status,
};
struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
const struct cx24113_config *config, struct i2c_adapter *i2c)
{
/* allocate memory for the internal state */
struct cx24113_state *state =
kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
int rc;
if (state == NULL) {
err("Unable to kmalloc\n");
goto error;
}
/* setup the state */
state->config = config;
state->i2c = i2c;
info("trying to detect myself\n");
/* making a dummy read, because of some expected troubles
* after power on */
cx24113_readreg(state, 0x00);
rc = cx24113_readreg(state, 0x00);
if (rc < 0) {
info("CX24113 not found.\n");
goto error;
}
state->rev = rc;
switch (rc) {
case 0x43:
info("detected CX24113 variant\n");
break;
case REV_CX24113:
info("sucessfully detected\n");
break;
default:
err("unsupported device id: %x\n", state->rev);
goto error;
}
state->ver = cx24113_readreg(state, 0x01);
info("version: %x\n", state->ver);
/* create dvb_frontend */
memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
sizeof(struct dvb_tuner_ops));
fe->tuner_priv = state;
return fe;
error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(cx24113_attach);
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
MODULE_LICENSE("GPL");

View file

@ -16,7 +16,7 @@
*
* 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.=
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CX24113_H
@ -30,9 +30,13 @@ struct cx24113_config {
u32 xtal_khz;
};
/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
* (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
#if defined(CONFIG_DVB_TUNER_CX24113) || \
(defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
const struct cx24113_config *config, struct i2c_adapter *i2c);
extern void cx24113_agc_callback(struct dvb_frontend *fe);
#else
static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
const struct cx24113_config *config, struct i2c_adapter *i2c)
{
@ -44,5 +48,6 @@ static inline void cx24113_agc_callback(struct dvb_frontend *fe)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
}
#endif
#endif /* CX24113_H */

View file

@ -106,7 +106,7 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
#define CX24116_HAS_SYNCLOCK (0x08)
#define CX24116_HAS_UNKNOWN1 (0x10)
#define CX24116_HAS_UNKNOWN2 (0x20)
#define CX24116_STATUS_MASK (0x3f)
#define CX24116_STATUS_MASK (0x0f)
#define CX24116_SIGNAL_MASK (0xc0)
#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
@ -160,6 +160,7 @@ struct cx24116_tuning {
fe_spectral_inversion_t inversion;
fe_code_rate_t fec;
fe_delivery_system_t delsys;
fe_modulation_t modulation;
fe_pilot_t pilot;
fe_rolloff_t rolloff;
@ -411,14 +412,15 @@ struct cx24116_modfec {
};
static int cx24116_lookup_fecmod(struct cx24116_state *state,
fe_modulation_t m, fe_code_rate_t f)
fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
{
int i, ret = -EOPNOTSUPP;
dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
if ((m == CX24116_MODFEC_MODES[i].modulation) &&
if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
(m == CX24116_MODFEC_MODES[i].modulation) &&
(f == CX24116_MODFEC_MODES[i].fec)) {
ret = i;
break;
@ -429,13 +431,13 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state,
}
static int cx24116_set_fec(struct cx24116_state *state,
fe_modulation_t mod, fe_code_rate_t fec)
fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
{
int ret = 0;
dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
ret = cx24116_lookup_fecmod(state, mod, fec);
ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
if (ret < 0)
return ret;
@ -679,7 +681,8 @@ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct cx24116_state *state = fe->demodulator_priv;
int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
CX24116_STATUS_MASK;
dprintk("%s: status = 0x%02x\n", __func__, lock);
@ -1205,7 +1208,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct cx24116_cmd cmd;
fe_status_t tunerstat;
int i, status, ret, retune;
int i, status, ret, retune = 1;
dprintk("%s()\n", __func__);
@ -1222,7 +1225,6 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
/* Pilot doesn't exist in DVB-S, turn bit off */
state->dnxt.pilot_val = CX24116_PILOT_OFF;
retune = 1;
/* DVB-S only supports 0.35 */
if (c->rolloff != ROLLOFF_35) {
@ -1250,7 +1252,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
case PILOT_AUTO: /* Not supported but emulated */
state->dnxt.pilot_val = (c->modulation == QPSK)
? CX24116_PILOT_OFF : CX24116_PILOT_ON;
retune = 2;
retune++;
break;
case PILOT_OFF:
state->dnxt.pilot_val = CX24116_PILOT_OFF;
@ -1287,6 +1289,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
__func__, c->delivery_system);
return -EOPNOTSUPP;
}
state->dnxt.delsys = c->delivery_system;
state->dnxt.modulation = c->modulation;
state->dnxt.frequency = c->frequency;
state->dnxt.pilot = c->pilot;
@ -1297,7 +1300,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
return ret;
/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
if (ret != 0)
return ret;
@ -1308,6 +1311,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
/* discard the 'current' tuning parameters and prepare to tune */
cx24116_clone_params(fe);
dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
@ -1427,6 +1431,23 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
return ret;
}
static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
{
*delay = HZ / 5;
if (params) {
int ret = cx24116_set_frontend(fe, params);
if (ret)
return ret;
}
return cx24116_read_status(fe, status);
}
static int cx24116_get_algo(struct dvb_frontend *fe)
{
return DVBFE_ALGO_HW;
}
static struct dvb_frontend_ops cx24116_ops = {
.info = {
@ -1458,6 +1479,8 @@ static struct dvb_frontend_ops cx24116_ops = {
.set_voltage = cx24116_set_voltage,
.diseqc_send_master_cmd = cx24116_send_diseqc_msg,
.diseqc_send_burst = cx24116_diseqc_send_burst,
.get_frontend_algo = cx24116_get_algo,
.tune = cx24116_tune,
.set_property = cx24116_set_property,
.get_property = cx24116_get_property,

View file

@ -66,7 +66,8 @@ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
return NULL;
}
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
static inline
int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
int no_of_demods, u8 default_addr,
struct dib7000p_config cfg[])
{
@ -74,13 +75,15 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
return -ENODEV;
}
extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
static inline
int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
}
extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
static inline
int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;

View file

@ -39,7 +39,7 @@ static const char mod_name[] = "drx397xD";
#define F_SET_0D4h 2
enum fw_ix {
#define _FW_ENTRY(a, b) b
#define _FW_ENTRY(a, b, c) b
#include "drx397xD_fw.h"
};
@ -72,11 +72,11 @@ static struct {
int refcnt;
const u8 *data[ARRAY_SIZE(blob_name)];
} fw[] = {
#define _FW_ENTRY(a, b) { \
.name = a, \
.file = 0, \
.lock = RW_LOCK_UNLOCKED, \
.refcnt = 0, \
#define _FW_ENTRY(a, b, c) { \
.name = a, \
.file = 0, \
.lock = __RW_LOCK_UNLOCKED(fw[c].lock), \
.refcnt = 0, \
.data = { } }
#include "drx397xD_fw.h"
};

View file

@ -18,8 +18,8 @@
*/
#ifdef _FW_ENTRY
_FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ),
_FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ),
_FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ),
_FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ),
#undef _FW_ENTRY
#endif /* _FW_ENTRY */

View file

@ -311,7 +311,7 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
.count = 4,
.entries = {
{ 1250000, 500, 0xc4, 0x00},
{ 1550000, 500, 0xc4, 0x40},
{ 1450000, 500, 0xc4, 0x40},
{ 2050000, 500, 0xc4, 0x80},
{ 2150000, 500, 0xc4, 0xc0},
},

View file

@ -0,0 +1,378 @@
/*
* Driver for LG ATSC lgdt3304 driver
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "lgdt3304.h"
static unsigned int debug = 0;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
#define dprintk(fmt, args...) if (debug) do {\
printk("lgdt3304 debug: " fmt, ##args); } while (0)
struct lgdt3304_state
{
struct dvb_frontend frontend;
fe_modulation_t current_modulation;
__u32 snr;
__u32 current_frequency;
__u8 addr;
struct i2c_adapter *i2c;
};
static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
{
struct lgdt3304_state *state = fe->demodulator_priv;
struct i2c_msg i2cmsgs = {
.addr = state->addr,
.flags = 0,
.len = 3,
.buf = buf
};
int i;
int err;
for (i=0; i<len-1; i+=3){
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
if (err < 0)
return err;
else
return -EREMOTEIO;
}
i2cmsgs.buf += 3;
}
return 0;
}
static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
{
struct lgdt3304_state *state = fe->demodulator_priv;
struct i2c_msg i2cmsgs[2];
int ret;
__u8 buf;
__u8 regbuf[2] = { reg>>8, reg&0xff };
i2cmsgs[0].addr = state->addr;
i2cmsgs[0].flags = 0;
i2cmsgs[0].len = 2;
i2cmsgs[0].buf = regbuf;
i2cmsgs[1].addr = state->addr;
i2cmsgs[1].flags = I2C_M_RD;
i2cmsgs[1].len = 1;
i2cmsgs[1].buf = &buf;
if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
return ret;
}
return buf;
}
static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
{
struct lgdt3304_state *state = fe->demodulator_priv;
char buffer[3] = { reg>>8, reg&0xff, val };
int ret;
struct i2c_msg i2cmsgs = {
.addr = state->addr,
.flags = 0,
.len = 3,
.buf=buffer
};
ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
if (ret != 1) {
printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
return ret;
}
return 0;
}
static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
{
lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
mdelay(200);
return 0;
}
static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
int err = 0;
static __u8 lgdt3304_vsb8_data[] = {
/* 16bit , 8bit */
/* regs , val */
0x00, 0x00, 0x02,
0x00, 0x00, 0x13,
0x00, 0x0d, 0x02,
0x00, 0x0e, 0x02,
0x00, 0x12, 0x32,
0x00, 0x13, 0xc4,
0x01, 0x12, 0x17,
0x01, 0x13, 0x15,
0x01, 0x14, 0x18,
0x01, 0x15, 0xff,
0x01, 0x16, 0x2c,
0x02, 0x14, 0x67,
0x02, 0x24, 0x8d,
0x04, 0x27, 0x12,
0x04, 0x28, 0x4f,
0x03, 0x08, 0x80,
0x03, 0x09, 0x00,
0x03, 0x0d, 0x00,
0x03, 0x0e, 0x1c,
0x03, 0x14, 0xe1,
0x05, 0x0e, 0x5b,
};
/* not yet tested .. */
static __u8 lgdt3304_qam64_data[] = {
/* 16bit , 8bit */
/* regs , val */
0x00, 0x00, 0x18,
0x00, 0x0d, 0x02,
//0x00, 0x0e, 0x02,
0x00, 0x12, 0x2a,
0x00, 0x13, 0x00,
0x03, 0x14, 0xe3,
0x03, 0x0e, 0x1c,
0x03, 0x08, 0x66,
0x03, 0x09, 0x66,
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x05, 0x0e, 0x5b,
};
/* tested with KWorld a340 */
static __u8 lgdt3304_qam256_data[] = {
/* 16bit , 8bit */
/* regs , val */
0x00, 0x00, 0x01, //0x19,
0x00, 0x12, 0x2a,
0x00, 0x13, 0x80,
0x00, 0x0d, 0x02,
0x03, 0x14, 0xe3,
0x03, 0x0e, 0x1c,
0x03, 0x08, 0x66,
0x03, 0x09, 0x66,
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x03, 0x0d, 0x14,
//0x05, 0x0e, 0x5b,
0x01, 0x06, 0x4a,
0x01, 0x07, 0x3d,
0x01, 0x08, 0x70,
0x01, 0x09, 0xa3,
0x05, 0x04, 0xfd,
0x00, 0x0d, 0x82,
0x05, 0x0e, 0x5b,
0x05, 0x0e, 0x5b,
0x00, 0x02, 0x9a,
0x00, 0x02, 0x9b,
0x00, 0x00, 0x01,
0x00, 0x12, 0x2a,
0x00, 0x13, 0x80,
0x00, 0x0d, 0x02,
0x03, 0x14, 0xe3,
0x03, 0x0e, 0x1c,
0x03, 0x08, 0x66,
0x03, 0x09, 0x66,
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x03, 0x0d, 0x14,
0x01, 0x06, 0x4a,
0x01, 0x07, 0x3d,
0x01, 0x08, 0x70,
0x01, 0x09, 0xa3,
0x05, 0x04, 0xfd,
0x00, 0x0d, 0x82,
0x05, 0x0e, 0x5b,
};
struct lgdt3304_state *state = fe->demodulator_priv;
if (state->current_modulation != param->u.vsb.modulation) {
switch(param->u.vsb.modulation) {
case VSB_8:
err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
sizeof(lgdt3304_vsb8_data));
break;
case QAM_64:
err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
sizeof(lgdt3304_qam64_data));
break;
case QAM_256:
err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
sizeof(lgdt3304_qam256_data));
break;
default:
break;
}
if (err) {
printk("%s error setting modulation\n", __FUNCTION__);
} else {
state->current_modulation = param->u.vsb.modulation;
}
}
state->current_frequency = param->frequency;
lgdt3304_soft_Reset(fe);
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, param);
return 0;
}
static int lgdt3304_init(struct dvb_frontend *fe) {
return 0;
}
static int lgdt3304_sleep(struct dvb_frontend *fe) {
return 0;
}
static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct lgdt3304_state *state = fe->demodulator_priv;
int r011d;
int qam_lck;
*status = 0;
dprintk("lgdt read status\n");
r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
dprintk("%02x\n", r011d);
switch(state->current_modulation) {
case VSB_8:
if (r011d & 0x80) {
dprintk("VSB Locked\n");
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
*status |= FE_HAS_SIGNAL;
}
break;
case QAM_64:
case QAM_256:
qam_lck = r011d & 0x7;
switch(qam_lck) {
case 0x0: dprintk("Unlock\n");
break;
case 0x4: dprintk("1st Lock in acquisition state\n");
break;
case 0x6: dprintk("2nd Lock in acquisition state\n");
break;
case 0x7: dprintk("Final Lock in good reception state\n");
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
*status |= FE_HAS_SIGNAL;
break;
}
break;
default:
printk("%s unhandled modulation\n", __FUNCTION__);
}
return 0;
}
static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
{
dprintk("read ber\n");
return 0;
}
static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
{
dprintk("read snr\n");
return 0;
}
static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
{
dprintk("read ucblocks\n");
return 0;
}
static void lgdt3304_release(struct dvb_frontend *fe)
{
struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops demod_lgdt3304={
.info = {
.name = "LG 3304",
.type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
.symbol_rate_min = 5056941,
.symbol_rate_max = 10762000,
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
.init = lgdt3304_init,
.sleep = lgdt3304_sleep,
.set_frontend = lgdt3304_set_parameters,
.read_snr = lgdt3304_read_snr,
.read_ber = lgdt3304_read_ber,
.read_status = lgdt3304_read_status,
.read_ucblocks = lgdt3304_read_ucblocks,
.release = lgdt3304_release,
};
struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
struct i2c_adapter *i2c)
{
struct lgdt3304_state *state;
state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
memset(state, 0x0, sizeof(struct lgdt3304_state));
state->addr = config->i2c_address;
state->i2c = i2c;
memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
EXPORT_SYMBOL_GPL(lgdt3304_attach);
MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,45 @@
/*
* Driver for DVB-T lgdt3304 demodulator
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.=
*/
#ifndef LGDT3304_H
#define LGDT3304_H
#include <linux/dvb/frontend.h>
struct lgdt3304_config
{
/* demodulator's I2C address */
u8 i2c_address;
};
#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_LGDT */
#endif /* LGDT3304_H */

View file

@ -874,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
/* Note: Leaving the I2C gate open here. */
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
/* Put the device into low-power mode until first use */
s5h1411_set_powerstate(&state->frontend, 1);
return &state->frontend;
error:

View file

@ -0,0 +1,216 @@
/*
* Driver for Sharp s921 driver
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include "s921_core.h"
static int s921_isdb_init(struct s921_isdb_t *dev);
static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params);
static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params);
static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data);
static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01,
0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00,
0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80,
0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12,
0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00,
0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff,
0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00,
0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88,
0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00,
0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06,
0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00,
0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00,
0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20,
0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70,
0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f,
0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00,
0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00,
0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30,
0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d,
0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f,
0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00,
0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84,
0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e,
0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba,
0xf8, 0xd7 };
static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b,
0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b,
0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b,
0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b,
0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b,
0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b,
0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b,
0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb,
0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb,
0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb,
0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb,
0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb,
0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb,
0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b,
0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b,
0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b,
0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b };
int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) {
switch(cmd) {
case ISDB_T_CMD_INIT:
s921_isdb_init(dev);
break;
case ISDB_T_CMD_SET_PARAM:
s921_isdb_set_parameters(dev, data);
break;
case ISDB_T_CMD_TUNE:
s921_isdb_tune(dev, data);
break;
case ISDB_T_CMD_GET_STATUS:
s921_isdb_get_status(dev, data);
break;
default:
printk("unhandled command\n");
return -EINVAL;
}
return 0;
}
static int s921_isdb_init(struct s921_isdb_t *dev) {
unsigned int i;
unsigned int ret;
printk("isdb_init\n");
for (i = 0; i < sizeof(init_table); i+=2) {
ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]);
if (ret != 0) {
printk("i2c write failed\n");
return ret;
}
}
return 0;
}
static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) {
int ret;
/* auto is sufficient for now, lateron this should be reflected in an extra interface */
ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2);
ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7);
if (ret < 0)
return -EINVAL;
return E_OK;
}
static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) {
int ret;
int index;
index = (params->frequency - 473143000)/6000000;
if (index > 48) {
return -EINVAL;
}
dev->i2c_write(dev->priv_dev, 0x47, 0x60);
ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a);
if (ret < 0)
return -EINVAL;
ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09);
if (ret < 0)
return -EINVAL;
dev->i2c_write(dev->priv_dev, 0x01, 0x40);
return 0;
}
static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) {
unsigned int *ret = (unsigned int*)data;
u8 ifagc_dt;
u8 rfagc_dt;
mdelay(10);
ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81);
rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82);
if (rfagc_dt == 0x40) {
*ret = 1;
}
return 0;
}

View file

@ -0,0 +1,114 @@
#ifndef _S921_CORE_H
#define _S921_CORE_H
//#define u8 unsigned int
//#define u32 unsigned int
//#define EINVAL -1
#define E_OK 0
struct s921_isdb_t {
void *priv_dev;
int (*i2c_write)(void *dev, u8 reg, u8 val);
int (*i2c_read)(void *dev, u8 reg);
};
#define ISDB_T_CMD_INIT 0
#define ISDB_T_CMD_SET_PARAM 1
#define ISDB_T_CMD_TUNE 2
#define ISDB_T_CMD_GET_STATUS 3
struct s921_isdb_t_tune_params {
u32 frequency;
};
struct s921_isdb_t_status {
};
struct s921_isdb_t_transmission_mode_params {
u8 mode;
u8 layer_a_mode;
#define ISDB_T_LA_MODE_1 0
#define ISDB_T_LA_MODE_2 1
#define ISDB_T_LA_MODE_3 2
u8 layer_a_carrier_modulation;
#define ISDB_T_LA_CM_DQPSK 0
#define ISDB_T_LA_CM_QPSK 1
#define ISDB_T_LA_CM_16QAM 2
#define ISDB_T_LA_CM_64QAM 3
#define ISDB_T_LA_CM_NOLAYER 4
u8 layer_a_code_rate;
#define ISDB_T_LA_CR_1_2 0
#define ISDB_T_LA_CR_2_3 1
#define ISDB_T_LA_CR_3_4 2
#define ISDB_T_LA_CR_5_6 4
#define ISDB_T_LA_CR_7_8 8
#define ISDB_T_LA_CR_NOLAYER 16
u8 layer_a_time_interleave;
#define ISDB_T_LA_TI_0 0
#define ISDB_T_LA_TI_1 1
#define ISDB_T_LA_TI_2 2
#define ISDB_T_LA_TI_4 4
#define ISDB_T_LA_TI_8 8
#define ISDB_T_LA_TI_16 16
#define ISDB_T_LA_TI_32 32
u8 layer_a_nseg;
u8 layer_b_mode;
#define ISDB_T_LB_MODE_1 0
#define ISDB_T_LB_MODE_2 1
#define ISDB_T_LB_MODE_3 2
u8 layer_b_carrier_modulation;
#define ISDB_T_LB_CM_DQPSK 0
#define ISDB_T_LB_CM_QPSK 1
#define ISDB_T_LB_CM_16QAM 2
#define ISDB_T_LB_CM_64QAM 3
#define ISDB_T_LB_CM_NOLAYER 4
u8 layer_b_code_rate;
#define ISDB_T_LB_CR_1_2 0
#define ISDB_T_LB_CR_2_3 1
#define ISDB_T_LB_CR_3_4 2
#define ISDB_T_LB_CR_5_6 4
#define ISDB_T_LB_CR_7_8 8
#define ISDB_T_LB_CR_NOLAYER 16
u8 layer_b_time_interleave;
#define ISDB_T_LB_TI_0 0
#define ISDB_T_LB_TI_1 1
#define ISDB_T_LB_TI_2 2
#define ISDB_T_LB_TI_4 4
#define ISDB_T_LB_TI_8 8
#define ISDB_T_LB_TI_16 16
#define ISDB_T_LB_TI_32 32
u8 layer_b_nseg;
u8 layer_c_mode;
#define ISDB_T_LC_MODE_1 0
#define ISDB_T_LC_MODE_2 1
#define ISDB_T_LC_MODE_3 2
u8 layer_c_carrier_modulation;
#define ISDB_T_LC_CM_DQPSK 0
#define ISDB_T_LC_CM_QPSK 1
#define ISDB_T_LC_CM_16QAM 2
#define ISDB_T_LC_CM_64QAM 3
#define ISDB_T_LC_CM_NOLAYER 4
u8 layer_c_code_rate;
#define ISDB_T_LC_CR_1_2 0
#define ISDB_T_LC_CR_2_3 1
#define ISDB_T_LC_CR_3_4 2
#define ISDB_T_LC_CR_5_6 4
#define ISDB_T_LC_CR_7_8 8
#define ISDB_T_LC_CR_NOLAYER 16
u8 layer_c_time_interleave;
#define ISDB_T_LC_TI_0 0
#define ISDB_T_LC_TI_1 1
#define ISDB_T_LC_TI_2 2
#define ISDB_T_LC_TI_4 4
#define ISDB_T_LC_TI_8 8
#define ISDB_T_LC_TI_16 16
#define ISDB_T_LC_TI_32 32
u8 layer_c_nseg;
};
int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
#endif

View file

@ -0,0 +1,190 @@
/*
* Driver for Sharp s921 driver
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
*
* All rights reserved.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "s921_module.h"
#include "s921_core.h"
static unsigned int debug = 0;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"s921 debugging (default off)");
#define dprintk(fmt, args...) if (debug) do {\
printk("s921 debug: " fmt, ##args); } while (0)
struct s921_state
{
struct dvb_frontend frontend;
fe_modulation_t current_modulation;
__u32 snr;
__u32 current_frequency;
__u8 addr;
struct s921_isdb_t dev;
struct i2c_adapter *i2c;
};
static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
struct s921_isdb_t_transmission_mode_params params;
struct s921_isdb_t_tune_params tune_params;
tune_params.frequency = param->frequency;
s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, &params);
s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
mdelay(100);
return 0;
}
static int s921_init(struct dvb_frontend *fe) {
printk("s921 init\n");
return 0;
}
static int s921_sleep(struct dvb_frontend *fe) {
printk("s921 sleep\n");
return 0;
}
static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
unsigned int ret;
mdelay(5);
s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
*status = 0;
printk("status: %02x\n", ret);
if (ret == 1) {
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_VITERBI;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
*status |= FE_HAS_SIGNAL;
}
return 0;
}
static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
{
dprintk("read ber\n");
return 0;
}
static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
{
dprintk("read snr\n");
return 0;
}
static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
{
dprintk("read ucblocks\n");
return 0;
}
static void s921_release(struct dvb_frontend *fe)
{
struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops demod_s921={
.info = {
.name = "SHARP S921",
.type = FE_OFDM,
.frequency_min = 473143000,
.frequency_max = 767143000,
.frequency_stepsize = 6000000,
.frequency_tolerance = 0,
.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_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_HIERARCHY_AUTO | FE_CAN_RECOVER |
FE_CAN_MUTE_TS
},
.init = s921_init,
.sleep = s921_sleep,
.set_frontend = s921_set_parameters,
.read_snr = s921_read_snr,
.read_ber = s921_read_ber,
.read_status = s921_read_status,
.read_ucblocks = s921_read_ucblocks,
.release = s921_release,
};
static int s921_write(void *dev, u8 reg, u8 val) {
struct s921_state *state = dev;
char buf[2]={reg,val};
int err;
struct i2c_msg i2cmsgs = {
.addr = state->addr,
.flags = 0,
.len = 2,
.buf = buf
};
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
if (err < 0)
return err;
else
return -EREMOTEIO;
}
return 0;
}
static int s921_read(void *dev, u8 reg) {
struct s921_state *state = dev;
u8 b1;
int ret;
struct i2c_msg msg[2] = { { .addr = state->addr,
.flags = 0,
.buf = &reg, .len = 1 },
{ .addr = state->addr,
.flags = I2C_M_RD,
.buf = &b1, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
return ret;
return b1;
}
struct dvb_frontend* s921_attach(const struct s921_config *config,
struct i2c_adapter *i2c)
{
struct s921_state *state;
state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
memset(state, 0x0, sizeof(struct s921_state));
state->addr = config->i2c_address;
state->i2c = i2c;
state->dev.i2c_write = &s921_write;
state->dev.i2c_read = &s921_read;
state->dev.priv_dev = state;
s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);
memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
EXPORT_SYMBOL_GPL(s921_attach);
MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,49 @@
/*
* Driver for DVB-T s921 demodulator
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.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; 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.=
*/
#ifndef S921_MODULE_H
#define S921_MODULE_H
#include <linux/dvb/frontend.h>
#include "s921_core.h"
int s921_isdb_init(struct s921_isdb_t *dev);
int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
struct s921_config
{
/* demodulator's I2C address */
u8 i2c_address;
};
#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE))
extern struct dvb_frontend* s921_attach(const struct s921_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* s921_attach(const struct s921_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_S921 */
#endif /* S921_H */

View file

@ -8,7 +8,6 @@
* (at your option) any later version.
*
*/
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,287 @@
/*
STB0899 Multistandard Frontend driver
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
Copyright (C) ST Microelectronics
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.
*/
#ifndef __STB0899_CFG_H
#define __STB0899_CFG_H
static const struct stb0899_s2_reg stb0899_s2_init_2[] = {
{ STB0899_OFF0_DMD_STATUS , STB0899_BASE_DMD_STATUS , 0x00000103 }, /* DMDSTATUS */
{ STB0899_OFF0_CRL_FREQ , STB0899_BASE_CRL_FREQ , 0x3ed1da56 }, /* CRLFREQ */
{ STB0899_OFF0_BTR_FREQ , STB0899_BASE_BTR_FREQ , 0x00004000 }, /* BTRFREQ */
{ STB0899_OFF0_IF_AGC_GAIN , STB0899_BASE_IF_AGC_GAIN , 0x00002ade }, /* IFAGCGAIN */
{ STB0899_OFF0_BB_AGC_GAIN , STB0899_BASE_BB_AGC_GAIN , 0x000001bc }, /* BBAGCGAIN */
{ STB0899_OFF0_DC_OFFSET , STB0899_BASE_DC_OFFSET , 0x00000200 }, /* DCOFFSET */
{ STB0899_OFF0_DMD_CNTRL , STB0899_BASE_DMD_CNTRL , 0x0000000f }, /* DMDCNTRL */
{ STB0899_OFF0_IF_AGC_CNTRL , STB0899_BASE_IF_AGC_CNTRL , 0x03fb4a20 }, /* IFAGCCNTRL */
{ STB0899_OFF0_BB_AGC_CNTRL , STB0899_BASE_BB_AGC_CNTRL , 0x00200c97 }, /* BBAGCCNTRL */
{ STB0899_OFF0_CRL_CNTRL , STB0899_BASE_CRL_CNTRL , 0x00000016 }, /* CRLCNTRL */
{ STB0899_OFF0_CRL_PHS_INIT , STB0899_BASE_CRL_PHS_INIT , 0x00000000 }, /* CRLPHSINIT */
{ STB0899_OFF0_CRL_FREQ_INIT , STB0899_BASE_CRL_FREQ_INIT , 0x00000000 }, /* CRLFREQINIT */
{ STB0899_OFF0_CRL_LOOP_GAIN , STB0899_BASE_CRL_LOOP_GAIN , 0x00000000 }, /* CRLLOOPGAIN */
{ STB0899_OFF0_CRL_NOM_FREQ , STB0899_BASE_CRL_NOM_FREQ , 0x3ed097b6 }, /* CRLNOMFREQ */
{ STB0899_OFF0_CRL_SWP_RATE , STB0899_BASE_CRL_SWP_RATE , 0x00000000 }, /* CRLSWPRATE */
{ STB0899_OFF0_CRL_MAX_SWP , STB0899_BASE_CRL_MAX_SWP , 0x00000000 }, /* CRLMAXSWP */
{ STB0899_OFF0_CRL_LK_CNTRL , STB0899_BASE_CRL_LK_CNTRL , 0x0f6cdc01 }, /* CRLLKCNTRL */
{ STB0899_OFF0_DECIM_CNTRL , STB0899_BASE_DECIM_CNTRL , 0x00000000 }, /* DECIMCNTRL */
{ STB0899_OFF0_BTR_CNTRL , STB0899_BASE_BTR_CNTRL , 0x00003993 }, /* BTRCNTRL */
{ STB0899_OFF0_BTR_LOOP_GAIN , STB0899_BASE_BTR_LOOP_GAIN , 0x000d3c6f }, /* BTRLOOPGAIN */
{ STB0899_OFF0_BTR_PHS_INIT , STB0899_BASE_BTR_PHS_INIT , 0x00000000 }, /* BTRPHSINIT */
{ STB0899_OFF0_BTR_FREQ_INIT , STB0899_BASE_BTR_FREQ_INIT , 0x00000000 }, /* BTRFREQINIT */
{ STB0899_OFF0_BTR_NOM_FREQ , STB0899_BASE_BTR_NOM_FREQ , 0x0238e38e }, /* BTRNOMFREQ */
{ STB0899_OFF0_BTR_LK_CNTRL , STB0899_BASE_BTR_LK_CNTRL , 0x00000000 }, /* BTRLKCNTRL */
{ STB0899_OFF0_DECN_CNTRL , STB0899_BASE_DECN_CNTRL , 0x00000000 }, /* DECNCNTRL */
{ STB0899_OFF0_TP_CNTRL , STB0899_BASE_TP_CNTRL , 0x00000000 }, /* TPCNTRL */
{ STB0899_OFF0_TP_BUF_STATUS , STB0899_BASE_TP_BUF_STATUS , 0x00000000 }, /* TPBUFSTATUS */
{ STB0899_OFF0_DC_ESTIM , STB0899_BASE_DC_ESTIM , 0x00000000 }, /* DCESTIM */
{ STB0899_OFF0_FLL_CNTRL , STB0899_BASE_FLL_CNTRL , 0x00000000 }, /* FLLCNTRL */
{ STB0899_OFF0_FLL_FREQ_WD , STB0899_BASE_FLL_FREQ_WD , 0x40070000 }, /* FLLFREQWD */
{ STB0899_OFF0_ANTI_ALIAS_SEL , STB0899_BASE_ANTI_ALIAS_SEL , 0x00000001 }, /* ANTIALIASSEL */
{ STB0899_OFF0_RRC_ALPHA , STB0899_BASE_RRC_ALPHA , 0x00000002 }, /* RRCALPHA */
{ STB0899_OFF0_DC_ADAPT_LSHFT , STB0899_BASE_DC_ADAPT_LSHFT , 0x00000000 }, /* DCADAPTISHFT */
{ STB0899_OFF0_IMB_OFFSET , STB0899_BASE_IMB_OFFSET , 0x0000fe01 }, /* IMBOFFSET */
{ STB0899_OFF0_IMB_ESTIMATE , STB0899_BASE_IMB_ESTIMATE , 0x00000000 }, /* IMBESTIMATE */
{ STB0899_OFF0_IMB_CNTRL , STB0899_BASE_IMB_CNTRL , 0x00000001 }, /* IMBCNTRL */
{ STB0899_OFF0_IF_AGC_CNTRL2 , STB0899_BASE_IF_AGC_CNTRL2 , 0x00005007 }, /* IFAGCCNTRL2 */
{ STB0899_OFF0_DMD_CNTRL2 , STB0899_BASE_DMD_CNTRL2 , 0x00000002 }, /* DMDCNTRL2 */
{ STB0899_OFF0_TP_BUFFER , STB0899_BASE_TP_BUFFER , 0x00000000 }, /* TPBUFFER */
{ STB0899_OFF0_TP_BUFFER1 , STB0899_BASE_TP_BUFFER1 , 0x00000000 }, /* TPBUFFER1 */
{ STB0899_OFF0_TP_BUFFER2 , STB0899_BASE_TP_BUFFER2 , 0x00000000 }, /* TPBUFFER2 */
{ STB0899_OFF0_TP_BUFFER3 , STB0899_BASE_TP_BUFFER3 , 0x00000000 }, /* TPBUFFER3 */
{ STB0899_OFF0_TP_BUFFER4 , STB0899_BASE_TP_BUFFER4 , 0x00000000 }, /* TPBUFFER4 */
{ STB0899_OFF0_TP_BUFFER5 , STB0899_BASE_TP_BUFFER5 , 0x00000000 }, /* TPBUFFER5 */
{ STB0899_OFF0_TP_BUFFER6 , STB0899_BASE_TP_BUFFER6 , 0x00000000 }, /* TPBUFFER6 */
{ STB0899_OFF0_TP_BUFFER7 , STB0899_BASE_TP_BUFFER7 , 0x00000000 }, /* TPBUFFER7 */
{ STB0899_OFF0_TP_BUFFER8 , STB0899_BASE_TP_BUFFER8 , 0x00000000 }, /* TPBUFFER8 */
{ STB0899_OFF0_TP_BUFFER9 , STB0899_BASE_TP_BUFFER9 , 0x00000000 }, /* TPBUFFER9 */
{ STB0899_OFF0_TP_BUFFER10 , STB0899_BASE_TP_BUFFER10 , 0x00000000 }, /* TPBUFFER10 */
{ STB0899_OFF0_TP_BUFFER11 , STB0899_BASE_TP_BUFFER11 , 0x00000000 }, /* TPBUFFER11 */
{ STB0899_OFF0_TP_BUFFER12 , STB0899_BASE_TP_BUFFER12 , 0x00000000 }, /* TPBUFFER12 */
{ STB0899_OFF0_TP_BUFFER13 , STB0899_BASE_TP_BUFFER13 , 0x00000000 }, /* TPBUFFER13 */
{ STB0899_OFF0_TP_BUFFER14 , STB0899_BASE_TP_BUFFER14 , 0x00000000 }, /* TPBUFFER14 */
{ STB0899_OFF0_TP_BUFFER15 , STB0899_BASE_TP_BUFFER15 , 0x00000000 }, /* TPBUFFER15 */
{ STB0899_OFF0_TP_BUFFER16 , STB0899_BASE_TP_BUFFER16 , 0x0000ff00 }, /* TPBUFFER16 */
{ STB0899_OFF0_TP_BUFFER17 , STB0899_BASE_TP_BUFFER17 , 0x00000100 }, /* TPBUFFER17 */
{ STB0899_OFF0_TP_BUFFER18 , STB0899_BASE_TP_BUFFER18 , 0x0000fe01 }, /* TPBUFFER18 */
{ STB0899_OFF0_TP_BUFFER19 , STB0899_BASE_TP_BUFFER19 , 0x000004fe }, /* TPBUFFER19 */
{ STB0899_OFF0_TP_BUFFER20 , STB0899_BASE_TP_BUFFER20 , 0x0000cfe7 }, /* TPBUFFER20 */
{ STB0899_OFF0_TP_BUFFER21 , STB0899_BASE_TP_BUFFER21 , 0x0000bec6 }, /* TPBUFFER21 */
{ STB0899_OFF0_TP_BUFFER22 , STB0899_BASE_TP_BUFFER22 , 0x0000c2bf }, /* TPBUFFER22 */
{ STB0899_OFF0_TP_BUFFER23 , STB0899_BASE_TP_BUFFER23 , 0x0000c1c1 }, /* TPBUFFER23 */
{ STB0899_OFF0_TP_BUFFER24 , STB0899_BASE_TP_BUFFER24 , 0x0000c1c1 }, /* TPBUFFER24 */
{ STB0899_OFF0_TP_BUFFER25 , STB0899_BASE_TP_BUFFER25 , 0x0000c1c1 }, /* TPBUFFER25 */
{ STB0899_OFF0_TP_BUFFER26 , STB0899_BASE_TP_BUFFER26 , 0x0000c1c1 }, /* TPBUFFER26 */
{ STB0899_OFF0_TP_BUFFER27 , STB0899_BASE_TP_BUFFER27 , 0x0000c1c0 }, /* TPBUFFER27 */
{ STB0899_OFF0_TP_BUFFER28 , STB0899_BASE_TP_BUFFER28 , 0x0000c0c0 }, /* TPBUFFER28 */
{ STB0899_OFF0_TP_BUFFER29 , STB0899_BASE_TP_BUFFER29 , 0x0000c1c1 }, /* TPBUFFER29 */
{ STB0899_OFF0_TP_BUFFER30 , STB0899_BASE_TP_BUFFER30 , 0x0000c1c1 }, /* TPBUFFER30 */
{ STB0899_OFF0_TP_BUFFER31 , STB0899_BASE_TP_BUFFER31 , 0x0000c0c1 }, /* TPBUFFER31 */
{ STB0899_OFF0_TP_BUFFER32 , STB0899_BASE_TP_BUFFER32 , 0x0000c0c1 }, /* TPBUFFER32 */
{ STB0899_OFF0_TP_BUFFER33 , STB0899_BASE_TP_BUFFER33 , 0x0000c1c1 }, /* TPBUFFER33 */
{ STB0899_OFF0_TP_BUFFER34 , STB0899_BASE_TP_BUFFER34 , 0x0000c1c1 }, /* TPBUFFER34 */
{ STB0899_OFF0_TP_BUFFER35 , STB0899_BASE_TP_BUFFER35 , 0x0000c0c1 }, /* TPBUFFER35 */
{ STB0899_OFF0_TP_BUFFER36 , STB0899_BASE_TP_BUFFER36 , 0x0000c1c1 }, /* TPBUFFER36 */
{ STB0899_OFF0_TP_BUFFER37 , STB0899_BASE_TP_BUFFER37 , 0x0000c0c1 }, /* TPBUFFER37 */
{ STB0899_OFF0_TP_BUFFER38 , STB0899_BASE_TP_BUFFER38 , 0x0000c1c1 }, /* TPBUFFER38 */
{ STB0899_OFF0_TP_BUFFER39 , STB0899_BASE_TP_BUFFER39 , 0x0000c0c0 }, /* TPBUFFER39 */
{ STB0899_OFF0_TP_BUFFER40 , STB0899_BASE_TP_BUFFER40 , 0x0000c1c0 }, /* TPBUFFER40 */
{ STB0899_OFF0_TP_BUFFER41 , STB0899_BASE_TP_BUFFER41 , 0x0000c1c1 }, /* TPBUFFER41 */
{ STB0899_OFF0_TP_BUFFER42 , STB0899_BASE_TP_BUFFER42 , 0x0000c0c0 }, /* TPBUFFER42 */
{ STB0899_OFF0_TP_BUFFER43 , STB0899_BASE_TP_BUFFER43 , 0x0000c1c0 }, /* TPBUFFER43 */
{ STB0899_OFF0_TP_BUFFER44 , STB0899_BASE_TP_BUFFER44 , 0x0000c0c1 }, /* TPBUFFER44 */
{ STB0899_OFF0_TP_BUFFER45 , STB0899_BASE_TP_BUFFER45 , 0x0000c1be }, /* TPBUFFER45 */
{ STB0899_OFF0_TP_BUFFER46 , STB0899_BASE_TP_BUFFER46 , 0x0000c1c9 }, /* TPBUFFER46 */
{ STB0899_OFF0_TP_BUFFER47 , STB0899_BASE_TP_BUFFER47 , 0x0000c0da }, /* TPBUFFER47 */
{ STB0899_OFF0_TP_BUFFER48 , STB0899_BASE_TP_BUFFER48 , 0x0000c0ba }, /* TPBUFFER48 */
{ STB0899_OFF0_TP_BUFFER49 , STB0899_BASE_TP_BUFFER49 , 0x0000c1c4 }, /* TPBUFFER49 */
{ STB0899_OFF0_TP_BUFFER50 , STB0899_BASE_TP_BUFFER50 , 0x0000c1bf }, /* TPBUFFER50 */
{ STB0899_OFF0_TP_BUFFER51 , STB0899_BASE_TP_BUFFER51 , 0x0000c0c1 }, /* TPBUFFER51 */
{ STB0899_OFF0_TP_BUFFER52 , STB0899_BASE_TP_BUFFER52 , 0x0000c1c0 }, /* TPBUFFER52 */
{ STB0899_OFF0_TP_BUFFER53 , STB0899_BASE_TP_BUFFER53 , 0x0000c0c1 }, /* TPBUFFER53 */
{ STB0899_OFF0_TP_BUFFER54 , STB0899_BASE_TP_BUFFER54 , 0x0000c1c1 }, /* TPBUFFER54 */
{ STB0899_OFF0_TP_BUFFER55 , STB0899_BASE_TP_BUFFER55 , 0x0000c1c1 }, /* TPBUFFER55 */
{ STB0899_OFF0_TP_BUFFER56 , STB0899_BASE_TP_BUFFER56 , 0x0000c1c1 }, /* TPBUFFER56 */
{ STB0899_OFF0_TP_BUFFER57 , STB0899_BASE_TP_BUFFER57 , 0x0000c1c1 }, /* TPBUFFER57 */
{ STB0899_OFF0_TP_BUFFER58 , STB0899_BASE_TP_BUFFER58 , 0x0000c1c1 }, /* TPBUFFER58 */
{ STB0899_OFF0_TP_BUFFER59 , STB0899_BASE_TP_BUFFER59 , 0x0000c1c1 }, /* TPBUFFER59 */
{ STB0899_OFF0_TP_BUFFER60 , STB0899_BASE_TP_BUFFER60 , 0x0000c1c1 }, /* TPBUFFER60 */
{ STB0899_OFF0_TP_BUFFER61 , STB0899_BASE_TP_BUFFER61 , 0x0000c1c1 }, /* TPBUFFER61 */
{ STB0899_OFF0_TP_BUFFER62 , STB0899_BASE_TP_BUFFER62 , 0x0000c1c1 }, /* TPBUFFER62 */
{ STB0899_OFF0_TP_BUFFER63 , STB0899_BASE_TP_BUFFER63 , 0x0000c1c0 }, /* TPBUFFER63 */
{ STB0899_OFF0_RESET_CNTRL , STB0899_BASE_RESET_CNTRL , 0x00000001 }, /* RESETCNTRL */
{ STB0899_OFF0_ACM_ENABLE , STB0899_BASE_ACM_ENABLE , 0x00005654 }, /* ACMENABLE */
{ STB0899_OFF0_DESCR_CNTRL , STB0899_BASE_DESCR_CNTRL , 0x00000000 }, /* DESCRCNTRL */
{ STB0899_OFF0_CSM_CNTRL1 , STB0899_BASE_CSM_CNTRL1 , 0x00020019 }, /* CSMCNTRL1 */
{ STB0899_OFF0_CSM_CNTRL2 , STB0899_BASE_CSM_CNTRL2 , 0x004b3237 }, /* CSMCNTRL2 */
{ STB0899_OFF0_CSM_CNTRL3 , STB0899_BASE_CSM_CNTRL3 , 0x0003dd17 }, /* CSMCNTRL3 */
{ STB0899_OFF0_CSM_CNTRL4 , STB0899_BASE_CSM_CNTRL4 , 0x00008008 }, /* CSMCNTRL4 */
{ STB0899_OFF0_UWP_CNTRL1 , STB0899_BASE_UWP_CNTRL1 , 0x002a3106 }, /* UWPCNTRL1 */
{ STB0899_OFF0_UWP_CNTRL2 , STB0899_BASE_UWP_CNTRL2 , 0x0006140a }, /* UWPCNTRL2 */
{ STB0899_OFF0_UWP_STAT1 , STB0899_BASE_UWP_STAT1 , 0x00008000 }, /* UWPSTAT1 */
{ STB0899_OFF0_UWP_STAT2 , STB0899_BASE_UWP_STAT2 , 0x00000000 }, /* UWPSTAT2 */
{ STB0899_OFF0_DMD_STAT2 , STB0899_BASE_DMD_STAT2 , 0x00000000 }, /* DMDSTAT2 */
{ STB0899_OFF0_FREQ_ADJ_SCALE , STB0899_BASE_FREQ_ADJ_SCALE , 0x00000471 }, /* FREQADJSCALE */
{ STB0899_OFF0_UWP_CNTRL3 , STB0899_BASE_UWP_CNTRL3 , 0x017b0465 }, /* UWPCNTRL3 */
{ STB0899_OFF0_SYM_CLK_SEL , STB0899_BASE_SYM_CLK_SEL , 0x00000002 }, /* SYMCLKSEL */
{ STB0899_OFF0_SOF_SRCH_TO , STB0899_BASE_SOF_SRCH_TO , 0x00196464 }, /* SOFSRCHTO */
{ STB0899_OFF0_ACQ_CNTRL1 , STB0899_BASE_ACQ_CNTRL1 , 0x00000603 }, /* ACQCNTRL1 */
{ STB0899_OFF0_ACQ_CNTRL2 , STB0899_BASE_ACQ_CNTRL2 , 0x02046666 }, /* ACQCNTRL2 */
{ STB0899_OFF0_ACQ_CNTRL3 , STB0899_BASE_ACQ_CNTRL3 , 0x10046583 }, /* ACQCNTRL3 */
{ STB0899_OFF0_FE_SETTLE , STB0899_BASE_FE_SETTLE , 0x00010404 }, /* FESETTLE */
{ STB0899_OFF0_AC_DWELL , STB0899_BASE_AC_DWELL , 0x0002aa8a }, /* ACDWELL */
{ STB0899_OFF0_ACQUIRE_TRIG , STB0899_BASE_ACQUIRE_TRIG , 0x00000000 }, /* ACQUIRETRIG */
{ STB0899_OFF0_LOCK_LOST , STB0899_BASE_LOCK_LOST , 0x00000001 }, /* LOCKLOST */
{ STB0899_OFF0_ACQ_STAT1 , STB0899_BASE_ACQ_STAT1 , 0x00000500 }, /* ACQSTAT1 */
{ STB0899_OFF0_ACQ_TIMEOUT , STB0899_BASE_ACQ_TIMEOUT , 0x0028a0a0 }, /* ACQTIMEOUT */
{ STB0899_OFF0_ACQ_TIME , STB0899_BASE_ACQ_TIME , 0x00000000 }, /* ACQTIME */
{ STB0899_OFF0_FINAL_AGC_CNTRL , STB0899_BASE_FINAL_AGC_CNTRL , 0x00800c17 }, /* FINALAGCCNTRL*/
{ STB0899_OFF0_FINAL_AGC_GAIN , STB0899_BASE_FINAL_AGC_GAIN , 0x00000000 }, /* FINALAGCCGAIN*/
{ STB0899_OFF0_EQUALIZER_INIT , STB0899_BASE_EQUALIZER_INIT , 0x00000000 }, /* EQUILIZERINIT*/
{ STB0899_OFF0_EQ_CNTRL , STB0899_BASE_EQ_CNTRL , 0x00054802 }, /* EQCNTL */
{ STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */
{ STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */
{ STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */
{ STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */
{ STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */
{ STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */
{ STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */
{ STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */
{ STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */
{ STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */
{ STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/
{ STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */
{ STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */
{ STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */
{ STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */
{ STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */
{ STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */
{ STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */
{ STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */
{ STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */
{ STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */
{ STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/
{ STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */
{ STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */
{ STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */
{ STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */
{ STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */
{ STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */
{ STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */
{ STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */
{ STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */
{ STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */
{ STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT10*/
{ STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */
{ STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */
{ STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */
{ STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */
{ STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */
{ STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */
{ STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */
{ STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */
{ STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */
{ STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */
{ STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/
{ 0xffff , 0xffffffff , 0xffffffff },
};
static const struct stb0899_s2_reg stb0899_s2_init_4[] = {
{ STB0899_OFF0_BLOCK_LNGTH , STB0899_BASE_BLOCK_LNGTH , 0x00000008 }, /* BLOCKLNGTH */
{ STB0899_OFF0_ROW_STR , STB0899_BASE_ROW_STR , 0x000000b4 }, /* ROWSTR */
{ STB0899_OFF0_BN_END_ADDR , STB0899_BASE_BN_END_ADDR , 0x000004b5 }, /* BNANDADDR */
{ STB0899_OFF0_CN_END_ADDR , STB0899_BASE_CN_END_ADDR , 0x00000b4b }, /* CNANDADDR */
{ STB0899_OFF0_INFO_LENGTH , STB0899_BASE_INFO_LENGTH , 0x00000078 }, /* INFOLENGTH */
{ STB0899_OFF0_BOT_ADDR , STB0899_BASE_BOT_ADDR , 0x000001e0 }, /* BOT_ADDR */
{ STB0899_OFF0_BCH_BLK_LN , STB0899_BASE_BCH_BLK_LN , 0x0000a8c0 }, /* BCHBLKLN */
{ STB0899_OFF0_BCH_T , STB0899_BASE_BCH_T , 0x0000000c }, /* BCHT */
{ STB0899_OFF0_CNFG_MODE , STB0899_BASE_CNFG_MODE , 0x00000001 }, /* CNFGMODE */
{ STB0899_OFF0_LDPC_STAT , STB0899_BASE_LDPC_STAT , 0x0000000d }, /* LDPCSTAT */
{ STB0899_OFF0_ITER_SCALE , STB0899_BASE_ITER_SCALE , 0x00000040 }, /* ITERSCALE */
{ STB0899_OFF0_INPUT_MODE , STB0899_BASE_INPUT_MODE , 0x00000000 }, /* INPUTMODE */
{ STB0899_OFF0_LDPCDECRST , STB0899_BASE_LDPCDECRST , 0x00000000 }, /* LDPCDECRST */
{ STB0899_OFF0_CLK_PER_BYTE_RW , STB0899_BASE_CLK_PER_BYTE_RW , 0x00000008 }, /* CLKPERBYTE */
{ STB0899_OFF0_BCH_ERRORS , STB0899_BASE_BCH_ERRORS , 0x00000000 }, /* BCHERRORS */
{ STB0899_OFF0_LDPC_ERRORS , STB0899_BASE_LDPC_ERRORS , 0x00000000 }, /* LDPCERRORS */
{ STB0899_OFF0_BCH_MODE , STB0899_BASE_BCH_MODE , 0x00000000 }, /* BCHMODE */
{ STB0899_OFF0_ERR_ACC_PER , STB0899_BASE_ERR_ACC_PER , 0x00000008 }, /* ERRACCPER */
{ STB0899_OFF0_BCH_ERR_ACC , STB0899_BASE_BCH_ERR_ACC , 0x00000000 }, /* BCHERRACC */
{ STB0899_OFF0_FEC_TP_SEL , STB0899_BASE_FEC_TP_SEL , 0x00000000 }, /* FECTPSEL */
{ 0xffff , 0xffffffff , 0xffffffff },
};
static const struct stb0899_s1_reg stb0899_s1_init_5[] = {
{ STB0899_TSTCK , 0x00 },
{ STB0899_TSTRES , 0x00 },
{ STB0899_TSTOUT , 0x00 },
{ STB0899_TSTIN , 0x00 },
{ STB0899_TSTSYS , 0x00 },
{ STB0899_TSTCHIP , 0x00 },
{ STB0899_TSTFREE , 0x00 },
{ STB0899_TSTI2C , 0x00 },
{ STB0899_BITSPEEDM , 0x00 },
{ STB0899_BITSPEEDL , 0x00 },
{ STB0899_TBUSBIT , 0x00 },
{ STB0899_TSTDIS , 0x00 },
{ STB0899_TSTDISRX , 0x00 },
{ STB0899_TSTJETON , 0x00 },
{ STB0899_TSTDCADJ , 0x00 },
{ STB0899_TSTAGC1 , 0x00 },
{ STB0899_TSTAGC1N , 0x00 },
{ STB0899_TSTPOLYPH , 0x00 },
{ STB0899_TSTR , 0x00 },
{ STB0899_TSTAGC2 , 0x00 },
{ STB0899_TSTCTL1 , 0x00 },
{ STB0899_TSTCTL2 , 0x00 },
{ STB0899_TSTCTL3 , 0x00 },
{ STB0899_TSTDEMAP , 0x00 },
{ STB0899_TSTDEMAP2 , 0x00 },
{ STB0899_TSTDEMMON , 0x00 },
{ STB0899_TSTRATE , 0x00 },
{ STB0899_TSTSELOUT , 0x00 },
{ STB0899_TSYNC , 0x00 },
{ STB0899_TSTERR , 0x00 },
{ STB0899_TSTRAM1 , 0x00 },
{ STB0899_TSTVSELOUT , 0x00 },
{ STB0899_TSTFORCEIN , 0x00 },
{ STB0899_TSTRS1 , 0x00 },
{ STB0899_TSTRS2 , 0x00 },
{ STB0899_TSTRS3 , 0x00 },
{ STB0899_GHOSTREG , 0x81 },
{ 0xffff , 0xff },
};
#define STB0899_DVBS2_ESNO_AVE 3
#define STB0899_DVBS2_ESNO_QUANT 32
#define STB0899_DVBS2_AVFRAMES_COARSE 10
#define STB0899_DVBS2_AVFRAMES_FINE 20
#define STB0899_DVBS2_MISS_THRESHOLD 6
#define STB0899_DVBS2_UWP_THRESHOLD_ACQ 1125
#define STB0899_DVBS2_UWP_THRESHOLD_TRACK 758
#define STB0899_DVBS2_UWP_THRESHOLD_SOF 1350
#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT 1664100
#define STB0899_DVBS2_BTR_NCO_BITS 28
#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET 15
#define STB0899_DVBS2_CRL_NCO_BITS 30
#define STB0899_DVBS2_LDPC_MAX_ITER 70
#endif //__STB0899_CFG_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,162 @@
/*
STB0899 Multistandard Frontend driver
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
Copyright (C) ST Microelectronics
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.
*/
#ifndef __STB0899_DRV_H
#define __STB0899_DRV_H
#include <linux/kernel.h>
#include <linux/module.h>
#include "dvb_frontend.h"
#define STB0899_TSMODE_SERIAL 1
#define STB0899_CLKPOL_FALLING 2
#define STB0899_CLKNULL_PARITY 3
#define STB0899_SYNC_FORCED 4
#define STB0899_FECMODE_DSS 5
struct stb0899_s1_reg {
u16 address;
u8 data;
};
struct stb0899_s2_reg {
u16 offset;
u32 base_address;
u32 data;
};
enum stb0899_inversion {
IQ_SWAP_OFF = 0,
IQ_SWAP_ON,
IQ_SWAP_AUTO
};
#define STB0899_GPIO00 0xf140
#define STB0899_GPIO01 0xf141
#define STB0899_GPIO02 0xf142
#define STB0899_GPIO03 0xf143
#define STB0899_GPIO04 0xf144
#define STB0899_GPIO05 0xf145
#define STB0899_GPIO06 0xf146
#define STB0899_GPIO07 0xf147
#define STB0899_GPIO08 0xf148
#define STB0899_GPIO09 0xf149
#define STB0899_GPIO10 0xf14a
#define STB0899_GPIO11 0xf14b
#define STB0899_GPIO12 0xf14c
#define STB0899_GPIO13 0xf14d
#define STB0899_GPIO14 0xf14e
#define STB0899_GPIO15 0xf14f
#define STB0899_GPIO16 0xf150
#define STB0899_GPIO17 0xf151
#define STB0899_GPIO18 0xf152
#define STB0899_GPIO19 0xf153
#define STB0899_GPIO20 0xf154
#define STB0899_GPIOPULLUP 0x01 /* Output device is connected to Vdd */
#define STB0899_GPIOPULLDN 0x00 /* Output device is connected to Vss */
#define STB0899_POSTPROC_GPIO_POWER 0x00
#define STB0899_POSTPROC_GPIO_LOCK 0x01
/*
* Post process output configuration control
* 1. POWER ON/OFF (index 0)
* 2. FE_HAS_LOCK/LOCK_LOSS (index 1)
*
* @gpio = one of the above listed GPIO's
* @level = output state: pulled up or low
*/
struct stb0899_postproc {
u16 gpio;
u8 level;
};
struct stb0899_config {
const struct stb0899_s1_reg *init_dev;
const struct stb0899_s2_reg *init_s2_demod;
const struct stb0899_s1_reg *init_s1_demod;
const struct stb0899_s2_reg *init_s2_fec;
const struct stb0899_s1_reg *init_tst;
const struct stb0899_postproc *postproc;
enum stb0899_inversion inversion;
u32 xtal_freq;
u8 demod_address;
u8 ts_output_mode;
u8 block_sync_mode;
u8 ts_pfbit_toggle;
u8 clock_polarity;
u8 data_clk_parity;
u8 fec_mode;
u8 data_output_ctl;
u8 data_fifo_mode;
u8 out_rate_comp;
u8 i2c_repeater;
// int inversion;
int lo_clk;
int hi_clk;
u32 esno_ave;
u32 esno_quant;
u32 avframes_coarse;
u32 avframes_fine;
u32 miss_threshold;
u32 uwp_threshold_acq;
u32 uwp_threshold_track;
u32 uwp_threshold_sof;
u32 sof_search_timeout;
u32 btr_nco_bits;
u32 btr_gain_shift_offset;
u32 crl_nco_bits;
u32 ldpc_max_iter;
int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency);
int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency);
int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
};
#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif //CONFIG_DVB_STB0899
#endif

View file

@ -0,0 +1,267 @@
/*
STB0899 Multistandard Frontend driver
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
Copyright (C) ST Microelectronics
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.
*/
#ifndef __STB0899_PRIV_H
#define __STB0899_PRIV_H
#include "dvb_frontend.h"
#include "stb0899_drv.h"
#define FE_ERROR 0
#define FE_NOTICE 1
#define FE_INFO 2
#define FE_DEBUG 3
#define FE_DEBUGREG 4
#define dprintk(x, y, z, format, arg...) do { \
if (z) { \
if ((*x > FE_ERROR) && (*x > y)) \
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
else if ((*x > FE_NOTICE) && (*x > y)) \
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
else if ((*x > FE_INFO) && (*x > y)) \
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
else if ((*x > FE_DEBUG) && (*x > y)) \
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
} else { \
if (*x > y) \
printk(format, ##arg); \
} \
} while(0)
#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \
((y <= val) && (val <= x)) ? 1 : 0)
#define BYTE0 0
#define BYTE1 8
#define BYTE2 16
#define BYTE3 24
#define GETBYTE(x, y) (((x) >> (y)) & 0xff)
#define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
#define MAKEWORD16(a, b) (((a) << 8) | (b))
#define MIN(x, y) ((x) <= (y) ? (x) : (y))
#define MAX(x, y) ((x) >= (y) ? (x) : (y))
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define LSB(x) ((x & 0xff))
#define MSB(y) ((y >> 8) & 0xff)
#define STB0899_GETFIELD(bitf, val) ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1))
#define STB0899_SETFIELD(mask, val, width, offset) (mask & (~(((1 << width) - 1) << \
offset))) | ((val & \
((1 << width) - 1)) << offset)
#define STB0899_SETFIELD_VAL(bitf, mask, val) (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\
STB0899_OFFST_##bitf))) | \
(val << STB0899_OFFST_##bitf))
enum stb0899_status {
NOAGC1 = 0,
AGC1OK,
NOTIMING,
ANALOGCARRIER,
TIMINGOK,
NOAGC2,
AGC2OK,
NOCARRIER,
CARRIEROK,
NODATA,
FALSELOCK,
DATAOK,
OUTOFRANGE,
RANGEOK,
DVBS2_DEMOD_LOCK,
DVBS2_DEMOD_NOLOCK,
DVBS2_FEC_LOCK,
DVBS2_FEC_NOLOCK
};
enum stb0899_modcod {
STB0899_DUMMY_PLF,
STB0899_QPSK_14,
STB0899_QPSK_13,
STB0899_QPSK_25,
STB0899_QPSK_12,
STB0899_QPSK_35,
STB0899_QPSK_23,
STB0899_QPSK_34,
STB0899_QPSK_45,
STB0899_QPSK_56,
STB0899_QPSK_89,
STB0899_QPSK_910,
STB0899_8PSK_35,
STB0899_8PSK_23,
STB0899_8PSK_34,
STB0899_8PSK_56,
STB0899_8PSK_89,
STB0899_8PSK_910,
STB0899_16APSK_23,
STB0899_16APSK_34,
STB0899_16APSK_45,
STB0899_16APSK_56,
STB0899_16APSK_89,
STB0899_16APSK_910,
STB0899_32APSK_34,
STB0899_32APSK_45,
STB0899_32APSK_56,
STB0899_32APSK_89,
STB0899_32APSK_910
};
enum stb0899_frame {
STB0899_LONG_FRAME,
STB0899_SHORT_FRAME
};
enum stb0899_alpha {
RRC_20,
RRC_25,
RRC_35
};
struct stb0899_tab {
s32 real;
s32 read;
};
enum stb0899_fec {
STB0899_FEC_1_2 = 13,
STB0899_FEC_2_3 = 18,
STB0899_FEC_3_4 = 21,
STB0899_FEC_5_6 = 24,
STB0899_FEC_6_7 = 25,
STB0899_FEC_7_8 = 26
};
struct stb0899_params {
u32 freq; /* Frequency */
u32 srate; /* Symbol rate */
enum fe_code_rate fecrate;
};
struct stb0899_internal {
u32 master_clk;
u32 freq; /* Demod internal Frequency */
u32 srate; /* Demod internal Symbol rate */
enum stb0899_fec fecrate; /* Demod internal FEC rate */
u32 srch_range; /* Demod internal Search Range */
u32 sub_range; /* Demod current sub range (Hz) */
u32 tuner_step; /* Tuner step (Hz) */
u32 tuner_offst; /* Relative offset to carrier (Hz) */
u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */
s32 mclk; /* Masterclock Divider factor (binary) */
s32 rolloff; /* Current RollOff of the filter (x100) */
s16 derot_freq; /* Current derotator frequency (Hz) */
s16 derot_percent;
s16 direction; /* Current derotator search direction */
s16 derot_step; /* Derotator step (binary value) */
s16 t_derot; /* Derotator time constant (ms) */
s16 t_data; /* Data recovery time constant (ms) */
s16 sub_dir; /* Direction of the next sub range */
s16 t_agc1; /* Agc1 time constant (ms) */
s16 t_agc2; /* Agc2 time constant (ms) */
u32 lock; /* Demod internal lock state */
enum stb0899_status status; /* Demod internal status */
/* DVB-S2 */
s32 agc_gain; /* RF AGC Gain */
s32 center_freq; /* Nominal carrier frequency */
s32 av_frame_coarse; /* Coarse carrier freq search frames */
s32 av_frame_fine; /* Fine carrier freq search frames */
s16 step_size; /* Carrier frequency search step size */
enum stb0899_alpha rrc_alpha;
enum stb0899_inversion inversion;
enum stb0899_modcod modcod;
u8 pilots; /* Pilots found */
enum stb0899_frame frame_length;
u8 v_status; /* VSTATUS */
u8 err_ctrl; /* ERRCTRLn */
};
struct stb0899_state {
struct i2c_adapter *i2c;
struct stb0899_config *config;
struct dvb_frontend frontend;
u32 *verbose; /* Cached module verbosity level */
struct stb0899_internal internal; /* Device internal parameters */
/* cached params from API */
enum fe_delivery_system delsys;
struct stb0899_params params;
u32 rx_freq; /* DiSEqC 2.0 receiver freq */
struct mutex search_lock;
};
/* stb0899.c */
extern int stb0899_read_reg(struct stb0899_state *state,
unsigned int reg);
extern u32 _stb0899_read_s2reg(struct stb0899_state *state,
u32 stb0899_i2cdev,
u32 stb0899_base_addr,
u16 stb0899_reg_offset);
extern int stb0899_read_regs(struct stb0899_state *state,
unsigned int reg, u8 *buf,
u32 count);
extern int stb0899_write_regs(struct stb0899_state *state,
unsigned int reg, u8 *data,
u32 count);
extern int stb0899_write_reg(struct stb0899_state *state,
unsigned int reg,
u8 data);
extern int stb0899_write_s2reg(struct stb0899_state *state,
u32 stb0899_i2cdev,
u32 stb0899_base_addr,
u16 stb0899_reg_offset,
u32 stb0899_data);
extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
#define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG))
//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA) (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA))
/* stb0899_algo.c */
extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state);
extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state);
extern long stb0899_carr_width(struct stb0899_state *state);
#endif //__STB0899_PRIV_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,545 @@
/*
STB6100 Silicon Tuner
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
Copyright (C) ST Microelectronics
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.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include "dvb_frontend.h"
#include "stb6100.h"
static unsigned int verbose;
module_param(verbose, int, 0644);
#define FE_ERROR 0
#define FE_NOTICE 1
#define FE_INFO 2
#define FE_DEBUG 3
#define dprintk(x, y, z, format, arg...) do { \
if (z) { \
if ((x > FE_ERROR) && (x > y)) \
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
else if ((x > FE_NOTICE) && (x > y)) \
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
else if ((x > FE_INFO) && (x > y)) \
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
else if ((x > FE_DEBUG) && (x > y)) \
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
} else { \
if (x > y) \
printk(format, ##arg); \
} \
} while(0)
struct stb6100_lkup {
u32 val_low;
u32 val_high;
u8 reg;
};
static int stb6100_release(struct dvb_frontend *fe);
static const struct stb6100_lkup lkup[] = {
{ 0, 950000, 0x0a },
{ 950000, 1000000, 0x0a },
{ 1000000, 1075000, 0x0c },
{ 1075000, 1200000, 0x00 },
{ 1200000, 1300000, 0x01 },
{ 1300000, 1370000, 0x02 },
{ 1370000, 1470000, 0x04 },
{ 1470000, 1530000, 0x05 },
{ 1530000, 1650000, 0x06 },
{ 1650000, 1800000, 0x08 },
{ 1800000, 1950000, 0x0a },
{ 1950000, 2150000, 0x0c },
{ 2150000, 9999999, 0x0c },
{ 0, 0, 0x00 }
};
/* Register names for easy debugging. */
static const char *stb6100_regnames[] = {
[STB6100_LD] = "LD",
[STB6100_VCO] = "VCO",
[STB6100_NI] = "NI",
[STB6100_NF_LSB] = "NF",
[STB6100_K] = "K",
[STB6100_G] = "G",
[STB6100_F] = "F",
[STB6100_DLB] = "DLB",
[STB6100_TEST1] = "TEST1",
[STB6100_FCCK] = "FCCK",
[STB6100_LPEN] = "LPEN",
[STB6100_TEST3] = "TEST3",
};
/* Template for normalisation, i.e. setting unused or undocumented
* bits as required according to the documentation.
*/
struct stb6100_regmask {
u8 mask;
u8 set;
};
static const struct stb6100_regmask stb6100_template[] = {
[STB6100_LD] = { 0xff, 0x00 },
[STB6100_VCO] = { 0xff, 0x00 },
[STB6100_NI] = { 0xff, 0x00 },
[STB6100_NF_LSB] = { 0xff, 0x00 },
[STB6100_K] = { 0xc7, 0x38 },
[STB6100_G] = { 0xef, 0x10 },
[STB6100_F] = { 0x1f, 0xc0 },
[STB6100_DLB] = { 0x38, 0xc4 },
[STB6100_TEST1] = { 0x00, 0x8f },
[STB6100_FCCK] = { 0x40, 0x0d },
[STB6100_LPEN] = { 0xf0, 0x0b },
[STB6100_TEST3] = { 0x00, 0xde },
};
static void stb6100_normalise_regs(u8 regs[])
{
int i;
for (i = 0; i < STB6100_NUMREGS; i++)
regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set;
}
static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
{
int rc;
struct i2c_msg msg = {
.addr = state->config->tuner_address,
.flags = I2C_M_RD,
.buf = regs,
.len = STB6100_NUMREGS
};
rc = i2c_transfer(state->i2c, &msg, 1);
if (unlikely(rc != 1)) {
dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]",
state->config->tuner_address, rc);
return -EREMOTEIO;
}
if (unlikely(verbose > FE_DEBUG)) {
int i;
dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address);
for (i = 0; i < STB6100_NUMREGS; i++)
dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[i], regs[i]);
}
return 0;
}
static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
{
u8 regs[STB6100_NUMREGS];
int rc;
if (unlikely(reg >= STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
return -EINVAL;
}
if ((rc = stb6100_read_regs(state, regs)) < 0)
return rc;
return (unsigned int)regs[reg];
}
static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
{
int rc;
u8 cmdbuf[len + 1];
struct i2c_msg msg = {
.addr = state->config->tuner_address,
.flags = 0,
.buf = cmdbuf,
.len = len + 1
};
if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d",
start, len);
return -EINVAL;
}
memcpy(&cmdbuf[1], buf, len);
cmdbuf[0] = start;
if (unlikely(verbose > FE_DEBUG)) {
int i;
dprintk(verbose, FE_DEBUG, 1, " Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len);
for (i = 0; i < len; i++)
dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[start + i], buf[i]);
}
rc = i2c_transfer(state->i2c, &msg, 1);
if (unlikely(rc != 1)) {
dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]",
(unsigned int)state->config->tuner_address, start, len, rc);
return -EREMOTEIO;
}
return 0;
}
static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
{
if (unlikely(reg >= STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
return -EREMOTEIO;
}
data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
return stb6100_write_reg_range(state, &data, reg, 1);
}
static int stb6100_write_regs(struct stb6100_state *state, u8 regs[])
{
stb6100_normalise_regs(regs);
return stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 1);
}
static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
{
int rc;
struct stb6100_state *state = fe->tuner_priv;
if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0)
return rc;
return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
}
static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
int rc;
u8 f;
struct stb6100_state *state = fe->tuner_priv;
if ((rc = stb6100_read_reg(state, STB6100_F)) < 0)
return rc;
f = rc & STB6100_F_F;
state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */
*bandwidth = state->bandwidth = state->status.bandwidth * 1000;
dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
return 0;
}
static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
{
u32 tmp;
int rc;
struct stb6100_state *state = fe->tuner_priv;
dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth);
bandwidth /= 2; /* ZIF */
if (bandwidth >= 36000000) /* F[4:0] BW/2 max =31+5=36 mhz for F=31 */
tmp = 31;
else if (bandwidth <= 5000000) /* bw/2 min = 5Mhz for F=0 */
tmp = 0;
else /* if 5 < bw/2 < 36 */
tmp = (bandwidth + 500000) / 1000000 - 5;
/* Turn on LPF bandwidth setting clock control,
* set bandwidth, wait 10ms, turn off.
*/
if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0)
return rc;
if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0)
return rc;
msleep(1);
if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0)
return rc;
return 0;
}
static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
int rc;
u32 nint, nfrac, fvco;
int psd2, odiv;
struct stb6100_state *state = fe->tuner_priv;
u8 regs[STB6100_NUMREGS];
if ((rc = stb6100_read_regs(state, regs)) < 0)
return rc;
odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT;
nint = regs[STB6100_NI];
nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB];
fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2);
*frequency = state->frequency = fvco >> (odiv + 1);
dprintk(verbose, FE_DEBUG, 1,
"frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u",
state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac);
return 0;
}
static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
int rc;
const struct stb6100_lkup *ptr;
struct stb6100_state *state = fe->tuner_priv;
struct dvb_frontend_parameters p;
u32 srate = 0, fvco, nint, nfrac;
u8 regs[STB6100_NUMREGS];
u8 g, psd2, odiv;
if ((rc = stb6100_read_regs(state, regs)) < 0)
return rc;
if (fe->ops.get_frontend) {
dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
fe->ops.get_frontend(fe, &p);
}
srate = p.u.qpsk.symbol_rate;
regs[STB6100_DLB] = 0xdc;
/* Disable LPEN */
regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */
if ((rc = stb6100_write_regs(state, regs)) < 0)
return rc;
/* Baseband gain. */
if (srate >= 15000000)
g = 9; // +4 dB
else if (srate >= 5000000)
g = 11; // +8 dB
else
g = 14; // +14 dB
regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g;
regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
/* VCO divide ratio (LO divide ratio, VCO prescaler enable). */
if (frequency <= 1075000)
odiv = 1;
else
odiv = 0;
regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT);
if ((frequency > 1075000) && (frequency <= 1325000))
psd2 = 0;
else
psd2 = 1;
regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
/* OSM */
for (ptr = lkup;
(ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
ptr++);
if (ptr->val_high == 0) {
printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
return -EINVAL;
}
regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */
fvco = frequency << (1 + odiv);
/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */
nint = fvco / (state->reference << psd2);
/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */
nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference;
dprintk(verbose, FE_DEBUG, 1,
"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
frequency, srate, (unsigned int)g, (unsigned int)odiv,
(unsigned int)psd2, state->reference,
ptr->reg, fvco, nint, nfrac);
regs[STB6100_NI] = nint;
regs[STB6100_NF_LSB] = nfrac;
regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */
regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */
regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */
regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */
/* Power up. */
regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN;
msleep(2);
if ((rc = stb6100_write_regs(state, regs)) < 0)
return rc;
msleep(2);
regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */
if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0)
return rc;
regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */
if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
return rc;
msleep(10); /* wait for LO to lock */
regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */
regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */
if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
return rc;
regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */
stb6100_normalise_regs(regs);
if ((rc = stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 3)) < 0)
return rc;
msleep(100);
return 0;
}
static int stb6100_sleep(struct dvb_frontend *fe)
{
/* TODO: power down */
return 0;
}
static int stb6100_init(struct dvb_frontend *fe)
{
struct stb6100_state *state = fe->tuner_priv;
struct tuner_state *status = &state->status;
status->tunerstep = 125000;
status->ifreq = 0;
status->refclock = 27000000; /* Hz */
status->iqsense = 1;
status->bandwidth = 36000; /* kHz */
state->bandwidth = status->bandwidth * 1000; /* MHz */
state->reference = status->refclock / 1000; /* kHz */
/* Set default bandwidth. */
return stb6100_set_bandwidth(fe, status->bandwidth);
}
static int stb6100_get_state(struct dvb_frontend *fe,
enum tuner_param param,
struct tuner_state *state)
{
switch (param) {
case DVBFE_TUNER_FREQUENCY:
stb6100_get_frequency(fe, &state->frequency);
break;
case DVBFE_TUNER_TUNERSTEP:
break;
case DVBFE_TUNER_IFFREQ:
break;
case DVBFE_TUNER_BANDWIDTH:
stb6100_get_bandwidth(fe, &state->bandwidth);
break;
case DVBFE_TUNER_REFCLOCK:
break;
default:
break;
}
return 0;
}
static int stb6100_set_state(struct dvb_frontend *fe,
enum tuner_param param,
struct tuner_state *state)
{
struct stb6100_state *tstate = fe->tuner_priv;
switch (param) {
case DVBFE_TUNER_FREQUENCY:
stb6100_set_frequency(fe, state->frequency);
tstate->frequency = state->frequency;
break;
case DVBFE_TUNER_TUNERSTEP:
break;
case DVBFE_TUNER_IFFREQ:
break;
case DVBFE_TUNER_BANDWIDTH:
stb6100_set_bandwidth(fe, state->bandwidth);
tstate->bandwidth = state->bandwidth;
break;
case DVBFE_TUNER_REFCLOCK:
break;
default:
break;
}
return 0;
}
static struct dvb_tuner_ops stb6100_ops = {
.info = {
.name = "STB6100 Silicon Tuner",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 0,
},
.init = stb6100_init,
.sleep = stb6100_sleep,
.get_status = stb6100_get_status,
.get_state = stb6100_get_state,
.set_state = stb6100_set_state,
.release = stb6100_release
};
struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
struct stb6100_config *config,
struct i2c_adapter *i2c)
{
struct stb6100_state *state = NULL;
state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL);
if (state == NULL)
goto error;
state->config = config;
state->i2c = i2c;
state->frontend = fe;
state->reference = config->refclock / 1000; /* kHz */
fe->tuner_priv = state;
fe->ops.tuner_ops = stb6100_ops;
printk("%s: Attaching STB6100 \n", __func__);
return fe;
error:
kfree(state);
return NULL;
}
static int stb6100_release(struct dvb_frontend *fe)
{
struct stb6100_state *state = fe->tuner_priv;
fe->tuner_priv = NULL;
kfree(state);
return 0;
}
EXPORT_SYMBOL(stb6100_attach);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STB6100 Silicon tuner");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,115 @@
/*
STB6100 Silicon Tuner
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
Copyright (C) ST Microelectronics
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.
*/
#ifndef __STB_6100_REG_H
#define __STB_6100_REG_H
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
#define STB6100_LD 0x00
#define STB6100_LD_LOCK (1 << 0)
#define STB6100_VCO 0x01
#define STB6100_VCO_OSCH (0x01 << 7)
#define STB6100_VCO_OSCH_SHIFT 7
#define STB6100_VCO_OCK (0x03 << 5)
#define STB6100_VCO_OCK_SHIFT 5
#define STB6100_VCO_ODIV (0x01 << 4)
#define STB6100_VCO_ODIV_SHIFT 4
#define STB6100_VCO_OSM (0x0f << 0)
#define STB6100_NI 0x02
#define STB6100_NF_LSB 0x03
#define STB6100_K 0x04
#define STB6100_K_PSD2 (0x01 << 2)
#define STB6100_K_PSD2_SHIFT 2
#define STB6100_K_NF_MSB (0x03 << 0)
#define STB6100_G 0x05
#define STB6100_G_G (0x0f << 0)
#define STB6100_G_GCT (0x07 << 5)
#define STB6100_F 0x06
#define STB6100_F_F (0x1f << 0)
#define STB6100_DLB 0x07
#define STB6100_TEST1 0x08
#define STB6100_FCCK 0x09
#define STB6100_FCCK_FCCK (0x01 << 6)
#define STB6100_LPEN 0x0a
#define STB6100_LPEN_LPEN (0x01 << 4)
#define STB6100_LPEN_SYNP (0x01 << 5)
#define STB6100_LPEN_OSCP (0x01 << 6)
#define STB6100_LPEN_BEN (0x01 << 7)
#define STB6100_TEST3 0x0b
#define STB6100_NUMREGS 0x0c
#define INRANGE(val, x, y) (((x <= val) && (val <= y)) || \
((y <= val) && (val <= x)) ? 1 : 0)
#define CHKRANGE(val, x, y) (((val >= x) && (val < y)) ? 1 : 0)
struct stb6100_config {
u8 tuner_address;
u32 refclock;
};
struct stb6100_state {
struct i2c_adapter *i2c;
const struct stb6100_config *config;
struct dvb_tuner_ops ops;
struct dvb_frontend *frontend;
struct tuner_state status;
u32 frequency;
u32 srate;
u32 bandwidth;
u32 reference;
};
#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
struct stb6100_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
struct stb6100_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif //CONFIG_DVB_STB6100
#endif

View file

@ -0,0 +1,108 @@
/*
STB6100 Silicon Tuner
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
Copyright (C) ST Microelectronics
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.
*/
static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
struct tuner_state t_state;
int err = 0;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
*frequency = t_state.frequency;
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
}
return 0;
}
static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
struct tuner_state t_state;
int err = 0;
t_state.frequency = frequency;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_state) {
if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
}
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
return 0;
}
static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
*bandwidth = t_state.bandwidth;
}
printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
return 0;
}
static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
{
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
struct tuner_state t_state;
int err = 0;
t_state.bandwidth = bandwidth;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_state) {
if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
}
printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
return 0;
}

View file

@ -0,0 +1,230 @@
/*
TDA8261 8PSK/QPSK tuner driver
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "dvb_frontend.h"
#include "tda8261.h"
struct tda8261_state {
struct dvb_frontend *fe;
struct i2c_adapter *i2c;
const struct tda8261_config *config;
/* state cache */
u32 frequency;
u32 bandwidth;
};
static int tda8261_read(struct tda8261_state *state, u8 *buf)
{
const struct tda8261_config *config = state->config;
int err = 0;
struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD,.buf = buf, .len = 2 };
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
printk("%s: read error, err=%d\n", __func__, err);
return err;
}
static int tda8261_write(struct tda8261_state *state, u8 *buf)
{
const struct tda8261_config *config = state->config;
int err = 0;
struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 };
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
printk("%s: write error, err=%d\n", __func__, err);
return err;
}
static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
{
struct tda8261_state *state = fe->tuner_priv;
u8 result = 0;
int err = 0;
*status = 0;
if ((err = tda8261_read(state, &result)) < 0) {
printk("%s: I/O Error\n", __func__);
return err;
}
if ((result >> 6) & 0x01) {
printk("%s: Tuner Phase Locked\n", __func__);
*status = 1;
}
return err;
}
static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */
static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
static int tda8261_get_state(struct dvb_frontend *fe,
enum tuner_param param,
struct tuner_state *tstate)
{
struct tda8261_state *state = fe->tuner_priv;
int err = 0;
switch (param) {
case DVBFE_TUNER_FREQUENCY:
tstate->frequency = state->frequency;
break;
case DVBFE_TUNER_BANDWIDTH:
tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
break;
default:
printk("%s: Unknown parameter (param=%d)\n", __func__, param);
err = -EINVAL;
break;
}
return err;
}
static int tda8261_set_state(struct dvb_frontend *fe,
enum tuner_param param,
struct tuner_state *tstate)
{
struct tda8261_state *state = fe->tuner_priv;
const struct tda8261_config *config = state->config;
u32 frequency, N, status = 0;
u8 buf[4];
int err = 0;
if (param & DVBFE_TUNER_FREQUENCY) {
/**
* N = Max VCO Frequency / Channel Spacing
* Max VCO Frequency = VCO frequency + (channel spacing - 1)
* (to account for half channel spacing on either side)
*/
frequency = tstate->frequency;
if ((frequency < 950000) || (frequency > 2150000)) {
printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
return -EINVAL;
}
N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
__func__, config->step_size, div_tab[config->step_size], N, N);
buf[0] = (N >> 8) & 0xff;
buf[1] = N & 0xff;
buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
if (frequency < 1450000)
buf[3] = 0x00;
if (frequency < 2000000)
buf[3] = 0x40;
if (frequency < 2150000)
buf[3] = 0x80;
/* Set params */
if ((err = tda8261_write(state, buf)) < 0) {
printk("%s: I/O Error\n", __func__);
return err;
}
/* sleep for some time */
printk("%s: Waiting to Phase LOCK\n", __func__);
msleep(20);
/* check status */
if ((err = tda8261_get_status(fe, &status)) < 0) {
printk("%s: I/O Error\n", __func__);
return err;
}
if (status == 1) {
printk("%s: Tuner Phase locked: status=%d\n", __func__, status);
state->frequency = frequency; /* cache successful state */
} else {
printk("%s: No Phase lock: status=%d\n", __func__, status);
}
} else {
printk("%s: Unknown parameter (param=%d)\n", __func__, param);
return -EINVAL;
}
return 0;
}
static int tda8261_release(struct dvb_frontend *fe)
{
struct tda8261_state *state = fe->tuner_priv;
fe->tuner_priv = NULL;
kfree(state);
return 0;
}
static struct dvb_tuner_ops tda8261_ops = {
.info = {
.name = "TDA8261",
// .tuner_name = NULL,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 0
},
.set_state = tda8261_set_state,
.get_state = tda8261_get_state,
.get_status = tda8261_get_status,
.release = tda8261_release
};
struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
const struct tda8261_config *config,
struct i2c_adapter *i2c)
{
struct tda8261_state *state = NULL;
if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL)
goto exit;
state->config = config;
state->i2c = i2c;
state->fe = fe;
fe->tuner_priv = state;
fe->ops.tuner_ops = tda8261_ops;
fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
// fe->ops.tuner_ops.tuner_name = &config->buf;
// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
// __func__, fe->ops.tuner_ops.tuner_name);
printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
return fe;
exit:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(tda8261_attach);
MODULE_PARM_DESC(verbose, "Set verbosity level");
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,55 @@
/*
TDA8261 8PSK/QPSK tuner driver
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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.
*/
#ifndef __TDA8261_H
#define __TDA8261_H
enum tda8261_step {
TDA8261_STEP_2000 = 0, /* 2000 kHz */
TDA8261_STEP_1000, /* 1000 kHz */
TDA8261_STEP_500, /* 500 kHz */
TDA8261_STEP_250, /* 250 kHz */
TDA8261_STEP_125 /* 125 kHz */
};
struct tda8261_config {
// u8 buf[16];
u8 addr;
enum tda8261_step step_size;
};
#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
const struct tda8261_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
const struct tda8261_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif //CONFIG_DVB_TDA8261
#endif// __TDA8261_H

View file

@ -0,0 +1,84 @@
/*
TDA8261 8PSK/QPSK tuner driver
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
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.
*/
static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
struct tuner_state t_state;
int err = 0;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
*frequency = t_state.frequency;
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
}
return 0;
}
static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
struct tuner_state t_state;
int err = 0;
t_state.frequency = frequency;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_state) {
if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
}
printk("%s: Frequency=%d\n", __func__, t_state.frequency);
return 0;
}
static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
if (&fe->ops)
frontend_ops = &fe->ops;
if (&frontend_ops->tuner_ops)
tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
*bandwidth = t_state.bandwidth;
}
printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
return 0;
}

View file

@ -220,15 +220,18 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
/* These are extrapolated from the 7 and 8MHz values */
zl10353_single_write(fe, MCLK_RATIO, 0x97);
zl10353_single_write(fe, 0x64, 0x34);
zl10353_single_write(fe, 0xcc, 0xdd);
break;
case BANDWIDTH_7_MHZ:
zl10353_single_write(fe, MCLK_RATIO, 0x86);
zl10353_single_write(fe, 0x64, 0x35);
zl10353_single_write(fe, 0xcc, 0x73);
break;
case BANDWIDTH_8_MHZ:
default:
zl10353_single_write(fe, MCLK_RATIO, 0x75);
zl10353_single_write(fe, 0x64, 0x36);
zl10353_single_write(fe, 0xcc, 0x73);
}
zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);

View file

@ -38,6 +38,16 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
{ USB_DEVICE(0x2040, 0x1801),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
{ USB_DEVICE(0x2040, 0x2000),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
{ USB_DEVICE(0x2040, 0x2009),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
{ USB_DEVICE(0x2040, 0x200a),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
{ USB_DEVICE(0x2040, 0x2010),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
{ USB_DEVICE(0x2040, 0x2019),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
{ USB_DEVICE(0x2040, 0x5500),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5510),
@ -96,6 +106,21 @@ static struct sms_board sms_boards[] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.led_power = 26,
.led_lo = 27,
.led_hi = 28,
},
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
.name = "Hauppauge WinTV MiniCard",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.lna_ctrl = 29,
},
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
.name = "Hauppauge WinTV MiniCard",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.lna_ctrl = 1,
},
};
@ -106,3 +131,88 @@ struct sms_board *sms_get_board(int id)
return &sms_boards[id];
}
static int sms_set_gpio(struct smscore_device_t *coredev, u32 pin, int enable)
{
int ret;
struct smscore_gpio_config gpioconfig = {
.direction = SMS_GPIO_DIRECTION_OUTPUT,
.pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
.outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST,
.outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA,
};
if (pin == 0)
return -EINVAL;
ret = smscore_configure_gpio(coredev, pin, &gpioconfig);
if (ret < 0)
return ret;
return smscore_set_gpio(coredev, pin, enable);
}
int sms_board_setup(struct smscore_device_t *coredev)
{
int board_id = smscore_get_board_id(coredev);
struct sms_board *board = sms_get_board(board_id);
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
/* turn off all LEDs */
sms_set_gpio(coredev, board->led_power, 0);
sms_set_gpio(coredev, board->led_hi, 0);
sms_set_gpio(coredev, board->led_lo, 0);
break;
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
/* turn off LNA */
sms_set_gpio(coredev, board->lna_ctrl, 0);
break;
}
return 0;
}
int sms_board_power(struct smscore_device_t *coredev, int onoff)
{
int board_id = smscore_get_board_id(coredev);
struct sms_board *board = sms_get_board(board_id);
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
/* power LED */
sms_set_gpio(coredev,
board->led_power, onoff ? 1 : 0);
break;
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
/* LNA */
sms_set_gpio(coredev,
board->lna_ctrl, onoff ? 1 : 0);
break;
}
return 0;
}
int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
{
int board_id = smscore_get_board_id(coredev);
struct sms_board *board = sms_get_board(board_id);
/* dont touch GPIO if LEDs are already set */
if (smscore_led_state(coredev, -1) == led)
return 0;
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
sms_set_gpio(coredev,
board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
sms_set_gpio(coredev,
board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
smscore_led_state(coredev, led);
break;
}
return 0;
}

View file

@ -32,14 +32,27 @@
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
struct sms_board {
enum sms_device_type_st type;
char *name, *fw[DEVICE_MODE_MAX];
/* gpios */
int led_power, led_hi, led_lo, lna_ctrl;
};
struct sms_board *sms_get_board(int id);
int sms_board_setup(struct smscore_device_t *coredev);
#define SMS_LED_OFF 0
#define SMS_LED_LO 1
#define SMS_LED_HI 2
int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
int sms_board_power(struct smscore_device_t *coredev, int onoff);
extern struct usb_device_id smsusb_id_table[];
#endif /* __SMS_CARDS_H__ */

View file

@ -91,6 +91,7 @@ struct smscore_device_t {
struct completion init_device_done, reload_start_done, resume_done;
int board_id;
int led_state;
};
void smscore_set_board_id(struct smscore_device_t *core, int id)
@ -98,6 +99,13 @@ void smscore_set_board_id(struct smscore_device_t *core, int id)
core->board_id = id;
}
int smscore_led_state(struct smscore_device_t *core, int led)
{
if (led >= 0)
core->led_state = led;
return core->led_state;
}
int smscore_get_board_id(struct smscore_device_t *core)
{
return core->board_id;
@ -1187,6 +1195,76 @@ int smsclient_sendrequest(struct smscore_client_t *client,
}
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_gpio_config *pinconfig)
{
struct {
struct SmsMsgHdr_ST hdr;
u32 data[6];
} msg;
if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
msg.hdr.msgDstId = HIF_TASK;
msg.hdr.msgFlags = 0;
msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
msg.hdr.msgLength = sizeof(msg);
msg.data[0] = pin;
msg.data[1] = pinconfig->pullupdown;
/* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
switch (pinconfig->outputdriving) {
case SMS_GPIO_OUTPUTDRIVING_16mA:
msg.data[3] = 7; /* Nova - 16mA */
break;
case SMS_GPIO_OUTPUTDRIVING_12mA:
msg.data[3] = 5; /* Nova - 11mA */
break;
case SMS_GPIO_OUTPUTDRIVING_8mA:
msg.data[3] = 3; /* Nova - 7mA */
break;
case SMS_GPIO_OUTPUTDRIVING_4mA:
default:
msg.data[3] = 2; /* Nova - 4mA */
break;
}
msg.data[4] = pinconfig->direction;
msg.data[5] = 0;
} else /* TODO: SMS_DEVICE_FAMILY1 */
return -EINVAL;
return coredev->sendrequest_handler(coredev->context,
&msg, sizeof(msg));
}
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
{
struct {
struct SmsMsgHdr_ST hdr;
u32 data[3];
} msg;
if (pin > MAX_GPIO_PIN_NUMBER)
return -EINVAL;
msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
msg.hdr.msgDstId = HIF_TASK;
msg.hdr.msgFlags = 0;
msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
msg.hdr.msgLength = sizeof(msg);
msg.data[0] = pin;
msg.data[1] = level ? 1 : 0;
msg.data[2] = 0;
return coredev->sendrequest_handler(coredev->context,
&msg, sizeof(msg));
}
static int __init smscore_module_init(void)
{
int rc = 0;

View file

@ -186,6 +186,8 @@ struct smsclient_params_t {
#define MSG_SW_RELOAD_EXEC_REQ 704
#define MSG_SW_RELOAD_EXEC_RES 705
#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
#define MSG_SMS_GPIO_CONFIG_EX_REQ 712
#define MSG_SMS_GPIO_CONFIG_EX_RES 713
#define MSG_SMS_ISDBT_TUNE_REQ 776
#define MSG_SMS_ISDBT_TUNE_RES 777
@ -341,6 +343,32 @@ struct SmsMsgStatisticsInfo_ST {
};
struct smscore_gpio_config {
#define SMS_GPIO_DIRECTION_INPUT 0
#define SMS_GPIO_DIRECTION_OUTPUT 1
u8 direction;
#define SMS_GPIO_PULLUPDOWN_NONE 0
#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
#define SMS_GPIO_PULLUPDOWN_PULLUP 2
#define SMS_GPIO_PULLUPDOWN_KEEPER 3
u8 pullupdown;
#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0
#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
u8 inputcharacteristics;
#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
u8 outputslewrate;
#define SMS_GPIO_OUTPUTDRIVING_4mA 0
#define SMS_GPIO_OUTPUTDRIVING_8mA 1
#define SMS_GPIO_OUTPUTDRIVING_12mA 2
#define SMS_GPIO_OUTPUTDRIVING_16mA 3
u8 outputdriving;
};
struct smsdvb_client_t {
struct list_head entry;
@ -353,7 +381,7 @@ struct smsdvb_client_t {
struct dvb_frontend frontend;
fe_status_t fe_status;
int fe_ber, fe_snr, fe_signal_strength;
int fe_ber, fe_snr, fe_unc, fe_signal_strength;
struct completion tune_done, stat_done;
@ -396,9 +424,15 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
extern void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb);
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_gpio_config *pinconfig);
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
void smscore_set_board_id(struct smscore_device_t *core, int id);
int smscore_get_board_id(struct smscore_device_t *core);
int smscore_led_state(struct smscore_device_t *core, int led);
/* smsdvb.c */
int smsdvb_register(void);
void smsdvb_unregister(void);

View file

@ -60,6 +60,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
client->fe_snr = p->Stat.SNR;
client->fe_ber = p->Stat.BER;
client->fe_unc = p->Stat.BERErrorCount;
if (p->Stat.InBandPwr < -95)
client->fe_signal_strength = 0;
@ -72,6 +73,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
client->fe_status = 0;
client->fe_snr =
client->fe_ber =
client->fe_unc =
client->fe_signal_strength = 0;
}
@ -165,8 +167,18 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
DVBT_BDA_CONTROL_MSG_ID,
HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
&client->stat_done);
int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
&client->stat_done);
if (ret < 0)
return ret;
if (client->fe_status & FE_HAS_LOCK)
sms_board_led_feedback(client->coredev,
(client->fe_unc == 0) ?
SMS_LED_HI : SMS_LED_LO);
else
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
return ret;
}
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@ -217,6 +229,18 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
return rc;
}
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
int rc = smsdvb_send_statistics_request(client);
if (!rc)
*ucblocks = client->fe_unc;
return rc;
}
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
@ -273,6 +297,28 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe,
/* todo: */
memcpy(fep, &client->fe_params,
sizeof(struct dvb_frontend_parameters));
return 0;
}
static int smsdvb_init(struct dvb_frontend *fe)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
sms_board_power(client->coredev, 1);
return 0;
}
static int smsdvb_sleep(struct dvb_frontend *fe)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
sms_board_power(client->coredev, 0);
return 0;
}
@ -308,6 +354,10 @@ static struct dvb_frontend_ops smsdvb_fe_ops = {
.read_ber = smsdvb_read_ber,
.read_signal_strength = smsdvb_read_signal_strength,
.read_snr = smsdvb_read_snr,
.read_ucblocks = smsdvb_read_ucblocks,
.init = smsdvb_init,
.sleep = smsdvb_sleep,
};
static int smsdvb_hotplug(struct smscore_device_t *coredev,
@ -402,6 +452,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
sms_info("success");
sms_board_setup(coredev);
return 0;
client_error:

View file

@ -432,11 +432,56 @@ static void smsusb_disconnect(struct usb_interface *intf)
smsusb_term_device(intf);
}
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
struct smsusb_device_t *dev =
(struct smsusb_device_t *)usb_get_intfdata(intf);
printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event);
smsusb_stop_streaming(dev);
return 0;
}
static int smsusb_resume(struct usb_interface *intf)
{
int rc, i;
struct smsusb_device_t *dev =
(struct smsusb_device_t *)usb_get_intfdata(intf);
struct usb_device *udev = interface_to_usbdev(intf);
printk(KERN_INFO "%s Entering.\n", __func__);
usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
if (intf->num_altsetting > 0) {
rc = usb_set_interface(udev,
intf->cur_altsetting->desc.
bInterfaceNumber, 0);
if (rc < 0) {
printk(KERN_INFO
"%s usb_set_interface failed, rc %d\n",
__func__, rc);
return rc;
}
}
smsusb_start_streaming(dev);
return 0;
}
static struct usb_driver smsusb_driver = {
.name = "sms1xxx",
.probe = smsusb_probe,
.disconnect = smsusb_disconnect,
.id_table = smsusb_id_table,
.suspend = smsusb_suspend,
.resume = smsusb_resume,
};
int smsusb_register(void)

View file

@ -104,6 +104,8 @@ config DVB_BUDGET_CI
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_STB0899 if !DVB_FE_CUSTOMISE
select DVB_STB6100 if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
@ -131,6 +133,8 @@ config DVB_BUDGET_AV
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_STB0899 if !DVB_FE_CUSTOMISE
select DVB_TDA8261 if !DVB_FE_CUSTOMISE
select DVB_TUA6100 if !DVB_FE_CUSTOMISE
help
Support for simple SAA7146 based DVB cards

View file

@ -35,6 +35,11 @@
#include "budget.h"
#include "stv0299.h"
#include "stb0899_drv.h"
#include "stb0899_reg.h"
#include "stb0899_cfg.h"
#include "tda8261.h"
#include "tda8261_cfg.h"
#include "tda1002x.h"
#include "tda1004x.h"
#include "tua6100.h"
@ -882,6 +887,281 @@ static struct stv0299_config philips_sd1878_config = {
.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
};
/* KNC1 DVB-S (STB0899) Inittab */
static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {
{ STB0899_DEV_ID , 0x81 },
{ STB0899_DISCNTRL1 , 0x32 },
{ STB0899_DISCNTRL2 , 0x80 },
{ STB0899_DISRX_ST0 , 0x04 },
{ STB0899_DISRX_ST1 , 0x00 },
{ STB0899_DISPARITY , 0x00 },
{ STB0899_DISFIFO , 0x00 },
{ STB0899_DISSTATUS , 0x20 },
{ STB0899_DISF22 , 0x8c },
{ STB0899_DISF22RX , 0x9a },
{ STB0899_SYSREG , 0x0b },
{ STB0899_ACRPRESC , 0x11 },
{ STB0899_ACRDIV1 , 0x0a },
{ STB0899_ACRDIV2 , 0x05 },
{ STB0899_DACR1 , 0x00 },
{ STB0899_DACR2 , 0x00 },
{ STB0899_OUTCFG , 0x00 },
{ STB0899_MODECFG , 0x00 },
{ STB0899_IRQSTATUS_3 , 0x30 },
{ STB0899_IRQSTATUS_2 , 0x00 },
{ STB0899_IRQSTATUS_1 , 0x00 },
{ STB0899_IRQSTATUS_0 , 0x00 },
{ STB0899_IRQMSK_3 , 0xf3 },
{ STB0899_IRQMSK_2 , 0xfc },
{ STB0899_IRQMSK_1 , 0xff },
{ STB0899_IRQMSK_0 , 0xff },
{ STB0899_IRQCFG , 0x00 },
{ STB0899_I2CCFG , 0x88 },
{ STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */
{ STB0899_IOPVALUE5 , 0x00 },
{ STB0899_IOPVALUE4 , 0x20 },
{ STB0899_IOPVALUE3 , 0xc9 },
{ STB0899_IOPVALUE2 , 0x90 },
{ STB0899_IOPVALUE1 , 0x40 },
{ STB0899_IOPVALUE0 , 0x00 },
{ STB0899_GPIO00CFG , 0x82 },
{ STB0899_GPIO01CFG , 0x82 },
{ STB0899_GPIO02CFG , 0x82 },
{ STB0899_GPIO03CFG , 0x82 },
{ STB0899_GPIO04CFG , 0x82 },
{ STB0899_GPIO05CFG , 0x82 },
{ STB0899_GPIO06CFG , 0x82 },
{ STB0899_GPIO07CFG , 0x82 },
{ STB0899_GPIO08CFG , 0x82 },
{ STB0899_GPIO09CFG , 0x82 },
{ STB0899_GPIO10CFG , 0x82 },
{ STB0899_GPIO11CFG , 0x82 },
{ STB0899_GPIO12CFG , 0x82 },
{ STB0899_GPIO13CFG , 0x82 },
{ STB0899_GPIO14CFG , 0x82 },
{ STB0899_GPIO15CFG , 0x82 },
{ STB0899_GPIO16CFG , 0x82 },
{ STB0899_GPIO17CFG , 0x82 },
{ STB0899_GPIO18CFG , 0x82 },
{ STB0899_GPIO19CFG , 0x82 },
{ STB0899_GPIO20CFG , 0x82 },
{ STB0899_SDATCFG , 0xb8 },
{ STB0899_SCLTCFG , 0xba },
{ STB0899_AGCRFCFG , 0x08 }, /* 0x1c */
{ STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
{ STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
{ STB0899_DIRCLKCFG , 0x82 },
{ STB0899_CLKOUT27CFG , 0x7e },
{ STB0899_STDBYCFG , 0x82 },
{ STB0899_CS0CFG , 0x82 },
{ STB0899_CS1CFG , 0x82 },
{ STB0899_DISEQCOCFG , 0x20 },
{ STB0899_GPIO32CFG , 0x82 },
{ STB0899_GPIO33CFG , 0x82 },
{ STB0899_GPIO34CFG , 0x82 },
{ STB0899_GPIO35CFG , 0x82 },
{ STB0899_GPIO36CFG , 0x82 },
{ STB0899_GPIO37CFG , 0x82 },
{ STB0899_GPIO38CFG , 0x82 },
{ STB0899_GPIO39CFG , 0x82 },
{ STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
{ STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
{ STB0899_FILTCTRL , 0x00 },
{ STB0899_SYSCTRL , 0x00 },
{ STB0899_STOPCLK1 , 0x20 },
{ STB0899_STOPCLK2 , 0x00 },
{ STB0899_INTBUFSTATUS , 0x00 },
{ STB0899_INTBUFCTRL , 0x0a },
{ 0xffff , 0xff },
};
static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
{ STB0899_DEMOD , 0x00 },
{ STB0899_RCOMPC , 0xc9 },
{ STB0899_AGC1CN , 0x41 },
{ STB0899_AGC1REF , 0x08 },
{ STB0899_RTC , 0x7a },
{ STB0899_TMGCFG , 0x4e },
{ STB0899_AGC2REF , 0x33 },
{ STB0899_TLSR , 0x84 },
{ STB0899_CFD , 0xee },
{ STB0899_ACLC , 0x87 },
{ STB0899_BCLC , 0x94 },
{ STB0899_EQON , 0x41 },
{ STB0899_LDT , 0xdd },
{ STB0899_LDT2 , 0xc9 },
{ STB0899_EQUALREF , 0xb4 },
{ STB0899_TMGRAMP , 0x10 },
{ STB0899_TMGTHD , 0x30 },
{ STB0899_IDCCOMP , 0xfb },
{ STB0899_QDCCOMP , 0x03 },
{ STB0899_POWERI , 0x3b },
{ STB0899_POWERQ , 0x3d },
{ STB0899_RCOMP , 0x81 },
{ STB0899_AGCIQIN , 0x80 },
{ STB0899_AGC2I1 , 0x04 },
{ STB0899_AGC2I2 , 0xf5 },
{ STB0899_TLIR , 0x25 },
{ STB0899_RTF , 0x80 },
{ STB0899_DSTATUS , 0x00 },
{ STB0899_LDI , 0xca },
{ STB0899_CFRM , 0xf1 },
{ STB0899_CFRL , 0xf3 },
{ STB0899_NIRM , 0x2a },
{ STB0899_NIRL , 0x05 },
{ STB0899_ISYMB , 0x17 },
{ STB0899_QSYMB , 0xfa },
{ STB0899_SFRH , 0x2f },
{ STB0899_SFRM , 0x68 },
{ STB0899_SFRL , 0x40 },
{ STB0899_SFRUPH , 0x2f },
{ STB0899_SFRUPM , 0x68 },
{ STB0899_SFRUPL , 0x40 },
{ STB0899_EQUAI1 , 0xfd },
{ STB0899_EQUAQ1 , 0x04 },
{ STB0899_EQUAI2 , 0x0f },
{ STB0899_EQUAQ2 , 0xff },
{ STB0899_EQUAI3 , 0xdf },
{ STB0899_EQUAQ3 , 0xfa },
{ STB0899_EQUAI4 , 0x37 },
{ STB0899_EQUAQ4 , 0x0d },
{ STB0899_EQUAI5 , 0xbd },
{ STB0899_EQUAQ5 , 0xf7 },
{ STB0899_DSTATUS2 , 0x00 },
{ STB0899_VSTATUS , 0x00 },
{ STB0899_VERROR , 0xff },
{ STB0899_IQSWAP , 0x2a },
{ STB0899_ECNT1M , 0x00 },
{ STB0899_ECNT1L , 0x00 },
{ STB0899_ECNT2M , 0x00 },
{ STB0899_ECNT2L , 0x00 },
{ STB0899_ECNT3M , 0x00 },
{ STB0899_ECNT3L , 0x00 },
{ STB0899_FECAUTO1 , 0x06 },
{ STB0899_FECM , 0x01 },
{ STB0899_VTH12 , 0xf0 },
{ STB0899_VTH23 , 0xa0 },
{ STB0899_VTH34 , 0x78 },
{ STB0899_VTH56 , 0x4e },
{ STB0899_VTH67 , 0x48 },
{ STB0899_VTH78 , 0x38 },
{ STB0899_PRVIT , 0xff },
{ STB0899_VITSYNC , 0x19 },
{ STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
{ STB0899_TSULC , 0x42 },
{ STB0899_RSLLC , 0x40 },
{ STB0899_TSLPL , 0x12 },
{ STB0899_TSCFGH , 0x0c },
{ STB0899_TSCFGM , 0x00 },
{ STB0899_TSCFGL , 0x0c },
{ STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
{ STB0899_RSSYNCDEL , 0x00 },
{ STB0899_TSINHDELH , 0x02 },
{ STB0899_TSINHDELM , 0x00 },
{ STB0899_TSINHDELL , 0x00 },
{ STB0899_TSLLSTKM , 0x00 },
{ STB0899_TSLLSTKL , 0x00 },
{ STB0899_TSULSTKM , 0x00 },
{ STB0899_TSULSTKL , 0xab },
{ STB0899_PCKLENUL , 0x00 },
{ STB0899_PCKLENLL , 0xcc },
{ STB0899_RSPCKLEN , 0xcc },
{ STB0899_TSSTATUS , 0x80 },
{ STB0899_ERRCTRL1 , 0xb6 },
{ STB0899_ERRCTRL2 , 0x96 },
{ STB0899_ERRCTRL3 , 0x89 },
{ STB0899_DMONMSK1 , 0x27 },
{ STB0899_DMONMSK0 , 0x03 },
{ STB0899_DEMAPVIT , 0x5c },
{ STB0899_PLPARM , 0x1f },
{ STB0899_PDELCTRL , 0x48 },
{ STB0899_PDELCTRL2 , 0x00 },
{ STB0899_BBHCTRL1 , 0x00 },
{ STB0899_BBHCTRL2 , 0x00 },
{ STB0899_HYSTTHRESH , 0x77 },
{ STB0899_MATCSTM , 0x00 },
{ STB0899_MATCSTL , 0x00 },
{ STB0899_UPLCSTM , 0x00 },
{ STB0899_UPLCSTL , 0x00 },
{ STB0899_DFLCSTM , 0x00 },
{ STB0899_DFLCSTL , 0x00 },
{ STB0899_SYNCCST , 0x00 },
{ STB0899_SYNCDCSTM , 0x00 },
{ STB0899_SYNCDCSTL , 0x00 },
{ STB0899_ISI_ENTRY , 0x00 },
{ STB0899_ISI_BIT_EN , 0x00 },
{ STB0899_MATSTRM , 0x00 },
{ STB0899_MATSTRL , 0x00 },
{ STB0899_UPLSTRM , 0x00 },
{ STB0899_UPLSTRL , 0x00 },
{ STB0899_DFLSTRM , 0x00 },
{ STB0899_DFLSTRL , 0x00 },
{ STB0899_SYNCSTR , 0x00 },
{ STB0899_SYNCDSTRM , 0x00 },
{ STB0899_SYNCDSTRL , 0x00 },
{ STB0899_CFGPDELSTATUS1 , 0x10 },
{ STB0899_CFGPDELSTATUS2 , 0x00 },
{ STB0899_BBFERRORM , 0x00 },
{ STB0899_BBFERRORL , 0x00 },
{ STB0899_UPKTERRORM , 0x00 },
{ STB0899_UPKTERRORL , 0x00 },
{ 0xffff , 0xff },
};
/* STB0899 demodulator config for the KNC1 and clones */
static struct stb0899_config knc1_dvbs2_config = {
.init_dev = knc1_stb0899_s1_init_1,
.init_s2_demod = stb0899_s2_init_2,
.init_s1_demod = knc1_stb0899_s1_init_3,
.init_s2_fec = stb0899_s2_init_4,
.init_tst = stb0899_s1_init_5,
.postproc = NULL,
.demod_address = 0x68,
// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */
.block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */
// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */
.xtal_freq = 27000000,
.inversion = IQ_SWAP_OFF, /* 1 */
.lo_clk = 76500000,
.hi_clk = 90000000,
.esno_ave = STB0899_DVBS2_ESNO_AVE,
.esno_quant = STB0899_DVBS2_ESNO_QUANT,
.avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
.avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
.miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
.uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
.uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
.sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
.btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
.crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
.ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
.tuner_get_frequency = tda8261_get_frequency,
.tuner_set_frequency = tda8261_set_frequency,
.tuner_set_bandwidth = NULL,
.tuner_get_bandwidth = tda8261_get_bandwidth,
.tuner_set_rfsiggain = NULL
};
/*
* SD1878/SHA tuner config
* 1F, Single I/P, Horizontal mount, High Sensitivity
*/
static const struct tda8261_config sd1878c_config = {
// .name = "SD1878/SHA",
.addr = 0x60,
.step_size = TDA8261_STEP_1000 /* kHz */
};
static u8 read_pwm(struct budget_av *budget_av)
{
u8 b = 0xff;
@ -905,8 +1185,11 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015
#define SUBID_DVBS_TV_STAR_CI 0x0016
#define SUBID_DVBS2_KNC1 0x0018
#define SUBID_DVBS2_KNC1_OEM 0x0019
#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH_2 0x001b
#define SUBID_DVBS2_EASYWATCH 0x001d
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_EASYWATCH 0x002a
@ -941,6 +1224,9 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBT_KNC1_PLUS:
case SUBID_DVBC_EASYWATCH:
case SUBID_DVBC_KNC1_PLUS_MK3:
case SUBID_DVBS2_KNC1:
case SUBID_DVBS2_KNC1_OEM:
case SUBID_DVBS2_EASYWATCH:
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
break;
}
@ -993,7 +1279,14 @@ static void frontend_init(struct budget_av *budget_av)
fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
}
break;
case SUBID_DVBS2_KNC1:
case SUBID_DVBS2_KNC1_OEM:
case SUBID_DVBS2_EASYWATCH:
budget_av->reinitialise_demod = 1;
if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap)))
dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap);
break;
case SUBID_DVBS_CINERGY1200:
fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
&budget_av->budget.i2c_adap);
@ -1260,6 +1553,8 @@ static struct saa7146_ext_vv vv_data = {
static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2);
MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2);
MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
@ -1290,6 +1585,9 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018),
MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019),
MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),

View file

@ -43,6 +43,11 @@
#include "stv0299.h"
#include "stv0297.h"
#include "tda1004x.h"
#include "stb0899_drv.h"
#include "stb0899_reg.h"
#include "stb0899_cfg.h"
#include "stb6100.h"
#include "stb6100_cfg.h"
#include "lnbp21.h"
#include "bsbe1.h"
#include "bsru6.h"
@ -1071,7 +1076,271 @@ static struct tda10023_config tda10023_config = {
.deltaf = 0xa511,
};
/* TT S2-3200 DVB-S (STB0899) Inittab */
static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
{ STB0899_DEV_ID , 0x81 },
{ STB0899_DISCNTRL1 , 0x32 },
{ STB0899_DISCNTRL2 , 0x80 },
{ STB0899_DISRX_ST0 , 0x04 },
{ STB0899_DISRX_ST1 , 0x00 },
{ STB0899_DISPARITY , 0x00 },
{ STB0899_DISFIFO , 0x00 },
{ STB0899_DISSTATUS , 0x20 },
{ STB0899_DISF22 , 0x8c },
{ STB0899_DISF22RX , 0x9a },
{ STB0899_SYSREG , 0x0b },
{ STB0899_ACRPRESC , 0x11 },
{ STB0899_ACRDIV1 , 0x0a },
{ STB0899_ACRDIV2 , 0x05 },
{ STB0899_DACR1 , 0x00 },
{ STB0899_DACR2 , 0x00 },
{ STB0899_OUTCFG , 0x00 },
{ STB0899_MODECFG , 0x00 },
{ STB0899_IRQSTATUS_3 , 0x30 },
{ STB0899_IRQSTATUS_2 , 0x00 },
{ STB0899_IRQSTATUS_1 , 0x00 },
{ STB0899_IRQSTATUS_0 , 0x00 },
{ STB0899_IRQMSK_3 , 0xf3 },
{ STB0899_IRQMSK_2 , 0xfc },
{ STB0899_IRQMSK_1 , 0xff },
{ STB0899_IRQMSK_0 , 0xff },
{ STB0899_IRQCFG , 0x00 },
{ STB0899_I2CCFG , 0x88 },
{ STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
{ STB0899_IOPVALUE5 , 0x00 },
{ STB0899_IOPVALUE4 , 0x20 },
{ STB0899_IOPVALUE3 , 0xc9 },
{ STB0899_IOPVALUE2 , 0x90 },
{ STB0899_IOPVALUE1 , 0x40 },
{ STB0899_IOPVALUE0 , 0x00 },
{ STB0899_GPIO00CFG , 0x82 },
{ STB0899_GPIO01CFG , 0x82 },
{ STB0899_GPIO02CFG , 0x82 },
{ STB0899_GPIO03CFG , 0x82 },
{ STB0899_GPIO04CFG , 0x82 },
{ STB0899_GPIO05CFG , 0x82 },
{ STB0899_GPIO06CFG , 0x82 },
{ STB0899_GPIO07CFG , 0x82 },
{ STB0899_GPIO08CFG , 0x82 },
{ STB0899_GPIO09CFG , 0x82 },
{ STB0899_GPIO10CFG , 0x82 },
{ STB0899_GPIO11CFG , 0x82 },
{ STB0899_GPIO12CFG , 0x82 },
{ STB0899_GPIO13CFG , 0x82 },
{ STB0899_GPIO14CFG , 0x82 },
{ STB0899_GPIO15CFG , 0x82 },
{ STB0899_GPIO16CFG , 0x82 },
{ STB0899_GPIO17CFG , 0x82 },
{ STB0899_GPIO18CFG , 0x82 },
{ STB0899_GPIO19CFG , 0x82 },
{ STB0899_GPIO20CFG , 0x82 },
{ STB0899_SDATCFG , 0xb8 },
{ STB0899_SCLTCFG , 0xba },
{ STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
{ STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
{ STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
{ STB0899_DIRCLKCFG , 0x82 },
{ STB0899_CLKOUT27CFG , 0x7e },
{ STB0899_STDBYCFG , 0x82 },
{ STB0899_CS0CFG , 0x82 },
{ STB0899_CS1CFG , 0x82 },
{ STB0899_DISEQCOCFG , 0x20 },
{ STB0899_GPIO32CFG , 0x82 },
{ STB0899_GPIO33CFG , 0x82 },
{ STB0899_GPIO34CFG , 0x82 },
{ STB0899_GPIO35CFG , 0x82 },
{ STB0899_GPIO36CFG , 0x82 },
{ STB0899_GPIO37CFG , 0x82 },
{ STB0899_GPIO38CFG , 0x82 },
{ STB0899_GPIO39CFG , 0x82 },
{ STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
{ STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
{ STB0899_FILTCTRL , 0x00 },
{ STB0899_SYSCTRL , 0x00 },
{ STB0899_STOPCLK1 , 0x20 },
{ STB0899_STOPCLK2 , 0x00 },
{ STB0899_INTBUFSTATUS , 0x00 },
{ STB0899_INTBUFCTRL , 0x0a },
{ 0xffff , 0xff },
};
static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
{ STB0899_DEMOD , 0x00 },
{ STB0899_RCOMPC , 0xc9 },
{ STB0899_AGC1CN , 0x41 },
{ STB0899_AGC1REF , 0x10 },
{ STB0899_RTC , 0x7a },
{ STB0899_TMGCFG , 0x4e },
{ STB0899_AGC2REF , 0x34 },
{ STB0899_TLSR , 0x84 },
{ STB0899_CFD , 0xc7 },
{ STB0899_ACLC , 0x87 },
{ STB0899_BCLC , 0x94 },
{ STB0899_EQON , 0x41 },
{ STB0899_LDT , 0xdd },
{ STB0899_LDT2 , 0xc9 },
{ STB0899_EQUALREF , 0xb4 },
{ STB0899_TMGRAMP , 0x10 },
{ STB0899_TMGTHD , 0x30 },
{ STB0899_IDCCOMP , 0xfb },
{ STB0899_QDCCOMP , 0x03 },
{ STB0899_POWERI , 0x3b },
{ STB0899_POWERQ , 0x3d },
{ STB0899_RCOMP , 0x81 },
{ STB0899_AGCIQIN , 0x80 },
{ STB0899_AGC2I1 , 0x04 },
{ STB0899_AGC2I2 , 0xf5 },
{ STB0899_TLIR , 0x25 },
{ STB0899_RTF , 0x80 },
{ STB0899_DSTATUS , 0x00 },
{ STB0899_LDI , 0xca },
{ STB0899_CFRM , 0xf1 },
{ STB0899_CFRL , 0xf3 },
{ STB0899_NIRM , 0x2a },
{ STB0899_NIRL , 0x05 },
{ STB0899_ISYMB , 0x17 },
{ STB0899_QSYMB , 0xfa },
{ STB0899_SFRH , 0x2f },
{ STB0899_SFRM , 0x68 },
{ STB0899_SFRL , 0x40 },
{ STB0899_SFRUPH , 0x2f },
{ STB0899_SFRUPM , 0x68 },
{ STB0899_SFRUPL , 0x40 },
{ STB0899_EQUAI1 , 0xfd },
{ STB0899_EQUAQ1 , 0x04 },
{ STB0899_EQUAI2 , 0x0f },
{ STB0899_EQUAQ2 , 0xff },
{ STB0899_EQUAI3 , 0xdf },
{ STB0899_EQUAQ3 , 0xfa },
{ STB0899_EQUAI4 , 0x37 },
{ STB0899_EQUAQ4 , 0x0d },
{ STB0899_EQUAI5 , 0xbd },
{ STB0899_EQUAQ5 , 0xf7 },
{ STB0899_DSTATUS2 , 0x00 },
{ STB0899_VSTATUS , 0x00 },
{ STB0899_VERROR , 0xff },
{ STB0899_IQSWAP , 0x2a },
{ STB0899_ECNT1M , 0x00 },
{ STB0899_ECNT1L , 0x00 },
{ STB0899_ECNT2M , 0x00 },
{ STB0899_ECNT2L , 0x00 },
{ STB0899_ECNT3M , 0x00 },
{ STB0899_ECNT3L , 0x00 },
{ STB0899_FECAUTO1 , 0x06 },
{ STB0899_FECM , 0x01 },
{ STB0899_VTH12 , 0xf0 },
{ STB0899_VTH23 , 0xa0 },
{ STB0899_VTH34 , 0x78 },
{ STB0899_VTH56 , 0x4e },
{ STB0899_VTH67 , 0x48 },
{ STB0899_VTH78 , 0x38 },
{ STB0899_PRVIT , 0xff },
{ STB0899_VITSYNC , 0x19 },
{ STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
{ STB0899_TSULC , 0x42 },
{ STB0899_RSLLC , 0x40 },
{ STB0899_TSLPL , 0x12 },
{ STB0899_TSCFGH , 0x0c },
{ STB0899_TSCFGM , 0x00 },
{ STB0899_TSCFGL , 0x0c },
{ STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
{ STB0899_RSSYNCDEL , 0x00 },
{ STB0899_TSINHDELH , 0x02 },
{ STB0899_TSINHDELM , 0x00 },
{ STB0899_TSINHDELL , 0x00 },
{ STB0899_TSLLSTKM , 0x00 },
{ STB0899_TSLLSTKL , 0x00 },
{ STB0899_TSULSTKM , 0x00 },
{ STB0899_TSULSTKL , 0xab },
{ STB0899_PCKLENUL , 0x00 },
{ STB0899_PCKLENLL , 0xcc },
{ STB0899_RSPCKLEN , 0xcc },
{ STB0899_TSSTATUS , 0x80 },
{ STB0899_ERRCTRL1 , 0xb6 },
{ STB0899_ERRCTRL2 , 0x96 },
{ STB0899_ERRCTRL3 , 0x89 },
{ STB0899_DMONMSK1 , 0x27 },
{ STB0899_DMONMSK0 , 0x03 },
{ STB0899_DEMAPVIT , 0x5c },
{ STB0899_PLPARM , 0x1f },
{ STB0899_PDELCTRL , 0x48 },
{ STB0899_PDELCTRL2 , 0x00 },
{ STB0899_BBHCTRL1 , 0x00 },
{ STB0899_BBHCTRL2 , 0x00 },
{ STB0899_HYSTTHRESH , 0x77 },
{ STB0899_MATCSTM , 0x00 },
{ STB0899_MATCSTL , 0x00 },
{ STB0899_UPLCSTM , 0x00 },
{ STB0899_UPLCSTL , 0x00 },
{ STB0899_DFLCSTM , 0x00 },
{ STB0899_DFLCSTL , 0x00 },
{ STB0899_SYNCCST , 0x00 },
{ STB0899_SYNCDCSTM , 0x00 },
{ STB0899_SYNCDCSTL , 0x00 },
{ STB0899_ISI_ENTRY , 0x00 },
{ STB0899_ISI_BIT_EN , 0x00 },
{ STB0899_MATSTRM , 0x00 },
{ STB0899_MATSTRL , 0x00 },
{ STB0899_UPLSTRM , 0x00 },
{ STB0899_UPLSTRL , 0x00 },
{ STB0899_DFLSTRM , 0x00 },
{ STB0899_DFLSTRL , 0x00 },
{ STB0899_SYNCSTR , 0x00 },
{ STB0899_SYNCDSTRM , 0x00 },
{ STB0899_SYNCDSTRL , 0x00 },
{ STB0899_CFGPDELSTATUS1 , 0x10 },
{ STB0899_CFGPDELSTATUS2 , 0x00 },
{ STB0899_BBFERRORM , 0x00 },
{ STB0899_BBFERRORL , 0x00 },
{ STB0899_UPKTERRORM , 0x00 },
{ STB0899_UPKTERRORL , 0x00 },
{ 0xffff , 0xff },
};
static struct stb0899_config tt3200_config = {
.init_dev = tt3200_stb0899_s1_init_1,
.init_s2_demod = stb0899_s2_init_2,
.init_s1_demod = tt3200_stb0899_s1_init_3,
.init_s2_fec = stb0899_s2_init_4,
.init_tst = stb0899_s1_init_5,
.postproc = NULL,
.demod_address = 0x68,
.xtal_freq = 27000000,
.inversion = IQ_SWAP_ON, /* 1 */
.lo_clk = 76500000,
.hi_clk = 99000000,
.esno_ave = STB0899_DVBS2_ESNO_AVE,
.esno_quant = STB0899_DVBS2_ESNO_QUANT,
.avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
.avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
.miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
.uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
.uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
.sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
.btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
.crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
.ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
.tuner_get_frequency = stb6100_get_frequency,
.tuner_set_frequency = stb6100_set_frequency,
.tuner_set_bandwidth = stb6100_set_bandwidth,
.tuner_get_bandwidth = stb6100_get_bandwidth,
.tuner_set_rfsiggain = NULL
};
struct stb6100_config tt3200_stb6100_config = {
.tuner_address = 0x60,
.refclock = 27000000,
};
static void frontend_init(struct budget_ci *budget_ci)
{
@ -1152,6 +1421,46 @@ static void frontend_init(struct budget_ci *budget_ci)
}
}
break;
case 0x1019: // TT S2-3200 PCI
/*
* NOTE! on some STB0899 versions, the internal PLL takes a longer time
* to settle, aka LOCK. On the older revisions of the chip, we don't see
* this, as a result on the newer chips the entire clock tree, will not
* be stable after a freshly POWER 'ed up situation.
* In this case, we should RESET the STB0899 (Active LOW) and wait for
* PLL stabilization.
*
* On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
* connected to the SAA7146 GPIO, GPIO2, Pin 142
*/
/* Reset Demodulator */
saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
/* Wait for everything to die */
msleep(50);
/* Pull it up out of Reset state */
saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
/* Wait for PLL to stabilize */
msleep(250);
/*
* PLL state should be stable now. Ideally, we should check
* for PLL LOCK status. But well, never mind!
*/
budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
dvb_frontend_detach(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
} else {
dvb_frontend_detach(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
break;
}
if (budget_ci->budget.dvb_frontend == NULL) {
@ -1242,6 +1551,7 @@ MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@ -1251,6 +1561,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
{
.vendor = 0,
}

View file

@ -103,6 +103,7 @@ static struct saa7146_pci_extension_data x_var = { \
#define BUDGET_CIN1200C_MK3 15
#define BUDGET_KNC1C_MK3 16
#define BUDGET_KNC1CP_MK3 17
#define BUDGET_KNC1S2 18
#define BUDGET_VIDEO_PORTA 0
#define BUDGET_VIDEO_PORTB 1

View file

@ -1,5 +1,5 @@
/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs
into both the USB and an analog audio input, so this thing
/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
The device plugs into both the USB and an analog audio input, so this thing
only deals with initialisation and frequency setting, the
audio data has to be handled by a sound driver.
@ -33,6 +33,10 @@
History:
Version 0.44:
Add suspend/resume functions, fix unplug of device,
a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
Version 0.43:
Oliver Neukum: avoided DMA coherency issue
@ -93,8 +97,8 @@
*/
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#define DRIVER_VERSION "v0.41"
#define RADIO_VERSION KERNEL_VERSION(0,4,1)
#define DRIVER_VERSION "v0.44"
#define RADIO_VERSION KERNEL_VERSION(0, 4, 4)
static struct v4l2_queryctrl radio_qctrl[] = {
{
@ -104,7 +108,27 @@ static struct v4l2_queryctrl radio_qctrl[] = {
.maximum = 1,
.default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
}
},
/* HINT: the disabled controls are only here to satify kradio and such apps */
{ .id = V4L2_CID_AUDIO_VOLUME,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_BALANCE,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_BASS,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_TREBLE,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
{
.id = V4L2_CID_AUDIO_LOUDNESS,
.flags = V4L2_CTRL_FLAG_DISABLED,
},
};
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
@ -125,12 +149,16 @@ devices, that would be 76 and 91. */
#define FREQ_MAX 108.0
#define FREQ_MUL 16000
#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_dsbr100_disconnect(struct usb_interface *intf);
static int usb_dsbr100_open(struct inode *inode, struct file *file);
static int usb_dsbr100_close(struct inode *inode, struct file *file);
static int usb_dsbr100_suspend(struct usb_interface *intf,
pm_message_t message);
static int usb_dsbr100_resume(struct usb_interface *intf);
static int radio_nr = -1;
module_param(radio_nr, int, 0);
@ -138,8 +166,9 @@ module_param(radio_nr, int, 0);
/* Data for one (physical) device */
struct dsbr100_device {
struct usb_device *usbdev;
struct video_device *videodev;
struct video_device videodev;
u8 *transfer_buffer;
struct mutex lock; /* buffer locking */
int curfreq;
int stereo;
int users;
@ -147,7 +176,6 @@ struct dsbr100_device {
int muted;
};
static struct usb_device_id usb_dsbr100_device_table [] = {
{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
{ } /* Terminating entry */
@ -157,10 +185,14 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
/* USB subsystem interface */
static struct usb_driver usb_dsbr100_driver = {
.name = "dsbr100",
.probe = usb_dsbr100_probe,
.disconnect = usb_dsbr100_disconnect,
.id_table = usb_dsbr100_device_table,
.name = "dsbr100",
.probe = usb_dsbr100_probe,
.disconnect = usb_dsbr100_disconnect,
.id_table = usb_dsbr100_device_table,
.suspend = usb_dsbr100_suspend,
.resume = usb_dsbr100_resume,
.reset_resume = usb_dsbr100_resume,
.supports_autosuspend = 0,
};
/* Low-level device interface begins here */
@ -168,95 +200,190 @@ static struct usb_driver usb_dsbr100_driver = {
/* switch on radio */
static int dsbr100_start(struct dsbr100_device *radio)
{
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x01, 0x00, radio->transfer_buffer, 8, 300) < 0)
return -1;
radio->muted=0;
return (radio->transfer_buffer)[0];
}
int retval;
int request;
mutex_lock(&radio->lock);
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0xC7, radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = USB_REQ_GET_STATUS;
goto usb_control_msg_failed;
}
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x01, 0x00, radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = DSB100_ONOFF;
goto usb_control_msg_failed;
}
radio->muted = 0;
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
usb_control_msg_failed:
mutex_unlock(&radio->lock);
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
__func__, retval, request);
return retval;
}
/* switch off radio */
static int dsbr100_stop(struct dsbr100_device *radio)
{
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0x00, radio->transfer_buffer, 8, 300) < 0)
return -1;
radio->muted=1;
int retval;
int request;
mutex_lock(&radio->lock);
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x16, 0x1C, radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = USB_REQ_GET_STATUS;
goto usb_control_msg_failed;
}
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0x00, radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = DSB100_ONOFF;
goto usb_control_msg_failed;
}
radio->muted = 1;
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
usb_control_msg_failed:
mutex_unlock(&radio->lock);
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
__func__, retval, request);
return retval;
}
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
{
int retval;
int request;
freq = (freq / 16 * 80) / 1000 + 856;
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_TUNE,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
(freq >> 8) & 0x00ff, freq & 0xff,
radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 ||
usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
radio->stereo = -1;
return -1;
mutex_lock(&radio->lock);
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_TUNE,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
(freq >> 8) & 0x00ff, freq & 0xff,
radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = DSB100_TUNE;
goto usb_control_msg_failed;
}
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x96, 0xB7, radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = USB_REQ_GET_STATUS;
goto usb_control_msg_failed;
}
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0x24, radio->transfer_buffer, 8, 300);
if (retval < 0) {
request = USB_REQ_GET_STATUS;
goto usb_control_msg_failed;
}
radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
usb_control_msg_failed:
radio->stereo = -1;
mutex_unlock(&radio->lock);
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
__func__, retval, request);
return retval;
}
/* return the device status. This is, in effect, just whether it
sees a stereo signal or not. Pity. */
static void dsbr100_getstat(struct dsbr100_device *radio)
{
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
int retval;
mutex_lock(&radio->lock);
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0)
radio->stereo = -1;
else
radio->stereo = !(radio->transfer_buffer[0] & 0x01);
}
0x00 , 0x24, radio->transfer_buffer, 8, 300);
if (retval < 0) {
radio->stereo = -1;
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
__func__, retval, USB_REQ_GET_STATUS);
} else {
radio->stereo = !(radio->transfer_buffer[0] & 0x01);
}
mutex_unlock(&radio->lock);
}
/* USB subsystem interface begins here */
/* handle unplugging of the device, release data structures
if nothing keeps us from doing it. If something is still
keeping us busy, the release callback of v4l will take care
of releasing it. */
/*
* Handle unplugging of the device.
* We call video_unregister_device in any case.
* The last function called in this procedure is
* usb_dsbr100_video_device_release
*/
static void usb_dsbr100_disconnect(struct usb_interface *intf)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
usb_set_intfdata (intf, NULL);
if (radio) {
video_unregister_device(radio->videodev);
radio->videodev = NULL;
if (radio->users) {
kfree(radio->transfer_buffer);
kfree(radio);
} else {
radio->removed = 1;
}
}
mutex_lock(&radio->lock);
radio->removed = 1;
mutex_unlock(&radio->lock);
video_unregister_device(&radio->videodev);
}
@ -276,6 +403,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
/* safety check */
if (radio->removed)
return -EIO;
if (v->index > 0)
return -EINVAL;
@ -297,6 +428,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct dsbr100_device *radio = video_drvdata(file);
/* safety check */
if (radio->removed)
return -EIO;
if (v->index > 0)
return -EINVAL;
@ -307,9 +444,15 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct dsbr100_device *radio = video_drvdata(file);
int retval;
/* safety check */
if (radio->removed)
return -EIO;
radio->curfreq = f->frequency;
if (dsbr100_setfreq(radio, radio->curfreq) == -1)
retval = dsbr100_setfreq(radio, radio->curfreq);
if (retval < 0)
dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
return 0;
}
@ -319,6 +462,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
/* safety check */
if (radio->removed)
return -EIO;
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
return 0;
@ -343,6 +490,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
/* safety check */
if (radio->removed)
return -EIO;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = radio->muted;
@ -355,17 +506,24 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct dsbr100_device *radio = video_drvdata(file);
int retval;
/* safety check */
if (radio->removed)
return -EIO;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
if (dsbr100_stop(radio) == -1) {
retval = dsbr100_stop(radio);
if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not respond properly\n");
return -EBUSY;
}
} else {
if (dsbr100_start(radio) == -1) {
retval = dsbr100_start(radio);
if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not respond properly\n");
return -EBUSY;
@ -417,7 +575,8 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
radio->users = 1;
radio->muted = 1;
if (dsbr100_start(radio) < 0) {
retval = dsbr100_start(radio);
if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not start up properly\n");
radio->users = 0;
@ -426,9 +585,9 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
}
retval = dsbr100_setfreq(radio, radio->curfreq);
if (retval == -1)
printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n");
if (retval < 0)
dev_warn(&radio->usbdev->dev,
"set frequency failed\n");
unlock_kernel();
return 0;
@ -437,17 +596,62 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
static int usb_dsbr100_close(struct inode *inode, struct file *file)
{
struct dsbr100_device *radio = video_drvdata(file);
int retval;
if (!radio)
return -ENODEV;
radio->users = 0;
if (radio->removed) {
kfree(radio->transfer_buffer);
kfree(radio);
if (!radio->removed) {
retval = dsbr100_stop(radio);
if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"dsbr100_stop failed\n");
}
}
return 0;
}
/* Suspend device - stop device. */
static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
int retval;
retval = dsbr100_stop(radio);
if (retval < 0)
dev_warn(&intf->dev, "dsbr100_stop failed\n");
dev_info(&intf->dev, "going into suspend..\n");
return 0;
}
/* Resume device - start device. */
static int usb_dsbr100_resume(struct usb_interface *intf)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
int retval;
retval = dsbr100_start(radio);
if (retval < 0)
dev_warn(&intf->dev, "dsbr100_start failed\n");
dev_info(&intf->dev, "coming out of suspend..\n");
return 0;
}
/* free data structures */
static void usb_dsbr100_video_device_release(struct video_device *videodev)
{
struct dsbr100_device *radio = videodev_to_radio(videodev);
kfree(radio->transfer_buffer);
kfree(radio);
}
/* File system interface */
static const struct file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
@ -476,19 +680,19 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
};
/* V4L2 interface */
static struct video_device dsbr100_videodev_template = {
static struct video_device dsbr100_videodev_data = {
.name = "D-Link DSB-R 100",
.fops = &usb_dsbr100_fops,
.ioctl_ops = &usb_dsbr100_ioctl_ops,
.release = video_device_release,
.release = usb_dsbr100_video_device_release,
};
/* check if the device is present and register with v4l and
usb if it is */
/* check if the device is present and register with v4l and usb if it is */
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct dsbr100_device *radio;
int retval;
radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
@ -501,23 +705,18 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
kfree(radio);
return -ENOMEM;
}
radio->videodev = video_device_alloc();
if (!(radio->videodev)) {
kfree(radio->transfer_buffer);
kfree(radio);
return -ENOMEM;
}
memcpy(radio->videodev, &dsbr100_videodev_template,
sizeof(dsbr100_videodev_template));
mutex_init(&radio->lock);
radio->videodev = dsbr100_videodev_data;
radio->removed = 0;
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
video_set_drvdata(radio->videodev, radio);
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
dev_warn(&intf->dev, "Could not register video device\n");
video_device_release(radio->videodev);
video_set_drvdata(&radio->videodev, radio);
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
if (retval < 0) {
dev_err(&intf->dev, "couldn't register video device\n");
kfree(radio->transfer_buffer);
kfree(radio);
return -EIO;

View file

@ -1,7 +1,7 @@
/* radiotrack (radioreveal) driver for Linux radio support
* (c) 1997 M. Kirkwood
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
* History:

View file

@ -23,7 +23,7 @@
* 2002-01-17 Adam Belay <ambx1@neo.rr.com>
* Updated to latest pnp code
*
* 2003-01-31 Alan Cox <alan@redhat.com>
* 2003-01-31 Alan Cox <alan@lxorguk.ukuu.org.uk>
* Cleaned up locking, delay code, general odds and ends
*
* 2006-07-30 Hans J. Koch <koch@hjk-az.de>

View file

@ -8,7 +8,7 @@
* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
*
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
* TODO: Allow for more than one of these foolish entities :-)

View file

@ -72,6 +72,11 @@ MODULE_LICENSE("GPL");
#define USB_AMRADIO_VENDOR 0x07ca
#define USB_AMRADIO_PRODUCT 0xb800
/* dev_warn macro with driver name */
#define MR800_DRIVER_NAME "radio-mr800"
#define amradio_dev_warn(dev, fmt, arg...) \
dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
/* Probably USB_TIMEOUT should be modified in module parameter */
#define BUFFER_LENGTH 8
#define USB_TIMEOUT 500
@ -154,14 +159,14 @@ MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
/* USB subsystem interface */
static struct usb_driver usb_amradio_driver = {
.name = "radio-mr800",
.name = MR800_DRIVER_NAME,
.probe = usb_amradio_probe,
.disconnect = usb_amradio_disconnect,
.suspend = usb_amradio_suspend,
.resume = usb_amradio_resume,
.reset_resume = usb_amradio_resume,
.id_table = usb_amradio_device_table,
.supports_autosuspend = 1,
.supports_autosuspend = 0,
};
/* switch on radio. Send 8 bytes to device. */
@ -202,6 +207,10 @@ static int amradio_stop(struct amradio_device *radio)
int retval;
int size;
/* safety check */
if (radio->removed)
return -EIO;
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00;
@ -235,6 +244,10 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
int size;
unsigned short freq_send = 0x13 + (freq >> 3) / 25;
/* safety check */
if (radio->removed)
return -EIO;
mutex_lock(&radio->lock);
radio->buffer[0] = 0x00;
@ -288,18 +301,12 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
{
struct amradio_device *radio = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
mutex_lock(&radio->lock);
radio->removed = 1;
mutex_unlock(&radio->lock);
if (radio) {
video_unregister_device(radio->videodev);
radio->videodev = NULL;
if (radio->users) {
kfree(radio->buffer);
kfree(radio);
} else {
radio->removed = 1;
}
}
usb_set_intfdata(intf, NULL);
video_unregister_device(radio->videodev);
}
/* vidioc_querycap - query device capabilities */
@ -320,6 +327,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
/* safety check */
if (radio->removed)
return -EIO;
if (v->index > 0)
return -EINVAL;
@ -346,6 +357,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
/* safety check */
if (radio->removed)
return -EIO;
if (v->index > 0)
return -EINVAL;
return 0;
@ -357,9 +374,14 @@ static int vidioc_s_frequency(struct file *file, void *priv,
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
/* safety check */
if (radio->removed)
return -EIO;
radio->curfreq = f->frequency;
if (amradio_setfreq(radio, radio->curfreq) < 0)
warn("Set frequency failed");
amradio_dev_warn(&radio->videodev->dev,
"set frequency failed\n");
return 0;
}
@ -369,6 +391,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
/* safety check */
if (radio->removed)
return -EIO;
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
return 0;
@ -382,8 +408,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
if (qc->id && qc->id == radio_qctrl[i].id) {
memcpy(qc, &(radio_qctrl[i]),
sizeof(*qc));
memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
return 0;
}
}
@ -396,6 +421,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
/* safety check */
if (radio->removed)
return -EIO;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = radio->muted;
@ -410,16 +439,22 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
/* safety check */
if (radio->removed)
return -EIO;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
if (amradio_stop(radio) < 0) {
warn("amradio_stop() failed");
amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n");
return -1;
}
} else {
if (amradio_start(radio) < 0) {
warn("amradio_start() failed");
amradio_dev_warn(&radio->videodev->dev,
"amradio_start failed\n");
return -1;
}
}
@ -475,30 +510,38 @@ static int usb_amradio_open(struct inode *inode, struct file *file)
radio->muted = 1;
if (amradio_start(radio) < 0) {
warn("Radio did not start up properly");
amradio_dev_warn(&radio->videodev->dev,
"radio did not start up properly\n");
radio->users = 0;
unlock_kernel();
return -EIO;
}
if (amradio_setfreq(radio, radio->curfreq) < 0)
warn("Set frequency failed");
amradio_dev_warn(&radio->videodev->dev,
"set frequency failed\n");
unlock_kernel();
return 0;
}
/*close device - free driver structures */
/*close device */
static int usb_amradio_close(struct inode *inode, struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
int retval;
if (!radio)
return -ENODEV;
radio->users = 0;
if (radio->removed) {
kfree(radio->buffer);
kfree(radio);
if (!radio->removed) {
retval = amradio_stop(radio);
if (retval < 0)
amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n");
}
return 0;
}
@ -508,9 +551,9 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
struct amradio_device *radio = usb_get_intfdata(intf);
if (amradio_stop(radio) < 0)
warn("amradio_stop() failed");
dev_warn(&intf->dev, "amradio_stop failed\n");
info("radio-mr800: Going into suspend..");
dev_info(&intf->dev, "going into suspend..\n");
return 0;
}
@ -521,9 +564,9 @@ static int usb_amradio_resume(struct usb_interface *intf)
struct amradio_device *radio = usb_get_intfdata(intf);
if (amradio_start(radio) < 0)
warn("amradio_start() failed");
dev_warn(&intf->dev, "amradio_start failed\n");
info("radio-mr800: Coming out of suspend..");
dev_info(&intf->dev, "coming out of suspend..\n");
return 0;
}
@ -555,12 +598,24 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
.vidioc_s_input = vidioc_s_input,
};
static void usb_amradio_device_release(struct video_device *videodev)
{
struct amradio_device *radio = video_get_drvdata(videodev);
/* we call v4l to free radio->videodev */
video_device_release(videodev);
/* free rest memory */
kfree(radio->buffer);
kfree(radio);
}
/* V4L2 interface */
static struct video_device amradio_videodev_template = {
.name = "AverMedia MR 800 USB FM Radio",
.fops = &usb_amradio_fops,
.ioctl_ops = &usb_amradio_ioctl_ops,
.release = video_device_release,
.release = usb_amradio_device_release,
};
/* check if the device is present and register with v4l and
@ -602,7 +657,7 @@ static int usb_amradio_probe(struct usb_interface *intf,
video_set_drvdata(radio->videodev, radio);
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
warn("Could not register video device");
dev_warn(&intf->dev, "could not register video device\n");
video_device_release(radio->videodev);
kfree(radio->buffer);
kfree(radio);
@ -617,9 +672,13 @@ static int __init amradio_init(void)
{
int retval = usb_register(&usb_amradio_driver);
info(DRIVER_VERSION " " DRIVER_DESC);
pr_info(KBUILD_MODNAME
": version " DRIVER_VERSION " " DRIVER_DESC "\n");
if (retval)
err("usb_register failed. Error number %d", retval);
pr_err(KBUILD_MODNAME
": usb_register failed. Error number %d\n", retval);
return retval;
}

View file

@ -1,7 +1,7 @@
/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
*
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
* TODO: Allow for more than one of these foolish entities :-)

View file

@ -3,7 +3,7 @@
* (c) 1997 M. Kirkwood
* (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
*
* Fitted to new interface by Alan Cox <alan.cox@linux.org>
* Fitted to new interface by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Made working and cleaned up functions <mikael.hedin@irf.se>
* Support for ISAPnP by Ladislav Michl <ladis@psi.cz>
*

View file

@ -184,7 +184,7 @@ config VIDEO_MSP3400
config VIDEO_CS5345
tristate "Cirrus Logic CS5345 audio ADC"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
depends on VIDEO_V4L2 && I2C
---help---
Support for the Cirrus Logic CS5345 24-bit, 192 kHz
stereo A/D converter.
@ -204,7 +204,7 @@ config VIDEO_CS53L32A
config VIDEO_M52790
tristate "Mitsubishi M52790 A/V switch"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
depends on VIDEO_V4L2 && I2C
---help---
Support for the Mitsubishi M52790 A/V switch.
@ -242,7 +242,7 @@ config VIDEO_WM8739
config VIDEO_VP27SMPX
tristate "Panasonic VP27s internal MPX"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
depends on VIDEO_V4L2 && I2C
---help---
Support for the internal MPX of the Panasonic VP27s tuner.
@ -361,6 +361,17 @@ config VIDEO_SAA7191
To compile this driver as a module, choose M here: the
module will be called saa7191.
config VIDEO_TVP514X
tristate "Texas Instruments TVP514x video decoder"
depends on VIDEO_V4L2 && I2C
---help---
This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
decoder. It is currently working with the TI OMAP3 camera
controller.
To compile this driver as a module, choose M here: the
module will be called tvp514x.
config VIDEO_TVP5150
tristate "Texas Instruments TVP5150 video decoder"
depends on VIDEO_V4L2 && I2C
@ -387,7 +398,7 @@ comment "MPEG video encoders"
config VIDEO_CX2341X
tristate "Conexant CX2341x MPEG encoders"
depends on VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_COMMON
depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON
---help---
Support for the Conexant CX23416 MPEG encoders
and CX23415 MPEG encoder/decoders.
@ -725,10 +736,16 @@ config MT9M001_PCA9536_SWITCH
extender to switch between 8 and 10 bit datawidth modes
config SOC_CAMERA_MT9M111
tristate "mt9m111 support"
tristate "mt9m111 and mt9m112 support"
depends on SOC_CAMERA && I2C
help
This driver supports MT9M111 cameras from Micron
This driver supports MT9M111 and MT9M112 cameras from Micron
config SOC_CAMERA_MT9T031
tristate "mt9t031 support"
depends on SOC_CAMERA && I2C
help
This driver supports MT9T031 cameras from Micron.
config SOC_CAMERA_MT9V022
tristate "mt9v022 support"
@ -744,12 +761,24 @@ config MT9V022_PCA9536_SWITCH
Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
extender to switch between 8 and 10 bit datawidth modes
config SOC_CAMERA_TW9910
tristate "tw9910 support"
depends on SOC_CAMERA && I2C
help
This is a tw9910 video driver
config SOC_CAMERA_PLATFORM
tristate "platform camera support"
depends on SOC_CAMERA
help
This is a generic SoC camera platform driver, useful for testing
config SOC_CAMERA_OV772X
tristate "ov772x camera support"
depends on SOC_CAMERA && I2C
help
This is a ov772x camera driver
config VIDEO_PXA27x
tristate "PXA27x Quick Capture Interface driver"
depends on VIDEO_DEV && PXA27x && SOC_CAMERA
@ -764,6 +793,13 @@ config VIDEO_SH_MOBILE_CEU
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
config VIDEO_OMAP2
tristate "OMAP2 Camera Capture Interface driver"
depends on VIDEO_DEV && ARCH_OMAP2
select VIDEOBUF_DMA_SG
---help---
This is a v4l2 driver for the TI OMAP2 camera capture interface
#
# USB Multimedia device configuration
#

View file

@ -8,9 +8,11 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o
stkwebcam-objs := stk-webcam.o stk-sensor.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-compat-ioctl32.o v4l2-int-device.o
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
@ -25,6 +27,7 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
@ -66,6 +69,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
@ -129,11 +133,15 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
obj-$(CONFIG_VIDEO_AU0828) += au0828/

View file

@ -396,8 +396,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
return ret;
}
static int ar_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
static int ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct ar_device *ar = video_get_drvdata(dev);
@ -543,7 +542,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, ar_do_ioctl);
return video_usercopy(file, cmd, arg, ar_do_ioctl);
}
#if USE_INT

View file

@ -1,274 +0,0 @@
/* Driver for Bt832 CMOS Camera Video Processor
i2c-addresses: 0x88 or 0x8a
The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
connected to bt848/bt878 GPIO pins on this purpose.
(see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
Supported Cards:
- Pixelview Rev.4E: 0x8a
GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
(c) Gunther Mayer, 2002
STATUS:
- detect chip and hexdump
- reset chip and leave low power mode
- detect camera present
TODO:
- make it work (find correct setup for Bt832 and Bt878)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <media/v4l2-common.h>
#include "bttv.h"
#include "bt832.h"
MODULE_LICENSE("GPL");
/* Addresses to scan */
static unsigned short normal_i2c[] = { I2C_ADDR_BT832_ALT1>>1, I2C_ADDR_BT832_ALT2>>1,
I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
int debug; /* debug output */
module_param(debug, int, 0644);
/* ---------------------------------------------------------------------- */
static int bt832_detach(struct i2c_client *client);
static struct i2c_driver driver;
static struct i2c_client client_template;
struct bt832 {
struct i2c_client client;
};
int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
{
int i,rc;
buf[0]=0x80; // start at register 0 with auto-increment
if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
for(i=0;i<65;i++)
buf[i]=0;
if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
// Note: On READ the first byte is the current index
// (e.g. 0x80, what we just wrote)
if(debug>1) {
int i;
v4l_dbg(2, debug,i2c_client_s,"hexdump:");
for(i=1;i<65;i++) {
if(i!=1) {
if(((i-1)%8)==0) printk(" ");
if(((i-1)%16)==0) {
printk("\n");
v4l_dbg(2, debug,i2c_client_s,"hexdump:");
}
}
printk(" %02x",buf[i]);
}
printk("\n");
}
return 0;
}
// Return: 1 (is a bt832), 0 (No bt832 here)
int bt832_init(struct i2c_client *i2c_client_s)
{
unsigned char *buf;
int rc;
buf=kmalloc(65,GFP_KERNEL);
if (!buf) {
v4l_err(&t->client,
"Unable to allocate memory. Detaching.\n");
return 0;
}
bt832_hexdump(i2c_client_s,buf);
if(buf[0x40] != 0x31) {
v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
kfree(buf);
return 0;
}
v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
buf[0]=BT832_VP_STATUS; // Reg.52
buf[1]= 0x00;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
// Leave low power mode:
v4l_err(i2c_client_s,"leave low power mode.\n");
buf[0]=BT832_CAM_SETUP0; //0x39 57
buf[1]=0x08;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
buf[0]=BT832_VP_STATUS; // Reg.52
buf[1]= 0x00;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
// Enable Output
v4l_info(i2c_client_s,"Enable Output\n");
buf[0]=BT832_VP_CONTROL1; // Reg.40
buf[1]= 0x27 & (~0x01); // Default | !skip
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
// for testing (even works when no camera attached)
v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
v4l_info(i2c_client_s,"Camera Present: %s\n",
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
bt832_hexdump(i2c_client_s,buf);
kfree(buf);
return 1;
}
static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct bt832 *t;
client_template.adapter = adap;
client_template.addr = addr;
if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
return -ENOMEM;
t->client = client_template;
i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client);
v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
if(! bt832_init(&t->client)) {
bt832_detach(&t->client);
return -1;
}
return 0;
}
static int bt832_probe(struct i2c_adapter *adap)
{
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, bt832_attach);
return 0;
}
static int bt832_detach(struct i2c_client *client)
{
struct bt832 *t = i2c_get_clientdata(client);
v4l_info(&t->client,"dettach\n");
i2c_detach_client(client);
kfree(t);
return 0;
}
static int
bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct bt832 *t = i2c_get_clientdata(client);
if (debug>1)
v4l_i2c_print_ioctl(&t->client,cmd);
switch (cmd) {
case BT832_HEXDUMP: {
unsigned char *buf;
buf = kmalloc(65, GFP_KERNEL);
if (!buf) {
v4l_err(&t->client,
"Unable to allocate memory\n");
break;
}
bt832_hexdump(&t->client,buf);
kfree(buf);
}
break;
case BT832_REATTACH:
v4l_info(&t->client,"re-attach\n");
i2c_del_driver(&driver);
i2c_add_driver(&driver);
break;
}
return 0;
}
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
.driver = {
.name = "bt832",
},
.id = 0, /* FIXME */
.attach_adapter = bt832_probe,
.detach_client = bt832_detach,
.command = bt832_command,
};
static struct i2c_client client_template =
{
.name = "bt832",
.driver = &driver,
};
static int __init bt832_init_module(void)
{
return i2c_add_driver(&driver);
}
static void __exit bt832_cleanup_module(void)
{
i2c_del_driver(&driver);
}
module_init(bt832_init_module);
module_exit(bt832_cleanup_module);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/

View file

@ -1,305 +0,0 @@
/* Bt832 CMOS Camera Video Processor (VP)
The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
color digital camera directly to video capture devices via an 8-bit,
4:2:2 YUV or YCrCb video interface.
i2c addresses: 0x88 or 0x8a
*/
/* The 64 registers: */
// Input Processor
#define BT832_OFFSET 0
#define BT832_RCOMP 1
#define BT832_G1COMP 2
#define BT832_G2COMP 3
#define BT832_BCOMP 4
// Exposures:
#define BT832_FINEH 5
#define BT832_FINEL 6
#define BT832_COARSEH 7
#define BT832_COARSEL 8
#define BT832_CAMGAIN 9
// Main Processor:
#define BT832_M00 10
#define BT832_M01 11
#define BT832_M02 12
#define BT832_M10 13
#define BT832_M11 14
#define BT832_M12 15
#define BT832_M20 16
#define BT832_M21 17
#define BT832_M22 18
#define BT832_APCOR 19
#define BT832_GAMCOR 20
// Level Accumulator Inputs
#define BT832_VPCONTROL2 21
#define BT832_ZONECODE0 22
#define BT832_ZONECODE1 23
#define BT832_ZONECODE2 24
#define BT832_ZONECODE3 25
// Level Accumulator Outputs:
#define BT832_RACC 26
#define BT832_GACC 27
#define BT832_BACC 28
#define BT832_BLACKACC 29
#define BT832_EXP_AGC 30
#define BT832_LACC0 31
#define BT832_LACC1 32
#define BT832_LACC2 33
#define BT832_LACC3 34
#define BT832_LACC4 35
#define BT832_LACC5 36
#define BT832_LACC6 37
#define BT832_LACC7 38
// System:
#define BT832_VP_CONTROL0 39
#define BT832_VP_CONTROL1 40
#define BT832_THRESH 41
#define BT832_VP_TESTCONTROL0 42
#define BT832_VP_DMCODE 43
#define BT832_ACB_CONFIG 44
#define BT832_ACB_GNBASE 45
#define BT832_ACB_MU 46
#define BT832_CAM_TEST0 47
#define BT832_AEC_CONFIG 48
#define BT832_AEC_TL 49
#define BT832_AEC_TC 50
#define BT832_AEC_TH 51
// Status:
#define BT832_VP_STATUS 52
#define BT832_VP_LINECOUNT 53
#define BT832_CAM_DEVICEL 54 // e.g. 0x19
#define BT832_CAM_DEVICEH 55 // e.g. 0x40 == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
#define BT832_CAM_STATUS 56
#define BT832_56_CAMERA_PRESENT 0x20
//Camera Setups:
#define BT832_CAM_SETUP0 57
#define BT832_CAM_SETUP1 58
#define BT832_CAM_SETUP2 59
#define BT832_CAM_SETUP3 60
// System:
#define BT832_DEFCOR 61
#define BT832_VP_TESTCONTROL1 62
#define BT832_DEVICE_ID 63
# define BT832_DEVICE_ID__31 0x31 // Bt832 has ID 0x31
/* STMicroelectronivcs VV5404 camera module
i2c: 0x20: sensor address
i2c: 0xa0: eeprom for ccd defect map
*/
#define VV5404_device_h 0x00 // 0x19
#define VV5404_device_l 0x01 // 0x40
#define VV5404_status0 0x02
#define VV5404_linecountc 0x03 // current line counter
#define VV5404_linecountl 0x04
#define VV5404_setup0 0x10
#define VV5404_setup1 0x11
#define VV5404_setup2 0x12
#define VV5404_setup4 0x14
#define VV5404_setup5 0x15
#define VV5404_fine_h 0x20 // fine exposure
#define VV5404_fine_l 0x21
#define VV5404_coarse_h 0x22 //coarse exposure
#define VV5404_coarse_l 0x23
#define VV5404_gain 0x24 // ADC pre-amp gain setting
#define VV5404_clk_div 0x25
#define VV5404_cr 0x76 // control register
#define VV5404_as0 0x77 // ADC setup register
// IOCTL
#define BT832_HEXDUMP _IOR('b',1,int)
#define BT832_REATTACH _IOR('b',2,int)
/* from BT8x8VXD/capdrv/dialogs.cpp */
/*
typedef enum { SVI, Logitech, Rockwell } CAMERA;
static COMBOBOX_ENTRY gwCameraOptions[] =
{
{ SVI, "Silicon Vision 512N" },
{ Logitech, "Logitech VideoMan 1.3" },
{ Rockwell, "Rockwell QuartzSight PCI 1.0" }
};
// SRAM table values
//===========================================================================
typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
BYTE SRAMTable[][ 60 ] =
{
// TGB_NTSC624
{
0x33, // size of table = 51
0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
},
// TGB_NTSC780
{
0x33, // size of table = 51
0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
},
// TGB_NTSC858
{
0x33, // size of table = 51
0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
},
// TGB_NTSC392
// This table has been modified to be used for Fusion Rev D
{
0x2A, // size of table = 42
0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
0x20, 0x00
}
};
//===========================================================================
// This is the structure of the camera specifications
//===========================================================================
typedef struct tag_cameraSpec
{
SignalFormat signal; // which digital signal format the camera has
VideoFormat vidFormat; // video standard
SyncVideoRef syncRef; // which sync video reference is used
State syncOutput; // enable sync output for sync video input?
DecInputClk iClk; // which input clock is used
TimeGenByte tgb; // which timing generator byte does the camera use
int HReset; // select 64, 48, 32, or 16 CLKx1 for HReset
PLLFreq pllFreq; // what synthesized frequency to set PLL to
VSIZEPARMS vSize; // video size the camera produces
int lineCount; // expected total number of half-line per frame - 1
BOOL interlace; // interlace signal?
} CameraSpec;
//===========================================================================
// <UPDATE REQUIRED>
// Camera specifications database. Update this table whenever camera spec
// has been changed or added/deleted supported camera models
//===========================================================================
static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
{ // Silicon Vision 512N
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
{ 512, 0x64, 480, 0x13, 240 }, 0, TRUE
},
// Logitech VideoMan 1.3
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
{ 640, 0x80, 480, 0x1A, 240 }, 0, TRUE
},
// Rockwell QuartzSight
// Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
// Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
{ Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
// Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
{ 352, 0x20, 576, 0x08, 288 }, 607, FALSE
}
};
*/
/*
The corresponding APIs required to be invoked are:
SetConnector( ConCamera, TRUE/FALSE );
SetSignalFormat( spec.signal );
SetVideoFormat( spec.vidFormat );
SetSyncVideoRef( spec.syncRef );
SetEnableSyncOutput( spec.syncOutput );
SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
SetHReset( spec.HReset );
SetPLL( spec.pllFreq );
SetDecInputClock( spec.iClk );
SetVideoInfo( spec.vSize );
SetTotalLineCount( spec.lineCount );
SetInterlaceMode( spec.interlace );
*/
/* from web:
Video Sampling
Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
Pixel Clock Horiz Horiz Vert
Rate Total Active
NTSC square pixel 12.27 MHz 780 640 525
NTSC CCIR-601 13.5 MHz 858 720 525
NTSC 4FSc 14.32 MHz 910 768 525
PAL square pixel 14.75 MHz 944 768 625
PAL CCIR-601 13.5 MHz 864 720 625
PAL 4FSc 17.72 MHz 1135 948 625
For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
*/
/* from DScaler:*/
/*
//===========================================================================
// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
//
// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
//
//===========================================================================
// Timing generator SRAM table values for CCIR601 720x480 NTSC
//===========================================================================
// For NTSC CCIR656
BYTE BtCard::SRAMTable_NTSC[] =
{
// SRAM Timing Table for NTSC
0x0c, 0xc0, 0x00,
0x00, 0x90, 0xc2,
0x03, 0x10, 0x03,
0x06, 0x10, 0x34,
0x12, 0x12, 0x65,
0x02, 0x13, 0x24,
0x19, 0x00, 0x24,
0x39, 0x00, 0x96,
0x59, 0x08, 0x93,
0x83, 0x08, 0x97,
0x03, 0x50, 0x30,
0xc0, 0x40, 0x30,
0x86, 0x01, 0x01,
0xa6, 0x0d, 0x62,
0x03, 0x11, 0x61,
0x05, 0x37, 0x30,
0xac, 0x21, 0x50
};
//===========================================================================
// Timing generator SRAM table values for CCIR601 720x576 NTSC
//===========================================================================
// For PAL CCIR656
BYTE BtCard::SRAMTable_PAL[] =
{
// SRAM Timing Table for PAL
0x36, 0x11, 0x01,
0x00, 0x90, 0x02,
0x05, 0x10, 0x04,
0x16, 0x14, 0x05,
0x11, 0x00, 0x04,
0x12, 0xc0, 0x00,
0x31, 0x00, 0x06,
0x51, 0x08, 0x03,
0x89, 0x08, 0x07,
0xc0, 0x44, 0x00,
0x81, 0x01, 0x01,
0xa9, 0x0d, 0x02,
0x02, 0x50, 0x03,
0x37, 0x3d, 0x00,
0xaf, 0x21, 0x00,
};
*/

View file

@ -44,7 +44,6 @@
/* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin);
static void boot_bt832(struct bttv *btv);
static void hauppauge_eeprom(struct bttv *btv);
static void avermedia_eeprom(struct bttv *btv);
static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
@ -2217,9 +2216,9 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
[BTTV_BOARD_VD009X1_MINIDIN] = {
[BTTV_BOARD_VD009X1_VD011_MINIDIN] = {
/* M.Klahr@phytec.de */
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
.name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = UNSET, /* card has no tuner */
@ -2227,14 +2226,14 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
[BTTV_BOARD_VD009X1_COMBI] = {
.name = "PHYTEC VD-009-X1 Combi (bt878)",
[BTTV_BOARD_VD009X1_VD011_COMBI] = {
.name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = UNSET, /* card has no tuner */
@ -2242,7 +2241,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
@ -3061,6 +3060,54 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.has_radio = 1,
.has_remote = 1,
},
[BTTV_BOARD_VD012] = {
/* D.Heer@Phytec.de */
.name = "PHYTEC VD-012 (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = UNSET, /* card has no tuner */
.svhs = UNSET, /* card has no s-video */
.gpiomask = 0x00,
.muxsel = { 0, 2, 3, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
[BTTV_BOARD_VD012_X1] = {
/* D.Heer@Phytec.de */
.name = "PHYTEC VD-012-X1 (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
[BTTV_BOARD_VD012_X2] = {
/* D.Heer@Phytec.de */
.name = "PHYTEC VD-012-X2 (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
.tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 3, 2, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 0,
.pll = PLL_28,
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
}
};
@ -3673,13 +3720,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->c.type].audio_mode_gpio)
btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
/* detect Bt832 chip for quartzsight digital camera */
if ((bttv_I2CRead(btv, I2C_ADDR_BT832_ALT1, "Bt832") >=0) ||
(bttv_I2CRead(btv, I2C_ADDR_BT832_ALT2, "Bt832") >=0))
boot_bt832(btv);
}
if (!autoload)
return;
@ -4075,10 +4115,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
"init [%d]\n", btv->c.nr, pin);
}
static void __devinit boot_bt832(struct bttv *btv)
{
}
/* ----------------------------------------------------------------------- */
/* Imagenation L-Model PXC200 Framegrabber */
/* This is basically the same procedure as

View file

@ -42,7 +42,7 @@ static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
int len = strlen(sub->wanted);
if (0 == strncmp(dev->bus_id, sub->wanted, len))
if (0 == strncmp(dev_name(dev), sub->wanted, len))
return 1;
return 0;
}
@ -91,15 +91,14 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
sub->dev.parent = &core->pci->dev;
sub->dev.bus = &bttv_sub_bus_type;
sub->dev.release = release_sub_device;
snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
name, core->nr);
dev_set_name(&sub->dev, "%s%d", name, core->nr);
err = device_register(&sub->dev);
if (0 != err) {
kfree(sub);
return err;
}
printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
list_add_tail(&sub->list,&core->subs);
return 0;
}

View file

@ -130,8 +130,8 @@
#define BTTV_BOARD_XGUARD 0x67
#define BTTV_BOARD_NEBULA_DIGITV 0x68
#define BTTV_BOARD_PV143 0x69
#define BTTV_BOARD_VD009X1_MINIDIN 0x6a
#define BTTV_BOARD_VD009X1_COMBI 0x6b
#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a
#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b
#define BTTV_BOARD_VD009_MINIDIN 0x6c
#define BTTV_BOARD_VD009_COMBI 0x6d
#define BTTV_BOARD_IVC100 0x6e
@ -177,6 +177,10 @@
#define BTTV_BOARD_GEOVISION_GV600 0x96
#define BTTV_BOARD_KOZUMI_KTV_01C 0x97
#define BTTV_BOARD_ENLTV_FM_2 0x98
#define BTTV_BOARD_VD012 0x99
#define BTTV_BOARD_VD012_X1 0x9a
#define BTTV_BOARD_VD012_X2 0x9b
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
@ -308,7 +312,7 @@ struct bttv_sub_device {
struct bttv_sub_driver {
struct device_driver drv;
char wanted[BUS_ID_SIZE];
char wanted[20];
int (*probe)(struct bttv_sub_device *sub);
void (*remove)(struct bttv_sub_device *sub);
};

View file

@ -459,7 +459,7 @@ struct bttv {
};
/* our devices */
#define BTTV_MAX 16
#define BTTV_MAX 32
extern unsigned int bttv_num;
extern struct bttv bttvs[BTTV_MAX];

View file

@ -706,8 +706,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
* Video4linux interfacing
*/
static int qcam_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam=(struct qcam_device *)dev;
@ -867,7 +866,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
static int qcam_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
return video_usercopy(file, cmd, arg, qcam_do_ioctl);
}
static ssize_t qcam_read(struct file *file, char __user *buf,

View file

@ -500,8 +500,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
* Video4linux interfacing
*/
static int qcam_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam=(struct qcam_device *)dev;
@ -667,9 +666,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
}
static int qcam_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
return video_usercopy(file, cmd, arg, qcam_do_ioctl);
}
static ssize_t qcam_read(struct file *file, char __user *buf,

View file

@ -3333,8 +3333,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
return cam->decompressed_frame.count;
}
static int cpia_do_ioctl(struct inode *inode, struct file *file,
unsigned int ioctlnr, void *arg)
static int cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *dev = file->private_data;
struct cam_data *cam = video_get_drvdata(dev);
@ -3347,9 +3346,9 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
if (mutex_lock_interruptible(&cam->busy_lock))
return -EINTR;
//DBG("cpia_ioctl: %u\n", ioctlnr);
/* DBG("cpia_ioctl: %u\n", cmd); */
switch (ioctlnr) {
switch (cmd) {
/* query capabilities */
case VIDIOCGCAP:
{
@ -3724,7 +3723,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
static int cpia_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
return video_usercopy(file, cmd, arg, cpia_do_ioctl);
}

View file

@ -25,7 +25,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Stripped of 2.4 stuff ready for main kernel submit by
* Alan Cox <alan@redhat.com>
* Alan Cox <alan@lxorguk.ukuu.org.uk>
*
****************************************************************************/

View file

@ -25,7 +25,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Stripped of 2.4 stuff ready for main kernel submit by
* Alan Cox <alan@redhat.com>
* Alan Cox <alan@lxorguk.ukuu.org.uk>
****************************************************************************/
#include <linux/kernel.h>

View file

@ -26,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Stripped of 2.4 stuff ready for main kernel submit by
* Alan Cox <alan@redhat.com>
* Alan Cox <alan@lxorguk.ukuu.org.uk>
****************************************************************************/
#include <linux/version.h>
@ -1572,8 +1572,7 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
* cpia2_ioctl
*
*****************************************************************************/
static int cpia2_do_ioctl(struct inode *inode, struct file *file,
unsigned int ioctl_nr, void *arg)
static int cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct camera_data *cam = video_drvdata(file);
int retval = 0;
@ -1591,7 +1590,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
}
/* Priority check */
switch (ioctl_nr) {
switch (cmd) {
case VIDIOCSWIN:
case VIDIOCMCAPTURE:
case VIDIOC_S_FMT:
@ -1618,7 +1617,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
break;
}
switch (ioctl_nr) {
switch (cmd) {
case VIDIOCGCAP: /* query capabilities */
retval = ioctl_cap_query(arg, cam);
break;
@ -1683,7 +1682,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
retval = ioctl_input(ioctl_nr, arg,cam);
retval = ioctl_input(cmd, arg, cam);
break;
case VIDIOC_ENUM_FMT:
@ -1843,9 +1842,9 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
}
static int cpia2_ioctl(struct inode *inode, struct file *file,
unsigned int ioctl_nr, unsigned long iarg)
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl);
return video_usercopy(file, cmd, arg, cpia2_do_ioctl);
}
/******************************************************************************

Some files were not shown because too many files have changed in this diff Show more