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:
Linus Torvalds 2008-10-13 14:03:59 -07:00
commit cf2fa66055
377 changed files with 29942 additions and 6895 deletions

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -1,5 +1,5 @@
0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800]
1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2820,eb1a: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]

View File

@ -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]

View File

@ -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

View File

@ -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

View 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

View 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>

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
};

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

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

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

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

View File

@ -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.");

View File

@ -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,

View File

@ -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.

View File

@ -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

View 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.

View File

@ -0,0 +1,3 @@
obj-$(CONFIG_DVB_DM1105) += dm1105.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends

View 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");

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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."

View File

@ -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},

View File

@ -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;

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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)

View 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");

View 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 *)&param, 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,
};

View 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_ */

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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,

View 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");

View 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

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View 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_ */

View 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_ */

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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))

File diff suppressed because it is too large Load Diff

View 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 */

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View 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

View 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");

View 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 */

View File

@ -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 };

View File

@ -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;

View 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 = &reg1,
.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, &reg1, 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, &reg, 0x01);
reg &= ~start_acq;
status |= si21_writeregs(state, ACQ_CTRL_REG_2, &reg, 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,
&regs[0], 0x03);
reg = 0x56;
status |= si21_writeregs(state,
LSA_CTRL_REG_1, &reg, 1);
reg = 0x05;
status |= si21_writeregs(state,
BLIND_SCAN_CTRL_REG, &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, &regs[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, &regdata, 0x01);
regdata |= 1 << 6;
si21_writeregs(state, SYSTEM_MODE_REG, &regdata, 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");

View 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

View File

@ -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 &&

View 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");

View 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__ */

View 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");

View 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 */

View File

@ -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;

View File

@ -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;

View 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 */

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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