mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
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: (313 commits) V4L/DVB (9186): Added support for Prof 7300 DVB-S/S2 cards V4L/DVB (9185): S2API: Ensure we have a reasonable ROLLOFF default V4L/DVB (9184): cx24116: Change the default SNR units back to percentage by default. V4L/DVB (9183): S2API: Return error of the caller provides 0 commands. V4L/DVB (9182): S2API: Added support for DTV_HIERARCHY V4L/DVB (9181): S2API: Add support fot DTV_GUARD_INTERVAL and DTV_TRANSMISSION_MODE V4L/DVB (9180): S2API: Added support for DTV_CODE_RATE_HP/LP V4L/DVB (9179): S2API: frontend.h cleanup V4L/DVB (9178): cx24116: Add module parameter to return SNR as ESNO. V4L/DVB (9177): S2API: Change _8PSK / _16APSK to PSK_8 and APSK_16 V4L/DVB (9176): Add support for DvbWorld USB cards with STV0288 demodulator. V4L/DVB (9175): Remove NULL pointer in stb6000 driver. V4L/DVB (9174): Allow custom inittab for ST STV0288 demodulator. V4L/DVB (9173): S2API: Remove the hardcoded command limit during validation V4L/DVB (9172): S2API: Bugfix related to DVB-S / DVB-S2 tuning for the legacy API. V4L/DVB (9171): S2API: Stop an OOPS if illegal commands are dumped in S2API. V4L/DVB (9170): cx24116: Sanity checking to data input via S2API to the cx24116 demod. V4L/DVB (9169): uvcvideo: Support two new Bison Electronics webcams. V4L/DVB (9168): Add support for MSI TV@nywhere Plus remote V4L/DVB: v4l2-dev: remove duplicated #include ...
This commit is contained in:
commit
cf2fa66055
@ -150,3 +150,4 @@
|
||||
149 -> Typhoon TV-Tuner PCI (50684)
|
||||
150 -> Geovision GV-600 [008a:763c]
|
||||
151 -> Kozumi KTV-01C
|
||||
152 -> Encore ENL TV-FM-2 [1000:1801]
|
||||
|
@ -9,3 +9,5 @@
|
||||
8 -> Hauppauge WinTV-HVR1700 [0070:8101]
|
||||
9 -> Hauppauge WinTV-HVR1400 [0070:8010]
|
||||
10 -> DViCO FusionHDTV7 Dual Express [18ac:d618]
|
||||
11 -> DViCO FusionHDTV DVB-T Dual Express [18ac:db78]
|
||||
12 -> Leadtek Winfast PxDVR3200 H [107d:6681]
|
||||
|
@ -66,3 +66,11 @@
|
||||
65 -> DViCO FusionHDTV 7 Gold [18ac:d610]
|
||||
66 -> Prolink Pixelview MPEG 8000GT [1554:4935]
|
||||
67 -> Kworld PlusTV HD PCI 120 (ATSC 120) [17de:08c1]
|
||||
68 -> Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid [0070:6900,0070:6904,0070:6902]
|
||||
69 -> Hauppauge WinTV-HVR4000(Lite) DVB-S/S2 [0070:6905,0070:6906]
|
||||
70 -> TeVii S460 DVB-S/S2 [d460:9022]
|
||||
71 -> Omicom SS4 DVB-S/S2 PCI [A044:2011]
|
||||
72 -> TBS 8920 DVB-S/S2 [8920:8888]
|
||||
73 -> TeVii S420 DVB-S [d420:9022]
|
||||
74 -> Prolink Pixelview Global Extreme [1554:4976]
|
||||
75 -> PROF 7300 DVB-S/S2 [B033:3033]
|
||||
|
@ -1,5 +1,5 @@
|
||||
0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800]
|
||||
1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
|
||||
1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2820,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,7 +12,7 @@
|
||||
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)
|
||||
14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) [eb1a:2821]
|
||||
15 -> V-Gear PocketTV (em2800)
|
||||
16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b,2040:651f]
|
||||
17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227]
|
||||
|
@ -76,7 +76,7 @@
|
||||
75 -> AVerMedia AVerTVHD MCE A180 [1461:1044]
|
||||
76 -> SKNet MonsterTV Mobile [1131:4ee9]
|
||||
77 -> Pinnacle PCTV 40i/50i/110i (saa7133) [11bd:002e]
|
||||
78 -> ASUSTeK P7131 Dual [1043:4862,1043:4857]
|
||||
78 -> ASUSTeK P7131 Dual [1043:4862]
|
||||
79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
|
||||
80 -> ASUS Digimatrix TV [1043:0210]
|
||||
81 -> Philips Tiger reference design [1131:2018]
|
||||
@ -145,3 +145,9 @@
|
||||
144 -> Beholder BeholdTV M6 Extra [5ace:6193]
|
||||
145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636]
|
||||
146 -> ASUSTeK P7131 Analog
|
||||
147 -> Asus Tiger 3in1 [1043:4878]
|
||||
148 -> Encore ENLTV-FM v5.3 [1a7f:2008]
|
||||
149 -> Avermedia PCI pure analog (M135A) [1461:f11d]
|
||||
150 -> Zogis Real Angel 220
|
||||
151 -> ADS Tech Instant HDTV [1421:0380]
|
||||
152 -> Asus Tiger Rev:1.00 [1043:4857]
|
||||
|
@ -74,3 +74,4 @@ tuner=72 - Thomson FE6600
|
||||
tuner=73 - Samsung TCPG 6121P30A
|
||||
tuner=75 - Philips TEA5761 FM Radio
|
||||
tuner=76 - Xceive 5000 tuner
|
||||
tuner=77 - TCL tuner MF02GIP-5N-E
|
||||
|
@ -7,6 +7,7 @@ The modules are:
|
||||
xxxx vend:prod
|
||||
----
|
||||
spca501 0000:0000 MystFromOri Unknow Camera
|
||||
m5602 0402:5602 ALi Video Camera Controller
|
||||
spca501 040a:0002 Kodak DVC-325
|
||||
spca500 040a:0300 Kodak EZ200
|
||||
zc3xx 041e:041e Creative WebCam Live!
|
||||
@ -42,6 +43,7 @@ zc3xx 0458:7007 Genius VideoCam V2
|
||||
zc3xx 0458:700c Genius VideoCam V3
|
||||
zc3xx 0458:700f Genius VideoCam Web V2
|
||||
sonixj 0458:7025 Genius Eye 311Q
|
||||
sonixj 0458:702e Genius Slim 310 NB
|
||||
sonixj 045e:00f5 MicroSoft VX3000
|
||||
sonixj 045e:00f7 MicroSoft VX1000
|
||||
ov519 045e:028c Micro$oft xbox cam
|
||||
@ -81,7 +83,7 @@ spca561 046d:092b Labtec Webcam Plus
|
||||
spca561 046d:092c Logitech QC chat Elch2
|
||||
spca561 046d:092d Logitech QC Elch2
|
||||
spca561 046d:092e Logitech QC Elch2
|
||||
spca561 046d:092f Logitech QC Elch2
|
||||
spca561 046d:092f Logitech QuickCam Express Plus
|
||||
sunplus 046d:0960 Logitech ClickSmart 420
|
||||
sunplus 0471:0322 Philips DMVC1300K
|
||||
zc3xx 0471:0325 Philips SPC 200 NC
|
||||
@ -96,6 +98,29 @@ sunplus 04a5:3003 Benq DC 1300
|
||||
sunplus 04a5:3008 Benq DC 1500
|
||||
sunplus 04a5:300a Benq DC 3410
|
||||
spca500 04a5:300c Benq DC 1016
|
||||
finepix 04cb:0104 Fujifilm FinePix 4800
|
||||
finepix 04cb:0109 Fujifilm FinePix A202
|
||||
finepix 04cb:010b Fujifilm FinePix A203
|
||||
finepix 04cb:010f Fujifilm FinePix A204
|
||||
finepix 04cb:0111 Fujifilm FinePix A205
|
||||
finepix 04cb:0113 Fujifilm FinePix A210
|
||||
finepix 04cb:0115 Fujifilm FinePix A303
|
||||
finepix 04cb:0117 Fujifilm FinePix A310
|
||||
finepix 04cb:0119 Fujifilm FinePix F401
|
||||
finepix 04cb:011b Fujifilm FinePix F402
|
||||
finepix 04cb:011d Fujifilm FinePix F410
|
||||
finepix 04cb:0121 Fujifilm FinePix F601
|
||||
finepix 04cb:0123 Fujifilm FinePix F700
|
||||
finepix 04cb:0125 Fujifilm FinePix M603
|
||||
finepix 04cb:0127 Fujifilm FinePix S300
|
||||
finepix 04cb:0129 Fujifilm FinePix S304
|
||||
finepix 04cb:012b Fujifilm FinePix S500
|
||||
finepix 04cb:012d Fujifilm FinePix S602
|
||||
finepix 04cb:012f Fujifilm FinePix S700
|
||||
finepix 04cb:0131 Fujifilm FinePix unknown model
|
||||
finepix 04cb:013b Fujifilm FinePix unknown model
|
||||
finepix 04cb:013d Fujifilm FinePix unknown model
|
||||
finepix 04cb:013f Fujifilm FinePix F420
|
||||
sunplus 04f1:1001 JVC GC A50
|
||||
spca561 04fc:0561 Flexcam 100
|
||||
sunplus 04fc:500c Sunplus CA500C
|
||||
@ -181,6 +206,7 @@ pac207 093a:2468 PAC207
|
||||
pac207 093a:2470 Genius GF112
|
||||
pac207 093a:2471 Genius VideoCam ge111
|
||||
pac207 093a:2472 Genius VideoCam ge110
|
||||
pac207 093a:2476 Genius e-Messenger 112
|
||||
pac7311 093a:2600 PAC7311 Typhoon
|
||||
pac7311 093a:2601 Philips SPC 610 NC
|
||||
pac7311 093a:2603 PAC7312
|
||||
|
12
Documentation/video4linux/m5602.txt
Normal file
12
Documentation/video4linux/m5602.txt
Normal file
@ -0,0 +1,12 @@
|
||||
This document describes the ALi m5602 bridge connected
|
||||
to the following supported sensors:
|
||||
OmniVision OV9650,
|
||||
Samsung s5k83a,
|
||||
Samsung s5k4aa,
|
||||
Micron mt9m111,
|
||||
Pixel plus PO1030
|
||||
|
||||
This driver mimics the windows drivers, which have a braindead implementation sending bayer-encoded frames at VGA resolution.
|
||||
In a perfect world we should be able to reprogram the m5602 and the connected sensor in hardware instead, supporting a range of resolutions and pixelformats
|
||||
|
||||
Anyway, have fun and please report any bugs to m560x-driver-devel@lists.sourceforge.net
|
120
Documentation/video4linux/soc-camera.txt
Normal file
120
Documentation/video4linux/soc-camera.txt
Normal file
@ -0,0 +1,120 @@
|
||||
Soc-Camera Subsystem
|
||||
====================
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
The following terms are used in this document:
|
||||
- camera / camera device / camera sensor - a video-camera sensor chip, capable
|
||||
of connecting to a variety of systems and interfaces, typically uses i2c for
|
||||
control and configuration, and a parallel or a serial bus for data.
|
||||
- camera host - an interface, to which a camera is connected. Typically a
|
||||
specialised interface, present on many SoCs, e.g., PXA27x and PXA3xx, SuperH,
|
||||
AVR32, i.MX27, i.MX31.
|
||||
- camera host bus - a connection between a camera host and a camera. Can be
|
||||
parallel or serial, consists of data and control lines, e.g., clock, vertical
|
||||
and horizontal synchronization signals.
|
||||
|
||||
Purpose of the soc-camera subsystem
|
||||
-----------------------------------
|
||||
|
||||
The soc-camera subsystem provides a unified API between camera host drivers and
|
||||
camera sensor drivers. It implements a V4L2 interface to the user, currently
|
||||
only the mmap method is supported.
|
||||
|
||||
This subsystem has been written to connect drivers for System-on-Chip (SoC)
|
||||
video capture interfaces with drivers for CMOS camera sensor chips to enable
|
||||
the reuse of sensor drivers with various hosts. The subsystem has been designed
|
||||
to support multiple camera host interfaces and multiple cameras per interface,
|
||||
although most applications have only one camera sensor.
|
||||
|
||||
Existing drivers
|
||||
----------------
|
||||
|
||||
As of 2.6.27-rc4 there are two host drivers in the mainline: pxa_camera.c for
|
||||
PXA27x SoCs and sh_mobile_ceu_camera.c for SuperH SoCs, and four sensor drivers:
|
||||
mt9m001.c, mt9m111.c, mt9v022.c and a generic soc_camera_platform.c driver. This
|
||||
list is not supposed to be updated, look for more examples in your tree.
|
||||
|
||||
Camera host API
|
||||
---------------
|
||||
|
||||
A host camera driver is registered using the
|
||||
|
||||
soc_camera_host_register(struct soc_camera_host *);
|
||||
|
||||
function. The host object can be initialized as follows:
|
||||
|
||||
static struct soc_camera_host pxa_soc_camera_host = {
|
||||
.drv_name = PXA_CAM_DRV_NAME,
|
||||
.ops = &pxa_soc_camera_host_ops,
|
||||
};
|
||||
|
||||
All camera host methods are passed in a struct soc_camera_host_ops:
|
||||
|
||||
static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.add = pxa_camera_add_device,
|
||||
.remove = pxa_camera_remove_device,
|
||||
.suspend = pxa_camera_suspend,
|
||||
.resume = pxa_camera_resume,
|
||||
.set_fmt_cap = pxa_camera_set_fmt_cap,
|
||||
.try_fmt_cap = pxa_camera_try_fmt_cap,
|
||||
.init_videobuf = pxa_camera_init_videobuf,
|
||||
.reqbufs = pxa_camera_reqbufs,
|
||||
.poll = pxa_camera_poll,
|
||||
.querycap = pxa_camera_querycap,
|
||||
.try_bus_param = pxa_camera_try_bus_param,
|
||||
.set_bus_param = pxa_camera_set_bus_param,
|
||||
};
|
||||
|
||||
.add and .remove methods are called when a sensor is attached to or detached
|
||||
from the host, apart from performing host-internal tasks they shall also call
|
||||
sensor driver's .init and .release methods respectively. .suspend and .resume
|
||||
methods implement host's power-management functionality and its their
|
||||
responsibility to call respective sensor's methods. .try_bus_param and
|
||||
.set_bus_param are used to negotiate physical connection parameters between the
|
||||
host and the sensor. .init_videobuf is called by soc-camera core when a
|
||||
video-device is opened, further video-buffer management is implemented completely
|
||||
by the specific camera host driver. The rest of the methods are called from
|
||||
respective V4L2 operations.
|
||||
|
||||
Camera API
|
||||
----------
|
||||
|
||||
Sensor drivers can use struct soc_camera_link, typically provided by the
|
||||
platform, and used to specify to which camera host bus the sensor is connected,
|
||||
and arbitrarily provide platform .power and .reset methods for the camera.
|
||||
soc_camera_device_register() and soc_camera_device_unregister() functions are
|
||||
used to add a sensor driver to or remove one from the system. The registration
|
||||
function takes a pointer to struct soc_camera_device as the only parameter.
|
||||
This struct can be initialized as follows:
|
||||
|
||||
/* link to driver operations */
|
||||
icd->ops = &mt9m001_ops;
|
||||
/* link to the underlying physical (e.g., i2c) device */
|
||||
icd->control = &client->dev;
|
||||
/* window geometry */
|
||||
icd->x_min = 20;
|
||||
icd->y_min = 12;
|
||||
icd->x_current = 20;
|
||||
icd->y_current = 12;
|
||||
icd->width_min = 48;
|
||||
icd->width_max = 1280;
|
||||
icd->height_min = 32;
|
||||
icd->height_max = 1024;
|
||||
icd->y_skip_top = 1;
|
||||
/* camera bus ID, typically obtained from platform data */
|
||||
icd->iface = icl->bus_id;
|
||||
|
||||
struct soc_camera_ops provides .probe and .remove methods, which are called by
|
||||
the soc-camera core, when a camera is matched against or removed from a camera
|
||||
host bus, .init, .release, .suspend, and .resume are called from the camera host
|
||||
driver as discussed above. Other members of this struct provide respective V4L2
|
||||
functionality.
|
||||
|
||||
struct soc_camera_device also links to an array of struct soc_camera_data_format,
|
||||
listing pixel formats, supported by the camera.
|
||||
|
||||
--
|
||||
Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
|
@ -36,8 +36,6 @@
|
||||
|
||||
struct pxacamera_platform_data {
|
||||
int (*init)(struct device *);
|
||||
int (*power)(struct device *, int);
|
||||
int (*reset)(struct device *, int);
|
||||
|
||||
unsigned long flags;
|
||||
unsigned long mclk_10khz;
|
||||
|
@ -103,6 +103,56 @@ IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
|
||||
|
||||
/* Mauro Carvalho Chehab <mchehab@infradead.org> */
|
||||
IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
|
||||
[0x00] = KEY_POWER2,
|
||||
[0x2e] = KEY_DOT, /* '.' */
|
||||
[0x01] = KEY_MODE, /* TV/FM */
|
||||
|
||||
[0x05] = KEY_1,
|
||||
[0x06] = KEY_2,
|
||||
[0x07] = KEY_3,
|
||||
[0x09] = KEY_4,
|
||||
[0x0a] = KEY_5,
|
||||
[0x0b] = KEY_6,
|
||||
[0x0d] = KEY_7,
|
||||
[0x0e] = KEY_8,
|
||||
[0x0f] = KEY_9,
|
||||
[0x11] = KEY_0,
|
||||
|
||||
[0x13] = KEY_RIGHT, /* -> */
|
||||
[0x12] = KEY_LEFT, /* <- */
|
||||
|
||||
[0x17] = KEY_SLEEP, /* Capturar Imagem */
|
||||
[0x10] = KEY_SHUFFLE, /* Amostra */
|
||||
|
||||
/* FIXME: The keys bellow aren't ok */
|
||||
|
||||
[0x43] = KEY_CHANNELUP,
|
||||
[0x42] = KEY_CHANNELDOWN,
|
||||
[0x1f] = KEY_VOLUMEUP,
|
||||
[0x1e] = KEY_VOLUMEDOWN,
|
||||
[0x0c] = KEY_ENTER,
|
||||
|
||||
[0x14] = KEY_MUTE,
|
||||
[0x08] = KEY_AUDIO,
|
||||
|
||||
[0x03] = KEY_TEXT,
|
||||
[0x04] = KEY_EPG,
|
||||
[0x2b] = KEY_TV2, /* TV2 */
|
||||
|
||||
[0x1d] = KEY_RED,
|
||||
[0x1c] = KEY_YELLOW,
|
||||
[0x41] = KEY_GREEN,
|
||||
[0x40] = KEY_BLUE,
|
||||
|
||||
[0x1a] = KEY_PLAYPAUSE,
|
||||
[0x19] = KEY_RECORD,
|
||||
[0x18] = KEY_PLAY,
|
||||
[0x1b] = KEY_STOP,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
|
||||
|
||||
/* Attila Kondoros <attila.kondoros@chello.hu> */
|
||||
IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
|
||||
|
||||
@ -467,7 +517,8 @@ EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* MSI TV@nywhere remote */
|
||||
/* MSI TV@nywhere MASTER remote */
|
||||
|
||||
IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
|
||||
/* Keys 0 to 9 */
|
||||
[ 0x00 ] = KEY_0,
|
||||
@ -501,6 +552,95 @@ EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
|
||||
is marked "KS003". The controller is I2C at address 0x30, but does not seem
|
||||
to respond to probes until a read is performed from a valid device.
|
||||
I don't know why...
|
||||
|
||||
Note: This remote may be of similar or identical design to the
|
||||
Pixelview remote (?). The raw codes and duplicate button codes
|
||||
appear to be the same.
|
||||
|
||||
Henry Wong <henry@stuffedcow.net>
|
||||
Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
|
||||
|
||||
*/
|
||||
|
||||
IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
|
||||
|
||||
/* ---- Remote Button Layout ----
|
||||
|
||||
POWER SOURCE SCAN MUTE
|
||||
TV/FM 1 2 3
|
||||
|> 4 5 6
|
||||
<| 7 8 9
|
||||
^^UP 0 + RECALL
|
||||
vvDN RECORD STOP PLAY
|
||||
|
||||
MINIMIZE ZOOM
|
||||
|
||||
CH+
|
||||
VOL- VOL+
|
||||
CH-
|
||||
|
||||
SNAPSHOT MTS
|
||||
|
||||
<< FUNC >> RESET
|
||||
*/
|
||||
|
||||
[0x01] = KEY_KP1, /* 1 */
|
||||
[0x0b] = KEY_KP2, /* 2 */
|
||||
[0x1b] = KEY_KP3, /* 3 */
|
||||
[0x05] = KEY_KP4, /* 4 */
|
||||
[0x09] = KEY_KP5, /* 5 */
|
||||
[0x15] = KEY_KP6, /* 6 */
|
||||
[0x06] = KEY_KP7, /* 7 */
|
||||
[0x0a] = KEY_KP8, /* 8 */
|
||||
[0x12] = KEY_KP9, /* 9 */
|
||||
[0x02] = KEY_KP0, /* 0 */
|
||||
[0x10] = KEY_KPPLUS, /* + */
|
||||
[0x13] = KEY_AGAIN, /* Recall */
|
||||
|
||||
[0x1e] = KEY_POWER, /* Power */
|
||||
[0x07] = KEY_TUNER, /* Source */
|
||||
[0x1c] = KEY_SEARCH, /* Scan */
|
||||
[0x18] = KEY_MUTE, /* Mute */
|
||||
|
||||
[0x03] = KEY_RADIO, /* TV/FM */
|
||||
/* The next four keys are duplicates that appear to send the
|
||||
same IR code as Ch+, Ch-, >>, and << . The raw code assigned
|
||||
to them is the actual code + 0x20 - they will never be
|
||||
detected as such unless some way is discovered to distinguish
|
||||
these buttons from those that have the same code. */
|
||||
[0x3f] = KEY_RIGHT, /* |> and Ch+ */
|
||||
[0x37] = KEY_LEFT, /* <| and Ch- */
|
||||
[0x2c] = KEY_UP, /* ^^Up and >> */
|
||||
[0x24] = KEY_DOWN, /* vvDn and << */
|
||||
|
||||
[0x00] = KEY_RECORD, /* Record */
|
||||
[0x08] = KEY_STOP, /* Stop */
|
||||
[0x11] = KEY_PLAY, /* Play */
|
||||
|
||||
[0x0f] = KEY_CLOSE, /* Minimize */
|
||||
[0x19] = KEY_ZOOM, /* Zoom */
|
||||
[0x1a] = KEY_SHUFFLE, /* Snapshot */
|
||||
[0x0d] = KEY_LANGUAGE, /* MTS */
|
||||
|
||||
[0x14] = KEY_VOLUMEDOWN, /* Vol- */
|
||||
[0x16] = KEY_VOLUMEUP, /* Vol+ */
|
||||
[0x17] = KEY_CHANNELDOWN, /* Ch- */
|
||||
[0x1f] = KEY_CHANNELUP, /* Ch+ */
|
||||
|
||||
[0x04] = KEY_REWIND, /* << */
|
||||
[0x0e] = KEY_MENU, /* Function */
|
||||
[0x0c] = KEY_FASTFORWARD, /* >> */
|
||||
[0x1d] = KEY_RESTART, /* Reset */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* Cinergy 1400 DVB-T */
|
||||
IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
|
||||
[ 0x01 ] = KEY_POWER,
|
||||
@ -1792,12 +1932,61 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
|
||||
[ 0x41 ] = KEY_GREEN, /* AP2 */
|
||||
[ 0x47 ] = KEY_YELLOW, /* AP3 */
|
||||
[ 0x57 ] = KEY_BLUE, /* AP4 */
|
||||
|
||||
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
|
||||
|
||||
/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org> */
|
||||
IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = {
|
||||
[0x4c] = KEY_POWER2,
|
||||
[0x4a] = KEY_TUNER,
|
||||
[0x40] = KEY_1,
|
||||
[0x60] = KEY_2,
|
||||
[0x50] = KEY_3,
|
||||
[0x70] = KEY_4,
|
||||
[0x48] = KEY_5,
|
||||
[0x68] = KEY_6,
|
||||
[0x58] = KEY_7,
|
||||
[0x78] = KEY_8,
|
||||
[0x44] = KEY_9,
|
||||
[0x54] = KEY_0,
|
||||
|
||||
[0x64] = KEY_LAST, /* +100 */
|
||||
[0x4e] = KEY_AGAIN, /* Recall */
|
||||
|
||||
[0x6c] = KEY_SWITCHVIDEOMODE, /* Video Source */
|
||||
[0x5e] = KEY_MENU,
|
||||
[0x56] = KEY_SCREEN,
|
||||
[0x7a] = KEY_SETUP,
|
||||
|
||||
[0x46] = KEY_MUTE,
|
||||
[0x5c] = KEY_MODE, /* Stereo */
|
||||
[0x74] = KEY_INFO,
|
||||
[0x7c] = KEY_CLEAR,
|
||||
|
||||
[0x55] = KEY_UP,
|
||||
[0x49] = KEY_DOWN,
|
||||
[0x7e] = KEY_LEFT,
|
||||
[0x59] = KEY_RIGHT,
|
||||
[0x6a] = KEY_ENTER,
|
||||
|
||||
[0x42] = KEY_VOLUMEUP,
|
||||
[0x62] = KEY_VOLUMEDOWN,
|
||||
[0x52] = KEY_CHANNELUP,
|
||||
[0x72] = KEY_CHANNELDOWN,
|
||||
|
||||
[0x41] = KEY_RECORD,
|
||||
[0x51] = KEY_SHUFFLE, /* Snapshot */
|
||||
[0x75] = KEY_TIME, /* Timeshift */
|
||||
[0x71] = KEY_TV2, /* PIP */
|
||||
|
||||
[0x45] = KEY_REWIND,
|
||||
[0x6f] = KEY_PAUSE,
|
||||
[0x7d] = KEY_FORWARD,
|
||||
[0x79] = KEY_STOP,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2);
|
||||
|
||||
/* for the Technotrend 1500 bundled remotes (grey and black): */
|
||||
IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
|
||||
[ 0x01 ] = KEY_POWER,
|
||||
@ -2239,3 +2428,86 @@ IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
|
||||
[0x2a] = KEY_MENU,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
|
||||
|
||||
/* Encore ENLTV-FM v5.3
|
||||
Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
*/
|
||||
IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE] = {
|
||||
[0x10] = KEY_POWER2,
|
||||
[0x06] = KEY_MUTE,
|
||||
|
||||
[0x09] = KEY_1,
|
||||
[0x1d] = KEY_2,
|
||||
[0x1f] = KEY_3,
|
||||
[0x19] = KEY_4,
|
||||
[0x1b] = KEY_5,
|
||||
[0x11] = KEY_6,
|
||||
[0x17] = KEY_7,
|
||||
[0x12] = KEY_8,
|
||||
[0x16] = KEY_9,
|
||||
[0x48] = KEY_0,
|
||||
|
||||
[0x04] = KEY_LIST, /* -/-- */
|
||||
[0x40] = KEY_LAST, /* recall */
|
||||
|
||||
[0x02] = KEY_MODE, /* TV/AV */
|
||||
[0x05] = KEY_SHUFFLE, /* SNAPSHOT */
|
||||
|
||||
[0x4c] = KEY_CHANNELUP, /* UP */
|
||||
[0x00] = KEY_CHANNELDOWN, /* DOWN */
|
||||
[0x0d] = KEY_VOLUMEUP, /* RIGHT */
|
||||
[0x15] = KEY_VOLUMEDOWN, /* LEFT */
|
||||
[0x49] = KEY_ENTER, /* OK */
|
||||
|
||||
[0x54] = KEY_RECORD,
|
||||
[0x4d] = KEY_PLAY, /* pause */
|
||||
|
||||
[0x1e] = KEY_UP, /* video setting */
|
||||
[0x0e] = KEY_RIGHT, /* <- */
|
||||
[0x1a] = KEY_LEFT, /* -> */
|
||||
|
||||
[0x0a] = KEY_DOWN, /* video default */
|
||||
[0x0c] = KEY_ZOOM, /* hide pannel */
|
||||
[0x47] = KEY_SLEEP, /* shutdown */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53);
|
||||
|
||||
/* Zogis Real Audio 220 - 32 keys IR */
|
||||
IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
|
||||
[0x1c] = KEY_RADIO,
|
||||
[0x12] = KEY_POWER2,
|
||||
|
||||
[0x01] = KEY_1,
|
||||
[0x02] = KEY_2,
|
||||
[0x03] = KEY_3,
|
||||
[0x04] = KEY_4,
|
||||
[0x05] = KEY_5,
|
||||
[0x06] = KEY_6,
|
||||
[0x07] = KEY_7,
|
||||
[0x08] = KEY_8,
|
||||
[0x09] = KEY_9,
|
||||
[0x00] = KEY_0,
|
||||
|
||||
[0x0c] = KEY_VOLUMEUP,
|
||||
[0x18] = KEY_VOLUMEDOWN,
|
||||
[0x0b] = KEY_CHANNELUP,
|
||||
[0x15] = KEY_CHANNELDOWN,
|
||||
[0x16] = KEY_ENTER,
|
||||
|
||||
[0x11] = KEY_LIST, /* Source */
|
||||
[0x0d] = KEY_AUDIO, /* stereo */
|
||||
|
||||
[0x0f] = KEY_PREVIOUS, /* Prev */
|
||||
[0x1b] = KEY_PAUSE, /* Timeshift */
|
||||
[0x1a] = KEY_NEXT, /* Next */
|
||||
|
||||
[0x0e] = KEY_STOP,
|
||||
[0x1f] = KEY_PLAY,
|
||||
[0x1e] = KEY_PLAYPAUSE, /* Pause */
|
||||
|
||||
[0x1d] = KEY_RECORD,
|
||||
[0x13] = KEY_MUTE,
|
||||
[0x19] = KEY_SHUFFLE, /* Snapshot */
|
||||
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
|
||||
|
@ -234,7 +234,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
{
|
||||
__le32 *cpu;
|
||||
dma_addr_t dma_addr;
|
||||
dma_addr_t dma_addr = 0;
|
||||
|
||||
cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
|
||||
if (NULL == cpu) {
|
||||
|
@ -533,7 +533,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
|
||||
memcpy(vfd, &device_template, sizeof(struct video_device));
|
||||
strlcpy(vfd->name, name, sizeof(vfd->name));
|
||||
vfd->release = video_device_release;
|
||||
vfd->priv = dev;
|
||||
video_set_drvdata(vfd, dev);
|
||||
|
||||
// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
|
||||
if (video_register_device(vfd, type, -1) < 0) {
|
||||
|
@ -170,6 +170,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
|
||||
b[0] = REG_LO1B1;
|
||||
b[1] = 0xFF;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
mt2060_writeregs(priv,b,2);
|
||||
|
||||
freq = params->frequency / 1000; // Hz -> kHz
|
||||
@ -233,6 +236,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
|
||||
i++;
|
||||
} while (i<10);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -296,13 +302,35 @@ static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
static int mt2060_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mt2060_priv *priv = fe->tuner_priv;
|
||||
return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
|
||||
int ret;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
ret = mt2060_writereg(priv, REG_VGAG,
|
||||
(priv->cfg->clock_out << 6) | 0x33);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt2060_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct mt2060_priv *priv = fe->tuner_priv;
|
||||
return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
|
||||
int ret;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
ret = mt2060_writereg(priv, REG_VGAG,
|
||||
(priv->cfg->clock_out << 6) | 0x30);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt2060_release(struct dvb_frontend *fe)
|
||||
@ -344,6 +372,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
|
||||
priv->i2c = i2c;
|
||||
priv->if1_freq = if1;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
@ -360,6 +391,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
|
||||
|
||||
mt2060_calibrate(priv);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
|
||||
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL(mt2060_attach);
|
||||
|
@ -979,7 +979,6 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
|
||||
switch (instance) {
|
||||
case 0:
|
||||
goto fail;
|
||||
break;
|
||||
case 1:
|
||||
/* new tuner instance */
|
||||
state->config = cfg;
|
||||
|
@ -1155,7 +1155,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
||||
switch (instance) {
|
||||
case 0:
|
||||
goto fail;
|
||||
break;
|
||||
case 1:
|
||||
/* new tuner instance */
|
||||
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
|
||||
|
@ -447,17 +447,19 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
|
||||
else
|
||||
arg = 0;
|
||||
}
|
||||
if (priv->cfg->tuner_callback)
|
||||
priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
|
||||
gp_func, arg);
|
||||
if (fe->callback)
|
||||
fe->callback(priv->i2c_adap->algo_data,
|
||||
DVB_FRONTEND_COMPONENT_TUNER,
|
||||
gp_func, arg);
|
||||
buf[1] = high ? 0 : 1;
|
||||
if (priv->cfg->config == 2)
|
||||
buf[1] = high ? 1 : 0;
|
||||
i2c_transfer(priv->i2c_adap, &msg, 1);
|
||||
break;
|
||||
case 3: /* switch with GPIO of saa713x */
|
||||
if (priv->cfg->tuner_callback)
|
||||
priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
|
||||
if (fe->callback)
|
||||
fe->callback(priv->i2c_adap->algo_data,
|
||||
DVB_FRONTEND_COMPONENT_TUNER, 0, high);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ struct tda827x_config
|
||||
/* interface to tda829x driver */
|
||||
unsigned int config;
|
||||
int switch_addr;
|
||||
int (*tuner_callback) (void *dev, int command, int arg);
|
||||
|
||||
void (*agcf)(struct dvb_frontend *fe);
|
||||
};
|
||||
|
@ -672,10 +672,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
|
||||
priv->i2c_props.addr = i2c_addr;
|
||||
priv->i2c_props.adap = i2c_adap;
|
||||
priv->i2c_props.name = "tda829x";
|
||||
if (cfg) {
|
||||
if (cfg)
|
||||
priv->cfg.config = cfg->lna_cfg;
|
||||
priv->cfg.tuner_callback = cfg->tuner_callback;
|
||||
}
|
||||
|
||||
if (tda8290_probe(&priv->i2c_props) == 0) {
|
||||
priv->ver = TDA8290;
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
struct tda829x_config {
|
||||
unsigned int lna_cfg;
|
||||
int (*tuner_callback) (void *dev, int command, int arg);
|
||||
|
||||
unsigned int probe_tuner:1;
|
||||
#define TDA829X_PROBE_TUNER 0
|
||||
|
@ -686,7 +686,6 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
|
||||
case 0:
|
||||
mutex_unlock(&tda9887_list_mutex);
|
||||
return NULL;
|
||||
break;
|
||||
case 1:
|
||||
fe->analog_demod_priv = priv;
|
||||
priv->mode = T_STANDBY;
|
||||
|
@ -142,6 +142,7 @@ static inline int tuner_stereo(const int type, const int status)
|
||||
case TUNER_PHILIPS_FM1236_MK3:
|
||||
case TUNER_PHILIPS_FM1256_IH3:
|
||||
case TUNER_LG_NTSC_TAPE:
|
||||
case TUNER_TCL_MF02GIP_5N:
|
||||
return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
|
||||
default:
|
||||
return status & TUNER_STEREO;
|
||||
@ -494,6 +495,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
|
||||
case TUNER_PHILIPS_FMD1216ME_MK3:
|
||||
case TUNER_LG_NTSC_TAPE:
|
||||
case TUNER_PHILIPS_FM1256_IH3:
|
||||
case TUNER_TCL_MF02GIP_5N:
|
||||
buffer[3] = 0x19;
|
||||
break;
|
||||
case TUNER_TNF_5335MF:
|
||||
@ -1038,7 +1040,6 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
|
||||
case 0:
|
||||
mutex_unlock(&tuner_simple_list_mutex);
|
||||
return NULL;
|
||||
break;
|
||||
case 1:
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
|
@ -1216,6 +1216,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
|
||||
|
||||
static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
|
||||
{ 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
|
||||
{ 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
|
||||
{ 16 * 999.99 , 0x8e, 0x04, },
|
||||
};
|
||||
|
||||
static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
|
||||
{
|
||||
.type = TUNER_PARAM_TYPE_NTSC,
|
||||
.ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
|
||||
.count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
|
||||
.cb_first_if_lower_freq = 1,
|
||||
},
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct tunertype tuners[] = {
|
||||
@ -1641,6 +1658,11 @@ struct tunertype tuners[] = {
|
||||
.name = "Xceive 5000 tuner",
|
||||
/* see xc5000.c for details */
|
||||
},
|
||||
[TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
|
||||
.name = "TCL tuner MF02GIP-5N-E",
|
||||
.params = tuner_tcl_mf02gip_5n_params,
|
||||
.count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(tuners);
|
||||
|
||||
|
@ -71,9 +71,6 @@ struct firmware_properties {
|
||||
struct xc2028_data {
|
||||
struct list_head hybrid_tuner_instance_list;
|
||||
struct tuner_i2c_props i2c_props;
|
||||
int (*tuner_callback) (void *dev,
|
||||
int command, int arg);
|
||||
void *video_dev;
|
||||
__u32 frequency;
|
||||
|
||||
struct firmware_description *firm;
|
||||
@ -492,6 +489,23 @@ ret:
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
|
||||
{
|
||||
struct xc2028_data *priv = fe->tuner_priv;
|
||||
|
||||
/* analog side (tuner-core) uses i2c_adap->algo_data.
|
||||
* digital side is not guaranteed to have algo_data defined.
|
||||
*
|
||||
* digital side will always have fe->dvb defined.
|
||||
* analog side (tuner-core) doesn't (yet) define fe->dvb.
|
||||
*/
|
||||
|
||||
return (!fe->callback) ? -EINVAL :
|
||||
fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
|
||||
fe->dvb->priv : priv->i2c_props.adap->algo_data,
|
||||
DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
|
||||
}
|
||||
|
||||
static int load_firmware(struct dvb_frontend *fe, unsigned int type,
|
||||
v4l2_std_id *id)
|
||||
{
|
||||
@ -530,8 +544,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
|
||||
|
||||
if (!size) {
|
||||
/* Special callback command received */
|
||||
rc = priv->tuner_callback(priv->video_dev,
|
||||
XC2028_TUNER_RESET, 0);
|
||||
rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
|
||||
if (rc < 0) {
|
||||
tuner_err("Error at RESET code %d\n",
|
||||
(*p) & 0x7f);
|
||||
@ -542,8 +555,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
|
||||
if (size >= 0xff00) {
|
||||
switch (size) {
|
||||
case 0xff00:
|
||||
rc = priv->tuner_callback(priv->video_dev,
|
||||
XC2028_RESET_CLK, 0);
|
||||
rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
|
||||
if (rc < 0) {
|
||||
tuner_err("Error at RESET code %d\n",
|
||||
(*p) & 0x7f);
|
||||
@ -715,8 +727,7 @@ retry:
|
||||
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
|
||||
|
||||
/* Reset is needed before loading firmware */
|
||||
rc = priv->tuner_callback(priv->video_dev,
|
||||
XC2028_TUNER_RESET, 0);
|
||||
rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
@ -933,7 +944,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
|
||||
The reset CLK is needed only with tm6000.
|
||||
Driver should work fine even if this fails.
|
||||
*/
|
||||
priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
|
||||
do_tuner_callback(fe, XC2028_RESET_CLK, 1);
|
||||
|
||||
msleep(10);
|
||||
|
||||
@ -1002,11 +1013,6 @@ static int xc2028_set_params(struct dvb_frontend *fe,
|
||||
|
||||
tuner_dbg("%s called\n", __func__);
|
||||
|
||||
if (priv->ctrl.d2633)
|
||||
type |= D2633;
|
||||
else
|
||||
type |= D2620;
|
||||
|
||||
switch(fe->ops.info.type) {
|
||||
case FE_OFDM:
|
||||
bw = p->u.ofdm.bandwidth;
|
||||
@ -1021,10 +1027,8 @@ static int xc2028_set_params(struct dvb_frontend *fe,
|
||||
break;
|
||||
case FE_ATSC:
|
||||
bw = BANDWIDTH_6_MHZ;
|
||||
/* The only ATSC firmware (at least on v2.7) is D2633,
|
||||
so overrides ctrl->d2633 */
|
||||
type |= ATSC| D2633;
|
||||
type &= ~D2620;
|
||||
/* The only ATSC firmware (at least on v2.7) is D2633 */
|
||||
type |= ATSC | D2633;
|
||||
break;
|
||||
/* DVB-S is not supported */
|
||||
default:
|
||||
@ -1057,6 +1061,28 @@ static int xc2028_set_params(struct dvb_frontend *fe,
|
||||
tuner_err("error: bandwidth not supported.\n");
|
||||
};
|
||||
|
||||
/*
|
||||
Selects between D2633 or D2620 firmware.
|
||||
It doesn't make sense for ATSC, since it should be D2633 on all cases
|
||||
*/
|
||||
if (fe->ops.info.type != FE_ATSC) {
|
||||
switch (priv->ctrl.type) {
|
||||
case XC2028_D2633:
|
||||
type |= D2633;
|
||||
break;
|
||||
case XC2028_D2620:
|
||||
type |= D2620;
|
||||
break;
|
||||
case XC2028_AUTO:
|
||||
default:
|
||||
/* Zarlink seems to need D2633 */
|
||||
if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
|
||||
type |= D2633;
|
||||
else
|
||||
type |= D2620;
|
||||
}
|
||||
}
|
||||
|
||||
/* All S-code tables need a 200kHz shift */
|
||||
if (priv->ctrl.demod)
|
||||
demod = priv->ctrl.demod + 200;
|
||||
@ -1177,20 +1203,10 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
|
||||
break;
|
||||
case 1:
|
||||
/* new tuner instance */
|
||||
priv->tuner_callback = cfg->callback;
|
||||
priv->ctrl.max_len = 13;
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
/* analog side (tuner-core) uses i2c_adap->algo_data.
|
||||
* digital side is not guaranteed to have algo_data defined.
|
||||
*
|
||||
* digital side will always have fe->dvb defined.
|
||||
* analog side (tuner-core) doesn't (yet) define fe->dvb.
|
||||
*/
|
||||
priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
|
||||
fe->dvb->priv : cfg->i2c_adap->algo_data;
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
break;
|
||||
case 2:
|
||||
|
@ -24,24 +24,28 @@
|
||||
#define XC3028_FE_ZARLINK456 4560
|
||||
#define XC3028_FE_CHINA 5200
|
||||
|
||||
enum firmware_type {
|
||||
XC2028_AUTO = 0, /* By default, auto-detects */
|
||||
XC2028_D2633,
|
||||
XC2028_D2620,
|
||||
};
|
||||
|
||||
struct xc2028_ctrl {
|
||||
char *fname;
|
||||
int max_len;
|
||||
unsigned int scode_table;
|
||||
unsigned int mts :1;
|
||||
unsigned int d2633 :1;
|
||||
unsigned int input1:1;
|
||||
unsigned int vhfbw7:1;
|
||||
unsigned int uhfbw8:1;
|
||||
unsigned int demod;
|
||||
enum firmware_type type:2;
|
||||
};
|
||||
|
||||
struct xc2028_config {
|
||||
struct i2c_adapter *i2c_adap;
|
||||
u8 i2c_addr;
|
||||
void *video_dev;
|
||||
struct xc2028_ctrl *ctrl;
|
||||
int (*callback) (void *dev, int command, int arg);
|
||||
};
|
||||
|
||||
/* xc2028 commands for callback */
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "xc5000.h"
|
||||
#include "xc5000_priv.h"
|
||||
#include "tuner-i2c.h"
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
@ -40,12 +40,26 @@ 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);
|
||||
|
||||
#define dprintk(level,fmt, arg...) if (debug >= level) \
|
||||
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
|
||||
|
||||
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
|
||||
#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
|
||||
|
||||
struct xc5000_priv {
|
||||
struct tuner_i2c_props i2c_props;
|
||||
struct list_head hybrid_tuner_instance_list;
|
||||
|
||||
u32 if_khz;
|
||||
u32 freq_hz;
|
||||
u32 bandwidth;
|
||||
u8 video_standard;
|
||||
u8 rf_mode;
|
||||
};
|
||||
|
||||
/* Misc Defines */
|
||||
#define MAX_TV_STANDARD 23
|
||||
#define XC_MAX_I2C_WRITE_LENGTH 64
|
||||
@ -216,9 +230,12 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
|
||||
|
||||
dprintk(1, "%s()\n", __func__);
|
||||
|
||||
if (priv->cfg->tuner_callback) {
|
||||
ret = priv->cfg->tuner_callback(priv->devptr,
|
||||
XC5000_TUNER_RESET, 0);
|
||||
if (fe->callback) {
|
||||
ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
|
||||
fe->dvb->priv :
|
||||
priv->i2c_props.adap->algo_data,
|
||||
DVB_FRONTEND_COMPONENT_TUNER,
|
||||
XC5000_TUNER_RESET, 0);
|
||||
if (ret)
|
||||
printk(KERN_ERR "xc5000: reset failed\n");
|
||||
} else
|
||||
@ -509,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
|
||||
u8 buf[2] = { reg >> 8, reg & 0xff };
|
||||
u8 bval[2] = { 0, 0 };
|
||||
struct i2c_msg msg[2] = {
|
||||
{ .addr = priv->cfg->i2c_address,
|
||||
{ .addr = priv->i2c_props.addr,
|
||||
.flags = 0, .buf = &buf[0], .len = 2 },
|
||||
{ .addr = priv->cfg->i2c_address,
|
||||
{ .addr = priv->i2c_props.addr,
|
||||
.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
|
||||
};
|
||||
|
||||
if (i2c_transfer(priv->i2c, msg, 2) != 2) {
|
||||
if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
|
||||
printk(KERN_WARNING "xc5000: I2C read failed\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
@ -526,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
|
||||
|
||||
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
|
||||
{
|
||||
struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
|
||||
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
|
||||
.flags = 0, .buf = buf, .len = len };
|
||||
|
||||
if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
|
||||
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
|
||||
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
|
||||
(int)len);
|
||||
return -EREMOTEIO;
|
||||
@ -539,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
|
||||
|
||||
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
|
||||
{
|
||||
struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
|
||||
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
|
||||
.flags = I2C_M_RD, .buf = buf, .len = len };
|
||||
|
||||
if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
|
||||
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
|
||||
printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
@ -559,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
|
||||
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
|
||||
XC5000_DEFAULT_FIRMWARE);
|
||||
|
||||
ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
|
||||
ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
|
||||
ret = XC_RESULT_RESET_FAILURE;
|
||||
@ -675,10 +692,10 @@ static int xc5000_set_params(struct dvb_frontend *fe,
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
|
||||
ret = xc_set_IF_frequency(priv, priv->if_khz);
|
||||
if (ret != XC_RESULT_SUCCESS) {
|
||||
printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
|
||||
priv->cfg->if_khz);
|
||||
priv->if_khz);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -897,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe)
|
||||
|
||||
static int xc5000_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
|
||||
dprintk(1, "%s()\n", __func__);
|
||||
kfree(fe->tuner_priv);
|
||||
|
||||
mutex_lock(&xc5000_list_mutex);
|
||||
|
||||
if (priv)
|
||||
hybrid_tuner_release_state(priv);
|
||||
|
||||
mutex_unlock(&xc5000_list_mutex);
|
||||
|
||||
fe->tuner_priv = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -924,29 +951,43 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
|
||||
|
||||
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct xc5000_config *cfg, void *devptr)
|
||||
struct xc5000_config *cfg)
|
||||
{
|
||||
struct xc5000_priv *priv = NULL;
|
||||
int instance;
|
||||
u16 id = 0;
|
||||
|
||||
dprintk(1, "%s()\n", __func__);
|
||||
dprintk(1, "%s(%d-%04x)\n", __func__,
|
||||
i2c ? i2c_adapter_id(i2c) : -1,
|
||||
cfg ? cfg->i2c_address : -1);
|
||||
|
||||
priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
mutex_lock(&xc5000_list_mutex);
|
||||
|
||||
priv->cfg = cfg;
|
||||
priv->bandwidth = BANDWIDTH_6_MHZ;
|
||||
priv->i2c = i2c;
|
||||
priv->devptr = devptr;
|
||||
instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
|
||||
hybrid_tuner_instance_list,
|
||||
i2c, cfg->i2c_address, "xc5000");
|
||||
switch (instance) {
|
||||
case 0:
|
||||
goto fail;
|
||||
break;
|
||||
case 1:
|
||||
/* new tuner instance */
|
||||
priv->bandwidth = BANDWIDTH_6_MHZ;
|
||||
priv->if_khz = cfg->if_khz;
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
break;
|
||||
default:
|
||||
/* existing tuner instance */
|
||||
fe->tuner_priv = priv;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if firmware has been loaded. It is possible that another
|
||||
instance of the driver has loaded the firmware.
|
||||
*/
|
||||
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
}
|
||||
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
|
||||
goto fail;
|
||||
|
||||
switch(id) {
|
||||
case XC_PRODUCT_ID_FW_LOADED:
|
||||
@ -967,19 +1008,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
||||
printk(KERN_ERR
|
||||
"xc5000: Device not found at addr 0x%02x (0x%x)\n",
|
||||
cfg->i2c_address, id);
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_unlock(&xc5000_list_mutex);
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
if (xc5000_load_fw_on_attach)
|
||||
xc5000_init(fe);
|
||||
|
||||
return fe;
|
||||
fail:
|
||||
mutex_unlock(&xc5000_list_mutex);
|
||||
|
||||
xc5000_release(fe);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(xc5000_attach);
|
||||
|
||||
|
@ -30,8 +30,6 @@ struct i2c_adapter;
|
||||
struct xc5000_config {
|
||||
u8 i2c_address;
|
||||
u32 if_khz;
|
||||
|
||||
int (*tuner_callback) (void *priv, int command, int arg);
|
||||
};
|
||||
|
||||
/* xc5000 callback command */
|
||||
@ -49,13 +47,11 @@ struct xc5000_config {
|
||||
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct xc5000_config *cfg,
|
||||
void *devptr);
|
||||
struct xc5000_config *cfg);
|
||||
#else
|
||||
static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct xc5000_config *cfg,
|
||||
void *devptr)
|
||||
struct xc5000_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
|
||||
*
|
||||
* Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
|
||||
*
|
||||
* 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 XC5000_PRIV_H
|
||||
#define XC5000_PRIV_H
|
||||
|
||||
struct xc5000_priv {
|
||||
struct xc5000_config *cfg;
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
u32 freq_hz;
|
||||
u32 bandwidth;
|
||||
u8 video_standard;
|
||||
u8 rf_mode;
|
||||
|
||||
void *devptr;
|
||||
};
|
||||
|
||||
#endif
|
@ -20,7 +20,6 @@ comment "Supported USB Adapters"
|
||||
source "drivers/media/dvb/dvb-usb/Kconfig"
|
||||
source "drivers/media/dvb/ttusb-budget/Kconfig"
|
||||
source "drivers/media/dvb/ttusb-dec/Kconfig"
|
||||
source "drivers/media/dvb/cinergyT2/Kconfig"
|
||||
source "drivers/media/dvb/siano/Kconfig"
|
||||
|
||||
comment "Supported FlexCopII (B2C2) Adapters"
|
||||
@ -35,6 +34,10 @@ comment "Supported Pluto2 Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/pluto2/Kconfig"
|
||||
|
||||
comment "Supported SDMC DM1105 Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/dm1105/Kconfig"
|
||||
|
||||
comment "Supported DVB Frontends"
|
||||
depends on DVB_CORE
|
||||
source "drivers/media/dvb/frontends/Kconfig"
|
||||
|
@ -2,4 +2,4 @@
|
||||
# Makefile for the kernel multimedia device drivers.
|
||||
#
|
||||
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
|
||||
|
@ -10,7 +10,7 @@
|
||||
int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
|
||||
{
|
||||
u8 *tcpu;
|
||||
dma_addr_t tdma;
|
||||
dma_addr_t tdma = 0;
|
||||
|
||||
if (size % 2) {
|
||||
err("dma buffersize has to be even.");
|
||||
|
@ -702,7 +702,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
|
||||
}
|
||||
|
||||
if (card->fe == NULL)
|
||||
printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
|
||||
printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
card->bt->dev->vendor,
|
||||
card->bt->dev->device,
|
||||
card->bt->dev->subsystem_vendor,
|
||||
|
@ -1,85 +0,0 @@
|
||||
config DVB_CINERGYT2
|
||||
tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
|
||||
depends on DVB_CORE && USB && INPUT
|
||||
help
|
||||
Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_TUNING
|
||||
bool "sophisticated fine-tuning for CinergyT2 cards"
|
||||
depends on DVB_CINERGYT2
|
||||
help
|
||||
Here you can fine-tune some parameters of the CinergyT2 driver.
|
||||
|
||||
Normally you don't need to touch this, but in exotic setups you
|
||||
may fine-tune your setup and adjust e.g. DMA buffer sizes for
|
||||
a particular application.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_STREAM_URB_COUNT
|
||||
int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default "32"
|
||||
help
|
||||
USB Request Blocks for Highspeed Stream transfers are scheduled in
|
||||
a queue for the Host Controller.
|
||||
|
||||
Usually the default value is a safe choice.
|
||||
|
||||
You may increase this number if you are using this device in a
|
||||
Server Environment with many high-traffic USB Highspeed devices
|
||||
sharing the same USB bus.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_STREAM_BUF_SIZE
|
||||
int "Size of URB Stream Buffers for Highspeed Transfers"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default "512"
|
||||
help
|
||||
Should be a multiple of native buffer size of 512 bytes.
|
||||
Default value is a safe choice.
|
||||
|
||||
You may increase this number if you are using this device in a
|
||||
Server Environment with many high-traffic USB Highspeed devices
|
||||
sharing the same USB bus.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_QUERY_INTERVAL
|
||||
int "Status update interval [milliseconds]"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default "250"
|
||||
help
|
||||
This is the interval for status readouts from the demodulator.
|
||||
You may try lower values if you need more responsive signal quality
|
||||
measurements.
|
||||
|
||||
Please keep in mind that these updates cause traffic on the tuner
|
||||
control bus and thus may or may not affect reception sensitivity.
|
||||
|
||||
The default value should be a safe choice for common applications.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
|
||||
bool "Register the onboard IR Remote Control Receiver as Input Device"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the onboard Infrared Remote
|
||||
Control Receiver as Linux-Input device.
|
||||
|
||||
Right now only the keycode table for the default Remote Control
|
||||
delivered with the device is supported, please see the driver
|
||||
source code to find out how to add support for other controls.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_RC_QUERY_INTERVAL
|
||||
int "Infrared Remote Controller update interval [milliseconds]"
|
||||
depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
|
||||
default "50"
|
||||
help
|
||||
If you have a very fast-repeating remote control you can try lower
|
||||
values, for normal consumer receivers the default value should be
|
||||
a safe choice.
|
||||
|
@ -1,3 +0,0 @@
|
||||
obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
|
File diff suppressed because it is too large
Load Diff
18
drivers/media/dvb/dm1105/Kconfig
Normal file
18
drivers/media/dvb/dm1105/Kconfig
Normal file
@ -0,0 +1,18 @@
|
||||
config DVB_DM1105
|
||||
tristate "SDMC DM1105 based PCI cards"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
select DVB_PLL if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0288 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STB6000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
||||
select DVB_SI21XX if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for cards based on the SDMC DM1105 PCI chip like
|
||||
DvbWorld 2002
|
||||
|
||||
Since these cards have no MPEG decoder onboard, they transmit
|
||||
only compressed MPEG data over the PCI bus, so you need
|
||||
an external software decoder to watch TV on your computer.
|
||||
|
||||
Say Y or M if you own such a device and want to use it.
|
3
drivers/media/dvb/dm1105/Makefile
Normal file
3
drivers/media/dvb/dm1105/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
obj-$(CONFIG_DVB_DM1105) += dm1105.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
|
911
drivers/media/dvb/dm1105/dm1105.c
Normal file
911
drivers/media/dvb/dm1105/dm1105.c
Normal file
@ -0,0 +1,911 @@
|
||||
/*
|
||||
* dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip
|
||||
*
|
||||
* Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
|
||||
*
|
||||
* 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/version.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/input.h>
|
||||
#include <media/ir-common.h>
|
||||
|
||||
#include "demux.h"
|
||||
#include "dmxdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_net.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb-pll.h"
|
||||
|
||||
#include "stv0299.h"
|
||||
#include "stv0288.h"
|
||||
#include "stb6000.h"
|
||||
#include "si21xx.h"
|
||||
#include "cx24116.h"
|
||||
#include "z0194a.h"
|
||||
|
||||
/* ----------------------------------------------- */
|
||||
/*
|
||||
* PCI ID's
|
||||
*/
|
||||
#ifndef PCI_VENDOR_ID_TRIGEM
|
||||
#define PCI_VENDOR_ID_TRIGEM 0x109f
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_DM1105
|
||||
#define PCI_DEVICE_ID_DM1105 0x036f
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_DW2002
|
||||
#define PCI_DEVICE_ID_DW2002 0x2002
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_DW2004
|
||||
#define PCI_DEVICE_ID_DW2004 0x2004
|
||||
#endif
|
||||
/* ----------------------------------------------- */
|
||||
/* sdmc dm1105 registers */
|
||||
|
||||
/* TS Control */
|
||||
#define DM1105_TSCTR 0x00
|
||||
#define DM1105_DTALENTH 0x04
|
||||
|
||||
/* GPIO Interface */
|
||||
#define DM1105_GPIOVAL 0x08
|
||||
#define DM1105_GPIOCTR 0x0c
|
||||
|
||||
/* PID serial number */
|
||||
#define DM1105_PIDN 0x10
|
||||
|
||||
/* Odd-even secret key select */
|
||||
#define DM1105_CWSEL 0x14
|
||||
|
||||
/* Host Command Interface */
|
||||
#define DM1105_HOST_CTR 0x18
|
||||
#define DM1105_HOST_AD 0x1c
|
||||
|
||||
/* PCI Interface */
|
||||
#define DM1105_CR 0x30
|
||||
#define DM1105_RST 0x34
|
||||
#define DM1105_STADR 0x38
|
||||
#define DM1105_RLEN 0x3c
|
||||
#define DM1105_WRP 0x40
|
||||
#define DM1105_INTCNT 0x44
|
||||
#define DM1105_INTMAK 0x48
|
||||
#define DM1105_INTSTS 0x4c
|
||||
|
||||
/* CW Value */
|
||||
#define DM1105_ODD 0x50
|
||||
#define DM1105_EVEN 0x58
|
||||
|
||||
/* PID Value */
|
||||
#define DM1105_PID 0x60
|
||||
|
||||
/* IR Control */
|
||||
#define DM1105_IRCTR 0x64
|
||||
#define DM1105_IRMODE 0x68
|
||||
#define DM1105_SYSTEMCODE 0x6c
|
||||
#define DM1105_IRCODE 0x70
|
||||
|
||||
/* Unknown Values */
|
||||
#define DM1105_ENCRYPT 0x74
|
||||
#define DM1105_VER 0x7c
|
||||
|
||||
/* I2C Interface */
|
||||
#define DM1105_I2CCTR 0x80
|
||||
#define DM1105_I2CSTS 0x81
|
||||
#define DM1105_I2CDAT 0x82
|
||||
#define DM1105_I2C_RA 0x83
|
||||
/* ----------------------------------------------- */
|
||||
/* Interrupt Mask Bits */
|
||||
|
||||
#define INTMAK_TSIRQM 0x01
|
||||
#define INTMAK_HIRQM 0x04
|
||||
#define INTMAK_IRM 0x08
|
||||
#define INTMAK_ALLMASK (INTMAK_TSIRQM | \
|
||||
INTMAK_HIRQM | \
|
||||
INTMAK_IRM)
|
||||
#define INTMAK_NONEMASK 0x00
|
||||
|
||||
/* Interrupt Status Bits */
|
||||
#define INTSTS_TSIRQ 0x01
|
||||
#define INTSTS_HIRQ 0x04
|
||||
#define INTSTS_IR 0x08
|
||||
|
||||
/* IR Control Bits */
|
||||
#define DM1105_IR_EN 0x01
|
||||
#define DM1105_SYS_CHK 0x02
|
||||
#define DM1105_REP_FLG 0x08
|
||||
|
||||
/* EEPROM addr */
|
||||
#define IIC_24C01_addr 0xa0
|
||||
/* Max board count */
|
||||
#define DM1105_MAX 0x04
|
||||
|
||||
#define DRIVER_NAME "dm1105"
|
||||
|
||||
#define DM1105_DMA_PACKETS 47
|
||||
#define DM1105_DMA_PACKET_LENGTH (128*4)
|
||||
#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS)
|
||||
|
||||
/* GPIO's for LNB power control */
|
||||
#define DM1105_LNB_MASK 0x00000000
|
||||
#define DM1105_LNB_13V 0x00010100
|
||||
#define DM1105_LNB_18V 0x00000100
|
||||
|
||||
static int ir_debug;
|
||||
module_param(ir_debug, int, 0644);
|
||||
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static u16 ir_codes_dm1105_nec[128] = {
|
||||
[0x0a] = KEY_Q, /*power*/
|
||||
[0x0c] = KEY_M, /*mute*/
|
||||
[0x11] = KEY_1,
|
||||
[0x12] = KEY_2,
|
||||
[0x13] = KEY_3,
|
||||
[0x14] = KEY_4,
|
||||
[0x15] = KEY_5,
|
||||
[0x16] = KEY_6,
|
||||
[0x17] = KEY_7,
|
||||
[0x18] = KEY_8,
|
||||
[0x19] = KEY_9,
|
||||
[0x10] = KEY_0,
|
||||
[0x1c] = KEY_PAGEUP, /*ch+*/
|
||||
[0x0f] = KEY_PAGEDOWN, /*ch-*/
|
||||
[0x1a] = KEY_O, /*vol+*/
|
||||
[0x0e] = KEY_Z, /*vol-*/
|
||||
[0x04] = KEY_R, /*rec*/
|
||||
[0x09] = KEY_D, /*fav*/
|
||||
[0x08] = KEY_BACKSPACE, /*rewind*/
|
||||
[0x07] = KEY_A, /*fast*/
|
||||
[0x0b] = KEY_P, /*pause*/
|
||||
[0x02] = KEY_ESC, /*cancel*/
|
||||
[0x03] = KEY_G, /*tab*/
|
||||
[0x00] = KEY_UP, /*up*/
|
||||
[0x1f] = KEY_ENTER, /*ok*/
|
||||
[0x01] = KEY_DOWN, /*down*/
|
||||
[0x05] = KEY_C, /*cap*/
|
||||
[0x06] = KEY_S, /*stop*/
|
||||
[0x40] = KEY_F, /*full*/
|
||||
[0x1e] = KEY_W, /*tvmode*/
|
||||
[0x1b] = KEY_B, /*recall*/
|
||||
};
|
||||
|
||||
/* infrared remote control */
|
||||
struct infrared {
|
||||
u16 key_map[128];
|
||||
struct input_dev *input_dev;
|
||||
char input_phys[32];
|
||||
struct tasklet_struct ir_tasklet;
|
||||
u32 ir_command;
|
||||
};
|
||||
|
||||
struct dm1105dvb {
|
||||
/* pci */
|
||||
struct pci_dev *pdev;
|
||||
u8 __iomem *io_mem;
|
||||
|
||||
/* ir */
|
||||
struct infrared ir;
|
||||
|
||||
/* dvb */
|
||||
struct dmx_frontend hw_frontend;
|
||||
struct dmx_frontend mem_frontend;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_adapter dvb_adapter;
|
||||
struct dvb_demux demux;
|
||||
struct dvb_frontend *fe;
|
||||
struct dvb_net dvbnet;
|
||||
unsigned int full_ts_users;
|
||||
|
||||
/* i2c */
|
||||
struct i2c_adapter i2c_adap;
|
||||
|
||||
/* dma */
|
||||
dma_addr_t dma_addr;
|
||||
unsigned char *ts_buf;
|
||||
u32 wrp;
|
||||
u32 buffer_size;
|
||||
unsigned int PacketErrorCount;
|
||||
unsigned int dmarst;
|
||||
spinlock_t lock;
|
||||
|
||||
};
|
||||
|
||||
#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
|
||||
|
||||
static struct dm1105dvb *dm1105dvb_local;
|
||||
|
||||
static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb ;
|
||||
|
||||
int addr, rc, i, j, k, len, byte, data;
|
||||
u8 status;
|
||||
|
||||
dm1105dvb = i2c_adap->algo_data;
|
||||
for (i = 0; i < num; i++) {
|
||||
outb(0x00, dm_io_mem(DM1105_I2CCTR));
|
||||
if (msgs[i].flags & I2C_M_RD) {
|
||||
/* read bytes */
|
||||
addr = msgs[i].addr << 1;
|
||||
addr |= 1;
|
||||
outb(addr, dm_io_mem(DM1105_I2CDAT));
|
||||
for (byte = 0; byte < msgs[i].len; byte++)
|
||||
outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
|
||||
|
||||
outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
|
||||
for (j = 0; j < 55; j++) {
|
||||
mdelay(10);
|
||||
status = inb(dm_io_mem(DM1105_I2CSTS));
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
if (j >= 55)
|
||||
return -1;
|
||||
|
||||
for (byte = 0; byte < msgs[i].len; byte++) {
|
||||
rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
msgs[i].buf[byte] = rc;
|
||||
}
|
||||
} else {
|
||||
if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
|
||||
/* prepaired for cx24116 firmware */
|
||||
/* Write in small blocks */
|
||||
len = msgs[i].len - 1;
|
||||
k = 1;
|
||||
do {
|
||||
outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
|
||||
outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
|
||||
for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
|
||||
data = msgs[i].buf[k+byte];
|
||||
outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
|
||||
}
|
||||
outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
|
||||
for (j = 0; j < 25; j++) {
|
||||
mdelay(10);
|
||||
status = inb(dm_io_mem(DM1105_I2CSTS));
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= 25)
|
||||
return -1;
|
||||
|
||||
k += 48;
|
||||
len -= 48;
|
||||
} while (len > 0);
|
||||
} else {
|
||||
/* write bytes */
|
||||
outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
|
||||
for (byte = 0; byte < msgs[i].len; byte++) {
|
||||
data = msgs[i].buf[byte];
|
||||
outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
|
||||
}
|
||||
outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
|
||||
for (j = 0; j < 25; j++) {
|
||||
mdelay(10);
|
||||
status = inb(dm_io_mem(DM1105_I2CSTS));
|
||||
if ((status & 0xc0) == 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= 25)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u32 functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm dm1105_algo = {
|
||||
.master_xfer = dm1105_i2c_xfer,
|
||||
.functionality = functionality,
|
||||
};
|
||||
|
||||
static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
|
||||
{
|
||||
return container_of(feed->demux, struct dm1105dvb, demux);
|
||||
}
|
||||
|
||||
static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
|
||||
{
|
||||
return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
|
||||
}
|
||||
|
||||
static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
|
||||
|
||||
if (voltage == SEC_VOLTAGE_18) {
|
||||
outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
|
||||
outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
|
||||
} else {
|
||||
/*LNB ON-13V by default!*/
|
||||
outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
|
||||
outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
|
||||
}
|
||||
|
||||
static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
|
||||
outb(1, dm_io_mem(DM1105_CR));
|
||||
}
|
||||
|
||||
static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
|
||||
outb(0, dm_io_mem(DM1105_CR));
|
||||
}
|
||||
|
||||
static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
|
||||
|
||||
if (dm1105dvb->full_ts_users++ == 0)
|
||||
dm1105dvb_enable_irqs(dm1105dvb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
|
||||
|
||||
if (--dm1105dvb->full_ts_users == 0)
|
||||
dm1105dvb_disable_irqs(dm1105dvb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ir tasklet */
|
||||
static void dm1105_emit_key(unsigned long parm)
|
||||
{
|
||||
struct infrared *ir = (struct infrared *) parm;
|
||||
u32 ircom = ir->ir_command;
|
||||
u8 data;
|
||||
u16 keycode;
|
||||
|
||||
data = (ircom >> 8) & 0x7f;
|
||||
|
||||
input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
|
||||
input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
|
||||
keycode = ir->key_map[data];
|
||||
|
||||
if (!keycode)
|
||||
return;
|
||||
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(ir->input_dev);
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 0);
|
||||
input_sync(ir->input_dev);
|
||||
|
||||
}
|
||||
|
||||
static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = dev_id;
|
||||
unsigned int piece;
|
||||
unsigned int nbpackets;
|
||||
u32 command;
|
||||
u32 nextwrp;
|
||||
u32 oldwrp;
|
||||
|
||||
/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
|
||||
unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
|
||||
outb(intsts, dm_io_mem(DM1105_INTSTS));
|
||||
|
||||
switch (intsts) {
|
||||
case INTSTS_TSIRQ:
|
||||
case (INTSTS_TSIRQ | INTSTS_IR):
|
||||
nextwrp = inl(dm_io_mem(DM1105_WRP)) -
|
||||
inl(dm_io_mem(DM1105_STADR)) ;
|
||||
oldwrp = dm1105dvb->wrp;
|
||||
spin_lock(&dm1105dvb->lock);
|
||||
if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
|
||||
(dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
|
||||
(dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
|
||||
dm1105dvb->PacketErrorCount++;
|
||||
/* bad packet found */
|
||||
if ((dm1105dvb->PacketErrorCount >= 2) &&
|
||||
(dm1105dvb->dmarst == 0)) {
|
||||
outb(1, dm_io_mem(DM1105_RST));
|
||||
dm1105dvb->wrp = 0;
|
||||
dm1105dvb->PacketErrorCount = 0;
|
||||
dm1105dvb->dmarst = 0;
|
||||
spin_unlock(&dm1105dvb->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
if (nextwrp < oldwrp) {
|
||||
piece = dm1105dvb->buffer_size - oldwrp;
|
||||
memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
|
||||
nbpackets = (piece + nextwrp)/188;
|
||||
} else {
|
||||
nbpackets = (nextwrp - oldwrp)/188;
|
||||
}
|
||||
dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
|
||||
dm1105dvb->wrp = nextwrp;
|
||||
spin_unlock(&dm1105dvb->lock);
|
||||
break;
|
||||
case INTSTS_IR:
|
||||
command = inl(dm_io_mem(DM1105_IRCODE));
|
||||
if (ir_debug)
|
||||
printk("dm1105: received byte 0x%04x\n", command);
|
||||
|
||||
dm1105dvb->ir.ir_command = command;
|
||||
tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
|
||||
break;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* register with input layer */
|
||||
static void input_register_keys(struct infrared *ir)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ir->key_map); i++)
|
||||
set_bit(ir->key_map[i], ir->input_dev->keybit);
|
||||
|
||||
ir->input_dev->keycode = ir->key_map;
|
||||
ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
|
||||
ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
|
||||
}
|
||||
|
||||
int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
int err;
|
||||
|
||||
dm1105dvb_local = dm1105;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dm1105->ir.input_dev = input_dev;
|
||||
snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
|
||||
"pci-%s/ir0", pci_name(dm1105->pdev));
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY);
|
||||
input_dev->name = "DVB on-card IR receiver";
|
||||
|
||||
input_dev->phys = dm1105->ir.input_phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
input_dev->id.version = 2;
|
||||
if (dm1105->pdev->subsystem_vendor) {
|
||||
input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
|
||||
input_dev->id.product = dm1105->pdev->subsystem_device;
|
||||
} else {
|
||||
input_dev->id.vendor = dm1105->pdev->vendor;
|
||||
input_dev->id.product = dm1105->pdev->device;
|
||||
}
|
||||
input_dev->dev.parent = &dm1105->pdev->dev;
|
||||
/* initial keymap */
|
||||
memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map);
|
||||
input_register_keys(&dm1105->ir);
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
|
||||
{
|
||||
tasklet_kill(&dm1105->ir.ir_tasklet);
|
||||
input_unregister_device(dm1105->ir.input_dev);
|
||||
|
||||
}
|
||||
|
||||
static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
dm1105dvb_disable_irqs(dm1105dvb);
|
||||
|
||||
outb(0, dm_io_mem(DM1105_HOST_CTR));
|
||||
|
||||
/*DATALEN 188,*/
|
||||
outb(188, dm_io_mem(DM1105_DTALENTH));
|
||||
/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
|
||||
outw(0xc10a, dm_io_mem(DM1105_TSCTR));
|
||||
|
||||
/* map DMA and set address */
|
||||
dm1105dvb_dma_map(dm1105dvb);
|
||||
dm1105dvb_set_dma_addr(dm1105dvb);
|
||||
/* big buffer */
|
||||
outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
|
||||
outb(47, dm_io_mem(DM1105_INTCNT));
|
||||
|
||||
/* IR NEC mode enable */
|
||||
outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
|
||||
outb(0, dm_io_mem(DM1105_IRMODE));
|
||||
outw(0, dm_io_mem(DM1105_SYSTEMCODE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
dm1105dvb_disable_irqs(dm1105dvb);
|
||||
|
||||
/* IR disable */
|
||||
outb(0, dm_io_mem(DM1105_IRCTR));
|
||||
outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
|
||||
|
||||
dm1105dvb_dma_unmap(dm1105dvb);
|
||||
}
|
||||
|
||||
static struct stv0288_config earda_config = {
|
||||
.demod_address = 0x68,
|
||||
.min_delay_ms = 100,
|
||||
};
|
||||
|
||||
static struct si21xx_config serit_config = {
|
||||
.demod_address = 0x68,
|
||||
.min_delay_ms = 100,
|
||||
|
||||
};
|
||||
|
||||
static struct cx24116_config serit_sp2633_config = {
|
||||
.demod_address = 0x55,
|
||||
};
|
||||
|
||||
static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (dm1105dvb->pdev->subsystem_device) {
|
||||
case PCI_DEVICE_ID_DW2002:
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
stv0299_attach, &sharp_z0194a_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
|
||||
if (dm1105dvb->fe) {
|
||||
dm1105dvb->fe->ops.set_voltage =
|
||||
dm1105dvb_set_voltage;
|
||||
dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
|
||||
&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
|
||||
}
|
||||
|
||||
if (!dm1105dvb->fe) {
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
stv0288_attach, &earda_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe) {
|
||||
dm1105dvb->fe->ops.set_voltage =
|
||||
dm1105dvb_set_voltage;
|
||||
dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
|
||||
&dm1105dvb->i2c_adap);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm1105dvb->fe) {
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
si21xx_attach, &serit_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe)
|
||||
dm1105dvb->fe->ops.set_voltage =
|
||||
dm1105dvb_set_voltage;
|
||||
}
|
||||
break;
|
||||
case PCI_DEVICE_ID_DW2004:
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
cx24116_attach, &serit_sp2633_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
if (dm1105dvb->fe)
|
||||
dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dm1105dvb->fe) {
|
||||
dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
|
||||
if (ret < 0) {
|
||||
if (dm1105dvb->fe->ops.release)
|
||||
dm1105dvb->fe->ops.release(dm1105dvb->fe);
|
||||
dm1105dvb->fe = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
|
||||
{
|
||||
static u8 command[1] = { 0x28 };
|
||||
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = IIC_24C01_addr >> 1, .flags = 0,
|
||||
.buf = command, .len = 1 },
|
||||
{ .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
|
||||
.buf = mac, .len = 6 },
|
||||
};
|
||||
|
||||
dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
|
||||
dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
static int __devinit dm1105_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb;
|
||||
struct dvb_adapter *dvb_adapter;
|
||||
struct dvb_demux *dvbdemux;
|
||||
struct dmx_demux *dmx;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
|
||||
if (!dm1105dvb)
|
||||
goto out;
|
||||
|
||||
dm1105dvb->pdev = pdev;
|
||||
dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
|
||||
dm1105dvb->PacketErrorCount = 0;
|
||||
dm1105dvb->dmarst = 0;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret < 0)
|
||||
goto err_kfree;
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (ret < 0)
|
||||
goto err_pci_disable_device;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = pci_request_regions(pdev, DRIVER_NAME);
|
||||
if (ret < 0)
|
||||
goto err_pci_disable_device;
|
||||
|
||||
dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
if (!dm1105dvb->io_mem) {
|
||||
ret = -EIO;
|
||||
goto err_pci_release_regions;
|
||||
}
|
||||
|
||||
spin_lock_init(&dm1105dvb->lock);
|
||||
pci_set_drvdata(pdev, dm1105dvb);
|
||||
|
||||
ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
|
||||
if (ret < 0)
|
||||
goto err_pci_iounmap;
|
||||
|
||||
ret = dm1105dvb_hw_init(dm1105dvb);
|
||||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
|
||||
/* i2c */
|
||||
i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
|
||||
strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
|
||||
dm1105dvb->i2c_adap.owner = THIS_MODULE;
|
||||
dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
|
||||
dm1105dvb->i2c_adap.algo = &dm1105_algo;
|
||||
dm1105dvb->i2c_adap.algo_data = dm1105dvb;
|
||||
ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_dm1105dvb_hw_exit;
|
||||
|
||||
/* dvb */
|
||||
ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
|
||||
THIS_MODULE, &pdev->dev, adapter_nr);
|
||||
if (ret < 0)
|
||||
goto err_i2c_del_adapter;
|
||||
|
||||
dvb_adapter = &dm1105dvb->dvb_adapter;
|
||||
|
||||
dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
|
||||
|
||||
dvbdemux = &dm1105dvb->demux;
|
||||
dvbdemux->filternum = 256;
|
||||
dvbdemux->feednum = 256;
|
||||
dvbdemux->start_feed = dm1105dvb_start_feed;
|
||||
dvbdemux->stop_feed = dm1105dvb_stop_feed;
|
||||
dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
|
||||
DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
|
||||
ret = dvb_dmx_init(dvbdemux);
|
||||
if (ret < 0)
|
||||
goto err_dvb_unregister_adapter;
|
||||
|
||||
dmx = &dvbdemux->dmx;
|
||||
dm1105dvb->dmxdev.filternum = 256;
|
||||
dm1105dvb->dmxdev.demux = dmx;
|
||||
dm1105dvb->dmxdev.capabilities = 0;
|
||||
|
||||
ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
|
||||
if (ret < 0)
|
||||
goto err_dvb_dmx_release;
|
||||
|
||||
dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
|
||||
|
||||
ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
if (ret < 0)
|
||||
goto err_dvb_dmxdev_release;
|
||||
|
||||
dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
|
||||
|
||||
ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
|
||||
if (ret < 0)
|
||||
goto err_remove_hw_frontend;
|
||||
|
||||
ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
if (ret < 0)
|
||||
goto err_remove_mem_frontend;
|
||||
|
||||
ret = frontend_init(dm1105dvb);
|
||||
if (ret < 0)
|
||||
goto err_disconnect_frontend;
|
||||
|
||||
dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
|
||||
dm1105_ir_init(dm1105dvb);
|
||||
out:
|
||||
return ret;
|
||||
|
||||
err_disconnect_frontend:
|
||||
dmx->disconnect_frontend(dmx);
|
||||
err_remove_mem_frontend:
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
|
||||
err_remove_hw_frontend:
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
err_dvb_dmxdev_release:
|
||||
dvb_dmxdev_release(&dm1105dvb->dmxdev);
|
||||
err_dvb_dmx_release:
|
||||
dvb_dmx_release(dvbdemux);
|
||||
err_dvb_unregister_adapter:
|
||||
dvb_unregister_adapter(dvb_adapter);
|
||||
err_i2c_del_adapter:
|
||||
i2c_del_adapter(&dm1105dvb->i2c_adap);
|
||||
err_dm1105dvb_hw_exit:
|
||||
dm1105dvb_hw_exit(dm1105dvb);
|
||||
err_free_irq:
|
||||
free_irq(pdev->irq, dm1105dvb);
|
||||
err_pci_iounmap:
|
||||
pci_iounmap(pdev, dm1105dvb->io_mem);
|
||||
err_pci_release_regions:
|
||||
pci_release_regions(pdev);
|
||||
err_pci_disable_device:
|
||||
pci_disable_device(pdev);
|
||||
err_kfree:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(dm1105dvb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void __devexit dm1105_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
|
||||
struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
|
||||
struct dvb_demux *dvbdemux = &dm1105dvb->demux;
|
||||
struct dmx_demux *dmx = &dvbdemux->dmx;
|
||||
|
||||
dm1105_ir_exit(dm1105dvb);
|
||||
dmx->close(dmx);
|
||||
dvb_net_release(&dm1105dvb->dvbnet);
|
||||
if (dm1105dvb->fe)
|
||||
dvb_unregister_frontend(dm1105dvb->fe);
|
||||
|
||||
dmx->disconnect_frontend(dmx);
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
|
||||
dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
|
||||
dvb_dmxdev_release(&dm1105dvb->dmxdev);
|
||||
dvb_dmx_release(dvbdemux);
|
||||
dvb_unregister_adapter(dvb_adapter);
|
||||
if (&dm1105dvb->i2c_adap)
|
||||
i2c_del_adapter(&dm1105dvb->i2c_adap);
|
||||
|
||||
dm1105dvb_hw_exit(dm1105dvb);
|
||||
synchronize_irq(pdev->irq);
|
||||
free_irq(pdev->irq, dm1105dvb);
|
||||
pci_iounmap(pdev, dm1105dvb->io_mem);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(dm1105dvb);
|
||||
}
|
||||
|
||||
static struct pci_device_id dm1105_id_table[] __devinitdata = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_TRIGEM,
|
||||
.device = PCI_DEVICE_ID_DM1105,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_DEVICE_ID_DW2002,
|
||||
}, {
|
||||
.vendor = PCI_VENDOR_ID_TRIGEM,
|
||||
.device = PCI_DEVICE_ID_DM1105,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_DEVICE_ID_DW2004,
|
||||
}, {
|
||||
/* empty */
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, dm1105_id_table);
|
||||
|
||||
static struct pci_driver dm1105_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = dm1105_id_table,
|
||||
.probe = dm1105_probe,
|
||||
.remove = __devexit_p(dm1105_remove),
|
||||
};
|
||||
|
||||
static int __init dm1105_init(void)
|
||||
{
|
||||
return pci_register_driver(&dm1105_driver);
|
||||
}
|
||||
|
||||
static void __exit dm1105_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&dm1105_driver);
|
||||
}
|
||||
|
||||
module_init(dm1105_init);
|
||||
module_exit(dm1105_exit);
|
||||
|
||||
MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
|
||||
MODULE_DESCRIPTION("SDMC DM1105 DVB driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvbdev.h"
|
||||
#include <linux/dvb/version.h>
|
||||
|
||||
static int dvb_frontend_debug;
|
||||
static int dvb_shutdown_timeout;
|
||||
@ -755,6 +756,539 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dtv_cmds_h dtv_cmds[] = {
|
||||
[DTV_TUNE] = {
|
||||
.name = "DTV_TUNE",
|
||||
.cmd = DTV_TUNE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_CLEAR] = {
|
||||
.name = "DTV_CLEAR",
|
||||
.cmd = DTV_CLEAR,
|
||||
.set = 1,
|
||||
},
|
||||
|
||||
/* Set */
|
||||
[DTV_FREQUENCY] = {
|
||||
.name = "DTV_FREQUENCY",
|
||||
.cmd = DTV_FREQUENCY,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_BANDWIDTH_HZ] = {
|
||||
.name = "DTV_BANDWIDTH_HZ",
|
||||
.cmd = DTV_BANDWIDTH_HZ,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_MODULATION] = {
|
||||
.name = "DTV_MODULATION",
|
||||
.cmd = DTV_MODULATION,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_INVERSION] = {
|
||||
.name = "DTV_INVERSION",
|
||||
.cmd = DTV_INVERSION,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_DISEQC_MASTER] = {
|
||||
.name = "DTV_DISEQC_MASTER",
|
||||
.cmd = DTV_DISEQC_MASTER,
|
||||
.set = 1,
|
||||
.buffer = 1,
|
||||
},
|
||||
[DTV_SYMBOL_RATE] = {
|
||||
.name = "DTV_SYMBOL_RATE",
|
||||
.cmd = DTV_SYMBOL_RATE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_INNER_FEC] = {
|
||||
.name = "DTV_INNER_FEC",
|
||||
.cmd = DTV_INNER_FEC,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_VOLTAGE] = {
|
||||
.name = "DTV_VOLTAGE",
|
||||
.cmd = DTV_VOLTAGE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_TONE] = {
|
||||
.name = "DTV_TONE",
|
||||
.cmd = DTV_TONE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_PILOT] = {
|
||||
.name = "DTV_PILOT",
|
||||
.cmd = DTV_PILOT,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_ROLLOFF] = {
|
||||
.name = "DTV_ROLLOFF",
|
||||
.cmd = DTV_ROLLOFF,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_DELIVERY_SYSTEM] = {
|
||||
.name = "DTV_DELIVERY_SYSTEM",
|
||||
.cmd = DTV_DELIVERY_SYSTEM,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_HIERARCHY] = {
|
||||
.name = "DTV_HIERARCHY",
|
||||
.cmd = DTV_HIERARCHY,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_CODE_RATE_HP] = {
|
||||
.name = "DTV_CODE_RATE_HP",
|
||||
.cmd = DTV_CODE_RATE_HP,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_CODE_RATE_LP] = {
|
||||
.name = "DTV_CODE_RATE_LP",
|
||||
.cmd = DTV_CODE_RATE_LP,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_GUARD_INTERVAL] = {
|
||||
.name = "DTV_GUARD_INTERVAL",
|
||||
.cmd = DTV_GUARD_INTERVAL,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_TRANSMISSION_MODE] = {
|
||||
.name = "DTV_TRANSMISSION_MODE",
|
||||
.cmd = DTV_TRANSMISSION_MODE,
|
||||
.set = 1,
|
||||
},
|
||||
/* Get */
|
||||
[DTV_DISEQC_SLAVE_REPLY] = {
|
||||
.name = "DTV_DISEQC_SLAVE_REPLY",
|
||||
.cmd = DTV_DISEQC_SLAVE_REPLY,
|
||||
.set = 0,
|
||||
.buffer = 1,
|
||||
},
|
||||
[DTV_API_VERSION] = {
|
||||
.name = "DTV_API_VERSION",
|
||||
.cmd = DTV_API_VERSION,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_CODE_RATE_HP] = {
|
||||
.name = "DTV_CODE_RATE_HP",
|
||||
.cmd = DTV_CODE_RATE_HP,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_CODE_RATE_LP] = {
|
||||
.name = "DTV_CODE_RATE_LP",
|
||||
.cmd = DTV_CODE_RATE_LP,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_GUARD_INTERVAL] = {
|
||||
.name = "DTV_GUARD_INTERVAL",
|
||||
.cmd = DTV_GUARD_INTERVAL,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_TRANSMISSION_MODE] = {
|
||||
.name = "DTV_TRANSMISSION_MODE",
|
||||
.cmd = DTV_TRANSMISSION_MODE,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_HIERARCHY] = {
|
||||
.name = "DTV_HIERARCHY",
|
||||
.cmd = DTV_HIERARCHY,
|
||||
.set = 0,
|
||||
},
|
||||
};
|
||||
|
||||
void dtv_property_dump(struct dtv_property *tvp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
|
||||
printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n",
|
||||
__func__, tvp->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("%s() tvp.cmd = 0x%08x (%s)\n"
|
||||
,__FUNCTION__
|
||||
,tvp->cmd
|
||||
,dtv_cmds[ tvp->cmd ].name);
|
||||
|
||||
if(dtv_cmds[ tvp->cmd ].buffer) {
|
||||
|
||||
printk("%s() tvp.u.buffer.len = 0x%02x\n"
|
||||
,__FUNCTION__
|
||||
,tvp->u.buffer.len);
|
||||
|
||||
for(i = 0; i < tvp->u.buffer.len; i++)
|
||||
printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
|
||||
,__FUNCTION__
|
||||
,i
|
||||
,tvp->u.buffer.data[i]);
|
||||
|
||||
} else
|
||||
printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
|
||||
}
|
||||
|
||||
int is_legacy_delivery_system(fe_delivery_system_t s)
|
||||
{
|
||||
if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
|
||||
(s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Synchronise the legacy tuning parameters into the cache, so that demodulator
|
||||
* drivers can use a single set_frontend tuning function, regardless of whether
|
||||
* it's being used for the legacy or new API, reducing code and complexity.
|
||||
*/
|
||||
void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
printk("%s()\n", __FUNCTION__);
|
||||
|
||||
c->frequency = p->frequency;
|
||||
c->inversion = p->inversion;
|
||||
|
||||
switch (fe->ops.info.type) {
|
||||
case FE_QPSK:
|
||||
c->modulation = QPSK; /* implied for DVB-S in legacy API */
|
||||
c->rolloff = ROLLOFF_35;/* implied for DVB-S */
|
||||
c->symbol_rate = p->u.qpsk.symbol_rate;
|
||||
c->fec_inner = p->u.qpsk.fec_inner;
|
||||
c->delivery_system = SYS_DVBS;
|
||||
break;
|
||||
case FE_QAM:
|
||||
c->symbol_rate = p->u.qam.symbol_rate;
|
||||
c->fec_inner = p->u.qam.fec_inner;
|
||||
c->modulation = p->u.qam.modulation;
|
||||
c->delivery_system = SYS_DVBC_ANNEX_AC;
|
||||
break;
|
||||
case FE_OFDM:
|
||||
if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
|
||||
c->bandwidth_hz = 6000000;
|
||||
else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
|
||||
c->bandwidth_hz = 7000000;
|
||||
else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
|
||||
c->bandwidth_hz = 8000000;
|
||||
else
|
||||
/* Including BANDWIDTH_AUTO */
|
||||
c->bandwidth_hz = 0;
|
||||
c->code_rate_HP = p->u.ofdm.code_rate_HP;
|
||||
c->code_rate_LP = p->u.ofdm.code_rate_LP;
|
||||
c->modulation = p->u.ofdm.constellation;
|
||||
c->transmission_mode = p->u.ofdm.transmission_mode;
|
||||
c->guard_interval = p->u.ofdm.guard_interval;
|
||||
c->hierarchy = p->u.ofdm.hierarchy_information;
|
||||
c->delivery_system = SYS_DVBT;
|
||||
break;
|
||||
case FE_ATSC:
|
||||
c->modulation = p->u.vsb.modulation;
|
||||
if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
|
||||
c->delivery_system = SYS_ATSC;
|
||||
else
|
||||
c->delivery_system = SYS_DVBC_ANNEX_B;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure the cached values are set correctly in the frontend
|
||||
* legacy tuning structures, for the advanced tuning API.
|
||||
*/
|
||||
void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dvb_frontend_parameters *p = &fepriv->parameters;
|
||||
|
||||
printk("%s()\n", __FUNCTION__);
|
||||
|
||||
p->frequency = c->frequency;
|
||||
p->inversion = c->inversion;
|
||||
|
||||
switch (fe->ops.info.type) {
|
||||
case FE_QPSK:
|
||||
printk("%s() Preparing QPSK req\n", __FUNCTION__);
|
||||
p->u.qpsk.symbol_rate = c->symbol_rate;
|
||||
p->u.qpsk.fec_inner = c->fec_inner;
|
||||
c->delivery_system = SYS_DVBS;
|
||||
break;
|
||||
case FE_QAM:
|
||||
printk("%s() Preparing QAM req\n", __FUNCTION__);
|
||||
p->u.qam.symbol_rate = c->symbol_rate;
|
||||
p->u.qam.fec_inner = c->fec_inner;
|
||||
p->u.qam.modulation = c->modulation;
|
||||
c->delivery_system = SYS_DVBC_ANNEX_AC;
|
||||
break;
|
||||
case FE_OFDM:
|
||||
printk("%s() Preparing OFDM req\n", __FUNCTION__);
|
||||
if (c->bandwidth_hz == 6000000)
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
|
||||
else if (c->bandwidth_hz == 7000000)
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
|
||||
else if (c->bandwidth_hz == 8000000)
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
|
||||
else
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
|
||||
p->u.ofdm.code_rate_HP = c->code_rate_HP;
|
||||
p->u.ofdm.code_rate_LP = c->code_rate_LP;
|
||||
p->u.ofdm.constellation = c->modulation;
|
||||
p->u.ofdm.transmission_mode = c->transmission_mode;
|
||||
p->u.ofdm.guard_interval = c->guard_interval;
|
||||
p->u.ofdm.hierarchy_information = c->hierarchy;
|
||||
c->delivery_system = SYS_DVBT;
|
||||
break;
|
||||
case FE_ATSC:
|
||||
printk("%s() Preparing VSB req\n", __FUNCTION__);
|
||||
p->u.vsb.modulation = c->modulation;
|
||||
if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
|
||||
c->delivery_system = SYS_ATSC;
|
||||
else
|
||||
c->delivery_system = SYS_DVBC_ANNEX_B;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure the cached values are set correctly in the frontend
|
||||
* legacy tuning structures, for the legacy tuning API.
|
||||
*/
|
||||
void dtv_property_adv_params_sync(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dvb_frontend_parameters *p = &fepriv->parameters;
|
||||
|
||||
printk("%s()\n", __FUNCTION__);
|
||||
|
||||
p->frequency = c->frequency;
|
||||
p->inversion = c->inversion;
|
||||
|
||||
switch(c->modulation) {
|
||||
case PSK_8:
|
||||
case APSK_16:
|
||||
case QPSK:
|
||||
p->u.qpsk.symbol_rate = c->symbol_rate;
|
||||
p->u.qpsk.fec_inner = c->fec_inner;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(c->delivery_system == SYS_ISDBT) {
|
||||
/* Fake out a generic DVB-T request so we pass validation in the ioctl */
|
||||
p->frequency = c->frequency;
|
||||
p->inversion = INVERSION_AUTO;
|
||||
p->u.ofdm.constellation = QAM_AUTO;
|
||||
p->u.ofdm.code_rate_HP = FEC_AUTO;
|
||||
p->u.ofdm.code_rate_LP = FEC_AUTO;
|
||||
p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
|
||||
p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
|
||||
p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
void dtv_property_cache_submit(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
printk("%s()\n", __FUNCTION__);
|
||||
|
||||
/* For legacy delivery systems we don't need the delivery_system to
|
||||
* be specified, but we populate the older structures from the cache
|
||||
* so we can call set_frontend on older drivers.
|
||||
*/
|
||||
if(is_legacy_delivery_system(c->delivery_system)) {
|
||||
|
||||
printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
|
||||
dtv_property_legacy_params_sync(fe);
|
||||
|
||||
} else {
|
||||
printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
|
||||
|
||||
/* For advanced delivery systems / modulation types ...
|
||||
* we seed the lecacy dvb_frontend_parameters structure
|
||||
* so that the sanity checking code later in the IOCTL processing
|
||||
* can validate our basic frequency ranges, symbolrates, modulation
|
||||
* etc.
|
||||
*/
|
||||
dtv_property_adv_params_sync(fe);
|
||||
}
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg);
|
||||
static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg);
|
||||
|
||||
int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
|
||||
struct inode *inode, struct file *file)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
printk("%s()\n", __FUNCTION__);
|
||||
|
||||
dtv_property_dump(tvp);
|
||||
|
||||
/* Allow the frontend to validate incoming properties */
|
||||
if (fe->ops.get_property)
|
||||
r = fe->ops.get_property(fe, tvp);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch(tvp->cmd) {
|
||||
case DTV_FREQUENCY:
|
||||
tvp->u.data = fe->dtv_property_cache.frequency;
|
||||
break;
|
||||
case DTV_MODULATION:
|
||||
tvp->u.data = fe->dtv_property_cache.modulation;
|
||||
break;
|
||||
case DTV_BANDWIDTH_HZ:
|
||||
tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
|
||||
break;
|
||||
case DTV_INVERSION:
|
||||
tvp->u.data = fe->dtv_property_cache.inversion;
|
||||
break;
|
||||
case DTV_SYMBOL_RATE:
|
||||
tvp->u.data = fe->dtv_property_cache.symbol_rate;
|
||||
break;
|
||||
case DTV_INNER_FEC:
|
||||
tvp->u.data = fe->dtv_property_cache.fec_inner;
|
||||
break;
|
||||
case DTV_PILOT:
|
||||
tvp->u.data = fe->dtv_property_cache.pilot;
|
||||
break;
|
||||
case DTV_ROLLOFF:
|
||||
tvp->u.data = fe->dtv_property_cache.rolloff;
|
||||
break;
|
||||
case DTV_DELIVERY_SYSTEM:
|
||||
tvp->u.data = fe->dtv_property_cache.delivery_system;
|
||||
break;
|
||||
case DTV_VOLTAGE:
|
||||
tvp->u.data = fe->dtv_property_cache.voltage;
|
||||
break;
|
||||
case DTV_TONE:
|
||||
tvp->u.data = fe->dtv_property_cache.sectone;
|
||||
break;
|
||||
case DTV_API_VERSION:
|
||||
tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
|
||||
break;
|
||||
case DTV_CODE_RATE_HP:
|
||||
tvp->u.data = fe->dtv_property_cache.code_rate_HP;
|
||||
break;
|
||||
case DTV_CODE_RATE_LP:
|
||||
tvp->u.data = fe->dtv_property_cache.code_rate_LP;
|
||||
break;
|
||||
case DTV_GUARD_INTERVAL:
|
||||
tvp->u.data = fe->dtv_property_cache.guard_interval;
|
||||
break;
|
||||
case DTV_TRANSMISSION_MODE:
|
||||
tvp->u.data = fe->dtv_property_cache.transmission_mode;
|
||||
break;
|
||||
case DTV_HIERARCHY:
|
||||
tvp->u.data = fe->dtv_property_cache.hierarchy;
|
||||
break;
|
||||
default:
|
||||
r = -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
|
||||
struct inode *inode, struct file *file)
|
||||
{
|
||||
int r = 0;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
printk("%s()\n", __FUNCTION__);
|
||||
dtv_property_dump(tvp);
|
||||
|
||||
/* Allow the frontend to validate incoming properties */
|
||||
if (fe->ops.set_property)
|
||||
r = fe->ops.set_property(fe, tvp);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch(tvp->cmd) {
|
||||
case DTV_CLEAR:
|
||||
/* Reset a cache of data specific to the frontend here. This does
|
||||
* not effect hardware.
|
||||
*/
|
||||
printk("%s() Flushing property cache\n", __FUNCTION__);
|
||||
memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
|
||||
fe->dtv_property_cache.state = tvp->cmd;
|
||||
fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
|
||||
break;
|
||||
case DTV_TUNE:
|
||||
/* interpret the cache of data, build either a traditional frontend
|
||||
* tunerequest so we can pass validation in the FE_SET_FRONTEND
|
||||
* ioctl.
|
||||
*/
|
||||
fe->dtv_property_cache.state = tvp->cmd;
|
||||
printk("%s() Finalised property cache\n", __FUNCTION__);
|
||||
dtv_property_cache_submit(fe);
|
||||
|
||||
r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
|
||||
&fepriv->parameters);
|
||||
break;
|
||||
case DTV_FREQUENCY:
|
||||
fe->dtv_property_cache.frequency = tvp->u.data;
|
||||
break;
|
||||
case DTV_MODULATION:
|
||||
fe->dtv_property_cache.modulation = tvp->u.data;
|
||||
break;
|
||||
case DTV_BANDWIDTH_HZ:
|
||||
fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
|
||||
break;
|
||||
case DTV_INVERSION:
|
||||
fe->dtv_property_cache.inversion = tvp->u.data;
|
||||
break;
|
||||
case DTV_SYMBOL_RATE:
|
||||
fe->dtv_property_cache.symbol_rate = tvp->u.data;
|
||||
break;
|
||||
case DTV_INNER_FEC:
|
||||
fe->dtv_property_cache.fec_inner = tvp->u.data;
|
||||
break;
|
||||
case DTV_PILOT:
|
||||
fe->dtv_property_cache.pilot = tvp->u.data;
|
||||
break;
|
||||
case DTV_ROLLOFF:
|
||||
fe->dtv_property_cache.rolloff = tvp->u.data;
|
||||
break;
|
||||
case DTV_DELIVERY_SYSTEM:
|
||||
fe->dtv_property_cache.delivery_system = tvp->u.data;
|
||||
break;
|
||||
case DTV_VOLTAGE:
|
||||
fe->dtv_property_cache.voltage = tvp->u.data;
|
||||
r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
|
||||
(void *)fe->dtv_property_cache.voltage);
|
||||
break;
|
||||
case DTV_TONE:
|
||||
fe->dtv_property_cache.sectone = tvp->u.data;
|
||||
r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
|
||||
(void *)fe->dtv_property_cache.sectone);
|
||||
break;
|
||||
case DTV_CODE_RATE_HP:
|
||||
fe->dtv_property_cache.code_rate_HP = tvp->u.data;
|
||||
break;
|
||||
case DTV_CODE_RATE_LP:
|
||||
fe->dtv_property_cache.code_rate_LP = tvp->u.data;
|
||||
break;
|
||||
case DTV_GUARD_INTERVAL:
|
||||
fe->dtv_property_cache.guard_interval = tvp->u.data;
|
||||
break;
|
||||
case DTV_TRANSMISSION_MODE:
|
||||
fe->dtv_property_cache.transmission_mode = tvp->u.data;
|
||||
break;
|
||||
case DTV_HIERARCHY:
|
||||
fe->dtv_property_cache.hierarchy = tvp->u.data;
|
||||
break;
|
||||
default:
|
||||
r = -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
@ -776,6 +1310,116 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
|
||||
if (down_interruptible (&fepriv->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
|
||||
err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
|
||||
else {
|
||||
fe->dtv_property_cache.state = DTV_UNDEFINED;
|
||||
err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
|
||||
}
|
||||
|
||||
up(&fepriv->sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
int err = 0;
|
||||
|
||||
struct dtv_properties *tvps = NULL;
|
||||
struct dtv_property *tvp = NULL;
|
||||
int i;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if(cmd == FE_SET_PROPERTY) {
|
||||
printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
|
||||
|
||||
tvps = (struct dtv_properties __user *)parg;
|
||||
|
||||
printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
|
||||
printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
|
||||
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = (struct dtv_property *) kmalloc(tvps->num *
|
||||
sizeof(struct dtv_property), GFP_KERNEL);
|
||||
if (!tvp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
(tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
|
||||
err |= (tvp + i)->result;
|
||||
}
|
||||
|
||||
if(fe->dtv_property_cache.state == DTV_TUNE) {
|
||||
printk("%s() Property cache is full, tuning\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
} else
|
||||
if(cmd == FE_GET_PROPERTY) {
|
||||
printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
|
||||
|
||||
tvps = (struct dtv_properties __user *)parg;
|
||||
|
||||
printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
|
||||
printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
|
||||
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = (struct dtv_property *) kmalloc(tvps->num *
|
||||
sizeof(struct dtv_property), GFP_KERNEL);
|
||||
if (!tvp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
(tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
|
||||
err |= (tvp + i)->result;
|
||||
}
|
||||
|
||||
if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
out:
|
||||
kfree(tvp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
switch (cmd) {
|
||||
case FE_GET_INFO: {
|
||||
struct dvb_frontend_info* info = parg;
|
||||
@ -942,13 +1586,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
|
||||
case FE_SET_FRONTEND: {
|
||||
struct dvb_frontend_tune_settings fetunesettings;
|
||||
|
||||
if (dvb_frontend_check_parameters(fe, parg) < 0) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if(fe->dtv_property_cache.state == DTV_TUNE) {
|
||||
if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (dvb_frontend_check_parameters(fe, parg) < 0) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy (&fepriv->parameters, parg,
|
||||
sizeof (struct dvb_frontend_parameters));
|
||||
memcpy (&fepriv->parameters, parg,
|
||||
sizeof (struct dvb_frontend_parameters));
|
||||
dtv_property_cache_sync(fe, &fepriv->parameters);
|
||||
}
|
||||
|
||||
memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
|
||||
memcpy(&fetunesettings.parameters, parg,
|
||||
@ -1027,10 +1679,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
|
||||
break;
|
||||
};
|
||||
|
||||
up (&fepriv->sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
|
@ -169,6 +169,9 @@ struct dvb_frontend_ops {
|
||||
|
||||
struct dvb_tuner_ops tuner_ops;
|
||||
struct analog_demod_ops analog_ops;
|
||||
|
||||
int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
};
|
||||
|
||||
#define MAX_EVENT 8
|
||||
@ -182,6 +185,32 @@ struct dvb_fe_events {
|
||||
struct mutex mtx;
|
||||
};
|
||||
|
||||
struct dtv_frontend_properties {
|
||||
|
||||
/* Cache State */
|
||||
u32 state;
|
||||
|
||||
u32 frequency;
|
||||
fe_modulation_t modulation;
|
||||
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t sectone;
|
||||
fe_spectral_inversion_t inversion;
|
||||
fe_code_rate_t fec_inner;
|
||||
fe_transmit_mode_t transmission_mode;
|
||||
u32 bandwidth_hz; /* 0 = AUTO */
|
||||
fe_guard_interval_t guard_interval;
|
||||
fe_hierarchy_t hierarchy;
|
||||
u32 symbol_rate;
|
||||
fe_code_rate_t code_rate_HP;
|
||||
fe_code_rate_t code_rate_LP;
|
||||
|
||||
fe_pilot_t pilot;
|
||||
fe_rolloff_t rolloff;
|
||||
|
||||
fe_delivery_system_t delivery_system;
|
||||
};
|
||||
|
||||
struct dvb_frontend {
|
||||
struct dvb_frontend_ops ops;
|
||||
struct dvb_adapter *dvb;
|
||||
@ -190,6 +219,9 @@ struct dvb_frontend {
|
||||
void *frontend_priv;
|
||||
void *sec_priv;
|
||||
void *analog_demod_priv;
|
||||
struct dtv_frontend_properties dtv_property_cache;
|
||||
#define DVB_FRONTEND_COMPONENT_TUNER 0
|
||||
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
|
||||
};
|
||||
|
||||
extern int dvb_register_frontend(struct dvb_adapter *dvb,
|
||||
|
@ -72,9 +72,11 @@ config DVB_USB_DIB0700
|
||||
select DVB_DIB7000P
|
||||
select DVB_DIB7000M
|
||||
select DVB_DIB3000MC
|
||||
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
|
||||
select DVB_TUNER_DIB0070
|
||||
help
|
||||
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
|
||||
@ -108,6 +110,8 @@ config DVB_USB_CXUSB
|
||||
select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
|
||||
select DVB_DIB7000P if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Conexant USB2.0 hybrid reference design.
|
||||
Currently, only DVB and ATSC modes are supported, analog mode
|
||||
@ -245,12 +249,25 @@ config DVB_USB_AF9005_REMOTE
|
||||
Afatech AF9005 based receiver.
|
||||
|
||||
config DVB_USB_DW2102
|
||||
tristate "DvbWorld 2102 DVB-S USB2.0 receiver"
|
||||
tristate "DvbWorld DVB-S/S2 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_PLL if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0288 if !DVB_FE_CUSTOMISE
|
||||
select DVB_STB6000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
||||
select DVB_SI21XX if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver.
|
||||
Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
|
||||
and the TeVii S650.
|
||||
|
||||
config DVB_USB_CINERGY_T2
|
||||
tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
config DVB_USB_ANYSEE
|
||||
tristate "Anysee DVB-T/C USB2.0 support"
|
||||
@ -262,3 +279,22 @@ config DVB_USB_ANYSEE
|
||||
help
|
||||
Say Y here to support the Anysee E30, Anysee E30 Plus or
|
||||
Anysee E30 C Plus DVB USB2.0 receiver.
|
||||
|
||||
config DVB_USB_DTV5100
|
||||
tristate "AME DTV-5100 USB2.0 DVB-T support"
|
||||
depends on DVB_USB
|
||||
select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
|
||||
|
||||
config DVB_USB_AF9015
|
||||
tristate "Afatech AF9015 DVB-T USB2.0 support"
|
||||
depends on DVB_USB && EXPERIMENTAL
|
||||
select DVB_AF9013
|
||||
select DVB_PLL if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE
|
||||
select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
|
||||
|
@ -67,6 +67,16 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
|
||||
dvb-usb-dw2102-objs = dw2102.o
|
||||
obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
|
||||
|
||||
dvb-usb-dtv5100-objs = dtv5100.o
|
||||
obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
|
||||
|
||||
dvb-usb-af9015-objs = af9015.o
|
||||
obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
|
||||
|
||||
dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
|
||||
obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
|
||||
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
# due to tuner-xc3028
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
@ -25,7 +25,7 @@
|
||||
*/
|
||||
#include "af9005.h"
|
||||
/* debug */
|
||||
int dvb_usb_af9005_remote_debug;
|
||||
static int dvb_usb_af9005_remote_debug;
|
||||
module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,
|
||||
"enable (1) or disable (0) debug messages."
|
||||
|
@ -14,7 +14,7 @@ typedef struct {
|
||||
u8 val;
|
||||
} RegDesc;
|
||||
|
||||
RegDesc script[] = {
|
||||
static RegDesc script[] = {
|
||||
{0xa180, 0x0, 0x8, 0xa},
|
||||
{0xa181, 0x0, 0x8, 0xd7},
|
||||
{0xa182, 0x0, 0x8, 0xa3},
|
||||
|
@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644);
|
||||
MODULE_PARM_DESC(led, "enable led (default: 1).");
|
||||
|
||||
/* eeprom dump */
|
||||
int dvb_usb_af9005_dump_eeprom = 0;
|
||||
static int dvb_usb_af9005_dump_eeprom;
|
||||
module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
|
||||
MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/* remote control decoder */
|
||||
int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
|
||||
int *state);
|
||||
void *rc_keys;
|
||||
int *rc_keys_size;
|
||||
static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,
|
||||
u32 *event, int *state);
|
||||
static void *rc_keys;
|
||||
static int *rc_keys_size;
|
||||
|
||||
u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
|
||||
|
||||
@ -54,8 +54,8 @@ struct af9005_device_state {
|
||||
int led_state;
|
||||
};
|
||||
|
||||
int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
|
||||
u8 * rbuf, u16 rlen, int delay_ms)
|
||||
static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
|
||||
u8 *rbuf, u16 rlen, int delay_ms)
|
||||
{
|
||||
int actlen, ret = -ENOMEM;
|
||||
|
||||
@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
|
||||
{
|
||||
return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
|
||||
}
|
||||
|
||||
int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
|
||||
static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
|
||||
int readwrite, int type, u8 * values, int len)
|
||||
{
|
||||
struct af9005_device_state *st = d->priv;
|
||||
@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
|
||||
static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
|
||||
{
|
||||
int i, packets, ret, act_len;
|
||||
|
||||
|
1474
drivers/media/dvb/dvb-usb/af9015.c
Normal file
1474
drivers/media/dvb/dvb-usb/af9015.c
Normal file
File diff suppressed because it is too large
Load Diff
524
drivers/media/dvb/dvb-usb/af9015.h
Normal file
524
drivers/media/dvb/dvb-usb/af9015.h
Normal file
@ -0,0 +1,524 @@
|
||||
/*
|
||||
* DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* Thanks to Afatech who kindly provided information.
|
||||
*
|
||||
* 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 _DVB_USB_AF9015_H_
|
||||
#define _DVB_USB_AF9015_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "af9015"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_af9015_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args)
|
||||
#define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args)
|
||||
#define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args)
|
||||
|
||||
#define AF9015_I2C_EEPROM 0xa0
|
||||
#define AF9015_I2C_DEMOD 0x38
|
||||
#define AF9015_USB_TIMEOUT 2000
|
||||
|
||||
/* EEPROM locations */
|
||||
#define AF9015_EEPROM_IR_MODE 0x18
|
||||
#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34
|
||||
#define AF9015_EEPROM_TS_MODE 0x31
|
||||
#define AF9015_EEPROM_DEMOD2_I2C 0x32
|
||||
|
||||
#define AF9015_EEPROM_SAW_BW1 0x35
|
||||
#define AF9015_EEPROM_XTAL_TYPE1 0x36
|
||||
#define AF9015_EEPROM_SPEC_INV1 0x37
|
||||
#define AF9015_EEPROM_IF1L 0x38
|
||||
#define AF9015_EEPROM_IF1H 0x39
|
||||
#define AF9015_EEPROM_MT2060_IF1L 0x3a
|
||||
#define AF9015_EEPROM_MT2060_IF1H 0x3b
|
||||
#define AF9015_EEPROM_TUNER_ID1 0x3c
|
||||
|
||||
#define AF9015_EEPROM_SAW_BW2 0x45
|
||||
#define AF9015_EEPROM_XTAL_TYPE2 0x46
|
||||
#define AF9015_EEPROM_SPEC_INV2 0x47
|
||||
#define AF9015_EEPROM_IF2L 0x48
|
||||
#define AF9015_EEPROM_IF2H 0x49
|
||||
#define AF9015_EEPROM_MT2060_IF2L 0x4a
|
||||
#define AF9015_EEPROM_MT2060_IF2H 0x4b
|
||||
#define AF9015_EEPROM_TUNER_ID2 0x4c
|
||||
|
||||
#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1)
|
||||
|
||||
#define AF9015_GPIO_ON (1 << 0)
|
||||
#define AF9015_GPIO_EN (1 << 1)
|
||||
#define AF9015_GPIO_O (1 << 2)
|
||||
#define AF9015_GPIO_I (1 << 3)
|
||||
|
||||
#define AF9015_GPIO_TUNER_ON (AF9015_GPIO_ON|AF9015_GPIO_EN)
|
||||
#define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O)
|
||||
|
||||
struct req_t {
|
||||
u8 cmd; /* [0] */
|
||||
/* seq */ /* [1] */
|
||||
u8 i2c_addr; /* [2] */
|
||||
u16 addr; /* [3|4] */
|
||||
u8 mbox; /* [5] */
|
||||
u8 addr_len; /* [6] */
|
||||
u8 data_len; /* [7] */
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
enum af9015_cmd {
|
||||
GET_CONFIG = 0x10,
|
||||
DOWNLOAD_FIRMWARE = 0x11,
|
||||
BOOT = 0x13,
|
||||
READ_MEMORY = 0x20,
|
||||
WRITE_MEMORY = 0x21,
|
||||
READ_WRITE_I2C = 0x22,
|
||||
COPY_FIRMWARE = 0x23,
|
||||
RECONNECT_USB = 0x5a,
|
||||
WRITE_VIRTUAL_MEMORY = 0x26,
|
||||
GET_IR_CODE = 0x27,
|
||||
READ_I2C,
|
||||
WRITE_I2C,
|
||||
};
|
||||
|
||||
enum af9015_ir_mode {
|
||||
AF9015_IR_MODE_DISABLED = 0,
|
||||
AF9015_IR_MODE_HID,
|
||||
AF9015_IR_MODE_RLC,
|
||||
AF9015_IR_MODE_RC6,
|
||||
};
|
||||
|
||||
struct af9015_state {
|
||||
struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
|
||||
};
|
||||
|
||||
struct af9015_config {
|
||||
u8 dual_mode:1;
|
||||
u16 mt2060_if1[2];
|
||||
u16 firmware_size;
|
||||
u16 firmware_checksum;
|
||||
u8 *ir_table;
|
||||
u16 ir_table_size;
|
||||
};
|
||||
|
||||
enum af9015_remote {
|
||||
AF9015_REMOTE_NONE = 0,
|
||||
AF9015_REMOTE_A_LINK_DTU_M,
|
||||
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
|
||||
AF9015_REMOTE_MYGICTV_U718,
|
||||
};
|
||||
|
||||
/* Leadtek WinFast DTV Dongle Gold */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
|
||||
{ 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 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x28, KEY_ENTER },
|
||||
{ 0x00, 0x4f, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x50, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x51, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x52, KEY_CHANNELUP },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_leadtek[] = {
|
||||
0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00,
|
||||
0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* TwinHan AzureWave AD-TU700(704J) */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = {
|
||||
{ 0x05, 0x3f, KEY_POWER },
|
||||
{ 0x00, 0x19, KEY_FAVORITES }, /* Favorite List */
|
||||
{ 0x00, 0x04, KEY_TEXT }, /* Teletext */
|
||||
{ 0x00, 0x0e, KEY_POWER },
|
||||
{ 0x00, 0x0e, KEY_INFO }, /* Preview */
|
||||
{ 0x00, 0x08, KEY_EPG }, /* Info/EPG */
|
||||
{ 0x00, 0x0f, KEY_LIST }, /* Record List */
|
||||
{ 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 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x29, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x00, 0x4c, KEY_CLEAR }, /* Clear */
|
||||
{ 0x00, 0x2a, KEY_BACK }, /* Back */
|
||||
{ 0x00, 0x2b, KEY_TAB }, /* Tab */
|
||||
{ 0x00, 0x52, KEY_UP }, /* up arrow */
|
||||
{ 0x00, 0x51, KEY_DOWN }, /* down arrow */
|
||||
{ 0x00, 0x4f, KEY_RIGHT }, /* right arrow */
|
||||
{ 0x00, 0x50, KEY_LEFT }, /* left arrow */
|
||||
{ 0x00, 0x28, KEY_ENTER }, /* Enter / ok */
|
||||
{ 0x02, 0x52, KEY_VOLUMEUP },
|
||||
{ 0x02, 0x51, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x4e, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x4b, KEY_CHANNELUP },
|
||||
{ 0x00, 0x4a, KEY_RECORD },
|
||||
{ 0x01, 0x11, KEY_PLAY },
|
||||
{ 0x00, 0x17, KEY_PAUSE },
|
||||
{ 0x00, 0x0c, KEY_REWIND }, /* FR << */
|
||||
{ 0x00, 0x11, KEY_FASTFORWARD }, /* FF >> */
|
||||
{ 0x01, 0x15, KEY_PREVIOUS }, /* Replay */
|
||||
{ 0x01, 0x0e, KEY_NEXT }, /* Skip */
|
||||
{ 0x00, 0x13, KEY_CAMERA }, /* Capture */
|
||||
{ 0x01, 0x0f, KEY_LANGUAGE }, /* SAP */
|
||||
{ 0x01, 0x13, KEY_TV2 }, /* PIP */
|
||||
{ 0x00, 0x1d, KEY_ZOOM }, /* Full Screen */
|
||||
{ 0x01, 0x17, KEY_SUBTITLE }, /* Subtitle / CC */
|
||||
{ 0x00, 0x10, KEY_MUTE },
|
||||
{ 0x01, 0x19, KEY_AUDIO }, /* L/R */ /* TODO better event */
|
||||
{ 0x01, 0x16, KEY_SLEEP }, /* Hibernate */
|
||||
{ 0x01, 0x16, KEY_SWITCHVIDEOMODE },
|
||||
/* A/V */ /* TODO does not work */
|
||||
{ 0x00, 0x06, KEY_AGAIN }, /* Recall */
|
||||
{ 0x01, 0x16, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */
|
||||
{ 0x01, 0x16, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */
|
||||
{ 0x02, 0x15, KEY_RED },
|
||||
{ 0x02, 0x0a, KEY_GREEN },
|
||||
{ 0x02, 0x1c, KEY_YELLOW },
|
||||
{ 0x02, 0x05, KEY_BLUE },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_twinhan[] = {
|
||||
0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
|
||||
0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
|
||||
0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
|
||||
0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
|
||||
0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
|
||||
0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
|
||||
0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
|
||||
0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
|
||||
0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
|
||||
0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
|
||||
0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
|
||||
0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
|
||||
0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
|
||||
0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
|
||||
0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
|
||||
0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
|
||||
0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
|
||||
0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
|
||||
0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
|
||||
0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
|
||||
0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
|
||||
0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
|
||||
0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
|
||||
0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
|
||||
0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
|
||||
0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
|
||||
0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
|
||||
0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
|
||||
0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
|
||||
0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
|
||||
0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
|
||||
0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
|
||||
0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
|
||||
0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
|
||||
0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
|
||||
0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
|
||||
0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
|
||||
0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
|
||||
0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
|
||||
0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
|
||||
0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
|
||||
0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
|
||||
0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
|
||||
0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
|
||||
0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
|
||||
0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
|
||||
};
|
||||
|
||||
/* A-Link DTU(m) */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = {
|
||||
{ 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 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x2e, KEY_CHANNELUP },
|
||||
{ 0x00, 0x2d, KEY_CHANNELDOWN },
|
||||
{ 0x04, 0x28, KEY_ZOOM },
|
||||
{ 0x00, 0x41, KEY_MUTE },
|
||||
{ 0x00, 0x42, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x43, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x44, KEY_GOTO }, /* jump */
|
||||
{ 0x05, 0x45, KEY_POWER },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_a_link[] = {
|
||||
0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
|
||||
0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
|
||||
0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
|
||||
0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
|
||||
0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
|
||||
0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
|
||||
0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
|
||||
0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
|
||||
0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
|
||||
0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
|
||||
0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
|
||||
0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
|
||||
0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
|
||||
0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
|
||||
0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
|
||||
0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
|
||||
0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
|
||||
0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
|
||||
};
|
||||
|
||||
/* MSI DIGIVOX mini II V3.0 */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_msi[] = {
|
||||
{ 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 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x03, 0x0f, KEY_CHANNELUP },
|
||||
{ 0x03, 0x0e, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x42, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x43, KEY_VOLUMEUP },
|
||||
{ 0x05, 0x45, KEY_POWER },
|
||||
{ 0x00, 0x52, KEY_UP }, /* up */
|
||||
{ 0x00, 0x51, KEY_DOWN }, /* down */
|
||||
{ 0x00, 0x28, KEY_ENTER },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_msi[] = {
|
||||
0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
|
||||
0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
|
||||
0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
|
||||
0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
|
||||
0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
|
||||
0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
|
||||
0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
|
||||
0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
|
||||
0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
|
||||
0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
|
||||
0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
|
||||
0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
|
||||
0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
|
||||
0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
|
||||
0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
|
||||
0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
|
||||
0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
|
||||
0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
|
||||
};
|
||||
|
||||
/* MYGICTV U718 */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = {
|
||||
{ 0x00, 0x3d, KEY_SWITCHVIDEOMODE },
|
||||
/* TV / AV */
|
||||
{ 0x05, 0x45, KEY_POWER },
|
||||
{ 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 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x41, KEY_MUTE },
|
||||
{ 0x00, 0x2a, KEY_ESC }, /* Esc */
|
||||
{ 0x00, 0x2e, KEY_CHANNELUP },
|
||||
{ 0x00, 0x2d, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x42, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x43, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x52, KEY_UP }, /* up arrow */
|
||||
{ 0x00, 0x51, KEY_DOWN }, /* down arrow */
|
||||
{ 0x00, 0x4f, KEY_RIGHT }, /* right arrow */
|
||||
{ 0x00, 0x50, KEY_LEFT }, /* left arrow */
|
||||
{ 0x00, 0x28, KEY_ENTER }, /* ok */
|
||||
{ 0x01, 0x15, KEY_RECORD },
|
||||
{ 0x03, 0x13, KEY_PLAY },
|
||||
{ 0x01, 0x13, KEY_PAUSE },
|
||||
{ 0x01, 0x16, KEY_STOP },
|
||||
{ 0x03, 0x07, KEY_REWIND }, /* FR << */
|
||||
{ 0x03, 0x09, KEY_FASTFORWARD }, /* FF >> */
|
||||
{ 0x00, 0x3b, KEY_TIME }, /* TimeShift */
|
||||
{ 0x00, 0x3e, KEY_CAMERA }, /* Snapshot */
|
||||
{ 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */
|
||||
{ 0x00, 0x00, KEY_ZOOM }, /* 'select' (?) */
|
||||
{ 0x03, 0x16, KEY_SHUFFLE }, /* Shuffle */
|
||||
{ 0x03, 0x45, KEY_POWER },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_mygictv[] = {
|
||||
0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
|
||||
0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
|
||||
0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
|
||||
0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
|
||||
0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
|
||||
0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
|
||||
0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
|
||||
0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
|
||||
0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
|
||||
0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
|
||||
0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
|
||||
0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
|
||||
0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
|
||||
0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
|
||||
0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
|
||||
0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
|
||||
0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
|
||||
0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
|
||||
0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
|
||||
0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
|
||||
0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
|
||||
0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
|
||||
0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
|
||||
0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
|
||||
0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
|
||||
0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
|
||||
0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
|
||||
0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
|
||||
0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
|
||||
0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
|
||||
0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
|
||||
0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
|
||||
0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
|
||||
0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
|
||||
0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
|
||||
};
|
||||
|
||||
/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
|
||||
static u8 af9015_ir_table_kworld[] = {
|
||||
0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
|
||||
0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
|
||||
};
|
||||
|
||||
#endif
|
@ -41,6 +41,9 @@
|
||||
static int dvb_usb_anysee_debug;
|
||||
module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
|
||||
int dvb_usb_anysee_delsys;
|
||||
module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
|
||||
MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static struct mutex anysee_usb_mutex;
|
||||
@ -178,14 +181,14 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
inc = 1;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
i += inc;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return i;
|
||||
return ret ? ret : i;
|
||||
}
|
||||
|
||||
static u32 anysee_i2c_func(struct i2c_adapter *adapter)
|
||||
@ -272,9 +275,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
model demod hw firmware
|
||||
1. E30 MT352 02 0.2.1
|
||||
2. E30 ZL10353 02 0.2.1
|
||||
3. E30 Plus ZL10353 06 0.1.0
|
||||
4. E30C Plus TDA10023 0a 0.1.0 rev 0.2
|
||||
4. E30C Plus TDA10023 0f 0.1.2 rev 0.4
|
||||
3. E30 Combo ZL10353 0f 0.1.2 DVB-T/C combo
|
||||
4. E30 Plus ZL10353 06 0.1.0
|
||||
5. E30C Plus TDA10023 0a 0.1.0 rev 0.2
|
||||
E30C Plus TDA10023 0f 0.1.2 rev 0.4
|
||||
E30 Combo TDA10023 0f 0.1.2 DVB-T/C combo
|
||||
*/
|
||||
|
||||
/* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
|
||||
@ -293,6 +298,21 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for E30 Combo Plus DVB-T demodulator */
|
||||
if (dvb_usb_anysee_delsys) {
|
||||
ret = anysee_write_reg(adap->dev, 0xb0, 0x01);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Zarlink ZL10353 DVB-T demod */
|
||||
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe != NULL) {
|
||||
state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* connect demod on IO port D for TDA10023 & ZL10353 */
|
||||
ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
|
||||
if (ret)
|
||||
|
268
drivers/media/dvb/dvb-usb/cinergyT2-core.c
Normal file
268
drivers/media/dvb/dvb-usb/cinergyT2-core.c
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
|
||||
*
|
||||
* Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
|
||||
*
|
||||
* Based on the dvb-usb-framework code and the
|
||||
* original Terratec Cinergy T2 driver by:
|
||||
*
|
||||
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
|
||||
* Holger Waechtler <holger@qanu.de>
|
||||
*
|
||||
* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
|
||||
*
|
||||
* 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 "cinergyT2.h"
|
||||
|
||||
|
||||
/* 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 "
|
||||
"(or-able)).");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct cinergyt2_state {
|
||||
u8 rc_counter;
|
||||
};
|
||||
|
||||
/* We are missing a release hook with usb_device data */
|
||||
struct dvb_usb_device *cinergyt2_usb_device;
|
||||
|
||||
static struct dvb_usb_device_properties cinergyt2_properties;
|
||||
|
||||
static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
|
||||
{
|
||||
char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
|
||||
char result[64];
|
||||
return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
|
||||
sizeof(result), 0);
|
||||
}
|
||||
|
||||
static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
|
||||
{
|
||||
char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
|
||||
char state[3];
|
||||
return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
|
||||
}
|
||||
|
||||
static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
|
||||
char state[3];
|
||||
int ret;
|
||||
|
||||
adap->fe = cinergyt2_fe_attach(adap->dev);
|
||||
|
||||
ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
|
||||
sizeof(state), 0);
|
||||
if (ret < 0) {
|
||||
deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
|
||||
"state info\n");
|
||||
}
|
||||
|
||||
/* Copy this pointer as we are gonna need it in the release phase */
|
||||
cinergyt2_usb_device = adap->dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
|
||||
{ 0x04, 0x01, KEY_POWER },
|
||||
{ 0x04, 0x02, KEY_1 },
|
||||
{ 0x04, 0x03, KEY_2 },
|
||||
{ 0x04, 0x04, KEY_3 },
|
||||
{ 0x04, 0x05, KEY_4 },
|
||||
{ 0x04, 0x06, KEY_5 },
|
||||
{ 0x04, 0x07, KEY_6 },
|
||||
{ 0x04, 0x08, KEY_7 },
|
||||
{ 0x04, 0x09, KEY_8 },
|
||||
{ 0x04, 0x0a, KEY_9 },
|
||||
{ 0x04, 0x0c, KEY_0 },
|
||||
{ 0x04, 0x0b, KEY_VIDEO },
|
||||
{ 0x04, 0x0d, KEY_REFRESH },
|
||||
{ 0x04, 0x0e, KEY_SELECT },
|
||||
{ 0x04, 0x0f, KEY_EPG },
|
||||
{ 0x04, 0x10, KEY_UP },
|
||||
{ 0x04, 0x14, KEY_DOWN },
|
||||
{ 0x04, 0x11, KEY_LEFT },
|
||||
{ 0x04, 0x13, KEY_RIGHT },
|
||||
{ 0x04, 0x12, KEY_OK },
|
||||
{ 0x04, 0x15, KEY_TEXT },
|
||||
{ 0x04, 0x16, KEY_INFO },
|
||||
{ 0x04, 0x17, KEY_RED },
|
||||
{ 0x04, 0x18, KEY_GREEN },
|
||||
{ 0x04, 0x19, KEY_YELLOW },
|
||||
{ 0x04, 0x1a, KEY_BLUE },
|
||||
{ 0x04, 0x1c, KEY_VOLUMEUP },
|
||||
{ 0x04, 0x1e, KEY_VOLUMEDOWN },
|
||||
{ 0x04, 0x1d, KEY_MUTE },
|
||||
{ 0x04, 0x1b, KEY_CHANNELUP },
|
||||
{ 0x04, 0x1f, KEY_CHANNELDOWN },
|
||||
{ 0x04, 0x40, KEY_PAUSE },
|
||||
{ 0x04, 0x4c, KEY_PLAY },
|
||||
{ 0x04, 0x58, KEY_RECORD },
|
||||
{ 0x04, 0x54, KEY_PREVIOUS },
|
||||
{ 0x04, 0x48, KEY_STOP },
|
||||
{ 0x04, 0x5c, KEY_NEXT }
|
||||
};
|
||||
|
||||
/* Number of keypresses to ignore before detect repeating */
|
||||
#define RC_REPEAT_DELAY 3
|
||||
|
||||
static int repeatable_keys[] = {
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_VOLUMEUP,
|
||||
KEY_VOLUMEDOWN,
|
||||
KEY_CHANNELUP,
|
||||
KEY_CHANNELDOWN
|
||||
};
|
||||
|
||||
static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct cinergyt2_state *st = d->priv;
|
||||
u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
|
||||
int i;
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
|
||||
if (key[4] == 0xff) {
|
||||
/* key repeat */
|
||||
st->rc_counter++;
|
||||
if (st->rc_counter > RC_REPEAT_DELAY) {
|
||||
for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
|
||||
if (d->last_event == repeatable_keys[i]) {
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
*event = d->last_event;
|
||||
deb_rc("repeat key, event %x\n",
|
||||
*event);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
deb_rc("repeated key (non repeatable)\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hack to pass checksum on the custom field */
|
||||
key[2] = ~key[1];
|
||||
dvb_usb_nec_rc_key_to_event(d, key, event, state);
|
||||
if (key[0] != 0) {
|
||||
if (*event != d->last_event)
|
||||
st->rc_counter = 0;
|
||||
|
||||
deb_rc("key: %x %x %x %x %x\n",
|
||||
key[0], key[1], key[2], key[3], key[4]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf, &cinergyt2_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
}
|
||||
|
||||
|
||||
static struct usb_device_id cinergyt2_usb_table[] = {
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties cinergyt2_properties = {
|
||||
.size_of_priv = sizeof(struct cinergyt2_state),
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cinergyt2_streaming_ctrl,
|
||||
.frontend_attach = cinergyt2_frontend_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = cinergyt2_power_ctrl,
|
||||
|
||||
.rc_interval = 50,
|
||||
.rc_key_map = cinergyt2_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(cinergyt2_rc_keys),
|
||||
.rc_query = cinergyt2_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 1,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
|
||||
.cold_ids = {NULL},
|
||||
.warm_ids = { &cinergyt2_usb_table[0], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static struct usb_driver cinergyt2_driver = {
|
||||
.name = "cinergyT2",
|
||||
.probe = cinergyt2_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = cinergyt2_usb_table
|
||||
};
|
||||
|
||||
static int __init cinergyt2_usb_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = usb_register(&cinergyt2_driver);
|
||||
if (err) {
|
||||
err("usb_register() failed! (err %i)\n", err);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cinergyt2_usb_exit(void)
|
||||
{
|
||||
usb_deregister(&cinergyt2_driver);
|
||||
}
|
||||
|
||||
module_init(cinergyt2_usb_init);
|
||||
module_exit(cinergyt2_usb_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Tomi Orava");
|
351
drivers/media/dvb/dvb-usb/cinergyT2-fe.c
Normal file
351
drivers/media/dvb/dvb-usb/cinergyT2-fe.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
|
||||
*
|
||||
* Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
|
||||
*
|
||||
* Based on the dvb-usb-framework code and the
|
||||
* original Terratec Cinergy T2 driver by:
|
||||
*
|
||||
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
|
||||
* Holger Waechtler <holger@qanu.de>
|
||||
*
|
||||
* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
|
||||
*
|
||||
* 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 "cinergyT2.h"
|
||||
|
||||
|
||||
/**
|
||||
* convert linux-dvb frontend parameter set into TPS.
|
||||
* See ETSI ETS-300744, section 4.6.2, table 9 for details.
|
||||
*
|
||||
* This function is probably reusable and may better get placed in a support
|
||||
* library.
|
||||
*
|
||||
* We replace errornous fields by default TPS fields (the ones with value 0).
|
||||
*/
|
||||
|
||||
static uint16_t compute_tps(struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct dvb_ofdm_parameters *op = &p->u.ofdm;
|
||||
uint16_t tps = 0;
|
||||
|
||||
switch (op->code_rate_HP) {
|
||||
case FEC_2_3:
|
||||
tps |= (1 << 7);
|
||||
break;
|
||||
case FEC_3_4:
|
||||
tps |= (2 << 7);
|
||||
break;
|
||||
case FEC_5_6:
|
||||
tps |= (3 << 7);
|
||||
break;
|
||||
case FEC_7_8:
|
||||
tps |= (4 << 7);
|
||||
break;
|
||||
case FEC_1_2:
|
||||
case FEC_AUTO:
|
||||
default:
|
||||
/* tps |= (0 << 7) */;
|
||||
}
|
||||
|
||||
switch (op->code_rate_LP) {
|
||||
case FEC_2_3:
|
||||
tps |= (1 << 4);
|
||||
break;
|
||||
case FEC_3_4:
|
||||
tps |= (2 << 4);
|
||||
break;
|
||||
case FEC_5_6:
|
||||
tps |= (3 << 4);
|
||||
break;
|
||||
case FEC_7_8:
|
||||
tps |= (4 << 4);
|
||||
break;
|
||||
case FEC_1_2:
|
||||
case FEC_AUTO:
|
||||
default:
|
||||
/* tps |= (0 << 4) */;
|
||||
}
|
||||
|
||||
switch (op->constellation) {
|
||||
case QAM_16:
|
||||
tps |= (1 << 13);
|
||||
break;
|
||||
case QAM_64:
|
||||
tps |= (2 << 13);
|
||||
break;
|
||||
case QPSK:
|
||||
default:
|
||||
/* tps |= (0 << 13) */;
|
||||
}
|
||||
|
||||
switch (op->transmission_mode) {
|
||||
case TRANSMISSION_MODE_8K:
|
||||
tps |= (1 << 0);
|
||||
break;
|
||||
case TRANSMISSION_MODE_2K:
|
||||
default:
|
||||
/* tps |= (0 << 0) */;
|
||||
}
|
||||
|
||||
switch (op->guard_interval) {
|
||||
case GUARD_INTERVAL_1_16:
|
||||
tps |= (1 << 2);
|
||||
break;
|
||||
case GUARD_INTERVAL_1_8:
|
||||
tps |= (2 << 2);
|
||||
break;
|
||||
case GUARD_INTERVAL_1_4:
|
||||
tps |= (3 << 2);
|
||||
break;
|
||||
case GUARD_INTERVAL_1_32:
|
||||
default:
|
||||
/* tps |= (0 << 2) */;
|
||||
}
|
||||
|
||||
switch (op->hierarchy_information) {
|
||||
case HIERARCHY_1:
|
||||
tps |= (1 << 10);
|
||||
break;
|
||||
case HIERARCHY_2:
|
||||
tps |= (2 << 10);
|
||||
break;
|
||||
case HIERARCHY_4:
|
||||
tps |= (3 << 10);
|
||||
break;
|
||||
case HIERARCHY_NONE:
|
||||
default:
|
||||
/* tps |= (0 << 10) */;
|
||||
}
|
||||
|
||||
return tps;
|
||||
}
|
||||
|
||||
struct cinergyt2_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
struct dvb_usb_device *d;
|
||||
};
|
||||
|
||||
static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
|
||||
fe_status_t *status)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg result;
|
||||
u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
|
||||
sizeof(result), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (0xffff - le16_to_cpu(result.gain) > 30)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
if (result.lock_bits & (1 << 6))
|
||||
*status |= FE_HAS_LOCK;
|
||||
if (result.lock_bits & (1 << 5))
|
||||
*status |= FE_HAS_SYNC;
|
||||
if (result.lock_bits & (1 << 4))
|
||||
*status |= FE_HAS_CARRIER;
|
||||
if (result.lock_bits & (1 << 1))
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
|
||||
(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
|
||||
*status &= ~FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*ber = le32_to_cpu(status.viterbi_error_rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0) {
|
||||
err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
*unc = le32_to_cpu(status.uncorrected_block_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *strength)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0) {
|
||||
err("cinergyt2_fe_read_signal_strength() Failed!"
|
||||
" (Error=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*strength = (0xffff - le16_to_cpu(status.gain));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0) {
|
||||
err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*snr = (status.snr << 8) | status.snr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_init(struct dvb_frontend *fe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
deb_info("cinergyt2_fe_sleep() Called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 800;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_set_parameters_msg param;
|
||||
char result[2];
|
||||
int err;
|
||||
|
||||
param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
|
||||
param.tps = cpu_to_le16(compute_tps(fep));
|
||||
param.freq = cpu_to_le32(fep->frequency / 1000);
|
||||
param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
|
||||
|
||||
err = dvb_usb_generic_rw(state->d,
|
||||
(char *)¶m, sizeof(param),
|
||||
result, sizeof(result), 0);
|
||||
if (err < 0)
|
||||
err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cinergyt2_fe_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
if (state != NULL)
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cinergyt2_fe_ops;
|
||||
|
||||
struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct cinergyt2_fe_state *s = kzalloc(sizeof(
|
||||
struct cinergyt2_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->d = d;
|
||||
memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
return &s->fe;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops cinergyt2_fe_ops = {
|
||||
.info = {
|
||||
.name = DRIVER_NAME,
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 174000000,
|
||||
.frequency_max = 862000000,
|
||||
.frequency_stepsize = 166667,
|
||||
.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_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
|
||||
},
|
||||
|
||||
.release = cinergyt2_fe_release,
|
||||
|
||||
.init = cinergyt2_fe_init,
|
||||
.sleep = cinergyt2_fe_sleep,
|
||||
|
||||
.set_frontend = cinergyt2_fe_set_frontend,
|
||||
.get_frontend = cinergyt2_fe_get_frontend,
|
||||
.get_tune_settings = cinergyt2_fe_get_tune_settings,
|
||||
|
||||
.read_status = cinergyt2_fe_read_status,
|
||||
.read_ber = cinergyt2_fe_read_ber,
|
||||
.read_signal_strength = cinergyt2_fe_read_signal_strength,
|
||||
.read_snr = cinergyt2_fe_read_snr,
|
||||
.read_ucblocks = cinergyt2_fe_read_unc_blocks,
|
||||
};
|
95
drivers/media/dvb/dvb-usb/cinergyT2.h
Normal file
95
drivers/media/dvb/dvb-usb/cinergyT2.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
|
||||
*
|
||||
* Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
|
||||
*
|
||||
* Based on the dvb-usb-framework code and the
|
||||
* original Terratec Cinergy T2 driver by:
|
||||
*
|
||||
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
|
||||
* Holger Waechtler <holger@qanu.de>
|
||||
*
|
||||
* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
|
||||
*
|
||||
* 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 _DVB_USB_CINERGYT2_H_
|
||||
#define _DVB_USB_CINERGYT2_H_
|
||||
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "cinergyT2"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
|
||||
|
||||
extern int dvb_usb_cinergyt2_debug;
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args)
|
||||
#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args)
|
||||
#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args)
|
||||
#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args)
|
||||
#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args)
|
||||
#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args)
|
||||
|
||||
|
||||
|
||||
enum cinergyt2_ep1_cmd {
|
||||
CINERGYT2_EP1_PID_TABLE_RESET = 0x01,
|
||||
CINERGYT2_EP1_PID_SETUP = 0x02,
|
||||
CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03,
|
||||
CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04,
|
||||
CINERGYT2_EP1_GET_TUNER_STATUS = 0x05,
|
||||
CINERGYT2_EP1_START_SCAN = 0x06,
|
||||
CINERGYT2_EP1_CONTINUE_SCAN = 0x07,
|
||||
CINERGYT2_EP1_GET_RC_EVENTS = 0x08,
|
||||
CINERGYT2_EP1_SLEEP_MODE = 0x09,
|
||||
CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A
|
||||
};
|
||||
|
||||
|
||||
struct dvbt_get_status_msg {
|
||||
uint32_t freq;
|
||||
uint8_t bandwidth;
|
||||
uint16_t tps;
|
||||
uint8_t flags;
|
||||
uint16_t gain;
|
||||
uint8_t snr;
|
||||
uint32_t viterbi_error_rate;
|
||||
uint32_t rs_error_rate;
|
||||
uint32_t uncorrected_block_count;
|
||||
uint8_t lock_bits;
|
||||
uint8_t prev_lock_bits;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
struct dvbt_set_parameters_msg {
|
||||
uint8_t cmd;
|
||||
uint32_t freq;
|
||||
uint8_t bandwidth;
|
||||
uint16_t tps;
|
||||
uint8_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
|
||||
|
||||
#endif /* _DVB_USB_CINERGYT2_H_ */
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include "tuner-xc2028.h"
|
||||
#include "tuner-simple.h"
|
||||
#include "mxl5005s.h"
|
||||
#include "dib7000p.h"
|
||||
#include "dib0070.h"
|
||||
#include "lgs8gl5.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_cxusb_debug;
|
||||
@ -109,6 +112,25 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
|
||||
cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
|
||||
}
|
||||
|
||||
static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
|
||||
u8 addr, int onoff)
|
||||
{
|
||||
u8 o[2] = {addr, onoff};
|
||||
u8 i;
|
||||
int rc;
|
||||
|
||||
rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (i == 0x01)
|
||||
return 0;
|
||||
else {
|
||||
deb_info("gpio_write failed.\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
@ -262,6 +284,20 @@ static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
int ret;
|
||||
u8 b;
|
||||
ret = cxusb_power_ctrl(d, onoff);
|
||||
if (!onoff)
|
||||
return ret;
|
||||
|
||||
msleep(128);
|
||||
cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
|
||||
msleep(100);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
u8 buf[2] = { 0x03, 0x00 };
|
||||
@ -283,6 +319,67 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
|
||||
{
|
||||
int ep = d->props.generic_bulk_ctrl_endpoint;
|
||||
const int timeout = 100;
|
||||
const int junk_len = 32;
|
||||
u8 *junk;
|
||||
int rd_count;
|
||||
|
||||
/* Discard remaining data in video pipe */
|
||||
junk = kmalloc(junk_len, GFP_KERNEL);
|
||||
if (!junk)
|
||||
return;
|
||||
while (1) {
|
||||
if (usb_bulk_msg(d->udev,
|
||||
usb_rcvbulkpipe(d->udev, ep),
|
||||
junk, junk_len, &rd_count, timeout) < 0)
|
||||
break;
|
||||
if (!rd_count)
|
||||
break;
|
||||
}
|
||||
kfree(junk);
|
||||
}
|
||||
|
||||
static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
|
||||
{
|
||||
struct usb_data_stream_properties *p = &d->props.adapter[0].stream;
|
||||
const int timeout = 100;
|
||||
const int junk_len = p->u.bulk.buffersize;
|
||||
u8 *junk;
|
||||
int rd_count;
|
||||
|
||||
/* Discard remaining data in video pipe */
|
||||
junk = kmalloc(junk_len, GFP_KERNEL);
|
||||
if (!junk)
|
||||
return;
|
||||
while (1) {
|
||||
if (usb_bulk_msg(d->udev,
|
||||
usb_rcvbulkpipe(d->udev, p->endpoint),
|
||||
junk, junk_len, &rd_count, timeout) < 0)
|
||||
break;
|
||||
if (!rd_count)
|
||||
break;
|
||||
}
|
||||
kfree(junk);
|
||||
}
|
||||
|
||||
static int cxusb_d680_dmb_streaming_ctrl(
|
||||
struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
if (onoff) {
|
||||
u8 buf[2] = { 0x03, 0x00 };
|
||||
cxusb_d680_dmb_drain_video(adap->dev);
|
||||
return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
|
||||
buf, sizeof(buf), NULL, 0);
|
||||
} else {
|
||||
int ret = cxusb_ctrl_msg(adap->dev,
|
||||
CMD_STREAMING_OFF, NULL, 0, NULL, 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
@ -335,6 +432,32 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
|
||||
int *state)
|
||||
{
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
u8 ircode[2];
|
||||
int i;
|
||||
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[0] &&
|
||||
keymap[i].data == ircode[1]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
|
||||
{ 0xfe, 0x02, KEY_TV },
|
||||
{ 0xfe, 0x0e, KEY_MP3 },
|
||||
@ -422,6 +545,44 @@ static struct dvb_usb_rc_key dvico_portable_rc_keys[] = {
|
||||
{ 0xfc, 0x00, KEY_UNKNOWN }, /* HD */
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
|
||||
{ 0x00, 0x38, KEY_UNKNOWN }, /* TV/AV */
|
||||
{ 0x08, 0x0c, KEY_ZOOM },
|
||||
{ 0x08, 0x00, KEY_0 },
|
||||
{ 0x00, 0x01, KEY_1 },
|
||||
{ 0x08, 0x02, KEY_2 },
|
||||
{ 0x00, 0x03, KEY_3 },
|
||||
{ 0x08, 0x04, KEY_4 },
|
||||
{ 0x00, 0x05, KEY_5 },
|
||||
{ 0x08, 0x06, KEY_6 },
|
||||
{ 0x00, 0x07, KEY_7 },
|
||||
{ 0x08, 0x08, KEY_8 },
|
||||
{ 0x00, 0x09, KEY_9 },
|
||||
{ 0x00, 0x0a, KEY_MUTE },
|
||||
{ 0x08, 0x29, KEY_BACK },
|
||||
{ 0x00, 0x12, KEY_CHANNELUP },
|
||||
{ 0x08, 0x13, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x2b, KEY_VOLUMEUP },
|
||||
{ 0x08, 0x2c, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x20, KEY_UP },
|
||||
{ 0x08, 0x21, KEY_DOWN },
|
||||
{ 0x00, 0x11, KEY_LEFT },
|
||||
{ 0x08, 0x10, KEY_RIGHT },
|
||||
{ 0x00, 0x0d, KEY_OK },
|
||||
{ 0x08, 0x1f, KEY_RECORD },
|
||||
{ 0x00, 0x17, KEY_PLAYPAUSE },
|
||||
{ 0x08, 0x16, KEY_PLAYPAUSE },
|
||||
{ 0x00, 0x0b, KEY_STOP },
|
||||
{ 0x08, 0x27, KEY_FASTFORWARD },
|
||||
{ 0x00, 0x26, KEY_REWIND },
|
||||
{ 0x08, 0x1e, KEY_UNKNOWN }, /* Time Shift */
|
||||
{ 0x00, 0x0e, KEY_UNKNOWN }, /* Snapshot */
|
||||
{ 0x08, 0x2d, KEY_UNKNOWN }, /* Mouse Cursor */
|
||||
{ 0x00, 0x0f, KEY_UNKNOWN }, /* Minimize/Maximize */
|
||||
{ 0x08, 0x14, KEY_UNKNOWN }, /* Shuffle */
|
||||
{ 0x00, 0x25, KEY_POWER },
|
||||
};
|
||||
|
||||
static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
|
||||
@ -527,6 +688,24 @@ static struct mxl5005s_config aver_a868r_tuner = {
|
||||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
/* FIXME: needs tweaking */
|
||||
static struct mxl5005s_config d680_dmb_tuner = {
|
||||
.i2c_address = 0x63,
|
||||
.if_freq = 36125000UL,
|
||||
.xtal_freq = CRYSTAL_FREQ_16000000HZ,
|
||||
.agc_mode = MXL_SINGLE_AGC,
|
||||
.tracking_filter = MXL_TF_C,
|
||||
.rssi_enable = MXL_RSSI_ENABLE,
|
||||
.cap_select = MXL_CAP_SEL_ENABLE,
|
||||
.div_out = MXL_DIV_OUT_4,
|
||||
.clock_out = MXL_CLOCK_OUT_DISABLE,
|
||||
.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
|
||||
.top = MXL5005S_TOP_25P2,
|
||||
.mod_mode = MXL_DIGITAL_MODE,
|
||||
.if_mode = MXL_ZERO_IF,
|
||||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
@ -563,7 +742,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
|
||||
static int dvico_bluebird_xc2028_callback(void *ptr, int component,
|
||||
int command, int arg)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = ptr;
|
||||
struct dvb_usb_device *d = adap->dev;
|
||||
@ -591,14 +771,16 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
struct xc2028_config cfg = {
|
||||
.i2c_adap = &adap->dev->i2c_adap,
|
||||
.i2c_addr = 0x61,
|
||||
.callback = dvico_bluebird_xc2028_callback,
|
||||
};
|
||||
static struct xc2028_ctrl ctl = {
|
||||
.fname = "xc3028-v27.fw",
|
||||
.fname = XC2028_DEFAULT_FIRMWARE,
|
||||
.max_len = 64,
|
||||
.demod = XC3028_FE_ZARLINK456,
|
||||
};
|
||||
|
||||
/* FIXME: generalize & move to common area */
|
||||
adap->fe->callback = dvico_bluebird_xc2028_callback;
|
||||
|
||||
fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
|
||||
if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
|
||||
return -EIO;
|
||||
@ -615,6 +797,14 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_frontend *fe;
|
||||
fe = dvb_attach(mxl5005s_attach, adap->fe,
|
||||
&adap->dev->i2c_adap, &d680_dmb_tuner);
|
||||
return (fe == NULL) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 b;
|
||||
@ -726,6 +916,159 @@ no_IR:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dibx000_agc_config dib7070_agc_config = {
|
||||
.band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
|
||||
|
||||
/*
|
||||
* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
|
||||
* P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
|
||||
* P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
|
||||
*/
|
||||
.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
|
||||
(0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
|
||||
.inv_gain = 600,
|
||||
.time_stabiliz = 10,
|
||||
.alpha_level = 0,
|
||||
.thlock = 118,
|
||||
.wbd_inv = 0,
|
||||
.wbd_ref = 3530,
|
||||
.wbd_sel = 1,
|
||||
.wbd_alpha = 5,
|
||||
.agc1_max = 65535,
|
||||
.agc1_min = 0,
|
||||
.agc2_max = 65535,
|
||||
.agc2_min = 0,
|
||||
.agc1_pt1 = 0,
|
||||
.agc1_pt2 = 40,
|
||||
.agc1_pt3 = 183,
|
||||
.agc1_slope1 = 206,
|
||||
.agc1_slope2 = 255,
|
||||
.agc2_pt1 = 72,
|
||||
.agc2_pt2 = 152,
|
||||
.agc2_slope1 = 88,
|
||||
.agc2_slope2 = 90,
|
||||
.alpha_mant = 17,
|
||||
.alpha_exp = 27,
|
||||
.beta_mant = 23,
|
||||
.beta_exp = 51,
|
||||
.perform_agc_softsplit = 0,
|
||||
};
|
||||
|
||||
static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
|
||||
.internal = 60000,
|
||||
.sampling = 15000,
|
||||
.pll_prediv = 1,
|
||||
.pll_ratio = 20,
|
||||
.pll_range = 3,
|
||||
.pll_reset = 1,
|
||||
.pll_bypass = 0,
|
||||
.enable_refdiv = 0,
|
||||
.bypclk_div = 0,
|
||||
.IO_CLK_en_core = 1,
|
||||
.ADClkSrc = 1,
|
||||
.modulo = 2,
|
||||
/* refsel, sel, freq_15k */
|
||||
.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
|
||||
.ifreq = (0 << 25) | 0,
|
||||
.timf = 20452225,
|
||||
.xtal_hz = 12000000,
|
||||
};
|
||||
|
||||
static struct dib7000p_config cxusb_dualdig4_rev2_config = {
|
||||
.output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_config_count = 1,
|
||||
.agc = &dib7070_agc_config,
|
||||
.bw = &dib7070_bw_config_12_mhz,
|
||||
.tuner_is_baseband = 1,
|
||||
.spur_protect = 1,
|
||||
|
||||
.gpio_dir = 0xfcef,
|
||||
.gpio_val = 0x0110,
|
||||
|
||||
.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
|
||||
|
||||
.hostbus_diversity = 1,
|
||||
};
|
||||
|
||||
static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
|
||||
|
||||
cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
|
||||
|
||||
dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
|
||||
&cxusb_dualdig4_rev2_config);
|
||||
|
||||
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
|
||||
&cxusb_dualdig4_rev2_config);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
return dib7000p_set_gpio(fe, 8, 0, !onoff);
|
||||
}
|
||||
|
||||
static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dib0070_config dib7070p_dib0070_config = {
|
||||
.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
|
||||
.reset = dib7070_tuner_reset,
|
||||
.sleep = dib7070_tuner_sleep,
|
||||
.clock_khz = 12000,
|
||||
};
|
||||
|
||||
struct dib0700_adapter_state {
|
||||
int (*set_param_save) (struct dvb_frontend *,
|
||||
struct dvb_frontend_parameters *);
|
||||
};
|
||||
|
||||
static int dib7070_set_param_override(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
struct dib0700_adapter_state *state = adap->priv;
|
||||
|
||||
u16 offset;
|
||||
u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
|
||||
switch (band) {
|
||||
case BAND_VHF: offset = 950; break;
|
||||
default:
|
||||
case BAND_UHF: offset = 550; break;
|
||||
}
|
||||
|
||||
dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
|
||||
|
||||
return state->set_param_save(fe, fep);
|
||||
}
|
||||
|
||||
static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_adapter_state *st = adap->priv;
|
||||
struct i2c_adapter *tun_i2c =
|
||||
dib7000p_get_i2c_master(adap->fe,
|
||||
DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
|
||||
if (dvb_attach(dib0070_attach, adap->fe, tun_i2c,
|
||||
&dib7070p_dib0070_config) == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
st->set_param_save = adap->fe->ops.tuner_ops.set_params;
|
||||
adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
|
||||
@ -751,6 +1094,54 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct lgs8gl5_config lgs8gl5_cfg = {
|
||||
.demod_address = 0x19,
|
||||
};
|
||||
|
||||
static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap->dev;
|
||||
int n;
|
||||
|
||||
/* Select required USB configuration */
|
||||
if (usb_set_interface(d->udev, 0, 0) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
/* Unblock all USB pipes */
|
||||
usb_clear_halt(d->udev,
|
||||
usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
|
||||
usb_clear_halt(d->udev,
|
||||
usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
|
||||
usb_clear_halt(d->udev,
|
||||
usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
|
||||
|
||||
/* Drain USB pipes to avoid hang after reboot */
|
||||
for (n = 0; n < 5; n++) {
|
||||
cxusb_d680_dmb_drain_message(d);
|
||||
cxusb_d680_dmb_drain_video(d);
|
||||
msleep(200);
|
||||
}
|
||||
|
||||
/* Reset the tuner */
|
||||
if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
|
||||
err("clear tuner gpio failed");
|
||||
return -EIO;
|
||||
}
|
||||
msleep(100);
|
||||
if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
|
||||
err("set tuner gpio failed");
|
||||
return -EIO;
|
||||
}
|
||||
msleep(100);
|
||||
|
||||
/* Attach frontend */
|
||||
adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DViCO has shipped two devices with the same USB ID, but only one of them
|
||||
* needs a firmware download. Check the device class details to see if they
|
||||
@ -826,9 +1217,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
|
||||
static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
|
||||
static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
|
||||
|
||||
static int cxusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
@ -852,6 +1245,11 @@ static int cxusb_probe(struct usb_interface *intf,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf,
|
||||
&cxusb_bluebird_dualdig4_rev2_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0)
|
||||
return 0;
|
||||
|
||||
@ -876,6 +1274,8 @@ static struct usb_device_id cxusb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
|
||||
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
|
||||
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, cxusb_table);
|
||||
@ -1321,6 +1721,104 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
|
||||
}
|
||||
};
|
||||
|
||||
static
|
||||
struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
|
||||
.tuner_attach = cxusb_dualdig4_rev2_tuner_attach,
|
||||
.size_of_priv = sizeof(struct dib0700_adapter_state),
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = cxusb_bluebird_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = dvico_mce_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
|
||||
.rc_query = cxusb_rc_query,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
|
||||
{ NULL },
|
||||
{ &cxusb_table[17], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_d680_dmb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_d680_dmb_frontend_attach,
|
||||
.tuner_attach = cxusb_d680_dmb_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = cxusb_d680_dmb_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = d680_dmb_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(d680_dmb_rc_keys),
|
||||
.rc_query = cxusb_d680_dmb_rc_query,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
"Conexant DMB-TH Stick",
|
||||
{ NULL },
|
||||
{ &cxusb_table[18], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver cxusb_driver = {
|
||||
.name = "dvb_usb_cxusb",
|
||||
.probe = cxusb_probe,
|
||||
|
@ -31,6 +31,8 @@ extern int dvb_usb_dib0700_debug;
|
||||
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
|
||||
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
|
||||
#define REQUEST_SET_RC 0x11
|
||||
#define REQUEST_NEW_I2C_READ 0x12
|
||||
#define REQUEST_NEW_I2C_WRITE 0x13
|
||||
#define REQUEST_GET_VERSION 0x15
|
||||
|
||||
struct dib0700_state {
|
||||
@ -39,6 +41,8 @@ struct dib0700_state {
|
||||
u8 rc_toggle;
|
||||
u8 rc_counter;
|
||||
u8 is_dib7000pc;
|
||||
u8 fw_use_new_i2c_api;
|
||||
u8 disable_streaming_master_mode;
|
||||
};
|
||||
|
||||
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
|
||||
|
@ -82,9 +82,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C master xfer function
|
||||
* I2C master xfer function (supported in 1.20 firmware)
|
||||
*/
|
||||
static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
|
||||
static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
/* The new i2c firmware messages are more reliable and in particular
|
||||
properly support i2c read calls not preceded by a write */
|
||||
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */
|
||||
uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
|
||||
uint8_t en_start = 0;
|
||||
uint8_t en_stop = 0;
|
||||
uint8_t buf[255]; /* TBV: malloc ? */
|
||||
int result, i;
|
||||
|
||||
/* Ensure nobody else hits the i2c bus while we're sending our
|
||||
sequence of messages, (such as the remote control thread) */
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (i == 0) {
|
||||
/* First message in the transaction */
|
||||
en_start = 1;
|
||||
} else if (!(msg[i].flags & I2C_M_NOSTART)) {
|
||||
/* Device supports repeated-start */
|
||||
en_start = 1;
|
||||
} else {
|
||||
/* Not the first packet and device doesn't support
|
||||
repeated start */
|
||||
en_start = 0;
|
||||
}
|
||||
if (i == (num - 1)) {
|
||||
/* Last message in the transaction */
|
||||
en_stop = 1;
|
||||
}
|
||||
|
||||
if (msg[i].flags & I2C_M_RD) {
|
||||
/* Read request */
|
||||
u16 index, value;
|
||||
uint8_t i2c_dest;
|
||||
|
||||
i2c_dest = (msg[i].addr << 1);
|
||||
value = ((en_start << 7) | (en_stop << 6) |
|
||||
(msg[i].len & 0x3F)) << 8 | i2c_dest;
|
||||
/* I2C ctrl + FE bus; */
|
||||
index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
|
||||
|
||||
result = usb_control_msg(d->udev,
|
||||
usb_rcvctrlpipe(d->udev, 0),
|
||||
REQUEST_NEW_I2C_READ,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, msg[i].buf,
|
||||
msg[i].len,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result < 0) {
|
||||
err("i2c read error (status = %d)\n", result);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Write request */
|
||||
buf[0] = REQUEST_NEW_I2C_WRITE;
|
||||
buf[1] = (msg[i].addr << 1);
|
||||
buf[2] = (en_start << 7) | (en_stop << 6) |
|
||||
(msg[i].len & 0x3F);
|
||||
/* I2C ctrl + FE bus; */
|
||||
buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
|
||||
/* The Actual i2c payload */
|
||||
memcpy(&buf[4], msg[i].buf, msg[i].len);
|
||||
|
||||
result = usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev, 0),
|
||||
REQUEST_NEW_I2C_WRITE,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
0, 0, buf, msg[i].len + 4,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result < 0) {
|
||||
err("i2c write error (status = %d)\n", result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C master xfer function (pre-1.20 firmware)
|
||||
*/
|
||||
static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i,len;
|
||||
@ -124,6 +213,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num
|
||||
return i;
|
||||
}
|
||||
|
||||
static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct dib0700_state *st = d->priv;
|
||||
|
||||
if (st->fw_use_new_i2c_api == 1) {
|
||||
/* User running at least fw 1.20 */
|
||||
return dib0700_i2c_xfer_new(adap, msg, num);
|
||||
} else {
|
||||
/* Use legacy calls */
|
||||
return dib0700_i2c_xfer_legacy(adap, msg, num);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
@ -246,7 +350,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
|
||||
b[0] = REQUEST_ENABLE_VIDEO;
|
||||
b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
|
||||
b[2] = (0x01 << 4); /* Master mode */
|
||||
|
||||
if (st->disable_streaming_master_mode == 1)
|
||||
b[2] = 0x00;
|
||||
else
|
||||
b[2] = (0x01 << 4); /* Master mode */
|
||||
|
||||
b[3] = 0x00;
|
||||
|
||||
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "mt2060.h"
|
||||
#include "mt2266.h"
|
||||
#include "tuner-xc2028.h"
|
||||
#include "xc5000.h"
|
||||
#include "s5h1411.h"
|
||||
#include "dib0070.h"
|
||||
|
||||
static int force_lna_activation;
|
||||
@ -366,7 +368,8 @@ static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
|
||||
.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
|
||||
};
|
||||
|
||||
static int stk7700ph_xc3028_callback(void *ptr, int command, int arg)
|
||||
static int stk7700ph_xc3028_callback(void *ptr, int component,
|
||||
int command, int arg)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = ptr;
|
||||
|
||||
@ -394,7 +397,6 @@ static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
|
||||
|
||||
static struct xc2028_config stk7700ph_xc3028_config = {
|
||||
.i2c_addr = 0x61,
|
||||
.callback = stk7700ph_xc3028_callback,
|
||||
.ctrl = &stk7700ph_xc3028_ctrl,
|
||||
};
|
||||
|
||||
@ -435,7 +437,9 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
|
||||
stk7700ph_xc3028_config.i2c_adap = tun_i2c;
|
||||
stk7700ph_xc3028_config.video_dev = adap;
|
||||
|
||||
/* FIXME: generalize & move to common area */
|
||||
adap->fe->callback = stk7700ph_xc3028_callback;
|
||||
|
||||
return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config)
|
||||
== NULL ? -ENODEV : 0;
|
||||
@ -677,6 +681,43 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
|
||||
{ 0x01, 0x7d, KEY_VOLUMEDOWN },
|
||||
{ 0x02, 0x42, KEY_CHANNELUP },
|
||||
{ 0x00, 0x7d, KEY_CHANNELDOWN },
|
||||
|
||||
/* Key codes for Nova-TD "credit card" remote control. */
|
||||
{ 0x1d, 0x00, KEY_0 },
|
||||
{ 0x1d, 0x01, KEY_1 },
|
||||
{ 0x1d, 0x02, KEY_2 },
|
||||
{ 0x1d, 0x03, KEY_3 },
|
||||
{ 0x1d, 0x04, KEY_4 },
|
||||
{ 0x1d, 0x05, KEY_5 },
|
||||
{ 0x1d, 0x06, KEY_6 },
|
||||
{ 0x1d, 0x07, KEY_7 },
|
||||
{ 0x1d, 0x08, KEY_8 },
|
||||
{ 0x1d, 0x09, KEY_9 },
|
||||
{ 0x1d, 0x0a, KEY_TEXT },
|
||||
{ 0x1d, 0x0d, KEY_MENU },
|
||||
{ 0x1d, 0x0f, KEY_MUTE },
|
||||
{ 0x1d, 0x10, KEY_VOLUMEUP },
|
||||
{ 0x1d, 0x11, KEY_VOLUMEDOWN },
|
||||
{ 0x1d, 0x12, KEY_CHANNEL },
|
||||
{ 0x1d, 0x14, KEY_UP },
|
||||
{ 0x1d, 0x15, KEY_DOWN },
|
||||
{ 0x1d, 0x16, KEY_LEFT },
|
||||
{ 0x1d, 0x17, KEY_RIGHT },
|
||||
{ 0x1d, 0x1c, KEY_TV },
|
||||
{ 0x1d, 0x1e, KEY_NEXT },
|
||||
{ 0x1d, 0x1f, KEY_BACK },
|
||||
{ 0x1d, 0x20, KEY_CHANNELUP },
|
||||
{ 0x1d, 0x21, KEY_CHANNELDOWN },
|
||||
{ 0x1d, 0x24, KEY_LAST },
|
||||
{ 0x1d, 0x25, KEY_OK },
|
||||
{ 0x1d, 0x30, KEY_PAUSE },
|
||||
{ 0x1d, 0x32, KEY_REWIND },
|
||||
{ 0x1d, 0x34, KEY_FASTFORWARD },
|
||||
{ 0x1d, 0x35, KEY_PLAY },
|
||||
{ 0x1d, 0x36, KEY_STOP },
|
||||
{ 0x1d, 0x37, KEY_RECORD },
|
||||
{ 0x1d, 0x3b, KEY_GOTO },
|
||||
{ 0x1d, 0x3d, KEY_POWER },
|
||||
};
|
||||
|
||||
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
|
||||
@ -1078,6 +1119,97 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
|
||||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* S5H1411 */
|
||||
static struct s5h1411_config pinnacle_801e_config = {
|
||||
.output_mode = S5H1411_PARALLEL_OUTPUT,
|
||||
.gpio = S5H1411_GPIO_OFF,
|
||||
.mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
|
||||
.qam_if = S5H1411_IF_44000,
|
||||
.vsb_if = S5H1411_IF_44000,
|
||||
.inversion = S5H1411_INVERSION_OFF,
|
||||
.status_mode = S5H1411_DEMODLOCKING
|
||||
};
|
||||
|
||||
/* Pinnacle PCTV HD Pro 801e GPIOs map:
|
||||
GPIO0 - currently unknown
|
||||
GPIO1 - xc5000 tuner reset
|
||||
GPIO2 - CX25843 sleep
|
||||
GPIO3 - currently unknown
|
||||
GPIO4 - currently unknown
|
||||
GPIO6 - currently unknown
|
||||
GPIO7 - currently unknown
|
||||
GPIO9 - currently unknown
|
||||
GPIO10 - CX25843 reset
|
||||
*/
|
||||
static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
|
||||
/* Make use of the new i2c functions from FW 1.20 */
|
||||
st->fw_use_new_i2c_api = 1;
|
||||
|
||||
/* The s5h1411 requires the dib0700 to not be in master mode */
|
||||
st->disable_streaming_master_mode = 1;
|
||||
|
||||
/* All msleep values taken from Windows USB trace */
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
|
||||
dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0);
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
|
||||
msleep(400);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
|
||||
msleep(60);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
|
||||
msleep(30);
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0);
|
||||
msleep(30);
|
||||
|
||||
/* Put the CX25843 to sleep for now since we're in digital mode */
|
||||
dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
|
||||
|
||||
/* GPIOs are initialized, do the attach */
|
||||
adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config,
|
||||
&adap->dev->i2c_adap);
|
||||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int dib0700_xc5000_tuner_callback(void *priv, int component,
|
||||
int command, int arg)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = priv;
|
||||
|
||||
if (command == XC5000_TUNER_RESET) {
|
||||
/* Reset the tuner */
|
||||
dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
|
||||
msleep(330); /* from Windows USB trace */
|
||||
dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
|
||||
msleep(330); /* from Windows USB trace */
|
||||
} else {
|
||||
err("xc5000: unknown tuner callback command: %d\n", command);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xc5000_config s5h1411_xc5000_tunerconfig = {
|
||||
.i2c_address = 0x64,
|
||||
.if_khz = 5380,
|
||||
};
|
||||
|
||||
static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
/* FIXME: generalize & move to common area */
|
||||
adap->fe->callback = dib0700_xc5000_tuner_callback;
|
||||
|
||||
return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap,
|
||||
&s5h1411_xc5000_tunerconfig)
|
||||
== NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB-USB and USB stuff follows */
|
||||
struct usb_device_id dib0700_usb_id_table[] = {
|
||||
/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
|
||||
@ -1119,6 +1251,11 @@ struct usb_device_id dib0700_usb_id_table[] = {
|
||||
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
|
||||
/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
|
||||
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
|
||||
{ USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) },
|
||||
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) },
|
||||
{ USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) },
|
||||
/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) },
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) },
|
||||
{ 0 } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
@ -1126,7 +1263,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER, \
|
||||
.usb_ctrl = DEVICE_SPECIFIC, \
|
||||
.firmware = "dvb-usb-dib0700-1.10.fw", \
|
||||
.firmware = "dvb-usb-dib0700-1.20.fw", \
|
||||
.download_firmware = dib0700_download_firmware, \
|
||||
.no_reconnect = 1, \
|
||||
.size_of_priv = sizeof(struct dib0700_state), \
|
||||
@ -1293,7 +1430,12 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
||||
{ &dib0700_usb_id_table[31], NULL },
|
||||
{ NULL },
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
||||
.num_adapters = 1,
|
||||
@ -1408,7 +1550,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 3,
|
||||
.num_device_descs = 5,
|
||||
.devices = {
|
||||
{ "Terratec Cinergy HT USB XE",
|
||||
{ &dib0700_usb_id_table[27], NULL },
|
||||
@ -1422,6 +1564,47 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
||||
{ &dib0700_usb_id_table[32], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Gigabyte U8000-RH",
|
||||
{ &dib0700_usb_id_table[37], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "YUAN High-Tech STK7700PH",
|
||||
{ &dib0700_usb_id_table[38], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Asus My Cinema-U3000Hybrid",
|
||||
{ &dib0700_usb_id_table[39], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
|
||||
.rc_query = dib0700_rc_query
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = s5h1411_frontend_attach,
|
||||
.tuner_attach = xc5000_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
|
||||
.size_of_priv = sizeof(struct
|
||||
dib0700_adapter_state),
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "Pinnacle PCTV HD Pro USB Stick",
|
||||
{ &dib0700_usb_id_table[40], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Pinnacle PCTV HD USB Stick",
|
||||
{ &dib0700_usb_id_table[41], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
|
240
drivers/media/dvb/dvb-usb/dtv5100.c
Normal file
240
drivers/media/dvb/dvb-usb/dtv5100.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
|
||||
*
|
||||
* Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com>
|
||||
* http://royale.zerezo.com/dtv5100/
|
||||
*
|
||||
* Inspired by gl861.c and au6610.c drivers
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dtv5100.h"
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_dtv5100_debug;
|
||||
module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u8 request;
|
||||
u8 type;
|
||||
u16 value;
|
||||
u16 index;
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
/* write { reg }, read { value } */
|
||||
request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
|
||||
DTV5100_TUNER_READ);
|
||||
type = USB_TYPE_VENDOR | USB_DIR_IN;
|
||||
value = 0;
|
||||
break;
|
||||
case 2:
|
||||
/* write { reg, value } */
|
||||
request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
|
||||
DTV5100_TUNER_WRITE);
|
||||
type = USB_TYPE_VENDOR | USB_DIR_OUT;
|
||||
value = wbuf[1];
|
||||
break;
|
||||
default:
|
||||
warn("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
index = (addr << 8) + wbuf[0];
|
||||
|
||||
msleep(1); /* avoid I2C errors */
|
||||
return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
|
||||
type, value, index, rbuf, rlen,
|
||||
DTV5100_USB_TIMEOUT);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf,
|
||||
msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm dtv5100_i2c_algo = {
|
||||
.master_xfer = dtv5100_i2c_xfer,
|
||||
.functionality = dtv5100_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct zl10353_config dtv5100_zl10353_config = {
|
||||
.demod_address = DTV5100_DEMOD_ADDR,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
/* disable i2c gate, or it won't work... is this safe? */
|
||||
adap->fe->ops.i2c_gate_ctrl = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config dtv5100_qt1010_config = {
|
||||
.i2c_address = DTV5100_TUNER_ADDR
|
||||
};
|
||||
|
||||
static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe, &adap->dev->i2c_adap,
|
||||
&dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties dtv5100_properties;
|
||||
|
||||
static int dtv5100_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int i, ret;
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
/* initialize non qt1010/zl10353 part? */
|
||||
for (i = 0; dtv5100_init[i].request; i++) {
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
dtv5100_init[i].request,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
dtv5100_init[i].value,
|
||||
dtv5100_init[i].index, NULL, 0,
|
||||
DTV5100_USB_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dvb_usb_device_init(intf, &dtv5100_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_device_id dtv5100_table[] = {
|
||||
{ USB_DEVICE(0x06be, 0xa232) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dtv5100_table);
|
||||
|
||||
static struct dvb_usb_device_properties dtv5100_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
.frontend_attach = dtv5100_frontend_attach,
|
||||
.tuner_attach = dtv5100_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
} },
|
||||
|
||||
.i2c_algo = &dtv5100_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
.name = "AME DTV-5100 USB2.0 DVB-T",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &dtv5100_table[0], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver dtv5100_driver = {
|
||||
.name = "dvb_usb_dtv5100",
|
||||
.probe = dtv5100_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dtv5100_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init dtv5100_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_register(&dtv5100_driver);
|
||||
if (ret)
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit dtv5100_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&dtv5100_driver);
|
||||
}
|
||||
|
||||
module_init(dtv5100_module_init);
|
||||
module_exit(dtv5100_module_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
51
drivers/media/dvb/dvb-usb/dtv5100.h
Normal file
51
drivers/media/dvb/dvb-usb/dtv5100.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
|
||||
*
|
||||
* Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com>
|
||||
* http://royale.zerezo.com/dtv5100/
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _DVB_USB_DTV5100_H_
|
||||
#define _DVB_USB_DTV5100_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dtv5100"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define DTV5100_USB_TIMEOUT 500
|
||||
|
||||
#define DTV5100_DEMOD_ADDR 0x00
|
||||
#define DTV5100_DEMOD_WRITE 0xc0
|
||||
#define DTV5100_DEMOD_READ 0xc1
|
||||
|
||||
#define DTV5100_TUNER_ADDR 0xc4
|
||||
#define DTV5100_TUNER_WRITE 0xc7
|
||||
#define DTV5100_TUNER_READ 0xc8
|
||||
|
||||
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
|
||||
#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T"
|
||||
|
||||
static struct {
|
||||
u8 request;
|
||||
u8 value;
|
||||
u16 index;
|
||||
} dtv5100_init[] = {
|
||||
{ 0x000000c5, 0x00000000, 0x00000001 },
|
||||
{ 0x000000c5, 0x00000001, 0x00000001 },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
#endif
|
@ -22,6 +22,7 @@
|
||||
#define USB_VID_AVERMEDIA 0x07ca
|
||||
#define USB_VID_COMPRO 0x185b
|
||||
#define USB_VID_COMPRO_UNK 0x145f
|
||||
#define USB_VID_CONEXANT 0x0572
|
||||
#define USB_VID_CYPRESS 0x04b4
|
||||
#define USB_VID_DIBCOM 0x10b8
|
||||
#define USB_VID_DPOSH 0x1498
|
||||
@ -33,16 +34,19 @@
|
||||
#define USB_VID_HAUPPAUGE 0x2040
|
||||
#define USB_VID_HYPER_PALTEK 0x1025
|
||||
#define USB_VID_KWORLD 0xeb2a
|
||||
#define USB_VID_KWORLD_2 0x1b80
|
||||
#define USB_VID_KYE 0x0458
|
||||
#define USB_VID_LEADTEK 0x0413
|
||||
#define USB_VID_LITEON 0x04ca
|
||||
#define USB_VID_MEDION 0x1660
|
||||
#define USB_VID_MIGLIA 0x18f3
|
||||
#define USB_VID_MSI 0x0db0
|
||||
#define USB_VID_MSI_2 0x1462
|
||||
#define USB_VID_OPERA1 0x695c
|
||||
#define USB_VID_PINNACLE 0x2304
|
||||
#define USB_VID_TECHNOTREND 0x0b48
|
||||
#define USB_VID_TERRATEC 0x0ccd
|
||||
#define USB_VID_TELESTAR 0x10b9
|
||||
#define USB_VID_VISIONPLUS 0x13d3
|
||||
#define USB_VID_TWINHAN 0x1822
|
||||
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
|
||||
@ -50,15 +54,18 @@
|
||||
#define USB_VID_WIDEVIEW 0x14aa
|
||||
#define USB_VID_GIGABYTE 0x1044
|
||||
#define USB_VID_YUAN 0x1164
|
||||
|
||||
#define USB_VID_XTENSIONS 0x1ae7
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
#define USB_PID_ADSTECH_USB2_WARM 0xa334
|
||||
#define USB_PID_AFATECH_AF9005 0x9020
|
||||
#define USB_PID_AFATECH_AF9015_9015 0x9015
|
||||
#define USB_PID_AFATECH_AF9015_9016 0x9016
|
||||
#define USB_VID_ALINK_DTU 0xf170
|
||||
#define USB_PID_ANSONIC_DVBT_USB 0x6000
|
||||
#define USB_PID_ANYSEE 0x861f
|
||||
#define USB_PID_AZUREWAVE_AD_TU700 0x3237
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
|
||||
@ -69,6 +76,7 @@
|
||||
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
|
||||
#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78
|
||||
#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80
|
||||
#define USB_PID_CONEXANT_D680_DMB 0x86d6
|
||||
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
|
||||
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
|
||||
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
|
||||
@ -87,9 +95,12 @@
|
||||
#define USB_PID_UNIWILL_STK7700P 0x6003
|
||||
#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_PC160_2T 0xc160
|
||||
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
|
||||
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
|
||||
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
|
||||
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
|
||||
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
|
||||
@ -98,6 +109,7 @@
|
||||
#define USB_PID_TWINHAN_VP7045_WARM 0x3206
|
||||
#define USB_PID_TWINHAN_VP7021_COLD 0x3207
|
||||
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
|
||||
#define USB_PID_TINYTWIN 0x3226
|
||||
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
|
||||
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
|
||||
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
|
||||
@ -144,6 +156,9 @@
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039
|
||||
#define USB_PID_AVERMEDIA_VOLAR_X 0xa815
|
||||
#define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150
|
||||
#define USB_PID_AVERMEDIA_A309 0xa309
|
||||
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
|
||||
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
|
||||
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
|
||||
@ -153,8 +168,11 @@
|
||||
#define USB_PID_PINNACLE_PCTV2000E 0x022c
|
||||
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
|
||||
#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229
|
||||
#define USB_PID_PINNACLE_PCTV71E 0x022b
|
||||
#define USB_PID_PINNACLE_PCTV72E 0x0236
|
||||
#define USB_PID_PINNACLE_PCTV73E 0x0237
|
||||
#define USB_PID_PINNACLE_PCTV801E 0x023a
|
||||
#define USB_PID_PINNACLE_PCTV801E_SE 0x023b
|
||||
#define USB_PID_PCTV_200E 0x020e
|
||||
#define USB_PID_PCTV_400E 0x020f
|
||||
#define USB_PID_PCTV_450E 0x0222
|
||||
@ -171,6 +189,7 @@
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98
|
||||
#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70
|
||||
#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71
|
||||
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
|
||||
@ -190,6 +209,7 @@
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029
|
||||
#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
|
||||
#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201
|
||||
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
|
||||
@ -197,14 +217,21 @@
|
||||
#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
|
||||
#define USB_PID_SIGMATEK_DVB_110 0x6610
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
|
||||
#define USB_PID_MSI_DIGIVOX_DUO 0x8801
|
||||
#define USB_PID_OPERA1_COLD 0x2830
|
||||
#define USB_PID_OPERA1_WARM 0x3829
|
||||
#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514
|
||||
#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513
|
||||
#define USB_PID_GIGABYTE_U7000 0x7001
|
||||
#define USB_PID_GIGABYTE_U8000 0x7002
|
||||
#define USB_PID_ASUS_U3000 0x171f
|
||||
#define USB_PID_ASUS_U3000H 0x1736
|
||||
#define USB_PID_ASUS_U3100 0x173f
|
||||
#define USB_PID_YUAN_EC372S 0x1edc
|
||||
#define USB_PID_YUAN_STK7700PH 0x1f08
|
||||
#define USB_PID_DW2102 0x2102
|
||||
#define USB_PID_XTENSIONS_XD_380 0x0381
|
||||
#define USB_PID_TELESTAR_STARSTICK_2 0x8000
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card
|
||||
/* DVB USB framework compliant Linux driver for the
|
||||
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
|
||||
*
|
||||
* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
|
||||
*
|
||||
@ -10,62 +11,74 @@
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include "dw2102.h"
|
||||
#include "si21xx.h"
|
||||
#include "stv0299.h"
|
||||
#include "z0194a.h"
|
||||
#include "stv0288.h"
|
||||
#include "stb6000.h"
|
||||
#include "eds1547.h"
|
||||
#include "cx24116.h"
|
||||
|
||||
#ifndef USB_PID_DW2102
|
||||
#define USB_PID_DW2102 0x2102
|
||||
#endif
|
||||
|
||||
#define DW2102_READ_MSG 0
|
||||
#define DW2102_WRITE_MSG 1
|
||||
#ifndef USB_PID_DW2104
|
||||
#define USB_PID_DW2104 0x2104
|
||||
#endif
|
||||
|
||||
#define DW210X_READ_MSG 0
|
||||
#define DW210X_WRITE_MSG 1
|
||||
|
||||
#define REG_1F_SYMBOLRATE_BYTE0 0x1f
|
||||
#define REG_20_SYMBOLRATE_BYTE1 0x20
|
||||
#define REG_21_SYMBOLRATE_BYTE2 0x21
|
||||
|
||||
/* on my own*/
|
||||
#define DW2102_VOLTAGE_CTRL (0x1800)
|
||||
#define DW2102_RC_QUERY (0x1a00)
|
||||
|
||||
struct dw2102_state {
|
||||
struct dw210x_state {
|
||||
u32 last_key_pressed;
|
||||
};
|
||||
struct dw2102_rc_keys {
|
||||
struct dw210x_rc_keys {
|
||||
u32 keycode;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_dw2102_debug;
|
||||
module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value,
|
||||
u8 *data, u16 len, int flags)
|
||||
static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
|
||||
u16 index, u8 * data, u16 len, int flags)
|
||||
{
|
||||
int ret;
|
||||
u8 u8buf[len];
|
||||
|
||||
unsigned int pipe = (flags == DW2102_READ_MSG) ?
|
||||
usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
|
||||
u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
|
||||
unsigned int pipe = (flags == DW210X_READ_MSG) ?
|
||||
usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
|
||||
u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
|
||||
|
||||
if (flags == DW2102_WRITE_MSG)
|
||||
if (flags == DW210X_WRITE_MSG)
|
||||
memcpy(u8buf, data, len);
|
||||
ret = usb_control_msg(dev, pipe, request,
|
||||
request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000);
|
||||
ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
|
||||
value, index , u8buf, len, 2000);
|
||||
|
||||
if (flags == DW2102_READ_MSG)
|
||||
if (flags == DW210X_READ_MSG)
|
||||
memcpy(data, u8buf, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
|
||||
static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i = 0, ret = 0;
|
||||
u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
|
||||
u8 request;
|
||||
u16 value;
|
||||
|
||||
if (!d)
|
||||
@ -76,14 +89,12 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
switch (num) {
|
||||
case 2:
|
||||
/* read stv0299 register */
|
||||
request = 0xb5;
|
||||
value = msg[0].buf[0];/* register */
|
||||
for (i = 0; i < msg[1].len; i++) {
|
||||
value = value + i;
|
||||
ret = dw2102_op_rw(d->udev, 0xb5,
|
||||
value, buf6, 2, DW2102_READ_MSG);
|
||||
ret = dw210x_op_rw(d->udev, 0xb5, value, 0,
|
||||
buf6, 2, DW210X_READ_MSG);
|
||||
msg[1].buf[i] = buf6[0];
|
||||
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@ -93,8 +104,8 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
buf6[0] = 0x2a;
|
||||
buf6[1] = msg[0].buf[0];
|
||||
buf6[2] = msg[0].buf[1];
|
||||
ret = dw2102_op_rw(d->udev, 0xb2,
|
||||
0, buf6, 3, DW2102_WRITE_MSG);
|
||||
ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
|
||||
buf6, 3, DW210X_WRITE_MSG);
|
||||
break;
|
||||
case 0x60:
|
||||
if (msg[0].flags == 0) {
|
||||
@ -106,26 +117,26 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
buf6[4] = msg[0].buf[1];
|
||||
buf6[5] = msg[0].buf[2];
|
||||
buf6[6] = msg[0].buf[3];
|
||||
ret = dw2102_op_rw(d->udev, 0xb2,
|
||||
0, buf6, 7, DW2102_WRITE_MSG);
|
||||
ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
|
||||
buf6, 7, DW210X_WRITE_MSG);
|
||||
} else {
|
||||
/* write to tuner pll */
|
||||
ret = dw2102_op_rw(d->udev, 0xb5,
|
||||
0, buf6, 1, DW2102_READ_MSG);
|
||||
/* read from tuner */
|
||||
ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
|
||||
buf6, 1, DW210X_READ_MSG);
|
||||
msg[0].buf[0] = buf6[0];
|
||||
}
|
||||
break;
|
||||
case (DW2102_RC_QUERY):
|
||||
ret = dw2102_op_rw(d->udev, 0xb8,
|
||||
0, buf6, 2, DW2102_READ_MSG);
|
||||
ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
|
||||
buf6, 2, DW210X_READ_MSG);
|
||||
msg[0].buf[0] = buf6[0];
|
||||
msg[0].buf[1] = buf6[1];
|
||||
break;
|
||||
case (DW2102_VOLTAGE_CTRL):
|
||||
buf6[0] = 0x30;
|
||||
buf6[1] = msg[0].buf[0];
|
||||
ret = dw2102_op_rw(d->udev, 0xb2,
|
||||
0, buf6, 2, DW2102_WRITE_MSG);
|
||||
ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
|
||||
buf6, 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -136,17 +147,265 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 dw2102_i2c_func(struct i2c_adapter *adapter)
|
||||
static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msg[], int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret = 0;
|
||||
u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
switch (num) {
|
||||
case 2:
|
||||
/* read si2109 register by number */
|
||||
buf6[0] = 0xd0;
|
||||
buf6[1] = msg[0].len;
|
||||
buf6[2] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
buf6, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
/* read si2109 register */
|
||||
ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
|
||||
buf6, msg[1].len + 2, DW210X_READ_MSG);
|
||||
memcpy(msg[1].buf, buf6 + 2, msg[1].len);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
switch (msg[0].addr) {
|
||||
case 0x68:
|
||||
/* write to si2109 register */
|
||||
buf6[0] = 0xd0;
|
||||
buf6[1] = msg[0].len;
|
||||
memcpy(buf6 + 2, msg[0].buf, msg[0].len);
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
|
||||
msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
case(DW2102_RC_QUERY):
|
||||
ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
|
||||
buf6, 2, DW210X_READ_MSG);
|
||||
msg[0].buf[0] = buf6[0];
|
||||
msg[0].buf[1] = buf6[1];
|
||||
break;
|
||||
case(DW2102_VOLTAGE_CTRL):
|
||||
buf6[0] = 0x30;
|
||||
buf6[1] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
|
||||
buf6, 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return num;
|
||||
}
|
||||
static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret = 0;
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
switch (num) {
|
||||
case 2: {
|
||||
/* read */
|
||||
/* first write first register number */
|
||||
u8 ibuf [msg[1].len + 2], obuf[3];
|
||||
obuf[0] = 0xd0;
|
||||
obuf[1] = msg[0].len;
|
||||
obuf[2] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
/* second read registers */
|
||||
ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
|
||||
ibuf, msg[1].len + 2, DW210X_READ_MSG);
|
||||
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
switch (msg[0].addr) {
|
||||
case 0x68: {
|
||||
/* write to register */
|
||||
u8 obuf[msg[0].len + 2];
|
||||
obuf[0] = 0xd0;
|
||||
obuf[1] = msg[0].len;
|
||||
memcpy(obuf + 2, msg[0].buf, msg[0].len);
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
case 0x61: {
|
||||
/* write to tuner */
|
||||
u8 obuf[msg[0].len + 2];
|
||||
obuf[0] = 0xc2;
|
||||
obuf[1] = msg[0].len;
|
||||
memcpy(obuf + 2, msg[0].buf, msg[0].len);
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
case(DW2102_RC_QUERY): {
|
||||
u8 ibuf[2];
|
||||
ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
|
||||
ibuf, 2, DW210X_READ_MSG);
|
||||
memcpy(msg[0].buf, ibuf , 2);
|
||||
break;
|
||||
}
|
||||
case(DW2102_VOLTAGE_CTRL): {
|
||||
u8 obuf[2];
|
||||
obuf[0] = 0x30;
|
||||
obuf[1] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
|
||||
obuf, 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return num;
|
||||
}
|
||||
|
||||
static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret = 0;
|
||||
int len, i;
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
switch (num) {
|
||||
case 2: {
|
||||
/* read */
|
||||
/* first write first register number */
|
||||
u8 ibuf [msg[1].len + 2], obuf[3];
|
||||
obuf[0] = 0xaa;
|
||||
obuf[1] = msg[0].len;
|
||||
obuf[2] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
/* second read registers */
|
||||
ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0,
|
||||
ibuf, msg[1].len + 2, DW210X_READ_MSG);
|
||||
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
switch (msg[0].addr) {
|
||||
case 0x55: {
|
||||
if (msg[0].buf[0] == 0xf7) {
|
||||
/* firmware */
|
||||
/* Write in small blocks */
|
||||
u8 obuf[19];
|
||||
obuf[0] = 0xaa;
|
||||
obuf[1] = 0x11;
|
||||
obuf[2] = 0xf7;
|
||||
len = msg[0].len - 1;
|
||||
i = 1;
|
||||
do {
|
||||
memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len));
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG);
|
||||
i += 16;
|
||||
len -= 16;
|
||||
} while (len > 0);
|
||||
} else {
|
||||
/* write to register */
|
||||
u8 obuf[msg[0].len + 2];
|
||||
obuf[0] = 0xaa;
|
||||
obuf[1] = msg[0].len;
|
||||
memcpy(obuf + 2, msg[0].buf, msg[0].len);
|
||||
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
|
||||
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case(DW2102_RC_QUERY): {
|
||||
u8 ibuf[2];
|
||||
ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
|
||||
ibuf, 2, DW210X_READ_MSG);
|
||||
memcpy(msg[0].buf, ibuf , 2);
|
||||
break;
|
||||
}
|
||||
case(DW2102_VOLTAGE_CTRL): {
|
||||
u8 obuf[2];
|
||||
obuf[0] = 0x30;
|
||||
obuf[1] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
|
||||
obuf, 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm dw2102_i2c_algo = {
|
||||
.master_xfer = dw2102_i2c_transfer,
|
||||
.functionality = dw2102_i2c_func,
|
||||
.functionality = dw210x_i2c_func,
|
||||
};
|
||||
|
||||
static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
static struct i2c_algorithm dw2102_serit_i2c_algo = {
|
||||
.master_xfer = dw2102_serit_i2c_transfer,
|
||||
.functionality = dw210x_i2c_func,
|
||||
};
|
||||
|
||||
static struct i2c_algorithm dw2102_earda_i2c_algo = {
|
||||
.master_xfer = dw2102_earda_i2c_transfer,
|
||||
.functionality = dw210x_i2c_func,
|
||||
};
|
||||
|
||||
static struct i2c_algorithm dw2104_i2c_algo = {
|
||||
.master_xfer = dw2104_i2c_transfer,
|
||||
.functionality = dw210x_i2c_func,
|
||||
};
|
||||
|
||||
static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
int i;
|
||||
u8 ibuf[] = {0, 0};
|
||||
u8 eeprom[256], eepromline[16];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
|
||||
err("read eeprom failed.");
|
||||
return -1;
|
||||
} else {
|
||||
eepromline[i%16] = ibuf[0];
|
||||
eeprom[i] = ibuf[0];
|
||||
}
|
||||
if ((i % 16) == 15) {
|
||||
deb_xfer("%02x: ", i - 15);
|
||||
debug_dump(eepromline, 16, deb_xfer);
|
||||
}
|
||||
}
|
||||
memcpy(mac, eeprom + 8, 6);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
static u8 command_13v[1] = {0x00};
|
||||
static u8 command_18v[1] = {0x01};
|
||||
@ -163,14 +422,62 @@ static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cx24116_config dw2104_config = {
|
||||
.demod_address = 0x55,
|
||||
.mpg_clk_pos_pol = 0x01,
|
||||
};
|
||||
|
||||
static struct si21xx_config serit_sp1511lhb_config = {
|
||||
.demod_address = 0x68,
|
||||
.min_delay_ms = 100,
|
||||
|
||||
};
|
||||
|
||||
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
|
||||
&d->dev->i2c_adap)) != NULL) {
|
||||
d->fe->ops.set_voltage = dw210x_set_voltage;
|
||||
info("Attached cx24116!\n");
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties dw2102_properties;
|
||||
|
||||
static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
|
||||
&d->dev->i2c_adap);
|
||||
if (d->fe != NULL) {
|
||||
d->fe->ops.set_voltage = dw2102_set_voltage;
|
||||
info("Attached stv0299!\n");
|
||||
return 0;
|
||||
if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
|
||||
/*dw2102_properties.adapter->tuner_attach = NULL;*/
|
||||
d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
|
||||
&d->dev->i2c_adap);
|
||||
if (d->fe != NULL) {
|
||||
d->fe->ops.set_voltage = dw210x_set_voltage;
|
||||
info("Attached si21xx!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
|
||||
/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
|
||||
d->fe = dvb_attach(stv0288_attach, &earda_config,
|
||||
&d->dev->i2c_adap);
|
||||
if (d->fe != NULL) {
|
||||
d->fe->ops.set_voltage = dw210x_set_voltage;
|
||||
info("Attached stv0288!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
|
||||
/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
|
||||
d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
|
||||
&d->dev->i2c_adap);
|
||||
if (d->fe != NULL) {
|
||||
d->fe->ops.set_voltage = dw210x_set_voltage;
|
||||
info("Attached stv0299!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
@ -182,7 +489,15 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key dw2102_rc_keys[] = {
|
||||
static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(stb6000_attach, adap->fe, 0x61,
|
||||
&adap->dev->i2c_adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key dw210x_rc_keys[] = {
|
||||
{ 0xf8, 0x0a, KEY_Q }, /*power*/
|
||||
{ 0xf8, 0x0c, KEY_M }, /*mute*/
|
||||
{ 0xf8, 0x11, KEY_1 },
|
||||
@ -221,7 +536,7 @@ static struct dvb_usb_rc_key dw2102_rc_keys[] = {
|
||||
|
||||
static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct dw2102_state *st = d->priv;
|
||||
struct dw210x_state *st = d->priv;
|
||||
u8 key[2];
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
|
||||
@ -231,12 +546,12 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
|
||||
for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) {
|
||||
if (dw2102_rc_keys[i].data == msg[0].buf[0]) {
|
||||
for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
|
||||
if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = dw2102_rc_keys[i].event;
|
||||
*event = dw210x_rc_keys[i].event;
|
||||
st->last_key_pressed =
|
||||
dw2102_rc_keys[i].event;
|
||||
dw210x_rc_keys[i].event;
|
||||
break;
|
||||
}
|
||||
st->last_key_pressed = 0;
|
||||
@ -249,6 +564,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
static struct usb_device_id dw2102_table[] = {
|
||||
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
|
||||
{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
|
||||
{USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
|
||||
{USB_DEVICE(0x9022, 0xd650)},
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -260,7 +577,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
|
||||
u8 *b, *p;
|
||||
int ret = 0, i;
|
||||
u8 reset;
|
||||
u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0};
|
||||
u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
const struct firmware *fw;
|
||||
const char *filename = "dvb-usb-dw2101.fw";
|
||||
switch (dev->descriptor.idProduct) {
|
||||
@ -273,25 +590,23 @@ static int dw2102_load_firmware(struct usb_device *dev,
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case USB_PID_DW2102:
|
||||
default:
|
||||
fw = frmwr;
|
||||
break;
|
||||
}
|
||||
info("start downloading DW2102 firmware");
|
||||
info("start downloading DW210X firmware");
|
||||
p = kmalloc(fw->size, GFP_KERNEL);
|
||||
reset = 1;
|
||||
/*stop the CPU*/
|
||||
dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG);
|
||||
dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG);
|
||||
dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
|
||||
dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
|
||||
|
||||
if (p != NULL) {
|
||||
memcpy(p, fw->data, fw->size);
|
||||
for (i = 0; i < fw->size; i += 0x40) {
|
||||
b = (u8 *) p + i;
|
||||
if (dw2102_op_rw
|
||||
(dev, 0xa0, i, b , 0x40,
|
||||
DW2102_WRITE_MSG) != 0x40
|
||||
) {
|
||||
if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
|
||||
DW210X_WRITE_MSG) != 0x40) {
|
||||
err("error while transferring firmware");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
@ -299,43 +614,66 @@ static int dw2102_load_firmware(struct usb_device *dev,
|
||||
}
|
||||
/* restart the CPU */
|
||||
reset = 0;
|
||||
if (ret || dw2102_op_rw
|
||||
(dev, 0xa0, 0x7f92, &reset, 1,
|
||||
DW2102_WRITE_MSG) != 1) {
|
||||
if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
|
||||
DW210X_WRITE_MSG) != 1) {
|
||||
err("could not restart the USB controller CPU.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
if (ret || dw2102_op_rw
|
||||
(dev, 0xa0, 0xe600, &reset, 1,
|
||||
DW2102_WRITE_MSG) != 1) {
|
||||
if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
|
||||
DW210X_WRITE_MSG) != 1) {
|
||||
err("could not restart the USB controller CPU.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
/* init registers */
|
||||
switch (dev->descriptor.idProduct) {
|
||||
case USB_PID_DW2102:
|
||||
dw2102_op_rw
|
||||
(dev, 0xbf, 0x0040, &reset, 0,
|
||||
DW2102_WRITE_MSG);
|
||||
dw2102_op_rw
|
||||
(dev, 0xb9, 0x0000, &reset16[0], 2,
|
||||
DW2102_READ_MSG);
|
||||
case USB_PID_DW2104:
|
||||
case 0xd650:
|
||||
reset = 1;
|
||||
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
|
||||
DW210X_WRITE_MSG);
|
||||
reset = 0;
|
||||
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
|
||||
DW210X_WRITE_MSG);
|
||||
break;
|
||||
case USB_PID_DW2102:
|
||||
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
|
||||
DW210X_WRITE_MSG);
|
||||
dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
|
||||
DW210X_READ_MSG);
|
||||
/* check STV0299 frontend */
|
||||
dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
|
||||
DW210X_READ_MSG);
|
||||
if (reset16[0] == 0xa1) {
|
||||
dw2102_properties.i2c_algo = &dw2102_i2c_algo;
|
||||
dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
|
||||
break;
|
||||
} else {
|
||||
/* check STV0288 frontend */
|
||||
reset16[0] = 0xd0;
|
||||
reset16[1] = 1;
|
||||
reset16[2] = 0;
|
||||
dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
|
||||
DW210X_WRITE_MSG);
|
||||
dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
|
||||
DW210X_READ_MSG);
|
||||
if (reset16[2] == 0x11) {
|
||||
dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
|
||||
dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 0x2101:
|
||||
dw2102_op_rw
|
||||
(dev, 0xbc, 0x0030, &reset16[0], 2,
|
||||
DW2102_READ_MSG);
|
||||
dw2102_op_rw
|
||||
(dev, 0xba, 0x0000, &reset16[0], 7,
|
||||
DW2102_READ_MSG);
|
||||
dw2102_op_rw
|
||||
(dev, 0xba, 0x0000, &reset16[0], 7,
|
||||
DW2102_READ_MSG);
|
||||
dw2102_op_rw
|
||||
(dev, 0xb9, 0x0000, &reset16[0], 2,
|
||||
DW2102_READ_MSG);
|
||||
dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
|
||||
DW210X_READ_MSG);
|
||||
dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
|
||||
DW210X_READ_MSG);
|
||||
dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
|
||||
DW210X_READ_MSG);
|
||||
dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
|
||||
DW210X_READ_MSG);
|
||||
break;
|
||||
}
|
||||
msleep(100);
|
||||
kfree(p);
|
||||
}
|
||||
return ret;
|
||||
@ -345,12 +683,12 @@ static struct dvb_usb_device_properties dw2102_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-dw2102.fw",
|
||||
.size_of_priv = sizeof(struct dw2102_state),
|
||||
.size_of_priv = sizeof(struct dw210x_state),
|
||||
.no_reconnect = 1,
|
||||
|
||||
.i2c_algo = &dw2102_i2c_algo,
|
||||
.rc_key_map = dw2102_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys),
|
||||
.i2c_algo = &dw2102_serit_i2c_algo,
|
||||
.rc_key_map = dw210x_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
|
||||
.rc_interval = 150,
|
||||
.rc_query = dw2102_rc_query,
|
||||
|
||||
@ -358,11 +696,12 @@ static struct dvb_usb_device_properties dw2102_properties = {
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.num_adapters = 1,
|
||||
.download_firmware = dw2102_load_firmware,
|
||||
.adapter = {
|
||||
.read_mac_address = dw210x_read_mac_address,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = dw2102_frontend_attach,
|
||||
.streaming_ctrl = NULL,
|
||||
.tuner_attach = dw2102_tuner_attach,
|
||||
.tuner_attach = NULL,
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
@ -388,11 +727,64 @@ static struct dvb_usb_device_properties dw2102_properties = {
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties dw2104_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-dw2104.fw",
|
||||
.size_of_priv = sizeof(struct dw210x_state),
|
||||
.no_reconnect = 1,
|
||||
|
||||
.i2c_algo = &dw2104_i2c_algo,
|
||||
.rc_key_map = dw210x_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
|
||||
.rc_interval = 150,
|
||||
.rc_query = dw2102_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x81,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.num_adapters = 1,
|
||||
.download_firmware = dw2102_load_firmware,
|
||||
.read_mac_address = dw210x_read_mac_address,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = dw2104_frontend_attach,
|
||||
.streaming_ctrl = NULL,
|
||||
/*.tuner_attach = dw2104_tuner_attach,*/
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "DVBWorld DW2104 USB2.0",
|
||||
{&dw2102_table[2], NULL},
|
||||
{NULL},
|
||||
},
|
||||
{ "TeVii S650 USB2.0",
|
||||
{&dw2102_table[3], NULL},
|
||||
{NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static int dw2102_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf, &dw2102_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &dw2104_properties,
|
||||
THIS_MODULE, NULL, adapter_nr)) {
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_driver dw2102_driver = {
|
||||
@ -420,6 +812,6 @@ module_init(dw2102_module_init);
|
||||
module_exit(dw2102_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
|
||||
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device");
|
||||
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -4,6 +4,5 @@
|
||||
#define DVB_USB_LOG_PREFIX "dw2102"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_dw2102_debug;
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
|
||||
#endif
|
||||
|
@ -43,6 +43,20 @@ config DVB_S5H1420
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0288
|
||||
tristate "ST STV0288 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_STB6000
|
||||
tristate "ST STB6000 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0299
|
||||
tristate "ST STV0299 based"
|
||||
depends on DVB_CORE && I2C
|
||||
@ -92,6 +106,20 @@ config DVB_TUA6100
|
||||
help
|
||||
A DVB-S PLL chip.
|
||||
|
||||
config DVB_CX24116
|
||||
tristate "Conexant CX24116 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_SI21XX
|
||||
tristate "Silicon Labs SI21XX 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.
|
||||
|
||||
comment "DVB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
@ -385,4 +413,23 @@ config DVB_ISL6421
|
||||
help
|
||||
An SEC control chip.
|
||||
|
||||
config DVB_LGS8GL5
|
||||
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
comment "Tools to develop new frontends"
|
||||
|
||||
config DVB_DUMMY_FE
|
||||
tristate "Dummy frontend driver"
|
||||
default n
|
||||
|
||||
config DVB_AF9013
|
||||
tristate "Afatech AF9013 demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
endmenu
|
||||
|
@ -48,3 +48,10 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
|
||||
obj-$(CONFIG_DVB_AU8522) += au8522.o
|
||||
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
|
||||
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
|
||||
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
|
||||
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
|
||||
obj-$(CONFIG_DVB_AF9013) += af9013.o
|
||||
obj-$(CONFIG_DVB_CX24116) += cx24116.o
|
||||
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
|
||||
obj-$(CONFIG_DVB_STV0288) += stv0288.o
|
||||
obj-$(CONFIG_DVB_STB6000) += stb6000.o
|
||||
|
1685
drivers/media/dvb/frontends/af9013.c
Normal file
1685
drivers/media/dvb/frontends/af9013.c
Normal file
File diff suppressed because it is too large
Load Diff
107
drivers/media/dvb/frontends/af9013.h
Normal file
107
drivers/media/dvb/frontends/af9013.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* Thanks to Afatech who kindly provided information.
|
||||
*
|
||||
* 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 _AF9013_H_
|
||||
#define _AF9013_H_
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
enum af9013_ts_mode {
|
||||
AF9013_OUTPUT_MODE_PARALLEL,
|
||||
AF9013_OUTPUT_MODE_SERIAL,
|
||||
AF9013_OUTPUT_MODE_USB, /* only for AF9015 */
|
||||
};
|
||||
|
||||
enum af9013_tuner {
|
||||
AF9013_TUNER_MXL5003D = 3, /* MaxLinear */
|
||||
AF9013_TUNER_MXL5005D = 13, /* MaxLinear */
|
||||
AF9013_TUNER_MXL5005R = 30, /* MaxLinear */
|
||||
AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */
|
||||
AF9013_TUNER_MT2060 = 130, /* Microtune */
|
||||
AF9013_TUNER_MC44S803 = 133, /* Freescale */
|
||||
AF9013_TUNER_QT1010 = 134, /* Quantek */
|
||||
AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */
|
||||
AF9013_TUNER_MT2060_2 = 147, /* Microtune */
|
||||
AF9013_TUNER_TDA18271 = 156, /* NXP */
|
||||
AF9013_TUNER_QT1010A = 162, /* Quantek */
|
||||
};
|
||||
|
||||
/* AF9013/5 GPIOs (mostly guessed)
|
||||
demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
|
||||
demod#1-gpio#1 - xtal setting (?)
|
||||
demod#1-gpio#3 - tuner#1
|
||||
demod#2-gpio#0 - tuner#2
|
||||
demod#2-gpio#1 - xtal setting (?)
|
||||
*/
|
||||
#define AF9013_GPIO_ON (1 << 0)
|
||||
#define AF9013_GPIO_EN (1 << 1)
|
||||
#define AF9013_GPIO_O (1 << 2)
|
||||
#define AF9013_GPIO_I (1 << 3)
|
||||
|
||||
#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
|
||||
#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
|
||||
|
||||
#define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN)
|
||||
#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
|
||||
|
||||
struct af9013_config {
|
||||
/* demodulator's I2C address */
|
||||
u8 demod_address;
|
||||
|
||||
/* frequencies in kHz */
|
||||
u32 adc_clock;
|
||||
|
||||
/* tuner ID */
|
||||
u8 tuner;
|
||||
|
||||
/* tuner IF */
|
||||
u16 tuner_if;
|
||||
|
||||
/* TS data output mode */
|
||||
u8 output_mode:2;
|
||||
|
||||
/* RF spectrum inversion */
|
||||
u8 rf_spec_inv:1;
|
||||
|
||||
/* API version */
|
||||
u8 api_version[4];
|
||||
|
||||
/* GPIOs */
|
||||
u8 gpio[4];
|
||||
};
|
||||
|
||||
|
||||
#if defined(CONFIG_DVB_AF9013) || \
|
||||
(defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *af9013_attach(
|
||||
const struct af9013_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_AF9013 */
|
||||
|
||||
#endif /* _AF9013_H_ */
|
869
drivers/media/dvb/frontends/af9013_priv.h
Normal file
869
drivers/media/dvb/frontends/af9013_priv.h
Normal file
@ -0,0 +1,869 @@
|
||||
/*
|
||||
* DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* Thanks to Afatech who kindly provided information.
|
||||
*
|
||||
* 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 _AF9013_PRIV_
|
||||
#define _AF9013_PRIV_
|
||||
|
||||
#define LOG_PREFIX "af9013"
|
||||
extern int af9013_debug;
|
||||
|
||||
#define dprintk(var, level, args...) \
|
||||
do { if ((var & level)) printk(args); } while (0)
|
||||
|
||||
#define debug_dump(b, l, func) {\
|
||||
int loop_; \
|
||||
for (loop_ = 0; loop_ < l; loop_++) \
|
||||
func("%02x ", b[loop_]); \
|
||||
func("\n");\
|
||||
}
|
||||
|
||||
#define deb_info(args...) dprintk(af9013_debug, 0x01, args)
|
||||
|
||||
#undef err
|
||||
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
|
||||
#undef info
|
||||
#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
|
||||
#undef warn
|
||||
#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
|
||||
|
||||
#define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw"
|
||||
|
||||
struct regdesc {
|
||||
u16 addr;
|
||||
u8 pos:4;
|
||||
u8 len:4;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct snr_table {
|
||||
u32 val;
|
||||
u8 snr;
|
||||
};
|
||||
|
||||
/* QPSK SNR lookup table */
|
||||
static struct snr_table qpsk_snr_table[] = {
|
||||
{ 0x0b4771, 0 },
|
||||
{ 0x0c1aed, 1 },
|
||||
{ 0x0d0d27, 2 },
|
||||
{ 0x0e4d19, 3 },
|
||||
{ 0x0e5da8, 4 },
|
||||
{ 0x107097, 5 },
|
||||
{ 0x116975, 6 },
|
||||
{ 0x1252d9, 7 },
|
||||
{ 0x131fa4, 8 },
|
||||
{ 0x13d5e1, 9 },
|
||||
{ 0x148e53, 10 },
|
||||
{ 0x15358b, 11 },
|
||||
{ 0x15dd29, 12 },
|
||||
{ 0x168112, 13 },
|
||||
{ 0x170b61, 14 },
|
||||
{ 0xffffff, 15 },
|
||||
};
|
||||
|
||||
/* QAM16 SNR lookup table */
|
||||
static struct snr_table qam16_snr_table[] = {
|
||||
{ 0x05eb62, 5 },
|
||||
{ 0x05fecf, 6 },
|
||||
{ 0x060b80, 7 },
|
||||
{ 0x062501, 8 },
|
||||
{ 0x064865, 9 },
|
||||
{ 0x069604, 10 },
|
||||
{ 0x06f356, 11 },
|
||||
{ 0x07706a, 12 },
|
||||
{ 0x0804d3, 13 },
|
||||
{ 0x089d1a, 14 },
|
||||
{ 0x093e3d, 15 },
|
||||
{ 0x09e35d, 16 },
|
||||
{ 0x0a7c3c, 17 },
|
||||
{ 0x0afaf8, 18 },
|
||||
{ 0x0b719d, 19 },
|
||||
{ 0xffffff, 20 },
|
||||
};
|
||||
|
||||
/* QAM64 SNR lookup table */
|
||||
static struct snr_table qam64_snr_table[] = {
|
||||
{ 0x03109b, 12 },
|
||||
{ 0x0310d4, 13 },
|
||||
{ 0x031920, 14 },
|
||||
{ 0x0322d0, 15 },
|
||||
{ 0x0339fc, 16 },
|
||||
{ 0x0364a1, 17 },
|
||||
{ 0x038bcc, 18 },
|
||||
{ 0x03c7d3, 19 },
|
||||
{ 0x0408cc, 20 },
|
||||
{ 0x043bed, 21 },
|
||||
{ 0x048061, 22 },
|
||||
{ 0x04be95, 23 },
|
||||
{ 0x04fa7d, 24 },
|
||||
{ 0x052405, 25 },
|
||||
{ 0x05570d, 26 },
|
||||
{ 0xffffff, 27 },
|
||||
};
|
||||
|
||||
static struct regdesc ofsm_init[] = {
|
||||
{ 0xd73a, 0, 8, 0xa1 },
|
||||
{ 0xd73b, 0, 8, 0x1f },
|
||||
{ 0xd73c, 4, 4, 0x0a },
|
||||
{ 0xd732, 3, 1, 0x00 },
|
||||
{ 0xd731, 4, 2, 0x03 },
|
||||
{ 0xd73d, 7, 1, 0x01 },
|
||||
{ 0xd740, 0, 1, 0x00 },
|
||||
{ 0xd740, 1, 1, 0x00 },
|
||||
{ 0xd740, 2, 1, 0x00 },
|
||||
{ 0xd740, 3, 1, 0x01 },
|
||||
{ 0xd3c1, 4, 1, 0x01 },
|
||||
{ 0xd3a2, 0, 8, 0x00 },
|
||||
{ 0xd3a3, 0, 8, 0x04 },
|
||||
{ 0xd305, 0, 8, 0x32 },
|
||||
{ 0xd306, 0, 8, 0x10 },
|
||||
{ 0xd304, 0, 8, 0x04 },
|
||||
{ 0x9112, 0, 1, 0x01 },
|
||||
{ 0x911d, 0, 1, 0x01 },
|
||||
{ 0x911a, 0, 1, 0x01 },
|
||||
{ 0x911b, 0, 1, 0x01 },
|
||||
{ 0x9bce, 0, 4, 0x02 },
|
||||
{ 0x9116, 0, 1, 0x01 },
|
||||
{ 0x9bd1, 0, 1, 0x01 },
|
||||
{ 0xd2e0, 0, 8, 0xd0 },
|
||||
{ 0xd2e9, 0, 4, 0x0d },
|
||||
{ 0xd38c, 0, 8, 0xfc },
|
||||
{ 0xd38d, 0, 8, 0x00 },
|
||||
{ 0xd38e, 0, 8, 0x7e },
|
||||
{ 0xd38f, 0, 8, 0x00 },
|
||||
{ 0xd390, 0, 8, 0x2f },
|
||||
{ 0xd145, 4, 1, 0x01 },
|
||||
{ 0xd1a9, 4, 1, 0x01 },
|
||||
{ 0xd158, 5, 3, 0x01 },
|
||||
{ 0xd159, 0, 6, 0x06 },
|
||||
{ 0xd167, 0, 8, 0x00 },
|
||||
{ 0xd168, 0, 4, 0x07 },
|
||||
{ 0xd1c3, 5, 3, 0x00 },
|
||||
{ 0xd1c4, 0, 6, 0x00 },
|
||||
{ 0xd1c5, 0, 7, 0x10 },
|
||||
{ 0xd1c6, 0, 3, 0x02 },
|
||||
{ 0xd080, 2, 5, 0x03 },
|
||||
{ 0xd081, 4, 4, 0x09 },
|
||||
{ 0xd098, 4, 4, 0x0f },
|
||||
{ 0xd098, 0, 4, 0x03 },
|
||||
{ 0xdbc0, 3, 1, 0x01 },
|
||||
{ 0xdbc0, 4, 1, 0x01 },
|
||||
{ 0xdbc7, 0, 8, 0x08 },
|
||||
{ 0xdbc8, 4, 4, 0x00 },
|
||||
{ 0xdbc9, 0, 5, 0x01 },
|
||||
{ 0xd280, 0, 8, 0xe0 },
|
||||
{ 0xd281, 0, 8, 0xff },
|
||||
{ 0xd282, 0, 8, 0xff },
|
||||
{ 0xd283, 0, 8, 0xc3 },
|
||||
{ 0xd284, 0, 8, 0xff },
|
||||
{ 0xd285, 0, 4, 0x01 },
|
||||
{ 0xd0f0, 0, 7, 0x1a },
|
||||
{ 0xd0f1, 4, 1, 0x01 },
|
||||
{ 0xd0f2, 0, 8, 0x0c },
|
||||
{ 0xd103, 0, 4, 0x08 },
|
||||
{ 0xd0f8, 0, 7, 0x20 },
|
||||
{ 0xd111, 5, 1, 0x00 },
|
||||
{ 0xd111, 6, 1, 0x00 },
|
||||
{ 0x910b, 0, 8, 0x0a },
|
||||
{ 0x9115, 0, 8, 0x02 },
|
||||
{ 0x910c, 0, 8, 0x02 },
|
||||
{ 0x910d, 0, 8, 0x08 },
|
||||
{ 0x910e, 0, 8, 0x0a },
|
||||
{ 0x9bf6, 0, 8, 0x06 },
|
||||
{ 0x9bf8, 0, 8, 0x02 },
|
||||
{ 0x9bf7, 0, 8, 0x05 },
|
||||
{ 0x9bf9, 0, 8, 0x0f },
|
||||
{ 0x9bfc, 0, 8, 0x13 },
|
||||
{ 0x9bd3, 0, 8, 0xff },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Panasonic ENV77H11D5 tuner init
|
||||
AF9013_TUNER_ENV77H11D5 = 129 */
|
||||
static struct regdesc tuner_init_env77h11d5[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x03 },
|
||||
{ 0x9bbe, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0xd015, 0, 8, 0x50 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0xdf },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x44 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0xeb },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xf4 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xf9 },
|
||||
{ 0x9bc3, 0, 8, 0xdf },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0xeb },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bc9, 0, 8, 0x52 },
|
||||
{ 0xd011, 0, 8, 0x3c },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xf7 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x0b },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x4d },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* Microtune MT2060 tuner init
|
||||
AF9013_TUNER_MT2060 = 130 */
|
||||
static struct regdesc tuner_init_mt2060[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x07 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x00 },
|
||||
{ 0x9bcc, 0, 1, 0x00 },
|
||||
{ 0x9bb9, 0, 8, 0x75 },
|
||||
{ 0x9bcd, 0, 8, 0x24 },
|
||||
{ 0x9bff, 0, 8, 0x30 },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x32 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x36 },
|
||||
{ 0xd00d, 0, 2, 0x03 },
|
||||
{ 0xd00a, 0, 8, 0x35 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x07 },
|
||||
{ 0x9bc8, 0, 8, 0x90 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x36 },
|
||||
{ 0x9bc6, 0, 8, 0x03 },
|
||||
{ 0x9bba, 0, 8, 0xc9 },
|
||||
{ 0x9bc9, 0, 8, 0x79 },
|
||||
{ 0xd011, 0, 8, 0x10 },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0x45 },
|
||||
{ 0xd014, 0, 2, 0x03 },
|
||||
{ 0xd040, 0, 8, 0x98 },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0xcf },
|
||||
{ 0xd043, 0, 2, 0x03 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0xcc },
|
||||
{ 0x9be4, 0, 8, 0xa0 },
|
||||
{ 0x9bbd, 0, 8, 0x8e },
|
||||
{ 0x9be2, 0, 8, 0x4d },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Microtune MT2060 tuner init
|
||||
AF9013_TUNER_MT2060_2 = 147 */
|
||||
static struct regdesc tuner_init_mt2060_2[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x06 },
|
||||
{ 0x9bbe, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x32 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x36 },
|
||||
{ 0xd00d, 0, 2, 0x03 },
|
||||
{ 0xd00a, 0, 8, 0x35 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x07 },
|
||||
{ 0x9bc8, 0, 8, 0x90 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x36 },
|
||||
{ 0x9bc6, 0, 8, 0x03 },
|
||||
{ 0x9bba, 0, 8, 0xc9 },
|
||||
{ 0x9bc9, 0, 8, 0x79 },
|
||||
{ 0xd011, 0, 8, 0x10 },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0x45 },
|
||||
{ 0xd014, 0, 2, 0x03 },
|
||||
{ 0xd040, 0, 8, 0x98 },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0xcf },
|
||||
{ 0xd043, 0, 2, 0x03 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 8, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x96 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0xd045, 7, 1, 0x00 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* MaxLinear MXL5003 tuner init
|
||||
AF9013_TUNER_MXL5003D = 3 */
|
||||
static struct regdesc tuner_init_mxl5003d[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x09 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0x9bfc, 0, 8, 0x0f },
|
||||
{ 0x9bf6, 0, 8, 0x01 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0xd015, 0, 8, 0x33 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x40 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x6c },
|
||||
{ 0xd007, 0, 2, 0x00 },
|
||||
{ 0xd00c, 0, 8, 0x3d },
|
||||
{ 0xd00d, 0, 2, 0x00 },
|
||||
{ 0xd00a, 0, 8, 0x45 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x07 },
|
||||
{ 0x9bc8, 0, 8, 0x52 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x3d },
|
||||
{ 0x9bc6, 0, 8, 0x00 },
|
||||
{ 0x9bba, 0, 8, 0xa2 },
|
||||
{ 0x9bc9, 0, 8, 0xa0 },
|
||||
{ 0xd011, 0, 8, 0x56 },
|
||||
{ 0xd012, 0, 2, 0x00 },
|
||||
{ 0xd013, 0, 8, 0x50 },
|
||||
{ 0xd014, 0, 2, 0x00 },
|
||||
{ 0xd040, 0, 8, 0x56 },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0x50 },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 8, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* MaxLinear MXL5005 tuner init
|
||||
AF9013_TUNER_MXL5005D = 13
|
||||
AF9013_TUNER_MXL5005R = 30 */
|
||||
static struct regdesc tuner_init_mxl5005[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x07 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x28 },
|
||||
{ 0x9bff, 0, 8, 0x24 },
|
||||
{ 0xd015, 0, 8, 0x40 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x40 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x73 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0xfa },
|
||||
{ 0xd00d, 0, 2, 0x01 },
|
||||
{ 0xd00a, 0, 8, 0xff },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x23 },
|
||||
{ 0x9bc8, 0, 8, 0x55 },
|
||||
{ 0x9bc3, 0, 8, 0x01 },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0xfa },
|
||||
{ 0x9bc6, 0, 8, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xff },
|
||||
{ 0x9bc9, 0, 8, 0xff },
|
||||
{ 0x9bd3, 0, 8, 0x95 },
|
||||
{ 0xd011, 0, 8, 0x70 },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xfb },
|
||||
{ 0xd014, 0, 2, 0x01 },
|
||||
{ 0xd040, 0, 8, 0x70 },
|
||||
{ 0xd041, 0, 2, 0x01 },
|
||||
{ 0xd042, 0, 8, 0xfb },
|
||||
{ 0xd043, 0, 2, 0x01 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0x93 },
|
||||
{ 0x9be4, 0, 8, 0xfe },
|
||||
{ 0x9bbd, 0, 8, 0x63 },
|
||||
{ 0x9be2, 0, 8, 0xfe },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Quantek QT1010 tuner init
|
||||
AF9013_TUNER_QT1010 = 134
|
||||
AF9013_TUNER_QT1010A = 162 */
|
||||
static struct regdesc tuner_init_qt1010[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x09 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x28 },
|
||||
{ 0x9bff, 0, 8, 0x20 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x99 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x0f },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0x50 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x00 },
|
||||
{ 0x9bc8, 0, 8, 0x00 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x0f },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bba, 0, 8, 0xc5 },
|
||||
{ 0x9bc9, 0, 8, 0xff },
|
||||
{ 0xd011, 0, 8, 0x58 },
|
||||
{ 0xd012, 0, 2, 0x02 },
|
||||
{ 0xd013, 0, 8, 0x89 },
|
||||
{ 0xd014, 0, 2, 0x01 },
|
||||
{ 0xd040, 0, 8, 0x58 },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x89 },
|
||||
{ 0xd043, 0, 2, 0x01 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0xcd },
|
||||
{ 0x9be4, 0, 8, 0xbb },
|
||||
{ 0x9bbd, 0, 8, 0x93 },
|
||||
{ 0x9be2, 0, 8, 0x80 },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Freescale MC44S803 tuner init
|
||||
AF9013_TUNER_MC44S803 = 133 */
|
||||
static struct regdesc tuner_init_mc44s803[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x06 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0x9bf6, 0, 8, 0x01 },
|
||||
{ 0x9bf8, 0, 8, 0x02 },
|
||||
{ 0x9bf9, 0, 8, 0x02 },
|
||||
{ 0x9bfc, 0, 8, 0x1f },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x24 },
|
||||
{ 0x9bff, 0, 8, 0x24 },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x01 },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x7b },
|
||||
{ 0xd007, 0, 2, 0x00 },
|
||||
{ 0xd00c, 0, 8, 0x7c },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xfe },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x08 },
|
||||
{ 0x9bc8, 0, 8, 0x9a },
|
||||
{ 0x9bc3, 0, 8, 0x01 },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x7c },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bba, 0, 8, 0xfc },
|
||||
{ 0x9bc9, 0, 8, 0xaa },
|
||||
{ 0xd011, 0, 8, 0x6b },
|
||||
{ 0xd012, 0, 2, 0x00 },
|
||||
{ 0xd013, 0, 8, 0x88 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x6b },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0x7c },
|
||||
{ 0xd043, 0, 2, 0x02 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0x9e },
|
||||
{ 0x9be4, 0, 8, 0xff },
|
||||
{ 0x9bbd, 0, 8, 0x9e },
|
||||
{ 0x9be2, 0, 8, 0x25 },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
{ 0xd73b, 3, 1, 0x00 },
|
||||
};
|
||||
|
||||
/* unknown, probably for tin can tuner, tuner init
|
||||
AF9013_TUNER_UNKNOWN = 140 */
|
||||
static struct regdesc tuner_init_unknown[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x02 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x18 },
|
||||
{ 0x9bff, 0, 8, 0x2c },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0xdf },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x44 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x00 },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xf6 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xf9 },
|
||||
{ 0x9bc8, 0, 8, 0xaa },
|
||||
{ 0x9bc3, 0, 8, 0xdf },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x00 },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bc9, 0, 8, 0xf0 },
|
||||
{ 0xd011, 0, 8, 0x3c },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xf7 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x0b },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x4d },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* NXP TDA18271 tuner init
|
||||
AF9013_TUNER_TDA18271 = 156 */
|
||||
static struct regdesc tuner_init_tda18271[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x04 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x18 },
|
||||
{ 0x9bff, 0, 8, 0x2c },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0xdf },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x44 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x00 },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xf6 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xf9 },
|
||||
{ 0x9bc8, 0, 8, 0xaa },
|
||||
{ 0x9bc3, 0, 8, 0xdf },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x00 },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bc9, 0, 8, 0xf0 },
|
||||
{ 0xd011, 0, 8, 0x3c },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xf7 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x0b },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x4d },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0xa8 },
|
||||
{ 0x9be4, 0, 8, 0x7f },
|
||||
{ 0x9bbd, 0, 8, 0xa8 },
|
||||
{ 0x9be2, 0, 8, 0x20 },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
#endif /* _AF9013_PRIV_ */
|
@ -40,6 +40,8 @@ struct au8522_state {
|
||||
u32 current_frequency;
|
||||
fe_modulation_t current_modulation;
|
||||
|
||||
u32 fe_status;
|
||||
unsigned int led_state;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
|
||||
{
|
||||
struct au8522_led_config *led_config = state->config->led_cfg;
|
||||
u8 val;
|
||||
|
||||
/* bail out if we cant control an LED */
|
||||
if (!led_config || !led_config->gpio_output ||
|
||||
!led_config->gpio_output_enable || !led_config->gpio_output_disable)
|
||||
return 0;
|
||||
|
||||
val = au8522_readreg(state, 0x4000 |
|
||||
(led_config->gpio_output & ~0xc000));
|
||||
if (onoff) {
|
||||
/* enable GPIO output */
|
||||
val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
|
||||
val |= (led_config->gpio_output_enable & 0xff);
|
||||
} else {
|
||||
/* disable GPIO output */
|
||||
val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
|
||||
val |= (led_config->gpio_output_disable & 0xff);
|
||||
}
|
||||
return au8522_writereg(state, 0x8000 |
|
||||
(led_config->gpio_output & ~0xc000), val);
|
||||
}
|
||||
|
||||
/* led = 0 | off
|
||||
* led = 1 | signal ok
|
||||
* led = 2 | signal strong
|
||||
* led < 0 | only light led if leds are currently off
|
||||
*/
|
||||
static int au8522_led_ctrl(struct au8522_state *state, int led)
|
||||
{
|
||||
struct au8522_led_config *led_config = state->config->led_cfg;
|
||||
int i, ret = 0;
|
||||
|
||||
/* bail out if we cant control an LED */
|
||||
if (!led_config || !led_config->gpio_leds ||
|
||||
!led_config->num_led_states || !led_config->led_states)
|
||||
return 0;
|
||||
|
||||
if (led < 0) {
|
||||
/* if LED is already lit, then leave it as-is */
|
||||
if (state->led_state)
|
||||
return 0;
|
||||
else
|
||||
led *= -1;
|
||||
}
|
||||
|
||||
/* toggle LED if changing state */
|
||||
if (state->led_state != led) {
|
||||
u8 val;
|
||||
|
||||
dprintk("%s: %d\n", __func__, led);
|
||||
|
||||
au8522_led_gpio_enable(state, 1);
|
||||
|
||||
val = au8522_readreg(state, 0x4000 |
|
||||
(led_config->gpio_leds & ~0xc000));
|
||||
|
||||
/* start with all leds off */
|
||||
for (i = 0; i < led_config->num_led_states; i++)
|
||||
val &= ~led_config->led_states[i];
|
||||
|
||||
/* set selected LED state */
|
||||
if (led < led_config->num_led_states)
|
||||
val |= led_config->led_states[led];
|
||||
else if (led_config->num_led_states)
|
||||
val |=
|
||||
led_config->led_states[led_config->num_led_states - 1];
|
||||
|
||||
ret = au8522_writereg(state, 0x8000 |
|
||||
(led_config->gpio_leds & ~0xc000), val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->led_state = led;
|
||||
|
||||
if (led == 0)
|
||||
au8522_led_gpio_enable(state, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
/* turn off led */
|
||||
au8522_led_ctrl(state, 0);
|
||||
|
||||
state->current_frequency = 0;
|
||||
|
||||
return 0;
|
||||
@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
|
||||
break;
|
||||
}
|
||||
state->fe_status = *status;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
/* turn on LED, if it isn't on already */
|
||||
au8522_led_ctrl(state, -1);
|
||||
else
|
||||
/* turn off LED */
|
||||
au8522_led_ctrl(state, 0);
|
||||
|
||||
dprintk("%s() status 0x%08x\n", __func__, *status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_led_status(struct au8522_state *state, const u16 *snr)
|
||||
{
|
||||
struct au8522_led_config *led_config = state->config->led_cfg;
|
||||
int led;
|
||||
u16 strong;
|
||||
|
||||
/* bail out if we cant control an LED */
|
||||
if (!led_config)
|
||||
return 0;
|
||||
|
||||
if (0 == (state->fe_status & FE_HAS_LOCK))
|
||||
return au8522_led_ctrl(state, 0);
|
||||
else if (state->current_modulation == QAM_256)
|
||||
strong = led_config->qam256_strong;
|
||||
else if (state->current_modulation == QAM_64)
|
||||
strong = led_config->qam64_strong;
|
||||
else /* (state->current_modulation == VSB_8) */
|
||||
strong = led_config->vsb8_strong;
|
||||
|
||||
if (*snr >= strong)
|
||||
led = 2;
|
||||
else
|
||||
led = 1;
|
||||
|
||||
if ((state->led_state) &&
|
||||
(((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
|
||||
/* snr didn't change enough to bother
|
||||
* changing the color of the led */
|
||||
return 0;
|
||||
|
||||
return au8522_led_ctrl(state, led);
|
||||
}
|
||||
|
||||
static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
au8522_readreg(state, 0x4311),
|
||||
snr);
|
||||
|
||||
if (state->config->led_cfg)
|
||||
au8522_led_status(state, snr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,21 @@ enum au8522_if_freq {
|
||||
AU8522_IF_3_25MHZ,
|
||||
};
|
||||
|
||||
struct au8522_led_config {
|
||||
u16 vsb8_strong;
|
||||
u16 qam64_strong;
|
||||
u16 qam256_strong;
|
||||
|
||||
u16 gpio_output;
|
||||
/* unset hi bits, set low bits */
|
||||
u16 gpio_output_enable;
|
||||
u16 gpio_output_disable;
|
||||
|
||||
u16 gpio_leds;
|
||||
u8 *led_states;
|
||||
unsigned int num_led_states;
|
||||
};
|
||||
|
||||
struct au8522_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
@ -39,6 +54,8 @@ struct au8522_config {
|
||||
#define AU8522_DEMODLOCKING 1
|
||||
u8 status_mode;
|
||||
|
||||
struct au8522_led_config *led_cfg;
|
||||
|
||||
enum au8522_if_freq vsb_if;
|
||||
enum au8522_if_freq qam_if;
|
||||
};
|
||||
|
@ -33,12 +33,17 @@ struct cx24110_config
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) {
|
||||
int r = 0;
|
||||
u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)};
|
||||
static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
|
||||
{
|
||||
u8 buf[] = {
|
||||
(u8)((val >> 24) & 0xff),
|
||||
(u8)((val >> 16) & 0xff),
|
||||
(u8)((val >> 8) & 0xff)
|
||||
};
|
||||
|
||||
if (fe->ops.write)
|
||||
r = fe->ops.write(fe, buf, 3);
|
||||
return r;
|
||||
return fe->ops.write(fe, buf, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
|
||||
|
1423
drivers/media/dvb/frontends/cx24116.c
Normal file
1423
drivers/media/dvb/frontends/cx24116.c
Normal file
File diff suppressed because it is too large
Load Diff
53
drivers/media/dvb/frontends/cx24116.h
Normal file
53
drivers/media/dvb/frontends/cx24116.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
|
||||
|
||||
Copyright (C) 2006 Steven Toth <stoth@linuxtv.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 CX24116_H
|
||||
#define CX24116_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct cx24116_config
|
||||
{
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* Need to set device param for start_dma */
|
||||
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
|
||||
|
||||
/* Need to reset device during firmware loading */
|
||||
int (*reset_device)(struct dvb_frontend* fe);
|
||||
|
||||
/* Need to set MPEG parameters */
|
||||
u8 mpg_clk_pos_pol:0x02;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE)
|
||||
extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
|
||||
struct i2c_adapter* i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_CX24116
|
||||
|
||||
#endif /* CX24116_H */
|
@ -41,6 +41,7 @@ struct dib0070_config {
|
||||
extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct dib0070_config *cfg);
|
||||
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
|
||||
#else
|
||||
static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
|
||||
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
|
||||
|
||||
#endif
|
||||
|
@ -1284,7 +1284,10 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di
|
||||
}
|
||||
EXPORT_SYMBOL(dib7000m_get_i2c_master);
|
||||
|
||||
int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[])
|
||||
#if 0
|
||||
/* used with some prototype boards */
|
||||
int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
|
||||
u8 default_addr, struct dib7000m_config cfg[])
|
||||
{
|
||||
struct dib7000m_state st = { .i2c_adap = i2c };
|
||||
int k = 0;
|
||||
@ -1329,6 +1332,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dib7000m_i2c_enumeration);
|
||||
#endif
|
||||
|
||||
static struct dvb_frontend_ops dib7000m_ops;
|
||||
struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
|
||||
|
@ -1333,7 +1333,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
|
||||
/* Ensure the output mode remains at the previous default if it's
|
||||
* not specifically set by the caller.
|
||||
*/
|
||||
if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL)
|
||||
if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
|
||||
(st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
|
||||
st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
|
||||
|
||||
demod = &st->demod;
|
||||
|
@ -41,6 +41,14 @@ struct dib7000p_config {
|
||||
extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
|
||||
u8 i2c_addr,
|
||||
struct dib7000p_config *cfg);
|
||||
extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *,
|
||||
enum dibx000_i2c_interface,
|
||||
int);
|
||||
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
|
||||
int no_of_demods, u8 default_addr,
|
||||
struct dib7000p_config cfg[]);
|
||||
extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
|
||||
extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
|
||||
#else
|
||||
static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
|
||||
u8 i2c_addr,
|
||||
@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
|
||||
enum dibx000_i2c_interface i, int x)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
|
||||
int no_of_demods, u8 default_addr,
|
||||
struct dib7000p_config cfg[])
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
extern 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)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
|
||||
|
||||
extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
|
||||
extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
|
||||
extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
|
||||
extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
|
||||
|
||||
#endif
|
||||
|
@ -38,35 +38,32 @@ static const char mod_name[] = "drx397xD";
|
||||
#define F_SET_0D0h 1
|
||||
#define F_SET_0D4h 2
|
||||
|
||||
typedef enum fw_ix {
|
||||
enum fw_ix {
|
||||
#define _FW_ENTRY(a, b) b
|
||||
#include "drx397xD_fw.h"
|
||||
} fw_ix_t;
|
||||
};
|
||||
|
||||
/* chip specifics */
|
||||
struct drx397xD_state {
|
||||
struct i2c_adapter *i2c;
|
||||
struct dvb_frontend frontend;
|
||||
struct drx397xD_config config;
|
||||
fw_ix_t chip_rev;
|
||||
enum fw_ix chip_rev;
|
||||
int flags;
|
||||
u32 bandwidth_parm; /* internal bandwidth conversions */
|
||||
u32 f_osc; /* w90: actual osc frequency [Hz] */
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Firmware
|
||||
******************************************************************************/
|
||||
|
||||
/* Firmware */
|
||||
static const char *blob_name[] = {
|
||||
#define _BLOB_ENTRY(a, b) a
|
||||
#include "drx397xD_fw.h"
|
||||
};
|
||||
|
||||
typedef enum blob_ix {
|
||||
enum blob_ix {
|
||||
#define _BLOB_ENTRY(a, b) b
|
||||
#include "drx397xD_fw.h"
|
||||
} blob_ix_t;
|
||||
};
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
@ -85,7 +82,7 @@ static struct {
|
||||
};
|
||||
|
||||
/* use only with writer lock aquired */
|
||||
static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
|
||||
static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
|
||||
{
|
||||
memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
|
||||
if (fw[ix].file)
|
||||
@ -94,9 +91,9 @@ static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
|
||||
|
||||
static void drx_release_fw(struct drx397xD_state *s)
|
||||
{
|
||||
fw_ix_t ix = s->chip_rev;
|
||||
enum fw_ix ix = s->chip_rev;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
write_lock(&fw[ix].lock);
|
||||
if (fw[ix].refcnt) {
|
||||
@ -107,13 +104,13 @@ static void drx_release_fw(struct drx397xD_state *s)
|
||||
write_unlock(&fw[ix].lock);
|
||||
}
|
||||
|
||||
static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
|
||||
static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
|
||||
{
|
||||
const u8 *data;
|
||||
size_t size, len;
|
||||
int i = 0, j, rc = -EINVAL;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (ix < 0 || ix >= ARRAY_SIZE(fw))
|
||||
return -EINVAL;
|
||||
@ -175,32 +172,34 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
|
||||
goto exit_corrupt;
|
||||
}
|
||||
} while (i < size);
|
||||
exit_corrupt:
|
||||
|
||||
exit_corrupt:
|
||||
printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
|
||||
exit_err:
|
||||
exit_err:
|
||||
_drx_release_fw(s, ix);
|
||||
fw[ix].refcnt--;
|
||||
exit_ok:
|
||||
exit_ok:
|
||||
fw[ix].refcnt++;
|
||||
write_unlock(&fw[ix].lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* i2c bus IO
|
||||
******************************************************************************/
|
||||
|
||||
static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
|
||||
/* i2c bus IO */
|
||||
static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
|
||||
{
|
||||
struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 };
|
||||
const u8 *data;
|
||||
int len, rc = 0, i = 0;
|
||||
struct i2c_msg msg = {
|
||||
.addr = s->config.demod_address,
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
|
||||
pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__);
|
||||
pr_debug("%s drx_fw_ix_t out of range\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]);
|
||||
pr_debug("%s %s\n", __func__, blob_name[ix]);
|
||||
|
||||
read_lock(&fw[s->chip_rev].lock);
|
||||
data = fw[s->chip_rev].data[ix];
|
||||
@ -229,33 +228,33 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
|
||||
goto exit_rc;
|
||||
}
|
||||
}
|
||||
exit_rc:
|
||||
exit_rc:
|
||||
read_unlock(&fw[s->chip_rev].lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function is not endian safe, use the RD16 wrapper below */
|
||||
static int _read16(struct drx397xD_state *s, u32 i2c_adr)
|
||||
static int _read16(struct drx397xD_state *s, __le32 i2c_adr)
|
||||
{
|
||||
int rc;
|
||||
u8 a[4];
|
||||
u16 v;
|
||||
__le16 v;
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = s->config.demod_address,
|
||||
.flags = 0,
|
||||
.buf = a,
|
||||
.len = sizeof(a)
|
||||
}
|
||||
, {
|
||||
.addr = s->config.demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = (u8 *) & v,
|
||||
.len = sizeof(v)
|
||||
}
|
||||
.addr = s->config.demod_address,
|
||||
.flags = 0,
|
||||
.buf = a,
|
||||
.len = sizeof(a)
|
||||
}, {
|
||||
.addr = s->config.demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = (u8 *)&v,
|
||||
.len = sizeof(v)
|
||||
}
|
||||
};
|
||||
|
||||
*(u32 *) a = i2c_adr;
|
||||
*(__le32 *) a = i2c_adr;
|
||||
|
||||
rc = i2c_transfer(s->i2c, msg, 2);
|
||||
if (rc != 2)
|
||||
@ -265,7 +264,7 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr)
|
||||
}
|
||||
|
||||
/* Function is not endian safe, use the WR16.. wrappers below */
|
||||
static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
|
||||
static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val)
|
||||
{
|
||||
u8 a[6];
|
||||
int rc;
|
||||
@ -276,28 +275,28 @@ static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
|
||||
.len = sizeof(a)
|
||||
};
|
||||
|
||||
*(u32 *) a = i2c_adr;
|
||||
*(u16 *) & a[4] = val;
|
||||
*(__le32 *)a = i2c_adr;
|
||||
*(__le16 *)&a[4] = val;
|
||||
|
||||
rc = i2c_transfer(s->i2c, &msg, 1);
|
||||
if (rc != 1)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WR16(ss,adr, val) \
|
||||
#define WR16(ss, adr, val) \
|
||||
_write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
|
||||
#define WR16_E0(ss,adr, val) \
|
||||
#define WR16_E0(ss, adr, val) \
|
||||
_write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
|
||||
#define RD16(ss,adr) \
|
||||
#define RD16(ss, adr) \
|
||||
_read16(ss, I2C_ADR_C0(adr))
|
||||
|
||||
#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc
|
||||
|
||||
/*******************************************************************************
|
||||
* Tuner callback
|
||||
******************************************************************************/
|
||||
#define EXIT_RC(cmd) \
|
||||
if ((rc = (cmd)) < 0) \
|
||||
goto exit_rc
|
||||
|
||||
/* Tuner callback */
|
||||
static int PLL_Set(struct drx397xD_state *s,
|
||||
struct dvb_frontend_parameters *fep, int *df_tuner)
|
||||
{
|
||||
@ -305,7 +304,7 @@ static int PLL_Set(struct drx397xD_state *s,
|
||||
u32 f_tuner, f = fep->frequency;
|
||||
int rc;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
|
||||
(f < s->frontend.ops.tuner_ops.info.frequency_min))
|
||||
@ -325,28 +324,26 @@ static int PLL_Set(struct drx397xD_state *s,
|
||||
return rc;
|
||||
|
||||
*df_tuner = f_tuner - f;
|
||||
pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f,
|
||||
pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f,
|
||||
f_tuner);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Demodulator helper functions
|
||||
******************************************************************************/
|
||||
|
||||
/* Demodulator helper functions */
|
||||
static int SC_WaitForReady(struct drx397xD_state *s)
|
||||
{
|
||||
int cnt = 1000;
|
||||
int rc;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
while (cnt--) {
|
||||
rc = RD16(s, 0x820043);
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -354,13 +351,14 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
WR16(s, 0x820043, cmd);
|
||||
SC_WaitForReady(s);
|
||||
rc = RD16(s, 0x820042);
|
||||
if ((rc & 0xffff) == 0xffff)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -368,7 +366,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd)
|
||||
{
|
||||
int rc, cnt = 1000;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
rc = WR16(s, 0x420032, cmd);
|
||||
if (rc < 0)
|
||||
@ -383,22 +381,24 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd)
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
} while (--cnt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int HI_CfgCommand(struct drx397xD_state *s)
|
||||
{
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
WR16(s, 0x420033, 0x3973);
|
||||
WR16(s, 0x420034, s->config.w50); // code 4, log 4
|
||||
WR16(s, 0x420035, s->config.w52); // code 15, log 9
|
||||
WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */
|
||||
WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */
|
||||
WR16(s, 0x420036, s->config.demod_address << 1);
|
||||
WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1
|
||||
// WR16(s, 0x420033, 0x3973);
|
||||
WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */
|
||||
/* WR16(s, 0x420033, 0x3973); */
|
||||
if ((s->config.w56 & 8) == 0)
|
||||
return HI_Command(s, 3);
|
||||
|
||||
return WR16(s, 0x420032, 0x3);
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
|
||||
u16 w0C = agc->w0C;
|
||||
int quot, rem, i, rc = -EINVAL;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (agc->w04 > 0x3ff)
|
||||
goto exit_rc;
|
||||
@ -468,7 +468,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
|
||||
i = slowIncrDecLUT_15272[rem / 28];
|
||||
EXIT_RC(WR16(s, 0x0c2002b, i));
|
||||
rc = WR16(s, 0x0c2002c, i);
|
||||
exit_rc:
|
||||
exit_rc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -478,7 +478,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
|
||||
u16 w06 = agc->w06;
|
||||
int rc = -1;
|
||||
|
||||
pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06);
|
||||
pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06);
|
||||
|
||||
if (w04 > 0x3ff)
|
||||
goto exit_rc;
|
||||
@ -498,7 +498,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
|
||||
rc &= ~2;
|
||||
break;
|
||||
case 0:
|
||||
// loc_8000659
|
||||
/* loc_8000659 */
|
||||
s->config.w9C &= ~2;
|
||||
EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
|
||||
EXIT_RC(RD16(s, 0x0c20010));
|
||||
@ -522,7 +522,8 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
|
||||
rc |= 2;
|
||||
}
|
||||
rc = WR16(s, 0x0c20013, rc);
|
||||
exit_rc:
|
||||
|
||||
exit_rc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -554,7 +555,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s)
|
||||
int lockstat;
|
||||
u32 clk, clk_limit;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (s->config.d5C == 0) {
|
||||
EXIT_RC(WR16(s, 0x08200e8, 0x010));
|
||||
@ -598,11 +599,12 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s)
|
||||
|
||||
if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
|
||||
s->f_osc = clk;
|
||||
pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__,
|
||||
pr_debug("%s: osc %d %d [Hz]\n", __func__,
|
||||
s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
|
||||
}
|
||||
rc = WR16(s, 0x08200e8, 0);
|
||||
exit_rc:
|
||||
|
||||
exit_rc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -610,7 +612,7 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
|
||||
{
|
||||
int rc, si, bp;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
si = s->config.wA0;
|
||||
if (s->config.w98 == 0) {
|
||||
@ -620,17 +622,17 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
|
||||
si &= ~1;
|
||||
bp = 0x200;
|
||||
}
|
||||
if (s->config.w9A == 0) {
|
||||
if (s->config.w9A == 0)
|
||||
si |= 0x80;
|
||||
} else {
|
||||
else
|
||||
si &= ~0x80;
|
||||
}
|
||||
|
||||
EXIT_RC(WR16(s, 0x2150045, 0));
|
||||
EXIT_RC(WR16(s, 0x2150010, si));
|
||||
EXIT_RC(WR16(s, 0x2150011, bp));
|
||||
rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
|
||||
exit_rc:
|
||||
|
||||
exit_rc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -646,7 +648,7 @@ static int drx_tune(struct drx397xD_state *s,
|
||||
|
||||
int rc, df_tuner;
|
||||
int a, b, c, d;
|
||||
pr_debug("%s %d\n", __FUNCTION__, s->config.d60);
|
||||
pr_debug("%s %d\n", __func__, s->config.d60);
|
||||
|
||||
if (s->config.d60 != 2)
|
||||
goto set_tuner;
|
||||
@ -658,7 +660,7 @@ static int drx_tune(struct drx397xD_state *s,
|
||||
rc = ConfigureMPEGOutput(s, 0);
|
||||
if (rc < 0)
|
||||
goto set_tuner;
|
||||
set_tuner:
|
||||
set_tuner:
|
||||
|
||||
rc = PLL_Set(s, fep, &df_tuner);
|
||||
if (rc < 0) {
|
||||
@ -835,16 +837,16 @@ static int drx_tune(struct drx397xD_state *s,
|
||||
rc = WR16(s, 0x2010012, 0);
|
||||
if (rc < 0)
|
||||
goto exit_rc;
|
||||
// QPSK QAM16 QAM64
|
||||
ebx = 0x19f; // 62
|
||||
ebp = 0x1fb; // 15
|
||||
v20 = 0x16a; // 62
|
||||
v1E = 0x195; // 62
|
||||
v16 = 0x1bb; // 15
|
||||
v14 = 0x1ef; // 15
|
||||
v12 = 5; // 16
|
||||
v10 = 5; // 16
|
||||
v0E = 5; // 16
|
||||
/* QPSK QAM16 QAM64 */
|
||||
ebx = 0x19f; /* 62 */
|
||||
ebp = 0x1fb; /* 15 */
|
||||
v20 = 0x16a; /* 62 */
|
||||
v1E = 0x195; /* 62 */
|
||||
v16 = 0x1bb; /* 15 */
|
||||
v14 = 0x1ef; /* 15 */
|
||||
v12 = 5; /* 16 */
|
||||
v10 = 5; /* 16 */
|
||||
v0E = 5; /* 16 */
|
||||
}
|
||||
|
||||
switch (fep->u.ofdm.constellation) {
|
||||
@ -997,17 +999,17 @@ static int drx_tune(struct drx397xD_state *s,
|
||||
case BANDWIDTH_8_MHZ: /* 0 */
|
||||
case BANDWIDTH_AUTO:
|
||||
rc = WR16(s, 0x0c2003f, 0x32);
|
||||
s->bandwidth_parm = ebx = 0x8b8249; // 9142857
|
||||
s->bandwidth_parm = ebx = 0x8b8249;
|
||||
edx = 0;
|
||||
break;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
rc = WR16(s, 0x0c2003f, 0x3b);
|
||||
s->bandwidth_parm = ebx = 0x7a1200; // 8000000
|
||||
s->bandwidth_parm = ebx = 0x7a1200;
|
||||
edx = 0x4807;
|
||||
break;
|
||||
case BANDWIDTH_6_MHZ:
|
||||
rc = WR16(s, 0x0c2003f, 0x47);
|
||||
s->bandwidth_parm = ebx = 0x68a1b6; // 6857142
|
||||
s->bandwidth_parm = ebx = 0x68a1b6;
|
||||
edx = 0x0f07;
|
||||
break;
|
||||
};
|
||||
@ -1060,8 +1062,6 @@ static int drx_tune(struct drx397xD_state *s,
|
||||
WR16(s, 0x0820040, 1);
|
||||
SC_SendCommand(s, 1);
|
||||
|
||||
// rc = WR16(s, 0x2150000, 1);
|
||||
// if (rc < 0) goto exit_rc;
|
||||
|
||||
rc = WR16(s, 0x2150000, 2);
|
||||
rc = WR16(s, 0x2150016, a);
|
||||
@ -1069,7 +1069,8 @@ static int drx_tune(struct drx397xD_state *s,
|
||||
rc = WR16(s, 0x2150036, 0);
|
||||
rc = WR16(s, 0x2150000, 1);
|
||||
s->config.d60 = 2;
|
||||
exit_rc:
|
||||
|
||||
exit_rc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1082,7 +1083,7 @@ static int drx397x_init(struct dvb_frontend *fe)
|
||||
struct drx397xD_state *s = fe->demodulator_priv;
|
||||
int rc;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
s->config.rfagc.d00 = 2; /* 0x7c */
|
||||
s->config.rfagc.w04 = 0;
|
||||
@ -1102,18 +1103,18 @@ static int drx397x_init(struct dvb_frontend *fe)
|
||||
|
||||
/* HI_CfgCommand */
|
||||
s->config.w50 = 4;
|
||||
s->config.w52 = 9; // 0xf;
|
||||
s->config.w52 = 9;
|
||||
|
||||
s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */
|
||||
s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */
|
||||
s->config.w92 = 12000; // 20000;
|
||||
s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */
|
||||
s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */
|
||||
s->config.w92 = 12000;
|
||||
|
||||
s->config.w9C = 0x000e;
|
||||
s->config.w9E = 0x0000;
|
||||
|
||||
/* ConfigureMPEGOutput params */
|
||||
s->config.wA0 = 4;
|
||||
s->config.w98 = 1; // 0;
|
||||
s->config.w98 = 1;
|
||||
s->config.w9A = 1;
|
||||
|
||||
/* get chip revision */
|
||||
@ -1248,7 +1249,7 @@ static int drx397x_init(struct dvb_frontend *fe)
|
||||
rc = WR16(s, 0x0c20012, 1);
|
||||
}
|
||||
|
||||
write_DRXD_InitFE_1:
|
||||
write_DRXD_InitFE_1:
|
||||
|
||||
rc = write_fw(s, DRXD_InitFE_1);
|
||||
if (rc < 0)
|
||||
@ -1311,7 +1312,8 @@ static int drx397x_init(struct dvb_frontend *fe)
|
||||
s->config.d5C = 0;
|
||||
s->config.d60 = 1;
|
||||
s->config.d48 = 1;
|
||||
error:
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1326,7 +1328,8 @@ static int drx397x_set_frontend(struct dvb_frontend *fe,
|
||||
{
|
||||
struct drx397xD_state *s = fe->demodulator_priv;
|
||||
|
||||
s->config.s20d24 = 1; // 0;
|
||||
s->config.s20d24 = 1;
|
||||
|
||||
return drx_tune(s, params);
|
||||
}
|
||||
|
||||
@ -1337,18 +1340,16 @@ static int drx397x_get_tune_settings(struct dvb_frontend *fe,
|
||||
fe_tune_settings->min_delay_ms = 10000;
|
||||
fe_tune_settings->step_size = 0;
|
||||
fe_tune_settings->max_drift = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
|
||||
static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct drx397xD_state *s = fe->demodulator_priv;
|
||||
int lockstat;
|
||||
|
||||
GetLockStatus(s, &lockstat);
|
||||
/* TODO */
|
||||
// if (lockstat & 1)
|
||||
// CorrectSysClockDeviation(s);
|
||||
|
||||
*status = 0;
|
||||
if (lockstat & 2) {
|
||||
@ -1356,9 +1357,8 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
|
||||
ConfigureMPEGOutput(s, 1);
|
||||
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
|
||||
}
|
||||
if (lockstat & 4) {
|
||||
if (lockstat & 4)
|
||||
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1366,16 +1366,18 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
|
||||
static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
|
||||
{
|
||||
*ber = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr)
|
||||
static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
*snr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
|
||||
static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct drx397xD_state *s = fe->demodulator_priv;
|
||||
int rc;
|
||||
@ -1401,6 +1403,7 @@ static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
|
||||
* The following does the same but with less rounding errors:
|
||||
*/
|
||||
*strength = ~(7720 + (rc * 30744 >> 10));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1408,6 +1411,7 @@ static int drx397x_read_ucblocks(struct dvb_frontend *fe,
|
||||
unsigned int *ucblocks)
|
||||
{
|
||||
*ucblocks = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1436,22 +1440,22 @@ static struct dvb_frontend_ops drx397x_ops = {
|
||||
.frequency_max = 855250000,
|
||||
.frequency_stepsize = 166667,
|
||||
.frequency_tolerance = 0,
|
||||
.caps = /* 0x0C01B2EAE */
|
||||
FE_CAN_FEC_1_2 | // = 0x2,
|
||||
FE_CAN_FEC_2_3 | // = 0x4,
|
||||
FE_CAN_FEC_3_4 | // = 0x8,
|
||||
FE_CAN_FEC_5_6 | // = 0x20,
|
||||
FE_CAN_FEC_7_8 | // = 0x80,
|
||||
FE_CAN_FEC_AUTO | // = 0x200,
|
||||
FE_CAN_QPSK | // = 0x400,
|
||||
FE_CAN_QAM_16 | // = 0x800,
|
||||
FE_CAN_QAM_64 | // = 0x2000,
|
||||
FE_CAN_QAM_AUTO | // = 0x10000,
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000,
|
||||
FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000,
|
||||
FE_CAN_HIERARCHY_AUTO | // = 0x100000,
|
||||
FE_CAN_RECOVER | // = 0x40000000,
|
||||
FE_CAN_MUTE_TS // = 0x80000000
|
||||
.caps = /* 0x0C01B2EAE */
|
||||
FE_CAN_FEC_1_2 | /* = 0x2, */
|
||||
FE_CAN_FEC_2_3 | /* = 0x4, */
|
||||
FE_CAN_FEC_3_4 | /* = 0x8, */
|
||||
FE_CAN_FEC_5_6 | /* = 0x20, */
|
||||
FE_CAN_FEC_7_8 | /* = 0x80, */
|
||||
FE_CAN_FEC_AUTO | /* = 0x200, */
|
||||
FE_CAN_QPSK | /* = 0x400, */
|
||||
FE_CAN_QAM_16 | /* = 0x800, */
|
||||
FE_CAN_QAM_64 | /* = 0x2000, */
|
||||
FE_CAN_QAM_AUTO | /* = 0x10000, */
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */
|
||||
FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */
|
||||
FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */
|
||||
FE_CAN_RECOVER | /* = 0x40000000, */
|
||||
FE_CAN_MUTE_TS /* = 0x80000000 */
|
||||
},
|
||||
|
||||
.release = drx397x_release,
|
||||
@ -1472,33 +1476,35 @@ static struct dvb_frontend_ops drx397x_ops = {
|
||||
struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct drx397xD_state *s = NULL;
|
||||
struct drx397xD_state *state;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
|
||||
if (!state)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
s->i2c = i2c;
|
||||
memcpy(&s->config, config, sizeof(struct drx397xD_config));
|
||||
state->i2c = i2c;
|
||||
memcpy(&state->config, config, sizeof(struct drx397xD_config));
|
||||
|
||||
/* check if the demod is there */
|
||||
if (RD16(s, 0x2410019) < 0)
|
||||
if (RD16(state, 0x2410019) < 0)
|
||||
goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->frontend.demodulator_priv = s;
|
||||
memcpy(&state->frontend.ops, &drx397x_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
return &state->frontend;
|
||||
error:
|
||||
kfree(state);
|
||||
|
||||
return &s->frontend;
|
||||
error:
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drx397xD_attach);
|
||||
|
||||
MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
|
||||
MODULE_AUTHOR("Henk Vergonet");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(drx397xD_attach);
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define DRX_F_OFFSET 36000000
|
||||
|
||||
#define I2C_ADR_C0(x) \
|
||||
( (u32)cpu_to_le32( \
|
||||
( cpu_to_le32( \
|
||||
(u32)( \
|
||||
(((u32)(x) & (u32)0x000000ffUL) ) | \
|
||||
(((u32)(x) & (u32)0x0000ff00UL) << 16) | \
|
||||
@ -38,7 +38,7 @@
|
||||
)
|
||||
|
||||
#define I2C_ADR_E0(x) \
|
||||
( (u32)cpu_to_le32( \
|
||||
( cpu_to_le32( \
|
||||
(u32)( \
|
||||
(((u32)(x) & (u32)0x000000ffUL) ) | \
|
||||
(((u32)(x) & (u32)0x0000ff00UL) << 16) | \
|
||||
@ -122,7 +122,7 @@ extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config
|
||||
static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_DRX397XD */
|
||||
|
@ -75,9 +75,10 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
|
||||
|
||||
static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
|
||||
{
|
||||
if (fe->ops->tuner_ops->set_params) {
|
||||
fe->ops->tuner_ops->set_params(fe, p);
|
||||
if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe, p);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -131,7 +132,7 @@ error:
|
||||
|
||||
static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops;
|
||||
|
||||
struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
|
||||
struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
|
||||
{
|
||||
struct dvb_dummy_fe_state* state = NULL;
|
||||
|
||||
@ -151,7 +152,7 @@ error:
|
||||
|
||||
static struct dvb_frontend_ops dvb_dummy_fe_qam_ops;
|
||||
|
||||
struct dvb_frontend* dvb_dummy_fe_qam_attach()
|
||||
struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
|
||||
{
|
||||
struct dvb_dummy_fe_state* state = NULL;
|
||||
|
||||
|
133
drivers/media/dvb/frontends/eds1547.h
Normal file
133
drivers/media/dvb/frontends/eds1547.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* eds1547.h Earda EDS-1547 tuner support
|
||||
*
|
||||
* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
|
||||
#ifndef EDS1547
|
||||
#define EDS1547
|
||||
|
||||
static u8 stv0288_earda_inittab[] = {
|
||||
0x01, 0x57,
|
||||
0x02, 0x20,
|
||||
0x03, 0x8e,
|
||||
0x04, 0x8e,
|
||||
0x05, 0x12,
|
||||
0x06, 0x00,
|
||||
0x07, 0x00,
|
||||
0x09, 0x00,
|
||||
0x0a, 0x04,
|
||||
0x0b, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x0d, 0x00,
|
||||
0x0e, 0xd4,
|
||||
0x0f, 0x30,
|
||||
0x11, 0x44,
|
||||
0x12, 0x03,
|
||||
0x13, 0x48,
|
||||
0x14, 0x84,
|
||||
0x15, 0x45,
|
||||
0x16, 0xb7,
|
||||
0x17, 0x9c,
|
||||
0x18, 0x00,
|
||||
0x19, 0xa6,
|
||||
0x1a, 0x88,
|
||||
0x1b, 0x8f,
|
||||
0x1c, 0xf0,
|
||||
0x20, 0x0b,
|
||||
0x21, 0x54,
|
||||
0x22, 0x00,
|
||||
0x23, 0x00,
|
||||
0x2b, 0xff,
|
||||
0x2c, 0xf7,
|
||||
0x30, 0x00,
|
||||
0x31, 0x1e,
|
||||
0x32, 0x14,
|
||||
0x33, 0x0f,
|
||||
0x34, 0x09,
|
||||
0x35, 0x0c,
|
||||
0x36, 0x05,
|
||||
0x37, 0x2f,
|
||||
0x38, 0x16,
|
||||
0x39, 0xbd,
|
||||
0x3a, 0x00,
|
||||
0x3b, 0x13,
|
||||
0x3c, 0x11,
|
||||
0x3d, 0x30,
|
||||
0x40, 0x63,
|
||||
0x41, 0x04,
|
||||
0x42, 0x60,
|
||||
0x43, 0x00,
|
||||
0x44, 0x00,
|
||||
0x45, 0x00,
|
||||
0x46, 0x00,
|
||||
0x47, 0x00,
|
||||
0x4a, 0x00,
|
||||
0x50, 0x10,
|
||||
0x51, 0x36,
|
||||
0x52, 0x09,
|
||||
0x53, 0x94,
|
||||
0x54, 0x62,
|
||||
0x55, 0x29,
|
||||
0x56, 0x64,
|
||||
0x57, 0x2b,
|
||||
0x58, 0x54,
|
||||
0x59, 0x86,
|
||||
0x5a, 0x00,
|
||||
0x5b, 0x9b,
|
||||
0x5c, 0x08,
|
||||
0x5d, 0x7f,
|
||||
0x5e, 0x00,
|
||||
0x5f, 0xff,
|
||||
0x70, 0x00,
|
||||
0x71, 0x00,
|
||||
0x72, 0x00,
|
||||
0x74, 0x00,
|
||||
0x75, 0x00,
|
||||
0x76, 0x00,
|
||||
0x81, 0x00,
|
||||
0x82, 0x3f,
|
||||
0x83, 0x3f,
|
||||
0x84, 0x00,
|
||||
0x85, 0x00,
|
||||
0x88, 0x00,
|
||||
0x89, 0x00,
|
||||
0x8a, 0x00,
|
||||
0x8b, 0x00,
|
||||
0x8c, 0x00,
|
||||
0x90, 0x00,
|
||||
0x91, 0x00,
|
||||
0x92, 0x00,
|
||||
0x93, 0x00,
|
||||
0x94, 0x1c,
|
||||
0x97, 0x00,
|
||||
0xa0, 0x48,
|
||||
0xa1, 0x00,
|
||||
0xb0, 0xb8,
|
||||
0xb1, 0x3a,
|
||||
0xb2, 0x10,
|
||||
0xb3, 0x82,
|
||||
0xb4, 0x80,
|
||||
0xb5, 0x82,
|
||||
0xb6, 0x82,
|
||||
0xb7, 0x82,
|
||||
0xb8, 0x20,
|
||||
0xb9, 0x00,
|
||||
0xf0, 0x00,
|
||||
0xf1, 0x00,
|
||||
0xf2, 0xc0,
|
||||
0xff,0xff,
|
||||
};
|
||||
|
||||
static struct stv0288_config earda_config = {
|
||||
.demod_address = 0x68,
|
||||
.min_delay_ms = 100,
|
||||
.inittab = stv0288_earda_inittab,
|
||||
};
|
||||
|
||||
#endif
|
454
drivers/media/dvb/frontends/lgs8gl5.c
Normal file
454
drivers/media/dvb/frontends/lgs8gl5.c
Normal file
@ -0,0 +1,454 @@
|
||||
/*
|
||||
Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
|
||||
|
||||
Copyright (C) 2008 Sirius International (Hong Kong) Limited
|
||||
Timothy Lee <timothy.lee@siriushk.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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "lgs8gl5.h"
|
||||
|
||||
|
||||
#define REG_RESET 0x02
|
||||
#define REG_RESET_OFF 0x01
|
||||
#define REG_03 0x03
|
||||
#define REG_04 0x04
|
||||
#define REG_07 0x07
|
||||
#define REG_09 0x09
|
||||
#define REG_0A 0x0a
|
||||
#define REG_0B 0x0b
|
||||
#define REG_0C 0x0c
|
||||
#define REG_37 0x37
|
||||
#define REG_STRENGTH 0x4b
|
||||
#define REG_STRENGTH_MASK 0x7f
|
||||
#define REG_STRENGTH_CARRIER 0x80
|
||||
#define REG_INVERSION 0x7c
|
||||
#define REG_INVERSION_ON 0x80
|
||||
#define REG_7D 0x7d
|
||||
#define REG_7E 0x7e
|
||||
#define REG_A2 0xa2
|
||||
#define REG_STATUS 0xa4
|
||||
#define REG_STATUS_SYNC 0x04
|
||||
#define REG_STATUS_LOCK 0x01
|
||||
|
||||
|
||||
struct lgs8gl5_state {
|
||||
struct i2c_adapter *i2c;
|
||||
const struct lgs8gl5_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
};
|
||||
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "lgs8gl5: " args); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Writes into demod's register */
|
||||
static int
|
||||
lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[] = {reg, data};
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = 2
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
|
||||
__func__, reg, data, ret);
|
||||
return (ret != 1) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Reads from demod's register */
|
||||
static int
|
||||
lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b0[] = {reg};
|
||||
u8 b1[] = {0};
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = b0,
|
||||
.len = 1
|
||||
},
|
||||
{
|
||||
.addr = state->config->demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b1,
|
||||
.len = 1
|
||||
}
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
return b1[0];
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
|
||||
{
|
||||
lgs8gl5_read_reg(state, reg);
|
||||
lgs8gl5_write_reg(state, reg, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Writes into alternate device's register */
|
||||
/* TODO: Find out what that device is for! */
|
||||
static int
|
||||
lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 b0[] = {reg};
|
||||
u8 b1[] = {0};
|
||||
u8 b2[] = {reg, data};
|
||||
struct i2c_msg msg[3] = {
|
||||
{
|
||||
.addr = state->config->demod_address + 2,
|
||||
.flags = 0,
|
||||
.buf = b0,
|
||||
.len = 1
|
||||
},
|
||||
{
|
||||
.addr = state->config->demod_address + 2,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b1,
|
||||
.len = 1
|
||||
},
|
||||
{
|
||||
.addr = state->config->demod_address + 2,
|
||||
.flags = 0,
|
||||
.buf = b2,
|
||||
.len = 2
|
||||
},
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 3);
|
||||
return (ret != 3) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lgs8gl5_soft_reset(struct lgs8gl5_state *state)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
val = lgs8gl5_read_reg(state, REG_RESET);
|
||||
lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF);
|
||||
lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF);
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
|
||||
/* Starts demodulation */
|
||||
static void
|
||||
lgs8gl5_start_demod(struct lgs8gl5_state *state)
|
||||
{
|
||||
u8 val;
|
||||
int n;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
|
||||
lgs8gl5_soft_reset(state);
|
||||
lgs8gl5_update_reg(state, REG_07, 0x10);
|
||||
lgs8gl5_update_reg(state, REG_07, 0x10);
|
||||
lgs8gl5_write_reg(state, REG_09, 0x0e);
|
||||
lgs8gl5_write_reg(state, REG_0A, 0xe5);
|
||||
lgs8gl5_write_reg(state, REG_0B, 0x35);
|
||||
lgs8gl5_write_reg(state, REG_0C, 0x30);
|
||||
|
||||
lgs8gl5_update_reg(state, REG_03, 0x00);
|
||||
lgs8gl5_update_reg(state, REG_7E, 0x01);
|
||||
lgs8gl5_update_alt_reg(state, 0xc5, 0x00);
|
||||
lgs8gl5_update_reg(state, REG_04, 0x02);
|
||||
lgs8gl5_update_reg(state, REG_37, 0x01);
|
||||
lgs8gl5_soft_reset(state);
|
||||
|
||||
/* Wait for carrier */
|
||||
for (n = 0; n < 10; n++) {
|
||||
val = lgs8gl5_read_reg(state, REG_STRENGTH);
|
||||
dprintk("Wait for carrier[%d] 0x%02X\n", n, val);
|
||||
if (val & REG_STRENGTH_CARRIER)
|
||||
break;
|
||||
msleep(4);
|
||||
}
|
||||
if (!(val & REG_STRENGTH_CARRIER))
|
||||
return;
|
||||
|
||||
/* Wait for lock */
|
||||
for (n = 0; n < 20; n++) {
|
||||
val = lgs8gl5_read_reg(state, REG_STATUS);
|
||||
dprintk("Wait for lock[%d] 0x%02X\n", n, val);
|
||||
if (val & REG_STATUS_LOCK)
|
||||
break;
|
||||
msleep(12);
|
||||
}
|
||||
if (!(val & REG_STATUS_LOCK))
|
||||
return;
|
||||
|
||||
lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2));
|
||||
lgs8gl5_soft_reset(state);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
lgs8gl5_update_alt_reg(state, 0xc2, 0x28);
|
||||
lgs8gl5_soft_reset(state);
|
||||
lgs8gl5_update_reg(state, REG_07, 0x10);
|
||||
lgs8gl5_update_reg(state, REG_07, 0x10);
|
||||
lgs8gl5_write_reg(state, REG_09, 0x0e);
|
||||
lgs8gl5_write_reg(state, REG_0A, 0xe5);
|
||||
lgs8gl5_write_reg(state, REG_0B, 0x35);
|
||||
lgs8gl5_write_reg(state, REG_0C, 0x30);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
|
||||
u8 flags = lgs8gl5_read_reg(state, REG_STATUS);
|
||||
|
||||
*status = 0;
|
||||
|
||||
if ((level & REG_STRENGTH_MASK) > 0)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
if (level & REG_STRENGTH_CARRIER)
|
||||
*status |= FE_HAS_CARRIER;
|
||||
if (flags & REG_STATUS_SYNC)
|
||||
*status |= FE_HAS_SYNC;
|
||||
if (flags & REG_STATUS_LOCK)
|
||||
*status |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
*ber = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
|
||||
*signal_strength = (level & REG_STRENGTH_MASK) << 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
u8 level = lgs8gl5_read_reg(state, REG_STRENGTH);
|
||||
*snr = (level & REG_STRENGTH_MASK) << 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
*ucblocks = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)
|
||||
return -EINVAL;
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe, p);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
/* lgs8gl5_set_inversion(state, p->inversion); */
|
||||
|
||||
lgs8gl5_start_demod(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_get_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
|
||||
struct dvb_ofdm_parameters *o = &p->u.ofdm;
|
||||
|
||||
p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
|
||||
|
||||
o->code_rate_HP = FEC_1_2;
|
||||
o->code_rate_LP = FEC_7_8;
|
||||
o->guard_interval = GUARD_INTERVAL_1_32;
|
||||
o->transmission_mode = TRANSMISSION_MODE_2K;
|
||||
o->constellation = QAM_64;
|
||||
o->hierarchy_information = HIERARCHY_NONE;
|
||||
o->bandwidth = BANDWIDTH_8_MHZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lgs8gl5_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *fesettings)
|
||||
{
|
||||
fesettings->min_delay_ms = 240;
|
||||
fesettings->step_size = 0;
|
||||
fesettings->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lgs8gl5_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lgs8gl5_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops lgs8gl5_ops;
|
||||
|
||||
|
||||
struct dvb_frontend*
|
||||
lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
struct lgs8gl5_state *state = NULL;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* Allocate memory for the internal state */
|
||||
state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* Setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
||||
/* Check if the demod is there */
|
||||
if (lgs8gl5_read_reg(state, REG_RESET) < 0)
|
||||
goto error;
|
||||
|
||||
/* Create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &lgs8gl5_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(lgs8gl5_attach);
|
||||
|
||||
|
||||
static struct dvb_frontend_ops lgs8gl5_ops = {
|
||||
.info = {
|
||||
.name = "Legend Silicon LGS-8GL5 DMB-TH",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 474000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 10000,
|
||||
.frequency_tolerance = 0,
|
||||
.caps = FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
|
||||
FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_BANDWIDTH_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO |
|
||||
FE_CAN_RECOVER
|
||||
},
|
||||
|
||||
.release = lgs8gl5_release,
|
||||
|
||||
.init = lgs8gl5_init,
|
||||
|
||||
.set_frontend = lgs8gl5_set_frontend,
|
||||
.get_frontend = lgs8gl5_get_frontend,
|
||||
.get_tune_settings = lgs8gl5_get_tune_settings,
|
||||
|
||||
.read_status = lgs8gl5_read_status,
|
||||
.read_ber = lgs8gl5_read_ber,
|
||||
.read_signal_strength = lgs8gl5_read_signal_strength,
|
||||
.read_snr = lgs8gl5_read_snr,
|
||||
.read_ucblocks = lgs8gl5_read_ucblocks,
|
||||
};
|
||||
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
|
||||
MODULE_AUTHOR("Timothy Lee");
|
||||
MODULE_LICENSE("GPL");
|
45
drivers/media/dvb/frontends/lgs8gl5.h
Normal file
45
drivers/media/dvb/frontends/lgs8gl5.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
|
||||
|
||||
Copyright (C) 2008 Sirius International (Hong Kong) Limited
|
||||
Timothy Lee <timothy.lee@siriushk.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 LGS8GL5_H
|
||||
#define LGS8GL5_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct lgs8gl5_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_LGS8GL5) || \
|
||||
(defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *lgs8gl5_attach(
|
||||
const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *lgs8gl5_attach(
|
||||
const struct lgs8gl5_config *config, struct i2c_adapter *i2c) {
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_LGS8GL5 */
|
||||
|
||||
#endif /* LGS8GL5_H */
|
@ -80,7 +80,7 @@ static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len)
|
||||
static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
|
||||
{
|
||||
int err;
|
||||
struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
|
||||
@ -111,7 +111,7 @@ static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len)
|
||||
static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len)
|
||||
{
|
||||
u8 reg2 [] = { reg };
|
||||
|
||||
|
@ -88,7 +88,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len)
|
||||
static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
|
||||
{
|
||||
int err;
|
||||
struct i2c_msg msg;
|
||||
|
974
drivers/media/dvb/frontends/si21xx.c
Normal file
974
drivers/media/dvb/frontends/si21xx.c
Normal file
@ -0,0 +1,974 @@
|
||||
/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator
|
||||
*
|
||||
* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "si21xx.h"
|
||||
|
||||
#define REVISION_REG 0x00
|
||||
#define SYSTEM_MODE_REG 0x01
|
||||
#define TS_CTRL_REG_1 0x02
|
||||
#define TS_CTRL_REG_2 0x03
|
||||
#define PIN_CTRL_REG_1 0x04
|
||||
#define PIN_CTRL_REG_2 0x05
|
||||
#define LOCK_STATUS_REG_1 0x0f
|
||||
#define LOCK_STATUS_REG_2 0x10
|
||||
#define ACQ_STATUS_REG 0x11
|
||||
#define ACQ_CTRL_REG_1 0x13
|
||||
#define ACQ_CTRL_REG_2 0x14
|
||||
#define PLL_DIVISOR_REG 0x15
|
||||
#define COARSE_TUNE_REG 0x16
|
||||
#define FINE_TUNE_REG_L 0x17
|
||||
#define FINE_TUNE_REG_H 0x18
|
||||
|
||||
#define ANALOG_AGC_POWER_LEVEL_REG 0x28
|
||||
#define CFO_ESTIMATOR_CTRL_REG_1 0x29
|
||||
#define CFO_ESTIMATOR_CTRL_REG_2 0x2a
|
||||
#define CFO_ESTIMATOR_CTRL_REG_3 0x2b
|
||||
|
||||
#define SYM_RATE_ESTIMATE_REG_L 0x31
|
||||
#define SYM_RATE_ESTIMATE_REG_M 0x32
|
||||
#define SYM_RATE_ESTIMATE_REG_H 0x33
|
||||
|
||||
#define CFO_ESTIMATOR_OFFSET_REG_L 0x36
|
||||
#define CFO_ESTIMATOR_OFFSET_REG_H 0x37
|
||||
#define CFO_ERROR_REG_L 0x38
|
||||
#define CFO_ERROR_REG_H 0x39
|
||||
#define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a
|
||||
|
||||
#define SYM_RATE_REG_L 0x3f
|
||||
#define SYM_RATE_REG_M 0x40
|
||||
#define SYM_RATE_REG_H 0x41
|
||||
#define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42
|
||||
#define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43
|
||||
|
||||
#define C_N_ESTIMATOR_CTRL_REG 0x7c
|
||||
#define C_N_ESTIMATOR_THRSHLD_REG 0x7d
|
||||
#define C_N_ESTIMATOR_LEVEL_REG_L 0x7e
|
||||
#define C_N_ESTIMATOR_LEVEL_REG_H 0x7f
|
||||
|
||||
#define BLIND_SCAN_CTRL_REG 0x80
|
||||
|
||||
#define LSA_CTRL_REG_1 0x8D
|
||||
#define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f
|
||||
#define ONE_DB_BNDWDTH_THRSHLD_REG 0x90
|
||||
#define TWO_DB_BNDWDTH_THRSHLD_REG 0x91
|
||||
#define THREE_DB_BNDWDTH_THRSHLD_REG 0x92
|
||||
#define INBAND_POWER_THRSHLD_REG 0x93
|
||||
#define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94
|
||||
|
||||
#define VIT_SRCH_CTRL_REG_1 0xa0
|
||||
#define VIT_SRCH_CTRL_REG_2 0xa1
|
||||
#define VIT_SRCH_CTRL_REG_3 0xa2
|
||||
#define VIT_SRCH_STATUS_REG 0xa3
|
||||
#define VITERBI_BER_COUNT_REG_L 0xab
|
||||
#define REED_SOLOMON_CTRL_REG 0xb0
|
||||
#define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1
|
||||
#define PRBS_CTRL_REG 0xb5
|
||||
|
||||
#define LNB_CTRL_REG_1 0xc0
|
||||
#define LNB_CTRL_REG_2 0xc1
|
||||
#define LNB_CTRL_REG_3 0xc2
|
||||
#define LNB_CTRL_REG_4 0xc3
|
||||
#define LNB_CTRL_STATUS_REG 0xc4
|
||||
#define LNB_FIFO_REGS_0 0xc5
|
||||
#define LNB_FIFO_REGS_1 0xc6
|
||||
#define LNB_FIFO_REGS_2 0xc7
|
||||
#define LNB_FIFO_REGS_3 0xc8
|
||||
#define LNB_FIFO_REGS_4 0xc9
|
||||
#define LNB_FIFO_REGS_5 0xca
|
||||
#define LNB_SUPPLY_CTRL_REG_1 0xcb
|
||||
#define LNB_SUPPLY_CTRL_REG_2 0xcc
|
||||
#define LNB_SUPPLY_CTRL_REG_3 0xcd
|
||||
#define LNB_SUPPLY_CTRL_REG_4 0xce
|
||||
#define LNB_SUPPLY_STATUS_REG 0xcf
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define FAIL -1
|
||||
#define PASS 0
|
||||
|
||||
#define ALLOWABLE_FS_COUNT 10
|
||||
#define STATUS_BER 0
|
||||
#define STATUS_UCBLOCKS 1
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "si21xx: " args); \
|
||||
} while (0)
|
||||
|
||||
enum {
|
||||
ACTIVE_HIGH,
|
||||
ACTIVE_LOW
|
||||
};
|
||||
enum {
|
||||
BYTE_WIDE,
|
||||
BIT_WIDE
|
||||
};
|
||||
enum {
|
||||
CLK_GAPPED_MODE,
|
||||
CLK_CONTINUOUS_MODE
|
||||
};
|
||||
enum {
|
||||
RISING_EDGE,
|
||||
FALLING_EDGE
|
||||
};
|
||||
enum {
|
||||
MSB_FIRST,
|
||||
LSB_FIRST
|
||||
};
|
||||
enum {
|
||||
SERIAL,
|
||||
PARALLEL
|
||||
};
|
||||
|
||||
struct si21xx_state {
|
||||
struct i2c_adapter *i2c;
|
||||
const struct si21xx_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
u8 initialised:1;
|
||||
int errmode;
|
||||
int fs; /*Sampling rate of the ADC in MHz*/
|
||||
};
|
||||
|
||||
/* register default initialization */
|
||||
static u8 serit_sp1511lhb_inittab[] = {
|
||||
0x01, 0x28, /* set i2c_inc_disable */
|
||||
0x20, 0x03,
|
||||
0x27, 0x20,
|
||||
0xe0, 0x45,
|
||||
0xe1, 0x08,
|
||||
0xfe, 0x01,
|
||||
0x01, 0x28,
|
||||
0x89, 0x09,
|
||||
0x04, 0x80,
|
||||
0x05, 0x01,
|
||||
0x06, 0x00,
|
||||
0x20, 0x03,
|
||||
0x24, 0x88,
|
||||
0x29, 0x09,
|
||||
0x2a, 0x0f,
|
||||
0x2c, 0x10,
|
||||
0x2d, 0x19,
|
||||
0x2e, 0x08,
|
||||
0x2f, 0x10,
|
||||
0x30, 0x19,
|
||||
0x34, 0x20,
|
||||
0x35, 0x03,
|
||||
0x45, 0x02,
|
||||
0x46, 0x45,
|
||||
0x47, 0xd0,
|
||||
0x48, 0x00,
|
||||
0x49, 0x40,
|
||||
0x4a, 0x03,
|
||||
0x4c, 0xfd,
|
||||
0x4f, 0x2e,
|
||||
0x50, 0x2e,
|
||||
0x51, 0x10,
|
||||
0x52, 0x10,
|
||||
0x56, 0x92,
|
||||
0x59, 0x00,
|
||||
0x5a, 0x2d,
|
||||
0x5b, 0x33,
|
||||
0x5c, 0x1f,
|
||||
0x5f, 0x76,
|
||||
0x62, 0xc0,
|
||||
0x63, 0xc0,
|
||||
0x64, 0xf3,
|
||||
0x65, 0xf3,
|
||||
0x79, 0x40,
|
||||
0x6a, 0x40,
|
||||
0x6b, 0x0a,
|
||||
0x6c, 0x80,
|
||||
0x6d, 0x27,
|
||||
0x71, 0x06,
|
||||
0x75, 0x60,
|
||||
0x78, 0x00,
|
||||
0x79, 0xb5,
|
||||
0x7c, 0x05,
|
||||
0x7d, 0x1a,
|
||||
0x87, 0x55,
|
||||
0x88, 0x72,
|
||||
0x8f, 0x08,
|
||||
0x90, 0xe0,
|
||||
0x94, 0x40,
|
||||
0xa0, 0x3f,
|
||||
0xa1, 0xc0,
|
||||
0xa4, 0xcc,
|
||||
0xa5, 0x66,
|
||||
0xa6, 0x66,
|
||||
0xa7, 0x7b,
|
||||
0xa8, 0x7b,
|
||||
0xa9, 0x7b,
|
||||
0xaa, 0x9a,
|
||||
0xed, 0x04,
|
||||
0xad, 0x00,
|
||||
0xae, 0x03,
|
||||
0xcc, 0xab,
|
||||
0x01, 0x08,
|
||||
0xff, 0xff
|
||||
};
|
||||
|
||||
/* low level read/writes */
|
||||
static int si21_writeregs(struct si21xx_state *state, u8 reg1,
|
||||
u8 *data, int len)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[60];/* = { reg1, data };*/
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = len + 1
|
||||
};
|
||||
|
||||
msg.buf[0] = reg1;
|
||||
memcpy(msg.buf + 1, data, len);
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
|
||||
if (ret != 1)
|
||||
dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, "
|
||||
"ret == %i)\n", __func__, reg1, data[0], ret);
|
||||
|
||||
return (ret != 1) ? -EREMOTEIO : 0;
|
||||
}
|
||||
|
||||
static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = 2
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
|
||||
if (ret != 1)
|
||||
dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, "
|
||||
"ret == %i)\n", __func__, reg, data, ret);
|
||||
|
||||
return (ret != 1) ? -EREMOTEIO : 0;
|
||||
}
|
||||
|
||||
static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
if (len != 2)
|
||||
return -EINVAL;
|
||||
|
||||
return si21_writereg(state, buf[0], buf[1]);
|
||||
}
|
||||
|
||||
static u8 si21_readreg(struct si21xx_state *state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b0[] = { reg };
|
||||
u8 b1[] = { 0 };
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = b0,
|
||||
.len = 1
|
||||
}, {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b1,
|
||||
.len = 1
|
||||
}
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2)
|
||||
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
|
||||
__func__, reg, ret);
|
||||
|
||||
return b1[0];
|
||||
}
|
||||
|
||||
static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = ®1,
|
||||
.len = 1
|
||||
}, {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b,
|
||||
.len = len
|
||||
}
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2)
|
||||
dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
|
||||
|
||||
return ret == 2 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout)
|
||||
{
|
||||
unsigned long start = jiffies;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) {
|
||||
if (jiffies - start > timeout) {
|
||||
dprintk("%s: timeout!!\n", __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(10);
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u32 sym_rate, data_rate;
|
||||
int i;
|
||||
u8 sym_rate_bytes[3];
|
||||
|
||||
dprintk("%s : srate = %i\n", __func__ , srate);
|
||||
|
||||
if ((srate < 1000000) || (srate > 45000000))
|
||||
return -EINVAL;
|
||||
|
||||
data_rate = srate;
|
||||
sym_rate = 0;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
sym_rate /= 100;
|
||||
sym_rate = sym_rate + ((data_rate % 100) * 0x800000) /
|
||||
state->fs;
|
||||
data_rate /= 100;
|
||||
}
|
||||
for (i = 0; i < 3; ++i)
|
||||
sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff);
|
||||
|
||||
si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21xx_send_diseqc_msg(struct dvb_frontend *fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u8 lnb_status;
|
||||
u8 LNB_CTRL_1;
|
||||
int status;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
status = PASS;
|
||||
LNB_CTRL_1 = 0;
|
||||
|
||||
status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01);
|
||||
status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01);
|
||||
|
||||
/*fill the FIFO*/
|
||||
status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len);
|
||||
|
||||
LNB_CTRL_1 = (lnb_status & 0x70);
|
||||
LNB_CTRL_1 |= m->msg_len;
|
||||
|
||||
LNB_CTRL_1 |= 0x80; /* begin LNB signaling */
|
||||
|
||||
status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int si21xx_send_diseqc_burst(struct dvb_frontend *fe,
|
||||
fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u8 val;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (si21xx_wait_diseqc_idle(state, 100) < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
val = (0x80 | si21_readreg(state, 0xc1));
|
||||
if (si21_writereg(state, LNB_CTRL_REG_1,
|
||||
burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10)))
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (si21xx_wait_diseqc_idle(state, 100) < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (si21_writereg(state, LNB_CTRL_REG_1, val))
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* 30.06.2008 */
|
||||
static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u8 val;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
|
||||
|
||||
switch (tone) {
|
||||
case SEC_TONE_ON:
|
||||
return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20);
|
||||
|
||||
case SEC_TONE_OFF:
|
||||
return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20));
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
u8 val;
|
||||
dprintk("%s: %s\n", __func__,
|
||||
volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
|
||||
volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
|
||||
|
||||
|
||||
val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1));
|
||||
|
||||
switch (volt) {
|
||||
case SEC_VOLTAGE_18:
|
||||
return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40);
|
||||
break;
|
||||
case SEC_VOLTAGE_13:
|
||||
return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
|
||||
static int si21xx_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
int i;
|
||||
int status = 0;
|
||||
u8 reg1;
|
||||
u8 val;
|
||||
u8 reg2[2];
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
for (i = 0; ; i += 2) {
|
||||
reg1 = serit_sp1511lhb_inittab[i];
|
||||
val = serit_sp1511lhb_inittab[i+1];
|
||||
if (reg1 == 0xff && val == 0xff)
|
||||
break;
|
||||
si21_writeregs(state, reg1, &val, 1);
|
||||
}
|
||||
|
||||
/*DVB QPSK SYSTEM MODE REG*/
|
||||
reg1 = 0x08;
|
||||
si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01);
|
||||
|
||||
/*transport stream config*/
|
||||
/*
|
||||
mode = PARALLEL;
|
||||
sdata_form = LSB_FIRST;
|
||||
clk_edge = FALLING_EDGE;
|
||||
clk_mode = CLK_GAPPED_MODE;
|
||||
strt_len = BYTE_WIDE;
|
||||
sync_pol = ACTIVE_HIGH;
|
||||
val_pol = ACTIVE_HIGH;
|
||||
err_pol = ACTIVE_HIGH;
|
||||
sclk_rate = 0x00;
|
||||
parity = 0x00 ;
|
||||
data_delay = 0x00;
|
||||
clk_delay = 0x00;
|
||||
pclk_smooth = 0x00;
|
||||
*/
|
||||
reg2[0] =
|
||||
PARALLEL + (LSB_FIRST << 1)
|
||||
+ (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3)
|
||||
+ (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5)
|
||||
+ (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7);
|
||||
|
||||
reg2[1] = 0;
|
||||
/* sclk_rate + (parity << 2)
|
||||
+ (data_delay << 3) + (clk_delay << 4)
|
||||
+ (pclk_smooth << 5);
|
||||
*/
|
||||
status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02);
|
||||
if (status != 0)
|
||||
dprintk(" %s : TS Set Error\n", __func__);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u8 regs_read[2];
|
||||
u8 reg_read;
|
||||
u8 i;
|
||||
u8 lock;
|
||||
u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG);
|
||||
|
||||
si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02);
|
||||
reg_read = 0;
|
||||
|
||||
for (i = 0; i < 7; ++i)
|
||||
reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i);
|
||||
|
||||
lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80));
|
||||
|
||||
dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock);
|
||||
*status = 0;
|
||||
|
||||
if (signal > 10)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
|
||||
if (lock & 0x2)
|
||||
*status |= FE_HAS_CARRIER;
|
||||
|
||||
if (lock & 0x20)
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
if (lock & 0x40)
|
||||
*status |= FE_HAS_SYNC;
|
||||
|
||||
if ((lock & 0x7b) == 0x7b)
|
||||
*status |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
/*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG,
|
||||
(u8*)agclevel, 0x01);*/
|
||||
|
||||
u16 signal = (3 * si21_readreg(state, 0x27) *
|
||||
si21_readreg(state, 0x28));
|
||||
|
||||
dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__,
|
||||
si21_readreg(state, 0x27),
|
||||
si21_readreg(state, 0x28), (int) signal);
|
||||
|
||||
signal <<= 4;
|
||||
*strength = signal;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (state->errmode != STATUS_BER)
|
||||
return 0;
|
||||
|
||||
*ber = (si21_readreg(state, 0x1d) << 8) |
|
||||
si21_readreg(state, 0x1e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) |
|
||||
si21_readreg(state, 0x25));
|
||||
xsnr = 3 * (xsnr - 0xa100);
|
||||
*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (state->errmode != STATUS_UCBLOCKS)
|
||||
*ucblocks = 0;
|
||||
else
|
||||
*ucblocks = (si21_readreg(state, 0x1d) << 8) |
|
||||
si21_readreg(state, 0x1e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initiates a channel acquisition sequence
|
||||
using the specified symbol rate and code rate */
|
||||
static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
|
||||
fe_code_rate_t crate)
|
||||
{
|
||||
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u8 coderates[] = {
|
||||
0x0, 0x01, 0x02, 0x04, 0x00,
|
||||
0x8, 0x10, 0x20, 0x00, 0x3f
|
||||
};
|
||||
|
||||
u8 coderate_ptr;
|
||||
int status;
|
||||
u8 start_acq = 0x80;
|
||||
u8 reg, regs[3];
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
status = PASS;
|
||||
coderate_ptr = coderates[crate];
|
||||
|
||||
si21xx_set_symbolrate(fe, symbrate);
|
||||
|
||||
/* write code rates to use in the Viterbi search */
|
||||
status |= si21_writeregs(state,
|
||||
VIT_SRCH_CTRL_REG_1,
|
||||
&coderate_ptr, 0x01);
|
||||
|
||||
/* clear acq_start bit */
|
||||
status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01);
|
||||
reg &= ~start_acq;
|
||||
status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01);
|
||||
|
||||
/* use new Carrier Frequency Offset Estimator (QuickLock) */
|
||||
regs[0] = 0xCB;
|
||||
regs[1] = 0x40;
|
||||
regs[2] = 0xCB;
|
||||
|
||||
status |= si21_writeregs(state,
|
||||
TWO_DB_BNDWDTH_THRSHLD_REG,
|
||||
®s[0], 0x03);
|
||||
reg = 0x56;
|
||||
status |= si21_writeregs(state,
|
||||
LSA_CTRL_REG_1, ®, 1);
|
||||
reg = 0x05;
|
||||
status |= si21_writeregs(state,
|
||||
BLIND_SCAN_CTRL_REG, ®, 1);
|
||||
/* start automatic acq */
|
||||
status |= si21_writeregs(state,
|
||||
ACQ_CTRL_REG_2, &start_acq, 0x01);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p)
|
||||
{
|
||||
dprintk("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p)
|
||||
{
|
||||
dprintk("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21xx_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *dfp)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
/* freq Channel carrier frequency in KHz (i.e. 1550000 KHz)
|
||||
datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/
|
||||
|
||||
/* in MHz */
|
||||
unsigned char coarse_tune_freq;
|
||||
int fine_tune_freq;
|
||||
unsigned char sample_rate = 0;
|
||||
/* boolean */
|
||||
unsigned int inband_interferer_ind;
|
||||
|
||||
/* INTERMEDIATE VALUES */
|
||||
int icoarse_tune_freq; /* MHz */
|
||||
int ifine_tune_freq; /* MHz */
|
||||
unsigned int band_high;
|
||||
unsigned int band_low;
|
||||
unsigned int x1;
|
||||
unsigned int x2;
|
||||
int i;
|
||||
unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = {
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = {
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE,
|
||||
FALSE, FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
int status;
|
||||
|
||||
/* allowable sample rates for ADC in MHz */
|
||||
int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195,
|
||||
196, 204, 205, 206, 207
|
||||
};
|
||||
/* in MHz */
|
||||
int if_limit_high;
|
||||
int if_limit_low;
|
||||
int lnb_lo;
|
||||
int lnb_uncertanity;
|
||||
|
||||
int rf_freq;
|
||||
int data_rate;
|
||||
unsigned char regs[4];
|
||||
|
||||
dprintk("%s : FE_SET_FRONTEND\n", __func__);
|
||||
|
||||
if (c->delivery_system != SYS_DVBS) {
|
||||
dprintk("%s: unsupported delivery system selected (%d)\n",
|
||||
__func__, c->delivery_system);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
|
||||
inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE;
|
||||
|
||||
if_limit_high = -700000;
|
||||
if_limit_low = -100000;
|
||||
/* in MHz */
|
||||
lnb_lo = 0;
|
||||
lnb_uncertanity = 0;
|
||||
|
||||
rf_freq = 10 * c->frequency ;
|
||||
data_rate = c->symbol_rate / 100;
|
||||
|
||||
status = PASS;
|
||||
|
||||
band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200)
|
||||
+ (data_rate * 135)) / 200;
|
||||
|
||||
band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200)
|
||||
+ (data_rate * 135)) / 200;
|
||||
|
||||
|
||||
icoarse_tune_freq = 100000 *
|
||||
(((rf_freq - lnb_lo) -
|
||||
(if_limit_low + if_limit_high) / 2)
|
||||
/ 100000);
|
||||
|
||||
ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ;
|
||||
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
|
||||
(afs[i] * 2500) + afs[i] * 2500;
|
||||
|
||||
x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) *
|
||||
(afs[i] * 2500);
|
||||
|
||||
if (((band_low < x1) && (x1 < band_high)) ||
|
||||
((band_low < x2) && (x2 < band_high)))
|
||||
inband_interferer_div4[i] = TRUE;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
|
||||
(afs[i] * 5000) + afs[i] * 5000;
|
||||
|
||||
x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) *
|
||||
(afs[i] * 5000);
|
||||
|
||||
if (((band_low < x1) && (x1 < band_high)) ||
|
||||
((band_low < x2) && (x2 < band_high)))
|
||||
inband_interferer_div2[i] = TRUE;
|
||||
}
|
||||
|
||||
inband_interferer_ind = TRUE;
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
|
||||
inband_interferer_ind &= inband_interferer_div2[i] |
|
||||
inband_interferer_div4[i];
|
||||
|
||||
if (inband_interferer_ind) {
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
if (inband_interferer_div2[i] == FALSE) {
|
||||
sample_rate = (u8) afs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
|
||||
if ((inband_interferer_div2[i] |
|
||||
inband_interferer_div4[i]) == FALSE) {
|
||||
sample_rate = (u8) afs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sample_rate > 207 || sample_rate < 192)
|
||||
sample_rate = 200;
|
||||
|
||||
fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) /
|
||||
((sample_rate) * 1000));
|
||||
|
||||
coarse_tune_freq = (u8)(icoarse_tune_freq / 100000);
|
||||
|
||||
regs[0] = sample_rate;
|
||||
regs[1] = coarse_tune_freq;
|
||||
regs[2] = fine_tune_freq & 0xFF;
|
||||
regs[3] = fine_tune_freq >> 8 & 0xFF;
|
||||
|
||||
status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04);
|
||||
|
||||
state->fs = sample_rate;/*ADC MHz*/
|
||||
si21xx_setacquire(fe, c->symbol_rate, c->fec_inner);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int si21xx_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
u8 regdata;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01);
|
||||
regdata |= 1 << 6;
|
||||
si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01);
|
||||
state->initialised = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void si21xx_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct si21xx_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops si21xx_ops = {
|
||||
|
||||
.info = {
|
||||
.name = "SL SI21XX DVB-S",
|
||||
.type = FE_QPSK,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 125, /* kHz for QPSK frontends */
|
||||
.frequency_tolerance = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.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_QPSK |
|
||||
FE_CAN_FEC_AUTO
|
||||
},
|
||||
|
||||
.release = si21xx_release,
|
||||
.init = si21xx_init,
|
||||
.sleep = si21xx_sleep,
|
||||
.write = si21_write,
|
||||
.read_status = si21_read_status,
|
||||
.read_ber = si21_read_ber,
|
||||
.read_signal_strength = si21_read_signal_strength,
|
||||
.read_snr = si21_read_snr,
|
||||
.read_ucblocks = si21_read_ucblocks,
|
||||
.diseqc_send_master_cmd = si21xx_send_diseqc_msg,
|
||||
.diseqc_send_burst = si21xx_send_diseqc_burst,
|
||||
.set_tone = si21xx_set_tone,
|
||||
.set_voltage = si21xx_set_voltage,
|
||||
|
||||
.set_property = si21xx_set_property,
|
||||
.get_property = si21xx_get_property,
|
||||
.set_frontend = si21xx_set_frontend,
|
||||
};
|
||||
|
||||
struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct si21xx_state *state = NULL;
|
||||
int id;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->initialised = 0;
|
||||
state->errmode = STATUS_BER;
|
||||
|
||||
/* check if the demod is there */
|
||||
id = si21_readreg(state, SYSTEM_MODE_REG);
|
||||
si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */
|
||||
msleep(200);
|
||||
id = si21_readreg(state, 0x00);
|
||||
|
||||
/* register 0x00 contains:
|
||||
0x34 for SI2107
|
||||
0x24 for SI2108
|
||||
0x14 for SI2109
|
||||
0x04 for SI2110
|
||||
*/
|
||||
if (id != 0x04 && id != 0x14)
|
||||
goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &si21xx_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(si21xx_attach);
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver");
|
||||
MODULE_AUTHOR("Igor M. Liplianin");
|
||||
MODULE_LICENSE("GPL");
|
37
drivers/media/dvb/frontends/si21xx.h
Normal file
37
drivers/media/dvb/frontends/si21xx.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef SI21XX_H
|
||||
#define SI21XX_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
struct si21xx_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* minimum delay before retuning */
|
||||
int min_delay_ms;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_SI21XX) || \
|
||||
(defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *si21xx_attach(
|
||||
const struct si21xx_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val)
|
||||
{
|
||||
int r = 0;
|
||||
u8 buf[] = {reg, val};
|
||||
if (fe->ops.write)
|
||||
r = fe->ops.write(fe, buf, 2);
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
@ -337,7 +337,8 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
{
|
||||
struct sp887x_state* state = fe->demodulator_priv;
|
||||
int actual_freq, err;
|
||||
unsigned actual_freq;
|
||||
int err;
|
||||
u16 val, reg0xc05;
|
||||
|
||||
if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ &&
|
||||
|
255
drivers/media/dvb/frontends/stb6000.c
Normal file
255
drivers/media/dvb/frontends/stb6000.c
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
Driver for ST STB6000 DVBS Silicon tuner
|
||||
|
||||
Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
|
||||
|
||||
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/module.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include "stb6000.h"
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "stb6000: " args); \
|
||||
} while (0)
|
||||
|
||||
struct stb6000_priv {
|
||||
/* i2c details */
|
||||
int i2c_address;
|
||||
struct i2c_adapter *i2c;
|
||||
u32 frequency;
|
||||
};
|
||||
|
||||
static int stb6000_release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6000_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stb6000_priv *priv = fe->tuner_priv;
|
||||
int ret;
|
||||
u8 buf[] = { 10, 0 };
|
||||
struct i2c_msg msg = {
|
||||
.addr = priv->i2c_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = 2
|
||||
};
|
||||
|
||||
dprintk("%s:\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
dprintk("%s: i2c error\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return (ret == 1) ? 0 : ret;
|
||||
}
|
||||
|
||||
static int stb6000_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct stb6000_priv *priv = fe->tuner_priv;
|
||||
unsigned int n, m;
|
||||
int ret;
|
||||
u32 freq_mhz;
|
||||
int bandwidth;
|
||||
u8 buf[12];
|
||||
struct i2c_msg msg = {
|
||||
.addr = priv->i2c_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = 12
|
||||
};
|
||||
|
||||
dprintk("%s:\n", __func__);
|
||||
|
||||
freq_mhz = params->frequency / 1000;
|
||||
bandwidth = params->u.qpsk.symbol_rate / 1000000;
|
||||
|
||||
if (bandwidth > 31)
|
||||
bandwidth = 31;
|
||||
|
||||
if ((freq_mhz > 949) && (freq_mhz < 2151)) {
|
||||
buf[0] = 0x01;
|
||||
buf[1] = 0xac;
|
||||
if (freq_mhz < 1950)
|
||||
buf[1] = 0xaa;
|
||||
if (freq_mhz < 1800)
|
||||
buf[1] = 0xa8;
|
||||
if (freq_mhz < 1650)
|
||||
buf[1] = 0xa6;
|
||||
if (freq_mhz < 1530)
|
||||
buf[1] = 0xa5;
|
||||
if (freq_mhz < 1470)
|
||||
buf[1] = 0xa4;
|
||||
if (freq_mhz < 1370)
|
||||
buf[1] = 0xa2;
|
||||
if (freq_mhz < 1300)
|
||||
buf[1] = 0xa1;
|
||||
if (freq_mhz < 1200)
|
||||
buf[1] = 0xa0;
|
||||
if (freq_mhz < 1075)
|
||||
buf[1] = 0xbc;
|
||||
if (freq_mhz < 1000)
|
||||
buf[1] = 0xba;
|
||||
if (freq_mhz < 1075) {
|
||||
n = freq_mhz / 8; /* vco=lo*4 */
|
||||
m = 2;
|
||||
} else {
|
||||
n = freq_mhz / 16; /* vco=lo*2 */
|
||||
m = 1;
|
||||
}
|
||||
buf[2] = n >> 1;
|
||||
buf[3] = (unsigned char)(((n & 1) << 7) |
|
||||
(m * freq_mhz - n * 16) | 0x60);
|
||||
buf[4] = 0x04;
|
||||
buf[5] = 0x0e;
|
||||
|
||||
buf[6] = (unsigned char)(bandwidth);
|
||||
|
||||
buf[7] = 0xd8;
|
||||
buf[8] = 0xd0;
|
||||
buf[9] = 0x50;
|
||||
buf[10] = 0xeb;
|
||||
buf[11] = 0x4f;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
dprintk("%s: i2c error\n", __func__);
|
||||
|
||||
udelay(10);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
buf[0] = 0x07;
|
||||
buf[1] = 0xdf;
|
||||
buf[2] = 0xd0;
|
||||
buf[3] = 0x50;
|
||||
buf[4] = 0xfb;
|
||||
msg.len = 5;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
dprintk("%s: i2c error\n", __func__);
|
||||
|
||||
udelay(10);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
priv->frequency = freq_mhz * 1000;
|
||||
|
||||
return (ret == 1) ? 0 : ret;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct stb6000_priv *priv = fe->tuner_priv;
|
||||
*frequency = priv->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops stb6000_tuner_ops = {
|
||||
.info = {
|
||||
.name = "ST STB6000",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000
|
||||
},
|
||||
.release = stb6000_release,
|
||||
.sleep = stb6000_sleep,
|
||||
.set_params = stb6000_set_params,
|
||||
.get_frequency = stb6000_get_frequency,
|
||||
};
|
||||
|
||||
struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct stb6000_priv *priv = NULL;
|
||||
u8 b0[] = { 0 };
|
||||
u8 b1[] = { 0, 0 };
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = addr,
|
||||
.flags = 0,
|
||||
.buf = b0,
|
||||
.len = 0
|
||||
}, {
|
||||
.addr = addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b1,
|
||||
.len = 2
|
||||
}
|
||||
};
|
||||
int ret;
|
||||
|
||||
dprintk("%s:\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
/* is some i2c device here ? */
|
||||
ret = i2c_transfer(i2c, msg, 2);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
if (ret != 2)
|
||||
return NULL;
|
||||
|
||||
priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
priv->i2c_address = addr;
|
||||
priv->i2c = i2c;
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL(stb6000_attach);
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("DVB STB6000 driver");
|
||||
MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
|
||||
MODULE_LICENSE("GPL");
|
51
drivers/media/dvb/frontends/stb6000.h
Normal file
51
drivers/media/dvb/frontends/stb6000.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Driver for ST stb6000 DVBS Silicon tuner
|
||||
|
||||
Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
|
||||
|
||||
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 __DVB_STB6000_H__
|
||||
#define __DVB_STB6000_H__
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
/**
|
||||
* Attach a stb6000 tuner to the supplied frontend structure.
|
||||
*
|
||||
* @param fe Frontend to attach to.
|
||||
* @param addr i2c address of the tuner.
|
||||
* @param i2c i2c adapter to use.
|
||||
* @return FE pointer on success, NULL on failure.
|
||||
*/
|
||||
#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \
|
||||
&& defined(MODULE))
|
||||
extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe,
|
||||
int addr,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_STB6000 */
|
||||
|
||||
#endif /* __DVB_STB6000_H__ */
|
618
drivers/media/dvb/frontends/stv0288.c
Normal file
618
drivers/media/dvb/frontends/stv0288.c
Normal file
@ -0,0 +1,618 @@
|
||||
/*
|
||||
Driver for ST STV0288 demodulator
|
||||
Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
|
||||
for Reel Multimedia
|
||||
Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com>
|
||||
Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
|
||||
Removed stb6000 specific tuner code and revised some
|
||||
procedures.
|
||||
|
||||
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 <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "stv0288.h"
|
||||
|
||||
struct stv0288_state {
|
||||
struct i2c_adapter *i2c;
|
||||
const struct stv0288_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u8 initialised:1;
|
||||
u32 tuner_frequency;
|
||||
u32 symbol_rate;
|
||||
fe_code_rate_t fec_inner;
|
||||
int errmode;
|
||||
};
|
||||
|
||||
#define STATUS_BER 0
|
||||
#define STATUS_UCBLOCKS 1
|
||||
|
||||
static int debug;
|
||||
static int debug_legacy_dish_switch;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "stv0288: " args); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = 2
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
|
||||
if (ret != 1)
|
||||
dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
|
||||
"ret == %i)\n", __func__, reg, data, ret);
|
||||
|
||||
return (ret != 1) ? -EREMOTEIO : 0;
|
||||
}
|
||||
|
||||
static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
if (len != 2)
|
||||
return -EINVAL;
|
||||
|
||||
return stv0288_writeregI(state, buf[0], buf[1]);
|
||||
}
|
||||
|
||||
static u8 stv0288_readreg(struct stv0288_state *state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b0[] = { reg };
|
||||
u8 b1[] = { 0 };
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = state->config->demod_address,
|
||||
.flags = 0,
|
||||
.buf = b0,
|
||||
.len = 1
|
||||
}, {
|
||||
.addr = state->config->demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b1,
|
||||
.len = 1
|
||||
}
|
||||
};
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2)
|
||||
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
|
||||
__func__, reg, ret);
|
||||
|
||||
return b1[0];
|
||||
}
|
||||
|
||||
static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
unsigned int temp;
|
||||
unsigned char b[3];
|
||||
|
||||
if ((srate < 1000000) || (srate > 45000000))
|
||||
return -EINVAL;
|
||||
|
||||
temp = (unsigned int)srate / 1000;
|
||||
|
||||
temp = temp * 32768;
|
||||
temp = temp / 25;
|
||||
temp = temp / 125;
|
||||
b[0] = (unsigned char)((temp >> 12) & 0xff);
|
||||
b[1] = (unsigned char)((temp >> 4) & 0xff);
|
||||
b[2] = (unsigned char)((temp << 4) & 0xf0);
|
||||
stv0288_writeregI(state, 0x28, 0x80); /* SFRH */
|
||||
stv0288_writeregI(state, 0x29, 0); /* SFRM */
|
||||
stv0288_writeregI(state, 0x2a, 0); /* SFRL */
|
||||
|
||||
stv0288_writeregI(state, 0x28, b[0]);
|
||||
stv0288_writeregI(state, 0x29, b[1]);
|
||||
stv0288_writeregI(state, 0x2a, b[2]);
|
||||
dprintk("stv0288: stv0288_set_symbolrate\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
int i;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
stv0288_writeregI(state, 0x09, 0);
|
||||
msleep(30);
|
||||
stv0288_writeregI(state, 0x05, 0x16);
|
||||
|
||||
for (i = 0; i < m->msg_len; i++) {
|
||||
if (stv0288_writeregI(state, 0x06, m->msg[i]))
|
||||
return -EREMOTEIO;
|
||||
msleep(12);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
|
||||
fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (stv0288_writeregI(state, 0x06, 0x12))
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
switch (tone) {
|
||||
case SEC_TONE_ON:
|
||||
if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
|
||||
return -EREMOTEIO;
|
||||
return stv0288_writeregI(state, 0x06, 0xff);
|
||||
|
||||
case SEC_TONE_OFF:
|
||||
if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
|
||||
return -EREMOTEIO;
|
||||
return stv0288_writeregI(state, 0x06, 0x00);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 stv0288_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x20,
|
||||
0x09, 0x0,
|
||||
0x0a, 0x4,
|
||||
0x0b, 0x0,
|
||||
0x0c, 0x0,
|
||||
0x0d, 0x0,
|
||||
0x0e, 0xd4,
|
||||
0x0f, 0x30,
|
||||
0x11, 0x80,
|
||||
0x12, 0x03,
|
||||
0x13, 0x48,
|
||||
0x14, 0x84,
|
||||
0x15, 0x45,
|
||||
0x16, 0xb7,
|
||||
0x17, 0x9c,
|
||||
0x18, 0x0,
|
||||
0x19, 0xa6,
|
||||
0x1a, 0x88,
|
||||
0x1b, 0x8f,
|
||||
0x1c, 0xf0,
|
||||
0x20, 0x0b,
|
||||
0x21, 0x54,
|
||||
0x22, 0x0,
|
||||
0x23, 0x0,
|
||||
0x2b, 0xff,
|
||||
0x2c, 0xf7,
|
||||
0x30, 0x0,
|
||||
0x31, 0x1e,
|
||||
0x32, 0x14,
|
||||
0x33, 0x0f,
|
||||
0x34, 0x09,
|
||||
0x35, 0x0c,
|
||||
0x36, 0x05,
|
||||
0x37, 0x2f,
|
||||
0x38, 0x16,
|
||||
0x39, 0xbe,
|
||||
0x3a, 0x0,
|
||||
0x3b, 0x13,
|
||||
0x3c, 0x11,
|
||||
0x3d, 0x30,
|
||||
0x40, 0x63,
|
||||
0x41, 0x04,
|
||||
0x42, 0x60,
|
||||
0x43, 0x00,
|
||||
0x44, 0x00,
|
||||
0x45, 0x00,
|
||||
0x46, 0x00,
|
||||
0x47, 0x00,
|
||||
0x4a, 0x00,
|
||||
0x50, 0x10,
|
||||
0x51, 0x38,
|
||||
0x52, 0x21,
|
||||
0x58, 0x54,
|
||||
0x59, 0x86,
|
||||
0x5a, 0x0,
|
||||
0x5b, 0x9b,
|
||||
0x5c, 0x08,
|
||||
0x5d, 0x7f,
|
||||
0x5e, 0x0,
|
||||
0x5f, 0xff,
|
||||
0x70, 0x0,
|
||||
0x71, 0x0,
|
||||
0x72, 0x0,
|
||||
0x74, 0x0,
|
||||
0x75, 0x0,
|
||||
0x76, 0x0,
|
||||
0x81, 0x0,
|
||||
0x82, 0x3f,
|
||||
0x83, 0x3f,
|
||||
0x84, 0x0,
|
||||
0x85, 0x0,
|
||||
0x88, 0x0,
|
||||
0x89, 0x0,
|
||||
0x8a, 0x0,
|
||||
0x8b, 0x0,
|
||||
0x8c, 0x0,
|
||||
0x90, 0x0,
|
||||
0x91, 0x0,
|
||||
0x92, 0x0,
|
||||
0x93, 0x0,
|
||||
0x94, 0x1c,
|
||||
0x97, 0x0,
|
||||
0xa0, 0x48,
|
||||
0xa1, 0x0,
|
||||
0xb0, 0xb8,
|
||||
0xb1, 0x3a,
|
||||
0xb2, 0x10,
|
||||
0xb3, 0x82,
|
||||
0xb4, 0x80,
|
||||
0xb5, 0x82,
|
||||
0xb6, 0x82,
|
||||
0xb7, 0x82,
|
||||
0xb8, 0x20,
|
||||
0xb9, 0x0,
|
||||
0xf0, 0x0,
|
||||
0xf1, 0x0,
|
||||
0xf2, 0xc0,
|
||||
0x51, 0x36,
|
||||
0x52, 0x09,
|
||||
0x53, 0x94,
|
||||
0x54, 0x62,
|
||||
0x55, 0x29,
|
||||
0x56, 0x64,
|
||||
0x57, 0x2b,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
|
||||
{
|
||||
dprintk("%s: %s\n", __func__,
|
||||
volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
|
||||
volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
int i;
|
||||
u8 reg;
|
||||
u8 val;
|
||||
|
||||
dprintk("stv0288: init chip\n");
|
||||
stv0288_writeregI(state, 0x41, 0x04);
|
||||
msleep(50);
|
||||
|
||||
/* we have default inittab */
|
||||
if (state->config->inittab == NULL) {
|
||||
for (i = 0; !(stv0288_inittab[i] == 0xff &&
|
||||
stv0288_inittab[i + 1] == 0xff); i += 2)
|
||||
stv0288_writeregI(state, stv0288_inittab[i],
|
||||
stv0288_inittab[i + 1]);
|
||||
} else {
|
||||
for (i = 0; ; i += 2) {
|
||||
reg = state->config->inittab[i];
|
||||
val = state->config->inittab[i+1];
|
||||
if (reg == 0xff && val == 0xff)
|
||||
break;
|
||||
stv0288_writeregI(state, reg, val);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
u8 sync = stv0288_readreg(state, 0x24);
|
||||
if (sync == 255)
|
||||
sync = 0;
|
||||
|
||||
dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
|
||||
|
||||
*status = 0;
|
||||
|
||||
if ((sync & 0x08) == 0x08) {
|
||||
*status |= FE_HAS_LOCK;
|
||||
dprintk("stv0288 has locked\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
if (state->errmode != STATUS_BER)
|
||||
return 0;
|
||||
*ber = (stv0288_readreg(state, 0x26) << 8) |
|
||||
stv0288_readreg(state, 0x27);
|
||||
dprintk("stv0288_read_ber %d\n", *ber);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8));
|
||||
|
||||
|
||||
signal = signal * 5 / 4;
|
||||
*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
|
||||
dprintk("stv0288_read_signal_strength %d\n", *strength);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int stv0288_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
stv0288_writeregI(state, 0x41, 0x84);
|
||||
state->initialised = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8)
|
||||
| stv0288_readreg(state, 0x2e));
|
||||
xsnr = 3 * (xsnr - 0xa100);
|
||||
*snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
|
||||
dprintk("stv0288_read_snr %d\n", *snr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
if (state->errmode != STATUS_BER)
|
||||
return 0;
|
||||
*ucblocks = (stv0288_readreg(state, 0x26) << 8) |
|
||||
stv0288_readreg(state, 0x27);
|
||||
dprintk("stv0288_read_ber %d\n", *ucblocks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
|
||||
{
|
||||
dprintk("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p)
|
||||
{
|
||||
dprintk("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *dfp)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
char tm;
|
||||
unsigned char tda[3];
|
||||
|
||||
dprintk("%s : FE_SET_FRONTEND\n", __func__);
|
||||
|
||||
if (c->delivery_system != SYS_DVBS) {
|
||||
dprintk("%s: unsupported delivery "
|
||||
"system selected (%d)\n",
|
||||
__func__, c->delivery_system);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (state->config->set_ts_params)
|
||||
state->config->set_ts_params(fe, 0);
|
||||
|
||||
/* only frequency & symbol_rate are used for tuner*/
|
||||
dfp->frequency = c->frequency;
|
||||
dfp->u.qpsk.symbol_rate = c->symbol_rate;
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe, dfp);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
udelay(10);
|
||||
stv0288_set_symbolrate(fe, c->symbol_rate);
|
||||
/* Carrier lock control register */
|
||||
stv0288_writeregI(state, 0x15, 0xc5);
|
||||
|
||||
tda[0] = 0x2b; /* CFRM */
|
||||
tda[2] = 0x0; /* CFRL */
|
||||
for (tm = -6; tm < 7;) {
|
||||
/* Viterbi status */
|
||||
if (stv0288_readreg(state, 0x24) & 0x80)
|
||||
break;
|
||||
|
||||
tda[2] += 40;
|
||||
if (tda[2] < 40)
|
||||
tm++;
|
||||
tda[1] = (unsigned char)tm;
|
||||
stv0288_writeregI(state, 0x2b, tda[1]);
|
||||
stv0288_writeregI(state, 0x2c, tda[2]);
|
||||
udelay(30);
|
||||
}
|
||||
|
||||
state->tuner_frequency = c->frequency;
|
||||
state->fec_inner = FEC_AUTO;
|
||||
state->symbol_rate = c->symbol_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
||||
if (enable)
|
||||
stv0288_writeregI(state, 0x01, 0xb5);
|
||||
else
|
||||
stv0288_writeregI(state, 0x01, 0x35);
|
||||
|
||||
udelay(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stv0288_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops stv0288_ops = {
|
||||
|
||||
.info = {
|
||||
.name = "ST STV0288 DVB-S",
|
||||
.type = FE_QPSK,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
|
||||
.frequency_tolerance = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.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_QPSK |
|
||||
FE_CAN_FEC_AUTO
|
||||
},
|
||||
|
||||
.release = stv0288_release,
|
||||
.init = stv0288_init,
|
||||
.sleep = stv0288_sleep,
|
||||
.write = stv0288_write,
|
||||
.i2c_gate_ctrl = stv0288_i2c_gate_ctrl,
|
||||
.read_status = stv0288_read_status,
|
||||
.read_ber = stv0288_read_ber,
|
||||
.read_signal_strength = stv0288_read_signal_strength,
|
||||
.read_snr = stv0288_read_snr,
|
||||
.read_ucblocks = stv0288_read_ucblocks,
|
||||
.diseqc_send_master_cmd = stv0288_send_diseqc_msg,
|
||||
.diseqc_send_burst = stv0288_send_diseqc_burst,
|
||||
.set_tone = stv0288_set_tone,
|
||||
.set_voltage = stv0288_set_voltage,
|
||||
|
||||
.set_property = stv0288_set_property,
|
||||
.get_property = stv0288_get_property,
|
||||
.set_frontend = stv0288_set_frontend,
|
||||
};
|
||||
|
||||
struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct stv0288_state *state = NULL;
|
||||
int id;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->initialised = 0;
|
||||
state->tuner_frequency = 0;
|
||||
state->symbol_rate = 0;
|
||||
state->fec_inner = 0;
|
||||
state->errmode = STATUS_BER;
|
||||
|
||||
stv0288_writeregI(state, 0x41, 0x04);
|
||||
msleep(200);
|
||||
id = stv0288_readreg(state, 0x00);
|
||||
dprintk("stv0288 id %x\n", id);
|
||||
|
||||
/* register 0x00 contains 0x11 for STV0288 */
|
||||
if (id != 0x11)
|
||||
goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &stv0288_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(stv0288_attach);
|
||||
|
||||
module_param(debug_legacy_dish_switch, int, 0444);
|
||||
MODULE_PARM_DESC(debug_legacy_dish_switch,
|
||||
"Enable timing analysis for Dish Network legacy switches");
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver");
|
||||
MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
67
drivers/media/dvb/frontends/stv0288.h
Normal file
67
drivers/media/dvb/frontends/stv0288.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
Driver for ST STV0288 demodulator
|
||||
|
||||
Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de
|
||||
for Reel Multimedia
|
||||
Copyright (C) 2008 TurboSight.com, <bob@turbosight.com>
|
||||
Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
|
||||
Removed stb6000 specific tuner code and revised some
|
||||
procedures.
|
||||
|
||||
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 STV0288_H
|
||||
#define STV0288_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
struct stv0288_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
u8* inittab;
|
||||
|
||||
/* minimum delay before retuning */
|
||||
int min_delay_ms;
|
||||
|
||||
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \
|
||||
defined(MODULE))
|
||||
extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_STV0288 */
|
||||
|
||||
static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val)
|
||||
{
|
||||
int r = 0;
|
||||
u8 buf[] = { reg, val };
|
||||
if (fe->ops.write)
|
||||
r = fe->ops.write(fe, buf, 2);
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif /* STV0288_H */
|
@ -559,6 +559,8 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
|
||||
int invval = 0;
|
||||
|
||||
dprintk ("%s : FE_SET_FRONTEND\n", __func__);
|
||||
if (state->config->set_ts_params)
|
||||
state->config->set_ts_params(fe, 0);
|
||||
|
||||
// set the inversion
|
||||
if (p->inversion == INVERSION_OFF) invval = 0;
|
||||
|
@ -89,15 +89,18 @@ struct stv0299_config
|
||||
int min_delay_ms;
|
||||
|
||||
/* Set the symbol rate */
|
||||
int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
|
||||
int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio);
|
||||
|
||||
/* Set device param to start dma */
|
||||
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
|
||||
struct i2c_adapter* i2c);
|
||||
extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
|
73
drivers/media/dvb/frontends/tdhd1.h
Normal file
73
drivers/media/dvb/frontends/tdhd1.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* tdhd1.h - ALPS TDHD1-204A tuner support
|
||||
*
|
||||
* Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*
|
||||
* The project's page is at http://www.linuxtv.org
|
||||
*/
|
||||
|
||||
#ifndef TDHD1_H
|
||||
#define TDHD1_H
|
||||
|
||||
#include "tda1004x.h"
|
||||
|
||||
static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name);
|
||||
|
||||
static struct tda1004x_config alps_tdhd1_204a_config = {
|
||||
.demod_address = 0x8,
|
||||
.invert = 1,
|
||||
.invert_oclk = 0,
|
||||
.xtal_freq = TDA10046_XTAL_4M,
|
||||
.agc_config = TDA10046_AGC_DEFAULT,
|
||||
.if_freq = TDA10046_FREQ_3617,
|
||||
.request_firmware = alps_tdhd1_204_request_firmware
|
||||
};
|
||||
|
||||
static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct i2c_adapter *i2c = fe->tuner_priv;
|
||||
u8 data[4];
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
|
||||
u32 div;
|
||||
|
||||
div = (params->frequency + 36166666) / 166666;
|
||||
|
||||
data[0] = (div >> 8) & 0x7f;
|
||||
data[1] = div & 0xff;
|
||||
data[2] = 0x85;
|
||||
|
||||
if (params->frequency >= 174000000 && params->frequency <= 230000000)
|
||||
data[3] = 0x02;
|
||||
else if (params->frequency >= 470000000 && params->frequency <= 823000000)
|
||||
data[3] = 0x0C;
|
||||
else if (params->frequency > 823000000 && params->frequency <= 862000000)
|
||||
data[3] = 0x8C;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(i2c, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TDHD1_H */
|
@ -86,6 +86,7 @@ config DVB_BUDGET
|
||||
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA826X if !DVB_FE_CUSTOMISE
|
||||
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for simple SAA7146 based DVB cards (so called Budget-
|
||||
or Nova-PCI cards) without onboard MPEG2 decoder, and without
|
||||
|
@ -88,6 +88,7 @@ static int budgetpatch;
|
||||
static int wss_cfg_4_3 = 0x4008;
|
||||
static int wss_cfg_16_9 = 0x0007;
|
||||
static int tv_standard;
|
||||
static int full_ts;
|
||||
|
||||
module_param_named(debug, av7110_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
|
||||
@ -106,6 +107,8 @@ module_param(volume, int, 0444);
|
||||
MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
|
||||
module_param(budgetpatch, int, 0444);
|
||||
MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
|
||||
module_param(full_ts, int, 0444);
|
||||
MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable");
|
||||
module_param(wss_cfg_4_3, int, 0444);
|
||||
MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
|
||||
module_param(wss_cfg_16_9, int, 0444);
|
||||
@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC");
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static void restart_feeds(struct av7110 *av7110);
|
||||
static int budget_start_feed(struct dvb_demux_feed *feed);
|
||||
static int budget_stop_feed(struct dvb_demux_feed *feed);
|
||||
|
||||
static int av7110_num;
|
||||
|
||||
@ -376,9 +381,9 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir,
|
||||
irdebi(av7110, DEBISWAB, addr, 0, len);
|
||||
}
|
||||
|
||||
static void debiirq(unsigned long data)
|
||||
static void debiirq(unsigned long cookie)
|
||||
{
|
||||
struct av7110 *av7110 = (struct av7110 *) data;
|
||||
struct av7110 *av7110 = (struct av7110 *)cookie;
|
||||
int type = av7110->debitype;
|
||||
int handle = (type >> 8) & 0x1f;
|
||||
unsigned int xfer = 0;
|
||||
@ -487,9 +492,9 @@ debi_done:
|
||||
}
|
||||
|
||||
/* irq from av7110 firmware writing the mailbox register in the DPRAM */
|
||||
static void gpioirq(unsigned long data)
|
||||
static void gpioirq(unsigned long cookie)
|
||||
{
|
||||
struct av7110 *av7110 = (struct av7110 *) data;
|
||||
struct av7110 *av7110 = (struct av7110 *)cookie;
|
||||
u32 rxbuf, txbuf;
|
||||
int len;
|
||||
|
||||
@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
|
||||
|
||||
dprintk(4, "%p\n", av7110);
|
||||
|
||||
if (av7110->full_ts)
|
||||
return 0;
|
||||
|
||||
if (dvbdmxfilter->type == DMX_TYPE_SEC) {
|
||||
if (hw_sections) {
|
||||
buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |
|
||||
@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
|
||||
|
||||
dprintk(4, "%p\n", av7110);
|
||||
|
||||
if (av7110->full_ts)
|
||||
return 0;
|
||||
|
||||
handle = dvbdmxfilter->hw_handle;
|
||||
if (handle >= 32) {
|
||||
printk("%s tried to stop invalid filter %04x, filter type = %x\n",
|
||||
@ -913,7 +924,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((dvbdmxfeed->ts_type & TS_PACKET)) {
|
||||
if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) {
|
||||
if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
|
||||
ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
|
||||
if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
|
||||
@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
|
||||
if (!demux->dmx.frontend)
|
||||
return -EINVAL;
|
||||
|
||||
if (feed->pid > 0x1fff)
|
||||
if (!av7110->full_ts && feed->pid > 0x1fff)
|
||||
return -EINVAL;
|
||||
|
||||
if (feed->type == DMX_TYPE_TS) {
|
||||
@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
|
||||
}
|
||||
}
|
||||
|
||||
else if (feed->type == DMX_TYPE_SEC) {
|
||||
if (av7110->full_ts) {
|
||||
budget_start_feed(feed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (feed->type == DMX_TYPE_SEC) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < demux->filternum; i++) {
|
||||
@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
|
||||
ret = StopHWFilter(feed->filter);
|
||||
}
|
||||
|
||||
if (!ret && feed->type == DMX_TYPE_SEC) {
|
||||
if (av7110->full_ts) {
|
||||
budget_stop_feed(feed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (feed->type == DMX_TYPE_SEC) {
|
||||
for (i = 0; i<demux->filternum; i++) {
|
||||
if (demux->filter[i].state == DMX_STATE_GO &&
|
||||
demux->filter[i].filter.parent == &feed->feed.sec) {
|
||||
@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110)
|
||||
struct dvb_demux *dvbdmx = &av7110->demux;
|
||||
struct dvb_demux_feed *feed;
|
||||
int mode;
|
||||
int feeding;
|
||||
int i, j;
|
||||
|
||||
dprintk(4, "%p\n", av7110);
|
||||
@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110)
|
||||
av7110->playing = 0;
|
||||
av7110->rec_mode = 0;
|
||||
|
||||
feeding = av7110->feeding1; /* full_ts mod */
|
||||
|
||||
for (i = 0; i < dvbdmx->feednum; i++) {
|
||||
feed = &dvbdmx->feed[i];
|
||||
if (feed->state == DMX_STATE_GO) {
|
||||
@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110)
|
||||
}
|
||||
}
|
||||
|
||||
av7110->feeding1 = feeding; /* full_ts mod */
|
||||
|
||||
if (mode)
|
||||
av7110_av_start_play(av7110, mode);
|
||||
}
|
||||
@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget)
|
||||
|
||||
if (budget->feeding1)
|
||||
return ++budget->feeding1;
|
||||
memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
|
||||
memset(budget->grabbing, 0x00, TS_BUFLEN);
|
||||
budget->ttbp = 0;
|
||||
SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */
|
||||
SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
|
||||
saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
|
||||
return ++budget->feeding1;
|
||||
@ -1233,18 +1260,14 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
|
||||
return status;
|
||||
}
|
||||
|
||||
static void vpeirq(unsigned long data)
|
||||
static void vpeirq(unsigned long cookie)
|
||||
{
|
||||
struct av7110 *budget = (struct av7110 *) data;
|
||||
struct av7110 *budget = (struct av7110 *)cookie;
|
||||
u8 *mem = (u8 *) (budget->grabbing);
|
||||
u32 olddma = budget->ttbp;
|
||||
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
|
||||
struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
|
||||
|
||||
if (!budgetpatch) {
|
||||
printk("av7110.c: vpeirq() called while budgetpatch disabled!"
|
||||
" check saa7146 IER register\n");
|
||||
BUG();
|
||||
}
|
||||
/* nearest lower position divisible by 188 */
|
||||
newdma -= newdma % 188;
|
||||
|
||||
@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data)
|
||||
|
||||
if (newdma > olddma)
|
||||
/* no wraparound, dump olddma..newdma */
|
||||
dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188);
|
||||
dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
|
||||
else {
|
||||
/* wraparound, dump olddma..buflen and 0..newdma */
|
||||
dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188);
|
||||
dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188);
|
||||
dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
|
||||
dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110)
|
||||
for (i = 0; i < 32; i++)
|
||||
av7110->handle2filter[i] = NULL;
|
||||
|
||||
dvbdemux->filternum = 32;
|
||||
dvbdemux->feednum = 32;
|
||||
dvbdemux->filternum = (av7110->full_ts) ? 256 : 32;
|
||||
dvbdemux->feednum = (av7110->full_ts) ? 256 : 32;
|
||||
dvbdemux->start_feed = av7110_start_feed;
|
||||
dvbdemux->stop_feed = av7110_stop_feed;
|
||||
dvbdemux->write_to_decoder = av7110_write_to_decoder;
|
||||
@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110)
|
||||
dvb_dmx_init(&av7110->demux);
|
||||
av7110->demux.dmx.get_stc = dvb_get_stc;
|
||||
|
||||
av7110->dmxdev.filternum = 32;
|
||||
av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32;
|
||||
av7110->dmxdev.demux = &dvbdemux->dmx;
|
||||
av7110->dmxdev.capabilities = 0;
|
||||
|
||||
@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val)
|
||||
return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
|
||||
{
|
||||
u8 mm1[] = {0x00};
|
||||
@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
|
||||
|
||||
return mm2[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* INITIALIZATION
|
||||
@ -2256,7 +2277,7 @@ static int frontend_init(struct av7110 *av7110)
|
||||
if (!av7110->fe) {
|
||||
/* FIXME: propagate the failure code from the lower layers */
|
||||
ret = -ENOMEM;
|
||||
printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
|
||||
printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
av7110->dev->pci->vendor,
|
||||
av7110->dev->pci->device,
|
||||
av7110->dev->pci->subsystem_vendor,
|
||||
@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
|
||||
av7110->dvb_adapter.proposed_mac);
|
||||
ret = -ENOMEM;
|
||||
|
||||
if (budgetpatch) {
|
||||
/* full-ts mod? */
|
||||
if (full_ts)
|
||||
av7110->full_ts = true;
|
||||
|
||||
/* check for full-ts flag in eeprom */
|
||||
if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
|
||||
u8 flags = i2c_readreg(av7110, 0xaa, 2);
|
||||
if (flags != 0xff && (flags & 0x01))
|
||||
av7110->full_ts = true;
|
||||
}
|
||||
|
||||
if (av7110->full_ts) {
|
||||
printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
|
||||
spin_lock_init(&av7110->feedlock1);
|
||||
av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
|
||||
&av7110->pt);
|
||||
if (!av7110->grabbing)
|
||||
goto err_i2c_del_3;
|
||||
|
||||
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
|
||||
saa7146_write(dev, MC2, (MASK_10 | MASK_26));
|
||||
|
||||
saa7146_write(dev, DD1_INIT, 0x00000600);
|
||||
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
|
||||
|
||||
saa7146_write(dev, BRS_CTRL, 0x60000000);
|
||||
saa7146_write(dev, MC2, MASK_08 | MASK_24);
|
||||
|
||||
/* dma3 */
|
||||
saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
|
||||
saa7146_write(dev, BASE_ODD3, 0);
|
||||
saa7146_write(dev, BASE_EVEN3, 0);
|
||||
saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
|
||||
saa7146_write(dev, PITCH3, TS_WIDTH);
|
||||
saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
|
||||
saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
|
||||
saa7146_write(dev, MC2, MASK_04 | MASK_20);
|
||||
|
||||
tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
|
||||
|
||||
} else if (budgetpatch) {
|
||||
spin_lock_init(&av7110->feedlock1);
|
||||
av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
|
||||
&av7110->pt);
|
||||
@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa)
|
||||
#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
|
||||
av7110_ir_exit(av7110);
|
||||
#endif
|
||||
if (budgetpatch) {
|
||||
/* Disable RPS1 */
|
||||
saa7146_write(saa, MC1, MASK_29);
|
||||
/* VSYNC LOW (inactive) */
|
||||
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
|
||||
if (budgetpatch || av7110->full_ts) {
|
||||
if (budgetpatch) {
|
||||
/* Disable RPS1 */
|
||||
saa7146_write(saa, MC1, MASK_29);
|
||||
/* VSYNC LOW (inactive) */
|
||||
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
|
||||
}
|
||||
saa7146_write(saa, MC1, MASK_20); /* DMA3 off */
|
||||
SAA7146_IER_DISABLE(saa, MASK_10);
|
||||
SAA7146_ISR_CLEAR(saa, MASK_10);
|
||||
@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
|
||||
tasklet_schedule(&av7110->gpio_tasklet);
|
||||
}
|
||||
|
||||
if ((*isr & MASK_10) && budgetpatch)
|
||||
if (*isr & MASK_10)
|
||||
tasklet_schedule(&av7110->vpe_tasklet);
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,7 @@ struct av7110 {
|
||||
unsigned char *grabbing;
|
||||
struct saa7146_pgtable pt;
|
||||
struct tasklet_struct vpe_tasklet;
|
||||
bool full_ts;
|
||||
|
||||
int fe_synced;
|
||||
struct mutex pid_mutex;
|
||||
|
@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
|
||||
if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
|
||||
return 0;
|
||||
|
||||
switch (feed->pes_type) {
|
||||
case 0:
|
||||
if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
|
||||
|
@ -57,6 +57,8 @@
|
||||
#define SLOTSTATUS_READY 8
|
||||
#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct budget_av {
|
||||
struct budget budget;
|
||||
struct video_device *vd;
|
||||
@ -1049,7 +1051,7 @@ static void frontend_init(struct budget_av *budget_av)
|
||||
|
||||
if (fe == NULL) {
|
||||
printk(KERN_ERR "budget-av: A frontend driver was not found "
|
||||
"for device %04x/%04x subsystem %04x/%04x\n",
|
||||
"for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
saa->pci->vendor,
|
||||
saa->pci->device,
|
||||
saa->pci->subsystem_vendor,
|
||||
@ -1127,7 +1129,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
|
||||
|
||||
dev->ext_priv = budget_av;
|
||||
|
||||
if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
|
||||
err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE,
|
||||
adapter_nr);
|
||||
if (err) {
|
||||
kfree(budget_av);
|
||||
return err;
|
||||
}
|
||||
|
@ -92,6 +92,8 @@ static int ir_debug;
|
||||
module_param(ir_debug, int, 0644);
|
||||
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct budget_ci_ir {
|
||||
struct input_dev *dev;
|
||||
struct tasklet_struct msp430_irq_tasklet;
|
||||
@ -1153,7 +1155,7 @@ static void frontend_init(struct budget_ci *budget_ci)
|
||||
}
|
||||
|
||||
if (budget_ci->budget.dvb_frontend == NULL) {
|
||||
printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
|
||||
printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
budget_ci->budget.dev->pci->vendor,
|
||||
budget_ci->budget.dev->pci->device,
|
||||
budget_ci->budget.dev->pci->subsystem_vendor,
|
||||
@ -1183,7 +1185,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
|
||||
|
||||
dev->ext_priv = budget_ci;
|
||||
|
||||
err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
|
||||
err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
|
||||
adapter_nr);
|
||||
if (err)
|
||||
goto out2;
|
||||
|
||||
|
@ -57,8 +57,6 @@ module_param_named(bufsize, dma_buffer_size, int, 0444);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
|
||||
MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/****************************************************************************
|
||||
* TT budget / WinTV Nova
|
||||
****************************************************************************/
|
||||
@ -411,7 +409,7 @@ static void budget_unregister(struct budget *budget)
|
||||
|
||||
int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
||||
struct saa7146_pci_extension_data *info,
|
||||
struct module *owner)
|
||||
struct module *owner, short *adapter_nums)
|
||||
{
|
||||
int ret = 0;
|
||||
struct budget_info *bi = info->ext_priv;
|
||||
@ -474,7 +472,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
|
||||
printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
|
||||
|
||||
ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name,
|
||||
owner, &budget->dev->pci->dev, adapter_nr);
|
||||
owner, &budget->dev->pci->dev, adapter_nums);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
|
||||
#include "bsru6.h"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define budget_patch budget
|
||||
|
||||
static struct saa7146_extension budget_extension;
|
||||
@ -360,7 +362,7 @@ static void frontend_init(struct budget_patch* budget)
|
||||
}
|
||||
|
||||
if (budget->dvb_frontend == NULL) {
|
||||
printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
|
||||
printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
budget->dev->pci->vendor,
|
||||
budget->dev->pci->device,
|
||||
budget->dev->pci->subsystem_vendor,
|
||||
@ -592,8 +594,9 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
|
||||
|
||||
dprintk(2, "budget: %p\n", budget);
|
||||
|
||||
if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
|
||||
kfree (budget);
|
||||
err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
|
||||
if (err) {
|
||||
kfree(budget);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user