diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-13 17:03:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-13 17:03:59 -0400 |
commit | cf2fa66055d718ae13e62451bb546505f63906a2 (patch) | |
tree | e206d3f04e74a34e9aa88d21af6c26eea21d4121 /drivers/media/dvb | |
parent | 4501a466f28788485604ee42641d7a5fe7258d16 (diff) | |
parent | 57f51dbc45f65f7ee1e8c8f77200bb8000e3e271 (diff) |
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
...
Diffstat (limited to 'drivers/media/dvb')
77 files changed, 13471 insertions, 1554 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 8bc1445bd33b..0bcd852576d6 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig | |||
@@ -20,7 +20,6 @@ comment "Supported USB Adapters" | |||
20 | source "drivers/media/dvb/dvb-usb/Kconfig" | 20 | source "drivers/media/dvb/dvb-usb/Kconfig" |
21 | source "drivers/media/dvb/ttusb-budget/Kconfig" | 21 | source "drivers/media/dvb/ttusb-budget/Kconfig" |
22 | source "drivers/media/dvb/ttusb-dec/Kconfig" | 22 | source "drivers/media/dvb/ttusb-dec/Kconfig" |
23 | source "drivers/media/dvb/cinergyT2/Kconfig" | ||
24 | source "drivers/media/dvb/siano/Kconfig" | 23 | source "drivers/media/dvb/siano/Kconfig" |
25 | 24 | ||
26 | comment "Supported FlexCopII (B2C2) Adapters" | 25 | comment "Supported FlexCopII (B2C2) Adapters" |
@@ -35,6 +34,10 @@ comment "Supported Pluto2 Adapters" | |||
35 | depends on DVB_CORE && PCI && I2C | 34 | depends on DVB_CORE && PCI && I2C |
36 | source "drivers/media/dvb/pluto2/Kconfig" | 35 | source "drivers/media/dvb/pluto2/Kconfig" |
37 | 36 | ||
37 | comment "Supported SDMC DM1105 Adapters" | ||
38 | depends on DVB_CORE && PCI && I2C | ||
39 | source "drivers/media/dvb/dm1105/Kconfig" | ||
40 | |||
38 | comment "Supported DVB Frontends" | 41 | comment "Supported DVB Frontends" |
39 | depends on DVB_CORE | 42 | depends on DVB_CORE |
40 | source "drivers/media/dvb/frontends/Kconfig" | 43 | source "drivers/media/dvb/frontends/Kconfig" |
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index d6ba4d195201..f91e9eb15e52 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile | |||
@@ -2,4 +2,4 @@ | |||
2 | # Makefile for the kernel multimedia device drivers. | 2 | # Makefile for the kernel multimedia device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/ | 5 | obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ |
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c index a91ed28f03a4..26f0011a5078 100644 --- a/drivers/media/dvb/b2c2/flexcop-dma.c +++ b/drivers/media/dvb/b2c2/flexcop-dma.c | |||
@@ -10,7 +10,7 @@ | |||
10 | int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size) | 10 | int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size) |
11 | { | 11 | { |
12 | u8 *tcpu; | 12 | u8 *tcpu; |
13 | dma_addr_t tdma; | 13 | dma_addr_t tdma = 0; |
14 | 14 | ||
15 | if (size % 2) { | 15 | if (size % 2) { |
16 | err("dma buffersize has to be even."); | 16 | err("dma buffersize has to be even."); |
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 6afbfbbef0ce..48762a2b9e42 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c | |||
@@ -702,7 +702,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) | |||
702 | } | 702 | } |
703 | 703 | ||
704 | if (card->fe == NULL) | 704 | if (card->fe == NULL) |
705 | printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", | 705 | printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", |
706 | card->bt->dev->vendor, | 706 | card->bt->dev->vendor, |
707 | card->bt->dev->device, | 707 | card->bt->dev->device, |
708 | card->bt->dev->subsystem_vendor, | 708 | card->bt->dev->subsystem_vendor, |
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig deleted file mode 100644 index c03513b2ccae..000000000000 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | config DVB_CINERGYT2 | ||
2 | tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver" | ||
3 | depends on DVB_CORE && USB && INPUT | ||
4 | help | ||
5 | Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers | ||
6 | |||
7 | Say Y if you own such a device and want to use it. | ||
8 | |||
9 | |||
10 | config DVB_CINERGYT2_TUNING | ||
11 | bool "sophisticated fine-tuning for CinergyT2 cards" | ||
12 | depends on DVB_CINERGYT2 | ||
13 | help | ||
14 | Here you can fine-tune some parameters of the CinergyT2 driver. | ||
15 | |||
16 | Normally you don't need to touch this, but in exotic setups you | ||
17 | may fine-tune your setup and adjust e.g. DMA buffer sizes for | ||
18 | a particular application. | ||
19 | |||
20 | |||
21 | config DVB_CINERGYT2_STREAM_URB_COUNT | ||
22 | int "Number of queued USB Request Blocks for Highspeed Stream Transfers" | ||
23 | depends on DVB_CINERGYT2_TUNING | ||
24 | default "32" | ||
25 | help | ||
26 | USB Request Blocks for Highspeed Stream transfers are scheduled in | ||
27 | a queue for the Host Controller. | ||
28 | |||
29 | Usually the default value is a safe choice. | ||
30 | |||
31 | You may increase this number if you are using this device in a | ||
32 | Server Environment with many high-traffic USB Highspeed devices | ||
33 | sharing the same USB bus. | ||
34 | |||
35 | |||
36 | config DVB_CINERGYT2_STREAM_BUF_SIZE | ||
37 | int "Size of URB Stream Buffers for Highspeed Transfers" | ||
38 | depends on DVB_CINERGYT2_TUNING | ||
39 | default "512" | ||
40 | help | ||
41 | Should be a multiple of native buffer size of 512 bytes. | ||
42 | Default value is a safe choice. | ||
43 | |||
44 | You may increase this number if you are using this device in a | ||
45 | Server Environment with many high-traffic USB Highspeed devices | ||
46 | sharing the same USB bus. | ||
47 | |||
48 | |||
49 | config DVB_CINERGYT2_QUERY_INTERVAL | ||
50 | int "Status update interval [milliseconds]" | ||
51 | depends on DVB_CINERGYT2_TUNING | ||
52 | default "250" | ||
53 | help | ||
54 | This is the interval for status readouts from the demodulator. | ||
55 | You may try lower values if you need more responsive signal quality | ||
56 | measurements. | ||
57 | |||
58 | Please keep in mind that these updates cause traffic on the tuner | ||
59 | control bus and thus may or may not affect reception sensitivity. | ||
60 | |||
61 | The default value should be a safe choice for common applications. | ||
62 | |||
63 | |||
64 | config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE | ||
65 | bool "Register the onboard IR Remote Control Receiver as Input Device" | ||
66 | depends on DVB_CINERGYT2_TUNING | ||
67 | default y | ||
68 | help | ||
69 | Enable this option if you want to use the onboard Infrared Remote | ||
70 | Control Receiver as Linux-Input device. | ||
71 | |||
72 | Right now only the keycode table for the default Remote Control | ||
73 | delivered with the device is supported, please see the driver | ||
74 | source code to find out how to add support for other controls. | ||
75 | |||
76 | |||
77 | config DVB_CINERGYT2_RC_QUERY_INTERVAL | ||
78 | int "Infrared Remote Controller update interval [milliseconds]" | ||
79 | depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE | ||
80 | default "50" | ||
81 | help | ||
82 | If you have a very fast-repeating remote control you can try lower | ||
83 | values, for normal consumer receivers the default value should be | ||
84 | a safe choice. | ||
85 | |||
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile deleted file mode 100644 index d762d8cb0cf1..000000000000 --- a/drivers/media/dvb/cinergyT2/Makefile +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o | ||
2 | |||
3 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ | ||
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c deleted file mode 100644 index a824f3719f81..000000000000 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ /dev/null | |||
@@ -1,1105 +0,0 @@ | |||
1 | /* | ||
2 | * TerraTec Cinergy T²/qanu USB2 DVB-T adapter. | ||
3 | * | ||
4 | * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and | ||
5 | * Holger Waechtler <holger@qanu.de> | ||
6 | * | ||
7 | * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/usb.h> | ||
29 | #include <linux/input.h> | ||
30 | #include <linux/dvb/frontend.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <asm/io.h> | ||
34 | |||
35 | #include "dmxdev.h" | ||
36 | #include "dvb_demux.h" | ||
37 | #include "dvb_net.h" | ||
38 | |||
39 | #ifdef CONFIG_DVB_CINERGYT2_TUNING | ||
40 | #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT) | ||
41 | #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE) | ||
42 | #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL) | ||
43 | #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE | ||
44 | #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL) | ||
45 | #define ENABLE_RC (1) | ||
46 | #endif | ||
47 | #else | ||
48 | #define STREAM_URB_COUNT (32) | ||
49 | #define STREAM_BUF_SIZE (512) /* bytes */ | ||
50 | #define ENABLE_RC (1) | ||
51 | #define RC_QUERY_INTERVAL (50) /* milliseconds */ | ||
52 | #define QUERY_INTERVAL (333) /* milliseconds */ | ||
53 | #endif | ||
54 | |||
55 | #define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" | ||
56 | |||
57 | static int debug; | ||
58 | module_param_named(debug, debug, int, 0644); | ||
59 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
60 | |||
61 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
62 | |||
63 | #define dprintk(level, args...) \ | ||
64 | do { \ | ||
65 | if ((debug & level)) { \ | ||
66 | printk("%s: %s(): ", KBUILD_MODNAME, \ | ||
67 | __func__); \ | ||
68 | printk(args); } \ | ||
69 | } while (0) | ||
70 | |||
71 | enum cinergyt2_ep1_cmd { | ||
72 | CINERGYT2_EP1_PID_TABLE_RESET = 0x01, | ||
73 | CINERGYT2_EP1_PID_SETUP = 0x02, | ||
74 | CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, | ||
75 | CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, | ||
76 | CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, | ||
77 | CINERGYT2_EP1_START_SCAN = 0x06, | ||
78 | CINERGYT2_EP1_CONTINUE_SCAN = 0x07, | ||
79 | CINERGYT2_EP1_GET_RC_EVENTS = 0x08, | ||
80 | CINERGYT2_EP1_SLEEP_MODE = 0x09 | ||
81 | }; | ||
82 | |||
83 | struct dvbt_set_parameters_msg { | ||
84 | uint8_t cmd; | ||
85 | __le32 freq; | ||
86 | uint8_t bandwidth; | ||
87 | __le16 tps; | ||
88 | uint8_t flags; | ||
89 | } __attribute__((packed)); | ||
90 | |||
91 | struct dvbt_get_status_msg { | ||
92 | __le32 freq; | ||
93 | uint8_t bandwidth; | ||
94 | __le16 tps; | ||
95 | uint8_t flags; | ||
96 | __le16 gain; | ||
97 | uint8_t snr; | ||
98 | __le32 viterbi_error_rate; | ||
99 | __le32 rs_error_rate; | ||
100 | __le32 uncorrected_block_count; | ||
101 | uint8_t lock_bits; | ||
102 | uint8_t prev_lock_bits; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | static struct dvb_frontend_info cinergyt2_fe_info = { | ||
106 | .name = DRIVER_NAME, | ||
107 | .type = FE_OFDM, | ||
108 | .frequency_min = 174000000, | ||
109 | .frequency_max = 862000000, | ||
110 | .frequency_stepsize = 166667, | ||
111 | .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | | ||
112 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
113 | FE_CAN_FEC_AUTO | | ||
114 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
115 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
116 | FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS | ||
117 | }; | ||
118 | |||
119 | struct cinergyt2 { | ||
120 | struct dvb_demux demux; | ||
121 | struct usb_device *udev; | ||
122 | struct mutex sem; | ||
123 | struct mutex wq_sem; | ||
124 | struct dvb_adapter adapter; | ||
125 | struct dvb_device *fedev; | ||
126 | struct dmxdev dmxdev; | ||
127 | struct dvb_net dvbnet; | ||
128 | |||
129 | int streaming; | ||
130 | int sleeping; | ||
131 | |||
132 | struct dvbt_set_parameters_msg param; | ||
133 | struct dvbt_get_status_msg status; | ||
134 | struct delayed_work query_work; | ||
135 | |||
136 | wait_queue_head_t poll_wq; | ||
137 | int pending_fe_events; | ||
138 | int disconnect_pending; | ||
139 | unsigned int uncorrected_block_count; | ||
140 | atomic_t inuse; | ||
141 | |||
142 | void *streambuf; | ||
143 | dma_addr_t streambuf_dmahandle; | ||
144 | struct urb *stream_urb [STREAM_URB_COUNT]; | ||
145 | |||
146 | #ifdef ENABLE_RC | ||
147 | struct input_dev *rc_input_dev; | ||
148 | char phys[64]; | ||
149 | struct delayed_work rc_query_work; | ||
150 | int rc_input_event; | ||
151 | __le32 rc_last_code; | ||
152 | unsigned long last_event_jiffies; | ||
153 | #endif | ||
154 | }; | ||
155 | |||
156 | enum { | ||
157 | CINERGYT2_RC_EVENT_TYPE_NONE = 0x00, | ||
158 | CINERGYT2_RC_EVENT_TYPE_NEC = 0x01, | ||
159 | CINERGYT2_RC_EVENT_TYPE_RC5 = 0x02 | ||
160 | }; | ||
161 | |||
162 | struct cinergyt2_rc_event { | ||
163 | char type; | ||
164 | __le32 value; | ||
165 | } __attribute__((packed)); | ||
166 | |||
167 | static const uint32_t rc_keys[] = { | ||
168 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xfe01eb04, KEY_POWER, | ||
169 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xfd02eb04, KEY_1, | ||
170 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xfc03eb04, KEY_2, | ||
171 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xfb04eb04, KEY_3, | ||
172 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xfa05eb04, KEY_4, | ||
173 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf906eb04, KEY_5, | ||
174 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf807eb04, KEY_6, | ||
175 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf708eb04, KEY_7, | ||
176 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf609eb04, KEY_8, | ||
177 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf50aeb04, KEY_9, | ||
178 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf30ceb04, KEY_0, | ||
179 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf40beb04, KEY_VIDEO, | ||
180 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf20deb04, KEY_REFRESH, | ||
181 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf10eeb04, KEY_SELECT, | ||
182 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xf00feb04, KEY_EPG, | ||
183 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xef10eb04, KEY_UP, | ||
184 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xeb14eb04, KEY_DOWN, | ||
185 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xee11eb04, KEY_LEFT, | ||
186 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xec13eb04, KEY_RIGHT, | ||
187 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xed12eb04, KEY_OK, | ||
188 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xea15eb04, KEY_TEXT, | ||
189 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe916eb04, KEY_INFO, | ||
190 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe817eb04, KEY_RED, | ||
191 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe718eb04, KEY_GREEN, | ||
192 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe619eb04, KEY_YELLOW, | ||
193 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe51aeb04, KEY_BLUE, | ||
194 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe31ceb04, KEY_VOLUMEUP, | ||
195 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe11eeb04, KEY_VOLUMEDOWN, | ||
196 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe21deb04, KEY_MUTE, | ||
197 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe41beb04, KEY_CHANNELUP, | ||
198 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xe01feb04, KEY_CHANNELDOWN, | ||
199 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xbf40eb04, KEY_PAUSE, | ||
200 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xb34ceb04, KEY_PLAY, | ||
201 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xa758eb04, KEY_RECORD, | ||
202 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xab54eb04, KEY_PREVIOUS, | ||
203 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xb748eb04, KEY_STOP, | ||
204 | CINERGYT2_RC_EVENT_TYPE_NEC, 0xa35ceb04, KEY_NEXT | ||
205 | }; | ||
206 | |||
207 | static int cinergyt2_command (struct cinergyt2 *cinergyt2, | ||
208 | char *send_buf, int send_buf_len, | ||
209 | char *recv_buf, int recv_buf_len) | ||
210 | { | ||
211 | int actual_len; | ||
212 | char dummy; | ||
213 | int ret; | ||
214 | |||
215 | ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1), | ||
216 | send_buf, send_buf_len, &actual_len, 1000); | ||
217 | |||
218 | if (ret) | ||
219 | dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret); | ||
220 | |||
221 | if (!recv_buf) | ||
222 | recv_buf = &dummy; | ||
223 | |||
224 | ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1), | ||
225 | recv_buf, recv_buf_len, &actual_len, 1000); | ||
226 | |||
227 | if (ret) | ||
228 | dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret); | ||
229 | |||
230 | return ret ? ret : actual_len; | ||
231 | } | ||
232 | |||
233 | static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable) | ||
234 | { | ||
235 | char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; | ||
236 | cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); | ||
237 | } | ||
238 | |||
239 | static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep) | ||
240 | { | ||
241 | char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 }; | ||
242 | cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); | ||
243 | cinergyt2->sleeping = sleep; | ||
244 | } | ||
245 | |||
246 | static void cinergyt2_stream_irq (struct urb *urb); | ||
247 | |||
248 | static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb) | ||
249 | { | ||
250 | int err; | ||
251 | |||
252 | usb_fill_bulk_urb(urb, | ||
253 | cinergyt2->udev, | ||
254 | usb_rcvbulkpipe(cinergyt2->udev, 0x2), | ||
255 | urb->transfer_buffer, | ||
256 | STREAM_BUF_SIZE, | ||
257 | cinergyt2_stream_irq, | ||
258 | cinergyt2); | ||
259 | |||
260 | if ((err = usb_submit_urb(urb, GFP_ATOMIC))) | ||
261 | dprintk(1, "urb submission failed (err = %i)!\n", err); | ||
262 | |||
263 | return err; | ||
264 | } | ||
265 | |||
266 | static void cinergyt2_stream_irq (struct urb *urb) | ||
267 | { | ||
268 | struct cinergyt2 *cinergyt2 = urb->context; | ||
269 | |||
270 | if (urb->actual_length > 0) | ||
271 | dvb_dmx_swfilter(&cinergyt2->demux, | ||
272 | urb->transfer_buffer, urb->actual_length); | ||
273 | |||
274 | if (cinergyt2->streaming) | ||
275 | cinergyt2_submit_stream_urb(cinergyt2, urb); | ||
276 | } | ||
277 | |||
278 | static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2) | ||
279 | { | ||
280 | int i; | ||
281 | |||
282 | for (i=0; i<STREAM_URB_COUNT; i++) | ||
283 | usb_free_urb(cinergyt2->stream_urb[i]); | ||
284 | |||
285 | usb_buffer_free(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, | ||
286 | cinergyt2->streambuf, cinergyt2->streambuf_dmahandle); | ||
287 | } | ||
288 | |||
289 | static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2) | ||
290 | { | ||
291 | int i; | ||
292 | |||
293 | cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, | ||
294 | GFP_KERNEL, &cinergyt2->streambuf_dmahandle); | ||
295 | if (!cinergyt2->streambuf) { | ||
296 | dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n"); | ||
297 | return -ENOMEM; | ||
298 | } | ||
299 | |||
300 | memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE); | ||
301 | |||
302 | for (i=0; i<STREAM_URB_COUNT; i++) { | ||
303 | struct urb *urb; | ||
304 | |||
305 | if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) { | ||
306 | dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n"); | ||
307 | cinergyt2_free_stream_urbs(cinergyt2); | ||
308 | return -ENOMEM; | ||
309 | } | ||
310 | |||
311 | urb->transfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE; | ||
312 | urb->transfer_buffer_length = STREAM_BUF_SIZE; | ||
313 | |||
314 | cinergyt2->stream_urb[i] = urb; | ||
315 | } | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2) | ||
321 | { | ||
322 | int i; | ||
323 | |||
324 | cinergyt2_control_stream_transfer(cinergyt2, 0); | ||
325 | |||
326 | for (i=0; i<STREAM_URB_COUNT; i++) | ||
327 | usb_kill_urb(cinergyt2->stream_urb[i]); | ||
328 | } | ||
329 | |||
330 | static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2) | ||
331 | { | ||
332 | int i, err; | ||
333 | |||
334 | for (i=0; i<STREAM_URB_COUNT; i++) { | ||
335 | if ((err = cinergyt2_submit_stream_urb(cinergyt2, cinergyt2->stream_urb[i]))) { | ||
336 | cinergyt2_stop_stream_xfer(cinergyt2); | ||
337 | dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err); | ||
338 | return err; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | cinergyt2_control_stream_transfer(cinergyt2, 1); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
347 | { | ||
348 | struct dvb_demux *demux = dvbdmxfeed->demux; | ||
349 | struct cinergyt2 *cinergyt2 = demux->priv; | ||
350 | |||
351 | if (cinergyt2->disconnect_pending) | ||
352 | return -EAGAIN; | ||
353 | if (mutex_lock_interruptible(&cinergyt2->sem)) | ||
354 | return -ERESTARTSYS; | ||
355 | |||
356 | if (cinergyt2->streaming == 0) | ||
357 | cinergyt2_start_stream_xfer(cinergyt2); | ||
358 | |||
359 | cinergyt2->streaming++; | ||
360 | mutex_unlock(&cinergyt2->sem); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
365 | { | ||
366 | struct dvb_demux *demux = dvbdmxfeed->demux; | ||
367 | struct cinergyt2 *cinergyt2 = demux->priv; | ||
368 | |||
369 | if (cinergyt2->disconnect_pending) | ||
370 | return -EAGAIN; | ||
371 | if (mutex_lock_interruptible(&cinergyt2->sem)) | ||
372 | return -ERESTARTSYS; | ||
373 | |||
374 | if (--cinergyt2->streaming == 0) | ||
375 | cinergyt2_stop_stream_xfer(cinergyt2); | ||
376 | |||
377 | mutex_unlock(&cinergyt2->sem); | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * convert linux-dvb frontend parameter set into TPS. | ||
383 | * See ETSI ETS-300744, section 4.6.2, table 9 for details. | ||
384 | * | ||
385 | * This function is probably reusable and may better get placed in a support | ||
386 | * library. | ||
387 | * | ||
388 | * We replace errornous fields by default TPS fields (the ones with value 0). | ||
389 | */ | ||
390 | static uint16_t compute_tps (struct dvb_frontend_parameters *p) | ||
391 | { | ||
392 | struct dvb_ofdm_parameters *op = &p->u.ofdm; | ||
393 | uint16_t tps = 0; | ||
394 | |||
395 | switch (op->code_rate_HP) { | ||
396 | case FEC_2_3: | ||
397 | tps |= (1 << 7); | ||
398 | break; | ||
399 | case FEC_3_4: | ||
400 | tps |= (2 << 7); | ||
401 | break; | ||
402 | case FEC_5_6: | ||
403 | tps |= (3 << 7); | ||
404 | break; | ||
405 | case FEC_7_8: | ||
406 | tps |= (4 << 7); | ||
407 | break; | ||
408 | case FEC_1_2: | ||
409 | case FEC_AUTO: | ||
410 | default: | ||
411 | /* tps |= (0 << 7) */; | ||
412 | } | ||
413 | |||
414 | switch (op->code_rate_LP) { | ||
415 | case FEC_2_3: | ||
416 | tps |= (1 << 4); | ||
417 | break; | ||
418 | case FEC_3_4: | ||
419 | tps |= (2 << 4); | ||
420 | break; | ||
421 | case FEC_5_6: | ||
422 | tps |= (3 << 4); | ||
423 | break; | ||
424 | case FEC_7_8: | ||
425 | tps |= (4 << 4); | ||
426 | break; | ||
427 | case FEC_1_2: | ||
428 | case FEC_AUTO: | ||
429 | default: | ||
430 | /* tps |= (0 << 4) */; | ||
431 | } | ||
432 | |||
433 | switch (op->constellation) { | ||
434 | case QAM_16: | ||
435 | tps |= (1 << 13); | ||
436 | break; | ||
437 | case QAM_64: | ||
438 | tps |= (2 << 13); | ||
439 | break; | ||
440 | case QPSK: | ||
441 | default: | ||
442 | /* tps |= (0 << 13) */; | ||
443 | } | ||
444 | |||
445 | switch (op->transmission_mode) { | ||
446 | case TRANSMISSION_MODE_8K: | ||
447 | tps |= (1 << 0); | ||
448 | break; | ||
449 | case TRANSMISSION_MODE_2K: | ||
450 | default: | ||
451 | /* tps |= (0 << 0) */; | ||
452 | } | ||
453 | |||
454 | switch (op->guard_interval) { | ||
455 | case GUARD_INTERVAL_1_16: | ||
456 | tps |= (1 << 2); | ||
457 | break; | ||
458 | case GUARD_INTERVAL_1_8: | ||
459 | tps |= (2 << 2); | ||
460 | break; | ||
461 | case GUARD_INTERVAL_1_4: | ||
462 | tps |= (3 << 2); | ||
463 | break; | ||
464 | case GUARD_INTERVAL_1_32: | ||
465 | default: | ||
466 | /* tps |= (0 << 2) */; | ||
467 | } | ||
468 | |||
469 | switch (op->hierarchy_information) { | ||
470 | case HIERARCHY_1: | ||
471 | tps |= (1 << 10); | ||
472 | break; | ||
473 | case HIERARCHY_2: | ||
474 | tps |= (2 << 10); | ||
475 | break; | ||
476 | case HIERARCHY_4: | ||
477 | tps |= (3 << 10); | ||
478 | break; | ||
479 | case HIERARCHY_NONE: | ||
480 | default: | ||
481 | /* tps |= (0 << 10) */; | ||
482 | } | ||
483 | |||
484 | return tps; | ||
485 | } | ||
486 | |||
487 | static int cinergyt2_open (struct inode *inode, struct file *file) | ||
488 | { | ||
489 | struct dvb_device *dvbdev = file->private_data; | ||
490 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | ||
491 | int err = -EAGAIN; | ||
492 | |||
493 | if (cinergyt2->disconnect_pending) | ||
494 | goto out; | ||
495 | err = mutex_lock_interruptible(&cinergyt2->wq_sem); | ||
496 | if (err) | ||
497 | goto out; | ||
498 | |||
499 | err = mutex_lock_interruptible(&cinergyt2->sem); | ||
500 | if (err) | ||
501 | goto out_unlock1; | ||
502 | |||
503 | if ((err = dvb_generic_open(inode, file))) | ||
504 | goto out_unlock2; | ||
505 | |||
506 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
507 | cinergyt2_sleep(cinergyt2, 0); | ||
508 | schedule_delayed_work(&cinergyt2->query_work, HZ/2); | ||
509 | } | ||
510 | |||
511 | atomic_inc(&cinergyt2->inuse); | ||
512 | |||
513 | out_unlock2: | ||
514 | mutex_unlock(&cinergyt2->sem); | ||
515 | out_unlock1: | ||
516 | mutex_unlock(&cinergyt2->wq_sem); | ||
517 | out: | ||
518 | return err; | ||
519 | } | ||
520 | |||
521 | static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) | ||
522 | { | ||
523 | dvb_net_release(&cinergyt2->dvbnet); | ||
524 | dvb_dmxdev_release(&cinergyt2->dmxdev); | ||
525 | dvb_dmx_release(&cinergyt2->demux); | ||
526 | dvb_unregister_device(cinergyt2->fedev); | ||
527 | dvb_unregister_adapter(&cinergyt2->adapter); | ||
528 | |||
529 | cinergyt2_free_stream_urbs(cinergyt2); | ||
530 | kfree(cinergyt2); | ||
531 | } | ||
532 | |||
533 | static int cinergyt2_release (struct inode *inode, struct file *file) | ||
534 | { | ||
535 | struct dvb_device *dvbdev = file->private_data; | ||
536 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | ||
537 | |||
538 | mutex_lock(&cinergyt2->wq_sem); | ||
539 | |||
540 | if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
541 | cancel_rearming_delayed_work(&cinergyt2->query_work); | ||
542 | |||
543 | mutex_lock(&cinergyt2->sem); | ||
544 | cinergyt2_sleep(cinergyt2, 1); | ||
545 | mutex_unlock(&cinergyt2->sem); | ||
546 | } | ||
547 | |||
548 | mutex_unlock(&cinergyt2->wq_sem); | ||
549 | |||
550 | if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) { | ||
551 | warn("delayed unregister in release"); | ||
552 | cinergyt2_unregister(cinergyt2); | ||
553 | } | ||
554 | |||
555 | return dvb_generic_release(inode, file); | ||
556 | } | ||
557 | |||
558 | static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait) | ||
559 | { | ||
560 | struct dvb_device *dvbdev = file->private_data; | ||
561 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | ||
562 | unsigned int mask = 0; | ||
563 | |||
564 | if (cinergyt2->disconnect_pending) | ||
565 | return -EAGAIN; | ||
566 | if (mutex_lock_interruptible(&cinergyt2->sem)) | ||
567 | return -ERESTARTSYS; | ||
568 | |||
569 | poll_wait(file, &cinergyt2->poll_wq, wait); | ||
570 | |||
571 | if (cinergyt2->pending_fe_events != 0) | ||
572 | mask |= (POLLIN | POLLRDNORM | POLLPRI); | ||
573 | |||
574 | mutex_unlock(&cinergyt2->sem); | ||
575 | |||
576 | return mask; | ||
577 | } | ||
578 | |||
579 | |||
580 | static int cinergyt2_ioctl (struct inode *inode, struct file *file, | ||
581 | unsigned cmd, unsigned long arg) | ||
582 | { | ||
583 | struct dvb_device *dvbdev = file->private_data; | ||
584 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | ||
585 | struct dvbt_get_status_msg *stat = &cinergyt2->status; | ||
586 | fe_status_t status = 0; | ||
587 | |||
588 | switch (cmd) { | ||
589 | case FE_GET_INFO: | ||
590 | return copy_to_user((void __user*) arg, &cinergyt2_fe_info, | ||
591 | sizeof(struct dvb_frontend_info)); | ||
592 | |||
593 | case FE_READ_STATUS: | ||
594 | if (0xffff - le16_to_cpu(stat->gain) > 30) | ||
595 | status |= FE_HAS_SIGNAL; | ||
596 | if (stat->lock_bits & (1 << 6)) | ||
597 | status |= FE_HAS_LOCK; | ||
598 | if (stat->lock_bits & (1 << 5)) | ||
599 | status |= FE_HAS_SYNC; | ||
600 | if (stat->lock_bits & (1 << 4)) | ||
601 | status |= FE_HAS_CARRIER; | ||
602 | if (stat->lock_bits & (1 << 1)) | ||
603 | status |= FE_HAS_VITERBI; | ||
604 | |||
605 | return copy_to_user((void __user*) arg, &status, sizeof(status)); | ||
606 | |||
607 | case FE_READ_BER: | ||
608 | return put_user(le32_to_cpu(stat->viterbi_error_rate), | ||
609 | (__u32 __user *) arg); | ||
610 | |||
611 | case FE_READ_SIGNAL_STRENGTH: | ||
612 | return put_user(0xffff - le16_to_cpu(stat->gain), | ||
613 | (__u16 __user *) arg); | ||
614 | |||
615 | case FE_READ_SNR: | ||
616 | return put_user((stat->snr << 8) | stat->snr, | ||
617 | (__u16 __user *) arg); | ||
618 | |||
619 | case FE_READ_UNCORRECTED_BLOCKS: | ||
620 | { | ||
621 | uint32_t unc_count; | ||
622 | |||
623 | if (mutex_lock_interruptible(&cinergyt2->sem)) | ||
624 | return -ERESTARTSYS; | ||
625 | unc_count = cinergyt2->uncorrected_block_count; | ||
626 | cinergyt2->uncorrected_block_count = 0; | ||
627 | mutex_unlock(&cinergyt2->sem); | ||
628 | |||
629 | /* UNC are already converted to host byte order... */ | ||
630 | return put_user(unc_count,(__u32 __user *) arg); | ||
631 | } | ||
632 | case FE_SET_FRONTEND: | ||
633 | { | ||
634 | struct dvbt_set_parameters_msg *param = &cinergyt2->param; | ||
635 | struct dvb_frontend_parameters p; | ||
636 | int err; | ||
637 | |||
638 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) | ||
639 | return -EPERM; | ||
640 | |||
641 | if (copy_from_user(&p, (void __user*) arg, sizeof(p))) | ||
642 | return -EFAULT; | ||
643 | |||
644 | if (cinergyt2->disconnect_pending) | ||
645 | return -EAGAIN; | ||
646 | if (mutex_lock_interruptible(&cinergyt2->sem)) | ||
647 | return -ERESTARTSYS; | ||
648 | |||
649 | param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; | ||
650 | param->tps = cpu_to_le16(compute_tps(&p)); | ||
651 | param->freq = cpu_to_le32(p.frequency / 1000); | ||
652 | param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ; | ||
653 | |||
654 | stat->lock_bits = 0; | ||
655 | cinergyt2->pending_fe_events++; | ||
656 | wake_up_interruptible(&cinergyt2->poll_wq); | ||
657 | |||
658 | err = cinergyt2_command(cinergyt2, | ||
659 | (char *) param, sizeof(*param), | ||
660 | NULL, 0); | ||
661 | |||
662 | mutex_unlock(&cinergyt2->sem); | ||
663 | |||
664 | return (err < 0) ? err : 0; | ||
665 | } | ||
666 | |||
667 | case FE_GET_FRONTEND: | ||
668 | /** | ||
669 | * trivial to implement (see struct dvbt_get_status_msg). | ||
670 | * equivalent to FE_READ ioctls, but needs | ||
671 | * TPS -> linux-dvb parameter set conversion. Feel free | ||
672 | * to implement this and send us a patch if you need this | ||
673 | * functionality. | ||
674 | */ | ||
675 | break; | ||
676 | |||
677 | case FE_GET_EVENT: | ||
678 | { | ||
679 | /** | ||
680 | * for now we only fill the status field. the parameters | ||
681 | * are trivial to fill as soon FE_GET_FRONTEND is done. | ||
682 | */ | ||
683 | struct dvb_frontend_event __user *e = (void __user *) arg; | ||
684 | if (cinergyt2->pending_fe_events == 0) { | ||
685 | if (file->f_flags & O_NONBLOCK) | ||
686 | return -EWOULDBLOCK; | ||
687 | wait_event_interruptible(cinergyt2->poll_wq, | ||
688 | cinergyt2->pending_fe_events > 0); | ||
689 | } | ||
690 | cinergyt2->pending_fe_events = 0; | ||
691 | return cinergyt2_ioctl(inode, file, FE_READ_STATUS, | ||
692 | (unsigned long) &e->status); | ||
693 | } | ||
694 | |||
695 | default: | ||
696 | ; | ||
697 | } | ||
698 | |||
699 | return -EINVAL; | ||
700 | } | ||
701 | |||
702 | static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma) | ||
703 | { | ||
704 | struct dvb_device *dvbdev = file->private_data; | ||
705 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | ||
706 | int ret = 0; | ||
707 | |||
708 | lock_kernel(); | ||
709 | |||
710 | if (vma->vm_flags & (VM_WRITE | VM_EXEC)) { | ||
711 | ret = -EPERM; | ||
712 | goto bailout; | ||
713 | } | ||
714 | |||
715 | if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) { | ||
716 | ret = -EINVAL; | ||
717 | goto bailout; | ||
718 | } | ||
719 | |||
720 | vma->vm_flags |= (VM_IO | VM_DONTCOPY); | ||
721 | vma->vm_file = file; | ||
722 | |||
723 | ret = remap_pfn_range(vma, vma->vm_start, | ||
724 | virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT, | ||
725 | vma->vm_end - vma->vm_start, | ||
726 | vma->vm_page_prot) ? -EAGAIN : 0; | ||
727 | bailout: | ||
728 | unlock_kernel(); | ||
729 | return ret; | ||
730 | } | ||
731 | |||
732 | static struct file_operations cinergyt2_fops = { | ||
733 | .owner = THIS_MODULE, | ||
734 | .ioctl = cinergyt2_ioctl, | ||
735 | .poll = cinergyt2_poll, | ||
736 | .open = cinergyt2_open, | ||
737 | .release = cinergyt2_release, | ||
738 | .mmap = cinergyt2_mmap | ||
739 | }; | ||
740 | |||
741 | static struct dvb_device cinergyt2_fe_template = { | ||
742 | .users = ~0, | ||
743 | .writers = 1, | ||
744 | .readers = (~0)-1, | ||
745 | .fops = &cinergyt2_fops | ||
746 | }; | ||
747 | |||
748 | #ifdef ENABLE_RC | ||
749 | |||
750 | static void cinergyt2_query_rc (struct work_struct *work) | ||
751 | { | ||
752 | struct cinergyt2 *cinergyt2 = | ||
753 | container_of(work, struct cinergyt2, rc_query_work.work); | ||
754 | char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; | ||
755 | struct cinergyt2_rc_event rc_events[12]; | ||
756 | int n, len, i; | ||
757 | |||
758 | if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) | ||
759 | return; | ||
760 | |||
761 | len = cinergyt2_command(cinergyt2, buf, sizeof(buf), | ||
762 | (char *) rc_events, sizeof(rc_events)); | ||
763 | if (len < 0) | ||
764 | goto out; | ||
765 | if (len == 0) { | ||
766 | if (time_after(jiffies, cinergyt2->last_event_jiffies + | ||
767 | msecs_to_jiffies(150))) { | ||
768 | /* stop key repeat */ | ||
769 | if (cinergyt2->rc_input_event != KEY_MAX) { | ||
770 | dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); | ||
771 | input_report_key(cinergyt2->rc_input_dev, | ||
772 | cinergyt2->rc_input_event, 0); | ||
773 | input_sync(cinergyt2->rc_input_dev); | ||
774 | cinergyt2->rc_input_event = KEY_MAX; | ||
775 | } | ||
776 | cinergyt2->rc_last_code = cpu_to_le32(~0); | ||
777 | } | ||
778 | goto out; | ||
779 | } | ||
780 | cinergyt2->last_event_jiffies = jiffies; | ||
781 | |||
782 | for (n = 0; n < (len / sizeof(rc_events[0])); n++) { | ||
783 | dprintk(1, "rc_events[%d].value = %x, type=%x\n", | ||
784 | n, le32_to_cpu(rc_events[n].value), rc_events[n].type); | ||
785 | |||
786 | if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC && | ||
787 | rc_events[n].value == cpu_to_le32(~0)) { | ||
788 | /* keyrepeat bit -> just repeat last rc_input_event */ | ||
789 | } else { | ||
790 | cinergyt2->rc_input_event = KEY_MAX; | ||
791 | for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) { | ||
792 | if (rc_keys[i + 0] == rc_events[n].type && | ||
793 | rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { | ||
794 | cinergyt2->rc_input_event = rc_keys[i + 2]; | ||
795 | break; | ||
796 | } | ||
797 | } | ||
798 | } | ||
799 | |||
800 | if (cinergyt2->rc_input_event != KEY_MAX) { | ||
801 | if (rc_events[n].value == cinergyt2->rc_last_code && | ||
802 | cinergyt2->rc_last_code != cpu_to_le32(~0)) { | ||
803 | /* emit a key-up so the double event is recognized */ | ||
804 | dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); | ||
805 | input_report_key(cinergyt2->rc_input_dev, | ||
806 | cinergyt2->rc_input_event, 0); | ||
807 | } | ||
808 | dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); | ||
809 | input_report_key(cinergyt2->rc_input_dev, | ||
810 | cinergyt2->rc_input_event, 1); | ||
811 | input_sync(cinergyt2->rc_input_dev); | ||
812 | cinergyt2->rc_last_code = rc_events[n].value; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | out: | ||
817 | schedule_delayed_work(&cinergyt2->rc_query_work, | ||
818 | msecs_to_jiffies(RC_QUERY_INTERVAL)); | ||
819 | |||
820 | mutex_unlock(&cinergyt2->sem); | ||
821 | } | ||
822 | |||
823 | static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) | ||
824 | { | ||
825 | struct input_dev *input_dev; | ||
826 | int i; | ||
827 | int err; | ||
828 | |||
829 | input_dev = input_allocate_device(); | ||
830 | if (!input_dev) | ||
831 | return -ENOMEM; | ||
832 | |||
833 | usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys)); | ||
834 | strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); | ||
835 | cinergyt2->rc_input_event = KEY_MAX; | ||
836 | cinergyt2->rc_last_code = cpu_to_le32(~0); | ||
837 | INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc); | ||
838 | |||
839 | input_dev->name = DRIVER_NAME " remote control"; | ||
840 | input_dev->phys = cinergyt2->phys; | ||
841 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); | ||
842 | for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) | ||
843 | set_bit(rc_keys[i + 2], input_dev->keybit); | ||
844 | input_dev->keycodesize = 0; | ||
845 | input_dev->keycodemax = 0; | ||
846 | input_dev->id.bustype = BUS_USB; | ||
847 | input_dev->id.vendor = le16_to_cpu(cinergyt2->udev->descriptor.idVendor); | ||
848 | input_dev->id.product = le16_to_cpu(cinergyt2->udev->descriptor.idProduct); | ||
849 | input_dev->id.version = 1; | ||
850 | input_dev->dev.parent = &cinergyt2->udev->dev; | ||
851 | |||
852 | err = input_register_device(input_dev); | ||
853 | if (err) { | ||
854 | input_free_device(input_dev); | ||
855 | return err; | ||
856 | } | ||
857 | |||
858 | cinergyt2->rc_input_dev = input_dev; | ||
859 | schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) | ||
865 | { | ||
866 | cancel_rearming_delayed_work(&cinergyt2->rc_query_work); | ||
867 | input_unregister_device(cinergyt2->rc_input_dev); | ||
868 | } | ||
869 | |||
870 | static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) | ||
871 | { | ||
872 | cancel_rearming_delayed_work(&cinergyt2->rc_query_work); | ||
873 | } | ||
874 | |||
875 | static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) | ||
876 | { | ||
877 | schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); | ||
878 | } | ||
879 | |||
880 | #else | ||
881 | |||
882 | static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; } | ||
883 | static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { } | ||
884 | static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { } | ||
885 | static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } | ||
886 | |||
887 | #endif /* ENABLE_RC */ | ||
888 | |||
889 | static void cinergyt2_query (struct work_struct *work) | ||
890 | { | ||
891 | struct cinergyt2 *cinergyt2 = | ||
892 | container_of(work, struct cinergyt2, query_work.work); | ||
893 | char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; | ||
894 | struct dvbt_get_status_msg *s = &cinergyt2->status; | ||
895 | uint8_t lock_bits; | ||
896 | |||
897 | if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) | ||
898 | return; | ||
899 | |||
900 | lock_bits = s->lock_bits; | ||
901 | |||
902 | cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s)); | ||
903 | |||
904 | cinergyt2->uncorrected_block_count += | ||
905 | le32_to_cpu(s->uncorrected_block_count); | ||
906 | |||
907 | if (lock_bits != s->lock_bits) { | ||
908 | wake_up_interruptible(&cinergyt2->poll_wq); | ||
909 | cinergyt2->pending_fe_events++; | ||
910 | } | ||
911 | |||
912 | schedule_delayed_work(&cinergyt2->query_work, | ||
913 | msecs_to_jiffies(QUERY_INTERVAL)); | ||
914 | |||
915 | mutex_unlock(&cinergyt2->sem); | ||
916 | } | ||
917 | |||
918 | static int cinergyt2_probe (struct usb_interface *intf, | ||
919 | const struct usb_device_id *id) | ||
920 | { | ||
921 | struct cinergyt2 *cinergyt2; | ||
922 | int err; | ||
923 | |||
924 | if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { | ||
925 | dprintk(1, "out of memory?!?\n"); | ||
926 | return -ENOMEM; | ||
927 | } | ||
928 | |||
929 | usb_set_intfdata (intf, (void *) cinergyt2); | ||
930 | |||
931 | mutex_init(&cinergyt2->sem); | ||
932 | mutex_init(&cinergyt2->wq_sem); | ||
933 | init_waitqueue_head (&cinergyt2->poll_wq); | ||
934 | INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query); | ||
935 | |||
936 | cinergyt2->udev = interface_to_usbdev(intf); | ||
937 | cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; | ||
938 | |||
939 | if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) { | ||
940 | dprintk(1, "unable to allocate stream urbs\n"); | ||
941 | kfree(cinergyt2); | ||
942 | return -ENOMEM; | ||
943 | } | ||
944 | |||
945 | err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, | ||
946 | THIS_MODULE, &cinergyt2->udev->dev, | ||
947 | adapter_nr); | ||
948 | if (err < 0) { | ||
949 | kfree(cinergyt2); | ||
950 | return err; | ||
951 | } | ||
952 | |||
953 | cinergyt2->demux.priv = cinergyt2; | ||
954 | cinergyt2->demux.filternum = 256; | ||
955 | cinergyt2->demux.feednum = 256; | ||
956 | cinergyt2->demux.start_feed = cinergyt2_start_feed; | ||
957 | cinergyt2->demux.stop_feed = cinergyt2_stop_feed; | ||
958 | cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING | | ||
959 | DMX_SECTION_FILTERING | | ||
960 | DMX_MEMORY_BASED_FILTERING; | ||
961 | |||
962 | if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) { | ||
963 | dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err); | ||
964 | goto bailout; | ||
965 | } | ||
966 | |||
967 | cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum; | ||
968 | cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx; | ||
969 | cinergyt2->dmxdev.capabilities = 0; | ||
970 | |||
971 | if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) { | ||
972 | dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err); | ||
973 | goto bailout; | ||
974 | } | ||
975 | |||
976 | if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx)) | ||
977 | dprintk(1, "dvb_net_init() failed!\n"); | ||
978 | |||
979 | dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev, | ||
980 | &cinergyt2_fe_template, cinergyt2, | ||
981 | DVB_DEVICE_FRONTEND); | ||
982 | |||
983 | err = cinergyt2_register_rc(cinergyt2); | ||
984 | if (err) | ||
985 | goto bailout; | ||
986 | |||
987 | return 0; | ||
988 | |||
989 | bailout: | ||
990 | dvb_net_release(&cinergyt2->dvbnet); | ||
991 | dvb_dmxdev_release(&cinergyt2->dmxdev); | ||
992 | dvb_dmx_release(&cinergyt2->demux); | ||
993 | dvb_unregister_adapter(&cinergyt2->adapter); | ||
994 | cinergyt2_free_stream_urbs(cinergyt2); | ||
995 | kfree(cinergyt2); | ||
996 | return -ENOMEM; | ||
997 | } | ||
998 | |||
999 | static void cinergyt2_disconnect (struct usb_interface *intf) | ||
1000 | { | ||
1001 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); | ||
1002 | |||
1003 | cinergyt2_unregister_rc(cinergyt2); | ||
1004 | cancel_rearming_delayed_work(&cinergyt2->query_work); | ||
1005 | wake_up_interruptible(&cinergyt2->poll_wq); | ||
1006 | |||
1007 | cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); | ||
1008 | cinergyt2->disconnect_pending = 1; | ||
1009 | |||
1010 | if (!atomic_read(&cinergyt2->inuse)) | ||
1011 | cinergyt2_unregister(cinergyt2); | ||
1012 | } | ||
1013 | |||
1014 | static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) | ||
1015 | { | ||
1016 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); | ||
1017 | |||
1018 | if (cinergyt2->disconnect_pending) | ||
1019 | return -EAGAIN; | ||
1020 | if (mutex_lock_interruptible(&cinergyt2->wq_sem)) | ||
1021 | return -ERESTARTSYS; | ||
1022 | |||
1023 | cinergyt2_suspend_rc(cinergyt2); | ||
1024 | cancel_rearming_delayed_work(&cinergyt2->query_work); | ||
1025 | |||
1026 | mutex_lock(&cinergyt2->sem); | ||
1027 | if (cinergyt2->streaming) | ||
1028 | cinergyt2_stop_stream_xfer(cinergyt2); | ||
1029 | cinergyt2_sleep(cinergyt2, 1); | ||
1030 | mutex_unlock(&cinergyt2->sem); | ||
1031 | |||
1032 | mutex_unlock(&cinergyt2->wq_sem); | ||
1033 | |||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | static int cinergyt2_resume (struct usb_interface *intf) | ||
1038 | { | ||
1039 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); | ||
1040 | struct dvbt_set_parameters_msg *param = &cinergyt2->param; | ||
1041 | int err = -EAGAIN; | ||
1042 | |||
1043 | if (cinergyt2->disconnect_pending) | ||
1044 | goto out; | ||
1045 | err = mutex_lock_interruptible(&cinergyt2->wq_sem); | ||
1046 | if (err) | ||
1047 | goto out; | ||
1048 | |||
1049 | err = mutex_lock_interruptible(&cinergyt2->sem); | ||
1050 | if (err) | ||
1051 | goto out_unlock1; | ||
1052 | |||
1053 | if (!cinergyt2->sleeping) { | ||
1054 | cinergyt2_sleep(cinergyt2, 0); | ||
1055 | cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0); | ||
1056 | if (cinergyt2->streaming) | ||
1057 | cinergyt2_start_stream_xfer(cinergyt2); | ||
1058 | schedule_delayed_work(&cinergyt2->query_work, HZ/2); | ||
1059 | } | ||
1060 | |||
1061 | cinergyt2_resume_rc(cinergyt2); | ||
1062 | |||
1063 | mutex_unlock(&cinergyt2->sem); | ||
1064 | out_unlock1: | ||
1065 | mutex_unlock(&cinergyt2->wq_sem); | ||
1066 | out: | ||
1067 | return err; | ||
1068 | } | ||
1069 | |||
1070 | static const struct usb_device_id cinergyt2_table [] __devinitdata = { | ||
1071 | { USB_DEVICE(0x0ccd, 0x0038) }, | ||
1072 | { 0 } | ||
1073 | }; | ||
1074 | |||
1075 | MODULE_DEVICE_TABLE(usb, cinergyt2_table); | ||
1076 | |||
1077 | static struct usb_driver cinergyt2_driver = { | ||
1078 | .name = "cinergyT2", | ||
1079 | .probe = cinergyt2_probe, | ||
1080 | .disconnect = cinergyt2_disconnect, | ||
1081 | .suspend = cinergyt2_suspend, | ||
1082 | .resume = cinergyt2_resume, | ||
1083 | .id_table = cinergyt2_table | ||
1084 | }; | ||
1085 | |||
1086 | static int __init cinergyt2_init (void) | ||
1087 | { | ||
1088 | int err; | ||
1089 | |||
1090 | if ((err = usb_register(&cinergyt2_driver)) < 0) | ||
1091 | dprintk(1, "usb_register() failed! (err %i)\n", err); | ||
1092 | |||
1093 | return err; | ||
1094 | } | ||
1095 | |||
1096 | static void __exit cinergyt2_exit (void) | ||
1097 | { | ||
1098 | usb_deregister(&cinergyt2_driver); | ||
1099 | } | ||
1100 | |||
1101 | module_init (cinergyt2_init); | ||
1102 | module_exit (cinergyt2_exit); | ||
1103 | |||
1104 | MODULE_LICENSE("GPL"); | ||
1105 | MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); | ||
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig new file mode 100644 index 000000000000..1332301ef3ae --- /dev/null +++ b/drivers/media/dvb/dm1105/Kconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | config DVB_DM1105 | ||
2 | tristate "SDMC DM1105 based PCI cards" | ||
3 | depends on DVB_CORE && PCI && I2C | ||
4 | select DVB_PLL if !DVB_FE_CUSTOMISE | ||
5 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | ||
6 | select DVB_STV0288 if !DVB_FE_CUSTOMISE | ||
7 | select DVB_STB6000 if !DVB_FE_CUSTOMISE | ||
8 | select DVB_CX24116 if !DVB_FE_CUSTOMISE | ||
9 | select DVB_SI21XX if !DVB_FE_CUSTOMISE | ||
10 | help | ||
11 | Support for cards based on the SDMC DM1105 PCI chip like | ||
12 | DvbWorld 2002 | ||
13 | |||
14 | Since these cards have no MPEG decoder onboard, they transmit | ||
15 | only compressed MPEG data over the PCI bus, so you need | ||
16 | an external software decoder to watch TV on your computer. | ||
17 | |||
18 | Say Y or M if you own such a device and want to use it. | ||
diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile new file mode 100644 index 000000000000..8ac28b0546af --- /dev/null +++ b/drivers/media/dvb/dm1105/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_DVB_DM1105) += dm1105.o | ||
2 | |||
3 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends | ||
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c new file mode 100644 index 000000000000..f7321448b4b1 --- /dev/null +++ b/drivers/media/dvb/dm1105/dm1105.c | |||
@@ -0,0 +1,911 @@ | |||
1 | /* | ||
2 | * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip | ||
3 | * | ||
4 | * Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/version.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/proc_fs.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/dma-mapping.h> | ||
30 | #include <linux/input.h> | ||
31 | #include <media/ir-common.h> | ||
32 | |||
33 | #include "demux.h" | ||
34 | #include "dmxdev.h" | ||
35 | #include "dvb_demux.h" | ||
36 | #include "dvb_frontend.h" | ||
37 | #include "dvb_net.h" | ||
38 | #include "dvbdev.h" | ||
39 | #include "dvb-pll.h" | ||
40 | |||
41 | #include "stv0299.h" | ||
42 | #include "stv0288.h" | ||
43 | #include "stb6000.h" | ||
44 | #include "si21xx.h" | ||
45 | #include "cx24116.h" | ||
46 | #include "z0194a.h" | ||
47 | |||
48 | /* ----------------------------------------------- */ | ||
49 | /* | ||
50 | * PCI ID's | ||
51 | */ | ||
52 | #ifndef PCI_VENDOR_ID_TRIGEM | ||
53 | #define PCI_VENDOR_ID_TRIGEM 0x109f | ||
54 | #endif | ||
55 | #ifndef PCI_DEVICE_ID_DM1105 | ||
56 | #define PCI_DEVICE_ID_DM1105 0x036f | ||
57 | #endif | ||
58 | #ifndef PCI_DEVICE_ID_DW2002 | ||
59 | #define PCI_DEVICE_ID_DW2002 0x2002 | ||
60 | #endif | ||
61 | #ifndef PCI_DEVICE_ID_DW2004 | ||
62 | #define PCI_DEVICE_ID_DW2004 0x2004 | ||
63 | #endif | ||
64 | /* ----------------------------------------------- */ | ||
65 | /* sdmc dm1105 registers */ | ||
66 | |||
67 | /* TS Control */ | ||
68 | #define DM1105_TSCTR 0x00 | ||
69 | #define DM1105_DTALENTH 0x04 | ||
70 | |||
71 | /* GPIO Interface */ | ||
72 | #define DM1105_GPIOVAL 0x08 | ||
73 | #define DM1105_GPIOCTR 0x0c | ||
74 | |||
75 | /* PID serial number */ | ||
76 | #define DM1105_PIDN 0x10 | ||
77 | |||
78 | /* Odd-even secret key select */ | ||
79 | #define DM1105_CWSEL 0x14 | ||
80 | |||
81 | /* Host Command Interface */ | ||
82 | #define DM1105_HOST_CTR 0x18 | ||
83 | #define DM1105_HOST_AD 0x1c | ||
84 | |||
85 | /* PCI Interface */ | ||
86 | #define DM1105_CR 0x30 | ||
87 | #define DM1105_RST 0x34 | ||
88 | #define DM1105_STADR 0x38 | ||
89 | #define DM1105_RLEN 0x3c | ||
90 | #define DM1105_WRP 0x40 | ||
91 | #define DM1105_INTCNT 0x44 | ||
92 | #define DM1105_INTMAK 0x48 | ||
93 | #define DM1105_INTSTS 0x4c | ||
94 | |||
95 | /* CW Value */ | ||
96 | #define DM1105_ODD 0x50 | ||
97 | #define DM1105_EVEN 0x58 | ||
98 | |||
99 | /* PID Value */ | ||
100 | #define DM1105_PID 0x60 | ||
101 | |||
102 | /* IR Control */ | ||
103 | #define DM1105_IRCTR 0x64 | ||
104 | #define DM1105_IRMODE 0x68 | ||
105 | #define DM1105_SYSTEMCODE 0x6c | ||
106 | #define DM1105_IRCODE 0x70 | ||
107 | |||
108 | /* Unknown Values */ | ||
109 | #define DM1105_ENCRYPT 0x74 | ||
110 | #define DM1105_VER 0x7c | ||
111 | |||
112 | /* I2C Interface */ | ||
113 | #define DM1105_I2CCTR 0x80 | ||
114 | #define DM1105_I2CSTS 0x81 | ||
115 | #define DM1105_I2CDAT 0x82 | ||
116 | #define DM1105_I2C_RA 0x83 | ||
117 | /* ----------------------------------------------- */ | ||
118 | /* Interrupt Mask Bits */ | ||
119 | |||
120 | #define INTMAK_TSIRQM 0x01 | ||
121 | #define INTMAK_HIRQM 0x04 | ||
122 | #define INTMAK_IRM 0x08 | ||
123 | #define INTMAK_ALLMASK (INTMAK_TSIRQM | \ | ||
124 | INTMAK_HIRQM | \ | ||
125 | INTMAK_IRM) | ||
126 | #define INTMAK_NONEMASK 0x00 | ||
127 | |||
128 | /* Interrupt Status Bits */ | ||
129 | #define INTSTS_TSIRQ 0x01 | ||
130 | #define INTSTS_HIRQ 0x04 | ||
131 | #define INTSTS_IR 0x08 | ||
132 | |||
133 | /* IR Control Bits */ | ||
134 | #define DM1105_IR_EN 0x01 | ||
135 | #define DM1105_SYS_CHK 0x02 | ||
136 | #define DM1105_REP_FLG 0x08 | ||
137 | |||
138 | /* EEPROM addr */ | ||
139 | #define IIC_24C01_addr 0xa0 | ||
140 | /* Max board count */ | ||
141 | #define DM1105_MAX 0x04 | ||
142 | |||
143 | #define DRIVER_NAME "dm1105" | ||
144 | |||
145 | #define DM1105_DMA_PACKETS 47 | ||
146 | #define DM1105_DMA_PACKET_LENGTH (128*4) | ||
147 | #define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) | ||
148 | |||
149 | /* GPIO's for LNB power control */ | ||
150 | #define DM1105_LNB_MASK 0x00000000 | ||
151 | #define DM1105_LNB_13V 0x00010100 | ||
152 | #define DM1105_LNB_18V 0x00000100 | ||
153 | |||
154 | static int ir_debug; | ||
155 | module_param(ir_debug, int, 0644); | ||
156 | MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); | ||
157 | |||
158 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
159 | |||
160 | static u16 ir_codes_dm1105_nec[128] = { | ||
161 | [0x0a] = KEY_Q, /*power*/ | ||
162 | [0x0c] = KEY_M, /*mute*/ | ||
163 | [0x11] = KEY_1, | ||
164 | [0x12] = KEY_2, | ||
165 | [0x13] = KEY_3, | ||
166 | [0x14] = KEY_4, | ||
167 | [0x15] = KEY_5, | ||
168 | [0x16] = KEY_6, | ||
169 | [0x17] = KEY_7, | ||
170 | [0x18] = KEY_8, | ||
171 | [0x19] = KEY_9, | ||
172 | [0x10] = KEY_0, | ||
173 | [0x1c] = KEY_PAGEUP, /*ch+*/ | ||
174 | [0x0f] = KEY_PAGEDOWN, /*ch-*/ | ||
175 | [0x1a] = KEY_O, /*vol+*/ | ||
176 | [0x0e] = KEY_Z, /*vol-*/ | ||
177 | [0x04] = KEY_R, /*rec*/ | ||
178 | [0x09] = KEY_D, /*fav*/ | ||
179 | [0x08] = KEY_BACKSPACE, /*rewind*/ | ||
180 | [0x07] = KEY_A, /*fast*/ | ||
181 | [0x0b] = KEY_P, /*pause*/ | ||
182 | [0x02] = KEY_ESC, /*cancel*/ | ||
183 | [0x03] = KEY_G, /*tab*/ | ||
184 | [0x00] = KEY_UP, /*up*/ | ||
185 | [0x1f] = KEY_ENTER, /*ok*/ | ||
186 | [0x01] = KEY_DOWN, /*down*/ | ||
187 | [0x05] = KEY_C, /*cap*/ | ||
188 | [0x06] = KEY_S, /*stop*/ | ||
189 | [0x40] = KEY_F, /*full*/ | ||
190 | [0x1e] = KEY_W, /*tvmode*/ | ||
191 | [0x1b] = KEY_B, /*recall*/ | ||
192 | }; | ||
193 | |||
194 | /* infrared remote control */ | ||
195 | struct infrared { | ||
196 | u16 key_map[128]; | ||
197 | struct input_dev *input_dev; | ||
198 | char input_phys[32]; | ||
199 | struct tasklet_struct ir_tasklet; | ||
200 | u32 ir_command; | ||
201 | }; | ||
202 | |||
203 | struct dm1105dvb { | ||
204 | /* pci */ | ||
205 | struct pci_dev *pdev; | ||
206 | u8 __iomem *io_mem; | ||
207 | |||
208 | /* ir */ | ||
209 | struct infrared ir; | ||
210 | |||
211 | /* dvb */ | ||
212 | struct dmx_frontend hw_frontend; | ||
213 | struct dmx_frontend mem_frontend; | ||
214 | struct dmxdev dmxdev; | ||
215 | struct dvb_adapter dvb_adapter; | ||
216 | struct dvb_demux demux; | ||
217 | struct dvb_frontend *fe; | ||
218 | struct dvb_net dvbnet; | ||
219 | unsigned int full_ts_users; | ||
220 | |||
221 | /* i2c */ | ||
222 | struct i2c_adapter i2c_adap; | ||
223 | |||
224 | /* dma */ | ||
225 | dma_addr_t dma_addr; | ||
226 | unsigned char *ts_buf; | ||
227 | u32 wrp; | ||
228 | u32 buffer_size; | ||
229 | unsigned int PacketErrorCount; | ||
230 | unsigned int dmarst; | ||
231 | spinlock_t lock; | ||
232 | |||
233 | }; | ||
234 | |||
235 | #define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg])) | ||
236 | |||
237 | static struct dm1105dvb *dm1105dvb_local; | ||
238 | |||
239 | static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
240 | struct i2c_msg *msgs, int num) | ||
241 | { | ||
242 | struct dm1105dvb *dm1105dvb ; | ||
243 | |||
244 | int addr, rc, i, j, k, len, byte, data; | ||
245 | u8 status; | ||
246 | |||
247 | dm1105dvb = i2c_adap->algo_data; | ||
248 | for (i = 0; i < num; i++) { | ||
249 | outb(0x00, dm_io_mem(DM1105_I2CCTR)); | ||
250 | if (msgs[i].flags & I2C_M_RD) { | ||
251 | /* read bytes */ | ||
252 | addr = msgs[i].addr << 1; | ||
253 | addr |= 1; | ||
254 | outb(addr, dm_io_mem(DM1105_I2CDAT)); | ||
255 | for (byte = 0; byte < msgs[i].len; byte++) | ||
256 | outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1)); | ||
257 | |||
258 | outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR)); | ||
259 | for (j = 0; j < 55; j++) { | ||
260 | mdelay(10); | ||
261 | status = inb(dm_io_mem(DM1105_I2CSTS)); | ||
262 | if ((status & 0xc0) == 0x40) | ||
263 | break; | ||
264 | } | ||
265 | if (j >= 55) | ||
266 | return -1; | ||
267 | |||
268 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
269 | rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1)); | ||
270 | if (rc < 0) | ||
271 | goto err; | ||
272 | msgs[i].buf[byte] = rc; | ||
273 | } | ||
274 | } else { | ||
275 | if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { | ||
276 | /* prepaired for cx24116 firmware */ | ||
277 | /* Write in small blocks */ | ||
278 | len = msgs[i].len - 1; | ||
279 | k = 1; | ||
280 | do { | ||
281 | outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT)); | ||
282 | outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1)); | ||
283 | for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { | ||
284 | data = msgs[i].buf[k+byte]; | ||
285 | outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2)); | ||
286 | } | ||
287 | outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR)); | ||
288 | for (j = 0; j < 25; j++) { | ||
289 | mdelay(10); | ||
290 | status = inb(dm_io_mem(DM1105_I2CSTS)); | ||
291 | if ((status & 0xc0) == 0x40) | ||
292 | break; | ||
293 | } | ||
294 | |||
295 | if (j >= 25) | ||
296 | return -1; | ||
297 | |||
298 | k += 48; | ||
299 | len -= 48; | ||
300 | } while (len > 0); | ||
301 | } else { | ||
302 | /* write bytes */ | ||
303 | outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT)); | ||
304 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
305 | data = msgs[i].buf[byte]; | ||
306 | outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1)); | ||
307 | } | ||
308 | outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR)); | ||
309 | for (j = 0; j < 25; j++) { | ||
310 | mdelay(10); | ||
311 | status = inb(dm_io_mem(DM1105_I2CSTS)); | ||
312 | if ((status & 0xc0) == 0x40) | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | if (j >= 25) | ||
317 | return -1; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | return num; | ||
322 | err: | ||
323 | return rc; | ||
324 | } | ||
325 | |||
326 | static u32 functionality(struct i2c_adapter *adap) | ||
327 | { | ||
328 | return I2C_FUNC_I2C; | ||
329 | } | ||
330 | |||
331 | static struct i2c_algorithm dm1105_algo = { | ||
332 | .master_xfer = dm1105_i2c_xfer, | ||
333 | .functionality = functionality, | ||
334 | }; | ||
335 | |||
336 | static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed) | ||
337 | { | ||
338 | return container_of(feed->demux, struct dm1105dvb, demux); | ||
339 | } | ||
340 | |||
341 | static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe) | ||
342 | { | ||
343 | return container_of(fe->dvb, struct dm1105dvb, dvb_adapter); | ||
344 | } | ||
345 | |||
346 | static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
347 | { | ||
348 | struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe); | ||
349 | |||
350 | if (voltage == SEC_VOLTAGE_18) { | ||
351 | outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); | ||
352 | outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL)); | ||
353 | } else { | ||
354 | /*LNB ON-13V by default!*/ | ||
355 | outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); | ||
356 | outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL)); | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb) | ||
363 | { | ||
364 | outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR)); | ||
365 | } | ||
366 | |||
367 | static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb) | ||
368 | { | ||
369 | dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr); | ||
370 | |||
371 | return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr); | ||
372 | } | ||
373 | |||
374 | static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) | ||
375 | { | ||
376 | pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr); | ||
377 | } | ||
378 | |||
379 | static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb) | ||
380 | { | ||
381 | outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK)); | ||
382 | outb(1, dm_io_mem(DM1105_CR)); | ||
383 | } | ||
384 | |||
385 | static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb) | ||
386 | { | ||
387 | outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK)); | ||
388 | outb(0, dm_io_mem(DM1105_CR)); | ||
389 | } | ||
390 | |||
391 | static int dm1105dvb_start_feed(struct dvb_demux_feed *f) | ||
392 | { | ||
393 | struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f); | ||
394 | |||
395 | if (dm1105dvb->full_ts_users++ == 0) | ||
396 | dm1105dvb_enable_irqs(dm1105dvb); | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int dm1105dvb_stop_feed(struct dvb_demux_feed *f) | ||
402 | { | ||
403 | struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f); | ||
404 | |||
405 | if (--dm1105dvb->full_ts_users == 0) | ||
406 | dm1105dvb_disable_irqs(dm1105dvb); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /* ir tasklet */ | ||
412 | static void dm1105_emit_key(unsigned long parm) | ||
413 | { | ||
414 | struct infrared *ir = (struct infrared *) parm; | ||
415 | u32 ircom = ir->ir_command; | ||
416 | u8 data; | ||
417 | u16 keycode; | ||
418 | |||
419 | data = (ircom >> 8) & 0x7f; | ||
420 | |||
421 | input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data); | ||
422 | input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); | ||
423 | keycode = ir->key_map[data]; | ||
424 | |||
425 | if (!keycode) | ||
426 | return; | ||
427 | |||
428 | input_event(ir->input_dev, EV_KEY, keycode, 1); | ||
429 | input_sync(ir->input_dev); | ||
430 | input_event(ir->input_dev, EV_KEY, keycode, 0); | ||
431 | input_sync(ir->input_dev); | ||
432 | |||
433 | } | ||
434 | |||
435 | static irqreturn_t dm1105dvb_irq(int irq, void *dev_id) | ||
436 | { | ||
437 | struct dm1105dvb *dm1105dvb = dev_id; | ||
438 | unsigned int piece; | ||
439 | unsigned int nbpackets; | ||
440 | u32 command; | ||
441 | u32 nextwrp; | ||
442 | u32 oldwrp; | ||
443 | |||
444 | /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ | ||
445 | unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS)); | ||
446 | outb(intsts, dm_io_mem(DM1105_INTSTS)); | ||
447 | |||
448 | switch (intsts) { | ||
449 | case INTSTS_TSIRQ: | ||
450 | case (INTSTS_TSIRQ | INTSTS_IR): | ||
451 | nextwrp = inl(dm_io_mem(DM1105_WRP)) - | ||
452 | inl(dm_io_mem(DM1105_STADR)) ; | ||
453 | oldwrp = dm1105dvb->wrp; | ||
454 | spin_lock(&dm1105dvb->lock); | ||
455 | if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) && | ||
456 | (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) && | ||
457 | (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) { | ||
458 | dm1105dvb->PacketErrorCount++; | ||
459 | /* bad packet found */ | ||
460 | if ((dm1105dvb->PacketErrorCount >= 2) && | ||
461 | (dm1105dvb->dmarst == 0)) { | ||
462 | outb(1, dm_io_mem(DM1105_RST)); | ||
463 | dm1105dvb->wrp = 0; | ||
464 | dm1105dvb->PacketErrorCount = 0; | ||
465 | dm1105dvb->dmarst = 0; | ||
466 | spin_unlock(&dm1105dvb->lock); | ||
467 | return IRQ_HANDLED; | ||
468 | } | ||
469 | } | ||
470 | if (nextwrp < oldwrp) { | ||
471 | piece = dm1105dvb->buffer_size - oldwrp; | ||
472 | memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp); | ||
473 | nbpackets = (piece + nextwrp)/188; | ||
474 | } else { | ||
475 | nbpackets = (nextwrp - oldwrp)/188; | ||
476 | } | ||
477 | dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets); | ||
478 | dm1105dvb->wrp = nextwrp; | ||
479 | spin_unlock(&dm1105dvb->lock); | ||
480 | break; | ||
481 | case INTSTS_IR: | ||
482 | command = inl(dm_io_mem(DM1105_IRCODE)); | ||
483 | if (ir_debug) | ||
484 | printk("dm1105: received byte 0x%04x\n", command); | ||
485 | |||
486 | dm1105dvb->ir.ir_command = command; | ||
487 | tasklet_schedule(&dm1105dvb->ir.ir_tasklet); | ||
488 | break; | ||
489 | } | ||
490 | return IRQ_HANDLED; | ||
491 | |||
492 | |||
493 | } | ||
494 | |||
495 | /* register with input layer */ | ||
496 | static void input_register_keys(struct infrared *ir) | ||
497 | { | ||
498 | int i; | ||
499 | |||
500 | memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); | ||
501 | |||
502 | for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) | ||
503 | set_bit(ir->key_map[i], ir->input_dev->keybit); | ||
504 | |||
505 | ir->input_dev->keycode = ir->key_map; | ||
506 | ir->input_dev->keycodesize = sizeof(ir->key_map[0]); | ||
507 | ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); | ||
508 | } | ||
509 | |||
510 | int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) | ||
511 | { | ||
512 | struct input_dev *input_dev; | ||
513 | int err; | ||
514 | |||
515 | dm1105dvb_local = dm1105; | ||
516 | |||
517 | input_dev = input_allocate_device(); | ||
518 | if (!input_dev) | ||
519 | return -ENOMEM; | ||
520 | |||
521 | dm1105->ir.input_dev = input_dev; | ||
522 | snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), | ||
523 | "pci-%s/ir0", pci_name(dm1105->pdev)); | ||
524 | |||
525 | input_dev->evbit[0] = BIT(EV_KEY); | ||
526 | input_dev->name = "DVB on-card IR receiver"; | ||
527 | |||
528 | input_dev->phys = dm1105->ir.input_phys; | ||
529 | input_dev->id.bustype = BUS_PCI; | ||
530 | input_dev->id.version = 2; | ||
531 | if (dm1105->pdev->subsystem_vendor) { | ||
532 | input_dev->id.vendor = dm1105->pdev->subsystem_vendor; | ||
533 | input_dev->id.product = dm1105->pdev->subsystem_device; | ||
534 | } else { | ||
535 | input_dev->id.vendor = dm1105->pdev->vendor; | ||
536 | input_dev->id.product = dm1105->pdev->device; | ||
537 | } | ||
538 | input_dev->dev.parent = &dm1105->pdev->dev; | ||
539 | /* initial keymap */ | ||
540 | memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map); | ||
541 | input_register_keys(&dm1105->ir); | ||
542 | err = input_register_device(input_dev); | ||
543 | if (err) { | ||
544 | input_free_device(input_dev); | ||
545 | return err; | ||
546 | } | ||
547 | |||
548 | tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir); | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | |||
554 | void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105) | ||
555 | { | ||
556 | tasklet_kill(&dm1105->ir.ir_tasklet); | ||
557 | input_unregister_device(dm1105->ir.input_dev); | ||
558 | |||
559 | } | ||
560 | |||
561 | static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb) | ||
562 | { | ||
563 | dm1105dvb_disable_irqs(dm1105dvb); | ||
564 | |||
565 | outb(0, dm_io_mem(DM1105_HOST_CTR)); | ||
566 | |||
567 | /*DATALEN 188,*/ | ||
568 | outb(188, dm_io_mem(DM1105_DTALENTH)); | ||
569 | /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/ | ||
570 | outw(0xc10a, dm_io_mem(DM1105_TSCTR)); | ||
571 | |||
572 | /* map DMA and set address */ | ||
573 | dm1105dvb_dma_map(dm1105dvb); | ||
574 | dm1105dvb_set_dma_addr(dm1105dvb); | ||
575 | /* big buffer */ | ||
576 | outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN)); | ||
577 | outb(47, dm_io_mem(DM1105_INTCNT)); | ||
578 | |||
579 | /* IR NEC mode enable */ | ||
580 | outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR)); | ||
581 | outb(0, dm_io_mem(DM1105_IRMODE)); | ||
582 | outw(0, dm_io_mem(DM1105_SYSTEMCODE)); | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb) | ||
588 | { | ||
589 | dm1105dvb_disable_irqs(dm1105dvb); | ||
590 | |||
591 | /* IR disable */ | ||
592 | outb(0, dm_io_mem(DM1105_IRCTR)); | ||
593 | outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK)); | ||
594 | |||
595 | dm1105dvb_dma_unmap(dm1105dvb); | ||
596 | } | ||
597 | |||
598 | static struct stv0288_config earda_config = { | ||
599 | .demod_address = 0x68, | ||
600 | .min_delay_ms = 100, | ||
601 | }; | ||
602 | |||
603 | static struct si21xx_config serit_config = { | ||
604 | .demod_address = 0x68, | ||
605 | .min_delay_ms = 100, | ||
606 | |||
607 | }; | ||
608 | |||
609 | static struct cx24116_config serit_sp2633_config = { | ||
610 | .demod_address = 0x55, | ||
611 | }; | ||
612 | |||
613 | static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) | ||
614 | { | ||
615 | int ret; | ||
616 | |||
617 | switch (dm1105dvb->pdev->subsystem_device) { | ||
618 | case PCI_DEVICE_ID_DW2002: | ||
619 | dm1105dvb->fe = dvb_attach( | ||
620 | stv0299_attach, &sharp_z0194a_config, | ||
621 | &dm1105dvb->i2c_adap); | ||
622 | |||
623 | if (dm1105dvb->fe) { | ||
624 | dm1105dvb->fe->ops.set_voltage = | ||
625 | dm1105dvb_set_voltage; | ||
626 | dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60, | ||
627 | &dm1105dvb->i2c_adap, DVB_PLL_OPERA1); | ||
628 | } | ||
629 | |||
630 | if (!dm1105dvb->fe) { | ||
631 | dm1105dvb->fe = dvb_attach( | ||
632 | stv0288_attach, &earda_config, | ||
633 | &dm1105dvb->i2c_adap); | ||
634 | if (dm1105dvb->fe) { | ||
635 | dm1105dvb->fe->ops.set_voltage = | ||
636 | dm1105dvb_set_voltage; | ||
637 | dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61, | ||
638 | &dm1105dvb->i2c_adap); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | if (!dm1105dvb->fe) { | ||
643 | dm1105dvb->fe = dvb_attach( | ||
644 | si21xx_attach, &serit_config, | ||
645 | &dm1105dvb->i2c_adap); | ||
646 | if (dm1105dvb->fe) | ||
647 | dm1105dvb->fe->ops.set_voltage = | ||
648 | dm1105dvb_set_voltage; | ||
649 | } | ||
650 | break; | ||
651 | case PCI_DEVICE_ID_DW2004: | ||
652 | dm1105dvb->fe = dvb_attach( | ||
653 | cx24116_attach, &serit_sp2633_config, | ||
654 | &dm1105dvb->i2c_adap); | ||
655 | if (dm1105dvb->fe) | ||
656 | dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; | ||
657 | break; | ||
658 | } | ||
659 | |||
660 | if (!dm1105dvb->fe) { | ||
661 | dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n"); | ||
662 | return -ENODEV; | ||
663 | } | ||
664 | |||
665 | ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe); | ||
666 | if (ret < 0) { | ||
667 | if (dm1105dvb->fe->ops.release) | ||
668 | dm1105dvb->fe->ops.release(dm1105dvb->fe); | ||
669 | dm1105dvb->fe = NULL; | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac) | ||
677 | { | ||
678 | static u8 command[1] = { 0x28 }; | ||
679 | |||
680 | struct i2c_msg msg[] = { | ||
681 | { .addr = IIC_24C01_addr >> 1, .flags = 0, | ||
682 | .buf = command, .len = 1 }, | ||
683 | { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD, | ||
684 | .buf = mac, .len = 6 }, | ||
685 | }; | ||
686 | |||
687 | dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2); | ||
688 | dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
689 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
690 | } | ||
691 | |||
692 | static int __devinit dm1105_probe(struct pci_dev *pdev, | ||
693 | const struct pci_device_id *ent) | ||
694 | { | ||
695 | struct dm1105dvb *dm1105dvb; | ||
696 | struct dvb_adapter *dvb_adapter; | ||
697 | struct dvb_demux *dvbdemux; | ||
698 | struct dmx_demux *dmx; | ||
699 | int ret = -ENOMEM; | ||
700 | |||
701 | dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL); | ||
702 | if (!dm1105dvb) | ||
703 | goto out; | ||
704 | |||
705 | dm1105dvb->pdev = pdev; | ||
706 | dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES; | ||
707 | dm1105dvb->PacketErrorCount = 0; | ||
708 | dm1105dvb->dmarst = 0; | ||
709 | |||
710 | ret = pci_enable_device(pdev); | ||
711 | if (ret < 0) | ||
712 | goto err_kfree; | ||
713 | |||
714 | ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
715 | if (ret < 0) | ||
716 | goto err_pci_disable_device; | ||
717 | |||
718 | pci_set_master(pdev); | ||
719 | |||
720 | ret = pci_request_regions(pdev, DRIVER_NAME); | ||
721 | if (ret < 0) | ||
722 | goto err_pci_disable_device; | ||
723 | |||
724 | dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); | ||
725 | if (!dm1105dvb->io_mem) { | ||
726 | ret = -EIO; | ||
727 | goto err_pci_release_regions; | ||
728 | } | ||
729 | |||
730 | spin_lock_init(&dm1105dvb->lock); | ||
731 | pci_set_drvdata(pdev, dm1105dvb); | ||
732 | |||
733 | ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb); | ||
734 | if (ret < 0) | ||
735 | goto err_pci_iounmap; | ||
736 | |||
737 | ret = dm1105dvb_hw_init(dm1105dvb); | ||
738 | if (ret < 0) | ||
739 | goto err_free_irq; | ||
740 | |||
741 | /* i2c */ | ||
742 | i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb); | ||
743 | strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME); | ||
744 | dm1105dvb->i2c_adap.owner = THIS_MODULE; | ||
745 | dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL; | ||
746 | dm1105dvb->i2c_adap.dev.parent = &pdev->dev; | ||
747 | dm1105dvb->i2c_adap.algo = &dm1105_algo; | ||
748 | dm1105dvb->i2c_adap.algo_data = dm1105dvb; | ||
749 | ret = i2c_add_adapter(&dm1105dvb->i2c_adap); | ||
750 | |||
751 | if (ret < 0) | ||
752 | goto err_dm1105dvb_hw_exit; | ||
753 | |||
754 | /* dvb */ | ||
755 | ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME, | ||
756 | THIS_MODULE, &pdev->dev, adapter_nr); | ||
757 | if (ret < 0) | ||
758 | goto err_i2c_del_adapter; | ||
759 | |||
760 | dvb_adapter = &dm1105dvb->dvb_adapter; | ||
761 | |||
762 | dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac); | ||
763 | |||
764 | dvbdemux = &dm1105dvb->demux; | ||
765 | dvbdemux->filternum = 256; | ||
766 | dvbdemux->feednum = 256; | ||
767 | dvbdemux->start_feed = dm1105dvb_start_feed; | ||
768 | dvbdemux->stop_feed = dm1105dvb_stop_feed; | ||
769 | dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | | ||
770 | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); | ||
771 | ret = dvb_dmx_init(dvbdemux); | ||
772 | if (ret < 0) | ||
773 | goto err_dvb_unregister_adapter; | ||
774 | |||
775 | dmx = &dvbdemux->dmx; | ||
776 | dm1105dvb->dmxdev.filternum = 256; | ||
777 | dm1105dvb->dmxdev.demux = dmx; | ||
778 | dm1105dvb->dmxdev.capabilities = 0; | ||
779 | |||
780 | ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter); | ||
781 | if (ret < 0) | ||
782 | goto err_dvb_dmx_release; | ||
783 | |||
784 | dm1105dvb->hw_frontend.source = DMX_FRONTEND_0; | ||
785 | |||
786 | ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend); | ||
787 | if (ret < 0) | ||
788 | goto err_dvb_dmxdev_release; | ||
789 | |||
790 | dm1105dvb->mem_frontend.source = DMX_MEMORY_FE; | ||
791 | |||
792 | ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend); | ||
793 | if (ret < 0) | ||
794 | goto err_remove_hw_frontend; | ||
795 | |||
796 | ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend); | ||
797 | if (ret < 0) | ||
798 | goto err_remove_mem_frontend; | ||
799 | |||
800 | ret = frontend_init(dm1105dvb); | ||
801 | if (ret < 0) | ||
802 | goto err_disconnect_frontend; | ||
803 | |||
804 | dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx); | ||
805 | dm1105_ir_init(dm1105dvb); | ||
806 | out: | ||
807 | return ret; | ||
808 | |||
809 | err_disconnect_frontend: | ||
810 | dmx->disconnect_frontend(dmx); | ||
811 | err_remove_mem_frontend: | ||
812 | dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend); | ||
813 | err_remove_hw_frontend: | ||
814 | dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend); | ||
815 | err_dvb_dmxdev_release: | ||
816 | dvb_dmxdev_release(&dm1105dvb->dmxdev); | ||
817 | err_dvb_dmx_release: | ||
818 | dvb_dmx_release(dvbdemux); | ||
819 | err_dvb_unregister_adapter: | ||
820 | dvb_unregister_adapter(dvb_adapter); | ||
821 | err_i2c_del_adapter: | ||
822 | i2c_del_adapter(&dm1105dvb->i2c_adap); | ||
823 | err_dm1105dvb_hw_exit: | ||
824 | dm1105dvb_hw_exit(dm1105dvb); | ||
825 | err_free_irq: | ||
826 | free_irq(pdev->irq, dm1105dvb); | ||
827 | err_pci_iounmap: | ||
828 | pci_iounmap(pdev, dm1105dvb->io_mem); | ||
829 | err_pci_release_regions: | ||
830 | pci_release_regions(pdev); | ||
831 | err_pci_disable_device: | ||
832 | pci_disable_device(pdev); | ||
833 | err_kfree: | ||
834 | pci_set_drvdata(pdev, NULL); | ||
835 | kfree(dm1105dvb); | ||
836 | goto out; | ||
837 | } | ||
838 | |||
839 | static void __devexit dm1105_remove(struct pci_dev *pdev) | ||
840 | { | ||
841 | struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev); | ||
842 | struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter; | ||
843 | struct dvb_demux *dvbdemux = &dm1105dvb->demux; | ||
844 | struct dmx_demux *dmx = &dvbdemux->dmx; | ||
845 | |||
846 | dm1105_ir_exit(dm1105dvb); | ||
847 | dmx->close(dmx); | ||
848 | dvb_net_release(&dm1105dvb->dvbnet); | ||
849 | if (dm1105dvb->fe) | ||
850 | dvb_unregister_frontend(dm1105dvb->fe); | ||
851 | |||
852 | dmx->disconnect_frontend(dmx); | ||
853 | dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend); | ||
854 | dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend); | ||
855 | dvb_dmxdev_release(&dm1105dvb->dmxdev); | ||
856 | dvb_dmx_release(dvbdemux); | ||
857 | dvb_unregister_adapter(dvb_adapter); | ||
858 | if (&dm1105dvb->i2c_adap) | ||
859 | i2c_del_adapter(&dm1105dvb->i2c_adap); | ||
860 | |||
861 | dm1105dvb_hw_exit(dm1105dvb); | ||
862 | synchronize_irq(pdev->irq); | ||
863 | free_irq(pdev->irq, dm1105dvb); | ||
864 | pci_iounmap(pdev, dm1105dvb->io_mem); | ||
865 | pci_release_regions(pdev); | ||
866 | pci_disable_device(pdev); | ||
867 | pci_set_drvdata(pdev, NULL); | ||
868 | kfree(dm1105dvb); | ||
869 | } | ||
870 | |||
871 | static struct pci_device_id dm1105_id_table[] __devinitdata = { | ||
872 | { | ||
873 | .vendor = PCI_VENDOR_ID_TRIGEM, | ||
874 | .device = PCI_DEVICE_ID_DM1105, | ||
875 | .subvendor = PCI_ANY_ID, | ||
876 | .subdevice = PCI_DEVICE_ID_DW2002, | ||
877 | }, { | ||
878 | .vendor = PCI_VENDOR_ID_TRIGEM, | ||
879 | .device = PCI_DEVICE_ID_DM1105, | ||
880 | .subvendor = PCI_ANY_ID, | ||
881 | .subdevice = PCI_DEVICE_ID_DW2004, | ||
882 | }, { | ||
883 | /* empty */ | ||
884 | }, | ||
885 | }; | ||
886 | |||
887 | MODULE_DEVICE_TABLE(pci, dm1105_id_table); | ||
888 | |||
889 | static struct pci_driver dm1105_driver = { | ||
890 | .name = DRIVER_NAME, | ||
891 | .id_table = dm1105_id_table, | ||
892 | .probe = dm1105_probe, | ||
893 | .remove = __devexit_p(dm1105_remove), | ||
894 | }; | ||
895 | |||
896 | static int __init dm1105_init(void) | ||
897 | { | ||
898 | return pci_register_driver(&dm1105_driver); | ||
899 | } | ||
900 | |||
901 | static void __exit dm1105_exit(void) | ||
902 | { | ||
903 | pci_unregister_driver(&dm1105_driver); | ||
904 | } | ||
905 | |||
906 | module_init(dm1105_init); | ||
907 | module_exit(dm1105_exit); | ||
908 | |||
909 | MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>"); | ||
910 | MODULE_DESCRIPTION("SDMC DM1105 DVB driver"); | ||
911 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 3526e3ee9487..f170e822fadc 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -40,6 +40,7 @@ | |||
40 | 40 | ||
41 | #include "dvb_frontend.h" | 41 | #include "dvb_frontend.h" |
42 | #include "dvbdev.h" | 42 | #include "dvbdev.h" |
43 | #include <linux/dvb/version.h> | ||
43 | 44 | ||
44 | static int dvb_frontend_debug; | 45 | static int dvb_frontend_debug; |
45 | static int dvb_shutdown_timeout; | 46 | static int dvb_shutdown_timeout; |
@@ -755,6 +756,539 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, | |||
755 | return 0; | 756 | return 0; |
756 | } | 757 | } |
757 | 758 | ||
759 | struct dtv_cmds_h dtv_cmds[] = { | ||
760 | [DTV_TUNE] = { | ||
761 | .name = "DTV_TUNE", | ||
762 | .cmd = DTV_TUNE, | ||
763 | .set = 1, | ||
764 | }, | ||
765 | [DTV_CLEAR] = { | ||
766 | .name = "DTV_CLEAR", | ||
767 | .cmd = DTV_CLEAR, | ||
768 | .set = 1, | ||
769 | }, | ||
770 | |||
771 | /* Set */ | ||
772 | [DTV_FREQUENCY] = { | ||
773 | .name = "DTV_FREQUENCY", | ||
774 | .cmd = DTV_FREQUENCY, | ||
775 | .set = 1, | ||
776 | }, | ||
777 | [DTV_BANDWIDTH_HZ] = { | ||
778 | .name = "DTV_BANDWIDTH_HZ", | ||
779 | .cmd = DTV_BANDWIDTH_HZ, | ||
780 | .set = 1, | ||
781 | }, | ||
782 | [DTV_MODULATION] = { | ||
783 | .name = "DTV_MODULATION", | ||
784 | .cmd = DTV_MODULATION, | ||
785 | .set = 1, | ||
786 | }, | ||
787 | [DTV_INVERSION] = { | ||
788 | .name = "DTV_INVERSION", | ||
789 | .cmd = DTV_INVERSION, | ||
790 | .set = 1, | ||
791 | }, | ||
792 | [DTV_DISEQC_MASTER] = { | ||
793 | .name = "DTV_DISEQC_MASTER", | ||
794 | .cmd = DTV_DISEQC_MASTER, | ||
795 | .set = 1, | ||
796 | .buffer = 1, | ||
797 | }, | ||
798 | [DTV_SYMBOL_RATE] = { | ||
799 | .name = "DTV_SYMBOL_RATE", | ||
800 | .cmd = DTV_SYMBOL_RATE, | ||
801 | .set = 1, | ||
802 | }, | ||
803 | [DTV_INNER_FEC] = { | ||
804 | .name = "DTV_INNER_FEC", | ||
805 | .cmd = DTV_INNER_FEC, | ||
806 | .set = 1, | ||
807 | }, | ||
808 | [DTV_VOLTAGE] = { | ||
809 | .name = "DTV_VOLTAGE", | ||
810 | .cmd = DTV_VOLTAGE, | ||
811 | .set = 1, | ||
812 | }, | ||
813 | [DTV_TONE] = { | ||
814 | .name = "DTV_TONE", | ||
815 | .cmd = DTV_TONE, | ||
816 | .set = 1, | ||
817 | }, | ||
818 | [DTV_PILOT] = { | ||
819 | .name = "DTV_PILOT", | ||
820 | .cmd = DTV_PILOT, | ||
821 | .set = 1, | ||
822 | }, | ||
823 | [DTV_ROLLOFF] = { | ||
824 | .name = "DTV_ROLLOFF", | ||
825 | .cmd = DTV_ROLLOFF, | ||
826 | .set = 1, | ||
827 | }, | ||
828 | [DTV_DELIVERY_SYSTEM] = { | ||
829 | .name = "DTV_DELIVERY_SYSTEM", | ||
830 | .cmd = DTV_DELIVERY_SYSTEM, | ||
831 | .set = 1, | ||
832 | }, | ||
833 | [DTV_HIERARCHY] = { | ||
834 | .name = "DTV_HIERARCHY", | ||
835 | .cmd = DTV_HIERARCHY, | ||
836 | .set = 1, | ||
837 | }, | ||
838 | [DTV_CODE_RATE_HP] = { | ||
839 | .name = "DTV_CODE_RATE_HP", | ||
840 | .cmd = DTV_CODE_RATE_HP, | ||
841 | .set = 1, | ||
842 | }, | ||
843 | [DTV_CODE_RATE_LP] = { | ||
844 | .name = "DTV_CODE_RATE_LP", | ||
845 | .cmd = DTV_CODE_RATE_LP, | ||
846 | .set = 1, | ||
847 | }, | ||
848 | [DTV_GUARD_INTERVAL] = { | ||
849 | .name = "DTV_GUARD_INTERVAL", | ||
850 | .cmd = DTV_GUARD_INTERVAL, | ||
851 | .set = 1, | ||
852 | }, | ||
853 | [DTV_TRANSMISSION_MODE] = { | ||
854 | .name = "DTV_TRANSMISSION_MODE", | ||
855 | .cmd = DTV_TRANSMISSION_MODE, | ||
856 | .set = 1, | ||
857 | }, | ||
858 | /* Get */ | ||
859 | [DTV_DISEQC_SLAVE_REPLY] = { | ||
860 | .name = "DTV_DISEQC_SLAVE_REPLY", | ||
861 | .cmd = DTV_DISEQC_SLAVE_REPLY, | ||
862 | .set = 0, | ||
863 | .buffer = 1, | ||
864 | }, | ||
865 | [DTV_API_VERSION] = { | ||
866 | .name = "DTV_API_VERSION", | ||
867 | .cmd = DTV_API_VERSION, | ||
868 | .set = 0, | ||
869 | }, | ||
870 | [DTV_CODE_RATE_HP] = { | ||
871 | .name = "DTV_CODE_RATE_HP", | ||
872 | .cmd = DTV_CODE_RATE_HP, | ||
873 | .set = 0, | ||
874 | }, | ||
875 | [DTV_CODE_RATE_LP] = { | ||
876 | .name = "DTV_CODE_RATE_LP", | ||
877 | .cmd = DTV_CODE_RATE_LP, | ||
878 | .set = 0, | ||
879 | }, | ||
880 | [DTV_GUARD_INTERVAL] = { | ||
881 | .name = "DTV_GUARD_INTERVAL", | ||
882 | .cmd = DTV_GUARD_INTERVAL, | ||
883 | .set = 0, | ||
884 | }, | ||
885 | [DTV_TRANSMISSION_MODE] = { | ||
886 | .name = "DTV_TRANSMISSION_MODE", | ||
887 | .cmd = DTV_TRANSMISSION_MODE, | ||
888 | .set = 0, | ||
889 | }, | ||
890 | [DTV_HIERARCHY] = { | ||
891 | .name = "DTV_HIERARCHY", | ||
892 | .cmd = DTV_HIERARCHY, | ||
893 | .set = 0, | ||
894 | }, | ||
895 | }; | ||
896 | |||
897 | void dtv_property_dump(struct dtv_property *tvp) | ||
898 | { | ||
899 | int i; | ||
900 | |||
901 | if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { | ||
902 | printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n", | ||
903 | __func__, tvp->cmd); | ||
904 | return; | ||
905 | } | ||
906 | |||
907 | printk("%s() tvp.cmd = 0x%08x (%s)\n" | ||
908 | ,__FUNCTION__ | ||
909 | ,tvp->cmd | ||
910 | ,dtv_cmds[ tvp->cmd ].name); | ||
911 | |||
912 | if(dtv_cmds[ tvp->cmd ].buffer) { | ||
913 | |||
914 | printk("%s() tvp.u.buffer.len = 0x%02x\n" | ||
915 | ,__FUNCTION__ | ||
916 | ,tvp->u.buffer.len); | ||
917 | |||
918 | for(i = 0; i < tvp->u.buffer.len; i++) | ||
919 | printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" | ||
920 | ,__FUNCTION__ | ||
921 | ,i | ||
922 | ,tvp->u.buffer.data[i]); | ||
923 | |||
924 | } else | ||
925 | printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data); | ||
926 | } | ||
927 | |||
928 | int is_legacy_delivery_system(fe_delivery_system_t s) | ||
929 | { | ||
930 | if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || | ||
931 | (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS)) | ||
932 | return 1; | ||
933 | |||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | /* Synchronise the legacy tuning parameters into the cache, so that demodulator | ||
938 | * drivers can use a single set_frontend tuning function, regardless of whether | ||
939 | * it's being used for the legacy or new API, reducing code and complexity. | ||
940 | */ | ||
941 | void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) | ||
942 | { | ||
943 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
944 | |||
945 | printk("%s()\n", __FUNCTION__); | ||
946 | |||
947 | c->frequency = p->frequency; | ||
948 | c->inversion = p->inversion; | ||
949 | |||
950 | switch (fe->ops.info.type) { | ||
951 | case FE_QPSK: | ||
952 | c->modulation = QPSK; /* implied for DVB-S in legacy API */ | ||
953 | c->rolloff = ROLLOFF_35;/* implied for DVB-S */ | ||
954 | c->symbol_rate = p->u.qpsk.symbol_rate; | ||
955 | c->fec_inner = p->u.qpsk.fec_inner; | ||
956 | c->delivery_system = SYS_DVBS; | ||
957 | break; | ||
958 | case FE_QAM: | ||
959 | c->symbol_rate = p->u.qam.symbol_rate; | ||
960 | c->fec_inner = p->u.qam.fec_inner; | ||
961 | c->modulation = p->u.qam.modulation; | ||
962 | c->delivery_system = SYS_DVBC_ANNEX_AC; | ||
963 | break; | ||
964 | case FE_OFDM: | ||
965 | if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) | ||
966 | c->bandwidth_hz = 6000000; | ||
967 | else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) | ||
968 | c->bandwidth_hz = 7000000; | ||
969 | else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) | ||
970 | c->bandwidth_hz = 8000000; | ||
971 | else | ||
972 | /* Including BANDWIDTH_AUTO */ | ||
973 | c->bandwidth_hz = 0; | ||
974 | c->code_rate_HP = p->u.ofdm.code_rate_HP; | ||
975 | c->code_rate_LP = p->u.ofdm.code_rate_LP; | ||
976 | c->modulation = p->u.ofdm.constellation; | ||
977 | c->transmission_mode = p->u.ofdm.transmission_mode; | ||
978 | c->guard_interval = p->u.ofdm.guard_interval; | ||
979 | c->hierarchy = p->u.ofdm.hierarchy_information; | ||
980 | c->delivery_system = SYS_DVBT; | ||
981 | break; | ||
982 | case FE_ATSC: | ||
983 | c->modulation = p->u.vsb.modulation; | ||
984 | if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) | ||
985 | c->delivery_system = SYS_ATSC; | ||
986 | else | ||
987 | c->delivery_system = SYS_DVBC_ANNEX_B; | ||
988 | break; | ||
989 | } | ||
990 | } | ||
991 | |||
992 | /* Ensure the cached values are set correctly in the frontend | ||
993 | * legacy tuning structures, for the advanced tuning API. | ||
994 | */ | ||
995 | void dtv_property_legacy_params_sync(struct dvb_frontend *fe) | ||
996 | { | ||
997 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
998 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
999 | struct dvb_frontend_parameters *p = &fepriv->parameters; | ||
1000 | |||
1001 | printk("%s()\n", __FUNCTION__); | ||
1002 | |||
1003 | p->frequency = c->frequency; | ||
1004 | p->inversion = c->inversion; | ||
1005 | |||
1006 | switch (fe->ops.info.type) { | ||
1007 | case FE_QPSK: | ||
1008 | printk("%s() Preparing QPSK req\n", __FUNCTION__); | ||
1009 | p->u.qpsk.symbol_rate = c->symbol_rate; | ||
1010 | p->u.qpsk.fec_inner = c->fec_inner; | ||
1011 | c->delivery_system = SYS_DVBS; | ||
1012 | break; | ||
1013 | case FE_QAM: | ||
1014 | printk("%s() Preparing QAM req\n", __FUNCTION__); | ||
1015 | p->u.qam.symbol_rate = c->symbol_rate; | ||
1016 | p->u.qam.fec_inner = c->fec_inner; | ||
1017 | p->u.qam.modulation = c->modulation; | ||
1018 | c->delivery_system = SYS_DVBC_ANNEX_AC; | ||
1019 | break; | ||
1020 | case FE_OFDM: | ||
1021 | printk("%s() Preparing OFDM req\n", __FUNCTION__); | ||
1022 | if (c->bandwidth_hz == 6000000) | ||
1023 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
1024 | else if (c->bandwidth_hz == 7000000) | ||
1025 | p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
1026 | else if (c->bandwidth_hz == 8000000) | ||
1027 | p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
1028 | else | ||
1029 | p->u.ofdm.bandwidth = BANDWIDTH_AUTO; | ||
1030 | p->u.ofdm.code_rate_HP = c->code_rate_HP; | ||
1031 | p->u.ofdm.code_rate_LP = c->code_rate_LP; | ||
1032 | p->u.ofdm.constellation = c->modulation; | ||
1033 | p->u.ofdm.transmission_mode = c->transmission_mode; | ||
1034 | p->u.ofdm.guard_interval = c->guard_interval; | ||
1035 | p->u.ofdm.hierarchy_information = c->hierarchy; | ||
1036 | c->delivery_system = SYS_DVBT; | ||
1037 | break; | ||
1038 | case FE_ATSC: | ||
1039 | printk("%s() Preparing VSB req\n", __FUNCTION__); | ||
1040 | p->u.vsb.modulation = c->modulation; | ||
1041 | if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) | ||
1042 | c->delivery_system = SYS_ATSC; | ||
1043 | else | ||
1044 | c->delivery_system = SYS_DVBC_ANNEX_B; | ||
1045 | break; | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | /* Ensure the cached values are set correctly in the frontend | ||
1050 | * legacy tuning structures, for the legacy tuning API. | ||
1051 | */ | ||
1052 | void dtv_property_adv_params_sync(struct dvb_frontend *fe) | ||
1053 | { | ||
1054 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1055 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
1056 | struct dvb_frontend_parameters *p = &fepriv->parameters; | ||
1057 | |||
1058 | printk("%s()\n", __FUNCTION__); | ||
1059 | |||
1060 | p->frequency = c->frequency; | ||
1061 | p->inversion = c->inversion; | ||
1062 | |||
1063 | switch(c->modulation) { | ||
1064 | case PSK_8: | ||
1065 | case APSK_16: | ||
1066 | case QPSK: | ||
1067 | p->u.qpsk.symbol_rate = c->symbol_rate; | ||
1068 | p->u.qpsk.fec_inner = c->fec_inner; | ||
1069 | break; | ||
1070 | default: | ||
1071 | break; | ||
1072 | } | ||
1073 | |||
1074 | if(c->delivery_system == SYS_ISDBT) { | ||
1075 | /* Fake out a generic DVB-T request so we pass validation in the ioctl */ | ||
1076 | p->frequency = c->frequency; | ||
1077 | p->inversion = INVERSION_AUTO; | ||
1078 | p->u.ofdm.constellation = QAM_AUTO; | ||
1079 | p->u.ofdm.code_rate_HP = FEC_AUTO; | ||
1080 | p->u.ofdm.code_rate_LP = FEC_AUTO; | ||
1081 | p->u.ofdm.bandwidth = BANDWIDTH_AUTO; | ||
1082 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; | ||
1083 | p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; | ||
1084 | p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | void dtv_property_cache_submit(struct dvb_frontend *fe) | ||
1089 | { | ||
1090 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1091 | |||
1092 | printk("%s()\n", __FUNCTION__); | ||
1093 | |||
1094 | /* For legacy delivery systems we don't need the delivery_system to | ||
1095 | * be specified, but we populate the older structures from the cache | ||
1096 | * so we can call set_frontend on older drivers. | ||
1097 | */ | ||
1098 | if(is_legacy_delivery_system(c->delivery_system)) { | ||
1099 | |||
1100 | printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation); | ||
1101 | dtv_property_legacy_params_sync(fe); | ||
1102 | |||
1103 | } else { | ||
1104 | printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation); | ||
1105 | |||
1106 | /* For advanced delivery systems / modulation types ... | ||
1107 | * we seed the lecacy dvb_frontend_parameters structure | ||
1108 | * so that the sanity checking code later in the IOCTL processing | ||
1109 | * can validate our basic frequency ranges, symbolrates, modulation | ||
1110 | * etc. | ||
1111 | */ | ||
1112 | dtv_property_adv_params_sync(fe); | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, | ||
1117 | unsigned int cmd, void *parg); | ||
1118 | static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, | ||
1119 | unsigned int cmd, void *parg); | ||
1120 | |||
1121 | int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, | ||
1122 | struct inode *inode, struct file *file) | ||
1123 | { | ||
1124 | int r = 0; | ||
1125 | |||
1126 | printk("%s()\n", __FUNCTION__); | ||
1127 | |||
1128 | dtv_property_dump(tvp); | ||
1129 | |||
1130 | /* Allow the frontend to validate incoming properties */ | ||
1131 | if (fe->ops.get_property) | ||
1132 | r = fe->ops.get_property(fe, tvp); | ||
1133 | |||
1134 | if (r < 0) | ||
1135 | return r; | ||
1136 | |||
1137 | switch(tvp->cmd) { | ||
1138 | case DTV_FREQUENCY: | ||
1139 | tvp->u.data = fe->dtv_property_cache.frequency; | ||
1140 | break; | ||
1141 | case DTV_MODULATION: | ||
1142 | tvp->u.data = fe->dtv_property_cache.modulation; | ||
1143 | break; | ||
1144 | case DTV_BANDWIDTH_HZ: | ||
1145 | tvp->u.data = fe->dtv_property_cache.bandwidth_hz; | ||
1146 | break; | ||
1147 | case DTV_INVERSION: | ||
1148 | tvp->u.data = fe->dtv_property_cache.inversion; | ||
1149 | break; | ||
1150 | case DTV_SYMBOL_RATE: | ||
1151 | tvp->u.data = fe->dtv_property_cache.symbol_rate; | ||
1152 | break; | ||
1153 | case DTV_INNER_FEC: | ||
1154 | tvp->u.data = fe->dtv_property_cache.fec_inner; | ||
1155 | break; | ||
1156 | case DTV_PILOT: | ||
1157 | tvp->u.data = fe->dtv_property_cache.pilot; | ||
1158 | break; | ||
1159 | case DTV_ROLLOFF: | ||
1160 | tvp->u.data = fe->dtv_property_cache.rolloff; | ||
1161 | break; | ||
1162 | case DTV_DELIVERY_SYSTEM: | ||
1163 | tvp->u.data = fe->dtv_property_cache.delivery_system; | ||
1164 | break; | ||
1165 | case DTV_VOLTAGE: | ||
1166 | tvp->u.data = fe->dtv_property_cache.voltage; | ||
1167 | break; | ||
1168 | case DTV_TONE: | ||
1169 | tvp->u.data = fe->dtv_property_cache.sectone; | ||
1170 | break; | ||
1171 | case DTV_API_VERSION: | ||
1172 | tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR; | ||
1173 | break; | ||
1174 | case DTV_CODE_RATE_HP: | ||
1175 | tvp->u.data = fe->dtv_property_cache.code_rate_HP; | ||
1176 | break; | ||
1177 | case DTV_CODE_RATE_LP: | ||
1178 | tvp->u.data = fe->dtv_property_cache.code_rate_LP; | ||
1179 | break; | ||
1180 | case DTV_GUARD_INTERVAL: | ||
1181 | tvp->u.data = fe->dtv_property_cache.guard_interval; | ||
1182 | break; | ||
1183 | case DTV_TRANSMISSION_MODE: | ||
1184 | tvp->u.data = fe->dtv_property_cache.transmission_mode; | ||
1185 | break; | ||
1186 | case DTV_HIERARCHY: | ||
1187 | tvp->u.data = fe->dtv_property_cache.hierarchy; | ||
1188 | break; | ||
1189 | default: | ||
1190 | r = -1; | ||
1191 | } | ||
1192 | |||
1193 | return r; | ||
1194 | } | ||
1195 | |||
1196 | int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, | ||
1197 | struct inode *inode, struct file *file) | ||
1198 | { | ||
1199 | int r = 0; | ||
1200 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
1201 | printk("%s()\n", __FUNCTION__); | ||
1202 | dtv_property_dump(tvp); | ||
1203 | |||
1204 | /* Allow the frontend to validate incoming properties */ | ||
1205 | if (fe->ops.set_property) | ||
1206 | r = fe->ops.set_property(fe, tvp); | ||
1207 | |||
1208 | if (r < 0) | ||
1209 | return r; | ||
1210 | |||
1211 | switch(tvp->cmd) { | ||
1212 | case DTV_CLEAR: | ||
1213 | /* Reset a cache of data specific to the frontend here. This does | ||
1214 | * not effect hardware. | ||
1215 | */ | ||
1216 | printk("%s() Flushing property cache\n", __FUNCTION__); | ||
1217 | memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties)); | ||
1218 | fe->dtv_property_cache.state = tvp->cmd; | ||
1219 | fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; | ||
1220 | break; | ||
1221 | case DTV_TUNE: | ||
1222 | /* interpret the cache of data, build either a traditional frontend | ||
1223 | * tunerequest so we can pass validation in the FE_SET_FRONTEND | ||
1224 | * ioctl. | ||
1225 | */ | ||
1226 | fe->dtv_property_cache.state = tvp->cmd; | ||
1227 | printk("%s() Finalised property cache\n", __FUNCTION__); | ||
1228 | dtv_property_cache_submit(fe); | ||
1229 | |||
1230 | r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, | ||
1231 | &fepriv->parameters); | ||
1232 | break; | ||
1233 | case DTV_FREQUENCY: | ||
1234 | fe->dtv_property_cache.frequency = tvp->u.data; | ||
1235 | break; | ||
1236 | case DTV_MODULATION: | ||
1237 | fe->dtv_property_cache.modulation = tvp->u.data; | ||
1238 | break; | ||
1239 | case DTV_BANDWIDTH_HZ: | ||
1240 | fe->dtv_property_cache.bandwidth_hz = tvp->u.data; | ||
1241 | break; | ||
1242 | case DTV_INVERSION: | ||
1243 | fe->dtv_property_cache.inversion = tvp->u.data; | ||
1244 | break; | ||
1245 | case DTV_SYMBOL_RATE: | ||
1246 | fe->dtv_property_cache.symbol_rate = tvp->u.data; | ||
1247 | break; | ||
1248 | case DTV_INNER_FEC: | ||
1249 | fe->dtv_property_cache.fec_inner = tvp->u.data; | ||
1250 | break; | ||
1251 | case DTV_PILOT: | ||
1252 | fe->dtv_property_cache.pilot = tvp->u.data; | ||
1253 | break; | ||
1254 | case DTV_ROLLOFF: | ||
1255 | fe->dtv_property_cache.rolloff = tvp->u.data; | ||
1256 | break; | ||
1257 | case DTV_DELIVERY_SYSTEM: | ||
1258 | fe->dtv_property_cache.delivery_system = tvp->u.data; | ||
1259 | break; | ||
1260 | case DTV_VOLTAGE: | ||
1261 | fe->dtv_property_cache.voltage = tvp->u.data; | ||
1262 | r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE, | ||
1263 | (void *)fe->dtv_property_cache.voltage); | ||
1264 | break; | ||
1265 | case DTV_TONE: | ||
1266 | fe->dtv_property_cache.sectone = tvp->u.data; | ||
1267 | r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE, | ||
1268 | (void *)fe->dtv_property_cache.sectone); | ||
1269 | break; | ||
1270 | case DTV_CODE_RATE_HP: | ||
1271 | fe->dtv_property_cache.code_rate_HP = tvp->u.data; | ||
1272 | break; | ||
1273 | case DTV_CODE_RATE_LP: | ||
1274 | fe->dtv_property_cache.code_rate_LP = tvp->u.data; | ||
1275 | break; | ||
1276 | case DTV_GUARD_INTERVAL: | ||
1277 | fe->dtv_property_cache.guard_interval = tvp->u.data; | ||
1278 | break; | ||
1279 | case DTV_TRANSMISSION_MODE: | ||
1280 | fe->dtv_property_cache.transmission_mode = tvp->u.data; | ||
1281 | break; | ||
1282 | case DTV_HIERARCHY: | ||
1283 | fe->dtv_property_cache.hierarchy = tvp->u.data; | ||
1284 | break; | ||
1285 | default: | ||
1286 | r = -1; | ||
1287 | } | ||
1288 | |||
1289 | return r; | ||
1290 | } | ||
1291 | |||
758 | static int dvb_frontend_ioctl(struct inode *inode, struct file *file, | 1292 | static int dvb_frontend_ioctl(struct inode *inode, struct file *file, |
759 | unsigned int cmd, void *parg) | 1293 | unsigned int cmd, void *parg) |
760 | { | 1294 | { |
@@ -776,6 +1310,116 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, | |||
776 | if (down_interruptible (&fepriv->sem)) | 1310 | if (down_interruptible (&fepriv->sem)) |
777 | return -ERESTARTSYS; | 1311 | return -ERESTARTSYS; |
778 | 1312 | ||
1313 | if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) | ||
1314 | err = dvb_frontend_ioctl_properties(inode, file, cmd, parg); | ||
1315 | else { | ||
1316 | fe->dtv_property_cache.state = DTV_UNDEFINED; | ||
1317 | err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg); | ||
1318 | } | ||
1319 | |||
1320 | up(&fepriv->sem); | ||
1321 | return err; | ||
1322 | } | ||
1323 | |||
1324 | static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, | ||
1325 | unsigned int cmd, void *parg) | ||
1326 | { | ||
1327 | struct dvb_device *dvbdev = file->private_data; | ||
1328 | struct dvb_frontend *fe = dvbdev->priv; | ||
1329 | int err = 0; | ||
1330 | |||
1331 | struct dtv_properties *tvps = NULL; | ||
1332 | struct dtv_property *tvp = NULL; | ||
1333 | int i; | ||
1334 | |||
1335 | dprintk("%s\n", __func__); | ||
1336 | |||
1337 | if(cmd == FE_SET_PROPERTY) { | ||
1338 | printk("%s() FE_SET_PROPERTY\n", __FUNCTION__); | ||
1339 | |||
1340 | tvps = (struct dtv_properties __user *)parg; | ||
1341 | |||
1342 | printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num); | ||
1343 | printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props); | ||
1344 | |||
1345 | /* Put an arbitrary limit on the number of messages that can | ||
1346 | * be sent at once */ | ||
1347 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) | ||
1348 | return -EINVAL; | ||
1349 | |||
1350 | tvp = (struct dtv_property *) kmalloc(tvps->num * | ||
1351 | sizeof(struct dtv_property), GFP_KERNEL); | ||
1352 | if (!tvp) { | ||
1353 | err = -ENOMEM; | ||
1354 | goto out; | ||
1355 | } | ||
1356 | |||
1357 | if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { | ||
1358 | err = -EFAULT; | ||
1359 | goto out; | ||
1360 | } | ||
1361 | |||
1362 | for (i = 0; i < tvps->num; i++) { | ||
1363 | (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file); | ||
1364 | err |= (tvp + i)->result; | ||
1365 | } | ||
1366 | |||
1367 | if(fe->dtv_property_cache.state == DTV_TUNE) { | ||
1368 | printk("%s() Property cache is full, tuning\n", __FUNCTION__); | ||
1369 | } | ||
1370 | |||
1371 | } else | ||
1372 | if(cmd == FE_GET_PROPERTY) { | ||
1373 | printk("%s() FE_GET_PROPERTY\n", __FUNCTION__); | ||
1374 | |||
1375 | tvps = (struct dtv_properties __user *)parg; | ||
1376 | |||
1377 | printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num); | ||
1378 | printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props); | ||
1379 | |||
1380 | /* Put an arbitrary limit on the number of messages that can | ||
1381 | * be sent at once */ | ||
1382 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) | ||
1383 | return -EINVAL; | ||
1384 | |||
1385 | tvp = (struct dtv_property *) kmalloc(tvps->num * | ||
1386 | sizeof(struct dtv_property), GFP_KERNEL); | ||
1387 | if (!tvp) { | ||
1388 | err = -ENOMEM; | ||
1389 | goto out; | ||
1390 | } | ||
1391 | |||
1392 | if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { | ||
1393 | err = -EFAULT; | ||
1394 | goto out; | ||
1395 | } | ||
1396 | |||
1397 | for (i = 0; i < tvps->num; i++) { | ||
1398 | (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file); | ||
1399 | err |= (tvp + i)->result; | ||
1400 | } | ||
1401 | |||
1402 | if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { | ||
1403 | err = -EFAULT; | ||
1404 | goto out; | ||
1405 | } | ||
1406 | |||
1407 | } else | ||
1408 | err = -EOPNOTSUPP; | ||
1409 | |||
1410 | out: | ||
1411 | kfree(tvp); | ||
1412 | return err; | ||
1413 | } | ||
1414 | |||
1415 | static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, | ||
1416 | unsigned int cmd, void *parg) | ||
1417 | { | ||
1418 | struct dvb_device *dvbdev = file->private_data; | ||
1419 | struct dvb_frontend *fe = dvbdev->priv; | ||
1420 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
1421 | int err = -EOPNOTSUPP; | ||
1422 | |||
779 | switch (cmd) { | 1423 | switch (cmd) { |
780 | case FE_GET_INFO: { | 1424 | case FE_GET_INFO: { |
781 | struct dvb_frontend_info* info = parg; | 1425 | struct dvb_frontend_info* info = parg; |
@@ -942,13 +1586,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, | |||
942 | case FE_SET_FRONTEND: { | 1586 | case FE_SET_FRONTEND: { |
943 | struct dvb_frontend_tune_settings fetunesettings; | 1587 | struct dvb_frontend_tune_settings fetunesettings; |
944 | 1588 | ||
945 | if (dvb_frontend_check_parameters(fe, parg) < 0) { | 1589 | if(fe->dtv_property_cache.state == DTV_TUNE) { |
946 | err = -EINVAL; | 1590 | if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { |
947 | break; | 1591 | err = -EINVAL; |
948 | } | 1592 | break; |
1593 | } | ||
1594 | } else { | ||
1595 | if (dvb_frontend_check_parameters(fe, parg) < 0) { | ||
1596 | err = -EINVAL; | ||
1597 | break; | ||
1598 | } | ||
949 | 1599 | ||
950 | memcpy (&fepriv->parameters, parg, | 1600 | memcpy (&fepriv->parameters, parg, |
951 | sizeof (struct dvb_frontend_parameters)); | 1601 | sizeof (struct dvb_frontend_parameters)); |
1602 | dtv_property_cache_sync(fe, &fepriv->parameters); | ||
1603 | } | ||
952 | 1604 | ||
953 | memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); | 1605 | memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); |
954 | memcpy(&fetunesettings.parameters, parg, | 1606 | memcpy(&fetunesettings.parameters, parg, |
@@ -1027,10 +1679,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, | |||
1027 | break; | 1679 | break; |
1028 | }; | 1680 | }; |
1029 | 1681 | ||
1030 | up (&fepriv->sem); | ||
1031 | return err; | 1682 | return err; |
1032 | } | 1683 | } |
1033 | 1684 | ||
1685 | |||
1034 | static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) | 1686 | static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) |
1035 | { | 1687 | { |
1036 | struct dvb_device *dvbdev = file->private_data; | 1688 | struct dvb_device *dvbdev = file->private_data; |
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index aa4133f0bd19..3055301ff3ca 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h | |||
@@ -169,6 +169,9 @@ struct dvb_frontend_ops { | |||
169 | 169 | ||
170 | struct dvb_tuner_ops tuner_ops; | 170 | struct dvb_tuner_ops tuner_ops; |
171 | struct analog_demod_ops analog_ops; | 171 | struct analog_demod_ops analog_ops; |
172 | |||
173 | int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); | ||
174 | int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); | ||
172 | }; | 175 | }; |
173 | 176 | ||
174 | #define MAX_EVENT 8 | 177 | #define MAX_EVENT 8 |
@@ -182,6 +185,32 @@ struct dvb_fe_events { | |||
182 | struct mutex mtx; | 185 | struct mutex mtx; |
183 | }; | 186 | }; |
184 | 187 | ||
188 | struct dtv_frontend_properties { | ||
189 | |||
190 | /* Cache State */ | ||
191 | u32 state; | ||
192 | |||
193 | u32 frequency; | ||
194 | fe_modulation_t modulation; | ||
195 | |||
196 | fe_sec_voltage_t voltage; | ||
197 | fe_sec_tone_mode_t sectone; | ||
198 | fe_spectral_inversion_t inversion; | ||
199 | fe_code_rate_t fec_inner; | ||
200 | fe_transmit_mode_t transmission_mode; | ||
201 | u32 bandwidth_hz; /* 0 = AUTO */ | ||
202 | fe_guard_interval_t guard_interval; | ||
203 | fe_hierarchy_t hierarchy; | ||
204 | u32 symbol_rate; | ||
205 | fe_code_rate_t code_rate_HP; | ||
206 | fe_code_rate_t code_rate_LP; | ||
207 | |||
208 | fe_pilot_t pilot; | ||
209 | fe_rolloff_t rolloff; | ||
210 | |||
211 | fe_delivery_system_t delivery_system; | ||
212 | }; | ||
213 | |||
185 | struct dvb_frontend { | 214 | struct dvb_frontend { |
186 | struct dvb_frontend_ops ops; | 215 | struct dvb_frontend_ops ops; |
187 | struct dvb_adapter *dvb; | 216 | struct dvb_adapter *dvb; |
@@ -190,6 +219,9 @@ struct dvb_frontend { | |||
190 | void *frontend_priv; | 219 | void *frontend_priv; |
191 | void *sec_priv; | 220 | void *sec_priv; |
192 | void *analog_demod_priv; | 221 | void *analog_demod_priv; |
222 | struct dtv_frontend_properties dtv_property_cache; | ||
223 | #define DVB_FRONTEND_COMPONENT_TUNER 0 | ||
224 | int (*callback)(void *adapter_priv, int component, int cmd, int arg); | ||
193 | }; | 225 | }; |
194 | 226 | ||
195 | extern int dvb_register_frontend(struct dvb_adapter *dvb, | 227 | extern int dvb_register_frontend(struct dvb_adapter *dvb, |
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e84152b7576d..3c13bcfa6385 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig | |||
@@ -72,9 +72,11 @@ config DVB_USB_DIB0700 | |||
72 | select DVB_DIB7000P | 72 | select DVB_DIB7000P |
73 | select DVB_DIB7000M | 73 | select DVB_DIB7000M |
74 | select DVB_DIB3000MC | 74 | select DVB_DIB3000MC |
75 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE | ||
75 | select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE | 76 | select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE |
76 | select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE | 77 | select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE |
77 | select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE | 78 | select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE |
79 | select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE | ||
78 | select DVB_TUNER_DIB0070 | 80 | select DVB_TUNER_DIB0070 |
79 | help | 81 | help |
80 | Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The | 82 | Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The |
@@ -108,6 +110,8 @@ config DVB_USB_CXUSB | |||
108 | select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE | 110 | select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE |
109 | select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE | 111 | select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE |
110 | select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE | 112 | select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE |
113 | select DVB_DIB7000P if !DVB_FE_CUSTOMISE | ||
114 | select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE | ||
111 | help | 115 | help |
112 | Say Y here to support the Conexant USB2.0 hybrid reference design. | 116 | Say Y here to support the Conexant USB2.0 hybrid reference design. |
113 | Currently, only DVB and ATSC modes are supported, analog mode | 117 | Currently, only DVB and ATSC modes are supported, analog mode |
@@ -245,12 +249,25 @@ config DVB_USB_AF9005_REMOTE | |||
245 | Afatech AF9005 based receiver. | 249 | Afatech AF9005 based receiver. |
246 | 250 | ||
247 | config DVB_USB_DW2102 | 251 | config DVB_USB_DW2102 |
248 | tristate "DvbWorld 2102 DVB-S USB2.0 receiver" | 252 | tristate "DvbWorld DVB-S/S2 USB2.0 support" |
249 | depends on DVB_USB | 253 | depends on DVB_USB |
250 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | ||
251 | select DVB_PLL if !DVB_FE_CUSTOMISE | 254 | select DVB_PLL if !DVB_FE_CUSTOMISE |
255 | select DVB_STV0299 if !DVB_FE_CUSTOMISE | ||
256 | select DVB_STV0288 if !DVB_FE_CUSTOMISE | ||
257 | select DVB_STB6000 if !DVB_FE_CUSTOMISE | ||
258 | select DVB_CX24116 if !DVB_FE_CUSTOMISE | ||
259 | select DVB_SI21XX if !DVB_FE_CUSTOMISE | ||
252 | help | 260 | help |
253 | Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver. | 261 | Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers |
262 | and the TeVii S650. | ||
263 | |||
264 | config DVB_USB_CINERGY_T2 | ||
265 | tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" | ||
266 | depends on DVB_USB | ||
267 | help | ||
268 | Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers | ||
269 | |||
270 | Say Y if you own such a device and want to use it. | ||
254 | 271 | ||
255 | config DVB_USB_ANYSEE | 272 | config DVB_USB_ANYSEE |
256 | tristate "Anysee DVB-T/C USB2.0 support" | 273 | tristate "Anysee DVB-T/C USB2.0 support" |
@@ -262,3 +279,22 @@ config DVB_USB_ANYSEE | |||
262 | help | 279 | help |
263 | Say Y here to support the Anysee E30, Anysee E30 Plus or | 280 | Say Y here to support the Anysee E30, Anysee E30 Plus or |
264 | Anysee E30 C Plus DVB USB2.0 receiver. | 281 | Anysee E30 C Plus DVB USB2.0 receiver. |
282 | |||
283 | config DVB_USB_DTV5100 | ||
284 | tristate "AME DTV-5100 USB2.0 DVB-T support" | ||
285 | depends on DVB_USB | ||
286 | select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE | ||
287 | help | ||
288 | Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. | ||
289 | |||
290 | config DVB_USB_AF9015 | ||
291 | tristate "Afatech AF9015 DVB-T USB2.0 support" | ||
292 | depends on DVB_USB && EXPERIMENTAL | ||
293 | select DVB_AF9013 | ||
294 | select DVB_PLL if !DVB_FE_CUSTOMISE | ||
295 | select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE | ||
296 | select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE | ||
297 | select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE | ||
298 | select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE | ||
299 | help | ||
300 | Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver | ||
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index e206f1ea0027..3122b7cc2c23 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
@@ -67,6 +67,16 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o | |||
67 | dvb-usb-dw2102-objs = dw2102.o | 67 | dvb-usb-dw2102-objs = dw2102.o |
68 | obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o | 68 | obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o |
69 | 69 | ||
70 | dvb-usb-dtv5100-objs = dtv5100.o | ||
71 | obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o | ||
72 | |||
73 | dvb-usb-af9015-objs = af9015.o | ||
74 | obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o | ||
75 | |||
76 | dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o | ||
77 | obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o | ||
78 | |||
79 | |||
70 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 80 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
71 | # due to tuner-xc3028 | 81 | # due to tuner-xc3028 |
72 | EXTRA_CFLAGS += -Idrivers/media/common/tuners | 82 | EXTRA_CFLAGS += -Idrivers/media/common/tuners |
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c index ff00c0e8f4a1..7c596f926764 100644 --- a/drivers/media/dvb/dvb-usb/af9005-remote.c +++ b/drivers/media/dvb/dvb-usb/af9005-remote.c | |||
@@ -25,7 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | #include "af9005.h" | 26 | #include "af9005.h" |
27 | /* debug */ | 27 | /* debug */ |
28 | int dvb_usb_af9005_remote_debug; | 28 | static int dvb_usb_af9005_remote_debug; |
29 | module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); | 29 | module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); |
30 | MODULE_PARM_DESC(debug, | 30 | MODULE_PARM_DESC(debug, |
31 | "enable (1) or disable (0) debug messages." | 31 | "enable (1) or disable (0) debug messages." |
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h index 6eeaae51b1ca..4d69045426dd 100644 --- a/drivers/media/dvb/dvb-usb/af9005-script.h +++ b/drivers/media/dvb/dvb-usb/af9005-script.h | |||
@@ -14,7 +14,7 @@ typedef struct { | |||
14 | u8 val; | 14 | u8 val; |
15 | } RegDesc; | 15 | } RegDesc; |
16 | 16 | ||
17 | RegDesc script[] = { | 17 | static RegDesc script[] = { |
18 | {0xa180, 0x0, 0x8, 0xa}, | 18 | {0xa180, 0x0, 0x8, 0xa}, |
19 | {0xa181, 0x0, 0x8, 0xd7}, | 19 | {0xa181, 0x0, 0x8, 0xd7}, |
20 | {0xa182, 0x0, 0x8, 0xa3}, | 20 | {0xa182, 0x0, 0x8, 0xa3}, |
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index cfe71feefcad..ca5a0a4d2a47 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c | |||
@@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644); | |||
35 | MODULE_PARM_DESC(led, "enable led (default: 1)."); | 35 | MODULE_PARM_DESC(led, "enable led (default: 1)."); |
36 | 36 | ||
37 | /* eeprom dump */ | 37 | /* eeprom dump */ |
38 | int dvb_usb_af9005_dump_eeprom = 0; | 38 | static int dvb_usb_af9005_dump_eeprom; |
39 | module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); | 39 | module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); |
40 | MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); | 40 | MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); |
41 | 41 | ||
42 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 42 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
43 | 43 | ||
44 | /* remote control decoder */ | 44 | /* remote control decoder */ |
45 | int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event, | 45 | static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, |
46 | int *state); | 46 | u32 *event, int *state); |
47 | void *rc_keys; | 47 | static void *rc_keys; |
48 | int *rc_keys_size; | 48 | static int *rc_keys_size; |
49 | 49 | ||
50 | u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; | 50 | u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; |
51 | 51 | ||
@@ -54,8 +54,8 @@ struct af9005_device_state { | |||
54 | int led_state; | 54 | int led_state; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, | 57 | static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, |
58 | u8 * rbuf, u16 rlen, int delay_ms) | 58 | u8 *rbuf, u16 rlen, int delay_ms) |
59 | { | 59 | { |
60 | int actlen, ret = -ENOMEM; | 60 | int actlen, ret = -ENOMEM; |
61 | 61 | ||
@@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, | |||
98 | return ret; | 98 | return ret; |
99 | } | 99 | } |
100 | 100 | ||
101 | int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len) | 101 | static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, |
102 | { | ||
103 | return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0); | ||
104 | } | ||
105 | |||
106 | int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, | ||
107 | int readwrite, int type, u8 * values, int len) | 102 | int readwrite, int type, u8 * values, int len) |
108 | { | 103 | { |
109 | struct af9005_device_state *st = d->priv; | 104 | struct af9005_device_state *st = d->priv; |
@@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) | |||
765 | return 0; | 760 | return 0; |
766 | } | 761 | } |
767 | 762 | ||
768 | int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) | 763 | static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) |
769 | { | 764 | { |
770 | int i, packets, ret, act_len; | 765 | int i, packets, ret, act_len; |
771 | 766 | ||
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c new file mode 100644 index 000000000000..cb0829c038ce --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9015.c | |||
@@ -0,0 +1,1474 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "af9015.h" | ||
25 | #include "af9013.h" | ||
26 | #include "mt2060.h" | ||
27 | #include "qt1010.h" | ||
28 | #include "tda18271.h" | ||
29 | #include "mxl5005s.h" | ||
30 | #if 0 | ||
31 | #include "mc44s80x.h" | ||
32 | #endif | ||
33 | |||
34 | int dvb_usb_af9015_debug; | ||
35 | module_param_named(debug, dvb_usb_af9015_debug, int, 0644); | ||
36 | MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); | ||
37 | int dvb_usb_af9015_remote; | ||
38 | module_param_named(remote, dvb_usb_af9015_remote, int, 0644); | ||
39 | MODULE_PARM_DESC(remote, "select remote"); | ||
40 | int dvb_usb_af9015_dual_mode; | ||
41 | module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644); | ||
42 | MODULE_PARM_DESC(dual_mode, "enable dual mode"); | ||
43 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
44 | |||
45 | static DEFINE_MUTEX(af9015_usb_mutex); | ||
46 | |||
47 | static struct af9015_config af9015_config; | ||
48 | static struct dvb_usb_device_properties af9015_properties[2]; | ||
49 | int af9015_properties_count = ARRAY_SIZE(af9015_properties); | ||
50 | |||
51 | static struct af9013_config af9015_af9013_config[] = { | ||
52 | { | ||
53 | .demod_address = AF9015_I2C_DEMOD, | ||
54 | .output_mode = AF9013_OUTPUT_MODE_USB, | ||
55 | .api_version = { 0, 1, 9, 0 }, | ||
56 | .gpio[0] = AF9013_GPIO_HI, | ||
57 | .gpio[3] = AF9013_GPIO_TUNER_ON, | ||
58 | |||
59 | }, { | ||
60 | .output_mode = AF9013_OUTPUT_MODE_SERIAL, | ||
61 | .api_version = { 0, 1, 9, 0 }, | ||
62 | .gpio[0] = AF9013_GPIO_TUNER_ON, | ||
63 | .gpio[1] = AF9013_GPIO_LO, | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) | ||
68 | { | ||
69 | int act_len, ret; | ||
70 | u8 buf[64]; | ||
71 | u8 write = 1; | ||
72 | u8 msg_len = 8; | ||
73 | static u8 seq; /* packet sequence number */ | ||
74 | |||
75 | if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) | ||
76 | return -EAGAIN; | ||
77 | |||
78 | buf[0] = req->cmd; | ||
79 | buf[1] = seq++; | ||
80 | buf[2] = req->i2c_addr; | ||
81 | buf[3] = req->addr >> 8; | ||
82 | buf[4] = req->addr & 0xff; | ||
83 | buf[5] = req->mbox; | ||
84 | buf[6] = req->addr_len; | ||
85 | buf[7] = req->data_len; | ||
86 | |||
87 | switch (req->cmd) { | ||
88 | case GET_CONFIG: | ||
89 | case BOOT: | ||
90 | case READ_MEMORY: | ||
91 | case RECONNECT_USB: | ||
92 | case GET_IR_CODE: | ||
93 | write = 0; | ||
94 | break; | ||
95 | case READ_I2C: | ||
96 | write = 0; | ||
97 | buf[2] |= 0x01; /* set I2C direction */ | ||
98 | case WRITE_I2C: | ||
99 | buf[0] = READ_WRITE_I2C; | ||
100 | break; | ||
101 | case WRITE_MEMORY: | ||
102 | if (((req->addr & 0xff00) == 0xff00) || | ||
103 | ((req->addr & 0xae00) == 0xae00)) | ||
104 | buf[0] = WRITE_VIRTUAL_MEMORY; | ||
105 | case WRITE_VIRTUAL_MEMORY: | ||
106 | case COPY_FIRMWARE: | ||
107 | case DOWNLOAD_FIRMWARE: | ||
108 | break; | ||
109 | default: | ||
110 | err("unknown command:%d", req->cmd); | ||
111 | ret = -1; | ||
112 | goto error_unlock; | ||
113 | } | ||
114 | |||
115 | /* write requested */ | ||
116 | if (write) { | ||
117 | memcpy(&buf[8], req->data, req->data_len); | ||
118 | msg_len += req->data_len; | ||
119 | } | ||
120 | deb_xfer(">>> "); | ||
121 | debug_dump(buf, msg_len, deb_xfer); | ||
122 | |||
123 | /* send req */ | ||
124 | ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, | ||
125 | &act_len, AF9015_USB_TIMEOUT); | ||
126 | if (ret) | ||
127 | err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); | ||
128 | else | ||
129 | if (act_len != msg_len) | ||
130 | ret = -1; /* all data is not send */ | ||
131 | if (ret) | ||
132 | goto error_unlock; | ||
133 | |||
134 | /* no ack for those packets */ | ||
135 | if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) | ||
136 | goto exit_unlock; | ||
137 | |||
138 | /* receive ack and data if read req */ | ||
139 | msg_len = 1 + 1 + req->data_len; /* seq + status + data len */ | ||
140 | ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, | ||
141 | &act_len, AF9015_USB_TIMEOUT); | ||
142 | if (ret) { | ||
143 | err("recv bulk message failed:%d", ret); | ||
144 | ret = -1; | ||
145 | goto error_unlock; | ||
146 | } | ||
147 | |||
148 | deb_xfer("<<< "); | ||
149 | debug_dump(buf, act_len, deb_xfer); | ||
150 | |||
151 | /* remote controller query status is 1 if remote code is not received */ | ||
152 | if (req->cmd == GET_IR_CODE && buf[1] == 1) { | ||
153 | buf[1] = 0; /* clear command "error" status */ | ||
154 | memset(&buf[2], 0, req->data_len); | ||
155 | buf[3] = 1; /* no remote code received mark */ | ||
156 | } | ||
157 | |||
158 | /* check status */ | ||
159 | if (buf[1]) { | ||
160 | err("command failed:%d", buf[1]); | ||
161 | ret = -1; | ||
162 | goto error_unlock; | ||
163 | } | ||
164 | |||
165 | /* read request, copy returned data to return buf */ | ||
166 | if (!write) | ||
167 | memcpy(req->data, &buf[2], req->data_len); | ||
168 | |||
169 | error_unlock: | ||
170 | exit_unlock: | ||
171 | mutex_unlock(&af9015_usb_mutex); | ||
172 | |||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) | ||
177 | { | ||
178 | return af9015_rw_udev(d->udev, req); | ||
179 | } | ||
180 | |||
181 | static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, | ||
182 | u8 len) | ||
183 | { | ||
184 | struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, | ||
185 | val}; | ||
186 | return af9015_ctrl_msg(d, &req); | ||
187 | } | ||
188 | |||
189 | static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) | ||
190 | { | ||
191 | return af9015_write_regs(d, addr, &val, 1); | ||
192 | } | ||
193 | |||
194 | static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) | ||
195 | { | ||
196 | struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val}; | ||
197 | return af9015_ctrl_msg(d, &req); | ||
198 | } | ||
199 | |||
200 | static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, | ||
201 | u8 val) | ||
202 | { | ||
203 | struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; | ||
204 | |||
205 | if (addr == af9015_af9013_config[0].demod_address || | ||
206 | addr == af9015_af9013_config[1].demod_address) | ||
207 | req.addr_len = 3; | ||
208 | |||
209 | return af9015_ctrl_msg(d, &req); | ||
210 | } | ||
211 | |||
212 | static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, | ||
213 | u8 *val) | ||
214 | { | ||
215 | struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; | ||
216 | |||
217 | if (addr == af9015_af9013_config[0].demod_address || | ||
218 | addr == af9015_af9013_config[1].demod_address) | ||
219 | req.addr_len = 3; | ||
220 | |||
221 | return af9015_ctrl_msg(d, &req); | ||
222 | } | ||
223 | |||
224 | static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
225 | int num) | ||
226 | { | ||
227 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
228 | int ret = 0, i = 0; | ||
229 | u16 addr; | ||
230 | u8 mbox, addr_len; | ||
231 | struct req_t req; | ||
232 | |||
233 | /* TODO: implement bus lock | ||
234 | |||
235 | The bus lock is needed because there is two tuners both using same I2C-address. | ||
236 | Due to that the only way to select correct tuner is use demodulator I2C-gate. | ||
237 | |||
238 | ................................................ | ||
239 | . AF9015 includes integrated AF9013 demodulator. | ||
240 | . ____________ ____________ . ____________ | ||
241 | .| uC | | demod | . | tuner | | ||
242 | .|------------| |------------| . |------------| | ||
243 | .| AF9015 | | AF9013/5 | . | MXL5003 | | ||
244 | .| |--+----I2C-------|-----/ -----|-.-----I2C-------| | | ||
245 | .| | | | addr 0x38 | . | addr 0xc6 | | ||
246 | .|____________| | |____________| . |____________| | ||
247 | .................|.............................. | ||
248 | | ____________ ____________ | ||
249 | | | demod | | tuner | | ||
250 | | |------------| |------------| | ||
251 | | | AF9013 | | MXL5003 | | ||
252 | +----I2C-------|-----/ -----|-------I2C-------| | | ||
253 | | addr 0x3a | | addr 0xc6 | | ||
254 | |____________| |____________| | ||
255 | */ | ||
256 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
257 | return -EAGAIN; | ||
258 | |||
259 | while (i < num) { | ||
260 | if (msg[i].addr == af9015_af9013_config[0].demod_address || | ||
261 | msg[i].addr == af9015_af9013_config[1].demod_address) { | ||
262 | addr = msg[i].buf[0] << 8; | ||
263 | addr += msg[i].buf[1]; | ||
264 | mbox = msg[i].buf[2]; | ||
265 | addr_len = 3; | ||
266 | } else { | ||
267 | addr = msg[i].buf[0]; | ||
268 | addr_len = 1; | ||
269 | mbox = 0; | ||
270 | } | ||
271 | |||
272 | if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { | ||
273 | if (msg[i].addr == | ||
274 | af9015_af9013_config[0].demod_address) | ||
275 | req.cmd = READ_MEMORY; | ||
276 | else | ||
277 | req.cmd = READ_I2C; | ||
278 | req.i2c_addr = msg[i].addr; | ||
279 | req.addr = addr; | ||
280 | req.mbox = mbox; | ||
281 | req.addr_len = addr_len; | ||
282 | req.data_len = msg[i+1].len; | ||
283 | req.data = &msg[i+1].buf[0]; | ||
284 | ret = af9015_ctrl_msg(d, &req); | ||
285 | i += 2; | ||
286 | } else { | ||
287 | if (msg[i].addr == | ||
288 | af9015_af9013_config[0].demod_address) | ||
289 | req.cmd = WRITE_MEMORY; | ||
290 | else | ||
291 | req.cmd = WRITE_I2C; | ||
292 | req.i2c_addr = msg[i].addr; | ||
293 | req.addr = addr; | ||
294 | req.mbox = mbox; | ||
295 | req.addr_len = addr_len; | ||
296 | req.data_len = msg[i].len-addr_len; | ||
297 | req.data = &msg[i].buf[addr_len]; | ||
298 | ret = af9015_ctrl_msg(d, &req); | ||
299 | i += 1; | ||
300 | } | ||
301 | if (ret) | ||
302 | goto error; | ||
303 | |||
304 | } | ||
305 | ret = i; | ||
306 | |||
307 | error: | ||
308 | mutex_unlock(&d->i2c_mutex); | ||
309 | |||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static u32 af9015_i2c_func(struct i2c_adapter *adapter) | ||
314 | { | ||
315 | return I2C_FUNC_I2C; | ||
316 | } | ||
317 | |||
318 | static struct i2c_algorithm af9015_i2c_algo = { | ||
319 | .master_xfer = af9015_i2c_xfer, | ||
320 | .functionality = af9015_i2c_func, | ||
321 | }; | ||
322 | |||
323 | static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) | ||
324 | { | ||
325 | int ret; | ||
326 | u8 val, mask = 0x01; | ||
327 | |||
328 | ret = af9015_read_reg(d, addr, &val); | ||
329 | if (ret) | ||
330 | return ret; | ||
331 | |||
332 | mask <<= bit; | ||
333 | if (op) { | ||
334 | /* set bit */ | ||
335 | val |= mask; | ||
336 | } else { | ||
337 | /* clear bit */ | ||
338 | mask ^= 0xff; | ||
339 | val &= mask; | ||
340 | } | ||
341 | |||
342 | return af9015_write_reg(d, addr, val); | ||
343 | } | ||
344 | |||
345 | static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) | ||
346 | { | ||
347 | return af9015_do_reg_bit(d, addr, bit, 1); | ||
348 | } | ||
349 | |||
350 | static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) | ||
351 | { | ||
352 | return af9015_do_reg_bit(d, addr, bit, 0); | ||
353 | } | ||
354 | |||
355 | static int af9015_init_endpoint(struct dvb_usb_device *d) | ||
356 | { | ||
357 | int ret; | ||
358 | u16 frame_size; | ||
359 | u8 packet_size; | ||
360 | deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); | ||
361 | |||
362 | #define TS_PACKET_SIZE 188 | ||
363 | |||
364 | #define TS_USB20_PACKET_COUNT 348 | ||
365 | #define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) | ||
366 | |||
367 | #define TS_USB11_PACKET_COUNT 21 | ||
368 | #define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) | ||
369 | |||
370 | #define TS_USB20_MAX_PACKET_SIZE 512 | ||
371 | #define TS_USB11_MAX_PACKET_SIZE 64 | ||
372 | |||
373 | if (d->udev->speed == USB_SPEED_FULL) { | ||
374 | frame_size = TS_USB11_FRAME_SIZE/4; | ||
375 | packet_size = TS_USB11_MAX_PACKET_SIZE/4; | ||
376 | } else { | ||
377 | frame_size = TS_USB20_FRAME_SIZE/4; | ||
378 | packet_size = TS_USB20_MAX_PACKET_SIZE/4; | ||
379 | } | ||
380 | |||
381 | ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ | ||
382 | if (ret) | ||
383 | goto error; | ||
384 | ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ | ||
385 | if (ret) | ||
386 | goto error; | ||
387 | ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ | ||
388 | if (ret) | ||
389 | goto error; | ||
390 | ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ | ||
391 | if (ret) | ||
392 | goto error; | ||
393 | ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ | ||
394 | if (ret) | ||
395 | goto error; | ||
396 | if (af9015_config.dual_mode) { | ||
397 | ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ | ||
398 | if (ret) | ||
399 | goto error; | ||
400 | } | ||
401 | ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ | ||
402 | if (ret) | ||
403 | goto error; | ||
404 | if (af9015_config.dual_mode) { | ||
405 | ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ | ||
406 | if (ret) | ||
407 | goto error; | ||
408 | } | ||
409 | /* EP4 xfer length */ | ||
410 | ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); | ||
411 | if (ret) | ||
412 | goto error; | ||
413 | ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); | ||
414 | if (ret) | ||
415 | goto error; | ||
416 | /* EP5 xfer length */ | ||
417 | ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); | ||
418 | if (ret) | ||
419 | goto error; | ||
420 | ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); | ||
421 | if (ret) | ||
422 | goto error; | ||
423 | ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ | ||
424 | if (ret) | ||
425 | goto error; | ||
426 | ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ | ||
427 | if (ret) | ||
428 | goto error; | ||
429 | ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ | ||
430 | if (ret) | ||
431 | goto error; | ||
432 | if (af9015_config.dual_mode) { | ||
433 | ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ | ||
434 | if (ret) | ||
435 | goto error; | ||
436 | } | ||
437 | |||
438 | /* enable / disable mp2if2 */ | ||
439 | if (af9015_config.dual_mode) | ||
440 | ret = af9015_set_reg_bit(d, 0xd50b, 0); | ||
441 | else | ||
442 | ret = af9015_clear_reg_bit(d, 0xd50b, 0); | ||
443 | error: | ||
444 | if (ret) | ||
445 | err("endpoint init failed:%d", ret); | ||
446 | return ret; | ||
447 | } | ||
448 | |||
449 | static int af9015_copy_firmware(struct dvb_usb_device *d) | ||
450 | { | ||
451 | int ret; | ||
452 | u8 fw_params[4]; | ||
453 | u8 val, i; | ||
454 | struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), | ||
455 | fw_params }; | ||
456 | deb_info("%s:\n", __func__); | ||
457 | |||
458 | fw_params[0] = af9015_config.firmware_size >> 8; | ||
459 | fw_params[1] = af9015_config.firmware_size & 0xff; | ||
460 | fw_params[2] = af9015_config.firmware_checksum >> 8; | ||
461 | fw_params[3] = af9015_config.firmware_checksum & 0xff; | ||
462 | |||
463 | /* wait 2nd demodulator ready */ | ||
464 | msleep(100); | ||
465 | |||
466 | ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val); | ||
467 | if (ret) | ||
468 | goto error; | ||
469 | else | ||
470 | deb_info("%s: firmware status:%02x\n", __func__, val); | ||
471 | |||
472 | if (val == 0x0c) /* fw is running, no need for download */ | ||
473 | goto exit; | ||
474 | |||
475 | /* set I2C master clock to fast (to speed up firmware copy) */ | ||
476 | ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ | ||
477 | if (ret) | ||
478 | goto error; | ||
479 | |||
480 | msleep(50); | ||
481 | |||
482 | /* copy firmware */ | ||
483 | ret = af9015_ctrl_msg(d, &req); | ||
484 | if (ret) | ||
485 | err("firmware copy cmd failed:%d", ret); | ||
486 | deb_info("%s: firmware copy done\n", __func__); | ||
487 | |||
488 | /* set I2C master clock back to normal */ | ||
489 | ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ | ||
490 | if (ret) | ||
491 | goto error; | ||
492 | |||
493 | /* request boot firmware */ | ||
494 | ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, | ||
495 | 0xe205, 1); | ||
496 | deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); | ||
497 | if (ret) | ||
498 | goto error; | ||
499 | |||
500 | for (i = 0; i < 15; i++) { | ||
501 | msleep(100); | ||
502 | |||
503 | /* check firmware status */ | ||
504 | ret = af9015_read_reg_i2c(d, | ||
505 | af9015_af9013_config[1].demod_address, 0x98be, &val); | ||
506 | deb_info("%s: firmware status cmd status:%d fw status:%02x\n", | ||
507 | __func__, ret, val); | ||
508 | if (ret) | ||
509 | goto error; | ||
510 | |||
511 | if (val == 0x0c || val == 0x04) /* success or fail */ | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | if (val == 0x04) { | ||
516 | err("firmware did not run"); | ||
517 | ret = -1; | ||
518 | } else if (val != 0x0c) { | ||
519 | err("firmware boot timeout"); | ||
520 | ret = -1; | ||
521 | } | ||
522 | |||
523 | error: | ||
524 | exit: | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | /* dump eeprom */ | ||
529 | static int af9015_eeprom_dump(struct dvb_usb_device *d) | ||
530 | { | ||
531 | char buf[52], buf2[4]; | ||
532 | u8 reg, val; | ||
533 | |||
534 | for (reg = 0; ; reg++) { | ||
535 | if (reg % 16 == 0) { | ||
536 | if (reg) | ||
537 | deb_info("%s\n", buf); | ||
538 | sprintf(buf, "%02x: ", reg); | ||
539 | } | ||
540 | if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0) | ||
541 | sprintf(buf2, "%02x ", val); | ||
542 | else | ||
543 | strcpy(buf2, "-- "); | ||
544 | strcat(buf, buf2); | ||
545 | if (reg == 0xff) | ||
546 | break; | ||
547 | } | ||
548 | deb_info("%s\n", buf); | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | int af9015_download_ir_table(struct dvb_usb_device *d) | ||
553 | { | ||
554 | int i, packets = 0, ret; | ||
555 | u16 addr = 0x9a56; /* ir-table start address */ | ||
556 | struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL}; | ||
557 | u8 *data = NULL; | ||
558 | deb_info("%s:\n", __func__); | ||
559 | |||
560 | data = af9015_config.ir_table; | ||
561 | packets = af9015_config.ir_table_size; | ||
562 | |||
563 | /* no remote */ | ||
564 | if (!packets) | ||
565 | goto exit; | ||
566 | |||
567 | /* load remote ir-table */ | ||
568 | for (i = 0; i < packets; i++) { | ||
569 | req.addr = addr + i; | ||
570 | req.data = &data[i]; | ||
571 | ret = af9015_ctrl_msg(d, &req); | ||
572 | if (ret) { | ||
573 | err("ir-table download failed at packet %d with " \ | ||
574 | "code %d", i, ret); | ||
575 | return ret; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | exit: | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int af9015_init(struct dvb_usb_device *d) | ||
584 | { | ||
585 | int ret; | ||
586 | deb_info("%s:\n", __func__); | ||
587 | |||
588 | ret = af9015_init_endpoint(d); | ||
589 | if (ret) | ||
590 | goto error; | ||
591 | |||
592 | ret = af9015_download_ir_table(d); | ||
593 | if (ret) | ||
594 | goto error; | ||
595 | |||
596 | error: | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
601 | { | ||
602 | int ret; | ||
603 | deb_info("%s: onoff:%d\n", __func__, onoff); | ||
604 | |||
605 | if (onoff) | ||
606 | ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); | ||
607 | else | ||
608 | ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); | ||
609 | |||
610 | return ret; | ||
611 | } | ||
612 | |||
613 | static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, | ||
614 | int onoff) | ||
615 | { | ||
616 | int ret; | ||
617 | u8 idx; | ||
618 | |||
619 | deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", | ||
620 | __func__, index, pid, onoff); | ||
621 | |||
622 | ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); | ||
623 | if (ret) | ||
624 | goto error; | ||
625 | |||
626 | ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); | ||
627 | if (ret) | ||
628 | goto error; | ||
629 | |||
630 | idx = ((index & 0x1f) | (1 << 5)); | ||
631 | ret = af9015_write_reg(adap->dev, 0xd504, idx); | ||
632 | |||
633 | error: | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | static int af9015_download_firmware(struct usb_device *udev, | ||
638 | const struct firmware *fw) | ||
639 | { | ||
640 | int i, len, packets, remainder, ret; | ||
641 | struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; | ||
642 | u16 addr = 0x5100; /* firmware start address */ | ||
643 | u16 checksum = 0; | ||
644 | |||
645 | deb_info("%s:\n", __func__); | ||
646 | |||
647 | /* calc checksum */ | ||
648 | for (i = 0; i < fw->size; i++) | ||
649 | checksum += fw->data[i]; | ||
650 | |||
651 | af9015_config.firmware_size = fw->size; | ||
652 | af9015_config.firmware_checksum = checksum; | ||
653 | |||
654 | #define FW_PACKET_MAX_DATA 55 | ||
655 | |||
656 | packets = fw->size / FW_PACKET_MAX_DATA; | ||
657 | remainder = fw->size % FW_PACKET_MAX_DATA; | ||
658 | len = FW_PACKET_MAX_DATA; | ||
659 | for (i = 0; i <= packets; i++) { | ||
660 | if (i == packets) /* set size of the last packet */ | ||
661 | len = remainder; | ||
662 | |||
663 | req.data_len = len; | ||
664 | req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); | ||
665 | req.addr = addr; | ||
666 | addr += FW_PACKET_MAX_DATA; | ||
667 | |||
668 | ret = af9015_rw_udev(udev, &req); | ||
669 | if (ret) { | ||
670 | err("firmware download failed at packet %d with " \ | ||
671 | "code %d", i, ret); | ||
672 | goto error; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /* firmware loaded, request boot */ | ||
677 | req.cmd = BOOT; | ||
678 | ret = af9015_rw_udev(udev, &req); | ||
679 | if (ret) { | ||
680 | err("firmware boot failed:%d", ret); | ||
681 | goto error; | ||
682 | } | ||
683 | |||
684 | /* firmware is running, reconnect device in the usb bus */ | ||
685 | req.cmd = RECONNECT_USB; | ||
686 | ret = af9015_rw_udev(udev, &req); | ||
687 | if (ret) | ||
688 | err("reconnect failed: %d", ret); | ||
689 | |||
690 | error: | ||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | static int af9015_read_config(struct usb_device *udev) | ||
695 | { | ||
696 | int ret; | ||
697 | u8 val, i, offset = 0; | ||
698 | struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; | ||
699 | char manufacturer[10]; | ||
700 | |||
701 | /* IR remote controller */ | ||
702 | req.addr = AF9015_EEPROM_IR_MODE; | ||
703 | ret = af9015_rw_udev(udev, &req); | ||
704 | if (ret) | ||
705 | goto error; | ||
706 | deb_info("%s: IR mode:%d\n", __func__, val); | ||
707 | for (i = 0; i < af9015_properties_count; i++) { | ||
708 | if (val == AF9015_IR_MODE_DISABLED || val == 0x04) { | ||
709 | af9015_properties[i].rc_key_map = NULL; | ||
710 | af9015_properties[i].rc_key_map_size = 0; | ||
711 | } else if (dvb_usb_af9015_remote) { | ||
712 | /* load remote defined as module param */ | ||
713 | switch (dvb_usb_af9015_remote) { | ||
714 | case AF9015_REMOTE_A_LINK_DTU_M: | ||
715 | af9015_properties[i].rc_key_map = | ||
716 | af9015_rc_keys_a_link; | ||
717 | af9015_properties[i].rc_key_map_size = | ||
718 | ARRAY_SIZE(af9015_rc_keys_a_link); | ||
719 | af9015_config.ir_table = af9015_ir_table_a_link; | ||
720 | af9015_config.ir_table_size = | ||
721 | ARRAY_SIZE(af9015_ir_table_a_link); | ||
722 | break; | ||
723 | case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3: | ||
724 | af9015_properties[i].rc_key_map = | ||
725 | af9015_rc_keys_msi; | ||
726 | af9015_properties[i].rc_key_map_size = | ||
727 | ARRAY_SIZE(af9015_rc_keys_msi); | ||
728 | af9015_config.ir_table = af9015_ir_table_msi; | ||
729 | af9015_config.ir_table_size = | ||
730 | ARRAY_SIZE(af9015_ir_table_msi); | ||
731 | break; | ||
732 | case AF9015_REMOTE_MYGICTV_U718: | ||
733 | af9015_properties[i].rc_key_map = | ||
734 | af9015_rc_keys_mygictv; | ||
735 | af9015_properties[i].rc_key_map_size = | ||
736 | ARRAY_SIZE(af9015_rc_keys_mygictv); | ||
737 | af9015_config.ir_table = | ||
738 | af9015_ir_table_mygictv; | ||
739 | af9015_config.ir_table_size = | ||
740 | ARRAY_SIZE(af9015_ir_table_mygictv); | ||
741 | break; | ||
742 | } | ||
743 | } else { | ||
744 | switch (udev->descriptor.idVendor) { | ||
745 | case USB_VID_LEADTEK: | ||
746 | af9015_properties[i].rc_key_map = | ||
747 | af9015_rc_keys_leadtek; | ||
748 | af9015_properties[i].rc_key_map_size = | ||
749 | ARRAY_SIZE(af9015_rc_keys_leadtek); | ||
750 | af9015_config.ir_table = | ||
751 | af9015_ir_table_leadtek; | ||
752 | af9015_config.ir_table_size = | ||
753 | ARRAY_SIZE(af9015_ir_table_leadtek); | ||
754 | break; | ||
755 | case USB_VID_VISIONPLUS: | ||
756 | if (udev->descriptor.idProduct == | ||
757 | USB_PID_AZUREWAVE_AD_TU700) { | ||
758 | af9015_properties[i].rc_key_map = | ||
759 | af9015_rc_keys_twinhan; | ||
760 | af9015_properties[i].rc_key_map_size = | ||
761 | ARRAY_SIZE(af9015_rc_keys_twinhan); | ||
762 | af9015_config.ir_table = | ||
763 | af9015_ir_table_twinhan; | ||
764 | af9015_config.ir_table_size = | ||
765 | ARRAY_SIZE(af9015_ir_table_twinhan); | ||
766 | } | ||
767 | break; | ||
768 | case USB_VID_KWORLD_2: | ||
769 | /* TODO: use correct rc keys */ | ||
770 | af9015_properties[i].rc_key_map = | ||
771 | af9015_rc_keys_twinhan; | ||
772 | af9015_properties[i].rc_key_map_size = | ||
773 | ARRAY_SIZE(af9015_rc_keys_twinhan); | ||
774 | af9015_config.ir_table = af9015_ir_table_kworld; | ||
775 | af9015_config.ir_table_size = | ||
776 | ARRAY_SIZE(af9015_ir_table_kworld); | ||
777 | break; | ||
778 | /* Check USB manufacturer and product strings and try | ||
779 | to determine correct remote in case of chip vendor | ||
780 | reference IDs are used. */ | ||
781 | case USB_VID_AFATECH: | ||
782 | memset(manufacturer, 0, sizeof(manufacturer)); | ||
783 | usb_string(udev, udev->descriptor.iManufacturer, | ||
784 | manufacturer, sizeof(manufacturer)); | ||
785 | if (!strcmp("Geniatech", manufacturer)) { | ||
786 | /* iManufacturer 1 Geniatech | ||
787 | iProduct 2 AF9015 */ | ||
788 | af9015_properties[i].rc_key_map = | ||
789 | af9015_rc_keys_mygictv; | ||
790 | af9015_properties[i].rc_key_map_size = | ||
791 | ARRAY_SIZE(af9015_rc_keys_mygictv); | ||
792 | af9015_config.ir_table = | ||
793 | af9015_ir_table_mygictv; | ||
794 | af9015_config.ir_table_size = | ||
795 | ARRAY_SIZE(af9015_ir_table_mygictv); | ||
796 | } else if (!strcmp("MSI", manufacturer)) { | ||
797 | /* iManufacturer 1 MSI | ||
798 | iProduct 2 MSI K-VOX */ | ||
799 | af9015_properties[i].rc_key_map = | ||
800 | af9015_rc_keys_msi; | ||
801 | af9015_properties[i].rc_key_map_size = | ||
802 | ARRAY_SIZE(af9015_rc_keys_msi); | ||
803 | af9015_config.ir_table = | ||
804 | af9015_ir_table_msi; | ||
805 | af9015_config.ir_table_size = | ||
806 | ARRAY_SIZE(af9015_ir_table_msi); | ||
807 | } | ||
808 | break; | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | |||
813 | /* TS mode - one or two receivers */ | ||
814 | req.addr = AF9015_EEPROM_TS_MODE; | ||
815 | ret = af9015_rw_udev(udev, &req); | ||
816 | if (ret) | ||
817 | goto error; | ||
818 | af9015_config.dual_mode = val; | ||
819 | deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode); | ||
820 | /* disable dual mode by default because it is buggy */ | ||
821 | if (!dvb_usb_af9015_dual_mode) | ||
822 | af9015_config.dual_mode = 0; | ||
823 | |||
824 | /* set buffer size according to USB port speed */ | ||
825 | for (i = 0; i < af9015_properties_count; i++) { | ||
826 | /* USB1.1 set smaller buffersize and disable 2nd adapter */ | ||
827 | if (udev->speed == USB_SPEED_FULL) { | ||
828 | af9015_properties[i].adapter->stream.u.bulk.buffersize = | ||
829 | TS_USB11_MAX_PACKET_SIZE; | ||
830 | /* disable 2nd adapter because we don't have | ||
831 | PID-filters */ | ||
832 | af9015_config.dual_mode = 0; | ||
833 | } else { | ||
834 | af9015_properties[i].adapter->stream.u.bulk.buffersize = | ||
835 | TS_USB20_MAX_PACKET_SIZE; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | if (af9015_config.dual_mode) { | ||
840 | /* read 2nd demodulator I2C address */ | ||
841 | req.addr = AF9015_EEPROM_DEMOD2_I2C; | ||
842 | ret = af9015_rw_udev(udev, &req); | ||
843 | if (ret) | ||
844 | goto error; | ||
845 | af9015_af9013_config[1].demod_address = val; | ||
846 | |||
847 | /* enable 2nd adapter */ | ||
848 | for (i = 0; i < af9015_properties_count; i++) | ||
849 | af9015_properties[i].num_adapters = 2; | ||
850 | |||
851 | } else { | ||
852 | /* disable 2nd adapter */ | ||
853 | for (i = 0; i < af9015_properties_count; i++) | ||
854 | af9015_properties[i].num_adapters = 1; | ||
855 | } | ||
856 | |||
857 | for (i = 0; i < af9015_properties[0].num_adapters; i++) { | ||
858 | if (i == 1) | ||
859 | offset = AF9015_EEPROM_OFFSET; | ||
860 | /* xtal */ | ||
861 | req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; | ||
862 | ret = af9015_rw_udev(udev, &req); | ||
863 | if (ret) | ||
864 | goto error; | ||
865 | switch (val) { | ||
866 | case 0: | ||
867 | af9015_af9013_config[i].adc_clock = 28800; | ||
868 | break; | ||
869 | case 1: | ||
870 | af9015_af9013_config[i].adc_clock = 20480; | ||
871 | break; | ||
872 | case 2: | ||
873 | af9015_af9013_config[i].adc_clock = 28000; | ||
874 | break; | ||
875 | case 3: | ||
876 | af9015_af9013_config[i].adc_clock = 25000; | ||
877 | break; | ||
878 | }; | ||
879 | deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i, | ||
880 | val, af9015_af9013_config[i].adc_clock); | ||
881 | |||
882 | /* tuner IF */ | ||
883 | req.addr = AF9015_EEPROM_IF1H + offset; | ||
884 | ret = af9015_rw_udev(udev, &req); | ||
885 | if (ret) | ||
886 | goto error; | ||
887 | af9015_af9013_config[i].tuner_if = val << 8; | ||
888 | req.addr = AF9015_EEPROM_IF1L + offset; | ||
889 | ret = af9015_rw_udev(udev, &req); | ||
890 | if (ret) | ||
891 | goto error; | ||
892 | af9015_af9013_config[i].tuner_if += val; | ||
893 | deb_info("%s: [%d] IF1:%d\n", __func__, i, | ||
894 | af9015_af9013_config[0].tuner_if); | ||
895 | |||
896 | /* MT2060 IF1 */ | ||
897 | req.addr = AF9015_EEPROM_MT2060_IF1H + offset; | ||
898 | ret = af9015_rw_udev(udev, &req); | ||
899 | if (ret) | ||
900 | goto error; | ||
901 | af9015_config.mt2060_if1[i] = val << 8; | ||
902 | req.addr = AF9015_EEPROM_MT2060_IF1L + offset; | ||
903 | ret = af9015_rw_udev(udev, &req); | ||
904 | if (ret) | ||
905 | goto error; | ||
906 | af9015_config.mt2060_if1[i] += val; | ||
907 | deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i, | ||
908 | af9015_config.mt2060_if1[i]); | ||
909 | |||
910 | /* tuner */ | ||
911 | req.addr = AF9015_EEPROM_TUNER_ID1 + offset; | ||
912 | ret = af9015_rw_udev(udev, &req); | ||
913 | if (ret) | ||
914 | goto error; | ||
915 | switch (val) { | ||
916 | case AF9013_TUNER_ENV77H11D5: | ||
917 | case AF9013_TUNER_MT2060: | ||
918 | case AF9013_TUNER_MC44S803: | ||
919 | case AF9013_TUNER_QT1010: | ||
920 | case AF9013_TUNER_UNKNOWN: | ||
921 | case AF9013_TUNER_MT2060_2: | ||
922 | case AF9013_TUNER_TDA18271: | ||
923 | case AF9013_TUNER_QT1010A: | ||
924 | af9015_af9013_config[i].rf_spec_inv = 1; | ||
925 | break; | ||
926 | case AF9013_TUNER_MXL5003D: | ||
927 | case AF9013_TUNER_MXL5005D: | ||
928 | case AF9013_TUNER_MXL5005R: | ||
929 | af9015_af9013_config[i].rf_spec_inv = 0; | ||
930 | break; | ||
931 | default: | ||
932 | warn("tuner id:%d not supported, please report!", val); | ||
933 | return -ENODEV; | ||
934 | }; | ||
935 | |||
936 | af9015_af9013_config[i].tuner = val; | ||
937 | deb_info("%s: [%d] tuner id:%d\n", __func__, i, val); | ||
938 | } | ||
939 | |||
940 | error: | ||
941 | if (ret) | ||
942 | err("eeprom read failed:%d", ret); | ||
943 | |||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | static int af9015_identify_state(struct usb_device *udev, | ||
948 | struct dvb_usb_device_properties *props, | ||
949 | struct dvb_usb_device_description **desc, | ||
950 | int *cold) | ||
951 | { | ||
952 | int ret; | ||
953 | u8 reply; | ||
954 | struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; | ||
955 | |||
956 | ret = af9015_rw_udev(udev, &req); | ||
957 | if (ret) | ||
958 | return ret; | ||
959 | |||
960 | deb_info("%s: reply:%02x\n", __func__, reply); | ||
961 | if (reply == 0x02) | ||
962 | *cold = 0; | ||
963 | else | ||
964 | *cold = 1; | ||
965 | |||
966 | return ret; | ||
967 | } | ||
968 | |||
969 | static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | ||
970 | { | ||
971 | u8 buf[8]; | ||
972 | struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf}; | ||
973 | struct dvb_usb_rc_key *keymap = d->props.rc_key_map; | ||
974 | int i, ret; | ||
975 | |||
976 | memset(buf, 0, sizeof(buf)); | ||
977 | |||
978 | ret = af9015_ctrl_msg(d, &req); | ||
979 | if (ret) | ||
980 | return ret; | ||
981 | |||
982 | *event = 0; | ||
983 | *state = REMOTE_NO_KEY_PRESSED; | ||
984 | |||
985 | for (i = 0; i < d->props.rc_key_map_size; i++) { | ||
986 | if (!buf[1] && keymap[i].custom == buf[0] && | ||
987 | keymap[i].data == buf[2]) { | ||
988 | *event = keymap[i].event; | ||
989 | *state = REMOTE_KEY_PRESSED; | ||
990 | break; | ||
991 | } | ||
992 | } | ||
993 | if (!buf[1]) | ||
994 | deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
995 | __func__, buf[0], buf[1], buf[2], buf[3], buf[4], | ||
996 | buf[5], buf[6], buf[7]); | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | /* init 2nd I2C adapter */ | ||
1002 | int af9015_i2c_init(struct dvb_usb_device *d) | ||
1003 | { | ||
1004 | int ret; | ||
1005 | struct af9015_state *state = d->priv; | ||
1006 | deb_info("%s:\n", __func__); | ||
1007 | |||
1008 | strncpy(state->i2c_adap.name, d->desc->name, | ||
1009 | sizeof(state->i2c_adap.name)); | ||
1010 | #ifdef I2C_ADAP_CLASS_TV_DIGITAL | ||
1011 | state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, | ||
1012 | #else | ||
1013 | state->i2c_adap.class = I2C_CLASS_TV_DIGITAL, | ||
1014 | #endif | ||
1015 | state->i2c_adap.algo = d->props.i2c_algo; | ||
1016 | state->i2c_adap.algo_data = NULL; | ||
1017 | state->i2c_adap.dev.parent = &d->udev->dev; | ||
1018 | |||
1019 | i2c_set_adapdata(&state->i2c_adap, d); | ||
1020 | |||
1021 | ret = i2c_add_adapter(&state->i2c_adap); | ||
1022 | if (ret < 0) | ||
1023 | err("could not add i2c adapter"); | ||
1024 | |||
1025 | return ret; | ||
1026 | } | ||
1027 | |||
1028 | static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) | ||
1029 | { | ||
1030 | int ret; | ||
1031 | struct af9015_state *state = adap->dev->priv; | ||
1032 | struct i2c_adapter *i2c_adap; | ||
1033 | |||
1034 | if (adap->id == 0) { | ||
1035 | /* select I2C adapter */ | ||
1036 | i2c_adap = &adap->dev->i2c_adap; | ||
1037 | |||
1038 | deb_info("%s: init I2C\n", __func__); | ||
1039 | ret = af9015_i2c_init(adap->dev); | ||
1040 | |||
1041 | /* dump eeprom (debug) */ | ||
1042 | ret = af9015_eeprom_dump(adap->dev); | ||
1043 | if (ret) | ||
1044 | return ret; | ||
1045 | } else { | ||
1046 | /* select I2C adapter */ | ||
1047 | i2c_adap = &state->i2c_adap; | ||
1048 | |||
1049 | /* copy firmware to 2nd demodulator */ | ||
1050 | if (af9015_config.dual_mode) { | ||
1051 | ret = af9015_copy_firmware(adap->dev); | ||
1052 | if (ret) { | ||
1053 | err("firmware copy to 2nd frontend " \ | ||
1054 | "failed, will disable it"); | ||
1055 | af9015_config.dual_mode = 0; | ||
1056 | return -ENODEV; | ||
1057 | } | ||
1058 | } else { | ||
1059 | return -ENODEV; | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | /* attach demodulator */ | ||
1064 | adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], | ||
1065 | i2c_adap); | ||
1066 | |||
1067 | return adap->fe == NULL ? -ENODEV : 0; | ||
1068 | } | ||
1069 | |||
1070 | static struct mt2060_config af9015_mt2060_config = { | ||
1071 | .i2c_address = 0xc0, | ||
1072 | .clock_out = 0, | ||
1073 | }; | ||
1074 | |||
1075 | static struct qt1010_config af9015_qt1010_config = { | ||
1076 | .i2c_address = 0xc4, | ||
1077 | }; | ||
1078 | |||
1079 | static struct tda18271_config af9015_tda18271_config = { | ||
1080 | .gate = TDA18271_GATE_DIGITAL, | ||
1081 | .small_i2c = 1, | ||
1082 | }; | ||
1083 | |||
1084 | static struct mxl5005s_config af9015_mxl5003_config = { | ||
1085 | .i2c_address = 0xc6, | ||
1086 | .if_freq = IF_FREQ_4570000HZ, | ||
1087 | .xtal_freq = CRYSTAL_FREQ_16000000HZ, | ||
1088 | .agc_mode = MXL_SINGLE_AGC, | ||
1089 | .tracking_filter = MXL_TF_DEFAULT, | ||
1090 | .rssi_enable = MXL_RSSI_ENABLE, | ||
1091 | .cap_select = MXL_CAP_SEL_ENABLE, | ||
1092 | .div_out = MXL_DIV_OUT_4, | ||
1093 | .clock_out = MXL_CLOCK_OUT_DISABLE, | ||
1094 | .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, | ||
1095 | .top = MXL5005S_TOP_25P2, | ||
1096 | .mod_mode = MXL_DIGITAL_MODE, | ||
1097 | .if_mode = MXL_ZERO_IF, | ||
1098 | .AgcMasterByte = 0x00, | ||
1099 | }; | ||
1100 | |||
1101 | static struct mxl5005s_config af9015_mxl5005_config = { | ||
1102 | .i2c_address = 0xc6, | ||
1103 | .if_freq = IF_FREQ_4570000HZ, | ||
1104 | .xtal_freq = CRYSTAL_FREQ_16000000HZ, | ||
1105 | .agc_mode = MXL_SINGLE_AGC, | ||
1106 | .tracking_filter = MXL_TF_OFF, | ||
1107 | .rssi_enable = MXL_RSSI_ENABLE, | ||
1108 | .cap_select = MXL_CAP_SEL_ENABLE, | ||
1109 | .div_out = MXL_DIV_OUT_4, | ||
1110 | .clock_out = MXL_CLOCK_OUT_DISABLE, | ||
1111 | .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, | ||
1112 | .top = MXL5005S_TOP_25P2, | ||
1113 | .mod_mode = MXL_DIGITAL_MODE, | ||
1114 | .if_mode = MXL_ZERO_IF, | ||
1115 | .AgcMasterByte = 0x00, | ||
1116 | }; | ||
1117 | |||
1118 | static int af9015_tuner_attach(struct dvb_usb_adapter *adap) | ||
1119 | { | ||
1120 | struct af9015_state *state = adap->dev->priv; | ||
1121 | struct i2c_adapter *i2c_adap; | ||
1122 | int ret; | ||
1123 | deb_info("%s: \n", __func__); | ||
1124 | |||
1125 | /* select I2C adapter */ | ||
1126 | if (adap->id == 0) | ||
1127 | i2c_adap = &adap->dev->i2c_adap; | ||
1128 | else | ||
1129 | i2c_adap = &state->i2c_adap; | ||
1130 | |||
1131 | switch (af9015_af9013_config[adap->id].tuner) { | ||
1132 | case AF9013_TUNER_MT2060: | ||
1133 | case AF9013_TUNER_MT2060_2: | ||
1134 | ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap, | ||
1135 | &af9015_mt2060_config, | ||
1136 | af9015_config.mt2060_if1[adap->id]) | ||
1137 | == NULL ? -ENODEV : 0; | ||
1138 | break; | ||
1139 | case AF9013_TUNER_QT1010: | ||
1140 | case AF9013_TUNER_QT1010A: | ||
1141 | ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap, | ||
1142 | &af9015_qt1010_config) == NULL ? -ENODEV : 0; | ||
1143 | break; | ||
1144 | case AF9013_TUNER_TDA18271: | ||
1145 | ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap, | ||
1146 | &af9015_tda18271_config) == NULL ? -ENODEV : 0; | ||
1147 | break; | ||
1148 | case AF9013_TUNER_MXL5003D: | ||
1149 | ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, | ||
1150 | &af9015_mxl5003_config) == NULL ? -ENODEV : 0; | ||
1151 | break; | ||
1152 | case AF9013_TUNER_MXL5005D: | ||
1153 | case AF9013_TUNER_MXL5005R: | ||
1154 | ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, | ||
1155 | &af9015_mxl5005_config) == NULL ? -ENODEV : 0; | ||
1156 | break; | ||
1157 | case AF9013_TUNER_ENV77H11D5: | ||
1158 | ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap, | ||
1159 | DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; | ||
1160 | break; | ||
1161 | case AF9013_TUNER_MC44S803: | ||
1162 | #if 0 | ||
1163 | ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap) | ||
1164 | == NULL ? -ENODEV : 0; | ||
1165 | #else | ||
1166 | ret = -ENODEV; | ||
1167 | info("Freescale MC44S803 tuner found but no driver for that" \ | ||
1168 | "tuner. Look at the Linuxtv.org for tuner driver" \ | ||
1169 | "status."); | ||
1170 | #endif | ||
1171 | break; | ||
1172 | case AF9013_TUNER_UNKNOWN: | ||
1173 | default: | ||
1174 | ret = -ENODEV; | ||
1175 | err("Unknown tuner id:%d", | ||
1176 | af9015_af9013_config[adap->id].tuner); | ||
1177 | } | ||
1178 | return ret; | ||
1179 | } | ||
1180 | |||
1181 | static struct usb_device_id af9015_usb_table[] = { | ||
1182 | /* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, | ||
1183 | {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, | ||
1184 | {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, | ||
1185 | {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, | ||
1186 | {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, | ||
1187 | /* 5 */{USB_DEVICE(USB_VID_VISIONPLUS, | ||
1188 | USB_PID_TINYTWIN)}, | ||
1189 | {USB_DEVICE(USB_VID_VISIONPLUS, | ||
1190 | USB_PID_AZUREWAVE_AD_TU700)}, | ||
1191 | {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, | ||
1192 | {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, | ||
1193 | {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, | ||
1194 | /* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, | ||
1195 | {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, | ||
1196 | {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, | ||
1197 | {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, | ||
1198 | {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, | ||
1199 | /* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, | ||
1200 | {0}, | ||
1201 | }; | ||
1202 | MODULE_DEVICE_TABLE(usb, af9015_usb_table); | ||
1203 | |||
1204 | static struct dvb_usb_device_properties af9015_properties[] = { | ||
1205 | { | ||
1206 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
1207 | |||
1208 | .usb_ctrl = DEVICE_SPECIFIC, | ||
1209 | .download_firmware = af9015_download_firmware, | ||
1210 | .firmware = "dvb-usb-af9015.fw", | ||
1211 | |||
1212 | .size_of_priv = sizeof(struct af9015_state), \ | ||
1213 | |||
1214 | .num_adapters = 2, | ||
1215 | .adapter = { | ||
1216 | { | ||
1217 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | | ||
1218 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | ||
1219 | |||
1220 | .pid_filter_count = 32, | ||
1221 | .pid_filter = af9015_pid_filter, | ||
1222 | .pid_filter_ctrl = af9015_pid_filter_ctrl, | ||
1223 | |||
1224 | .frontend_attach = | ||
1225 | af9015_af9013_frontend_attach, | ||
1226 | .tuner_attach = af9015_tuner_attach, | ||
1227 | .stream = { | ||
1228 | .type = USB_BULK, | ||
1229 | .count = 6, | ||
1230 | .endpoint = 0x84, | ||
1231 | }, | ||
1232 | }, | ||
1233 | { | ||
1234 | .frontend_attach = | ||
1235 | af9015_af9013_frontend_attach, | ||
1236 | .tuner_attach = af9015_tuner_attach, | ||
1237 | .stream = { | ||
1238 | .type = USB_BULK, | ||
1239 | .count = 6, | ||
1240 | .endpoint = 0x85, | ||
1241 | }, | ||
1242 | } | ||
1243 | }, | ||
1244 | |||
1245 | .identify_state = af9015_identify_state, | ||
1246 | |||
1247 | .rc_query = af9015_rc_query, | ||
1248 | .rc_interval = 150, | ||
1249 | |||
1250 | .i2c_algo = &af9015_i2c_algo, | ||
1251 | |||
1252 | .num_device_descs = 9, | ||
1253 | .devices = { | ||
1254 | { | ||
1255 | .name = "Afatech AF9015 DVB-T USB2.0 stick", | ||
1256 | .cold_ids = {&af9015_usb_table[0], | ||
1257 | &af9015_usb_table[1], NULL}, | ||
1258 | .warm_ids = {NULL}, | ||
1259 | }, | ||
1260 | { | ||
1261 | .name = "Leadtek WinFast DTV Dongle Gold", | ||
1262 | .cold_ids = {&af9015_usb_table[2], NULL}, | ||
1263 | .warm_ids = {NULL}, | ||
1264 | }, | ||
1265 | { | ||
1266 | .name = "Pinnacle PCTV 71e", | ||
1267 | .cold_ids = {&af9015_usb_table[3], NULL}, | ||
1268 | .warm_ids = {NULL}, | ||
1269 | }, | ||
1270 | { | ||
1271 | .name = "KWorld PlusTV Dual DVB-T Stick " \ | ||
1272 | "(DVB-T 399U)", | ||
1273 | .cold_ids = {&af9015_usb_table[4], NULL}, | ||
1274 | .warm_ids = {NULL}, | ||
1275 | }, | ||
1276 | { | ||
1277 | .name = "DigitalNow TinyTwin DVB-T Receiver", | ||
1278 | .cold_ids = {&af9015_usb_table[5], NULL}, | ||
1279 | .warm_ids = {NULL}, | ||
1280 | }, | ||
1281 | { | ||
1282 | .name = "TwinHan AzureWave AD-TU700(704J)", | ||
1283 | .cold_ids = {&af9015_usb_table[6], NULL}, | ||
1284 | .warm_ids = {NULL}, | ||
1285 | }, | ||
1286 | { | ||
1287 | .name = "TerraTec Cinergy T USB XE", | ||
1288 | .cold_ids = {&af9015_usb_table[7], NULL}, | ||
1289 | .warm_ids = {NULL}, | ||
1290 | }, | ||
1291 | { | ||
1292 | .name = "KWorld PlusTV Dual DVB-T PCI " \ | ||
1293 | "(DVB-T PC160-2T)", | ||
1294 | .cold_ids = {&af9015_usb_table[8], NULL}, | ||
1295 | .warm_ids = {NULL}, | ||
1296 | }, | ||
1297 | { | ||
1298 | .name = "AVerMedia AVerTV DVB-T Volar X", | ||
1299 | .cold_ids = {&af9015_usb_table[9], NULL}, | ||
1300 | .warm_ids = {NULL}, | ||
1301 | }, | ||
1302 | } | ||
1303 | }, { | ||
1304 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
1305 | |||
1306 | .usb_ctrl = DEVICE_SPECIFIC, | ||
1307 | .download_firmware = af9015_download_firmware, | ||
1308 | .firmware = "dvb-usb-af9015.fw", | ||
1309 | |||
1310 | .size_of_priv = sizeof(struct af9015_state), \ | ||
1311 | |||
1312 | .num_adapters = 2, | ||
1313 | .adapter = { | ||
1314 | { | ||
1315 | .caps = DVB_USB_ADAP_HAS_PID_FILTER | | ||
1316 | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, | ||
1317 | |||
1318 | .pid_filter_count = 32, | ||
1319 | .pid_filter = af9015_pid_filter, | ||
1320 | .pid_filter_ctrl = af9015_pid_filter_ctrl, | ||
1321 | |||
1322 | .frontend_attach = | ||
1323 | af9015_af9013_frontend_attach, | ||
1324 | .tuner_attach = af9015_tuner_attach, | ||
1325 | .stream = { | ||
1326 | .type = USB_BULK, | ||
1327 | .count = 6, | ||
1328 | .endpoint = 0x84, | ||
1329 | }, | ||
1330 | }, | ||
1331 | { | ||
1332 | .frontend_attach = | ||
1333 | af9015_af9013_frontend_attach, | ||
1334 | .tuner_attach = af9015_tuner_attach, | ||
1335 | .stream = { | ||
1336 | .type = USB_BULK, | ||
1337 | .count = 6, | ||
1338 | .endpoint = 0x85, | ||
1339 | }, | ||
1340 | } | ||
1341 | }, | ||
1342 | |||
1343 | .identify_state = af9015_identify_state, | ||
1344 | |||
1345 | .rc_query = af9015_rc_query, | ||
1346 | .rc_interval = 150, | ||
1347 | |||
1348 | .i2c_algo = &af9015_i2c_algo, | ||
1349 | |||
1350 | .num_device_descs = 6, | ||
1351 | .devices = { | ||
1352 | { | ||
1353 | .name = "Xtensions XD-380", | ||
1354 | .cold_ids = {&af9015_usb_table[10], NULL}, | ||
1355 | .warm_ids = {NULL}, | ||
1356 | }, | ||
1357 | { | ||
1358 | .name = "MSI DIGIVOX Duo", | ||
1359 | .cold_ids = {&af9015_usb_table[11], NULL}, | ||
1360 | .warm_ids = {NULL}, | ||
1361 | }, | ||
1362 | { | ||
1363 | .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", | ||
1364 | .cold_ids = {&af9015_usb_table[12], NULL}, | ||
1365 | .warm_ids = {NULL}, | ||
1366 | }, | ||
1367 | { | ||
1368 | .name = "Telestar Starstick 2", | ||
1369 | .cold_ids = {&af9015_usb_table[13], NULL}, | ||
1370 | .warm_ids = {NULL}, | ||
1371 | }, | ||
1372 | { | ||
1373 | .name = "AVerMedia A309", | ||
1374 | .cold_ids = {&af9015_usb_table[14], NULL}, | ||
1375 | .warm_ids = {NULL}, | ||
1376 | }, | ||
1377 | { | ||
1378 | .name = "MSI Digi VOX mini III", | ||
1379 | .cold_ids = {&af9015_usb_table[15], NULL}, | ||
1380 | .warm_ids = {NULL}, | ||
1381 | }, | ||
1382 | } | ||
1383 | } | ||
1384 | }; | ||
1385 | |||
1386 | static int af9015_usb_probe(struct usb_interface *intf, | ||
1387 | const struct usb_device_id *id) | ||
1388 | { | ||
1389 | int ret = 0; | ||
1390 | struct dvb_usb_device *d = NULL; | ||
1391 | struct usb_device *udev = interface_to_usbdev(intf); | ||
1392 | u8 i; | ||
1393 | |||
1394 | deb_info("%s: interface:%d\n", __func__, | ||
1395 | intf->cur_altsetting->desc.bInterfaceNumber); | ||
1396 | |||
1397 | /* interface 0 is used by DVB-T receiver and | ||
1398 | interface 1 is for remote controller (HID) */ | ||
1399 | if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { | ||
1400 | ret = af9015_read_config(udev); | ||
1401 | if (ret) | ||
1402 | return ret; | ||
1403 | |||
1404 | for (i = 0; i < af9015_properties_count; i++) { | ||
1405 | ret = dvb_usb_device_init(intf, &af9015_properties[i], | ||
1406 | THIS_MODULE, &d, adapter_nr); | ||
1407 | if (!ret) | ||
1408 | break; | ||
1409 | if (ret != -ENODEV) | ||
1410 | return ret; | ||
1411 | } | ||
1412 | if (ret) | ||
1413 | return ret; | ||
1414 | |||
1415 | if (d) | ||
1416 | ret = af9015_init(d); | ||
1417 | } | ||
1418 | |||
1419 | return ret; | ||
1420 | } | ||
1421 | |||
1422 | void af9015_i2c_exit(struct dvb_usb_device *d) | ||
1423 | { | ||
1424 | struct af9015_state *state = d->priv; | ||
1425 | deb_info("%s: \n", __func__); | ||
1426 | |||
1427 | /* remove 2nd I2C adapter */ | ||
1428 | if (d->state & DVB_USB_STATE_I2C) | ||
1429 | i2c_del_adapter(&state->i2c_adap); | ||
1430 | } | ||
1431 | |||
1432 | static void af9015_usb_device_exit(struct usb_interface *intf) | ||
1433 | { | ||
1434 | struct dvb_usb_device *d = usb_get_intfdata(intf); | ||
1435 | deb_info("%s: \n", __func__); | ||
1436 | |||
1437 | /* remove 2nd I2C adapter */ | ||
1438 | if (d != NULL && d->desc != NULL) | ||
1439 | af9015_i2c_exit(d); | ||
1440 | |||
1441 | dvb_usb_device_exit(intf); | ||
1442 | } | ||
1443 | |||
1444 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
1445 | static struct usb_driver af9015_usb_driver = { | ||
1446 | .name = "dvb_usb_af9015", | ||
1447 | .probe = af9015_usb_probe, | ||
1448 | .disconnect = af9015_usb_device_exit, | ||
1449 | .id_table = af9015_usb_table, | ||
1450 | }; | ||
1451 | |||
1452 | /* module stuff */ | ||
1453 | static int __init af9015_usb_module_init(void) | ||
1454 | { | ||
1455 | int ret; | ||
1456 | ret = usb_register(&af9015_usb_driver); | ||
1457 | if (ret) | ||
1458 | err("module init failed:%d", ret); | ||
1459 | |||
1460 | return ret; | ||
1461 | } | ||
1462 | |||
1463 | static void __exit af9015_usb_module_exit(void) | ||
1464 | { | ||
1465 | /* deregister this driver from the USB subsystem */ | ||
1466 | usb_deregister(&af9015_usb_driver); | ||
1467 | } | ||
1468 | |||
1469 | module_init(af9015_usb_module_init); | ||
1470 | module_exit(af9015_usb_module_exit); | ||
1471 | |||
1472 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
1473 | MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T"); | ||
1474 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h new file mode 100644 index 000000000000..882e8a4b3681 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9015.h | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _DVB_USB_AF9015_H_ | ||
25 | #define _DVB_USB_AF9015_H_ | ||
26 | |||
27 | #define DVB_USB_LOG_PREFIX "af9015" | ||
28 | #include "dvb-usb.h" | ||
29 | |||
30 | extern int dvb_usb_af9015_debug; | ||
31 | #define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) | ||
32 | #define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) | ||
33 | #define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args) | ||
34 | #define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args) | ||
35 | #define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args) | ||
36 | #define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args) | ||
37 | |||
38 | #define AF9015_I2C_EEPROM 0xa0 | ||
39 | #define AF9015_I2C_DEMOD 0x38 | ||
40 | #define AF9015_USB_TIMEOUT 2000 | ||
41 | |||
42 | /* EEPROM locations */ | ||
43 | #define AF9015_EEPROM_IR_MODE 0x18 | ||
44 | #define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 | ||
45 | #define AF9015_EEPROM_TS_MODE 0x31 | ||
46 | #define AF9015_EEPROM_DEMOD2_I2C 0x32 | ||
47 | |||
48 | #define AF9015_EEPROM_SAW_BW1 0x35 | ||
49 | #define AF9015_EEPROM_XTAL_TYPE1 0x36 | ||
50 | #define AF9015_EEPROM_SPEC_INV1 0x37 | ||
51 | #define AF9015_EEPROM_IF1L 0x38 | ||
52 | #define AF9015_EEPROM_IF1H 0x39 | ||
53 | #define AF9015_EEPROM_MT2060_IF1L 0x3a | ||
54 | #define AF9015_EEPROM_MT2060_IF1H 0x3b | ||
55 | #define AF9015_EEPROM_TUNER_ID1 0x3c | ||
56 | |||
57 | #define AF9015_EEPROM_SAW_BW2 0x45 | ||
58 | #define AF9015_EEPROM_XTAL_TYPE2 0x46 | ||
59 | #define AF9015_EEPROM_SPEC_INV2 0x47 | ||
60 | #define AF9015_EEPROM_IF2L 0x48 | ||
61 | #define AF9015_EEPROM_IF2H 0x49 | ||
62 | #define AF9015_EEPROM_MT2060_IF2L 0x4a | ||
63 | #define AF9015_EEPROM_MT2060_IF2H 0x4b | ||
64 | #define AF9015_EEPROM_TUNER_ID2 0x4c | ||
65 | |||
66 | #define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) | ||
67 | |||
68 | #define AF9015_GPIO_ON (1 << 0) | ||
69 | #define AF9015_GPIO_EN (1 << 1) | ||
70 | #define AF9015_GPIO_O (1 << 2) | ||
71 | #define AF9015_GPIO_I (1 << 3) | ||
72 | |||
73 | #define AF9015_GPIO_TUNER_ON (AF9015_GPIO_ON|AF9015_GPIO_EN) | ||
74 | #define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O) | ||
75 | |||
76 | struct req_t { | ||
77 | u8 cmd; /* [0] */ | ||
78 | /* seq */ /* [1] */ | ||
79 | u8 i2c_addr; /* [2] */ | ||
80 | u16 addr; /* [3|4] */ | ||
81 | u8 mbox; /* [5] */ | ||
82 | u8 addr_len; /* [6] */ | ||
83 | u8 data_len; /* [7] */ | ||
84 | u8 *data; | ||
85 | }; | ||
86 | |||
87 | enum af9015_cmd { | ||
88 | GET_CONFIG = 0x10, | ||
89 | DOWNLOAD_FIRMWARE = 0x11, | ||
90 | BOOT = 0x13, | ||
91 | READ_MEMORY = 0x20, | ||
92 | WRITE_MEMORY = 0x21, | ||
93 | READ_WRITE_I2C = 0x22, | ||
94 | COPY_FIRMWARE = 0x23, | ||
95 | RECONNECT_USB = 0x5a, | ||
96 | WRITE_VIRTUAL_MEMORY = 0x26, | ||
97 | GET_IR_CODE = 0x27, | ||
98 | READ_I2C, | ||
99 | WRITE_I2C, | ||
100 | }; | ||
101 | |||
102 | enum af9015_ir_mode { | ||
103 | AF9015_IR_MODE_DISABLED = 0, | ||
104 | AF9015_IR_MODE_HID, | ||
105 | AF9015_IR_MODE_RLC, | ||
106 | AF9015_IR_MODE_RC6, | ||
107 | }; | ||
108 | |||
109 | struct af9015_state { | ||
110 | struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */ | ||
111 | }; | ||
112 | |||
113 | struct af9015_config { | ||
114 | u8 dual_mode:1; | ||
115 | u16 mt2060_if1[2]; | ||
116 | u16 firmware_size; | ||
117 | u16 firmware_checksum; | ||
118 | u8 *ir_table; | ||
119 | u16 ir_table_size; | ||
120 | }; | ||
121 | |||
122 | enum af9015_remote { | ||
123 | AF9015_REMOTE_NONE = 0, | ||
124 | AF9015_REMOTE_A_LINK_DTU_M, | ||
125 | AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, | ||
126 | AF9015_REMOTE_MYGICTV_U718, | ||
127 | }; | ||
128 | |||
129 | /* Leadtek WinFast DTV Dongle Gold */ | ||
130 | static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = { | ||
131 | { 0x00, 0x1e, KEY_1 }, | ||
132 | { 0x00, 0x1f, KEY_2 }, | ||
133 | { 0x00, 0x20, KEY_3 }, | ||
134 | { 0x00, 0x21, KEY_4 }, | ||
135 | { 0x00, 0x22, KEY_5 }, | ||
136 | { 0x00, 0x23, KEY_6 }, | ||
137 | { 0x00, 0x24, KEY_7 }, | ||
138 | { 0x00, 0x25, KEY_8 }, | ||
139 | { 0x00, 0x26, KEY_9 }, | ||
140 | { 0x00, 0x27, KEY_0 }, | ||
141 | { 0x00, 0x28, KEY_ENTER }, | ||
142 | { 0x00, 0x4f, KEY_VOLUMEUP }, | ||
143 | { 0x00, 0x50, KEY_VOLUMEDOWN }, | ||
144 | { 0x00, 0x51, KEY_CHANNELDOWN }, | ||
145 | { 0x00, 0x52, KEY_CHANNELUP }, | ||
146 | }; | ||
147 | |||
148 | static u8 af9015_ir_table_leadtek[] = { | ||
149 | 0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, | ||
150 | 0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00, | ||
151 | 0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00, | ||
152 | 0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, | ||
153 | 0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00, | ||
154 | 0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00, | ||
155 | 0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, | ||
156 | 0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, | ||
157 | 0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, | ||
158 | 0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, | ||
159 | 0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, | ||
160 | 0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, | ||
161 | 0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, | ||
162 | 0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, | ||
163 | 0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, | ||
164 | 0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, | ||
165 | 0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, | ||
166 | 0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, | ||
167 | 0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, | ||
168 | 0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, | ||
169 | 0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00, | ||
170 | 0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, | ||
171 | 0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, | ||
172 | 0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, | ||
173 | 0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, | ||
174 | 0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, | ||
175 | 0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, | ||
176 | 0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, | ||
177 | 0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, | ||
178 | 0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, | ||
179 | 0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, | ||
180 | 0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, | ||
181 | 0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, | ||
182 | 0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, | ||
183 | 0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, | ||
184 | 0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, | ||
185 | 0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, | ||
186 | 0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, | ||
187 | 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, | ||
188 | 0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, | ||
189 | 0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, | ||
190 | 0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, | ||
191 | 0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, | ||
192 | 0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, | ||
193 | 0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, | ||
194 | 0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, | ||
195 | 0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, | ||
196 | 0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, | ||
197 | 0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, | ||
198 | 0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, | ||
199 | }; | ||
200 | |||
201 | /* TwinHan AzureWave AD-TU700(704J) */ | ||
202 | static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = { | ||
203 | { 0x05, 0x3f, KEY_POWER }, | ||
204 | { 0x00, 0x19, KEY_FAVORITES }, /* Favorite List */ | ||
205 | { 0x00, 0x04, KEY_TEXT }, /* Teletext */ | ||
206 | { 0x00, 0x0e, KEY_POWER }, | ||
207 | { 0x00, 0x0e, KEY_INFO }, /* Preview */ | ||
208 | { 0x00, 0x08, KEY_EPG }, /* Info/EPG */ | ||
209 | { 0x00, 0x0f, KEY_LIST }, /* Record List */ | ||
210 | { 0x00, 0x1e, KEY_1 }, | ||
211 | { 0x00, 0x1f, KEY_2 }, | ||
212 | { 0x00, 0x20, KEY_3 }, | ||
213 | { 0x00, 0x21, KEY_4 }, | ||
214 | { 0x00, 0x22, KEY_5 }, | ||
215 | { 0x00, 0x23, KEY_6 }, | ||
216 | { 0x00, 0x24, KEY_7 }, | ||
217 | { 0x00, 0x25, KEY_8 }, | ||
218 | { 0x00, 0x26, KEY_9 }, | ||
219 | { 0x00, 0x27, KEY_0 }, | ||
220 | { 0x00, 0x29, KEY_CANCEL }, /* Cancel */ | ||
221 | { 0x00, 0x4c, KEY_CLEAR }, /* Clear */ | ||
222 | { 0x00, 0x2a, KEY_BACK }, /* Back */ | ||
223 | { 0x00, 0x2b, KEY_TAB }, /* Tab */ | ||
224 | { 0x00, 0x52, KEY_UP }, /* up arrow */ | ||
225 | { 0x00, 0x51, KEY_DOWN }, /* down arrow */ | ||
226 | { 0x00, 0x4f, KEY_RIGHT }, /* right arrow */ | ||
227 | { 0x00, 0x50, KEY_LEFT }, /* left arrow */ | ||
228 | { 0x00, 0x28, KEY_ENTER }, /* Enter / ok */ | ||
229 | { 0x02, 0x52, KEY_VOLUMEUP }, | ||
230 | { 0x02, 0x51, KEY_VOLUMEDOWN }, | ||
231 | { 0x00, 0x4e, KEY_CHANNELDOWN }, | ||
232 | { 0x00, 0x4b, KEY_CHANNELUP }, | ||
233 | { 0x00, 0x4a, KEY_RECORD }, | ||
234 | { 0x01, 0x11, KEY_PLAY }, | ||
235 | { 0x00, 0x17, KEY_PAUSE }, | ||
236 | { 0x00, 0x0c, KEY_REWIND }, /* FR << */ | ||
237 | { 0x00, 0x11, KEY_FASTFORWARD }, /* FF >> */ | ||
238 | { 0x01, 0x15, KEY_PREVIOUS }, /* Replay */ | ||
239 | { 0x01, 0x0e, KEY_NEXT }, /* Skip */ | ||
240 | { 0x00, 0x13, KEY_CAMERA }, /* Capture */ | ||
241 | { 0x01, 0x0f, KEY_LANGUAGE }, /* SAP */ | ||
242 | { 0x01, 0x13, KEY_TV2 }, /* PIP */ | ||
243 | { 0x00, 0x1d, KEY_ZOOM }, /* Full Screen */ | ||
244 | { 0x01, 0x17, KEY_SUBTITLE }, /* Subtitle / CC */ | ||
245 | { 0x00, 0x10, KEY_MUTE }, | ||
246 | { 0x01, 0x19, KEY_AUDIO }, /* L/R */ /* TODO better event */ | ||
247 | { 0x01, 0x16, KEY_SLEEP }, /* Hibernate */ | ||
248 | { 0x01, 0x16, KEY_SWITCHVIDEOMODE }, | ||
249 | /* A/V */ /* TODO does not work */ | ||
250 | { 0x00, 0x06, KEY_AGAIN }, /* Recall */ | ||
251 | { 0x01, 0x16, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */ | ||
252 | { 0x01, 0x16, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */ | ||
253 | { 0x02, 0x15, KEY_RED }, | ||
254 | { 0x02, 0x0a, KEY_GREEN }, | ||
255 | { 0x02, 0x1c, KEY_YELLOW }, | ||
256 | { 0x02, 0x05, KEY_BLUE }, | ||
257 | }; | ||
258 | |||
259 | static u8 af9015_ir_table_twinhan[] = { | ||
260 | 0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00, | ||
261 | 0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00, | ||
262 | 0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00, | ||
263 | 0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00, | ||
264 | 0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00, | ||
265 | 0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00, | ||
266 | 0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00, | ||
267 | 0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00, | ||
268 | 0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00, | ||
269 | 0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00, | ||
270 | 0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00, | ||
271 | 0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00, | ||
272 | 0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00, | ||
273 | 0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00, | ||
274 | 0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00, | ||
275 | 0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00, | ||
276 | 0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00, | ||
277 | 0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00, | ||
278 | 0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00, | ||
279 | 0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00, | ||
280 | 0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00, | ||
281 | 0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00, | ||
282 | 0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00, | ||
283 | 0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00, | ||
284 | 0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00, | ||
285 | 0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00, | ||
286 | 0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00, | ||
287 | 0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00, | ||
288 | 0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00, | ||
289 | 0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00, | ||
290 | 0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00, | ||
291 | 0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00, | ||
292 | 0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00, | ||
293 | 0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00, | ||
294 | 0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00, | ||
295 | 0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00, | ||
296 | 0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00, | ||
297 | 0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00, | ||
298 | 0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00, | ||
299 | 0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00, | ||
300 | 0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00, | ||
301 | 0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00, | ||
302 | 0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00, | ||
303 | 0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00, | ||
304 | 0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00, | ||
305 | 0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00, | ||
306 | 0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00, | ||
307 | 0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00, | ||
308 | 0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00, | ||
309 | 0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00, | ||
310 | }; | ||
311 | |||
312 | /* A-Link DTU(m) */ | ||
313 | static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = { | ||
314 | { 0x00, 0x1e, KEY_1 }, | ||
315 | { 0x00, 0x1f, KEY_2 }, | ||
316 | { 0x00, 0x20, KEY_3 }, | ||
317 | { 0x00, 0x21, KEY_4 }, | ||
318 | { 0x00, 0x22, KEY_5 }, | ||
319 | { 0x00, 0x23, KEY_6 }, | ||
320 | { 0x00, 0x24, KEY_7 }, | ||
321 | { 0x00, 0x25, KEY_8 }, | ||
322 | { 0x00, 0x26, KEY_9 }, | ||
323 | { 0x00, 0x27, KEY_0 }, | ||
324 | { 0x00, 0x2e, KEY_CHANNELUP }, | ||
325 | { 0x00, 0x2d, KEY_CHANNELDOWN }, | ||
326 | { 0x04, 0x28, KEY_ZOOM }, | ||
327 | { 0x00, 0x41, KEY_MUTE }, | ||
328 | { 0x00, 0x42, KEY_VOLUMEDOWN }, | ||
329 | { 0x00, 0x43, KEY_VOLUMEUP }, | ||
330 | { 0x00, 0x44, KEY_GOTO }, /* jump */ | ||
331 | { 0x05, 0x45, KEY_POWER }, | ||
332 | }; | ||
333 | |||
334 | static u8 af9015_ir_table_a_link[] = { | ||
335 | 0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */ | ||
336 | 0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */ | ||
337 | 0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */ | ||
338 | 0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */ | ||
339 | 0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */ | ||
340 | 0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */ | ||
341 | 0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */ | ||
342 | 0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */ | ||
343 | 0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */ | ||
344 | 0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */ | ||
345 | 0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */ | ||
346 | 0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */ | ||
347 | 0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */ | ||
348 | 0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */ | ||
349 | 0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */ | ||
350 | 0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */ | ||
351 | 0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */ | ||
352 | 0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */ | ||
353 | }; | ||
354 | |||
355 | /* MSI DIGIVOX mini II V3.0 */ | ||
356 | static struct dvb_usb_rc_key af9015_rc_keys_msi[] = { | ||
357 | { 0x00, 0x1e, KEY_1 }, | ||
358 | { 0x00, 0x1f, KEY_2 }, | ||
359 | { 0x00, 0x20, KEY_3 }, | ||
360 | { 0x00, 0x21, KEY_4 }, | ||
361 | { 0x00, 0x22, KEY_5 }, | ||
362 | { 0x00, 0x23, KEY_6 }, | ||
363 | { 0x00, 0x24, KEY_7 }, | ||
364 | { 0x00, 0x25, KEY_8 }, | ||
365 | { 0x00, 0x26, KEY_9 }, | ||
366 | { 0x00, 0x27, KEY_0 }, | ||
367 | { 0x03, 0x0f, KEY_CHANNELUP }, | ||
368 | { 0x03, 0x0e, KEY_CHANNELDOWN }, | ||
369 | { 0x00, 0x42, KEY_VOLUMEDOWN }, | ||
370 | { 0x00, 0x43, KEY_VOLUMEUP }, | ||
371 | { 0x05, 0x45, KEY_POWER }, | ||
372 | { 0x00, 0x52, KEY_UP }, /* up */ | ||
373 | { 0x00, 0x51, KEY_DOWN }, /* down */ | ||
374 | { 0x00, 0x28, KEY_ENTER }, | ||
375 | }; | ||
376 | |||
377 | static u8 af9015_ir_table_msi[] = { | ||
378 | 0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */ | ||
379 | 0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */ | ||
380 | 0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */ | ||
381 | 0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */ | ||
382 | 0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */ | ||
383 | 0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */ | ||
384 | 0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */ | ||
385 | 0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */ | ||
386 | 0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */ | ||
387 | 0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */ | ||
388 | 0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */ | ||
389 | 0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */ | ||
390 | 0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */ | ||
391 | 0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */ | ||
392 | 0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */ | ||
393 | 0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */ | ||
394 | 0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */ | ||
395 | 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */ | ||
396 | }; | ||
397 | |||
398 | /* MYGICTV U718 */ | ||
399 | static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = { | ||
400 | { 0x00, 0x3d, KEY_SWITCHVIDEOMODE }, | ||
401 | /* TV / AV */ | ||
402 | { 0x05, 0x45, KEY_POWER }, | ||
403 | { 0x00, 0x1e, KEY_1 }, | ||
404 | { 0x00, 0x1f, KEY_2 }, | ||
405 | { 0x00, 0x20, KEY_3 }, | ||
406 | { 0x00, 0x21, KEY_4 }, | ||
407 | { 0x00, 0x22, KEY_5 }, | ||
408 | { 0x00, 0x23, KEY_6 }, | ||
409 | { 0x00, 0x24, KEY_7 }, | ||
410 | { 0x00, 0x25, KEY_8 }, | ||
411 | { 0x00, 0x26, KEY_9 }, | ||
412 | { 0x00, 0x27, KEY_0 }, | ||
413 | { 0x00, 0x41, KEY_MUTE }, | ||
414 | { 0x00, 0x2a, KEY_ESC }, /* Esc */ | ||
415 | { 0x00, 0x2e, KEY_CHANNELUP }, | ||
416 | { 0x00, 0x2d, KEY_CHANNELDOWN }, | ||
417 | { 0x00, 0x42, KEY_VOLUMEDOWN }, | ||
418 | { 0x00, 0x43, KEY_VOLUMEUP }, | ||
419 | { 0x00, 0x52, KEY_UP }, /* up arrow */ | ||
420 | { 0x00, 0x51, KEY_DOWN }, /* down arrow */ | ||
421 | { 0x00, 0x4f, KEY_RIGHT }, /* right arrow */ | ||
422 | { 0x00, 0x50, KEY_LEFT }, /* left arrow */ | ||
423 | { 0x00, 0x28, KEY_ENTER }, /* ok */ | ||
424 | { 0x01, 0x15, KEY_RECORD }, | ||
425 | { 0x03, 0x13, KEY_PLAY }, | ||
426 | { 0x01, 0x13, KEY_PAUSE }, | ||
427 | { 0x01, 0x16, KEY_STOP }, | ||
428 | { 0x03, 0x07, KEY_REWIND }, /* FR << */ | ||
429 | { 0x03, 0x09, KEY_FASTFORWARD }, /* FF >> */ | ||
430 | { 0x00, 0x3b, KEY_TIME }, /* TimeShift */ | ||
431 | { 0x00, 0x3e, KEY_CAMERA }, /* Snapshot */ | ||
432 | { 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */ | ||
433 | { 0x00, 0x00, KEY_ZOOM }, /* 'select' (?) */ | ||
434 | { 0x03, 0x16, KEY_SHUFFLE }, /* Shuffle */ | ||
435 | { 0x03, 0x45, KEY_POWER }, | ||
436 | }; | ||
437 | |||
438 | static u8 af9015_ir_table_mygictv[] = { | ||
439 | 0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */ | ||
440 | 0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */ | ||
441 | 0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */ | ||
442 | 0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */ | ||
443 | 0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */ | ||
444 | 0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */ | ||
445 | 0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */ | ||
446 | 0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */ | ||
447 | 0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */ | ||
448 | 0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */ | ||
449 | 0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */ | ||
450 | 0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */ | ||
451 | 0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */ | ||
452 | 0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */ | ||
453 | 0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */ | ||
454 | 0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */ | ||
455 | 0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */ | ||
456 | 0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */ | ||
457 | 0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */ | ||
458 | 0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */ | ||
459 | 0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */ | ||
460 | 0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */ | ||
461 | 0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */ | ||
462 | 0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */ | ||
463 | 0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */ | ||
464 | 0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */ | ||
465 | 0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */ | ||
466 | 0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */ | ||
467 | 0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */ | ||
468 | 0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */ | ||
469 | 0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */ | ||
470 | 0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */ | ||
471 | 0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */ | ||
472 | 0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */ | ||
473 | 0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */ | ||
474 | }; | ||
475 | |||
476 | /* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */ | ||
477 | static u8 af9015_ir_table_kworld[] = { | ||
478 | 0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00, | ||
479 | 0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00, | ||
480 | 0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00, | ||
481 | 0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00, | ||
482 | 0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00, | ||
483 | 0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00, | ||
484 | 0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00, | ||
485 | 0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00, | ||
486 | 0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00, | ||
487 | 0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00, | ||
488 | 0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00, | ||
489 | 0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00, | ||
490 | 0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00, | ||
491 | 0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00, | ||
492 | 0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00, | ||
493 | 0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00, | ||
494 | 0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00, | ||
495 | 0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00, | ||
496 | 0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00, | ||
497 | 0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00, | ||
498 | 0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00, | ||
499 | 0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00, | ||
500 | 0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00, | ||
501 | 0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00, | ||
502 | 0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00, | ||
503 | 0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00, | ||
504 | 0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00, | ||
505 | 0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00, | ||
506 | 0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00, | ||
507 | 0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00, | ||
508 | 0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00, | ||
509 | 0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00, | ||
510 | 0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00, | ||
511 | 0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00, | ||
512 | 0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00, | ||
513 | 0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00, | ||
514 | 0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00, | ||
515 | 0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00, | ||
516 | 0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00, | ||
517 | 0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00, | ||
518 | 0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00, | ||
519 | 0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00, | ||
520 | 0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00, | ||
521 | 0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00, | ||
522 | }; | ||
523 | |||
524 | #endif | ||
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 2f408d2e1ef3..c786359fba03 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c | |||
@@ -41,6 +41,9 @@ | |||
41 | static int dvb_usb_anysee_debug; | 41 | static int dvb_usb_anysee_debug; |
42 | module_param_named(debug, dvb_usb_anysee_debug, int, 0644); | 42 | module_param_named(debug, dvb_usb_anysee_debug, int, 0644); |
43 | MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); | 43 | MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); |
44 | int dvb_usb_anysee_delsys; | ||
45 | module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644); | ||
46 | MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)"); | ||
44 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 47 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
45 | 48 | ||
46 | static struct mutex anysee_usb_mutex; | 49 | static struct mutex anysee_usb_mutex; |
@@ -178,14 +181,14 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, | |||
178 | inc = 1; | 181 | inc = 1; |
179 | } | 182 | } |
180 | if (ret) | 183 | if (ret) |
181 | return ret; | 184 | break; |
182 | 185 | ||
183 | i += inc; | 186 | i += inc; |
184 | } | 187 | } |
185 | 188 | ||
186 | mutex_unlock(&d->i2c_mutex); | 189 | mutex_unlock(&d->i2c_mutex); |
187 | 190 | ||
188 | return i; | 191 | return ret ? ret : i; |
189 | } | 192 | } |
190 | 193 | ||
191 | static u32 anysee_i2c_func(struct i2c_adapter *adapter) | 194 | static u32 anysee_i2c_func(struct i2c_adapter *adapter) |
@@ -272,9 +275,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) | |||
272 | model demod hw firmware | 275 | model demod hw firmware |
273 | 1. E30 MT352 02 0.2.1 | 276 | 1. E30 MT352 02 0.2.1 |
274 | 2. E30 ZL10353 02 0.2.1 | 277 | 2. E30 ZL10353 02 0.2.1 |
275 | 3. E30 Plus ZL10353 06 0.1.0 | 278 | 3. E30 Combo ZL10353 0f 0.1.2 DVB-T/C combo |
276 | 4. E30C Plus TDA10023 0a 0.1.0 rev 0.2 | 279 | 4. E30 Plus ZL10353 06 0.1.0 |
277 | 4. E30C Plus TDA10023 0f 0.1.2 rev 0.4 | 280 | 5. E30C Plus TDA10023 0a 0.1.0 rev 0.2 |
281 | E30C Plus TDA10023 0f 0.1.2 rev 0.4 | ||
282 | E30 Combo TDA10023 0f 0.1.2 DVB-T/C combo | ||
278 | */ | 283 | */ |
279 | 284 | ||
280 | /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */ | 285 | /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */ |
@@ -293,6 +298,21 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) | |||
293 | return 0; | 298 | return 0; |
294 | } | 299 | } |
295 | 300 | ||
301 | /* for E30 Combo Plus DVB-T demodulator */ | ||
302 | if (dvb_usb_anysee_delsys) { | ||
303 | ret = anysee_write_reg(adap->dev, 0xb0, 0x01); | ||
304 | if (ret) | ||
305 | return ret; | ||
306 | |||
307 | /* Zarlink ZL10353 DVB-T demod */ | ||
308 | adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, | ||
309 | &adap->dev->i2c_adap); | ||
310 | if (adap->fe != NULL) { | ||
311 | state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A; | ||
312 | return 0; | ||
313 | } | ||
314 | } | ||
315 | |||
296 | /* connect demod on IO port D for TDA10023 & ZL10353 */ | 316 | /* connect demod on IO port D for TDA10023 & ZL10353 */ |
297 | ret = anysee_write_reg(adap->dev, 0xb0, 0x25); | 317 | ret = anysee_write_reg(adap->dev, 0xb0, 0x25); |
298 | if (ret) | 318 | if (ret) |
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c new file mode 100644 index 000000000000..3ac9f74e9fbf --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. | ||
3 | * | ||
4 | * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) | ||
5 | * | ||
6 | * Based on the dvb-usb-framework code and the | ||
7 | * original Terratec Cinergy T2 driver by: | ||
8 | * | ||
9 | * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and | ||
10 | * Holger Waechtler <holger@qanu.de> | ||
11 | * | ||
12 | * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include "cinergyT2.h" | ||
31 | |||
32 | |||
33 | /* debug */ | ||
34 | int dvb_usb_cinergyt2_debug; | ||
35 | int disable_remote; | ||
36 | |||
37 | module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); | ||
38 | MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " | ||
39 | "(or-able))."); | ||
40 | |||
41 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
42 | |||
43 | struct cinergyt2_state { | ||
44 | u8 rc_counter; | ||
45 | }; | ||
46 | |||
47 | /* We are missing a release hook with usb_device data */ | ||
48 | struct dvb_usb_device *cinergyt2_usb_device; | ||
49 | |||
50 | static struct dvb_usb_device_properties cinergyt2_properties; | ||
51 | |||
52 | static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) | ||
53 | { | ||
54 | char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; | ||
55 | char result[64]; | ||
56 | return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, | ||
57 | sizeof(result), 0); | ||
58 | } | ||
59 | |||
60 | static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) | ||
61 | { | ||
62 | char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; | ||
63 | char state[3]; | ||
64 | return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); | ||
65 | } | ||
66 | |||
67 | static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) | ||
68 | { | ||
69 | char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; | ||
70 | char state[3]; | ||
71 | int ret; | ||
72 | |||
73 | adap->fe = cinergyt2_fe_attach(adap->dev); | ||
74 | |||
75 | ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, | ||
76 | sizeof(state), 0); | ||
77 | if (ret < 0) { | ||
78 | deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " | ||
79 | "state info\n"); | ||
80 | } | ||
81 | |||
82 | /* Copy this pointer as we are gonna need it in the release phase */ | ||
83 | cinergyt2_usb_device = adap->dev; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static struct dvb_usb_rc_key cinergyt2_rc_keys[] = { | ||
89 | { 0x04, 0x01, KEY_POWER }, | ||
90 | { 0x04, 0x02, KEY_1 }, | ||
91 | { 0x04, 0x03, KEY_2 }, | ||
92 | { 0x04, 0x04, KEY_3 }, | ||
93 | { 0x04, 0x05, KEY_4 }, | ||
94 | { 0x04, 0x06, KEY_5 }, | ||
95 | { 0x04, 0x07, KEY_6 }, | ||
96 | { 0x04, 0x08, KEY_7 }, | ||
97 | { 0x04, 0x09, KEY_8 }, | ||
98 | { 0x04, 0x0a, KEY_9 }, | ||
99 | { 0x04, 0x0c, KEY_0 }, | ||
100 | { 0x04, 0x0b, KEY_VIDEO }, | ||
101 | { 0x04, 0x0d, KEY_REFRESH }, | ||
102 | { 0x04, 0x0e, KEY_SELECT }, | ||
103 | { 0x04, 0x0f, KEY_EPG }, | ||
104 | { 0x04, 0x10, KEY_UP }, | ||
105 | { 0x04, 0x14, KEY_DOWN }, | ||
106 | { 0x04, 0x11, KEY_LEFT }, | ||
107 | { 0x04, 0x13, KEY_RIGHT }, | ||
108 | { 0x04, 0x12, KEY_OK }, | ||
109 | { 0x04, 0x15, KEY_TEXT }, | ||
110 | { 0x04, 0x16, KEY_INFO }, | ||
111 | { 0x04, 0x17, KEY_RED }, | ||
112 | { 0x04, 0x18, KEY_GREEN }, | ||
113 | { 0x04, 0x19, KEY_YELLOW }, | ||
114 | { 0x04, 0x1a, KEY_BLUE }, | ||
115 | { 0x04, 0x1c, KEY_VOLUMEUP }, | ||
116 | { 0x04, 0x1e, KEY_VOLUMEDOWN }, | ||
117 | { 0x04, 0x1d, KEY_MUTE }, | ||
118 | { 0x04, 0x1b, KEY_CHANNELUP }, | ||
119 | { 0x04, 0x1f, KEY_CHANNELDOWN }, | ||
120 | { 0x04, 0x40, KEY_PAUSE }, | ||
121 | { 0x04, 0x4c, KEY_PLAY }, | ||
122 | { 0x04, 0x58, KEY_RECORD }, | ||
123 | { 0x04, 0x54, KEY_PREVIOUS }, | ||
124 | { 0x04, 0x48, KEY_STOP }, | ||
125 | { 0x04, 0x5c, KEY_NEXT } | ||
126 | }; | ||
127 | |||
128 | /* Number of keypresses to ignore before detect repeating */ | ||
129 | #define RC_REPEAT_DELAY 3 | ||
130 | |||
131 | static int repeatable_keys[] = { | ||
132 | KEY_UP, | ||
133 | KEY_DOWN, | ||
134 | KEY_LEFT, | ||
135 | KEY_RIGHT, | ||
136 | KEY_VOLUMEUP, | ||
137 | KEY_VOLUMEDOWN, | ||
138 | KEY_CHANNELUP, | ||
139 | KEY_CHANNELDOWN | ||
140 | }; | ||
141 | |||
142 | static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | ||
143 | { | ||
144 | struct cinergyt2_state *st = d->priv; | ||
145 | u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; | ||
146 | int i; | ||
147 | |||
148 | *state = REMOTE_NO_KEY_PRESSED; | ||
149 | |||
150 | dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); | ||
151 | if (key[4] == 0xff) { | ||
152 | /* key repeat */ | ||
153 | st->rc_counter++; | ||
154 | if (st->rc_counter > RC_REPEAT_DELAY) { | ||
155 | for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { | ||
156 | if (d->last_event == repeatable_keys[i]) { | ||
157 | *state = REMOTE_KEY_REPEAT; | ||
158 | *event = d->last_event; | ||
159 | deb_rc("repeat key, event %x\n", | ||
160 | *event); | ||
161 | return 0; | ||
162 | } | ||
163 | } | ||
164 | deb_rc("repeated key (non repeatable)\n"); | ||
165 | } | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* hack to pass checksum on the custom field */ | ||
170 | key[2] = ~key[1]; | ||
171 | dvb_usb_nec_rc_key_to_event(d, key, event, state); | ||
172 | if (key[0] != 0) { | ||
173 | if (*event != d->last_event) | ||
174 | st->rc_counter = 0; | ||
175 | |||
176 | deb_rc("key: %x %x %x %x %x\n", | ||
177 | key[0], key[1], key[2], key[3], key[4]); | ||
178 | } | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int cinergyt2_usb_probe(struct usb_interface *intf, | ||
183 | const struct usb_device_id *id) | ||
184 | { | ||
185 | return dvb_usb_device_init(intf, &cinergyt2_properties, | ||
186 | THIS_MODULE, NULL, adapter_nr); | ||
187 | } | ||
188 | |||
189 | |||
190 | static struct usb_device_id cinergyt2_usb_table[] = { | ||
191 | { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, | ||
192 | { 0 } | ||
193 | }; | ||
194 | |||
195 | MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); | ||
196 | |||
197 | static struct dvb_usb_device_properties cinergyt2_properties = { | ||
198 | .size_of_priv = sizeof(struct cinergyt2_state), | ||
199 | .num_adapters = 1, | ||
200 | .adapter = { | ||
201 | { | ||
202 | .streaming_ctrl = cinergyt2_streaming_ctrl, | ||
203 | .frontend_attach = cinergyt2_frontend_attach, | ||
204 | |||
205 | /* parameter for the MPEG2-data transfer */ | ||
206 | .stream = { | ||
207 | .type = USB_BULK, | ||
208 | .count = 5, | ||
209 | .endpoint = 0x02, | ||
210 | .u = { | ||
211 | .bulk = { | ||
212 | .buffersize = 512, | ||
213 | } | ||
214 | } | ||
215 | }, | ||
216 | } | ||
217 | }, | ||
218 | |||
219 | .power_ctrl = cinergyt2_power_ctrl, | ||
220 | |||
221 | .rc_interval = 50, | ||
222 | .rc_key_map = cinergyt2_rc_keys, | ||
223 | .rc_key_map_size = ARRAY_SIZE(cinergyt2_rc_keys), | ||
224 | .rc_query = cinergyt2_rc_query, | ||
225 | |||
226 | .generic_bulk_ctrl_endpoint = 1, | ||
227 | |||
228 | .num_device_descs = 1, | ||
229 | .devices = { | ||
230 | { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", | ||
231 | .cold_ids = {NULL}, | ||
232 | .warm_ids = { &cinergyt2_usb_table[0], NULL }, | ||
233 | }, | ||
234 | { NULL }, | ||
235 | } | ||
236 | }; | ||
237 | |||
238 | |||
239 | static struct usb_driver cinergyt2_driver = { | ||
240 | .name = "cinergyT2", | ||
241 | .probe = cinergyt2_usb_probe, | ||
242 | .disconnect = dvb_usb_device_exit, | ||
243 | .id_table = cinergyt2_usb_table | ||
244 | }; | ||
245 | |||
246 | static int __init cinergyt2_usb_init(void) | ||
247 | { | ||
248 | int err; | ||
249 | |||
250 | err = usb_register(&cinergyt2_driver); | ||
251 | if (err) { | ||
252 | err("usb_register() failed! (err %i)\n", err); | ||
253 | return err; | ||
254 | } | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static void __exit cinergyt2_usb_exit(void) | ||
259 | { | ||
260 | usb_deregister(&cinergyt2_driver); | ||
261 | } | ||
262 | |||
263 | module_init(cinergyt2_usb_init); | ||
264 | module_exit(cinergyt2_usb_exit); | ||
265 | |||
266 | MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); | ||
267 | MODULE_LICENSE("GPL"); | ||
268 | MODULE_AUTHOR("Tomi Orava"); | ||
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c new file mode 100644 index 000000000000..649f25cca49e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c | |||
@@ -0,0 +1,351 @@ | |||
1 | /* | ||
2 | * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. | ||
3 | * | ||
4 | * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) | ||
5 | * | ||
6 | * Based on the dvb-usb-framework code and the | ||
7 | * original Terratec Cinergy T2 driver by: | ||
8 | * | ||
9 | * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and | ||
10 | * Holger Waechtler <holger@qanu.de> | ||
11 | * | ||
12 | * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include "cinergyT2.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * convert linux-dvb frontend parameter set into TPS. | ||
35 | * See ETSI ETS-300744, section 4.6.2, table 9 for details. | ||
36 | * | ||
37 | * This function is probably reusable and may better get placed in a support | ||
38 | * library. | ||
39 | * | ||
40 | * We replace errornous fields by default TPS fields (the ones with value 0). | ||
41 | */ | ||
42 | |||
43 | static uint16_t compute_tps(struct dvb_frontend_parameters *p) | ||
44 | { | ||
45 | struct dvb_ofdm_parameters *op = &p->u.ofdm; | ||
46 | uint16_t tps = 0; | ||
47 | |||
48 | switch (op->code_rate_HP) { | ||
49 | case FEC_2_3: | ||
50 | tps |= (1 << 7); | ||
51 | break; | ||
52 | case FEC_3_4: | ||
53 | tps |= (2 << 7); | ||
54 | break; | ||
55 | case FEC_5_6: | ||
56 | tps |= (3 << 7); | ||
57 | break; | ||
58 | case FEC_7_8: | ||
59 | tps |= (4 << 7); | ||
60 | break; | ||
61 | case FEC_1_2: | ||
62 | case FEC_AUTO: | ||
63 | default: | ||
64 | /* tps |= (0 << 7) */; | ||
65 | } | ||
66 | |||
67 | switch (op->code_rate_LP) { | ||
68 | case FEC_2_3: | ||
69 | tps |= (1 << 4); | ||
70 | break; | ||
71 | case FEC_3_4: | ||
72 | tps |= (2 << 4); | ||
73 | break; | ||
74 | case FEC_5_6: | ||
75 | tps |= (3 << 4); | ||
76 | break; | ||
77 | case FEC_7_8: | ||
78 | tps |= (4 << 4); | ||
79 | break; | ||
80 | case FEC_1_2: | ||
81 | case FEC_AUTO: | ||
82 | default: | ||
83 | /* tps |= (0 << 4) */; | ||
84 | } | ||
85 | |||
86 | switch (op->constellation) { | ||
87 | case QAM_16: | ||
88 | tps |= (1 << 13); | ||
89 | break; | ||
90 | case QAM_64: | ||
91 | tps |= (2 << 13); | ||
92 | break; | ||
93 | case QPSK: | ||
94 | default: | ||
95 | /* tps |= (0 << 13) */; | ||
96 | } | ||
97 | |||
98 | switch (op->transmission_mode) { | ||
99 | case TRANSMISSION_MODE_8K: | ||
100 | tps |= (1 << 0); | ||
101 | break; | ||
102 | case TRANSMISSION_MODE_2K: | ||
103 | default: | ||
104 | /* tps |= (0 << 0) */; | ||
105 | } | ||
106 | |||
107 | switch (op->guard_interval) { | ||
108 | case GUARD_INTERVAL_1_16: | ||
109 | tps |= (1 << 2); | ||
110 | break; | ||
111 | case GUARD_INTERVAL_1_8: | ||
112 | tps |= (2 << 2); | ||
113 | break; | ||
114 | case GUARD_INTERVAL_1_4: | ||
115 | tps |= (3 << 2); | ||
116 | break; | ||
117 | case GUARD_INTERVAL_1_32: | ||
118 | default: | ||
119 | /* tps |= (0 << 2) */; | ||
120 | } | ||
121 | |||
122 | switch (op->hierarchy_information) { | ||
123 | case HIERARCHY_1: | ||
124 | tps |= (1 << 10); | ||
125 | break; | ||
126 | case HIERARCHY_2: | ||
127 | tps |= (2 << 10); | ||
128 | break; | ||
129 | case HIERARCHY_4: | ||
130 | tps |= (3 << 10); | ||
131 | break; | ||
132 | case HIERARCHY_NONE: | ||
133 | default: | ||
134 | /* tps |= (0 << 10) */; | ||
135 | } | ||
136 | |||
137 | return tps; | ||
138 | } | ||
139 | |||
140 | struct cinergyt2_fe_state { | ||
141 | struct dvb_frontend fe; | ||
142 | struct dvb_usb_device *d; | ||
143 | }; | ||
144 | |||
145 | static int cinergyt2_fe_read_status(struct dvb_frontend *fe, | ||
146 | fe_status_t *status) | ||
147 | { | ||
148 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
149 | struct dvbt_get_status_msg result; | ||
150 | u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; | ||
151 | int ret; | ||
152 | |||
153 | ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, | ||
154 | sizeof(result), 0); | ||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | *status = 0; | ||
159 | |||
160 | if (0xffff - le16_to_cpu(result.gain) > 30) | ||
161 | *status |= FE_HAS_SIGNAL; | ||
162 | if (result.lock_bits & (1 << 6)) | ||
163 | *status |= FE_HAS_LOCK; | ||
164 | if (result.lock_bits & (1 << 5)) | ||
165 | *status |= FE_HAS_SYNC; | ||
166 | if (result.lock_bits & (1 << 4)) | ||
167 | *status |= FE_HAS_CARRIER; | ||
168 | if (result.lock_bits & (1 << 1)) | ||
169 | *status |= FE_HAS_VITERBI; | ||
170 | |||
171 | if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != | ||
172 | (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) | ||
173 | *status &= ~FE_HAS_LOCK; | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
179 | { | ||
180 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
181 | struct dvbt_get_status_msg status; | ||
182 | char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; | ||
183 | int ret; | ||
184 | |||
185 | ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, | ||
186 | sizeof(status), 0); | ||
187 | if (ret < 0) | ||
188 | return ret; | ||
189 | |||
190 | *ber = le32_to_cpu(status.viterbi_error_rate); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) | ||
195 | { | ||
196 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
197 | struct dvbt_get_status_msg status; | ||
198 | u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; | ||
199 | int ret; | ||
200 | |||
201 | ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, | ||
202 | sizeof(status), 0); | ||
203 | if (ret < 0) { | ||
204 | err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", | ||
205 | ret); | ||
206 | return ret; | ||
207 | } | ||
208 | *unc = le32_to_cpu(status.uncorrected_block_count); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, | ||
213 | u16 *strength) | ||
214 | { | ||
215 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
216 | struct dvbt_get_status_msg status; | ||
217 | char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; | ||
218 | int ret; | ||
219 | |||
220 | ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, | ||
221 | sizeof(status), 0); | ||
222 | if (ret < 0) { | ||
223 | err("cinergyt2_fe_read_signal_strength() Failed!" | ||
224 | " (Error=%d)\n", ret); | ||
225 | return ret; | ||
226 | } | ||
227 | *strength = (0xffff - le16_to_cpu(status.gain)); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
232 | { | ||
233 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
234 | struct dvbt_get_status_msg status; | ||
235 | char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; | ||
236 | int ret; | ||
237 | |||
238 | ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, | ||
239 | sizeof(status), 0); | ||
240 | if (ret < 0) { | ||
241 | err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | *snr = (status.snr << 8) | status.snr; | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int cinergyt2_fe_init(struct dvb_frontend *fe) | ||
249 | { | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int cinergyt2_fe_sleep(struct dvb_frontend *fe) | ||
254 | { | ||
255 | deb_info("cinergyt2_fe_sleep() Called\n"); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, | ||
260 | struct dvb_frontend_tune_settings *tune) | ||
261 | { | ||
262 | tune->min_delay_ms = 800; | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, | ||
267 | struct dvb_frontend_parameters *fep) | ||
268 | { | ||
269 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
270 | struct dvbt_set_parameters_msg param; | ||
271 | char result[2]; | ||
272 | int err; | ||
273 | |||
274 | param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; | ||
275 | param.tps = cpu_to_le16(compute_tps(fep)); | ||
276 | param.freq = cpu_to_le32(fep->frequency / 1000); | ||
277 | param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; | ||
278 | |||
279 | err = dvb_usb_generic_rw(state->d, | ||
280 | (char *)¶m, sizeof(param), | ||
281 | result, sizeof(result), 0); | ||
282 | if (err < 0) | ||
283 | err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); | ||
284 | |||
285 | return (err < 0) ? err : 0; | ||
286 | } | ||
287 | |||
288 | static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe, | ||
289 | struct dvb_frontend_parameters *fep) | ||
290 | { | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static void cinergyt2_fe_release(struct dvb_frontend *fe) | ||
295 | { | ||
296 | struct cinergyt2_fe_state *state = fe->demodulator_priv; | ||
297 | if (state != NULL) | ||
298 | kfree(state); | ||
299 | } | ||
300 | |||
301 | static struct dvb_frontend_ops cinergyt2_fe_ops; | ||
302 | |||
303 | struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) | ||
304 | { | ||
305 | struct cinergyt2_fe_state *s = kzalloc(sizeof( | ||
306 | struct cinergyt2_fe_state), GFP_KERNEL); | ||
307 | if (s == NULL) | ||
308 | return NULL; | ||
309 | |||
310 | s->d = d; | ||
311 | memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); | ||
312 | s->fe.demodulator_priv = s; | ||
313 | return &s->fe; | ||
314 | } | ||
315 | |||
316 | |||
317 | static struct dvb_frontend_ops cinergyt2_fe_ops = { | ||
318 | .info = { | ||
319 | .name = DRIVER_NAME, | ||
320 | .type = FE_OFDM, | ||
321 | .frequency_min = 174000000, | ||
322 | .frequency_max = 862000000, | ||
323 | .frequency_stepsize = 166667, | ||
324 | .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | ||
325 | | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | ||
326 | | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | ||
327 | | FE_CAN_FEC_AUTO | FE_CAN_QPSK | ||
328 | | FE_CAN_QAM_16 | FE_CAN_QAM_64 | ||
329 | | FE_CAN_QAM_AUTO | ||
330 | | FE_CAN_TRANSMISSION_MODE_AUTO | ||
331 | | FE_CAN_GUARD_INTERVAL_AUTO | ||
332 | | FE_CAN_HIERARCHY_AUTO | ||
333 | | FE_CAN_RECOVER | ||
334 | | FE_CAN_MUTE_TS | ||
335 | }, | ||
336 | |||
337 | .release = cinergyt2_fe_release, | ||
338 | |||
339 | .init = cinergyt2_fe_init, | ||
340 | .sleep = cinergyt2_fe_sleep, | ||
341 | |||
342 | .set_frontend = cinergyt2_fe_set_frontend, | ||
343 | .get_frontend = cinergyt2_fe_get_frontend, | ||
344 | .get_tune_settings = cinergyt2_fe_get_tune_settings, | ||
345 | |||
346 | .read_status = cinergyt2_fe_read_status, | ||
347 | .read_ber = cinergyt2_fe_read_ber, | ||
348 | .read_signal_strength = cinergyt2_fe_read_signal_strength, | ||
349 | .read_snr = cinergyt2_fe_read_snr, | ||
350 | .read_ucblocks = cinergyt2_fe_read_unc_blocks, | ||
351 | }; | ||
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h new file mode 100644 index 000000000000..11d79eb384c8 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cinergyT2.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. | ||
3 | * | ||
4 | * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) | ||
5 | * | ||
6 | * Based on the dvb-usb-framework code and the | ||
7 | * original Terratec Cinergy T2 driver by: | ||
8 | * | ||
9 | * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and | ||
10 | * Holger Waechtler <holger@qanu.de> | ||
11 | * | ||
12 | * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #ifndef _DVB_USB_CINERGYT2_H_ | ||
31 | #define _DVB_USB_CINERGYT2_H_ | ||
32 | |||
33 | #include <linux/usb/input.h> | ||
34 | |||
35 | #define DVB_USB_LOG_PREFIX "cinergyT2" | ||
36 | #include "dvb-usb.h" | ||
37 | |||
38 | #define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" | ||
39 | |||
40 | extern int dvb_usb_cinergyt2_debug; | ||
41 | |||
42 | #define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args) | ||
43 | #define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args) | ||
44 | #define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args) | ||
45 | #define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args) | ||
46 | #define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args) | ||
47 | #define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args) | ||
48 | #define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args) | ||
49 | #define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args) | ||
50 | #define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args) | ||
51 | |||
52 | |||
53 | |||
54 | enum cinergyt2_ep1_cmd { | ||
55 | CINERGYT2_EP1_PID_TABLE_RESET = 0x01, | ||
56 | CINERGYT2_EP1_PID_SETUP = 0x02, | ||
57 | CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, | ||
58 | CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, | ||
59 | CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, | ||
60 | CINERGYT2_EP1_START_SCAN = 0x06, | ||
61 | CINERGYT2_EP1_CONTINUE_SCAN = 0x07, | ||
62 | CINERGYT2_EP1_GET_RC_EVENTS = 0x08, | ||
63 | CINERGYT2_EP1_SLEEP_MODE = 0x09, | ||
64 | CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A | ||
65 | }; | ||
66 | |||
67 | |||
68 | struct dvbt_get_status_msg { | ||
69 | uint32_t freq; | ||
70 | uint8_t bandwidth; | ||
71 | uint16_t tps; | ||
72 | uint8_t flags; | ||
73 | uint16_t gain; | ||
74 | uint8_t snr; | ||
75 | uint32_t viterbi_error_rate; | ||
76 | uint32_t rs_error_rate; | ||
77 | uint32_t uncorrected_block_count; | ||
78 | uint8_t lock_bits; | ||
79 | uint8_t prev_lock_bits; | ||
80 | } __attribute__((packed)); | ||
81 | |||
82 | |||
83 | struct dvbt_set_parameters_msg { | ||
84 | uint8_t cmd; | ||
85 | uint32_t freq; | ||
86 | uint8_t bandwidth; | ||
87 | uint16_t tps; | ||
88 | uint8_t flags; | ||
89 | } __attribute__((packed)); | ||
90 | |||
91 | |||
92 | extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d); | ||
93 | |||
94 | #endif /* _DVB_USB_CINERGYT2_H_ */ | ||
95 | |||
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 563400277a42..406d7fba369d 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c | |||
@@ -36,6 +36,9 @@ | |||
36 | #include "tuner-xc2028.h" | 36 | #include "tuner-xc2028.h" |
37 | #include "tuner-simple.h" | 37 | #include "tuner-simple.h" |
38 | #include "mxl5005s.h" | 38 | #include "mxl5005s.h" |
39 | #include "dib7000p.h" | ||
40 | #include "dib0070.h" | ||
41 | #include "lgs8gl5.h" | ||
39 | 42 | ||
40 | /* debug */ | 43 | /* debug */ |
41 | static int dvb_usb_cxusb_debug; | 44 | static int dvb_usb_cxusb_debug; |
@@ -109,6 +112,25 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) | |||
109 | cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); | 112 | cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); |
110 | } | 113 | } |
111 | 114 | ||
115 | static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, | ||
116 | u8 addr, int onoff) | ||
117 | { | ||
118 | u8 o[2] = {addr, onoff}; | ||
119 | u8 i; | ||
120 | int rc; | ||
121 | |||
122 | rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); | ||
123 | |||
124 | if (rc < 0) | ||
125 | return rc; | ||
126 | if (i == 0x01) | ||
127 | return 0; | ||
128 | else { | ||
129 | deb_info("gpio_write failed.\n"); | ||
130 | return -EIO; | ||
131 | } | ||
132 | } | ||
133 | |||
112 | /* I2C */ | 134 | /* I2C */ |
113 | static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 135 | static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
114 | int num) | 136 | int num) |
@@ -262,6 +284,20 @@ static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) | |||
262 | return rc; | 284 | return rc; |
263 | } | 285 | } |
264 | 286 | ||
287 | static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
288 | { | ||
289 | int ret; | ||
290 | u8 b; | ||
291 | ret = cxusb_power_ctrl(d, onoff); | ||
292 | if (!onoff) | ||
293 | return ret; | ||
294 | |||
295 | msleep(128); | ||
296 | cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); | ||
297 | msleep(100); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
265 | static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | 301 | static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) |
266 | { | 302 | { |
267 | u8 buf[2] = { 0x03, 0x00 }; | 303 | u8 buf[2] = { 0x03, 0x00 }; |
@@ -283,6 +319,67 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
283 | return 0; | 319 | return 0; |
284 | } | 320 | } |
285 | 321 | ||
322 | static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) | ||
323 | { | ||
324 | int ep = d->props.generic_bulk_ctrl_endpoint; | ||
325 | const int timeout = 100; | ||
326 | const int junk_len = 32; | ||
327 | u8 *junk; | ||
328 | int rd_count; | ||
329 | |||
330 | /* Discard remaining data in video pipe */ | ||
331 | junk = kmalloc(junk_len, GFP_KERNEL); | ||
332 | if (!junk) | ||
333 | return; | ||
334 | while (1) { | ||
335 | if (usb_bulk_msg(d->udev, | ||
336 | usb_rcvbulkpipe(d->udev, ep), | ||
337 | junk, junk_len, &rd_count, timeout) < 0) | ||
338 | break; | ||
339 | if (!rd_count) | ||
340 | break; | ||
341 | } | ||
342 | kfree(junk); | ||
343 | } | ||
344 | |||
345 | static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) | ||
346 | { | ||
347 | struct usb_data_stream_properties *p = &d->props.adapter[0].stream; | ||
348 | const int timeout = 100; | ||
349 | const int junk_len = p->u.bulk.buffersize; | ||
350 | u8 *junk; | ||
351 | int rd_count; | ||
352 | |||
353 | /* Discard remaining data in video pipe */ | ||
354 | junk = kmalloc(junk_len, GFP_KERNEL); | ||
355 | if (!junk) | ||
356 | return; | ||
357 | while (1) { | ||
358 | if (usb_bulk_msg(d->udev, | ||
359 | usb_rcvbulkpipe(d->udev, p->endpoint), | ||
360 | junk, junk_len, &rd_count, timeout) < 0) | ||
361 | break; | ||
362 | if (!rd_count) | ||
363 | break; | ||
364 | } | ||
365 | kfree(junk); | ||
366 | } | ||
367 | |||
368 | static int cxusb_d680_dmb_streaming_ctrl( | ||
369 | struct dvb_usb_adapter *adap, int onoff) | ||
370 | { | ||
371 | if (onoff) { | ||
372 | u8 buf[2] = { 0x03, 0x00 }; | ||
373 | cxusb_d680_dmb_drain_video(adap->dev); | ||
374 | return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, | ||
375 | buf, sizeof(buf), NULL, 0); | ||
376 | } else { | ||
377 | int ret = cxusb_ctrl_msg(adap->dev, | ||
378 | CMD_STREAMING_OFF, NULL, 0, NULL, 0); | ||
379 | return ret; | ||
380 | } | ||
381 | } | ||
382 | |||
286 | static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | 383 | static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) |
287 | { | 384 | { |
288 | struct dvb_usb_rc_key *keymap = d->props.rc_key_map; | 385 | 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, | |||
335 | return 0; | 432 | return 0; |
336 | } | 433 | } |
337 | 434 | ||
435 | static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, | ||
436 | int *state) | ||
437 | { | ||
438 | struct dvb_usb_rc_key *keymap = d->props.rc_key_map; | ||
439 | u8 ircode[2]; | ||
440 | int i; | ||
441 | |||
442 | *event = 0; | ||
443 | *state = REMOTE_NO_KEY_PRESSED; | ||
444 | |||
445 | if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) | ||
446 | return 0; | ||
447 | |||
448 | for (i = 0; i < d->props.rc_key_map_size; i++) { | ||
449 | if (keymap[i].custom == ircode[0] && | ||
450 | keymap[i].data == ircode[1]) { | ||
451 | *event = keymap[i].event; | ||
452 | *state = REMOTE_KEY_PRESSED; | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
338 | static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { | 461 | static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { |
339 | { 0xfe, 0x02, KEY_TV }, | 462 | { 0xfe, 0x02, KEY_TV }, |
340 | { 0xfe, 0x0e, KEY_MP3 }, | 463 | { 0xfe, 0x0e, KEY_MP3 }, |
@@ -422,6 +545,44 @@ static struct dvb_usb_rc_key dvico_portable_rc_keys[] = { | |||
422 | { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ | 545 | { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ |
423 | }; | 546 | }; |
424 | 547 | ||
548 | static struct dvb_usb_rc_key d680_dmb_rc_keys[] = { | ||
549 | { 0x00, 0x38, KEY_UNKNOWN }, /* TV/AV */ | ||
550 | { 0x08, 0x0c, KEY_ZOOM }, | ||
551 | { 0x08, 0x00, KEY_0 }, | ||
552 | { 0x00, 0x01, KEY_1 }, | ||
553 | { 0x08, 0x02, KEY_2 }, | ||
554 | { 0x00, 0x03, KEY_3 }, | ||
555 | { 0x08, 0x04, KEY_4 }, | ||
556 | { 0x00, 0x05, KEY_5 }, | ||
557 | { 0x08, 0x06, KEY_6 }, | ||
558 | { 0x00, 0x07, KEY_7 }, | ||
559 | { 0x08, 0x08, KEY_8 }, | ||
560 | { 0x00, 0x09, KEY_9 }, | ||
561 | { 0x00, 0x0a, KEY_MUTE }, | ||
562 | { 0x08, 0x29, KEY_BACK }, | ||
563 | { 0x00, 0x12, KEY_CHANNELUP }, | ||
564 | { 0x08, 0x13, KEY_CHANNELDOWN }, | ||
565 | { 0x00, 0x2b, KEY_VOLUMEUP }, | ||
566 | { 0x08, 0x2c, KEY_VOLUMEDOWN }, | ||
567 | { 0x00, 0x20, KEY_UP }, | ||
568 | { 0x08, 0x21, KEY_DOWN }, | ||
569 | { 0x00, 0x11, KEY_LEFT }, | ||
570 | { 0x08, 0x10, KEY_RIGHT }, | ||
571 | { 0x00, 0x0d, KEY_OK }, | ||
572 | { 0x08, 0x1f, KEY_RECORD }, | ||
573 | { 0x00, 0x17, KEY_PLAYPAUSE }, | ||
574 | { 0x08, 0x16, KEY_PLAYPAUSE }, | ||
575 | { 0x00, 0x0b, KEY_STOP }, | ||
576 | { 0x08, 0x27, KEY_FASTFORWARD }, | ||
577 | { 0x00, 0x26, KEY_REWIND }, | ||
578 | { 0x08, 0x1e, KEY_UNKNOWN }, /* Time Shift */ | ||
579 | { 0x00, 0x0e, KEY_UNKNOWN }, /* Snapshot */ | ||
580 | { 0x08, 0x2d, KEY_UNKNOWN }, /* Mouse Cursor */ | ||
581 | { 0x00, 0x0f, KEY_UNKNOWN }, /* Minimize/Maximize */ | ||
582 | { 0x08, 0x14, KEY_UNKNOWN }, /* Shuffle */ | ||
583 | { 0x00, 0x25, KEY_POWER }, | ||
584 | }; | ||
585 | |||
425 | static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) | 586 | static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) |
426 | { | 587 | { |
427 | static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; | 588 | static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; |
@@ -527,6 +688,24 @@ static struct mxl5005s_config aver_a868r_tuner = { | |||
527 | .AgcMasterByte = 0x00, | 688 | .AgcMasterByte = 0x00, |
528 | }; | 689 | }; |
529 | 690 | ||
691 | /* FIXME: needs tweaking */ | ||
692 | static struct mxl5005s_config d680_dmb_tuner = { | ||
693 | .i2c_address = 0x63, | ||
694 | .if_freq = 36125000UL, | ||
695 | .xtal_freq = CRYSTAL_FREQ_16000000HZ, | ||
696 | .agc_mode = MXL_SINGLE_AGC, | ||
697 | .tracking_filter = MXL_TF_C, | ||
698 | .rssi_enable = MXL_RSSI_ENABLE, | ||
699 | .cap_select = MXL_CAP_SEL_ENABLE, | ||
700 | .div_out = MXL_DIV_OUT_4, | ||
701 | .clock_out = MXL_CLOCK_OUT_DISABLE, | ||
702 | .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, | ||
703 | .top = MXL5005S_TOP_25P2, | ||
704 | .mod_mode = MXL_DIGITAL_MODE, | ||
705 | .if_mode = MXL_ZERO_IF, | ||
706 | .AgcMasterByte = 0x00, | ||
707 | }; | ||
708 | |||
530 | /* Callbacks for DVB USB */ | 709 | /* Callbacks for DVB USB */ |
531 | static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) | 710 | static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) |
532 | { | 711 | { |
@@ -563,7 +742,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) | |||
563 | return 0; | 742 | return 0; |
564 | } | 743 | } |
565 | 744 | ||
566 | static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) | 745 | static int dvico_bluebird_xc2028_callback(void *ptr, int component, |
746 | int command, int arg) | ||
567 | { | 747 | { |
568 | struct dvb_usb_adapter *adap = ptr; | 748 | struct dvb_usb_adapter *adap = ptr; |
569 | struct dvb_usb_device *d = adap->dev; | 749 | struct dvb_usb_device *d = adap->dev; |
@@ -591,14 +771,16 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) | |||
591 | struct xc2028_config cfg = { | 771 | struct xc2028_config cfg = { |
592 | .i2c_adap = &adap->dev->i2c_adap, | 772 | .i2c_adap = &adap->dev->i2c_adap, |
593 | .i2c_addr = 0x61, | 773 | .i2c_addr = 0x61, |
594 | .callback = dvico_bluebird_xc2028_callback, | ||
595 | }; | 774 | }; |
596 | static struct xc2028_ctrl ctl = { | 775 | static struct xc2028_ctrl ctl = { |
597 | .fname = "xc3028-v27.fw", | 776 | .fname = XC2028_DEFAULT_FIRMWARE, |
598 | .max_len = 64, | 777 | .max_len = 64, |
599 | .demod = XC3028_FE_ZARLINK456, | 778 | .demod = XC3028_FE_ZARLINK456, |
600 | }; | 779 | }; |
601 | 780 | ||
781 | /* FIXME: generalize & move to common area */ | ||
782 | adap->fe->callback = dvico_bluebird_xc2028_callback; | ||
783 | |||
602 | fe = dvb_attach(xc2028_attach, adap->fe, &cfg); | 784 | fe = dvb_attach(xc2028_attach, adap->fe, &cfg); |
603 | if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) | 785 | if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) |
604 | return -EIO; | 786 | return -EIO; |
@@ -615,6 +797,14 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) | |||
615 | return 0; | 797 | return 0; |
616 | } | 798 | } |
617 | 799 | ||
800 | static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) | ||
801 | { | ||
802 | struct dvb_frontend *fe; | ||
803 | fe = dvb_attach(mxl5005s_attach, adap->fe, | ||
804 | &adap->dev->i2c_adap, &d680_dmb_tuner); | ||
805 | return (fe == NULL) ? -EIO : 0; | ||
806 | } | ||
807 | |||
618 | static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) | 808 | static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) |
619 | { | 809 | { |
620 | u8 b; | 810 | u8 b; |
@@ -726,6 +916,159 @@ no_IR: | |||
726 | return 0; | 916 | return 0; |
727 | } | 917 | } |
728 | 918 | ||
919 | static struct dibx000_agc_config dib7070_agc_config = { | ||
920 | .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, | ||
921 | |||
922 | /* | ||
923 | * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, | ||
924 | * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, | ||
925 | * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 | ||
926 | */ | ||
927 | .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | | ||
928 | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), | ||
929 | .inv_gain = 600, | ||
930 | .time_stabiliz = 10, | ||
931 | .alpha_level = 0, | ||
932 | .thlock = 118, | ||
933 | .wbd_inv = 0, | ||
934 | .wbd_ref = 3530, | ||
935 | .wbd_sel = 1, | ||
936 | .wbd_alpha = 5, | ||
937 | .agc1_max = 65535, | ||
938 | .agc1_min = 0, | ||
939 | .agc2_max = 65535, | ||
940 | .agc2_min = 0, | ||
941 | .agc1_pt1 = 0, | ||
942 | .agc1_pt2 = 40, | ||
943 | .agc1_pt3 = 183, | ||
944 | .agc1_slope1 = 206, | ||
945 | .agc1_slope2 = 255, | ||
946 | .agc2_pt1 = 72, | ||
947 | .agc2_pt2 = 152, | ||
948 | .agc2_slope1 = 88, | ||
949 | .agc2_slope2 = 90, | ||
950 | .alpha_mant = 17, | ||
951 | .alpha_exp = 27, | ||
952 | .beta_mant = 23, | ||
953 | .beta_exp = 51, | ||
954 | .perform_agc_softsplit = 0, | ||
955 | }; | ||
956 | |||
957 | static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { | ||
958 | .internal = 60000, | ||
959 | .sampling = 15000, | ||
960 | .pll_prediv = 1, | ||
961 | .pll_ratio = 20, | ||
962 | .pll_range = 3, | ||
963 | .pll_reset = 1, | ||
964 | .pll_bypass = 0, | ||
965 | .enable_refdiv = 0, | ||
966 | .bypclk_div = 0, | ||
967 | .IO_CLK_en_core = 1, | ||
968 | .ADClkSrc = 1, | ||
969 | .modulo = 2, | ||
970 | /* refsel, sel, freq_15k */ | ||
971 | .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), | ||
972 | .ifreq = (0 << 25) | 0, | ||
973 | .timf = 20452225, | ||
974 | .xtal_hz = 12000000, | ||
975 | }; | ||
976 | |||
977 | static struct dib7000p_config cxusb_dualdig4_rev2_config = { | ||
978 | .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, | ||
979 | .output_mpeg2_in_188_bytes = 1, | ||
980 | |||
981 | .agc_config_count = 1, | ||
982 | .agc = &dib7070_agc_config, | ||
983 | .bw = &dib7070_bw_config_12_mhz, | ||
984 | .tuner_is_baseband = 1, | ||
985 | .spur_protect = 1, | ||
986 | |||
987 | .gpio_dir = 0xfcef, | ||
988 | .gpio_val = 0x0110, | ||
989 | |||
990 | .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, | ||
991 | |||
992 | .hostbus_diversity = 1, | ||
993 | }; | ||
994 | |||
995 | static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) | ||
996 | { | ||
997 | if (usb_set_interface(adap->dev->udev, 0, 1) < 0) | ||
998 | err("set interface failed"); | ||
999 | |||
1000 | cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); | ||
1001 | |||
1002 | cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); | ||
1003 | |||
1004 | dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, | ||
1005 | &cxusb_dualdig4_rev2_config); | ||
1006 | |||
1007 | adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, | ||
1008 | &cxusb_dualdig4_rev2_config); | ||
1009 | if (adap->fe == NULL) | ||
1010 | return -EIO; | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) | ||
1016 | { | ||
1017 | return dib7000p_set_gpio(fe, 8, 0, !onoff); | ||
1018 | } | ||
1019 | |||
1020 | static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) | ||
1021 | { | ||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static struct dib0070_config dib7070p_dib0070_config = { | ||
1026 | .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, | ||
1027 | .reset = dib7070_tuner_reset, | ||
1028 | .sleep = dib7070_tuner_sleep, | ||
1029 | .clock_khz = 12000, | ||
1030 | }; | ||
1031 | |||
1032 | struct dib0700_adapter_state { | ||
1033 | int (*set_param_save) (struct dvb_frontend *, | ||
1034 | struct dvb_frontend_parameters *); | ||
1035 | }; | ||
1036 | |||
1037 | static int dib7070_set_param_override(struct dvb_frontend *fe, | ||
1038 | struct dvb_frontend_parameters *fep) | ||
1039 | { | ||
1040 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
1041 | struct dib0700_adapter_state *state = adap->priv; | ||
1042 | |||
1043 | u16 offset; | ||
1044 | u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); | ||
1045 | switch (band) { | ||
1046 | case BAND_VHF: offset = 950; break; | ||
1047 | default: | ||
1048 | case BAND_UHF: offset = 550; break; | ||
1049 | } | ||
1050 | |||
1051 | dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); | ||
1052 | |||
1053 | return state->set_param_save(fe, fep); | ||
1054 | } | ||
1055 | |||
1056 | static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) | ||
1057 | { | ||
1058 | struct dib0700_adapter_state *st = adap->priv; | ||
1059 | struct i2c_adapter *tun_i2c = | ||
1060 | dib7000p_get_i2c_master(adap->fe, | ||
1061 | DIBX000_I2C_INTERFACE_TUNER, 1); | ||
1062 | |||
1063 | if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, | ||
1064 | &dib7070p_dib0070_config) == NULL) | ||
1065 | return -ENODEV; | ||
1066 | |||
1067 | st->set_param_save = adap->fe->ops.tuner_ops.set_params; | ||
1068 | adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; | ||
1069 | return 0; | ||
1070 | } | ||
1071 | |||
729 | static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) | 1072 | static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) |
730 | { | 1073 | { |
731 | if (usb_set_interface(adap->dev->udev, 0, 1) < 0) | 1074 | 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) | |||
751 | return -EIO; | 1094 | return -EIO; |
752 | } | 1095 | } |
753 | 1096 | ||
1097 | static struct lgs8gl5_config lgs8gl5_cfg = { | ||
1098 | .demod_address = 0x19, | ||
1099 | }; | ||
1100 | |||
1101 | static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) | ||
1102 | { | ||
1103 | struct dvb_usb_device *d = adap->dev; | ||
1104 | int n; | ||
1105 | |||
1106 | /* Select required USB configuration */ | ||
1107 | if (usb_set_interface(d->udev, 0, 0) < 0) | ||
1108 | err("set interface failed"); | ||
1109 | |||
1110 | /* Unblock all USB pipes */ | ||
1111 | usb_clear_halt(d->udev, | ||
1112 | usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); | ||
1113 | usb_clear_halt(d->udev, | ||
1114 | usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); | ||
1115 | usb_clear_halt(d->udev, | ||
1116 | usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); | ||
1117 | |||
1118 | /* Drain USB pipes to avoid hang after reboot */ | ||
1119 | for (n = 0; n < 5; n++) { | ||
1120 | cxusb_d680_dmb_drain_message(d); | ||
1121 | cxusb_d680_dmb_drain_video(d); | ||
1122 | msleep(200); | ||
1123 | } | ||
1124 | |||
1125 | /* Reset the tuner */ | ||
1126 | if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { | ||
1127 | err("clear tuner gpio failed"); | ||
1128 | return -EIO; | ||
1129 | } | ||
1130 | msleep(100); | ||
1131 | if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { | ||
1132 | err("set tuner gpio failed"); | ||
1133 | return -EIO; | ||
1134 | } | ||
1135 | msleep(100); | ||
1136 | |||
1137 | /* Attach frontend */ | ||
1138 | adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap); | ||
1139 | if (adap->fe == NULL) | ||
1140 | return -EIO; | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
754 | /* | 1145 | /* |
755 | * DViCO has shipped two devices with the same USB ID, but only one of them | 1146 | * DViCO has shipped two devices with the same USB ID, but only one of them |
756 | * needs a firmware download. Check the device class details to see if they | 1147 | * 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; | |||
826 | static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; | 1217 | static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; |
827 | static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; | 1218 | static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; |
828 | static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; | 1219 | static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; |
1220 | static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; | ||
829 | static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; | 1221 | static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; |
830 | static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; | 1222 | static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; |
831 | static struct dvb_usb_device_properties cxusb_aver_a868r_properties; | 1223 | static struct dvb_usb_device_properties cxusb_aver_a868r_properties; |
1224 | static struct dvb_usb_device_properties cxusb_d680_dmb_properties; | ||
832 | 1225 | ||
833 | static int cxusb_probe(struct usb_interface *intf, | 1226 | static int cxusb_probe(struct usb_interface *intf, |
834 | const struct usb_device_id *id) | 1227 | const struct usb_device_id *id) |
@@ -852,6 +1245,11 @@ static int cxusb_probe(struct usb_interface *intf, | |||
852 | THIS_MODULE, NULL, adapter_nr) || | 1245 | THIS_MODULE, NULL, adapter_nr) || |
853 | 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, | 1246 | 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, |
854 | THIS_MODULE, NULL, adapter_nr) || | 1247 | THIS_MODULE, NULL, adapter_nr) || |
1248 | 0 == dvb_usb_device_init(intf, | ||
1249 | &cxusb_bluebird_dualdig4_rev2_properties, | ||
1250 | THIS_MODULE, NULL, adapter_nr) || | ||
1251 | 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, | ||
1252 | THIS_MODULE, NULL, adapter_nr) || | ||
855 | 0) | 1253 | 0) |
856 | return 0; | 1254 | return 0; |
857 | 1255 | ||
@@ -876,6 +1274,8 @@ static struct usb_device_id cxusb_table [] = { | |||
876 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, | 1274 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, |
877 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, | 1275 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, |
878 | { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, | 1276 | { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, |
1277 | { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, | ||
1278 | { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, | ||
879 | {} /* Terminating entry */ | 1279 | {} /* Terminating entry */ |
880 | }; | 1280 | }; |
881 | MODULE_DEVICE_TABLE (usb, cxusb_table); | 1281 | MODULE_DEVICE_TABLE (usb, cxusb_table); |
@@ -1321,6 +1721,104 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { | |||
1321 | } | 1721 | } |
1322 | }; | 1722 | }; |
1323 | 1723 | ||
1724 | static | ||
1725 | struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { | ||
1726 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
1727 | |||
1728 | .usb_ctrl = CYPRESS_FX2, | ||
1729 | |||
1730 | .size_of_priv = sizeof(struct cxusb_state), | ||
1731 | |||
1732 | .num_adapters = 1, | ||
1733 | .adapter = { | ||
1734 | { | ||
1735 | .streaming_ctrl = cxusb_streaming_ctrl, | ||
1736 | .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, | ||
1737 | .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, | ||
1738 | .size_of_priv = sizeof(struct dib0700_adapter_state), | ||
1739 | /* parameter for the MPEG2-data transfer */ | ||
1740 | .stream = { | ||
1741 | .type = USB_BULK, | ||
1742 | .count = 7, | ||
1743 | .endpoint = 0x02, | ||
1744 | .u = { | ||
1745 | .bulk = { | ||
1746 | .buffersize = 4096, | ||
1747 | } | ||
1748 | } | ||
1749 | }, | ||
1750 | }, | ||
1751 | }, | ||
1752 | |||
1753 | .power_ctrl = cxusb_bluebird_power_ctrl, | ||
1754 | |||
1755 | .i2c_algo = &cxusb_i2c_algo, | ||
1756 | |||
1757 | .generic_bulk_ctrl_endpoint = 0x01, | ||
1758 | |||
1759 | .rc_interval = 100, | ||
1760 | .rc_key_map = dvico_mce_rc_keys, | ||
1761 | .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), | ||
1762 | .rc_query = cxusb_rc_query, | ||
1763 | |||
1764 | .num_device_descs = 1, | ||
1765 | .devices = { | ||
1766 | { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", | ||
1767 | { NULL }, | ||
1768 | { &cxusb_table[17], NULL }, | ||
1769 | }, | ||
1770 | } | ||
1771 | }; | ||
1772 | |||
1773 | static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { | ||
1774 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
1775 | |||
1776 | .usb_ctrl = CYPRESS_FX2, | ||
1777 | |||
1778 | .size_of_priv = sizeof(struct cxusb_state), | ||
1779 | |||
1780 | .num_adapters = 1, | ||
1781 | .adapter = { | ||
1782 | { | ||
1783 | .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, | ||
1784 | .frontend_attach = cxusb_d680_dmb_frontend_attach, | ||
1785 | .tuner_attach = cxusb_d680_dmb_tuner_attach, | ||
1786 | |||
1787 | /* parameter for the MPEG2-data transfer */ | ||
1788 | .stream = { | ||
1789 | .type = USB_BULK, | ||
1790 | .count = 5, | ||
1791 | .endpoint = 0x02, | ||
1792 | .u = { | ||
1793 | .bulk = { | ||
1794 | .buffersize = 8192, | ||
1795 | } | ||
1796 | } | ||
1797 | }, | ||
1798 | }, | ||
1799 | }, | ||
1800 | |||
1801 | .power_ctrl = cxusb_d680_dmb_power_ctrl, | ||
1802 | |||
1803 | .i2c_algo = &cxusb_i2c_algo, | ||
1804 | |||
1805 | .generic_bulk_ctrl_endpoint = 0x01, | ||
1806 | |||
1807 | .rc_interval = 100, | ||
1808 | .rc_key_map = d680_dmb_rc_keys, | ||
1809 | .rc_key_map_size = ARRAY_SIZE(d680_dmb_rc_keys), | ||
1810 | .rc_query = cxusb_d680_dmb_rc_query, | ||
1811 | |||
1812 | .num_device_descs = 1, | ||
1813 | .devices = { | ||
1814 | { | ||
1815 | "Conexant DMB-TH Stick", | ||
1816 | { NULL }, | ||
1817 | { &cxusb_table[18], NULL }, | ||
1818 | }, | ||
1819 | } | ||
1820 | }; | ||
1821 | |||
1324 | static struct usb_driver cxusb_driver = { | 1822 | static struct usb_driver cxusb_driver = { |
1325 | .name = "dvb_usb_cxusb", | 1823 | .name = "dvb_usb_cxusb", |
1326 | .probe = cxusb_probe, | 1824 | .probe = cxusb_probe, |
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 66d4dc6ba46f..739193943c17 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h | |||
@@ -31,6 +31,8 @@ extern int dvb_usb_dib0700_debug; | |||
31 | // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) | 31 | // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) |
32 | // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) | 32 | // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) |
33 | #define REQUEST_SET_RC 0x11 | 33 | #define REQUEST_SET_RC 0x11 |
34 | #define REQUEST_NEW_I2C_READ 0x12 | ||
35 | #define REQUEST_NEW_I2C_WRITE 0x13 | ||
34 | #define REQUEST_GET_VERSION 0x15 | 36 | #define REQUEST_GET_VERSION 0x15 |
35 | 37 | ||
36 | struct dib0700_state { | 38 | struct dib0700_state { |
@@ -39,6 +41,8 @@ struct dib0700_state { | |||
39 | u8 rc_toggle; | 41 | u8 rc_toggle; |
40 | u8 rc_counter; | 42 | u8 rc_counter; |
41 | u8 is_dib7000pc; | 43 | u8 is_dib7000pc; |
44 | u8 fw_use_new_i2c_api; | ||
45 | u8 disable_streaming_master_mode; | ||
42 | }; | 46 | }; |
43 | 47 | ||
44 | extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); | 48 | extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); |
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 595a04696c87..dd53cee3896d 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c | |||
@@ -82,9 +82,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ | |||
82 | } | 82 | } |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * I2C master xfer function | 85 | * I2C master xfer function (supported in 1.20 firmware) |
86 | */ | 86 | */ |
87 | static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) | 87 | static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, |
88 | int num) | ||
89 | { | ||
90 | /* The new i2c firmware messages are more reliable and in particular | ||
91 | properly support i2c read calls not preceded by a write */ | ||
92 | |||
93 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
94 | uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ | ||
95 | uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ | ||
96 | uint8_t en_start = 0; | ||
97 | uint8_t en_stop = 0; | ||
98 | uint8_t buf[255]; /* TBV: malloc ? */ | ||
99 | int result, i; | ||
100 | |||
101 | /* Ensure nobody else hits the i2c bus while we're sending our | ||
102 | sequence of messages, (such as the remote control thread) */ | ||
103 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
104 | return -EAGAIN; | ||
105 | |||
106 | for (i = 0; i < num; i++) { | ||
107 | if (i == 0) { | ||
108 | /* First message in the transaction */ | ||
109 | en_start = 1; | ||
110 | } else if (!(msg[i].flags & I2C_M_NOSTART)) { | ||
111 | /* Device supports repeated-start */ | ||
112 | en_start = 1; | ||
113 | } else { | ||
114 | /* Not the first packet and device doesn't support | ||
115 | repeated start */ | ||
116 | en_start = 0; | ||
117 | } | ||
118 | if (i == (num - 1)) { | ||
119 | /* Last message in the transaction */ | ||
120 | en_stop = 1; | ||
121 | } | ||
122 | |||
123 | if (msg[i].flags & I2C_M_RD) { | ||
124 | /* Read request */ | ||
125 | u16 index, value; | ||
126 | uint8_t i2c_dest; | ||
127 | |||
128 | i2c_dest = (msg[i].addr << 1); | ||
129 | value = ((en_start << 7) | (en_stop << 6) | | ||
130 | (msg[i].len & 0x3F)) << 8 | i2c_dest; | ||
131 | /* I2C ctrl + FE bus; */ | ||
132 | index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); | ||
133 | |||
134 | result = usb_control_msg(d->udev, | ||
135 | usb_rcvctrlpipe(d->udev, 0), | ||
136 | REQUEST_NEW_I2C_READ, | ||
137 | USB_TYPE_VENDOR | USB_DIR_IN, | ||
138 | value, index, msg[i].buf, | ||
139 | msg[i].len, | ||
140 | USB_CTRL_GET_TIMEOUT); | ||
141 | if (result < 0) { | ||
142 | err("i2c read error (status = %d)\n", result); | ||
143 | break; | ||
144 | } | ||
145 | } else { | ||
146 | /* Write request */ | ||
147 | buf[0] = REQUEST_NEW_I2C_WRITE; | ||
148 | buf[1] = (msg[i].addr << 1); | ||
149 | buf[2] = (en_start << 7) | (en_stop << 6) | | ||
150 | (msg[i].len & 0x3F); | ||
151 | /* I2C ctrl + FE bus; */ | ||
152 | buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); | ||
153 | /* The Actual i2c payload */ | ||
154 | memcpy(&buf[4], msg[i].buf, msg[i].len); | ||
155 | |||
156 | result = usb_control_msg(d->udev, | ||
157 | usb_sndctrlpipe(d->udev, 0), | ||
158 | REQUEST_NEW_I2C_WRITE, | ||
159 | USB_TYPE_VENDOR | USB_DIR_OUT, | ||
160 | 0, 0, buf, msg[i].len + 4, | ||
161 | USB_CTRL_GET_TIMEOUT); | ||
162 | if (result < 0) { | ||
163 | err("i2c write error (status = %d)\n", result); | ||
164 | break; | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | mutex_unlock(&d->i2c_mutex); | ||
169 | return i; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * I2C master xfer function (pre-1.20 firmware) | ||
174 | */ | ||
175 | static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, | ||
176 | struct i2c_msg *msg, int num) | ||
88 | { | 177 | { |
89 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 178 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
90 | int i,len; | 179 | int i,len; |
@@ -124,6 +213,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num | |||
124 | return i; | 213 | return i; |
125 | } | 214 | } |
126 | 215 | ||
216 | static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, | ||
217 | int num) | ||
218 | { | ||
219 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
220 | struct dib0700_state *st = d->priv; | ||
221 | |||
222 | if (st->fw_use_new_i2c_api == 1) { | ||
223 | /* User running at least fw 1.20 */ | ||
224 | return dib0700_i2c_xfer_new(adap, msg, num); | ||
225 | } else { | ||
226 | /* Use legacy calls */ | ||
227 | return dib0700_i2c_xfer_legacy(adap, msg, num); | ||
228 | } | ||
229 | } | ||
230 | |||
127 | static u32 dib0700_i2c_func(struct i2c_adapter *adapter) | 231 | static u32 dib0700_i2c_func(struct i2c_adapter *adapter) |
128 | { | 232 | { |
129 | return I2C_FUNC_I2C; | 233 | return I2C_FUNC_I2C; |
@@ -246,7 +350,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
246 | 350 | ||
247 | b[0] = REQUEST_ENABLE_VIDEO; | 351 | b[0] = REQUEST_ENABLE_VIDEO; |
248 | b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ | 352 | b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ |
249 | b[2] = (0x01 << 4); /* Master mode */ | 353 | |
354 | if (st->disable_streaming_master_mode == 1) | ||
355 | b[2] = 0x00; | ||
356 | else | ||
357 | b[2] = (0x01 << 4); /* Master mode */ | ||
358 | |||
250 | b[3] = 0x00; | 359 | b[3] = 0x00; |
251 | 360 | ||
252 | deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); | 361 | deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); |
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 6c0e5c5f4362..0cfccc24b190 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include "mt2060.h" | 14 | #include "mt2060.h" |
15 | #include "mt2266.h" | 15 | #include "mt2266.h" |
16 | #include "tuner-xc2028.h" | 16 | #include "tuner-xc2028.h" |
17 | #include "xc5000.h" | ||
18 | #include "s5h1411.h" | ||
17 | #include "dib0070.h" | 19 | #include "dib0070.h" |
18 | 20 | ||
19 | static int force_lna_activation; | 21 | static int force_lna_activation; |
@@ -366,7 +368,8 @@ static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { | |||
366 | .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, | 368 | .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, |
367 | }; | 369 | }; |
368 | 370 | ||
369 | static int stk7700ph_xc3028_callback(void *ptr, int command, int arg) | 371 | static int stk7700ph_xc3028_callback(void *ptr, int component, |
372 | int command, int arg) | ||
370 | { | 373 | { |
371 | struct dvb_usb_adapter *adap = ptr; | 374 | struct dvb_usb_adapter *adap = ptr; |
372 | 375 | ||
@@ -394,7 +397,6 @@ static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { | |||
394 | 397 | ||
395 | static struct xc2028_config stk7700ph_xc3028_config = { | 398 | static struct xc2028_config stk7700ph_xc3028_config = { |
396 | .i2c_addr = 0x61, | 399 | .i2c_addr = 0x61, |
397 | .callback = stk7700ph_xc3028_callback, | ||
398 | .ctrl = &stk7700ph_xc3028_ctrl, | 400 | .ctrl = &stk7700ph_xc3028_ctrl, |
399 | }; | 401 | }; |
400 | 402 | ||
@@ -435,7 +437,9 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) | |||
435 | DIBX000_I2C_INTERFACE_TUNER, 1); | 437 | DIBX000_I2C_INTERFACE_TUNER, 1); |
436 | 438 | ||
437 | stk7700ph_xc3028_config.i2c_adap = tun_i2c; | 439 | stk7700ph_xc3028_config.i2c_adap = tun_i2c; |
438 | stk7700ph_xc3028_config.video_dev = adap; | 440 | |
441 | /* FIXME: generalize & move to common area */ | ||
442 | adap->fe->callback = stk7700ph_xc3028_callback; | ||
439 | 443 | ||
440 | return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) | 444 | return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) |
441 | == NULL ? -ENODEV : 0; | 445 | == NULL ? -ENODEV : 0; |
@@ -677,6 +681,43 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { | |||
677 | { 0x01, 0x7d, KEY_VOLUMEDOWN }, | 681 | { 0x01, 0x7d, KEY_VOLUMEDOWN }, |
678 | { 0x02, 0x42, KEY_CHANNELUP }, | 682 | { 0x02, 0x42, KEY_CHANNELUP }, |
679 | { 0x00, 0x7d, KEY_CHANNELDOWN }, | 683 | { 0x00, 0x7d, KEY_CHANNELDOWN }, |
684 | |||
685 | /* Key codes for Nova-TD "credit card" remote control. */ | ||
686 | { 0x1d, 0x00, KEY_0 }, | ||
687 | { 0x1d, 0x01, KEY_1 }, | ||
688 | { 0x1d, 0x02, KEY_2 }, | ||
689 | { 0x1d, 0x03, KEY_3 }, | ||
690 | { 0x1d, 0x04, KEY_4 }, | ||
691 | { 0x1d, 0x05, KEY_5 }, | ||
692 | { 0x1d, 0x06, KEY_6 }, | ||
693 | { 0x1d, 0x07, KEY_7 }, | ||
694 | { 0x1d, 0x08, KEY_8 }, | ||
695 | { 0x1d, 0x09, KEY_9 }, | ||
696 | { 0x1d, 0x0a, KEY_TEXT }, | ||
697 | { 0x1d, 0x0d, KEY_MENU }, | ||
698 | { 0x1d, 0x0f, KEY_MUTE }, | ||
699 | { 0x1d, 0x10, KEY_VOLUMEUP }, | ||
700 | { 0x1d, 0x11, KEY_VOLUMEDOWN }, | ||
701 | { 0x1d, 0x12, KEY_CHANNEL }, | ||
702 | { 0x1d, 0x14, KEY_UP }, | ||
703 | { 0x1d, 0x15, KEY_DOWN }, | ||
704 | { 0x1d, 0x16, KEY_LEFT }, | ||
705 | { 0x1d, 0x17, KEY_RIGHT }, | ||
706 | { 0x1d, 0x1c, KEY_TV }, | ||
707 | { 0x1d, 0x1e, KEY_NEXT }, | ||
708 | { 0x1d, 0x1f, KEY_BACK }, | ||
709 | { 0x1d, 0x20, KEY_CHANNELUP }, | ||
710 | { 0x1d, 0x21, KEY_CHANNELDOWN }, | ||
711 | { 0x1d, 0x24, KEY_LAST }, | ||
712 | { 0x1d, 0x25, KEY_OK }, | ||
713 | { 0x1d, 0x30, KEY_PAUSE }, | ||
714 | { 0x1d, 0x32, KEY_REWIND }, | ||
715 | { 0x1d, 0x34, KEY_FASTFORWARD }, | ||
716 | { 0x1d, 0x35, KEY_PLAY }, | ||
717 | { 0x1d, 0x36, KEY_STOP }, | ||
718 | { 0x1d, 0x37, KEY_RECORD }, | ||
719 | { 0x1d, 0x3b, KEY_GOTO }, | ||
720 | { 0x1d, 0x3d, KEY_POWER }, | ||
680 | }; | 721 | }; |
681 | 722 | ||
682 | /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ | 723 | /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ |
@@ -1078,6 +1119,97 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) | |||
1078 | return adap->fe == NULL ? -ENODEV : 0; | 1119 | return adap->fe == NULL ? -ENODEV : 0; |
1079 | } | 1120 | } |
1080 | 1121 | ||
1122 | /* S5H1411 */ | ||
1123 | static struct s5h1411_config pinnacle_801e_config = { | ||
1124 | .output_mode = S5H1411_PARALLEL_OUTPUT, | ||
1125 | .gpio = S5H1411_GPIO_OFF, | ||
1126 | .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, | ||
1127 | .qam_if = S5H1411_IF_44000, | ||
1128 | .vsb_if = S5H1411_IF_44000, | ||
1129 | .inversion = S5H1411_INVERSION_OFF, | ||
1130 | .status_mode = S5H1411_DEMODLOCKING | ||
1131 | }; | ||
1132 | |||
1133 | /* Pinnacle PCTV HD Pro 801e GPIOs map: | ||
1134 | GPIO0 - currently unknown | ||
1135 | GPIO1 - xc5000 tuner reset | ||
1136 | GPIO2 - CX25843 sleep | ||
1137 | GPIO3 - currently unknown | ||
1138 | GPIO4 - currently unknown | ||
1139 | GPIO6 - currently unknown | ||
1140 | GPIO7 - currently unknown | ||
1141 | GPIO9 - currently unknown | ||
1142 | GPIO10 - CX25843 reset | ||
1143 | */ | ||
1144 | static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) | ||
1145 | { | ||
1146 | struct dib0700_state *st = adap->dev->priv; | ||
1147 | |||
1148 | /* Make use of the new i2c functions from FW 1.20 */ | ||
1149 | st->fw_use_new_i2c_api = 1; | ||
1150 | |||
1151 | /* The s5h1411 requires the dib0700 to not be in master mode */ | ||
1152 | st->disable_streaming_master_mode = 1; | ||
1153 | |||
1154 | /* All msleep values taken from Windows USB trace */ | ||
1155 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); | ||
1156 | dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); | ||
1157 | dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); | ||
1158 | msleep(400); | ||
1159 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); | ||
1160 | msleep(60); | ||
1161 | dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); | ||
1162 | msleep(30); | ||
1163 | dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); | ||
1164 | dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); | ||
1165 | dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); | ||
1166 | dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); | ||
1167 | dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); | ||
1168 | msleep(30); | ||
1169 | |||
1170 | /* Put the CX25843 to sleep for now since we're in digital mode */ | ||
1171 | dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); | ||
1172 | |||
1173 | /* GPIOs are initialized, do the attach */ | ||
1174 | adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, | ||
1175 | &adap->dev->i2c_adap); | ||
1176 | return adap->fe == NULL ? -ENODEV : 0; | ||
1177 | } | ||
1178 | |||
1179 | static int dib0700_xc5000_tuner_callback(void *priv, int component, | ||
1180 | int command, int arg) | ||
1181 | { | ||
1182 | struct dvb_usb_adapter *adap = priv; | ||
1183 | |||
1184 | if (command == XC5000_TUNER_RESET) { | ||
1185 | /* Reset the tuner */ | ||
1186 | dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); | ||
1187 | msleep(330); /* from Windows USB trace */ | ||
1188 | dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); | ||
1189 | msleep(330); /* from Windows USB trace */ | ||
1190 | } else { | ||
1191 | err("xc5000: unknown tuner callback command: %d\n", command); | ||
1192 | return -EINVAL; | ||
1193 | } | ||
1194 | |||
1195 | return 0; | ||
1196 | } | ||
1197 | |||
1198 | static struct xc5000_config s5h1411_xc5000_tunerconfig = { | ||
1199 | .i2c_address = 0x64, | ||
1200 | .if_khz = 5380, | ||
1201 | }; | ||
1202 | |||
1203 | static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) | ||
1204 | { | ||
1205 | /* FIXME: generalize & move to common area */ | ||
1206 | adap->fe->callback = dib0700_xc5000_tuner_callback; | ||
1207 | |||
1208 | return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, | ||
1209 | &s5h1411_xc5000_tunerconfig) | ||
1210 | == NULL ? -ENODEV : 0; | ||
1211 | } | ||
1212 | |||
1081 | /* DVB-USB and USB stuff follows */ | 1213 | /* DVB-USB and USB stuff follows */ |
1082 | struct usb_device_id dib0700_usb_id_table[] = { | 1214 | struct usb_device_id dib0700_usb_id_table[] = { |
1083 | /* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, | 1215 | /* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, |
@@ -1119,6 +1251,11 @@ struct usb_device_id dib0700_usb_id_table[] = { | |||
1119 | { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, | 1251 | { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, |
1120 | /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, | 1252 | /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, |
1121 | { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, | 1253 | { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, |
1254 | { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, | ||
1255 | { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, | ||
1256 | { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, | ||
1257 | /* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, | ||
1258 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, | ||
1122 | { 0 } /* Terminating entry */ | 1259 | { 0 } /* Terminating entry */ |
1123 | }; | 1260 | }; |
1124 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); | 1261 | MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); |
@@ -1126,7 +1263,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); | |||
1126 | #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ | 1263 | #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ |
1127 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ | 1264 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ |
1128 | .usb_ctrl = DEVICE_SPECIFIC, \ | 1265 | .usb_ctrl = DEVICE_SPECIFIC, \ |
1129 | .firmware = "dvb-usb-dib0700-1.10.fw", \ | 1266 | .firmware = "dvb-usb-dib0700-1.20.fw", \ |
1130 | .download_firmware = dib0700_download_firmware, \ | 1267 | .download_firmware = dib0700_download_firmware, \ |
1131 | .no_reconnect = 1, \ | 1268 | .no_reconnect = 1, \ |
1132 | .size_of_priv = sizeof(struct dib0700_state), \ | 1269 | .size_of_priv = sizeof(struct dib0700_state), \ |
@@ -1293,7 +1430,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
1293 | { &dib0700_usb_id_table[31], NULL }, | 1430 | { &dib0700_usb_id_table[31], NULL }, |
1294 | { NULL }, | 1431 | { NULL }, |
1295 | } | 1432 | } |
1296 | } | 1433 | }, |
1434 | |||
1435 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
1436 | .rc_key_map = dib0700_rc_keys, | ||
1437 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
1438 | .rc_query = dib0700_rc_query | ||
1297 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | 1439 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, |
1298 | 1440 | ||
1299 | .num_adapters = 1, | 1441 | .num_adapters = 1, |
@@ -1408,7 +1550,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
1408 | }, | 1550 | }, |
1409 | }, | 1551 | }, |
1410 | 1552 | ||
1411 | .num_device_descs = 3, | 1553 | .num_device_descs = 5, |
1412 | .devices = { | 1554 | .devices = { |
1413 | { "Terratec Cinergy HT USB XE", | 1555 | { "Terratec Cinergy HT USB XE", |
1414 | { &dib0700_usb_id_table[27], NULL }, | 1556 | { &dib0700_usb_id_table[27], NULL }, |
@@ -1422,6 +1564,47 @@ struct dvb_usb_device_properties dib0700_devices[] = { | |||
1422 | { &dib0700_usb_id_table[32], NULL }, | 1564 | { &dib0700_usb_id_table[32], NULL }, |
1423 | { NULL }, | 1565 | { NULL }, |
1424 | }, | 1566 | }, |
1567 | { "Gigabyte U8000-RH", | ||
1568 | { &dib0700_usb_id_table[37], NULL }, | ||
1569 | { NULL }, | ||
1570 | }, | ||
1571 | { "YUAN High-Tech STK7700PH", | ||
1572 | { &dib0700_usb_id_table[38], NULL }, | ||
1573 | { NULL }, | ||
1574 | }, | ||
1575 | { "Asus My Cinema-U3000Hybrid", | ||
1576 | { &dib0700_usb_id_table[39], NULL }, | ||
1577 | { NULL }, | ||
1578 | }, | ||
1579 | }, | ||
1580 | .rc_interval = DEFAULT_RC_INTERVAL, | ||
1581 | .rc_key_map = dib0700_rc_keys, | ||
1582 | .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), | ||
1583 | .rc_query = dib0700_rc_query | ||
1584 | }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, | ||
1585 | .num_adapters = 1, | ||
1586 | .adapter = { | ||
1587 | { | ||
1588 | .frontend_attach = s5h1411_frontend_attach, | ||
1589 | .tuner_attach = xc5000_tuner_attach, | ||
1590 | |||
1591 | DIB0700_DEFAULT_STREAMING_CONFIG(0x02), | ||
1592 | |||
1593 | .size_of_priv = sizeof(struct | ||
1594 | dib0700_adapter_state), | ||
1595 | }, | ||
1596 | }, | ||
1597 | |||
1598 | .num_device_descs = 2, | ||
1599 | .devices = { | ||
1600 | { "Pinnacle PCTV HD Pro USB Stick", | ||
1601 | { &dib0700_usb_id_table[40], NULL }, | ||
1602 | { NULL }, | ||
1603 | }, | ||
1604 | { "Pinnacle PCTV HD USB Stick", | ||
1605 | { &dib0700_usb_id_table[41], NULL }, | ||
1606 | { NULL }, | ||
1607 | }, | ||
1425 | }, | 1608 | }, |
1426 | .rc_interval = DEFAULT_RC_INTERVAL, | 1609 | .rc_interval = DEFAULT_RC_INTERVAL, |
1427 | .rc_key_map = dib0700_rc_keys, | 1610 | .rc_key_map = dib0700_rc_keys, |
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c new file mode 100644 index 000000000000..078ce92ca436 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtv5100.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T | ||
3 | * | ||
4 | * Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com> | ||
5 | * http://royale.zerezo.com/dtv5100/ | ||
6 | * | ||
7 | * Inspired by gl861.c and au6610.c drivers | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include "dtv5100.h" | ||
25 | #include "zl10353.h" | ||
26 | #include "qt1010.h" | ||
27 | |||
28 | /* debug */ | ||
29 | static int dvb_usb_dtv5100_debug; | ||
30 | module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); | ||
31 | MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); | ||
32 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
33 | |||
34 | static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, | ||
35 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) | ||
36 | { | ||
37 | u8 request; | ||
38 | u8 type; | ||
39 | u16 value; | ||
40 | u16 index; | ||
41 | |||
42 | switch (wlen) { | ||
43 | case 1: | ||
44 | /* write { reg }, read { value } */ | ||
45 | request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : | ||
46 | DTV5100_TUNER_READ); | ||
47 | type = USB_TYPE_VENDOR | USB_DIR_IN; | ||
48 | value = 0; | ||
49 | break; | ||
50 | case 2: | ||
51 | /* write { reg, value } */ | ||
52 | request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : | ||
53 | DTV5100_TUNER_WRITE); | ||
54 | type = USB_TYPE_VENDOR | USB_DIR_OUT; | ||
55 | value = wbuf[1]; | ||
56 | break; | ||
57 | default: | ||
58 | warn("wlen = %x, aborting.", wlen); | ||
59 | return -EINVAL; | ||
60 | } | ||
61 | index = (addr << 8) + wbuf[0]; | ||
62 | |||
63 | msleep(1); /* avoid I2C errors */ | ||
64 | return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, | ||
65 | type, value, index, rbuf, rlen, | ||
66 | DTV5100_USB_TIMEOUT); | ||
67 | } | ||
68 | |||
69 | /* I2C */ | ||
70 | static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | ||
71 | int num) | ||
72 | { | ||
73 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
74 | int i; | ||
75 | |||
76 | if (num > 2) | ||
77 | return -EINVAL; | ||
78 | |||
79 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
80 | return -EAGAIN; | ||
81 | |||
82 | for (i = 0; i < num; i++) { | ||
83 | /* write/read request */ | ||
84 | if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { | ||
85 | if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, | ||
86 | msg[i].len, msg[i+1].buf, | ||
87 | msg[i+1].len) < 0) | ||
88 | break; | ||
89 | i++; | ||
90 | } else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, | ||
91 | msg[i].len, NULL, 0) < 0) | ||
92 | break; | ||
93 | } | ||
94 | |||
95 | mutex_unlock(&d->i2c_mutex); | ||
96 | return i; | ||
97 | } | ||
98 | |||
99 | static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) | ||
100 | { | ||
101 | return I2C_FUNC_I2C; | ||
102 | } | ||
103 | |||
104 | static struct i2c_algorithm dtv5100_i2c_algo = { | ||
105 | .master_xfer = dtv5100_i2c_xfer, | ||
106 | .functionality = dtv5100_i2c_func, | ||
107 | }; | ||
108 | |||
109 | /* Callbacks for DVB USB */ | ||
110 | static struct zl10353_config dtv5100_zl10353_config = { | ||
111 | .demod_address = DTV5100_DEMOD_ADDR, | ||
112 | .no_tuner = 1, | ||
113 | .parallel_ts = 1, | ||
114 | }; | ||
115 | |||
116 | static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) | ||
117 | { | ||
118 | adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, | ||
119 | &adap->dev->i2c_adap); | ||
120 | if (adap->fe == NULL) | ||
121 | return -EIO; | ||
122 | |||
123 | /* disable i2c gate, or it won't work... is this safe? */ | ||
124 | adap->fe->ops.i2c_gate_ctrl = NULL; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static struct qt1010_config dtv5100_qt1010_config = { | ||
130 | .i2c_address = DTV5100_TUNER_ADDR | ||
131 | }; | ||
132 | |||
133 | static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) | ||
134 | { | ||
135 | return dvb_attach(qt1010_attach, | ||
136 | adap->fe, &adap->dev->i2c_adap, | ||
137 | &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; | ||
138 | } | ||
139 | |||
140 | /* DVB USB Driver stuff */ | ||
141 | static struct dvb_usb_device_properties dtv5100_properties; | ||
142 | |||
143 | static int dtv5100_probe(struct usb_interface *intf, | ||
144 | const struct usb_device_id *id) | ||
145 | { | ||
146 | int i, ret; | ||
147 | struct usb_device *udev = interface_to_usbdev(intf); | ||
148 | |||
149 | /* initialize non qt1010/zl10353 part? */ | ||
150 | for (i = 0; dtv5100_init[i].request; i++) { | ||
151 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
152 | dtv5100_init[i].request, | ||
153 | USB_TYPE_VENDOR | USB_DIR_OUT, | ||
154 | dtv5100_init[i].value, | ||
155 | dtv5100_init[i].index, NULL, 0, | ||
156 | DTV5100_USB_TIMEOUT); | ||
157 | if (ret) | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | ret = dvb_usb_device_init(intf, &dtv5100_properties, | ||
162 | THIS_MODULE, NULL, adapter_nr); | ||
163 | if (ret) | ||
164 | return ret; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static struct usb_device_id dtv5100_table[] = { | ||
170 | { USB_DEVICE(0x06be, 0xa232) }, | ||
171 | { } /* Terminating entry */ | ||
172 | }; | ||
173 | MODULE_DEVICE_TABLE(usb, dtv5100_table); | ||
174 | |||
175 | static struct dvb_usb_device_properties dtv5100_properties = { | ||
176 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
177 | .usb_ctrl = DEVICE_SPECIFIC, | ||
178 | |||
179 | .size_of_priv = 0, | ||
180 | |||
181 | .num_adapters = 1, | ||
182 | .adapter = {{ | ||
183 | .frontend_attach = dtv5100_frontend_attach, | ||
184 | .tuner_attach = dtv5100_tuner_attach, | ||
185 | |||
186 | .stream = { | ||
187 | .type = USB_BULK, | ||
188 | .count = 8, | ||
189 | .endpoint = 0x82, | ||
190 | .u = { | ||
191 | .bulk = { | ||
192 | .buffersize = 4096, | ||
193 | } | ||
194 | } | ||
195 | }, | ||
196 | } }, | ||
197 | |||
198 | .i2c_algo = &dtv5100_i2c_algo, | ||
199 | |||
200 | .num_device_descs = 1, | ||
201 | .devices = { | ||
202 | { | ||
203 | .name = "AME DTV-5100 USB2.0 DVB-T", | ||
204 | .cold_ids = { NULL }, | ||
205 | .warm_ids = { &dtv5100_table[0], NULL }, | ||
206 | }, | ||
207 | } | ||
208 | }; | ||
209 | |||
210 | static struct usb_driver dtv5100_driver = { | ||
211 | .name = "dvb_usb_dtv5100", | ||
212 | .probe = dtv5100_probe, | ||
213 | .disconnect = dvb_usb_device_exit, | ||
214 | .id_table = dtv5100_table, | ||
215 | }; | ||
216 | |||
217 | /* module stuff */ | ||
218 | static int __init dtv5100_module_init(void) | ||
219 | { | ||
220 | int ret; | ||
221 | |||
222 | ret = usb_register(&dtv5100_driver); | ||
223 | if (ret) | ||
224 | err("usb_register failed. Error number %d", ret); | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static void __exit dtv5100_module_exit(void) | ||
230 | { | ||
231 | /* deregister this driver from the USB subsystem */ | ||
232 | usb_deregister(&dtv5100_driver); | ||
233 | } | ||
234 | |||
235 | module_init(dtv5100_module_init); | ||
236 | module_exit(dtv5100_module_exit); | ||
237 | |||
238 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
239 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
240 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h new file mode 100644 index 000000000000..93e96e04a82a --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtv5100.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T | ||
3 | * | ||
4 | * Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com> | ||
5 | * http://royale.zerezo.com/dtv5100/ | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef _DVB_USB_DTV5100_H_ | ||
23 | #define _DVB_USB_DTV5100_H_ | ||
24 | |||
25 | #define DVB_USB_LOG_PREFIX "dtv5100" | ||
26 | #include "dvb-usb.h" | ||
27 | |||
28 | #define DTV5100_USB_TIMEOUT 500 | ||
29 | |||
30 | #define DTV5100_DEMOD_ADDR 0x00 | ||
31 | #define DTV5100_DEMOD_WRITE 0xc0 | ||
32 | #define DTV5100_DEMOD_READ 0xc1 | ||
33 | |||
34 | #define DTV5100_TUNER_ADDR 0xc4 | ||
35 | #define DTV5100_TUNER_WRITE 0xc7 | ||
36 | #define DTV5100_TUNER_READ 0xc8 | ||
37 | |||
38 | #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" | ||
39 | #define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" | ||
40 | |||
41 | static struct { | ||
42 | u8 request; | ||
43 | u8 value; | ||
44 | u16 index; | ||
45 | } dtv5100_init[] = { | ||
46 | { 0x000000c5, 0x00000000, 0x00000001 }, | ||
47 | { 0x000000c5, 0x00000001, 0x00000001 }, | ||
48 | { } /* Terminating entry */ | ||
49 | }; | ||
50 | |||
51 | #endif | ||
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 03dfb9f2fe30..7380b94b3b36 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define USB_VID_AVERMEDIA 0x07ca | 22 | #define USB_VID_AVERMEDIA 0x07ca |
23 | #define USB_VID_COMPRO 0x185b | 23 | #define USB_VID_COMPRO 0x185b |
24 | #define USB_VID_COMPRO_UNK 0x145f | 24 | #define USB_VID_COMPRO_UNK 0x145f |
25 | #define USB_VID_CONEXANT 0x0572 | ||
25 | #define USB_VID_CYPRESS 0x04b4 | 26 | #define USB_VID_CYPRESS 0x04b4 |
26 | #define USB_VID_DIBCOM 0x10b8 | 27 | #define USB_VID_DIBCOM 0x10b8 |
27 | #define USB_VID_DPOSH 0x1498 | 28 | #define USB_VID_DPOSH 0x1498 |
@@ -33,16 +34,19 @@ | |||
33 | #define USB_VID_HAUPPAUGE 0x2040 | 34 | #define USB_VID_HAUPPAUGE 0x2040 |
34 | #define USB_VID_HYPER_PALTEK 0x1025 | 35 | #define USB_VID_HYPER_PALTEK 0x1025 |
35 | #define USB_VID_KWORLD 0xeb2a | 36 | #define USB_VID_KWORLD 0xeb2a |
37 | #define USB_VID_KWORLD_2 0x1b80 | ||
36 | #define USB_VID_KYE 0x0458 | 38 | #define USB_VID_KYE 0x0458 |
37 | #define USB_VID_LEADTEK 0x0413 | 39 | #define USB_VID_LEADTEK 0x0413 |
38 | #define USB_VID_LITEON 0x04ca | 40 | #define USB_VID_LITEON 0x04ca |
39 | #define USB_VID_MEDION 0x1660 | 41 | #define USB_VID_MEDION 0x1660 |
40 | #define USB_VID_MIGLIA 0x18f3 | 42 | #define USB_VID_MIGLIA 0x18f3 |
41 | #define USB_VID_MSI 0x0db0 | 43 | #define USB_VID_MSI 0x0db0 |
44 | #define USB_VID_MSI_2 0x1462 | ||
42 | #define USB_VID_OPERA1 0x695c | 45 | #define USB_VID_OPERA1 0x695c |
43 | #define USB_VID_PINNACLE 0x2304 | 46 | #define USB_VID_PINNACLE 0x2304 |
44 | #define USB_VID_TECHNOTREND 0x0b48 | 47 | #define USB_VID_TECHNOTREND 0x0b48 |
45 | #define USB_VID_TERRATEC 0x0ccd | 48 | #define USB_VID_TERRATEC 0x0ccd |
49 | #define USB_VID_TELESTAR 0x10b9 | ||
46 | #define USB_VID_VISIONPLUS 0x13d3 | 50 | #define USB_VID_VISIONPLUS 0x13d3 |
47 | #define USB_VID_TWINHAN 0x1822 | 51 | #define USB_VID_TWINHAN 0x1822 |
48 | #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 | 52 | #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 |
@@ -50,15 +54,18 @@ | |||
50 | #define USB_VID_WIDEVIEW 0x14aa | 54 | #define USB_VID_WIDEVIEW 0x14aa |
51 | #define USB_VID_GIGABYTE 0x1044 | 55 | #define USB_VID_GIGABYTE 0x1044 |
52 | #define USB_VID_YUAN 0x1164 | 56 | #define USB_VID_YUAN 0x1164 |
53 | 57 | #define USB_VID_XTENSIONS 0x1ae7 | |
54 | 58 | ||
55 | /* Product IDs */ | 59 | /* Product IDs */ |
56 | #define USB_PID_ADSTECH_USB2_COLD 0xa333 | 60 | #define USB_PID_ADSTECH_USB2_COLD 0xa333 |
57 | #define USB_PID_ADSTECH_USB2_WARM 0xa334 | 61 | #define USB_PID_ADSTECH_USB2_WARM 0xa334 |
58 | #define USB_PID_AFATECH_AF9005 0x9020 | 62 | #define USB_PID_AFATECH_AF9005 0x9020 |
63 | #define USB_PID_AFATECH_AF9015_9015 0x9015 | ||
64 | #define USB_PID_AFATECH_AF9015_9016 0x9016 | ||
59 | #define USB_VID_ALINK_DTU 0xf170 | 65 | #define USB_VID_ALINK_DTU 0xf170 |
60 | #define USB_PID_ANSONIC_DVBT_USB 0x6000 | 66 | #define USB_PID_ANSONIC_DVBT_USB 0x6000 |
61 | #define USB_PID_ANYSEE 0x861f | 67 | #define USB_PID_ANYSEE 0x861f |
68 | #define USB_PID_AZUREWAVE_AD_TU700 0x3237 | ||
62 | #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 | 69 | #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 |
63 | #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 | 70 | #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 |
64 | #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 | 71 | #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 |
@@ -69,6 +76,7 @@ | |||
69 | #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d | 76 | #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d |
70 | #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 | 77 | #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 |
71 | #define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 | 78 | #define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 |
79 | #define USB_PID_CONEXANT_D680_DMB 0x86d6 | ||
72 | #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 | 80 | #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 |
73 | #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 | 81 | #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 |
74 | #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 | 82 | #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 |
@@ -87,9 +95,12 @@ | |||
87 | #define USB_PID_UNIWILL_STK7700P 0x6003 | 95 | #define USB_PID_UNIWILL_STK7700P 0x6003 |
88 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 | 96 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 |
89 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 | 97 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 |
98 | #define USB_PID_KWORLD_399U 0xe399 | ||
99 | #define USB_PID_KWORLD_PC160_2T 0xc160 | ||
90 | #define USB_PID_KWORLD_VSTREAM_COLD 0x17de | 100 | #define USB_PID_KWORLD_VSTREAM_COLD 0x17de |
91 | #define USB_PID_KWORLD_VSTREAM_WARM 0x17df | 101 | #define USB_PID_KWORLD_VSTREAM_WARM 0x17df |
92 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 | 102 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 |
103 | #define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 | ||
93 | #define USB_PID_TWINHAN_VP7041_COLD 0x3201 | 104 | #define USB_PID_TWINHAN_VP7041_COLD 0x3201 |
94 | #define USB_PID_TWINHAN_VP7041_WARM 0x3202 | 105 | #define USB_PID_TWINHAN_VP7041_WARM 0x3202 |
95 | #define USB_PID_TWINHAN_VP7020_COLD 0x3203 | 106 | #define USB_PID_TWINHAN_VP7020_COLD 0x3203 |
@@ -98,6 +109,7 @@ | |||
98 | #define USB_PID_TWINHAN_VP7045_WARM 0x3206 | 109 | #define USB_PID_TWINHAN_VP7045_WARM 0x3206 |
99 | #define USB_PID_TWINHAN_VP7021_COLD 0x3207 | 110 | #define USB_PID_TWINHAN_VP7021_COLD 0x3207 |
100 | #define USB_PID_TWINHAN_VP7021_WARM 0x3208 | 111 | #define USB_PID_TWINHAN_VP7021_WARM 0x3208 |
112 | #define USB_PID_TINYTWIN 0x3226 | ||
101 | #define USB_PID_DNTV_TINYUSB2_COLD 0x3223 | 113 | #define USB_PID_DNTV_TINYUSB2_COLD 0x3223 |
102 | #define USB_PID_DNTV_TINYUSB2_WARM 0x3224 | 114 | #define USB_PID_DNTV_TINYUSB2_WARM 0x3224 |
103 | #define USB_PID_ULTIMA_TVBOX_COLD 0x8105 | 115 | #define USB_PID_ULTIMA_TVBOX_COLD 0x8105 |
@@ -144,6 +156,9 @@ | |||
144 | #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039 | 156 | #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039 |
145 | #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039 | 157 | #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039 |
146 | #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 | 158 | #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 |
159 | #define USB_PID_AVERMEDIA_VOLAR_X 0xa815 | ||
160 | #define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150 | ||
161 | #define USB_PID_AVERMEDIA_A309 0xa309 | ||
147 | #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 | 162 | #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 |
148 | #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a | 163 | #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a |
149 | #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 | 164 | #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 |
@@ -153,8 +168,11 @@ | |||
153 | #define USB_PID_PINNACLE_PCTV2000E 0x022c | 168 | #define USB_PID_PINNACLE_PCTV2000E 0x022c |
154 | #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 | 169 | #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 |
155 | #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 | 170 | #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 |
171 | #define USB_PID_PINNACLE_PCTV71E 0x022b | ||
156 | #define USB_PID_PINNACLE_PCTV72E 0x0236 | 172 | #define USB_PID_PINNACLE_PCTV72E 0x0236 |
157 | #define USB_PID_PINNACLE_PCTV73E 0x0237 | 173 | #define USB_PID_PINNACLE_PCTV73E 0x0237 |
174 | #define USB_PID_PINNACLE_PCTV801E 0x023a | ||
175 | #define USB_PID_PINNACLE_PCTV801E_SE 0x023b | ||
158 | #define USB_PID_PCTV_200E 0x020e | 176 | #define USB_PID_PCTV_200E 0x020e |
159 | #define USB_PID_PCTV_400E 0x020f | 177 | #define USB_PID_PCTV_400E 0x020f |
160 | #define USB_PID_PCTV_450E 0x0222 | 178 | #define USB_PID_PCTV_450E 0x0222 |
@@ -171,6 +189,7 @@ | |||
171 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 | 189 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 |
172 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 | 190 | #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 |
173 | #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 | 191 | #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 |
192 | #define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98 | ||
174 | #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 | 193 | #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 |
175 | #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 | 194 | #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 |
176 | #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 | 195 | #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 |
@@ -190,6 +209,7 @@ | |||
190 | #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 | 209 | #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 |
191 | #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 | 210 | #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 |
192 | #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 | 211 | #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 |
212 | #define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 | ||
193 | #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 | 213 | #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 |
194 | #define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 | 214 | #define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 |
195 | #define USB_PID_GENPIX_8PSK_REV_2 0x0202 | 215 | #define USB_PID_GENPIX_8PSK_REV_2 0x0202 |
@@ -197,14 +217,21 @@ | |||
197 | #define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 | 217 | #define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 |
198 | #define USB_PID_SIGMATEK_DVB_110 0x6610 | 218 | #define USB_PID_SIGMATEK_DVB_110 0x6610 |
199 | #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 | 219 | #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 |
220 | #define USB_PID_MSI_DIGIVOX_DUO 0x8801 | ||
200 | #define USB_PID_OPERA1_COLD 0x2830 | 221 | #define USB_PID_OPERA1_COLD 0x2830 |
201 | #define USB_PID_OPERA1_WARM 0x3829 | 222 | #define USB_PID_OPERA1_WARM 0x3829 |
202 | #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 | 223 | #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 |
203 | #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 | 224 | #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 |
204 | #define USB_PID_GIGABYTE_U7000 0x7001 | 225 | #define USB_PID_GIGABYTE_U7000 0x7001 |
226 | #define USB_PID_GIGABYTE_U8000 0x7002 | ||
205 | #define USB_PID_ASUS_U3000 0x171f | 227 | #define USB_PID_ASUS_U3000 0x171f |
228 | #define USB_PID_ASUS_U3000H 0x1736 | ||
206 | #define USB_PID_ASUS_U3100 0x173f | 229 | #define USB_PID_ASUS_U3100 0x173f |
207 | #define USB_PID_YUAN_EC372S 0x1edc | 230 | #define USB_PID_YUAN_EC372S 0x1edc |
231 | #define USB_PID_YUAN_STK7700PH 0x1f08 | ||
208 | #define USB_PID_DW2102 0x2102 | 232 | #define USB_PID_DW2102 0x2102 |
233 | #define USB_PID_XTENSIONS_XD_380 0x0381 | ||
234 | #define USB_PID_TELESTAR_STARSTICK_2 0x8000 | ||
235 | #define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 | ||
209 | 236 | ||
210 | #endif | 237 | #endif |
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index a4d898b44e55..ca53df61caa8 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card | 1 | /* DVB USB framework compliant Linux driver for the |
2 | * DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card | ||
2 | * | 3 | * |
3 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | 4 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) |
4 | * | 5 | * |
@@ -10,62 +11,74 @@ | |||
10 | */ | 11 | */ |
11 | #include <linux/version.h> | 12 | #include <linux/version.h> |
12 | #include "dw2102.h" | 13 | #include "dw2102.h" |
14 | #include "si21xx.h" | ||
13 | #include "stv0299.h" | 15 | #include "stv0299.h" |
14 | #include "z0194a.h" | 16 | #include "z0194a.h" |
17 | #include "stv0288.h" | ||
18 | #include "stb6000.h" | ||
19 | #include "eds1547.h" | ||
20 | #include "cx24116.h" | ||
15 | 21 | ||
16 | #ifndef USB_PID_DW2102 | 22 | #ifndef USB_PID_DW2102 |
17 | #define USB_PID_DW2102 0x2102 | 23 | #define USB_PID_DW2102 0x2102 |
18 | #endif | 24 | #endif |
19 | 25 | ||
20 | #define DW2102_READ_MSG 0 | 26 | #ifndef USB_PID_DW2104 |
21 | #define DW2102_WRITE_MSG 1 | 27 | #define USB_PID_DW2104 0x2104 |
28 | #endif | ||
29 | |||
30 | #define DW210X_READ_MSG 0 | ||
31 | #define DW210X_WRITE_MSG 1 | ||
22 | 32 | ||
23 | #define REG_1F_SYMBOLRATE_BYTE0 0x1f | 33 | #define REG_1F_SYMBOLRATE_BYTE0 0x1f |
24 | #define REG_20_SYMBOLRATE_BYTE1 0x20 | 34 | #define REG_20_SYMBOLRATE_BYTE1 0x20 |
25 | #define REG_21_SYMBOLRATE_BYTE2 0x21 | 35 | #define REG_21_SYMBOLRATE_BYTE2 0x21 |
26 | 36 | /* on my own*/ | |
27 | #define DW2102_VOLTAGE_CTRL (0x1800) | 37 | #define DW2102_VOLTAGE_CTRL (0x1800) |
28 | #define DW2102_RC_QUERY (0x1a00) | 38 | #define DW2102_RC_QUERY (0x1a00) |
29 | 39 | ||
30 | struct dw2102_state { | 40 | struct dw210x_state { |
31 | u32 last_key_pressed; | 41 | u32 last_key_pressed; |
32 | }; | 42 | }; |
33 | struct dw2102_rc_keys { | 43 | struct dw210x_rc_keys { |
34 | u32 keycode; | 44 | u32 keycode; |
35 | u32 event; | 45 | u32 event; |
36 | }; | 46 | }; |
37 | 47 | ||
48 | /* debug */ | ||
49 | static int dvb_usb_dw2102_debug; | ||
50 | module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); | ||
51 | MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS); | ||
52 | |||
38 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 53 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
39 | 54 | ||
40 | static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value, | 55 | static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, |
41 | u8 *data, u16 len, int flags) | 56 | u16 index, u8 * data, u16 len, int flags) |
42 | { | 57 | { |
43 | int ret; | 58 | int ret; |
44 | u8 u8buf[len]; | 59 | u8 u8buf[len]; |
45 | 60 | ||
46 | unsigned int pipe = (flags == DW2102_READ_MSG) ? | 61 | unsigned int pipe = (flags == DW210X_READ_MSG) ? |
47 | usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); | 62 | usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); |
48 | u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; | 63 | u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; |
49 | 64 | ||
50 | if (flags == DW2102_WRITE_MSG) | 65 | if (flags == DW210X_WRITE_MSG) |
51 | memcpy(u8buf, data, len); | 66 | memcpy(u8buf, data, len); |
52 | ret = usb_control_msg(dev, pipe, request, | 67 | ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, |
53 | request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000); | 68 | value, index , u8buf, len, 2000); |
54 | 69 | ||
55 | if (flags == DW2102_READ_MSG) | 70 | if (flags == DW210X_READ_MSG) |
56 | memcpy(data, u8buf, len); | 71 | memcpy(data, u8buf, len); |
57 | return ret; | 72 | return ret; |
58 | } | 73 | } |
59 | 74 | ||
60 | /* I2C */ | 75 | /* I2C */ |
61 | |||
62 | static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 76 | static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], |
63 | int num) | 77 | int num) |
64 | { | 78 | { |
65 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 79 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
66 | int i = 0, ret = 0; | 80 | int i = 0, ret = 0; |
67 | u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; | 81 | u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; |
68 | u8 request; | ||
69 | u16 value; | 82 | u16 value; |
70 | 83 | ||
71 | if (!d) | 84 | if (!d) |
@@ -76,14 +89,12 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
76 | switch (num) { | 89 | switch (num) { |
77 | case 2: | 90 | case 2: |
78 | /* read stv0299 register */ | 91 | /* read stv0299 register */ |
79 | request = 0xb5; | ||
80 | value = msg[0].buf[0];/* register */ | 92 | value = msg[0].buf[0];/* register */ |
81 | for (i = 0; i < msg[1].len; i++) { | 93 | for (i = 0; i < msg[1].len; i++) { |
82 | value = value + i; | 94 | value = value + i; |
83 | ret = dw2102_op_rw(d->udev, 0xb5, | 95 | ret = dw210x_op_rw(d->udev, 0xb5, value, 0, |
84 | value, buf6, 2, DW2102_READ_MSG); | 96 | buf6, 2, DW210X_READ_MSG); |
85 | msg[1].buf[i] = buf6[0]; | 97 | msg[1].buf[i] = buf6[0]; |
86 | |||
87 | } | 98 | } |
88 | break; | 99 | break; |
89 | case 1: | 100 | case 1: |
@@ -93,8 +104,8 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
93 | buf6[0] = 0x2a; | 104 | buf6[0] = 0x2a; |
94 | buf6[1] = msg[0].buf[0]; | 105 | buf6[1] = msg[0].buf[0]; |
95 | buf6[2] = msg[0].buf[1]; | 106 | buf6[2] = msg[0].buf[1]; |
96 | ret = dw2102_op_rw(d->udev, 0xb2, | 107 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
97 | 0, buf6, 3, DW2102_WRITE_MSG); | 108 | buf6, 3, DW210X_WRITE_MSG); |
98 | break; | 109 | break; |
99 | case 0x60: | 110 | case 0x60: |
100 | if (msg[0].flags == 0) { | 111 | if (msg[0].flags == 0) { |
@@ -106,26 +117,26 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
106 | buf6[4] = msg[0].buf[1]; | 117 | buf6[4] = msg[0].buf[1]; |
107 | buf6[5] = msg[0].buf[2]; | 118 | buf6[5] = msg[0].buf[2]; |
108 | buf6[6] = msg[0].buf[3]; | 119 | buf6[6] = msg[0].buf[3]; |
109 | ret = dw2102_op_rw(d->udev, 0xb2, | 120 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
110 | 0, buf6, 7, DW2102_WRITE_MSG); | 121 | buf6, 7, DW210X_WRITE_MSG); |
111 | } else { | 122 | } else { |
112 | /* write to tuner pll */ | 123 | /* read from tuner */ |
113 | ret = dw2102_op_rw(d->udev, 0xb5, | 124 | ret = dw210x_op_rw(d->udev, 0xb5, 0, 0, |
114 | 0, buf6, 1, DW2102_READ_MSG); | 125 | buf6, 1, DW210X_READ_MSG); |
115 | msg[0].buf[0] = buf6[0]; | 126 | msg[0].buf[0] = buf6[0]; |
116 | } | 127 | } |
117 | break; | 128 | break; |
118 | case (DW2102_RC_QUERY): | 129 | case (DW2102_RC_QUERY): |
119 | ret = dw2102_op_rw(d->udev, 0xb8, | 130 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, |
120 | 0, buf6, 2, DW2102_READ_MSG); | 131 | buf6, 2, DW210X_READ_MSG); |
121 | msg[0].buf[0] = buf6[0]; | 132 | msg[0].buf[0] = buf6[0]; |
122 | msg[0].buf[1] = buf6[1]; | 133 | msg[0].buf[1] = buf6[1]; |
123 | break; | 134 | break; |
124 | case (DW2102_VOLTAGE_CTRL): | 135 | case (DW2102_VOLTAGE_CTRL): |
125 | buf6[0] = 0x30; | 136 | buf6[0] = 0x30; |
126 | buf6[1] = msg[0].buf[0]; | 137 | buf6[1] = msg[0].buf[0]; |
127 | ret = dw2102_op_rw(d->udev, 0xb2, | 138 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, |
128 | 0, buf6, 2, DW2102_WRITE_MSG); | 139 | buf6, 2, DW210X_WRITE_MSG); |
129 | break; | 140 | break; |
130 | } | 141 | } |
131 | 142 | ||
@@ -136,17 +147,265 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); | |||
136 | return num; | 147 | return num; |
137 | } | 148 | } |
138 | 149 | ||
139 | static u32 dw2102_i2c_func(struct i2c_adapter *adapter) | 150 | static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, |
151 | struct i2c_msg msg[], int num) | ||
152 | { | ||
153 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
154 | int ret = 0; | ||
155 | u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; | ||
156 | |||
157 | if (!d) | ||
158 | return -ENODEV; | ||
159 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
160 | return -EAGAIN; | ||
161 | |||
162 | switch (num) { | ||
163 | case 2: | ||
164 | /* read si2109 register by number */ | ||
165 | buf6[0] = 0xd0; | ||
166 | buf6[1] = msg[0].len; | ||
167 | buf6[2] = msg[0].buf[0]; | ||
168 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
169 | buf6, msg[0].len + 2, DW210X_WRITE_MSG); | ||
170 | /* read si2109 register */ | ||
171 | ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, | ||
172 | buf6, msg[1].len + 2, DW210X_READ_MSG); | ||
173 | memcpy(msg[1].buf, buf6 + 2, msg[1].len); | ||
174 | |||
175 | break; | ||
176 | case 1: | ||
177 | switch (msg[0].addr) { | ||
178 | case 0x68: | ||
179 | /* write to si2109 register */ | ||
180 | buf6[0] = 0xd0; | ||
181 | buf6[1] = msg[0].len; | ||
182 | memcpy(buf6 + 2, msg[0].buf, msg[0].len); | ||
183 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, | ||
184 | msg[0].len + 2, DW210X_WRITE_MSG); | ||
185 | break; | ||
186 | case(DW2102_RC_QUERY): | ||
187 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
188 | buf6, 2, DW210X_READ_MSG); | ||
189 | msg[0].buf[0] = buf6[0]; | ||
190 | msg[0].buf[1] = buf6[1]; | ||
191 | break; | ||
192 | case(DW2102_VOLTAGE_CTRL): | ||
193 | buf6[0] = 0x30; | ||
194 | buf6[1] = msg[0].buf[0]; | ||
195 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | ||
196 | buf6, 2, DW210X_WRITE_MSG); | ||
197 | break; | ||
198 | } | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | mutex_unlock(&d->i2c_mutex); | ||
203 | return num; | ||
204 | } | ||
205 | static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | ||
206 | { | ||
207 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
208 | int ret = 0; | ||
209 | |||
210 | if (!d) | ||
211 | return -ENODEV; | ||
212 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
213 | return -EAGAIN; | ||
214 | |||
215 | switch (num) { | ||
216 | case 2: { | ||
217 | /* read */ | ||
218 | /* first write first register number */ | ||
219 | u8 ibuf [msg[1].len + 2], obuf[3]; | ||
220 | obuf[0] = 0xd0; | ||
221 | obuf[1] = msg[0].len; | ||
222 | obuf[2] = msg[0].buf[0]; | ||
223 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
224 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
225 | /* second read registers */ | ||
226 | ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0, | ||
227 | ibuf, msg[1].len + 2, DW210X_READ_MSG); | ||
228 | memcpy(msg[1].buf, ibuf + 2, msg[1].len); | ||
229 | |||
230 | break; | ||
231 | } | ||
232 | case 1: | ||
233 | switch (msg[0].addr) { | ||
234 | case 0x68: { | ||
235 | /* write to register */ | ||
236 | u8 obuf[msg[0].len + 2]; | ||
237 | obuf[0] = 0xd0; | ||
238 | obuf[1] = msg[0].len; | ||
239 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
240 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
241 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
242 | break; | ||
243 | } | ||
244 | case 0x61: { | ||
245 | /* write to tuner */ | ||
246 | u8 obuf[msg[0].len + 2]; | ||
247 | obuf[0] = 0xc2; | ||
248 | obuf[1] = msg[0].len; | ||
249 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
250 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
251 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
252 | break; | ||
253 | } | ||
254 | case(DW2102_RC_QUERY): { | ||
255 | u8 ibuf[2]; | ||
256 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
257 | ibuf, 2, DW210X_READ_MSG); | ||
258 | memcpy(msg[0].buf, ibuf , 2); | ||
259 | break; | ||
260 | } | ||
261 | case(DW2102_VOLTAGE_CTRL): { | ||
262 | u8 obuf[2]; | ||
263 | obuf[0] = 0x30; | ||
264 | obuf[1] = msg[0].buf[0]; | ||
265 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | ||
266 | obuf, 2, DW210X_WRITE_MSG); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | break; | ||
272 | } | ||
273 | |||
274 | mutex_unlock(&d->i2c_mutex); | ||
275 | return num; | ||
276 | } | ||
277 | |||
278 | static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) | ||
279 | { | ||
280 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
281 | int ret = 0; | ||
282 | int len, i; | ||
283 | |||
284 | if (!d) | ||
285 | return -ENODEV; | ||
286 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
287 | return -EAGAIN; | ||
288 | |||
289 | switch (num) { | ||
290 | case 2: { | ||
291 | /* read */ | ||
292 | /* first write first register number */ | ||
293 | u8 ibuf [msg[1].len + 2], obuf[3]; | ||
294 | obuf[0] = 0xaa; | ||
295 | obuf[1] = msg[0].len; | ||
296 | obuf[2] = msg[0].buf[0]; | ||
297 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
298 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
299 | /* second read registers */ | ||
300 | ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0, | ||
301 | ibuf, msg[1].len + 2, DW210X_READ_MSG); | ||
302 | memcpy(msg[1].buf, ibuf + 2, msg[1].len); | ||
303 | |||
304 | break; | ||
305 | } | ||
306 | case 1: | ||
307 | switch (msg[0].addr) { | ||
308 | case 0x55: { | ||
309 | if (msg[0].buf[0] == 0xf7) { | ||
310 | /* firmware */ | ||
311 | /* Write in small blocks */ | ||
312 | u8 obuf[19]; | ||
313 | obuf[0] = 0xaa; | ||
314 | obuf[1] = 0x11; | ||
315 | obuf[2] = 0xf7; | ||
316 | len = msg[0].len - 1; | ||
317 | i = 1; | ||
318 | do { | ||
319 | memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); | ||
320 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
321 | obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); | ||
322 | i += 16; | ||
323 | len -= 16; | ||
324 | } while (len > 0); | ||
325 | } else { | ||
326 | /* write to register */ | ||
327 | u8 obuf[msg[0].len + 2]; | ||
328 | obuf[0] = 0xaa; | ||
329 | obuf[1] = msg[0].len; | ||
330 | memcpy(obuf + 2, msg[0].buf, msg[0].len); | ||
331 | ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, | ||
332 | obuf, msg[0].len + 2, DW210X_WRITE_MSG); | ||
333 | } | ||
334 | break; | ||
335 | } | ||
336 | case(DW2102_RC_QUERY): { | ||
337 | u8 ibuf[2]; | ||
338 | ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, | ||
339 | ibuf, 2, DW210X_READ_MSG); | ||
340 | memcpy(msg[0].buf, ibuf , 2); | ||
341 | break; | ||
342 | } | ||
343 | case(DW2102_VOLTAGE_CTRL): { | ||
344 | u8 obuf[2]; | ||
345 | obuf[0] = 0x30; | ||
346 | obuf[1] = msg[0].buf[0]; | ||
347 | ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, | ||
348 | obuf, 2, DW210X_WRITE_MSG); | ||
349 | break; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | break; | ||
354 | } | ||
355 | |||
356 | mutex_unlock(&d->i2c_mutex); | ||
357 | return num; | ||
358 | } | ||
359 | |||
360 | static u32 dw210x_i2c_func(struct i2c_adapter *adapter) | ||
140 | { | 361 | { |
141 | return I2C_FUNC_I2C; | 362 | return I2C_FUNC_I2C; |
142 | } | 363 | } |
143 | 364 | ||
144 | static struct i2c_algorithm dw2102_i2c_algo = { | 365 | static struct i2c_algorithm dw2102_i2c_algo = { |
145 | .master_xfer = dw2102_i2c_transfer, | 366 | .master_xfer = dw2102_i2c_transfer, |
146 | .functionality = dw2102_i2c_func, | 367 | .functionality = dw210x_i2c_func, |
368 | }; | ||
369 | |||
370 | static struct i2c_algorithm dw2102_serit_i2c_algo = { | ||
371 | .master_xfer = dw2102_serit_i2c_transfer, | ||
372 | .functionality = dw210x_i2c_func, | ||
373 | }; | ||
374 | |||
375 | static struct i2c_algorithm dw2102_earda_i2c_algo = { | ||
376 | .master_xfer = dw2102_earda_i2c_transfer, | ||
377 | .functionality = dw210x_i2c_func, | ||
378 | }; | ||
379 | |||
380 | static struct i2c_algorithm dw2104_i2c_algo = { | ||
381 | .master_xfer = dw2104_i2c_transfer, | ||
382 | .functionality = dw210x_i2c_func, | ||
147 | }; | 383 | }; |
148 | 384 | ||
149 | static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | 385 | static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) |
386 | { | ||
387 | int i; | ||
388 | u8 ibuf[] = {0, 0}; | ||
389 | u8 eeprom[256], eepromline[16]; | ||
390 | |||
391 | for (i = 0; i < 256; i++) { | ||
392 | if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { | ||
393 | err("read eeprom failed."); | ||
394 | return -1; | ||
395 | } else { | ||
396 | eepromline[i%16] = ibuf[0]; | ||
397 | eeprom[i] = ibuf[0]; | ||
398 | } | ||
399 | if ((i % 16) == 15) { | ||
400 | deb_xfer("%02x: ", i - 15); | ||
401 | debug_dump(eepromline, 16, deb_xfer); | ||
402 | } | ||
403 | } | ||
404 | memcpy(mac, eeprom + 8, 6); | ||
405 | return 0; | ||
406 | }; | ||
407 | |||
408 | static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
150 | { | 409 | { |
151 | static u8 command_13v[1] = {0x00}; | 410 | static u8 command_13v[1] = {0x00}; |
152 | static u8 command_18v[1] = {0x01}; | 411 | static u8 command_18v[1] = {0x01}; |
@@ -163,18 +422,66 @@ static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |||
163 | return 0; | 422 | return 0; |
164 | } | 423 | } |
165 | 424 | ||
166 | static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | 425 | static struct cx24116_config dw2104_config = { |
426 | .demod_address = 0x55, | ||
427 | .mpg_clk_pos_pol = 0x01, | ||
428 | }; | ||
429 | |||
430 | static struct si21xx_config serit_sp1511lhb_config = { | ||
431 | .demod_address = 0x68, | ||
432 | .min_delay_ms = 100, | ||
433 | |||
434 | }; | ||
435 | |||
436 | static int dw2104_frontend_attach(struct dvb_usb_adapter *d) | ||
167 | { | 437 | { |
168 | d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, | 438 | if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, |
169 | &d->dev->i2c_adap); | 439 | &d->dev->i2c_adap)) != NULL) { |
170 | if (d->fe != NULL) { | 440 | d->fe->ops.set_voltage = dw210x_set_voltage; |
171 | d->fe->ops.set_voltage = dw2102_set_voltage; | 441 | info("Attached cx24116!\n"); |
172 | info("Attached stv0299!\n"); | ||
173 | return 0; | 442 | return 0; |
174 | } | 443 | } |
175 | return -EIO; | 444 | return -EIO; |
176 | } | 445 | } |
177 | 446 | ||
447 | static struct dvb_usb_device_properties dw2102_properties; | ||
448 | |||
449 | static int dw2102_frontend_attach(struct dvb_usb_adapter *d) | ||
450 | { | ||
451 | if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { | ||
452 | /*dw2102_properties.adapter->tuner_attach = NULL;*/ | ||
453 | d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, | ||
454 | &d->dev->i2c_adap); | ||
455 | if (d->fe != NULL) { | ||
456 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
457 | info("Attached si21xx!\n"); | ||
458 | return 0; | ||
459 | } | ||
460 | } | ||
461 | if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { | ||
462 | /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ | ||
463 | d->fe = dvb_attach(stv0288_attach, &earda_config, | ||
464 | &d->dev->i2c_adap); | ||
465 | if (d->fe != NULL) { | ||
466 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
467 | info("Attached stv0288!\n"); | ||
468 | return 0; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { | ||
473 | /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ | ||
474 | d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, | ||
475 | &d->dev->i2c_adap); | ||
476 | if (d->fe != NULL) { | ||
477 | d->fe->ops.set_voltage = dw210x_set_voltage; | ||
478 | info("Attached stv0299!\n"); | ||
479 | return 0; | ||
480 | } | ||
481 | } | ||
482 | return -EIO; | ||
483 | } | ||
484 | |||
178 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | 485 | static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) |
179 | { | 486 | { |
180 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, | 487 | dvb_attach(dvb_pll_attach, adap->fe, 0x60, |
@@ -182,7 +489,15 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) | |||
182 | return 0; | 489 | return 0; |
183 | } | 490 | } |
184 | 491 | ||
185 | static struct dvb_usb_rc_key dw2102_rc_keys[] = { | 492 | static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) |
493 | { | ||
494 | dvb_attach(stb6000_attach, adap->fe, 0x61, | ||
495 | &adap->dev->i2c_adap); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static struct dvb_usb_rc_key dw210x_rc_keys[] = { | ||
186 | { 0xf8, 0x0a, KEY_Q }, /*power*/ | 501 | { 0xf8, 0x0a, KEY_Q }, /*power*/ |
187 | { 0xf8, 0x0c, KEY_M }, /*mute*/ | 502 | { 0xf8, 0x0c, KEY_M }, /*mute*/ |
188 | { 0xf8, 0x11, KEY_1 }, | 503 | { 0xf8, 0x11, KEY_1 }, |
@@ -221,7 +536,7 @@ static struct dvb_usb_rc_key dw2102_rc_keys[] = { | |||
221 | 536 | ||
222 | static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | 537 | static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) |
223 | { | 538 | { |
224 | struct dw2102_state *st = d->priv; | 539 | struct dw210x_state *st = d->priv; |
225 | u8 key[2]; | 540 | u8 key[2]; |
226 | struct i2c_msg msg[] = { | 541 | struct i2c_msg msg[] = { |
227 | {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, | 542 | {.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) | |||
231 | 546 | ||
232 | *state = REMOTE_NO_KEY_PRESSED; | 547 | *state = REMOTE_NO_KEY_PRESSED; |
233 | if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { | 548 | if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { |
234 | for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) { | 549 | for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) { |
235 | if (dw2102_rc_keys[i].data == msg[0].buf[0]) { | 550 | if (dw210x_rc_keys[i].data == msg[0].buf[0]) { |
236 | *state = REMOTE_KEY_PRESSED; | 551 | *state = REMOTE_KEY_PRESSED; |
237 | *event = dw2102_rc_keys[i].event; | 552 | *event = dw210x_rc_keys[i].event; |
238 | st->last_key_pressed = | 553 | st->last_key_pressed = |
239 | dw2102_rc_keys[i].event; | 554 | dw210x_rc_keys[i].event; |
240 | break; | 555 | break; |
241 | } | 556 | } |
242 | st->last_key_pressed = 0; | 557 | st->last_key_pressed = 0; |
@@ -249,6 +564,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) | |||
249 | static struct usb_device_id dw2102_table[] = { | 564 | static struct usb_device_id dw2102_table[] = { |
250 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, | 565 | {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, |
251 | {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, | 566 | {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, |
567 | {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, | ||
568 | {USB_DEVICE(0x9022, 0xd650)}, | ||
252 | { } | 569 | { } |
253 | }; | 570 | }; |
254 | 571 | ||
@@ -260,7 +577,7 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
260 | u8 *b, *p; | 577 | u8 *b, *p; |
261 | int ret = 0, i; | 578 | int ret = 0, i; |
262 | u8 reset; | 579 | u8 reset; |
263 | u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0}; | 580 | u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; |
264 | const struct firmware *fw; | 581 | const struct firmware *fw; |
265 | const char *filename = "dvb-usb-dw2101.fw"; | 582 | const char *filename = "dvb-usb-dw2101.fw"; |
266 | switch (dev->descriptor.idProduct) { | 583 | switch (dev->descriptor.idProduct) { |
@@ -273,25 +590,23 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
273 | return ret; | 590 | return ret; |
274 | } | 591 | } |
275 | break; | 592 | break; |
276 | case USB_PID_DW2102: | 593 | default: |
277 | fw = frmwr; | 594 | fw = frmwr; |
278 | break; | 595 | break; |
279 | } | 596 | } |
280 | info("start downloading DW2102 firmware"); | 597 | info("start downloading DW210X firmware"); |
281 | p = kmalloc(fw->size, GFP_KERNEL); | 598 | p = kmalloc(fw->size, GFP_KERNEL); |
282 | reset = 1; | 599 | reset = 1; |
283 | /*stop the CPU*/ | 600 | /*stop the CPU*/ |
284 | dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG); | 601 | dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); |
285 | dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG); | 602 | dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); |
286 | 603 | ||
287 | if (p != NULL) { | 604 | if (p != NULL) { |
288 | memcpy(p, fw->data, fw->size); | 605 | memcpy(p, fw->data, fw->size); |
289 | for (i = 0; i < fw->size; i += 0x40) { | 606 | for (i = 0; i < fw->size; i += 0x40) { |
290 | b = (u8 *) p + i; | 607 | b = (u8 *) p + i; |
291 | if (dw2102_op_rw | 608 | if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, |
292 | (dev, 0xa0, i, b , 0x40, | 609 | DW210X_WRITE_MSG) != 0x40) { |
293 | DW2102_WRITE_MSG) != 0x40 | ||
294 | ) { | ||
295 | err("error while transferring firmware"); | 610 | err("error while transferring firmware"); |
296 | ret = -EINVAL; | 611 | ret = -EINVAL; |
297 | break; | 612 | break; |
@@ -299,43 +614,66 @@ static int dw2102_load_firmware(struct usb_device *dev, | |||
299 | } | 614 | } |
300 | /* restart the CPU */ | 615 | /* restart the CPU */ |
301 | reset = 0; | 616 | reset = 0; |
302 | if (ret || dw2102_op_rw | 617 | if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, |
303 | (dev, 0xa0, 0x7f92, &reset, 1, | 618 | DW210X_WRITE_MSG) != 1) { |
304 | DW2102_WRITE_MSG) != 1) { | ||
305 | err("could not restart the USB controller CPU."); | 619 | err("could not restart the USB controller CPU."); |
306 | ret = -EINVAL; | 620 | ret = -EINVAL; |
307 | } | 621 | } |
308 | if (ret || dw2102_op_rw | 622 | if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, |
309 | (dev, 0xa0, 0xe600, &reset, 1, | 623 | DW210X_WRITE_MSG) != 1) { |
310 | DW2102_WRITE_MSG) != 1) { | ||
311 | err("could not restart the USB controller CPU."); | 624 | err("could not restart the USB controller CPU."); |
312 | ret = -EINVAL; | 625 | ret = -EINVAL; |
313 | } | 626 | } |
314 | /* init registers */ | 627 | /* init registers */ |
315 | switch (dev->descriptor.idProduct) { | 628 | switch (dev->descriptor.idProduct) { |
316 | case USB_PID_DW2102: | 629 | case USB_PID_DW2104: |
317 | dw2102_op_rw | 630 | case 0xd650: |
318 | (dev, 0xbf, 0x0040, &reset, 0, | 631 | reset = 1; |
319 | DW2102_WRITE_MSG); | 632 | dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, |
320 | dw2102_op_rw | 633 | DW210X_WRITE_MSG); |
321 | (dev, 0xb9, 0x0000, &reset16[0], 2, | 634 | reset = 0; |
322 | DW2102_READ_MSG); | 635 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, |
636 | DW210X_WRITE_MSG); | ||
323 | break; | 637 | break; |
638 | case USB_PID_DW2102: | ||
639 | dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, | ||
640 | DW210X_WRITE_MSG); | ||
641 | dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, | ||
642 | DW210X_READ_MSG); | ||
643 | /* check STV0299 frontend */ | ||
644 | dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, | ||
645 | DW210X_READ_MSG); | ||
646 | if (reset16[0] == 0xa1) { | ||
647 | dw2102_properties.i2c_algo = &dw2102_i2c_algo; | ||
648 | dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; | ||
649 | break; | ||
650 | } else { | ||
651 | /* check STV0288 frontend */ | ||
652 | reset16[0] = 0xd0; | ||
653 | reset16[1] = 1; | ||
654 | reset16[2] = 0; | ||
655 | dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, | ||
656 | DW210X_WRITE_MSG); | ||
657 | dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, | ||
658 | DW210X_READ_MSG); | ||
659 | if (reset16[2] == 0x11) { | ||
660 | dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; | ||
661 | dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach; | ||
662 | break; | ||
663 | } | ||
664 | } | ||
324 | case 0x2101: | 665 | case 0x2101: |
325 | dw2102_op_rw | 666 | dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, |
326 | (dev, 0xbc, 0x0030, &reset16[0], 2, | 667 | DW210X_READ_MSG); |
327 | DW2102_READ_MSG); | 668 | dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, |
328 | dw2102_op_rw | 669 | DW210X_READ_MSG); |
329 | (dev, 0xba, 0x0000, &reset16[0], 7, | 670 | dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, |
330 | DW2102_READ_MSG); | 671 | DW210X_READ_MSG); |
331 | dw2102_op_rw | 672 | dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, |
332 | (dev, 0xba, 0x0000, &reset16[0], 7, | 673 | DW210X_READ_MSG); |
333 | DW2102_READ_MSG); | ||
334 | dw2102_op_rw | ||
335 | (dev, 0xb9, 0x0000, &reset16[0], 2, | ||
336 | DW2102_READ_MSG); | ||
337 | break; | 674 | break; |
338 | } | 675 | } |
676 | msleep(100); | ||
339 | kfree(p); | 677 | kfree(p); |
340 | } | 678 | } |
341 | return ret; | 679 | return ret; |
@@ -345,12 +683,12 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
345 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | 683 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, |
346 | .usb_ctrl = DEVICE_SPECIFIC, | 684 | .usb_ctrl = DEVICE_SPECIFIC, |
347 | .firmware = "dvb-usb-dw2102.fw", | 685 | .firmware = "dvb-usb-dw2102.fw", |
348 | .size_of_priv = sizeof(struct dw2102_state), | 686 | .size_of_priv = sizeof(struct dw210x_state), |
349 | .no_reconnect = 1, | 687 | .no_reconnect = 1, |
350 | 688 | ||
351 | .i2c_algo = &dw2102_i2c_algo, | 689 | .i2c_algo = &dw2102_serit_i2c_algo, |
352 | .rc_key_map = dw2102_rc_keys, | 690 | .rc_key_map = dw210x_rc_keys, |
353 | .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys), | 691 | .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), |
354 | .rc_interval = 150, | 692 | .rc_interval = 150, |
355 | .rc_query = dw2102_rc_query, | 693 | .rc_query = dw2102_rc_query, |
356 | 694 | ||
@@ -358,11 +696,12 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
358 | /* parameter for the MPEG2-data transfer */ | 696 | /* parameter for the MPEG2-data transfer */ |
359 | .num_adapters = 1, | 697 | .num_adapters = 1, |
360 | .download_firmware = dw2102_load_firmware, | 698 | .download_firmware = dw2102_load_firmware, |
361 | .adapter = { | 699 | .read_mac_address = dw210x_read_mac_address, |
700 | .adapter = { | ||
362 | { | 701 | { |
363 | .frontend_attach = dw2102_frontend_attach, | 702 | .frontend_attach = dw2102_frontend_attach, |
364 | .streaming_ctrl = NULL, | 703 | .streaming_ctrl = NULL, |
365 | .tuner_attach = dw2102_tuner_attach, | 704 | .tuner_attach = NULL, |
366 | .stream = { | 705 | .stream = { |
367 | .type = USB_BULK, | 706 | .type = USB_BULK, |
368 | .count = 8, | 707 | .count = 8, |
@@ -388,11 +727,64 @@ static struct dvb_usb_device_properties dw2102_properties = { | |||
388 | } | 727 | } |
389 | }; | 728 | }; |
390 | 729 | ||
730 | static struct dvb_usb_device_properties dw2104_properties = { | ||
731 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
732 | .usb_ctrl = DEVICE_SPECIFIC, | ||
733 | .firmware = "dvb-usb-dw2104.fw", | ||
734 | .size_of_priv = sizeof(struct dw210x_state), | ||
735 | .no_reconnect = 1, | ||
736 | |||
737 | .i2c_algo = &dw2104_i2c_algo, | ||
738 | .rc_key_map = dw210x_rc_keys, | ||
739 | .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), | ||
740 | .rc_interval = 150, | ||
741 | .rc_query = dw2102_rc_query, | ||
742 | |||
743 | .generic_bulk_ctrl_endpoint = 0x81, | ||
744 | /* parameter for the MPEG2-data transfer */ | ||
745 | .num_adapters = 1, | ||
746 | .download_firmware = dw2102_load_firmware, | ||
747 | .read_mac_address = dw210x_read_mac_address, | ||
748 | .adapter = { | ||
749 | { | ||
750 | .frontend_attach = dw2104_frontend_attach, | ||
751 | .streaming_ctrl = NULL, | ||
752 | /*.tuner_attach = dw2104_tuner_attach,*/ | ||
753 | .stream = { | ||
754 | .type = USB_BULK, | ||
755 | .count = 8, | ||
756 | .endpoint = 0x82, | ||
757 | .u = { | ||
758 | .bulk = { | ||
759 | .buffersize = 4096, | ||
760 | } | ||
761 | } | ||
762 | }, | ||
763 | } | ||
764 | }, | ||
765 | .num_device_descs = 2, | ||
766 | .devices = { | ||
767 | { "DVBWorld DW2104 USB2.0", | ||
768 | {&dw2102_table[2], NULL}, | ||
769 | {NULL}, | ||
770 | }, | ||
771 | { "TeVii S650 USB2.0", | ||
772 | {&dw2102_table[3], NULL}, | ||
773 | {NULL}, | ||
774 | }, | ||
775 | } | ||
776 | }; | ||
777 | |||
391 | static int dw2102_probe(struct usb_interface *intf, | 778 | static int dw2102_probe(struct usb_interface *intf, |
392 | const struct usb_device_id *id) | 779 | const struct usb_device_id *id) |
393 | { | 780 | { |
394 | return dvb_usb_device_init(intf, &dw2102_properties, | 781 | if (0 == dvb_usb_device_init(intf, &dw2102_properties, |
395 | THIS_MODULE, NULL, adapter_nr); | 782 | THIS_MODULE, NULL, adapter_nr) || |
783 | 0 == dvb_usb_device_init(intf, &dw2104_properties, | ||
784 | THIS_MODULE, NULL, adapter_nr)) { | ||
785 | return 0; | ||
786 | } | ||
787 | return -ENODEV; | ||
396 | } | 788 | } |
397 | 789 | ||
398 | static struct usb_driver dw2102_driver = { | 790 | static struct usb_driver dw2102_driver = { |
@@ -420,6 +812,6 @@ module_init(dw2102_module_init); | |||
420 | module_exit(dw2102_module_exit); | 812 | module_exit(dw2102_module_exit); |
421 | 813 | ||
422 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); | 814 | MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); |
423 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device"); | 815 | MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device"); |
424 | MODULE_VERSION("0.1"); | 816 | MODULE_VERSION("0.1"); |
425 | MODULE_LICENSE("GPL"); | 817 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h index 7a310f906837..e3370734e95a 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.h +++ b/drivers/media/dvb/dvb-usb/dw2102.h | |||
@@ -4,6 +4,5 @@ | |||
4 | #define DVB_USB_LOG_PREFIX "dw2102" | 4 | #define DVB_USB_LOG_PREFIX "dw2102" |
5 | #include "dvb-usb.h" | 5 | #include "dvb-usb.h" |
6 | 6 | ||
7 | extern int dvb_usb_dw2102_debug; | ||
8 | #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) | 7 | #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) |
9 | #endif | 8 | #endif |
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 7dbb4a223c99..96b93e21a84b 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -43,6 +43,20 @@ config DVB_S5H1420 | |||
43 | help | 43 | help |
44 | A DVB-S tuner module. Say Y when you want to support this frontend. | 44 | A DVB-S tuner module. Say Y when you want to support this frontend. |
45 | 45 | ||
46 | config DVB_STV0288 | ||
47 | tristate "ST STV0288 based" | ||
48 | depends on DVB_CORE && I2C | ||
49 | default m if DVB_FE_CUSTOMISE | ||
50 | help | ||
51 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
52 | |||
53 | config DVB_STB6000 | ||
54 | tristate "ST STB6000 silicon tuner" | ||
55 | depends on DVB_CORE && I2C | ||
56 | default m if DVB_FE_CUSTOMISE | ||
57 | help | ||
58 | A DVB-S silicon tuner module. Say Y when you want to support this tuner. | ||
59 | |||
46 | config DVB_STV0299 | 60 | config DVB_STV0299 |
47 | tristate "ST STV0299 based" | 61 | tristate "ST STV0299 based" |
48 | depends on DVB_CORE && I2C | 62 | depends on DVB_CORE && I2C |
@@ -92,6 +106,20 @@ config DVB_TUA6100 | |||
92 | help | 106 | help |
93 | A DVB-S PLL chip. | 107 | A DVB-S PLL chip. |
94 | 108 | ||
109 | config DVB_CX24116 | ||
110 | tristate "Conexant CX24116 based" | ||
111 | depends on DVB_CORE && I2C | ||
112 | default m if DVB_FE_CUSTOMISE | ||
113 | help | ||
114 | A DVB-S/S2 tuner module. Say Y when you want to support this frontend. | ||
115 | |||
116 | config DVB_SI21XX | ||
117 | tristate "Silicon Labs SI21XX based" | ||
118 | depends on DVB_CORE && I2C | ||
119 | default m if DVB_FE_CUSTOMISE | ||
120 | help | ||
121 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
122 | |||
95 | comment "DVB-T (terrestrial) frontends" | 123 | comment "DVB-T (terrestrial) frontends" |
96 | depends on DVB_CORE | 124 | depends on DVB_CORE |
97 | 125 | ||
@@ -385,4 +413,23 @@ config DVB_ISL6421 | |||
385 | help | 413 | help |
386 | An SEC control chip. | 414 | An SEC control chip. |
387 | 415 | ||
416 | config DVB_LGS8GL5 | ||
417 | tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" | ||
418 | depends on DVB_CORE && I2C | ||
419 | default m if DVB_FE_CUSTOMISE | ||
420 | help | ||
421 | A DMB-TH tuner module. Say Y when you want to support this frontend. | ||
422 | |||
423 | comment "Tools to develop new frontends" | ||
424 | |||
425 | config DVB_DUMMY_FE | ||
426 | tristate "Dummy frontend driver" | ||
427 | default n | ||
428 | |||
429 | config DVB_AF9013 | ||
430 | tristate "Afatech AF9013 demodulator" | ||
431 | depends on DVB_CORE && I2C | ||
432 | default m if DVB_FE_CUSTOMISE | ||
433 | help | ||
434 | Say Y when you want to support this frontend. | ||
388 | endmenu | 435 | endmenu |
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 028da55611c0..aba79f4a63a7 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -48,3 +48,10 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o | |||
48 | obj-$(CONFIG_DVB_AU8522) += au8522.o | 48 | obj-$(CONFIG_DVB_AU8522) += au8522.o |
49 | obj-$(CONFIG_DVB_TDA10048) += tda10048.o | 49 | obj-$(CONFIG_DVB_TDA10048) += tda10048.o |
50 | obj-$(CONFIG_DVB_S5H1411) += s5h1411.o | 50 | obj-$(CONFIG_DVB_S5H1411) += s5h1411.o |
51 | obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o | ||
52 | obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o | ||
53 | obj-$(CONFIG_DVB_AF9013) += af9013.o | ||
54 | obj-$(CONFIG_DVB_CX24116) += cx24116.o | ||
55 | obj-$(CONFIG_DVB_SI21XX) += si21xx.o | ||
56 | obj-$(CONFIG_DVB_STV0288) += stv0288.o | ||
57 | obj-$(CONFIG_DVB_STB6000) += stb6000.o | ||
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c new file mode 100644 index 000000000000..21c1060cf10e --- /dev/null +++ b/drivers/media/dvb/frontends/af9013.c | |||
@@ -0,0 +1,1685 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/firmware.h> | ||
32 | |||
33 | #include "dvb_frontend.h" | ||
34 | #include "af9013_priv.h" | ||
35 | #include "af9013.h" | ||
36 | |||
37 | int af9013_debug; | ||
38 | |||
39 | struct af9013_state { | ||
40 | struct i2c_adapter *i2c; | ||
41 | struct dvb_frontend frontend; | ||
42 | |||
43 | struct af9013_config config; | ||
44 | |||
45 | u16 signal_strength; | ||
46 | u32 ber; | ||
47 | u32 ucblocks; | ||
48 | u16 snr; | ||
49 | u32 frequency; | ||
50 | unsigned long next_statistics_check; | ||
51 | }; | ||
52 | |||
53 | static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; | ||
54 | |||
55 | static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, | ||
56 | u8 *val, u8 len) | ||
57 | { | ||
58 | u8 buf[3+len]; | ||
59 | struct i2c_msg msg = { | ||
60 | .addr = state->config.demod_address, | ||
61 | .flags = 0, | ||
62 | .len = sizeof(buf), | ||
63 | .buf = buf }; | ||
64 | |||
65 | buf[0] = reg >> 8; | ||
66 | buf[1] = reg & 0xff; | ||
67 | buf[2] = mbox; | ||
68 | memcpy(&buf[3], val, len); | ||
69 | |||
70 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
71 | warn("I2C write failed reg:%04x len:%d", reg, len); | ||
72 | return -EREMOTEIO; | ||
73 | } | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, | ||
78 | u8 len) | ||
79 | { | ||
80 | u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); | ||
81 | return af9013_write_regs(state, mbox, reg, val, len); | ||
82 | } | ||
83 | |||
84 | static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, | ||
85 | u8 len) | ||
86 | { | ||
87 | u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); | ||
88 | return af9013_write_regs(state, mbox, reg, val, len); | ||
89 | } | ||
90 | |||
91 | /* write single register */ | ||
92 | static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) | ||
93 | { | ||
94 | return af9013_write_ofdm_regs(state, reg, &val, 1); | ||
95 | } | ||
96 | |||
97 | /* read single register */ | ||
98 | static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) | ||
99 | { | ||
100 | u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; | ||
101 | u8 ibuf[1]; | ||
102 | struct i2c_msg msg[2] = { | ||
103 | { | ||
104 | .addr = state->config.demod_address, | ||
105 | .flags = 0, | ||
106 | .len = sizeof(obuf), | ||
107 | .buf = obuf | ||
108 | }, { | ||
109 | .addr = state->config.demod_address, | ||
110 | .flags = I2C_M_RD, | ||
111 | .len = sizeof(ibuf), | ||
112 | .buf = ibuf | ||
113 | } | ||
114 | }; | ||
115 | |||
116 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
117 | warn("I2C read failed reg:%04x", reg); | ||
118 | return -EREMOTEIO; | ||
119 | } | ||
120 | *val = ibuf[0]; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, | ||
125 | u8 len, u8 val) | ||
126 | { | ||
127 | int ret; | ||
128 | u8 tmp, mask; | ||
129 | |||
130 | ret = af9013_read_reg(state, reg, &tmp); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | mask = regmask[len - 1] << pos; | ||
135 | tmp = (tmp & ~mask) | ((val << pos) & mask); | ||
136 | |||
137 | return af9013_write_reg(state, reg, tmp); | ||
138 | } | ||
139 | |||
140 | static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, | ||
141 | u8 len, u8 *val) | ||
142 | { | ||
143 | int ret; | ||
144 | u8 tmp; | ||
145 | |||
146 | ret = af9013_read_reg(state, reg, &tmp); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | *val = (tmp >> pos) & regmask[len - 1]; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) | ||
154 | { | ||
155 | int ret; | ||
156 | u8 pos; | ||
157 | u16 addr; | ||
158 | deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); | ||
159 | |||
160 | /* GPIO0 & GPIO1 0xd735 | ||
161 | GPIO2 & GPIO3 0xd736 */ | ||
162 | |||
163 | switch (gpio) { | ||
164 | case 0: | ||
165 | case 1: | ||
166 | addr = 0xd735; | ||
167 | break; | ||
168 | case 2: | ||
169 | case 3: | ||
170 | addr = 0xd736; | ||
171 | break; | ||
172 | |||
173 | default: | ||
174 | err("invalid gpio:%d\n", gpio); | ||
175 | ret = -EINVAL; | ||
176 | goto error; | ||
177 | }; | ||
178 | |||
179 | switch (gpio) { | ||
180 | case 0: | ||
181 | case 2: | ||
182 | pos = 0; | ||
183 | break; | ||
184 | case 1: | ||
185 | case 3: | ||
186 | default: | ||
187 | pos = 4; | ||
188 | break; | ||
189 | }; | ||
190 | |||
191 | ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); | ||
192 | |||
193 | error: | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static u32 af913_div(u32 a, u32 b, u32 x) | ||
198 | { | ||
199 | u32 r = 0, c = 0, i; | ||
200 | deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); | ||
201 | |||
202 | if (a > b) { | ||
203 | c = a / b; | ||
204 | a = a - c * b; | ||
205 | } | ||
206 | |||
207 | for (i = 0; i < x; i++) { | ||
208 | if (a >= b) { | ||
209 | r += 1; | ||
210 | a -= b; | ||
211 | } | ||
212 | a <<= 1; | ||
213 | r <<= 1; | ||
214 | } | ||
215 | r = (c << (u32)x) + r; | ||
216 | |||
217 | deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); | ||
218 | return r; | ||
219 | } | ||
220 | |||
221 | static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) | ||
222 | { | ||
223 | int ret = 0; | ||
224 | u8 i = 0; | ||
225 | u8 buf[24]; | ||
226 | u32 ns_coeff1_2048nu; | ||
227 | u32 ns_coeff1_8191nu; | ||
228 | u32 ns_coeff1_8192nu; | ||
229 | u32 ns_coeff1_8193nu; | ||
230 | u32 ns_coeff2_2k; | ||
231 | u32 ns_coeff2_8k; | ||
232 | |||
233 | deb_info("%s: adc_clock:%d bw:%d\n", __func__, | ||
234 | state->config.adc_clock, bw); | ||
235 | |||
236 | switch (state->config.adc_clock) { | ||
237 | case 28800: /* 28.800 MHz */ | ||
238 | switch (bw) { | ||
239 | case BANDWIDTH_6_MHZ: | ||
240 | ns_coeff1_2048nu = 0x01e79e7a; | ||
241 | ns_coeff1_8191nu = 0x0079eb6e; | ||
242 | ns_coeff1_8192nu = 0x0079e79e; | ||
243 | ns_coeff1_8193nu = 0x0079e3cf; | ||
244 | ns_coeff2_2k = 0x00f3cf3d; | ||
245 | ns_coeff2_8k = 0x003cf3cf; | ||
246 | break; | ||
247 | case BANDWIDTH_7_MHZ: | ||
248 | ns_coeff1_2048nu = 0x0238e38e; | ||
249 | ns_coeff1_8191nu = 0x008e3d55; | ||
250 | ns_coeff1_8192nu = 0x008e38e4; | ||
251 | ns_coeff1_8193nu = 0x008e3472; | ||
252 | ns_coeff2_2k = 0x011c71c7; | ||
253 | ns_coeff2_8k = 0x00471c72; | ||
254 | break; | ||
255 | case BANDWIDTH_8_MHZ: | ||
256 | ns_coeff1_2048nu = 0x028a28a3; | ||
257 | ns_coeff1_8191nu = 0x00a28f3d; | ||
258 | ns_coeff1_8192nu = 0x00a28a29; | ||
259 | ns_coeff1_8193nu = 0x00a28514; | ||
260 | ns_coeff2_2k = 0x01451451; | ||
261 | ns_coeff2_8k = 0x00514514; | ||
262 | break; | ||
263 | default: | ||
264 | ret = -EINVAL; | ||
265 | } | ||
266 | break; | ||
267 | case 20480: /* 20.480 MHz */ | ||
268 | switch (bw) { | ||
269 | case BANDWIDTH_6_MHZ: | ||
270 | ns_coeff1_2048nu = 0x02adb6dc; | ||
271 | ns_coeff1_8191nu = 0x00ab7313; | ||
272 | ns_coeff1_8192nu = 0x00ab6db7; | ||
273 | ns_coeff1_8193nu = 0x00ab685c; | ||
274 | ns_coeff2_2k = 0x0156db6e; | ||
275 | ns_coeff2_8k = 0x0055b6dc; | ||
276 | break; | ||
277 | case BANDWIDTH_7_MHZ: | ||
278 | ns_coeff1_2048nu = 0x03200001; | ||
279 | ns_coeff1_8191nu = 0x00c80640; | ||
280 | ns_coeff1_8192nu = 0x00c80000; | ||
281 | ns_coeff1_8193nu = 0x00c7f9c0; | ||
282 | ns_coeff2_2k = 0x01900000; | ||
283 | ns_coeff2_8k = 0x00640000; | ||
284 | break; | ||
285 | case BANDWIDTH_8_MHZ: | ||
286 | ns_coeff1_2048nu = 0x03924926; | ||
287 | ns_coeff1_8191nu = 0x00e4996e; | ||
288 | ns_coeff1_8192nu = 0x00e49249; | ||
289 | ns_coeff1_8193nu = 0x00e48b25; | ||
290 | ns_coeff2_2k = 0x01c92493; | ||
291 | ns_coeff2_8k = 0x00724925; | ||
292 | break; | ||
293 | default: | ||
294 | ret = -EINVAL; | ||
295 | } | ||
296 | break; | ||
297 | case 28000: /* 28.000 MHz */ | ||
298 | switch (bw) { | ||
299 | case BANDWIDTH_6_MHZ: | ||
300 | ns_coeff1_2048nu = 0x01f58d10; | ||
301 | ns_coeff1_8191nu = 0x007d672f; | ||
302 | ns_coeff1_8192nu = 0x007d6344; | ||
303 | ns_coeff1_8193nu = 0x007d5f59; | ||
304 | ns_coeff2_2k = 0x00fac688; | ||
305 | ns_coeff2_8k = 0x003eb1a2; | ||
306 | break; | ||
307 | case BANDWIDTH_7_MHZ: | ||
308 | ns_coeff1_2048nu = 0x02492492; | ||
309 | ns_coeff1_8191nu = 0x00924db7; | ||
310 | ns_coeff1_8192nu = 0x00924925; | ||
311 | ns_coeff1_8193nu = 0x00924492; | ||
312 | ns_coeff2_2k = 0x01249249; | ||
313 | ns_coeff2_8k = 0x00492492; | ||
314 | break; | ||
315 | case BANDWIDTH_8_MHZ: | ||
316 | ns_coeff1_2048nu = 0x029cbc15; | ||
317 | ns_coeff1_8191nu = 0x00a7343f; | ||
318 | ns_coeff1_8192nu = 0x00a72f05; | ||
319 | ns_coeff1_8193nu = 0x00a729cc; | ||
320 | ns_coeff2_2k = 0x014e5e0a; | ||
321 | ns_coeff2_8k = 0x00539783; | ||
322 | break; | ||
323 | default: | ||
324 | ret = -EINVAL; | ||
325 | } | ||
326 | break; | ||
327 | case 25000: /* 25.000 MHz */ | ||
328 | switch (bw) { | ||
329 | case BANDWIDTH_6_MHZ: | ||
330 | ns_coeff1_2048nu = 0x0231bcb5; | ||
331 | ns_coeff1_8191nu = 0x008c7391; | ||
332 | ns_coeff1_8192nu = 0x008c6f2d; | ||
333 | ns_coeff1_8193nu = 0x008c6aca; | ||
334 | ns_coeff2_2k = 0x0118de5b; | ||
335 | ns_coeff2_8k = 0x00463797; | ||
336 | break; | ||
337 | case BANDWIDTH_7_MHZ: | ||
338 | ns_coeff1_2048nu = 0x028f5c29; | ||
339 | ns_coeff1_8191nu = 0x00a3dc29; | ||
340 | ns_coeff1_8192nu = 0x00a3d70a; | ||
341 | ns_coeff1_8193nu = 0x00a3d1ec; | ||
342 | ns_coeff2_2k = 0x0147ae14; | ||
343 | ns_coeff2_8k = 0x0051eb85; | ||
344 | break; | ||
345 | case BANDWIDTH_8_MHZ: | ||
346 | ns_coeff1_2048nu = 0x02ecfb9d; | ||
347 | ns_coeff1_8191nu = 0x00bb44c1; | ||
348 | ns_coeff1_8192nu = 0x00bb3ee7; | ||
349 | ns_coeff1_8193nu = 0x00bb390d; | ||
350 | ns_coeff2_2k = 0x01767dce; | ||
351 | ns_coeff2_8k = 0x005d9f74; | ||
352 | break; | ||
353 | default: | ||
354 | ret = -EINVAL; | ||
355 | } | ||
356 | break; | ||
357 | default: | ||
358 | err("invalid xtal"); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | if (ret) { | ||
362 | err("invalid bandwidth"); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24); | ||
367 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16); | ||
368 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8); | ||
369 | buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff)); | ||
370 | buf[i++] = (u8) ((ns_coeff2_2k & 0x01c00000) >> 22); | ||
371 | buf[i++] = (u8) ((ns_coeff2_2k & 0x003fc000) >> 14); | ||
372 | buf[i++] = (u8) ((ns_coeff2_2k & 0x00003fc0) >> 6); | ||
373 | buf[i++] = (u8) ((ns_coeff2_2k & 0x0000003f)); | ||
374 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24); | ||
375 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16); | ||
376 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8); | ||
377 | buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff)); | ||
378 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24); | ||
379 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16); | ||
380 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8); | ||
381 | buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff)); | ||
382 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24); | ||
383 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16); | ||
384 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8); | ||
385 | buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff)); | ||
386 | buf[i++] = (u8) ((ns_coeff2_8k & 0x01c00000) >> 22); | ||
387 | buf[i++] = (u8) ((ns_coeff2_8k & 0x003fc000) >> 14); | ||
388 | buf[i++] = (u8) ((ns_coeff2_8k & 0x00003fc0) >> 6); | ||
389 | buf[i++] = (u8) ((ns_coeff2_8k & 0x0000003f)); | ||
390 | |||
391 | deb_info("%s: coeff:", __func__); | ||
392 | debug_dump(buf, sizeof(buf), deb_info); | ||
393 | |||
394 | /* program */ | ||
395 | for (i = 0; i < sizeof(buf); i++) { | ||
396 | ret = af9013_write_reg(state, 0xae00 + i, buf[i]); | ||
397 | if (ret) | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int af9013_set_adc_ctrl(struct af9013_state *state) | ||
405 | { | ||
406 | int ret; | ||
407 | u8 buf[3], tmp, i; | ||
408 | u32 adc_cw; | ||
409 | |||
410 | deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); | ||
411 | |||
412 | /* adc frequency type */ | ||
413 | switch (state->config.adc_clock) { | ||
414 | case 28800: /* 28.800 MHz */ | ||
415 | tmp = 0; | ||
416 | break; | ||
417 | case 20480: /* 20.480 MHz */ | ||
418 | tmp = 1; | ||
419 | break; | ||
420 | case 28000: /* 28.000 MHz */ | ||
421 | tmp = 2; | ||
422 | break; | ||
423 | case 25000: /* 25.000 MHz */ | ||
424 | tmp = 3; | ||
425 | break; | ||
426 | default: | ||
427 | err("invalid xtal"); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); | ||
432 | |||
433 | buf[0] = (u8) ((adc_cw & 0x000000ff)); | ||
434 | buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); | ||
435 | buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); | ||
436 | |||
437 | deb_info("%s: adc_cw:", __func__); | ||
438 | debug_dump(buf, sizeof(buf), deb_info); | ||
439 | |||
440 | /* program */ | ||
441 | for (i = 0; i < sizeof(buf); i++) { | ||
442 | ret = af9013_write_reg(state, 0xd180 + i, buf[i]); | ||
443 | if (ret) | ||
444 | goto error; | ||
445 | } | ||
446 | ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); | ||
447 | error: | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) | ||
452 | { | ||
453 | int ret; | ||
454 | u16 addr; | ||
455 | u8 buf[3], i, j; | ||
456 | u32 adc_freq, freq_cw; | ||
457 | s8 bfs_spec_inv; | ||
458 | int if_sample_freq; | ||
459 | |||
460 | for (j = 0; j < 3; j++) { | ||
461 | if (j == 0) { | ||
462 | addr = 0xd140; /* fcw normal */ | ||
463 | bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; | ||
464 | } else if (j == 1) { | ||
465 | addr = 0x9be7; /* fcw dummy ram */ | ||
466 | bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; | ||
467 | } else { | ||
468 | addr = 0x9bea; /* fcw inverted */ | ||
469 | bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; | ||
470 | } | ||
471 | |||
472 | adc_freq = state->config.adc_clock * 1000; | ||
473 | if_sample_freq = state->config.tuner_if * 1000; | ||
474 | |||
475 | /* TDA18271 uses different sampling freq for every bw */ | ||
476 | if (state->config.tuner == AF9013_TUNER_TDA18271) { | ||
477 | switch (bw) { | ||
478 | case BANDWIDTH_6_MHZ: | ||
479 | if_sample_freq = 3300000; /* 3.3 MHz */ | ||
480 | break; | ||
481 | case BANDWIDTH_7_MHZ: | ||
482 | if_sample_freq = 3800000; /* 3.8 MHz */ | ||
483 | break; | ||
484 | case BANDWIDTH_8_MHZ: | ||
485 | default: | ||
486 | if_sample_freq = 4300000; /* 4.3 MHz */ | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | while (if_sample_freq > (adc_freq / 2)) | ||
492 | if_sample_freq = if_sample_freq - adc_freq; | ||
493 | |||
494 | if (if_sample_freq >= 0) | ||
495 | bfs_spec_inv = bfs_spec_inv * (-1); | ||
496 | else | ||
497 | if_sample_freq = if_sample_freq * (-1); | ||
498 | |||
499 | freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); | ||
500 | |||
501 | if (bfs_spec_inv == -1) | ||
502 | freq_cw = 0x00800000 - freq_cw; | ||
503 | |||
504 | buf[0] = (u8) ((freq_cw & 0x000000ff)); | ||
505 | buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); | ||
506 | buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); | ||
507 | |||
508 | |||
509 | deb_info("%s: freq_cw:", __func__); | ||
510 | debug_dump(buf, sizeof(buf), deb_info); | ||
511 | |||
512 | /* program */ | ||
513 | for (i = 0; i < sizeof(buf); i++) { | ||
514 | ret = af9013_write_reg(state, addr++, buf[i]); | ||
515 | if (ret) | ||
516 | goto error; | ||
517 | } | ||
518 | } | ||
519 | error: | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | static int af9013_set_ofdm_params(struct af9013_state *state, | ||
524 | struct dvb_ofdm_parameters *params, u8 *auto_mode) | ||
525 | { | ||
526 | int ret; | ||
527 | u8 i, buf[3] = {0, 0, 0}; | ||
528 | *auto_mode = 0; /* set if parameters are requested to auto set */ | ||
529 | |||
530 | switch (params->transmission_mode) { | ||
531 | case TRANSMISSION_MODE_AUTO: | ||
532 | *auto_mode = 1; | ||
533 | case TRANSMISSION_MODE_2K: | ||
534 | break; | ||
535 | case TRANSMISSION_MODE_8K: | ||
536 | buf[0] |= (1 << 0); | ||
537 | break; | ||
538 | default: | ||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | switch (params->guard_interval) { | ||
543 | case GUARD_INTERVAL_AUTO: | ||
544 | *auto_mode = 1; | ||
545 | case GUARD_INTERVAL_1_32: | ||
546 | break; | ||
547 | case GUARD_INTERVAL_1_16: | ||
548 | buf[0] |= (1 << 2); | ||
549 | break; | ||
550 | case GUARD_INTERVAL_1_8: | ||
551 | buf[0] |= (2 << 2); | ||
552 | break; | ||
553 | case GUARD_INTERVAL_1_4: | ||
554 | buf[0] |= (3 << 2); | ||
555 | break; | ||
556 | default: | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
560 | switch (params->hierarchy_information) { | ||
561 | case HIERARCHY_AUTO: | ||
562 | *auto_mode = 1; | ||
563 | case HIERARCHY_NONE: | ||
564 | break; | ||
565 | case HIERARCHY_1: | ||
566 | buf[0] |= (1 << 4); | ||
567 | break; | ||
568 | case HIERARCHY_2: | ||
569 | buf[0] |= (2 << 4); | ||
570 | break; | ||
571 | case HIERARCHY_4: | ||
572 | buf[0] |= (3 << 4); | ||
573 | break; | ||
574 | default: | ||
575 | return -EINVAL; | ||
576 | }; | ||
577 | |||
578 | switch (params->constellation) { | ||
579 | case QAM_AUTO: | ||
580 | *auto_mode = 1; | ||
581 | case QPSK: | ||
582 | break; | ||
583 | case QAM_16: | ||
584 | buf[1] |= (1 << 6); | ||
585 | break; | ||
586 | case QAM_64: | ||
587 | buf[1] |= (2 << 6); | ||
588 | break; | ||
589 | default: | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | |||
593 | /* Use HP. How and which case we can switch to LP? */ | ||
594 | buf[1] |= (1 << 4); | ||
595 | |||
596 | switch (params->code_rate_HP) { | ||
597 | case FEC_AUTO: | ||
598 | *auto_mode = 1; | ||
599 | case FEC_1_2: | ||
600 | break; | ||
601 | case FEC_2_3: | ||
602 | buf[2] |= (1 << 0); | ||
603 | break; | ||
604 | case FEC_3_4: | ||
605 | buf[2] |= (2 << 0); | ||
606 | break; | ||
607 | case FEC_5_6: | ||
608 | buf[2] |= (3 << 0); | ||
609 | break; | ||
610 | case FEC_7_8: | ||
611 | buf[2] |= (4 << 0); | ||
612 | break; | ||
613 | default: | ||
614 | return -EINVAL; | ||
615 | } | ||
616 | |||
617 | switch (params->code_rate_LP) { | ||
618 | case FEC_AUTO: | ||
619 | /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO | ||
620 | by dvb_frontend.c for compatibility */ | ||
621 | if (params->hierarchy_information != HIERARCHY_NONE) | ||
622 | *auto_mode = 1; | ||
623 | case FEC_1_2: | ||
624 | break; | ||
625 | case FEC_2_3: | ||
626 | buf[2] |= (1 << 3); | ||
627 | break; | ||
628 | case FEC_3_4: | ||
629 | buf[2] |= (2 << 3); | ||
630 | break; | ||
631 | case FEC_5_6: | ||
632 | buf[2] |= (3 << 3); | ||
633 | break; | ||
634 | case FEC_7_8: | ||
635 | buf[2] |= (4 << 3); | ||
636 | break; | ||
637 | case FEC_NONE: | ||
638 | if (params->hierarchy_information == HIERARCHY_AUTO) | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | switch (params->bandwidth) { | ||
645 | case BANDWIDTH_6_MHZ: | ||
646 | break; | ||
647 | case BANDWIDTH_7_MHZ: | ||
648 | buf[1] |= (1 << 2); | ||
649 | break; | ||
650 | case BANDWIDTH_8_MHZ: | ||
651 | buf[1] |= (2 << 2); | ||
652 | break; | ||
653 | default: | ||
654 | return -EINVAL; | ||
655 | } | ||
656 | |||
657 | /* program */ | ||
658 | for (i = 0; i < sizeof(buf); i++) { | ||
659 | ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); | ||
660 | if (ret) | ||
661 | break; | ||
662 | } | ||
663 | |||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | static int af9013_reset(struct af9013_state *state, u8 sleep) | ||
668 | { | ||
669 | int ret; | ||
670 | u8 tmp, i; | ||
671 | deb_info("%s\n", __func__); | ||
672 | |||
673 | /* enable OFDM reset */ | ||
674 | ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); | ||
675 | if (ret) | ||
676 | goto error; | ||
677 | |||
678 | /* start reset mechanism */ | ||
679 | ret = af9013_write_reg(state, 0xaeff, 1); | ||
680 | if (ret) | ||
681 | goto error; | ||
682 | |||
683 | /* reset is done when bit 1 is set */ | ||
684 | for (i = 0; i < 150; i++) { | ||
685 | ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); | ||
686 | if (ret) | ||
687 | goto error; | ||
688 | if (tmp) | ||
689 | break; /* reset done */ | ||
690 | msleep(10); | ||
691 | } | ||
692 | if (!tmp) | ||
693 | return -ETIMEDOUT; | ||
694 | |||
695 | /* don't clear reset when going to sleep */ | ||
696 | if (!sleep) { | ||
697 | /* clear OFDM reset */ | ||
698 | ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); | ||
699 | if (ret) | ||
700 | goto error; | ||
701 | |||
702 | /* disable OFDM reset */ | ||
703 | ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); | ||
704 | } | ||
705 | error: | ||
706 | return ret; | ||
707 | } | ||
708 | |||
709 | static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) | ||
710 | { | ||
711 | int ret; | ||
712 | deb_info("%s: onoff:%d\n", __func__, onoff); | ||
713 | |||
714 | if (onoff) { | ||
715 | /* power on */ | ||
716 | ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); | ||
717 | if (ret) | ||
718 | goto error; | ||
719 | ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); | ||
720 | if (ret) | ||
721 | goto error; | ||
722 | ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); | ||
723 | } else { | ||
724 | /* power off */ | ||
725 | ret = af9013_reset(state, 1); | ||
726 | if (ret) | ||
727 | goto error; | ||
728 | ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); | ||
729 | } | ||
730 | error: | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | static int af9013_lock_led(struct af9013_state *state, u8 onoff) | ||
735 | { | ||
736 | deb_info("%s: onoff:%d\n", __func__, onoff); | ||
737 | |||
738 | return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); | ||
739 | } | ||
740 | |||
741 | static int af9013_set_frontend(struct dvb_frontend *fe, | ||
742 | struct dvb_frontend_parameters *params) | ||
743 | { | ||
744 | struct af9013_state *state = fe->demodulator_priv; | ||
745 | int ret; | ||
746 | u8 auto_mode; /* auto set TPS */ | ||
747 | |||
748 | deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, | ||
749 | params->u.ofdm.bandwidth); | ||
750 | |||
751 | state->frequency = params->frequency; | ||
752 | |||
753 | /* program CFOE coefficients */ | ||
754 | ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); | ||
755 | if (ret) | ||
756 | goto error; | ||
757 | |||
758 | /* program frequency control */ | ||
759 | ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); | ||
760 | if (ret) | ||
761 | goto error; | ||
762 | |||
763 | /* clear TPS lock flag (inverted flag) */ | ||
764 | ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); | ||
765 | if (ret) | ||
766 | goto error; | ||
767 | |||
768 | /* clear MPEG2 lock flag */ | ||
769 | ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); | ||
770 | if (ret) | ||
771 | goto error; | ||
772 | |||
773 | /* empty channel function */ | ||
774 | ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); | ||
775 | if (ret) | ||
776 | goto error; | ||
777 | |||
778 | /* empty DVB-T channel function */ | ||
779 | ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); | ||
780 | if (ret) | ||
781 | goto error; | ||
782 | |||
783 | /* program tuner */ | ||
784 | if (fe->ops.tuner_ops.set_params) | ||
785 | fe->ops.tuner_ops.set_params(fe, params); | ||
786 | |||
787 | /* program TPS and bandwidth, check if auto mode needed */ | ||
788 | ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); | ||
789 | if (ret) | ||
790 | goto error; | ||
791 | |||
792 | if (auto_mode) { | ||
793 | /* clear easy mode flag */ | ||
794 | ret = af9013_write_reg(state, 0xaefd, 0); | ||
795 | deb_info("%s: auto TPS\n", __func__); | ||
796 | } else { | ||
797 | /* set easy mode flag */ | ||
798 | ret = af9013_write_reg(state, 0xaefd, 1); | ||
799 | if (ret) | ||
800 | goto error; | ||
801 | ret = af9013_write_reg(state, 0xaefe, 0); | ||
802 | deb_info("%s: manual TPS\n", __func__); | ||
803 | } | ||
804 | if (ret) | ||
805 | goto error; | ||
806 | |||
807 | /* everything is set, lets try to receive channel - OFSM GO! */ | ||
808 | ret = af9013_write_reg(state, 0xffff, 0); | ||
809 | if (ret) | ||
810 | goto error; | ||
811 | |||
812 | error: | ||
813 | return ret; | ||
814 | } | ||
815 | |||
816 | static int af9013_get_frontend(struct dvb_frontend *fe, | ||
817 | struct dvb_frontend_parameters *p) | ||
818 | { | ||
819 | struct af9013_state *state = fe->demodulator_priv; | ||
820 | int ret; | ||
821 | u8 i, buf[3]; | ||
822 | deb_info("%s\n", __func__); | ||
823 | |||
824 | /* read TPS registers */ | ||
825 | for (i = 0; i < 3; i++) { | ||
826 | ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); | ||
827 | if (ret) | ||
828 | goto error; | ||
829 | } | ||
830 | |||
831 | switch ((buf[1] >> 6) & 3) { | ||
832 | case 0: | ||
833 | p->u.ofdm.constellation = QPSK; | ||
834 | break; | ||
835 | case 1: | ||
836 | p->u.ofdm.constellation = QAM_16; | ||
837 | break; | ||
838 | case 2: | ||
839 | p->u.ofdm.constellation = QAM_64; | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | switch ((buf[0] >> 0) & 3) { | ||
844 | case 0: | ||
845 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; | ||
846 | break; | ||
847 | case 1: | ||
848 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; | ||
849 | } | ||
850 | |||
851 | switch ((buf[0] >> 2) & 3) { | ||
852 | case 0: | ||
853 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; | ||
854 | break; | ||
855 | case 1: | ||
856 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; | ||
857 | break; | ||
858 | case 2: | ||
859 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; | ||
860 | break; | ||
861 | case 3: | ||
862 | p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; | ||
863 | break; | ||
864 | } | ||
865 | |||
866 | switch ((buf[0] >> 4) & 7) { | ||
867 | case 0: | ||
868 | p->u.ofdm.hierarchy_information = HIERARCHY_NONE; | ||
869 | break; | ||
870 | case 1: | ||
871 | p->u.ofdm.hierarchy_information = HIERARCHY_1; | ||
872 | break; | ||
873 | case 2: | ||
874 | p->u.ofdm.hierarchy_information = HIERARCHY_2; | ||
875 | break; | ||
876 | case 3: | ||
877 | p->u.ofdm.hierarchy_information = HIERARCHY_4; | ||
878 | break; | ||
879 | } | ||
880 | |||
881 | switch ((buf[2] >> 0) & 7) { | ||
882 | case 0: | ||
883 | p->u.ofdm.code_rate_HP = FEC_1_2; | ||
884 | break; | ||
885 | case 1: | ||
886 | p->u.ofdm.code_rate_HP = FEC_2_3; | ||
887 | break; | ||
888 | case 2: | ||
889 | p->u.ofdm.code_rate_HP = FEC_3_4; | ||
890 | break; | ||
891 | case 3: | ||
892 | p->u.ofdm.code_rate_HP = FEC_5_6; | ||
893 | break; | ||
894 | case 4: | ||
895 | p->u.ofdm.code_rate_HP = FEC_7_8; | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | switch ((buf[2] >> 3) & 7) { | ||
900 | case 0: | ||
901 | p->u.ofdm.code_rate_LP = FEC_1_2; | ||
902 | break; | ||
903 | case 1: | ||
904 | p->u.ofdm.code_rate_LP = FEC_2_3; | ||
905 | break; | ||
906 | case 2: | ||
907 | p->u.ofdm.code_rate_LP = FEC_3_4; | ||
908 | break; | ||
909 | case 3: | ||
910 | p->u.ofdm.code_rate_LP = FEC_5_6; | ||
911 | break; | ||
912 | case 4: | ||
913 | p->u.ofdm.code_rate_LP = FEC_7_8; | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | switch ((buf[1] >> 2) & 3) { | ||
918 | case 0: | ||
919 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
920 | break; | ||
921 | case 1: | ||
922 | p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
923 | break; | ||
924 | case 2: | ||
925 | p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
926 | break; | ||
927 | } | ||
928 | |||
929 | p->inversion = INVERSION_AUTO; | ||
930 | p->frequency = state->frequency; | ||
931 | |||
932 | error: | ||
933 | return ret; | ||
934 | } | ||
935 | |||
936 | static int af9013_update_ber_unc(struct dvb_frontend *fe) | ||
937 | { | ||
938 | struct af9013_state *state = fe->demodulator_priv; | ||
939 | int ret; | ||
940 | u8 buf[3], i; | ||
941 | u32 error_bit_count = 0; | ||
942 | u32 total_bit_count = 0; | ||
943 | u32 abort_packet_count = 0; | ||
944 | |||
945 | state->ber = 0; | ||
946 | |||
947 | /* check if error bit count is ready */ | ||
948 | ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); | ||
949 | if (ret) | ||
950 | goto error; | ||
951 | if (!buf[0]) | ||
952 | goto exit; | ||
953 | |||
954 | /* get RSD packet abort count */ | ||
955 | for (i = 0; i < 2; i++) { | ||
956 | ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); | ||
957 | if (ret) | ||
958 | goto error; | ||
959 | } | ||
960 | abort_packet_count = (buf[1] << 8) + buf[0]; | ||
961 | |||
962 | /* get error bit count */ | ||
963 | for (i = 0; i < 3; i++) { | ||
964 | ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); | ||
965 | if (ret) | ||
966 | goto error; | ||
967 | } | ||
968 | error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
969 | error_bit_count = error_bit_count - abort_packet_count * 8 * 8; | ||
970 | |||
971 | /* get used RSD counting period (10000 RSD packets used) */ | ||
972 | for (i = 0; i < 2; i++) { | ||
973 | ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); | ||
974 | if (ret) | ||
975 | goto error; | ||
976 | } | ||
977 | total_bit_count = (buf[1] << 8) + buf[0]; | ||
978 | total_bit_count = total_bit_count - abort_packet_count; | ||
979 | total_bit_count = total_bit_count * 204 * 8; | ||
980 | |||
981 | if (total_bit_count) | ||
982 | state->ber = error_bit_count * 1000000000 / total_bit_count; | ||
983 | |||
984 | state->ucblocks += abort_packet_count; | ||
985 | |||
986 | deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, | ||
987 | error_bit_count, total_bit_count, abort_packet_count); | ||
988 | |||
989 | /* set BER counting range */ | ||
990 | ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); | ||
991 | if (ret) | ||
992 | goto error; | ||
993 | ret = af9013_write_reg(state, 0xd386, 10000 >> 8); | ||
994 | if (ret) | ||
995 | goto error; | ||
996 | /* reset and start BER counter */ | ||
997 | ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); | ||
998 | if (ret) | ||
999 | goto error; | ||
1000 | |||
1001 | exit: | ||
1002 | error: | ||
1003 | return ret; | ||
1004 | } | ||
1005 | |||
1006 | static int af9013_update_snr(struct dvb_frontend *fe) | ||
1007 | { | ||
1008 | struct af9013_state *state = fe->demodulator_priv; | ||
1009 | int ret; | ||
1010 | u8 buf[3], i, len; | ||
1011 | u32 quant = 0; | ||
1012 | struct snr_table *snr_table; | ||
1013 | |||
1014 | /* check if quantizer ready (for snr) */ | ||
1015 | ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); | ||
1016 | if (ret) | ||
1017 | goto error; | ||
1018 | if (buf[0]) { | ||
1019 | /* quantizer ready - read it */ | ||
1020 | for (i = 0; i < 3; i++) { | ||
1021 | ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); | ||
1022 | if (ret) | ||
1023 | goto error; | ||
1024 | } | ||
1025 | quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
1026 | |||
1027 | /* read current constellation */ | ||
1028 | ret = af9013_read_reg(state, 0xd3c1, &buf[0]); | ||
1029 | if (ret) | ||
1030 | goto error; | ||
1031 | |||
1032 | switch ((buf[0] >> 6) & 3) { | ||
1033 | case 0: | ||
1034 | len = ARRAY_SIZE(qpsk_snr_table); | ||
1035 | snr_table = qpsk_snr_table; | ||
1036 | break; | ||
1037 | case 1: | ||
1038 | len = ARRAY_SIZE(qam16_snr_table); | ||
1039 | snr_table = qam16_snr_table; | ||
1040 | break; | ||
1041 | case 2: | ||
1042 | len = ARRAY_SIZE(qam64_snr_table); | ||
1043 | snr_table = qam64_snr_table; | ||
1044 | break; | ||
1045 | default: | ||
1046 | len = 0; | ||
1047 | break; | ||
1048 | } | ||
1049 | |||
1050 | if (len) { | ||
1051 | for (i = 0; i < len; i++) { | ||
1052 | if (quant < snr_table[i].val) { | ||
1053 | state->snr = snr_table[i].snr * 10; | ||
1054 | break; | ||
1055 | } | ||
1056 | } | ||
1057 | } | ||
1058 | |||
1059 | /* set quantizer super frame count */ | ||
1060 | ret = af9013_write_reg(state, 0xd2e2, 1); | ||
1061 | if (ret) | ||
1062 | goto error; | ||
1063 | |||
1064 | /* check quantizer availability */ | ||
1065 | for (i = 0; i < 10; i++) { | ||
1066 | msleep(10); | ||
1067 | ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, | ||
1068 | &buf[0]); | ||
1069 | if (ret) | ||
1070 | goto error; | ||
1071 | if (!buf[0]) | ||
1072 | break; | ||
1073 | } | ||
1074 | |||
1075 | /* reset quantizer */ | ||
1076 | ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); | ||
1077 | if (ret) | ||
1078 | goto error; | ||
1079 | } | ||
1080 | |||
1081 | error: | ||
1082 | return ret; | ||
1083 | } | ||
1084 | |||
1085 | static int af9013_update_signal_strength(struct dvb_frontend *fe) | ||
1086 | { | ||
1087 | struct af9013_state *state = fe->demodulator_priv; | ||
1088 | int ret; | ||
1089 | u8 tmp0; | ||
1090 | u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80; | ||
1091 | int signal_strength; | ||
1092 | |||
1093 | deb_info("%s\n", __func__); | ||
1094 | |||
1095 | state->signal_strength = 0; | ||
1096 | |||
1097 | ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0); | ||
1098 | if (ret) | ||
1099 | goto error; | ||
1100 | if (tmp0) { | ||
1101 | ret = af9013_read_reg(state, 0x9bbd, &rf_50); | ||
1102 | if (ret) | ||
1103 | goto error; | ||
1104 | ret = af9013_read_reg(state, 0x9bd0, &rf_80); | ||
1105 | if (ret) | ||
1106 | goto error; | ||
1107 | ret = af9013_read_reg(state, 0x9be2, &if_50); | ||
1108 | if (ret) | ||
1109 | goto error; | ||
1110 | ret = af9013_read_reg(state, 0x9be4, &if_80); | ||
1111 | if (ret) | ||
1112 | goto error; | ||
1113 | ret = af9013_read_reg(state, 0xd07c, &rf_gain); | ||
1114 | if (ret) | ||
1115 | goto error; | ||
1116 | ret = af9013_read_reg(state, 0xd07d, &if_gain); | ||
1117 | if (ret) | ||
1118 | goto error; | ||
1119 | signal_strength = (0xffff / (9 * (rf_50 + if_50) - \ | ||
1120 | 11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \ | ||
1121 | 11 * (rf_80 + if_80)); | ||
1122 | if (signal_strength < 0) | ||
1123 | signal_strength = 0; | ||
1124 | else if (signal_strength > 0xffff) | ||
1125 | signal_strength = 0xffff; | ||
1126 | |||
1127 | state->signal_strength = signal_strength; | ||
1128 | } | ||
1129 | |||
1130 | error: | ||
1131 | return ret; | ||
1132 | } | ||
1133 | |||
1134 | static int af9013_update_statistics(struct dvb_frontend *fe) | ||
1135 | { | ||
1136 | struct af9013_state *state = fe->demodulator_priv; | ||
1137 | int ret; | ||
1138 | |||
1139 | if (time_before(jiffies, state->next_statistics_check)) | ||
1140 | return 0; | ||
1141 | |||
1142 | /* set minimum statistic update interval */ | ||
1143 | state->next_statistics_check = jiffies + msecs_to_jiffies(1200); | ||
1144 | |||
1145 | ret = af9013_update_signal_strength(fe); | ||
1146 | if (ret) | ||
1147 | goto error; | ||
1148 | ret = af9013_update_snr(fe); | ||
1149 | if (ret) | ||
1150 | goto error; | ||
1151 | ret = af9013_update_ber_unc(fe); | ||
1152 | if (ret) | ||
1153 | goto error; | ||
1154 | |||
1155 | error: | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | static int af9013_get_tune_settings(struct dvb_frontend *fe, | ||
1160 | struct dvb_frontend_tune_settings *fesettings) | ||
1161 | { | ||
1162 | fesettings->min_delay_ms = 800; | ||
1163 | fesettings->step_size = 0; | ||
1164 | fesettings->max_drift = 0; | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
1170 | { | ||
1171 | struct af9013_state *state = fe->demodulator_priv; | ||
1172 | int ret = 0; | ||
1173 | u8 tmp; | ||
1174 | *status = 0; | ||
1175 | |||
1176 | /* TPS lock */ | ||
1177 | ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); | ||
1178 | if (ret) | ||
1179 | goto error; | ||
1180 | if (tmp) | ||
1181 | *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; | ||
1182 | |||
1183 | /* MPEG2 lock */ | ||
1184 | ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); | ||
1185 | if (ret) | ||
1186 | goto error; | ||
1187 | if (tmp) | ||
1188 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | ||
1189 | |||
1190 | if (!*status & FE_HAS_SIGNAL) { | ||
1191 | /* AGC lock */ | ||
1192 | ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); | ||
1193 | if (ret) | ||
1194 | goto error; | ||
1195 | if (tmp) | ||
1196 | *status |= FE_HAS_SIGNAL; | ||
1197 | } | ||
1198 | |||
1199 | if (!*status & FE_HAS_CARRIER) { | ||
1200 | /* CFO lock */ | ||
1201 | ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); | ||
1202 | if (ret) | ||
1203 | goto error; | ||
1204 | if (tmp) | ||
1205 | *status |= FE_HAS_CARRIER; | ||
1206 | } | ||
1207 | |||
1208 | if (!*status & FE_HAS_CARRIER) { | ||
1209 | /* SFOE lock */ | ||
1210 | ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); | ||
1211 | if (ret) | ||
1212 | goto error; | ||
1213 | if (tmp) | ||
1214 | *status |= FE_HAS_CARRIER; | ||
1215 | } | ||
1216 | |||
1217 | ret = af9013_update_statistics(fe); | ||
1218 | |||
1219 | error: | ||
1220 | return ret; | ||
1221 | } | ||
1222 | |||
1223 | |||
1224 | static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
1225 | { | ||
1226 | struct af9013_state *state = fe->demodulator_priv; | ||
1227 | int ret; | ||
1228 | ret = af9013_update_statistics(fe); | ||
1229 | *ber = state->ber; | ||
1230 | return ret; | ||
1231 | } | ||
1232 | |||
1233 | static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
1234 | { | ||
1235 | struct af9013_state *state = fe->demodulator_priv; | ||
1236 | int ret; | ||
1237 | ret = af9013_update_statistics(fe); | ||
1238 | *strength = state->signal_strength; | ||
1239 | return ret; | ||
1240 | } | ||
1241 | |||
1242 | static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
1243 | { | ||
1244 | struct af9013_state *state = fe->demodulator_priv; | ||
1245 | int ret; | ||
1246 | ret = af9013_update_statistics(fe); | ||
1247 | *snr = state->snr; | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
1252 | { | ||
1253 | struct af9013_state *state = fe->demodulator_priv; | ||
1254 | int ret; | ||
1255 | ret = af9013_update_statistics(fe); | ||
1256 | *ucblocks = state->ucblocks; | ||
1257 | return ret; | ||
1258 | } | ||
1259 | |||
1260 | static int af9013_sleep(struct dvb_frontend *fe) | ||
1261 | { | ||
1262 | struct af9013_state *state = fe->demodulator_priv; | ||
1263 | int ret; | ||
1264 | deb_info("%s\n", __func__); | ||
1265 | |||
1266 | ret = af9013_lock_led(state, 0); | ||
1267 | if (ret) | ||
1268 | goto error; | ||
1269 | |||
1270 | ret = af9013_power_ctrl(state, 0); | ||
1271 | error: | ||
1272 | return ret; | ||
1273 | } | ||
1274 | |||
1275 | static int af9013_init(struct dvb_frontend *fe) | ||
1276 | { | ||
1277 | struct af9013_state *state = fe->demodulator_priv; | ||
1278 | int ret, i, len; | ||
1279 | u8 tmp0, tmp1; | ||
1280 | struct regdesc *init; | ||
1281 | deb_info("%s\n", __func__); | ||
1282 | |||
1283 | /* reset OFDM */ | ||
1284 | ret = af9013_reset(state, 0); | ||
1285 | if (ret) | ||
1286 | goto error; | ||
1287 | |||
1288 | /* power on */ | ||
1289 | ret = af9013_power_ctrl(state, 1); | ||
1290 | if (ret) | ||
1291 | goto error; | ||
1292 | |||
1293 | /* enable ADC */ | ||
1294 | ret = af9013_write_reg(state, 0xd73a, 0xa4); | ||
1295 | if (ret) | ||
1296 | goto error; | ||
1297 | |||
1298 | /* write API version to firmware */ | ||
1299 | for (i = 0; i < sizeof(state->config.api_version); i++) { | ||
1300 | ret = af9013_write_reg(state, 0x9bf2 + i, | ||
1301 | state->config.api_version[i]); | ||
1302 | if (ret) | ||
1303 | goto error; | ||
1304 | } | ||
1305 | |||
1306 | /* program ADC control */ | ||
1307 | ret = af9013_set_adc_ctrl(state); | ||
1308 | if (ret) | ||
1309 | goto error; | ||
1310 | |||
1311 | /* set I2C master clock */ | ||
1312 | ret = af9013_write_reg(state, 0xd416, 0x14); | ||
1313 | if (ret) | ||
1314 | goto error; | ||
1315 | |||
1316 | /* set 16 embx */ | ||
1317 | ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); | ||
1318 | if (ret) | ||
1319 | goto error; | ||
1320 | |||
1321 | /* set no trigger */ | ||
1322 | ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); | ||
1323 | if (ret) | ||
1324 | goto error; | ||
1325 | |||
1326 | /* set read-update bit for constellation */ | ||
1327 | ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); | ||
1328 | if (ret) | ||
1329 | goto error; | ||
1330 | |||
1331 | /* enable FEC monitor */ | ||
1332 | ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); | ||
1333 | if (ret) | ||
1334 | goto error; | ||
1335 | |||
1336 | /* load OFSM settings */ | ||
1337 | deb_info("%s: load ofsm settings\n", __func__); | ||
1338 | len = ARRAY_SIZE(ofsm_init); | ||
1339 | init = ofsm_init; | ||
1340 | for (i = 0; i < len; i++) { | ||
1341 | ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, | ||
1342 | init[i].len, init[i].val); | ||
1343 | if (ret) | ||
1344 | goto error; | ||
1345 | } | ||
1346 | |||
1347 | /* load tuner specific settings */ | ||
1348 | deb_info("%s: load tuner specific settings\n", __func__); | ||
1349 | switch (state->config.tuner) { | ||
1350 | case AF9013_TUNER_MXL5003D: | ||
1351 | len = ARRAY_SIZE(tuner_init_mxl5003d); | ||
1352 | init = tuner_init_mxl5003d; | ||
1353 | break; | ||
1354 | case AF9013_TUNER_MXL5005D: | ||
1355 | case AF9013_TUNER_MXL5005R: | ||
1356 | len = ARRAY_SIZE(tuner_init_mxl5005); | ||
1357 | init = tuner_init_mxl5005; | ||
1358 | break; | ||
1359 | case AF9013_TUNER_ENV77H11D5: | ||
1360 | len = ARRAY_SIZE(tuner_init_env77h11d5); | ||
1361 | init = tuner_init_env77h11d5; | ||
1362 | break; | ||
1363 | case AF9013_TUNER_MT2060: | ||
1364 | len = ARRAY_SIZE(tuner_init_mt2060); | ||
1365 | init = tuner_init_mt2060; | ||
1366 | break; | ||
1367 | case AF9013_TUNER_MC44S803: | ||
1368 | len = ARRAY_SIZE(tuner_init_mc44s803); | ||
1369 | init = tuner_init_mc44s803; | ||
1370 | break; | ||
1371 | case AF9013_TUNER_QT1010: | ||
1372 | case AF9013_TUNER_QT1010A: | ||
1373 | len = ARRAY_SIZE(tuner_init_qt1010); | ||
1374 | init = tuner_init_qt1010; | ||
1375 | break; | ||
1376 | case AF9013_TUNER_MT2060_2: | ||
1377 | len = ARRAY_SIZE(tuner_init_mt2060_2); | ||
1378 | init = tuner_init_mt2060_2; | ||
1379 | break; | ||
1380 | case AF9013_TUNER_TDA18271: | ||
1381 | len = ARRAY_SIZE(tuner_init_tda18271); | ||
1382 | init = tuner_init_tda18271; | ||
1383 | break; | ||
1384 | case AF9013_TUNER_UNKNOWN: | ||
1385 | default: | ||
1386 | len = ARRAY_SIZE(tuner_init_unknown); | ||
1387 | init = tuner_init_unknown; | ||
1388 | break; | ||
1389 | } | ||
1390 | |||
1391 | for (i = 0; i < len; i++) { | ||
1392 | ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, | ||
1393 | init[i].len, init[i].val); | ||
1394 | if (ret) | ||
1395 | goto error; | ||
1396 | } | ||
1397 | |||
1398 | /* set TS mode */ | ||
1399 | deb_info("%s: setting ts mode\n", __func__); | ||
1400 | tmp0 = 0; /* parallel mode */ | ||
1401 | tmp1 = 0; /* serial mode */ | ||
1402 | switch (state->config.output_mode) { | ||
1403 | case AF9013_OUTPUT_MODE_PARALLEL: | ||
1404 | tmp0 = 1; | ||
1405 | break; | ||
1406 | case AF9013_OUTPUT_MODE_SERIAL: | ||
1407 | tmp1 = 1; | ||
1408 | break; | ||
1409 | case AF9013_OUTPUT_MODE_USB: | ||
1410 | /* usb mode for AF9015 */ | ||
1411 | default: | ||
1412 | break; | ||
1413 | } | ||
1414 | ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ | ||
1415 | if (ret) | ||
1416 | goto error; | ||
1417 | ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ | ||
1418 | if (ret) | ||
1419 | goto error; | ||
1420 | |||
1421 | /* enable lock led */ | ||
1422 | ret = af9013_lock_led(state, 1); | ||
1423 | if (ret) | ||
1424 | goto error; | ||
1425 | |||
1426 | error: | ||
1427 | return ret; | ||
1428 | } | ||
1429 | |||
1430 | static struct dvb_frontend_ops af9013_ops; | ||
1431 | |||
1432 | static int af9013_download_firmware(struct af9013_state *state) | ||
1433 | { | ||
1434 | int i, len, packets, remainder, ret; | ||
1435 | const struct firmware *fw; | ||
1436 | u16 addr = 0x5100; /* firmware start address */ | ||
1437 | u16 checksum = 0; | ||
1438 | u8 val; | ||
1439 | u8 fw_params[4]; | ||
1440 | u8 *data; | ||
1441 | u8 *fw_file = AF9013_DEFAULT_FIRMWARE; | ||
1442 | |||
1443 | msleep(100); | ||
1444 | /* check whether firmware is already running */ | ||
1445 | ret = af9013_read_reg(state, 0x98be, &val); | ||
1446 | if (ret) | ||
1447 | goto error; | ||
1448 | else | ||
1449 | deb_info("%s: firmware status:%02x\n", __func__, val); | ||
1450 | |||
1451 | if (val == 0x0c) /* fw is running, no need for download */ | ||
1452 | goto exit; | ||
1453 | |||
1454 | info("found a '%s' in cold state, will try to load a firmware", | ||
1455 | af9013_ops.info.name); | ||
1456 | |||
1457 | /* request the firmware, this will block and timeout */ | ||
1458 | ret = request_firmware(&fw, fw_file, &state->i2c->dev); | ||
1459 | if (ret) { | ||
1460 | err("did not find the firmware file. (%s) " | ||
1461 | "Please see linux/Documentation/dvb/ for more details" \ | ||
1462 | " on firmware-problems. (%d)", | ||
1463 | fw_file, ret); | ||
1464 | goto error; | ||
1465 | } | ||
1466 | |||
1467 | info("downloading firmware from file '%s'", fw_file); | ||
1468 | |||
1469 | /* calc checksum */ | ||
1470 | for (i = 0; i < fw->size; i++) | ||
1471 | checksum += fw->data[i]; | ||
1472 | |||
1473 | fw_params[0] = checksum >> 8; | ||
1474 | fw_params[1] = checksum & 0xff; | ||
1475 | fw_params[2] = fw->size >> 8; | ||
1476 | fw_params[3] = fw->size & 0xff; | ||
1477 | |||
1478 | /* write fw checksum & size */ | ||
1479 | ret = af9013_write_ofsm_regs(state, 0x50fc, | ||
1480 | fw_params, sizeof(fw_params)); | ||
1481 | if (ret) | ||
1482 | goto error_release; | ||
1483 | |||
1484 | #define FW_PACKET_MAX_DATA 16 | ||
1485 | |||
1486 | packets = fw->size / FW_PACKET_MAX_DATA; | ||
1487 | remainder = fw->size % FW_PACKET_MAX_DATA; | ||
1488 | len = FW_PACKET_MAX_DATA; | ||
1489 | for (i = 0; i <= packets; i++) { | ||
1490 | if (i == packets) /* set size of the last packet */ | ||
1491 | len = remainder; | ||
1492 | |||
1493 | data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); | ||
1494 | ret = af9013_write_ofsm_regs(state, addr, data, len); | ||
1495 | addr += FW_PACKET_MAX_DATA; | ||
1496 | |||
1497 | if (ret) { | ||
1498 | err("firmware download failed at %d with %d", i, ret); | ||
1499 | goto error_release; | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | /* request boot firmware */ | ||
1504 | ret = af9013_write_reg(state, 0xe205, 1); | ||
1505 | if (ret) | ||
1506 | goto error_release; | ||
1507 | |||
1508 | for (i = 0; i < 15; i++) { | ||
1509 | msleep(100); | ||
1510 | |||
1511 | /* check firmware status */ | ||
1512 | ret = af9013_read_reg(state, 0x98be, &val); | ||
1513 | if (ret) | ||
1514 | goto error_release; | ||
1515 | |||
1516 | deb_info("%s: firmware status:%02x\n", __func__, val); | ||
1517 | |||
1518 | if (val == 0x0c || val == 0x04) /* success or fail */ | ||
1519 | break; | ||
1520 | } | ||
1521 | |||
1522 | if (val == 0x04) { | ||
1523 | err("firmware did not run"); | ||
1524 | ret = -1; | ||
1525 | } else if (val != 0x0c) { | ||
1526 | err("firmware boot timeout"); | ||
1527 | ret = -1; | ||
1528 | } | ||
1529 | |||
1530 | error_release: | ||
1531 | release_firmware(fw); | ||
1532 | error: | ||
1533 | exit: | ||
1534 | if (!ret) | ||
1535 | info("found a '%s' in warm state.", af9013_ops.info.name); | ||
1536 | return ret; | ||
1537 | } | ||
1538 | |||
1539 | static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
1540 | { | ||
1541 | int ret; | ||
1542 | struct af9013_state *state = fe->demodulator_priv; | ||
1543 | deb_info("%s: enable:%d\n", __func__, enable); | ||
1544 | |||
1545 | if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) | ||
1546 | ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); | ||
1547 | else | ||
1548 | ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); | ||
1549 | |||
1550 | return ret; | ||
1551 | } | ||
1552 | |||
1553 | static void af9013_release(struct dvb_frontend *fe) | ||
1554 | { | ||
1555 | struct af9013_state *state = fe->demodulator_priv; | ||
1556 | kfree(state); | ||
1557 | } | ||
1558 | |||
1559 | static struct dvb_frontend_ops af9013_ops; | ||
1560 | |||
1561 | struct dvb_frontend *af9013_attach(const struct af9013_config *config, | ||
1562 | struct i2c_adapter *i2c) | ||
1563 | { | ||
1564 | int ret; | ||
1565 | struct af9013_state *state = NULL; | ||
1566 | u8 buf[3], i; | ||
1567 | |||
1568 | /* allocate memory for the internal state */ | ||
1569 | state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); | ||
1570 | if (state == NULL) | ||
1571 | goto error; | ||
1572 | |||
1573 | /* setup the state */ | ||
1574 | state->i2c = i2c; | ||
1575 | memcpy(&state->config, config, sizeof(struct af9013_config)); | ||
1576 | |||
1577 | /* chip version */ | ||
1578 | ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); | ||
1579 | if (ret) | ||
1580 | goto error; | ||
1581 | |||
1582 | /* ROM version */ | ||
1583 | for (i = 0; i < 2; i++) { | ||
1584 | ret = af9013_read_reg(state, 0x116b + i, &buf[i]); | ||
1585 | if (ret) | ||
1586 | goto error; | ||
1587 | } | ||
1588 | deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, | ||
1589 | buf[2], buf[0], buf[1]); | ||
1590 | |||
1591 | /* download firmware */ | ||
1592 | if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { | ||
1593 | ret = af9013_download_firmware(state); | ||
1594 | if (ret) | ||
1595 | goto error; | ||
1596 | } | ||
1597 | |||
1598 | /* firmware version */ | ||
1599 | for (i = 0; i < 3; i++) { | ||
1600 | ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); | ||
1601 | if (ret) | ||
1602 | goto error; | ||
1603 | } | ||
1604 | info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]); | ||
1605 | |||
1606 | /* settings for mp2if */ | ||
1607 | if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { | ||
1608 | /* AF9015 split PSB to 1.5k + 0.5k */ | ||
1609 | ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); | ||
1610 | } else { | ||
1611 | /* AF9013 change the output bit to data7 */ | ||
1612 | ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); | ||
1613 | if (ret) | ||
1614 | goto error; | ||
1615 | /* AF9013 set mpeg to full speed */ | ||
1616 | ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); | ||
1617 | } | ||
1618 | if (ret) | ||
1619 | goto error; | ||
1620 | ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); | ||
1621 | if (ret) | ||
1622 | goto error; | ||
1623 | |||
1624 | /* set GPIOs */ | ||
1625 | for (i = 0; i < sizeof(state->config.gpio); i++) { | ||
1626 | ret = af9013_set_gpio(state, i, state->config.gpio[i]); | ||
1627 | if (ret) | ||
1628 | goto error; | ||
1629 | } | ||
1630 | |||
1631 | /* create dvb_frontend */ | ||
1632 | memcpy(&state->frontend.ops, &af9013_ops, | ||
1633 | sizeof(struct dvb_frontend_ops)); | ||
1634 | state->frontend.demodulator_priv = state; | ||
1635 | |||
1636 | return &state->frontend; | ||
1637 | error: | ||
1638 | kfree(state); | ||
1639 | return NULL; | ||
1640 | } | ||
1641 | EXPORT_SYMBOL(af9013_attach); | ||
1642 | |||
1643 | static struct dvb_frontend_ops af9013_ops = { | ||
1644 | .info = { | ||
1645 | .name = "Afatech AF9013 DVB-T", | ||
1646 | .type = FE_OFDM, | ||
1647 | .frequency_min = 174000000, | ||
1648 | .frequency_max = 862000000, | ||
1649 | .frequency_stepsize = 250000, | ||
1650 | .frequency_tolerance = 0, | ||
1651 | .caps = | ||
1652 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1653 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1654 | FE_CAN_QPSK | FE_CAN_QAM_16 | | ||
1655 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
1656 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
1657 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
1658 | FE_CAN_HIERARCHY_AUTO | | ||
1659 | FE_CAN_RECOVER | | ||
1660 | FE_CAN_MUTE_TS | ||
1661 | }, | ||
1662 | |||
1663 | .release = af9013_release, | ||
1664 | .init = af9013_init, | ||
1665 | .sleep = af9013_sleep, | ||
1666 | .i2c_gate_ctrl = af9013_i2c_gate_ctrl, | ||
1667 | |||
1668 | .set_frontend = af9013_set_frontend, | ||
1669 | .get_frontend = af9013_get_frontend, | ||
1670 | |||
1671 | .get_tune_settings = af9013_get_tune_settings, | ||
1672 | |||
1673 | .read_status = af9013_read_status, | ||
1674 | .read_ber = af9013_read_ber, | ||
1675 | .read_signal_strength = af9013_read_signal_strength, | ||
1676 | .read_snr = af9013_read_snr, | ||
1677 | .read_ucblocks = af9013_read_ucblocks, | ||
1678 | }; | ||
1679 | |||
1680 | module_param_named(debug, af9013_debug, int, 0644); | ||
1681 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
1682 | |||
1683 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
1684 | MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); | ||
1685 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h new file mode 100644 index 000000000000..28b90c91c766 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _AF9013_H_ | ||
25 | #define _AF9013_H_ | ||
26 | |||
27 | #include <linux/dvb/frontend.h> | ||
28 | |||
29 | enum af9013_ts_mode { | ||
30 | AF9013_OUTPUT_MODE_PARALLEL, | ||
31 | AF9013_OUTPUT_MODE_SERIAL, | ||
32 | AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ | ||
33 | }; | ||
34 | |||
35 | enum af9013_tuner { | ||
36 | AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ | ||
37 | AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ | ||
38 | AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ | ||
39 | AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ | ||
40 | AF9013_TUNER_MT2060 = 130, /* Microtune */ | ||
41 | AF9013_TUNER_MC44S803 = 133, /* Freescale */ | ||
42 | AF9013_TUNER_QT1010 = 134, /* Quantek */ | ||
43 | AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ | ||
44 | AF9013_TUNER_MT2060_2 = 147, /* Microtune */ | ||
45 | AF9013_TUNER_TDA18271 = 156, /* NXP */ | ||
46 | AF9013_TUNER_QT1010A = 162, /* Quantek */ | ||
47 | }; | ||
48 | |||
49 | /* AF9013/5 GPIOs (mostly guessed) | ||
50 | demod#1-gpio#0 - set demod#2 i2c-addr for dual devices | ||
51 | demod#1-gpio#1 - xtal setting (?) | ||
52 | demod#1-gpio#3 - tuner#1 | ||
53 | demod#2-gpio#0 - tuner#2 | ||
54 | demod#2-gpio#1 - xtal setting (?) | ||
55 | */ | ||
56 | #define AF9013_GPIO_ON (1 << 0) | ||
57 | #define AF9013_GPIO_EN (1 << 1) | ||
58 | #define AF9013_GPIO_O (1 << 2) | ||
59 | #define AF9013_GPIO_I (1 << 3) | ||
60 | |||
61 | #define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) | ||
62 | #define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) | ||
63 | |||
64 | #define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) | ||
65 | #define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) | ||
66 | |||
67 | struct af9013_config { | ||
68 | /* demodulator's I2C address */ | ||
69 | u8 demod_address; | ||
70 | |||
71 | /* frequencies in kHz */ | ||
72 | u32 adc_clock; | ||
73 | |||
74 | /* tuner ID */ | ||
75 | u8 tuner; | ||
76 | |||
77 | /* tuner IF */ | ||
78 | u16 tuner_if; | ||
79 | |||
80 | /* TS data output mode */ | ||
81 | u8 output_mode:2; | ||
82 | |||
83 | /* RF spectrum inversion */ | ||
84 | u8 rf_spec_inv:1; | ||
85 | |||
86 | /* API version */ | ||
87 | u8 api_version[4]; | ||
88 | |||
89 | /* GPIOs */ | ||
90 | u8 gpio[4]; | ||
91 | }; | ||
92 | |||
93 | |||
94 | #if defined(CONFIG_DVB_AF9013) || \ | ||
95 | (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) | ||
96 | extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, | ||
97 | struct i2c_adapter *i2c); | ||
98 | #else | ||
99 | static inline struct dvb_frontend *af9013_attach( | ||
100 | const struct af9013_config *config, struct i2c_adapter *i2c) | ||
101 | { | ||
102 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
103 | return NULL; | ||
104 | } | ||
105 | #endif /* CONFIG_DVB_AF9013 */ | ||
106 | |||
107 | #endif /* _AF9013_H_ */ | ||
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h new file mode 100644 index 000000000000..163e251d0b73 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013_priv.h | |||
@@ -0,0 +1,869 @@ | |||
1 | /* | ||
2 | * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver | ||
3 | * | ||
4 | * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> | ||
5 | * | ||
6 | * Thanks to Afatech who kindly provided information. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _AF9013_PRIV_ | ||
25 | #define _AF9013_PRIV_ | ||
26 | |||
27 | #define LOG_PREFIX "af9013" | ||
28 | extern int af9013_debug; | ||
29 | |||
30 | #define dprintk(var, level, args...) \ | ||
31 | do { if ((var & level)) printk(args); } while (0) | ||
32 | |||
33 | #define debug_dump(b, l, func) {\ | ||
34 | int loop_; \ | ||
35 | for (loop_ = 0; loop_ < l; loop_++) \ | ||
36 | func("%02x ", b[loop_]); \ | ||
37 | func("\n");\ | ||
38 | } | ||
39 | |||
40 | #define deb_info(args...) dprintk(af9013_debug, 0x01, args) | ||
41 | |||
42 | #undef err | ||
43 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
44 | #undef info | ||
45 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
46 | #undef warn | ||
47 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
48 | |||
49 | #define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" | ||
50 | |||
51 | struct regdesc { | ||
52 | u16 addr; | ||
53 | u8 pos:4; | ||
54 | u8 len:4; | ||
55 | u8 val; | ||
56 | }; | ||
57 | |||
58 | struct snr_table { | ||
59 | u32 val; | ||
60 | u8 snr; | ||
61 | }; | ||
62 | |||
63 | /* QPSK SNR lookup table */ | ||
64 | static struct snr_table qpsk_snr_table[] = { | ||
65 | { 0x0b4771, 0 }, | ||
66 | { 0x0c1aed, 1 }, | ||
67 | { 0x0d0d27, 2 }, | ||
68 | { 0x0e4d19, 3 }, | ||
69 | { 0x0e5da8, 4 }, | ||
70 | { 0x107097, 5 }, | ||
71 | { 0x116975, 6 }, | ||
72 | { 0x1252d9, 7 }, | ||
73 | { 0x131fa4, 8 }, | ||
74 | { 0x13d5e1, 9 }, | ||
75 | { 0x148e53, 10 }, | ||
76 | { 0x15358b, 11 }, | ||
77 | { 0x15dd29, 12 }, | ||
78 | { 0x168112, 13 }, | ||
79 | { 0x170b61, 14 }, | ||
80 | { 0xffffff, 15 }, | ||
81 | }; | ||
82 | |||
83 | /* QAM16 SNR lookup table */ | ||
84 | static struct snr_table qam16_snr_table[] = { | ||
85 | { 0x05eb62, 5 }, | ||
86 | { 0x05fecf, 6 }, | ||
87 | { 0x060b80, 7 }, | ||
88 | { 0x062501, 8 }, | ||
89 | { 0x064865, 9 }, | ||
90 | { 0x069604, 10 }, | ||
91 | { 0x06f356, 11 }, | ||
92 | { 0x07706a, 12 }, | ||
93 | { 0x0804d3, 13 }, | ||
94 | { 0x089d1a, 14 }, | ||
95 | { 0x093e3d, 15 }, | ||
96 | { 0x09e35d, 16 }, | ||
97 | { 0x0a7c3c, 17 }, | ||
98 | { 0x0afaf8, 18 }, | ||
99 | { 0x0b719d, 19 }, | ||
100 | { 0xffffff, 20 }, | ||
101 | }; | ||
102 | |||
103 | /* QAM64 SNR lookup table */ | ||
104 | static struct snr_table qam64_snr_table[] = { | ||
105 | { 0x03109b, 12 }, | ||
106 | { 0x0310d4, 13 }, | ||
107 | { 0x031920, 14 }, | ||
108 | { 0x0322d0, 15 }, | ||
109 | { 0x0339fc, 16 }, | ||
110 | { 0x0364a1, 17 }, | ||
111 | { 0x038bcc, 18 }, | ||
112 | { 0x03c7d3, 19 }, | ||
113 | { 0x0408cc, 20 }, | ||
114 | { 0x043bed, 21 }, | ||
115 | { 0x048061, 22 }, | ||
116 | { 0x04be95, 23 }, | ||
117 | { 0x04fa7d, 24 }, | ||
118 | { 0x052405, 25 }, | ||
119 | { 0x05570d, 26 }, | ||
120 | { 0xffffff, 27 }, | ||
121 | }; | ||
122 | |||
123 | static struct regdesc ofsm_init[] = { | ||
124 | { 0xd73a, 0, 8, 0xa1 }, | ||
125 | { 0xd73b, 0, 8, 0x1f }, | ||
126 | { 0xd73c, 4, 4, 0x0a }, | ||
127 | { 0xd732, 3, 1, 0x00 }, | ||
128 | { 0xd731, 4, 2, 0x03 }, | ||
129 | { 0xd73d, 7, 1, 0x01 }, | ||
130 | { 0xd740, 0, 1, 0x00 }, | ||
131 | { 0xd740, 1, 1, 0x00 }, | ||
132 | { 0xd740, 2, 1, 0x00 }, | ||
133 | { 0xd740, 3, 1, 0x01 }, | ||
134 | { 0xd3c1, 4, 1, 0x01 }, | ||
135 | { 0xd3a2, 0, 8, 0x00 }, | ||
136 | { 0xd3a3, 0, 8, 0x04 }, | ||
137 | { 0xd305, 0, 8, 0x32 }, | ||
138 | { 0xd306, 0, 8, 0x10 }, | ||
139 | { 0xd304, 0, 8, 0x04 }, | ||
140 | { 0x9112, 0, 1, 0x01 }, | ||
141 | { 0x911d, 0, 1, 0x01 }, | ||
142 | { 0x911a, 0, 1, 0x01 }, | ||
143 | { 0x911b, 0, 1, 0x01 }, | ||
144 | { 0x9bce, 0, 4, 0x02 }, | ||
145 | { 0x9116, 0, 1, 0x01 }, | ||
146 | { 0x9bd1, 0, 1, 0x01 }, | ||
147 | { 0xd2e0, 0, 8, 0xd0 }, | ||
148 | { 0xd2e9, 0, 4, 0x0d }, | ||
149 | { 0xd38c, 0, 8, 0xfc }, | ||
150 | { 0xd38d, 0, 8, 0x00 }, | ||
151 | { 0xd38e, 0, 8, 0x7e }, | ||
152 | { 0xd38f, 0, 8, 0x00 }, | ||
153 | { 0xd390, 0, 8, 0x2f }, | ||
154 | { 0xd145, 4, 1, 0x01 }, | ||
155 | { 0xd1a9, 4, 1, 0x01 }, | ||
156 | { 0xd158, 5, 3, 0x01 }, | ||
157 | { 0xd159, 0, 6, 0x06 }, | ||
158 | { 0xd167, 0, 8, 0x00 }, | ||
159 | { 0xd168, 0, 4, 0x07 }, | ||
160 | { 0xd1c3, 5, 3, 0x00 }, | ||
161 | { 0xd1c4, 0, 6, 0x00 }, | ||
162 | { 0xd1c5, 0, 7, 0x10 }, | ||
163 | { 0xd1c6, 0, 3, 0x02 }, | ||
164 | { 0xd080, 2, 5, 0x03 }, | ||
165 | { 0xd081, 4, 4, 0x09 }, | ||
166 | { 0xd098, 4, 4, 0x0f }, | ||
167 | { 0xd098, 0, 4, 0x03 }, | ||
168 | { 0xdbc0, 3, 1, 0x01 }, | ||
169 | { 0xdbc0, 4, 1, 0x01 }, | ||
170 | { 0xdbc7, 0, 8, 0x08 }, | ||
171 | { 0xdbc8, 4, 4, 0x00 }, | ||
172 | { 0xdbc9, 0, 5, 0x01 }, | ||
173 | { 0xd280, 0, 8, 0xe0 }, | ||
174 | { 0xd281, 0, 8, 0xff }, | ||
175 | { 0xd282, 0, 8, 0xff }, | ||
176 | { 0xd283, 0, 8, 0xc3 }, | ||
177 | { 0xd284, 0, 8, 0xff }, | ||
178 | { 0xd285, 0, 4, 0x01 }, | ||
179 | { 0xd0f0, 0, 7, 0x1a }, | ||
180 | { 0xd0f1, 4, 1, 0x01 }, | ||
181 | { 0xd0f2, 0, 8, 0x0c }, | ||
182 | { 0xd103, 0, 4, 0x08 }, | ||
183 | { 0xd0f8, 0, 7, 0x20 }, | ||
184 | { 0xd111, 5, 1, 0x00 }, | ||
185 | { 0xd111, 6, 1, 0x00 }, | ||
186 | { 0x910b, 0, 8, 0x0a }, | ||
187 | { 0x9115, 0, 8, 0x02 }, | ||
188 | { 0x910c, 0, 8, 0x02 }, | ||
189 | { 0x910d, 0, 8, 0x08 }, | ||
190 | { 0x910e, 0, 8, 0x0a }, | ||
191 | { 0x9bf6, 0, 8, 0x06 }, | ||
192 | { 0x9bf8, 0, 8, 0x02 }, | ||
193 | { 0x9bf7, 0, 8, 0x05 }, | ||
194 | { 0x9bf9, 0, 8, 0x0f }, | ||
195 | { 0x9bfc, 0, 8, 0x13 }, | ||
196 | { 0x9bd3, 0, 8, 0xff }, | ||
197 | { 0x9bbe, 0, 1, 0x01 }, | ||
198 | { 0x9bcc, 0, 1, 0x01 }, | ||
199 | }; | ||
200 | |||
201 | /* Panasonic ENV77H11D5 tuner init | ||
202 | AF9013_TUNER_ENV77H11D5 = 129 */ | ||
203 | static struct regdesc tuner_init_env77h11d5[] = { | ||
204 | { 0x9bd5, 0, 8, 0x01 }, | ||
205 | { 0x9bd6, 0, 8, 0x03 }, | ||
206 | { 0x9bbe, 0, 8, 0x01 }, | ||
207 | { 0xd1a0, 1, 1, 0x01 }, | ||
208 | { 0xd000, 0, 1, 0x01 }, | ||
209 | { 0xd000, 1, 1, 0x00 }, | ||
210 | { 0xd001, 1, 1, 0x01 }, | ||
211 | { 0xd001, 0, 1, 0x00 }, | ||
212 | { 0xd001, 5, 1, 0x00 }, | ||
213 | { 0xd002, 0, 5, 0x19 }, | ||
214 | { 0xd003, 0, 5, 0x1a }, | ||
215 | { 0xd004, 0, 5, 0x19 }, | ||
216 | { 0xd005, 0, 5, 0x1a }, | ||
217 | { 0xd00e, 0, 5, 0x10 }, | ||
218 | { 0xd00f, 0, 3, 0x04 }, | ||
219 | { 0xd00f, 3, 3, 0x05 }, | ||
220 | { 0xd010, 0, 3, 0x04 }, | ||
221 | { 0xd010, 3, 3, 0x05 }, | ||
222 | { 0xd016, 4, 4, 0x03 }, | ||
223 | { 0xd01f, 0, 6, 0x0a }, | ||
224 | { 0xd020, 0, 6, 0x0a }, | ||
225 | { 0x9bda, 0, 8, 0x00 }, | ||
226 | { 0x9be3, 0, 8, 0x00 }, | ||
227 | { 0xd015, 0, 8, 0x50 }, | ||
228 | { 0xd016, 0, 1, 0x00 }, | ||
229 | { 0xd044, 0, 8, 0x46 }, | ||
230 | { 0xd045, 0, 1, 0x00 }, | ||
231 | { 0xd008, 0, 8, 0xdf }, | ||
232 | { 0xd009, 0, 2, 0x02 }, | ||
233 | { 0xd006, 0, 8, 0x44 }, | ||
234 | { 0xd007, 0, 2, 0x01 }, | ||
235 | { 0xd00c, 0, 8, 0xeb }, | ||
236 | { 0xd00d, 0, 2, 0x02 }, | ||
237 | { 0xd00a, 0, 8, 0xf4 }, | ||
238 | { 0xd00b, 0, 2, 0x01 }, | ||
239 | { 0x9bba, 0, 8, 0xf9 }, | ||
240 | { 0x9bc3, 0, 8, 0xdf }, | ||
241 | { 0x9bc4, 0, 8, 0x02 }, | ||
242 | { 0x9bc5, 0, 8, 0xeb }, | ||
243 | { 0x9bc6, 0, 8, 0x02 }, | ||
244 | { 0x9bc9, 0, 8, 0x52 }, | ||
245 | { 0xd011, 0, 8, 0x3c }, | ||
246 | { 0xd012, 0, 2, 0x01 }, | ||
247 | { 0xd013, 0, 8, 0xf7 }, | ||
248 | { 0xd014, 0, 2, 0x02 }, | ||
249 | { 0xd040, 0, 8, 0x0b }, | ||
250 | { 0xd041, 0, 2, 0x02 }, | ||
251 | { 0xd042, 0, 8, 0x4d }, | ||
252 | { 0xd043, 0, 2, 0x00 }, | ||
253 | { 0xd045, 1, 1, 0x00 }, | ||
254 | { 0x9bcf, 0, 1, 0x01 }, | ||
255 | { 0xd045, 2, 1, 0x01 }, | ||
256 | { 0xd04f, 0, 8, 0x9a }, | ||
257 | { 0xd050, 0, 1, 0x01 }, | ||
258 | { 0xd051, 0, 8, 0x5a }, | ||
259 | { 0xd052, 0, 1, 0x01 }, | ||
260 | { 0xd053, 0, 8, 0x50 }, | ||
261 | { 0xd054, 0, 8, 0x46 }, | ||
262 | { 0x9bd7, 0, 8, 0x0a }, | ||
263 | { 0x9bd8, 0, 8, 0x14 }, | ||
264 | { 0x9bd9, 0, 8, 0x08 }, | ||
265 | }; | ||
266 | |||
267 | /* Microtune MT2060 tuner init | ||
268 | AF9013_TUNER_MT2060 = 130 */ | ||
269 | static struct regdesc tuner_init_mt2060[] = { | ||
270 | { 0x9bd5, 0, 8, 0x01 }, | ||
271 | { 0x9bd6, 0, 8, 0x07 }, | ||
272 | { 0xd1a0, 1, 1, 0x01 }, | ||
273 | { 0xd000, 0, 1, 0x01 }, | ||
274 | { 0xd000, 1, 1, 0x00 }, | ||
275 | { 0xd001, 1, 1, 0x01 }, | ||
276 | { 0xd001, 0, 1, 0x00 }, | ||
277 | { 0xd001, 5, 1, 0x00 }, | ||
278 | { 0xd002, 0, 5, 0x19 }, | ||
279 | { 0xd003, 0, 5, 0x1a }, | ||
280 | { 0xd004, 0, 5, 0x19 }, | ||
281 | { 0xd005, 0, 5, 0x1a }, | ||
282 | { 0xd00e, 0, 5, 0x10 }, | ||
283 | { 0xd00f, 0, 3, 0x04 }, | ||
284 | { 0xd00f, 3, 3, 0x05 }, | ||
285 | { 0xd010, 0, 3, 0x04 }, | ||
286 | { 0xd010, 3, 3, 0x05 }, | ||
287 | { 0xd016, 4, 4, 0x03 }, | ||
288 | { 0xd01f, 0, 6, 0x0a }, | ||
289 | { 0xd020, 0, 6, 0x0a }, | ||
290 | { 0x9bda, 0, 8, 0x00 }, | ||
291 | { 0x9be3, 0, 8, 0x00 }, | ||
292 | { 0x9bbe, 0, 1, 0x00 }, | ||
293 | { 0x9bcc, 0, 1, 0x00 }, | ||
294 | { 0x9bb9, 0, 8, 0x75 }, | ||
295 | { 0x9bcd, 0, 8, 0x24 }, | ||
296 | { 0x9bff, 0, 8, 0x30 }, | ||
297 | { 0xd015, 0, 8, 0x46 }, | ||
298 | { 0xd016, 0, 1, 0x00 }, | ||
299 | { 0xd044, 0, 8, 0x46 }, | ||
300 | { 0xd045, 0, 1, 0x00 }, | ||
301 | { 0xd008, 0, 8, 0x0f }, | ||
302 | { 0xd009, 0, 2, 0x02 }, | ||
303 | { 0xd006, 0, 8, 0x32 }, | ||
304 | { 0xd007, 0, 2, 0x01 }, | ||
305 | { 0xd00c, 0, 8, 0x36 }, | ||
306 | { 0xd00d, 0, 2, 0x03 }, | ||
307 | { 0xd00a, 0, 8, 0x35 }, | ||
308 | { 0xd00b, 0, 2, 0x01 }, | ||
309 | { 0x9bc7, 0, 8, 0x07 }, | ||
310 | { 0x9bc8, 0, 8, 0x90 }, | ||
311 | { 0x9bc3, 0, 8, 0x0f }, | ||
312 | { 0x9bc4, 0, 8, 0x02 }, | ||
313 | { 0x9bc5, 0, 8, 0x36 }, | ||
314 | { 0x9bc6, 0, 8, 0x03 }, | ||
315 | { 0x9bba, 0, 8, 0xc9 }, | ||
316 | { 0x9bc9, 0, 8, 0x79 }, | ||
317 | { 0xd011, 0, 8, 0x10 }, | ||
318 | { 0xd012, 0, 2, 0x01 }, | ||
319 | { 0xd013, 0, 8, 0x45 }, | ||
320 | { 0xd014, 0, 2, 0x03 }, | ||
321 | { 0xd040, 0, 8, 0x98 }, | ||
322 | { 0xd041, 0, 2, 0x00 }, | ||
323 | { 0xd042, 0, 8, 0xcf }, | ||
324 | { 0xd043, 0, 2, 0x03 }, | ||
325 | { 0xd045, 1, 1, 0x00 }, | ||
326 | { 0x9bcf, 0, 1, 0x01 }, | ||
327 | { 0xd045, 2, 1, 0x01 }, | ||
328 | { 0xd04f, 0, 8, 0x9a }, | ||
329 | { 0xd050, 0, 1, 0x01 }, | ||
330 | { 0xd051, 0, 8, 0x5a }, | ||
331 | { 0xd052, 0, 1, 0x01 }, | ||
332 | { 0xd053, 0, 8, 0x50 }, | ||
333 | { 0xd054, 0, 8, 0x46 }, | ||
334 | { 0x9bd7, 0, 8, 0x0a }, | ||
335 | { 0x9bd8, 0, 8, 0x14 }, | ||
336 | { 0x9bd9, 0, 8, 0x08 }, | ||
337 | { 0x9bd0, 0, 8, 0xcc }, | ||
338 | { 0x9be4, 0, 8, 0xa0 }, | ||
339 | { 0x9bbd, 0, 8, 0x8e }, | ||
340 | { 0x9be2, 0, 8, 0x4d }, | ||
341 | { 0x9bee, 0, 1, 0x01 }, | ||
342 | }; | ||
343 | |||
344 | /* Microtune MT2060 tuner init | ||
345 | AF9013_TUNER_MT2060_2 = 147 */ | ||
346 | static struct regdesc tuner_init_mt2060_2[] = { | ||
347 | { 0x9bd5, 0, 8, 0x01 }, | ||
348 | { 0x9bd6, 0, 8, 0x06 }, | ||
349 | { 0x9bbe, 0, 8, 0x01 }, | ||
350 | { 0xd1a0, 1, 1, 0x01 }, | ||
351 | { 0xd000, 0, 1, 0x01 }, | ||
352 | { 0xd000, 1, 1, 0x00 }, | ||
353 | { 0xd001, 1, 1, 0x01 }, | ||
354 | { 0xd001, 0, 1, 0x00 }, | ||
355 | { 0xd001, 5, 1, 0x00 }, | ||
356 | { 0xd002, 0, 5, 0x19 }, | ||
357 | { 0xd003, 0, 5, 0x1a }, | ||
358 | { 0xd004, 0, 5, 0x19 }, | ||
359 | { 0xd005, 0, 5, 0x1a }, | ||
360 | { 0xd00e, 0, 5, 0x10 }, | ||
361 | { 0xd00f, 0, 3, 0x04 }, | ||
362 | { 0xd00f, 3, 3, 0x05 }, | ||
363 | { 0xd010, 0, 3, 0x04 }, | ||
364 | { 0xd010, 3, 3, 0x05 }, | ||
365 | { 0xd016, 4, 4, 0x03 }, | ||
366 | { 0xd01f, 0, 6, 0x0a }, | ||
367 | { 0xd020, 0, 6, 0x0a }, | ||
368 | { 0xd015, 0, 8, 0x46 }, | ||
369 | { 0xd016, 0, 1, 0x00 }, | ||
370 | { 0xd044, 0, 8, 0x46 }, | ||
371 | { 0xd045, 0, 1, 0x00 }, | ||
372 | { 0xd008, 0, 8, 0x0f }, | ||
373 | { 0xd009, 0, 2, 0x02 }, | ||
374 | { 0xd006, 0, 8, 0x32 }, | ||
375 | { 0xd007, 0, 2, 0x01 }, | ||
376 | { 0xd00c, 0, 8, 0x36 }, | ||
377 | { 0xd00d, 0, 2, 0x03 }, | ||
378 | { 0xd00a, 0, 8, 0x35 }, | ||
379 | { 0xd00b, 0, 2, 0x01 }, | ||
380 | { 0x9bc7, 0, 8, 0x07 }, | ||
381 | { 0x9bc8, 0, 8, 0x90 }, | ||
382 | { 0x9bc3, 0, 8, 0x0f }, | ||
383 | { 0x9bc4, 0, 8, 0x02 }, | ||
384 | { 0x9bc5, 0, 8, 0x36 }, | ||
385 | { 0x9bc6, 0, 8, 0x03 }, | ||
386 | { 0x9bba, 0, 8, 0xc9 }, | ||
387 | { 0x9bc9, 0, 8, 0x79 }, | ||
388 | { 0xd011, 0, 8, 0x10 }, | ||
389 | { 0xd012, 0, 2, 0x01 }, | ||
390 | { 0xd013, 0, 8, 0x45 }, | ||
391 | { 0xd014, 0, 2, 0x03 }, | ||
392 | { 0xd040, 0, 8, 0x98 }, | ||
393 | { 0xd041, 0, 2, 0x00 }, | ||
394 | { 0xd042, 0, 8, 0xcf }, | ||
395 | { 0xd043, 0, 2, 0x03 }, | ||
396 | { 0xd045, 1, 1, 0x00 }, | ||
397 | { 0x9bcf, 0, 8, 0x01 }, | ||
398 | { 0xd045, 2, 1, 0x01 }, | ||
399 | { 0xd04f, 0, 8, 0x9a }, | ||
400 | { 0xd050, 0, 1, 0x01 }, | ||
401 | { 0xd051, 0, 8, 0x5a }, | ||
402 | { 0xd052, 0, 1, 0x01 }, | ||
403 | { 0xd053, 0, 8, 0x96 }, | ||
404 | { 0xd054, 0, 8, 0x46 }, | ||
405 | { 0xd045, 7, 1, 0x00 }, | ||
406 | { 0x9bd7, 0, 8, 0x0a }, | ||
407 | { 0x9bd8, 0, 8, 0x14 }, | ||
408 | { 0x9bd9, 0, 8, 0x08 }, | ||
409 | }; | ||
410 | |||
411 | /* MaxLinear MXL5003 tuner init | ||
412 | AF9013_TUNER_MXL5003D = 3 */ | ||
413 | static struct regdesc tuner_init_mxl5003d[] = { | ||
414 | { 0x9bd5, 0, 8, 0x01 }, | ||
415 | { 0x9bd6, 0, 8, 0x09 }, | ||
416 | { 0xd1a0, 1, 1, 0x01 }, | ||
417 | { 0xd000, 0, 1, 0x01 }, | ||
418 | { 0xd000, 1, 1, 0x00 }, | ||
419 | { 0xd001, 1, 1, 0x01 }, | ||
420 | { 0xd001, 0, 1, 0x00 }, | ||
421 | { 0xd001, 5, 1, 0x00 }, | ||
422 | { 0xd002, 0, 5, 0x19 }, | ||
423 | { 0xd003, 0, 5, 0x1a }, | ||
424 | { 0xd004, 0, 5, 0x19 }, | ||
425 | { 0xd005, 0, 5, 0x1a }, | ||
426 | { 0xd00e, 0, 5, 0x10 }, | ||
427 | { 0xd00f, 0, 3, 0x04 }, | ||
428 | { 0xd00f, 3, 3, 0x05 }, | ||
429 | { 0xd010, 0, 3, 0x04 }, | ||
430 | { 0xd010, 3, 3, 0x05 }, | ||
431 | { 0xd016, 4, 4, 0x03 }, | ||
432 | { 0xd01f, 0, 6, 0x0a }, | ||
433 | { 0xd020, 0, 6, 0x0a }, | ||
434 | { 0x9bda, 0, 8, 0x00 }, | ||
435 | { 0x9be3, 0, 8, 0x00 }, | ||
436 | { 0x9bfc, 0, 8, 0x0f }, | ||
437 | { 0x9bf6, 0, 8, 0x01 }, | ||
438 | { 0x9bbe, 0, 1, 0x01 }, | ||
439 | { 0xd015, 0, 8, 0x33 }, | ||
440 | { 0xd016, 0, 1, 0x00 }, | ||
441 | { 0xd044, 0, 8, 0x40 }, | ||
442 | { 0xd045, 0, 1, 0x00 }, | ||
443 | { 0xd008, 0, 8, 0x0f }, | ||
444 | { 0xd009, 0, 2, 0x02 }, | ||
445 | { 0xd006, 0, 8, 0x6c }, | ||
446 | { 0xd007, 0, 2, 0x00 }, | ||
447 | { 0xd00c, 0, 8, 0x3d }, | ||
448 | { 0xd00d, 0, 2, 0x00 }, | ||
449 | { 0xd00a, 0, 8, 0x45 }, | ||
450 | { 0xd00b, 0, 2, 0x01 }, | ||
451 | { 0x9bc7, 0, 8, 0x07 }, | ||
452 | { 0x9bc8, 0, 8, 0x52 }, | ||
453 | { 0x9bc3, 0, 8, 0x0f }, | ||
454 | { 0x9bc4, 0, 8, 0x02 }, | ||
455 | { 0x9bc5, 0, 8, 0x3d }, | ||
456 | { 0x9bc6, 0, 8, 0x00 }, | ||
457 | { 0x9bba, 0, 8, 0xa2 }, | ||
458 | { 0x9bc9, 0, 8, 0xa0 }, | ||
459 | { 0xd011, 0, 8, 0x56 }, | ||
460 | { 0xd012, 0, 2, 0x00 }, | ||
461 | { 0xd013, 0, 8, 0x50 }, | ||
462 | { 0xd014, 0, 2, 0x00 }, | ||
463 | { 0xd040, 0, 8, 0x56 }, | ||
464 | { 0xd041, 0, 2, 0x00 }, | ||
465 | { 0xd042, 0, 8, 0x50 }, | ||
466 | { 0xd043, 0, 2, 0x00 }, | ||
467 | { 0xd045, 1, 1, 0x00 }, | ||
468 | { 0x9bcf, 0, 8, 0x01 }, | ||
469 | { 0xd045, 2, 1, 0x01 }, | ||
470 | { 0xd04f, 0, 8, 0x9a }, | ||
471 | { 0xd050, 0, 1, 0x01 }, | ||
472 | { 0xd051, 0, 8, 0x5a }, | ||
473 | { 0xd052, 0, 1, 0x01 }, | ||
474 | { 0xd053, 0, 8, 0x50 }, | ||
475 | { 0xd054, 0, 8, 0x46 }, | ||
476 | { 0x9bd7, 0, 8, 0x0a }, | ||
477 | { 0x9bd8, 0, 8, 0x14 }, | ||
478 | { 0x9bd9, 0, 8, 0x08 }, | ||
479 | }; | ||
480 | |||
481 | /* MaxLinear MXL5005 tuner init | ||
482 | AF9013_TUNER_MXL5005D = 13 | ||
483 | AF9013_TUNER_MXL5005R = 30 */ | ||
484 | static struct regdesc tuner_init_mxl5005[] = { | ||
485 | { 0x9bd5, 0, 8, 0x01 }, | ||
486 | { 0x9bd6, 0, 8, 0x07 }, | ||
487 | { 0xd1a0, 1, 1, 0x01 }, | ||
488 | { 0xd000, 0, 1, 0x01 }, | ||
489 | { 0xd000, 1, 1, 0x00 }, | ||
490 | { 0xd001, 1, 1, 0x01 }, | ||
491 | { 0xd001, 0, 1, 0x00 }, | ||
492 | { 0xd001, 5, 1, 0x00 }, | ||
493 | { 0xd002, 0, 5, 0x19 }, | ||
494 | { 0xd003, 0, 5, 0x1a }, | ||
495 | { 0xd004, 0, 5, 0x19 }, | ||
496 | { 0xd005, 0, 5, 0x1a }, | ||
497 | { 0xd00e, 0, 5, 0x10 }, | ||
498 | { 0xd00f, 0, 3, 0x04 }, | ||
499 | { 0xd00f, 3, 3, 0x05 }, | ||
500 | { 0xd010, 0, 3, 0x04 }, | ||
501 | { 0xd010, 3, 3, 0x05 }, | ||
502 | { 0xd016, 4, 4, 0x03 }, | ||
503 | { 0xd01f, 0, 6, 0x0a }, | ||
504 | { 0xd020, 0, 6, 0x0a }, | ||
505 | { 0x9bda, 0, 8, 0x01 }, | ||
506 | { 0x9be3, 0, 8, 0x01 }, | ||
507 | { 0x9bbe, 0, 1, 0x01 }, | ||
508 | { 0x9bcc, 0, 1, 0x01 }, | ||
509 | { 0x9bb9, 0, 8, 0x00 }, | ||
510 | { 0x9bcd, 0, 8, 0x28 }, | ||
511 | { 0x9bff, 0, 8, 0x24 }, | ||
512 | { 0xd015, 0, 8, 0x40 }, | ||
513 | { 0xd016, 0, 1, 0x00 }, | ||
514 | { 0xd044, 0, 8, 0x40 }, | ||
515 | { 0xd045, 0, 1, 0x00 }, | ||
516 | { 0xd008, 0, 8, 0x0f }, | ||
517 | { 0xd009, 0, 2, 0x02 }, | ||
518 | { 0xd006, 0, 8, 0x73 }, | ||
519 | { 0xd007, 0, 2, 0x01 }, | ||
520 | { 0xd00c, 0, 8, 0xfa }, | ||
521 | { 0xd00d, 0, 2, 0x01 }, | ||
522 | { 0xd00a, 0, 8, 0xff }, | ||
523 | { 0xd00b, 0, 2, 0x01 }, | ||
524 | { 0x9bc7, 0, 8, 0x23 }, | ||
525 | { 0x9bc8, 0, 8, 0x55 }, | ||
526 | { 0x9bc3, 0, 8, 0x01 }, | ||
527 | { 0x9bc4, 0, 8, 0x02 }, | ||
528 | { 0x9bc5, 0, 8, 0xfa }, | ||
529 | { 0x9bc6, 0, 8, 0x01 }, | ||
530 | { 0x9bba, 0, 8, 0xff }, | ||
531 | { 0x9bc9, 0, 8, 0xff }, | ||
532 | { 0x9bd3, 0, 8, 0x95 }, | ||
533 | { 0xd011, 0, 8, 0x70 }, | ||
534 | { 0xd012, 0, 2, 0x01 }, | ||
535 | { 0xd013, 0, 8, 0xfb }, | ||
536 | { 0xd014, 0, 2, 0x01 }, | ||
537 | { 0xd040, 0, 8, 0x70 }, | ||
538 | { 0xd041, 0, 2, 0x01 }, | ||
539 | { 0xd042, 0, 8, 0xfb }, | ||
540 | { 0xd043, 0, 2, 0x01 }, | ||
541 | { 0xd045, 1, 1, 0x00 }, | ||
542 | { 0x9bcf, 0, 1, 0x01 }, | ||
543 | { 0xd045, 2, 1, 0x01 }, | ||
544 | { 0xd04f, 0, 8, 0x9a }, | ||
545 | { 0xd050, 0, 1, 0x01 }, | ||
546 | { 0xd051, 0, 8, 0x5a }, | ||
547 | { 0xd052, 0, 1, 0x01 }, | ||
548 | { 0xd053, 0, 8, 0x50 }, | ||
549 | { 0xd054, 0, 8, 0x46 }, | ||
550 | { 0x9bd7, 0, 8, 0x0a }, | ||
551 | { 0x9bd8, 0, 8, 0x14 }, | ||
552 | { 0x9bd9, 0, 8, 0x08 }, | ||
553 | { 0x9bd0, 0, 8, 0x93 }, | ||
554 | { 0x9be4, 0, 8, 0xfe }, | ||
555 | { 0x9bbd, 0, 8, 0x63 }, | ||
556 | { 0x9be2, 0, 8, 0xfe }, | ||
557 | { 0x9bee, 0, 1, 0x01 }, | ||
558 | }; | ||
559 | |||
560 | /* Quantek QT1010 tuner init | ||
561 | AF9013_TUNER_QT1010 = 134 | ||
562 | AF9013_TUNER_QT1010A = 162 */ | ||
563 | static struct regdesc tuner_init_qt1010[] = { | ||
564 | { 0x9bd5, 0, 8, 0x01 }, | ||
565 | { 0x9bd6, 0, 8, 0x09 }, | ||
566 | { 0xd1a0, 1, 1, 0x01 }, | ||
567 | { 0xd000, 0, 1, 0x01 }, | ||
568 | { 0xd000, 1, 1, 0x00 }, | ||
569 | { 0xd001, 1, 1, 0x01 }, | ||
570 | { 0xd001, 0, 1, 0x00 }, | ||
571 | { 0xd001, 5, 1, 0x00 }, | ||
572 | { 0xd002, 0, 5, 0x19 }, | ||
573 | { 0xd003, 0, 5, 0x1a }, | ||
574 | { 0xd004, 0, 5, 0x19 }, | ||
575 | { 0xd005, 0, 5, 0x1a }, | ||
576 | { 0xd00e, 0, 5, 0x10 }, | ||
577 | { 0xd00f, 0, 3, 0x04 }, | ||
578 | { 0xd00f, 3, 3, 0x05 }, | ||
579 | { 0xd010, 0, 3, 0x04 }, | ||
580 | { 0xd010, 3, 3, 0x05 }, | ||
581 | { 0xd016, 4, 4, 0x03 }, | ||
582 | { 0xd01f, 0, 6, 0x0a }, | ||
583 | { 0xd020, 0, 6, 0x0a }, | ||
584 | { 0x9bda, 0, 8, 0x01 }, | ||
585 | { 0x9be3, 0, 8, 0x01 }, | ||
586 | { 0xd015, 0, 8, 0x46 }, | ||
587 | { 0xd016, 0, 1, 0x00 }, | ||
588 | { 0xd044, 0, 8, 0x46 }, | ||
589 | { 0xd045, 0, 1, 0x00 }, | ||
590 | { 0x9bbe, 0, 1, 0x01 }, | ||
591 | { 0x9bcc, 0, 1, 0x01 }, | ||
592 | { 0x9bb9, 0, 8, 0x00 }, | ||
593 | { 0x9bcd, 0, 8, 0x28 }, | ||
594 | { 0x9bff, 0, 8, 0x20 }, | ||
595 | { 0xd008, 0, 8, 0x0f }, | ||
596 | { 0xd009, 0, 2, 0x02 }, | ||
597 | { 0xd006, 0, 8, 0x99 }, | ||
598 | { 0xd007, 0, 2, 0x01 }, | ||
599 | { 0xd00c, 0, 8, 0x0f }, | ||
600 | { 0xd00d, 0, 2, 0x02 }, | ||
601 | { 0xd00a, 0, 8, 0x50 }, | ||
602 | { 0xd00b, 0, 2, 0x01 }, | ||
603 | { 0x9bc7, 0, 8, 0x00 }, | ||
604 | { 0x9bc8, 0, 8, 0x00 }, | ||
605 | { 0x9bc3, 0, 8, 0x0f }, | ||
606 | { 0x9bc4, 0, 8, 0x02 }, | ||
607 | { 0x9bc5, 0, 8, 0x0f }, | ||
608 | { 0x9bc6, 0, 8, 0x02 }, | ||
609 | { 0x9bba, 0, 8, 0xc5 }, | ||
610 | { 0x9bc9, 0, 8, 0xff }, | ||
611 | { 0xd011, 0, 8, 0x58 }, | ||
612 | { 0xd012, 0, 2, 0x02 }, | ||
613 | { 0xd013, 0, 8, 0x89 }, | ||
614 | { 0xd014, 0, 2, 0x01 }, | ||
615 | { 0xd040, 0, 8, 0x58 }, | ||
616 | { 0xd041, 0, 2, 0x02 }, | ||
617 | { 0xd042, 0, 8, 0x89 }, | ||
618 | { 0xd043, 0, 2, 0x01 }, | ||
619 | { 0xd045, 1, 1, 0x00 }, | ||
620 | { 0x9bcf, 0, 1, 0x01 }, | ||
621 | { 0xd045, 2, 1, 0x01 }, | ||
622 | { 0xd04f, 0, 8, 0x9a }, | ||
623 | { 0xd050, 0, 1, 0x01 }, | ||
624 | { 0xd051, 0, 8, 0x5a }, | ||
625 | { 0xd052, 0, 1, 0x01 }, | ||
626 | { 0xd053, 0, 8, 0x50 }, | ||
627 | { 0xd054, 0, 8, 0x46 }, | ||
628 | { 0x9bd7, 0, 8, 0x0a }, | ||
629 | { 0x9bd8, 0, 8, 0x14 }, | ||
630 | { 0x9bd9, 0, 8, 0x08 }, | ||
631 | { 0x9bd0, 0, 8, 0xcd }, | ||
632 | { 0x9be4, 0, 8, 0xbb }, | ||
633 | { 0x9bbd, 0, 8, 0x93 }, | ||
634 | { 0x9be2, 0, 8, 0x80 }, | ||
635 | { 0x9bee, 0, 1, 0x01 }, | ||
636 | }; | ||
637 | |||
638 | /* Freescale MC44S803 tuner init | ||
639 | AF9013_TUNER_MC44S803 = 133 */ | ||
640 | static struct regdesc tuner_init_mc44s803[] = { | ||
641 | { 0x9bd5, 0, 8, 0x01 }, | ||
642 | { 0x9bd6, 0, 8, 0x06 }, | ||
643 | { 0xd1a0, 1, 1, 0x01 }, | ||
644 | { 0xd000, 0, 1, 0x01 }, | ||
645 | { 0xd000, 1, 1, 0x00 }, | ||
646 | { 0xd001, 1, 1, 0x01 }, | ||
647 | { 0xd001, 0, 1, 0x00 }, | ||
648 | { 0xd001, 5, 1, 0x00 }, | ||
649 | { 0xd002, 0, 5, 0x19 }, | ||
650 | { 0xd003, 0, 5, 0x1a }, | ||
651 | { 0xd004, 0, 5, 0x19 }, | ||
652 | { 0xd005, 0, 5, 0x1a }, | ||
653 | { 0xd00e, 0, 5, 0x10 }, | ||
654 | { 0xd00f, 0, 3, 0x04 }, | ||
655 | { 0xd00f, 3, 3, 0x05 }, | ||
656 | { 0xd010, 0, 3, 0x04 }, | ||
657 | { 0xd010, 3, 3, 0x05 }, | ||
658 | { 0xd016, 4, 4, 0x03 }, | ||
659 | { 0xd01f, 0, 6, 0x0a }, | ||
660 | { 0xd020, 0, 6, 0x0a }, | ||
661 | { 0x9bda, 0, 8, 0x00 }, | ||
662 | { 0x9be3, 0, 8, 0x00 }, | ||
663 | { 0x9bf6, 0, 8, 0x01 }, | ||
664 | { 0x9bf8, 0, 8, 0x02 }, | ||
665 | { 0x9bf9, 0, 8, 0x02 }, | ||
666 | { 0x9bfc, 0, 8, 0x1f }, | ||
667 | { 0x9bbe, 0, 1, 0x01 }, | ||
668 | { 0x9bcc, 0, 1, 0x01 }, | ||
669 | { 0x9bb9, 0, 8, 0x00 }, | ||
670 | { 0x9bcd, 0, 8, 0x24 }, | ||
671 | { 0x9bff, 0, 8, 0x24 }, | ||
672 | { 0xd015, 0, 8, 0x46 }, | ||
673 | { 0xd016, 0, 1, 0x00 }, | ||
674 | { 0xd044, 0, 8, 0x46 }, | ||
675 | { 0xd045, 0, 1, 0x00 }, | ||
676 | { 0xd008, 0, 8, 0x01 }, | ||
677 | { 0xd009, 0, 2, 0x02 }, | ||
678 | { 0xd006, 0, 8, 0x7b }, | ||
679 | { 0xd007, 0, 2, 0x00 }, | ||
680 | { 0xd00c, 0, 8, 0x7c }, | ||
681 | { 0xd00d, 0, 2, 0x02 }, | ||
682 | { 0xd00a, 0, 8, 0xfe }, | ||
683 | { 0xd00b, 0, 2, 0x01 }, | ||
684 | { 0x9bc7, 0, 8, 0x08 }, | ||
685 | { 0x9bc8, 0, 8, 0x9a }, | ||
686 | { 0x9bc3, 0, 8, 0x01 }, | ||
687 | { 0x9bc4, 0, 8, 0x02 }, | ||
688 | { 0x9bc5, 0, 8, 0x7c }, | ||
689 | { 0x9bc6, 0, 8, 0x02 }, | ||
690 | { 0x9bba, 0, 8, 0xfc }, | ||
691 | { 0x9bc9, 0, 8, 0xaa }, | ||
692 | { 0xd011, 0, 8, 0x6b }, | ||
693 | { 0xd012, 0, 2, 0x00 }, | ||
694 | { 0xd013, 0, 8, 0x88 }, | ||
695 | { 0xd014, 0, 2, 0x02 }, | ||
696 | { 0xd040, 0, 8, 0x6b }, | ||
697 | { 0xd041, 0, 2, 0x00 }, | ||
698 | { 0xd042, 0, 8, 0x7c }, | ||
699 | { 0xd043, 0, 2, 0x02 }, | ||
700 | { 0xd045, 1, 1, 0x00 }, | ||
701 | { 0x9bcf, 0, 1, 0x01 }, | ||
702 | { 0xd045, 2, 1, 0x01 }, | ||
703 | { 0xd04f, 0, 8, 0x9a }, | ||
704 | { 0xd050, 0, 1, 0x01 }, | ||
705 | { 0xd051, 0, 8, 0x5a }, | ||
706 | { 0xd052, 0, 1, 0x01 }, | ||
707 | { 0xd053, 0, 8, 0x50 }, | ||
708 | { 0xd054, 0, 8, 0x46 }, | ||
709 | { 0x9bd7, 0, 8, 0x0a }, | ||
710 | { 0x9bd8, 0, 8, 0x14 }, | ||
711 | { 0x9bd9, 0, 8, 0x08 }, | ||
712 | { 0x9bd0, 0, 8, 0x9e }, | ||
713 | { 0x9be4, 0, 8, 0xff }, | ||
714 | { 0x9bbd, 0, 8, 0x9e }, | ||
715 | { 0x9be2, 0, 8, 0x25 }, | ||
716 | { 0x9bee, 0, 1, 0x01 }, | ||
717 | { 0xd73b, 3, 1, 0x00 }, | ||
718 | }; | ||
719 | |||
720 | /* unknown, probably for tin can tuner, tuner init | ||
721 | AF9013_TUNER_UNKNOWN = 140 */ | ||
722 | static struct regdesc tuner_init_unknown[] = { | ||
723 | { 0x9bd5, 0, 8, 0x01 }, | ||
724 | { 0x9bd6, 0, 8, 0x02 }, | ||
725 | { 0xd1a0, 1, 1, 0x01 }, | ||
726 | { 0xd000, 0, 1, 0x01 }, | ||
727 | { 0xd000, 1, 1, 0x00 }, | ||
728 | { 0xd001, 1, 1, 0x01 }, | ||
729 | { 0xd001, 0, 1, 0x00 }, | ||
730 | { 0xd001, 5, 1, 0x00 }, | ||
731 | { 0xd002, 0, 5, 0x19 }, | ||
732 | { 0xd003, 0, 5, 0x1a }, | ||
733 | { 0xd004, 0, 5, 0x19 }, | ||
734 | { 0xd005, 0, 5, 0x1a }, | ||
735 | { 0xd00e, 0, 5, 0x10 }, | ||
736 | { 0xd00f, 0, 3, 0x04 }, | ||
737 | { 0xd00f, 3, 3, 0x05 }, | ||
738 | { 0xd010, 0, 3, 0x04 }, | ||
739 | { 0xd010, 3, 3, 0x05 }, | ||
740 | { 0xd016, 4, 4, 0x03 }, | ||
741 | { 0xd01f, 0, 6, 0x0a }, | ||
742 | { 0xd020, 0, 6, 0x0a }, | ||
743 | { 0x9bda, 0, 8, 0x01 }, | ||
744 | { 0x9be3, 0, 8, 0x01 }, | ||
745 | { 0xd1a0, 1, 1, 0x00 }, | ||
746 | { 0x9bbe, 0, 1, 0x01 }, | ||
747 | { 0x9bcc, 0, 1, 0x01 }, | ||
748 | { 0x9bb9, 0, 8, 0x00 }, | ||
749 | { 0x9bcd, 0, 8, 0x18 }, | ||
750 | { 0x9bff, 0, 8, 0x2c }, | ||
751 | { 0xd015, 0, 8, 0x46 }, | ||
752 | { 0xd016, 0, 1, 0x00 }, | ||
753 | { 0xd044, 0, 8, 0x46 }, | ||
754 | { 0xd045, 0, 1, 0x00 }, | ||
755 | { 0xd008, 0, 8, 0xdf }, | ||
756 | { 0xd009, 0, 2, 0x02 }, | ||
757 | { 0xd006, 0, 8, 0x44 }, | ||
758 | { 0xd007, 0, 2, 0x01 }, | ||
759 | { 0xd00c, 0, 8, 0x00 }, | ||
760 | { 0xd00d, 0, 2, 0x02 }, | ||
761 | { 0xd00a, 0, 8, 0xf6 }, | ||
762 | { 0xd00b, 0, 2, 0x01 }, | ||
763 | { 0x9bba, 0, 8, 0xf9 }, | ||
764 | { 0x9bc8, 0, 8, 0xaa }, | ||
765 | { 0x9bc3, 0, 8, 0xdf }, | ||
766 | { 0x9bc4, 0, 8, 0x02 }, | ||
767 | { 0x9bc5, 0, 8, 0x00 }, | ||
768 | { 0x9bc6, 0, 8, 0x02 }, | ||
769 | { 0x9bc9, 0, 8, 0xf0 }, | ||
770 | { 0xd011, 0, 8, 0x3c }, | ||
771 | { 0xd012, 0, 2, 0x01 }, | ||
772 | { 0xd013, 0, 8, 0xf7 }, | ||
773 | { 0xd014, 0, 2, 0x02 }, | ||
774 | { 0xd040, 0, 8, 0x0b }, | ||
775 | { 0xd041, 0, 2, 0x02 }, | ||
776 | { 0xd042, 0, 8, 0x4d }, | ||
777 | { 0xd043, 0, 2, 0x00 }, | ||
778 | { 0xd045, 1, 1, 0x00 }, | ||
779 | { 0x9bcf, 0, 1, 0x01 }, | ||
780 | { 0xd045, 2, 1, 0x01 }, | ||
781 | { 0xd04f, 0, 8, 0x9a }, | ||
782 | { 0xd050, 0, 1, 0x01 }, | ||
783 | { 0xd051, 0, 8, 0x5a }, | ||
784 | { 0xd052, 0, 1, 0x01 }, | ||
785 | { 0xd053, 0, 8, 0x50 }, | ||
786 | { 0xd054, 0, 8, 0x46 }, | ||
787 | { 0x9bd7, 0, 8, 0x0a }, | ||
788 | { 0x9bd8, 0, 8, 0x14 }, | ||
789 | { 0x9bd9, 0, 8, 0x08 }, | ||
790 | }; | ||
791 | |||
792 | /* NXP TDA18271 tuner init | ||
793 | AF9013_TUNER_TDA18271 = 156 */ | ||
794 | static struct regdesc tuner_init_tda18271[] = { | ||
795 | { 0x9bd5, 0, 8, 0x01 }, | ||
796 | { 0x9bd6, 0, 8, 0x04 }, | ||
797 | { 0xd1a0, 1, 1, 0x01 }, | ||
798 | { 0xd000, 0, 1, 0x01 }, | ||
799 | { 0xd000, 1, 1, 0x00 }, | ||
800 | { 0xd001, 1, 1, 0x01 }, | ||
801 | { 0xd001, 0, 1, 0x00 }, | ||
802 | { 0xd001, 5, 1, 0x00 }, | ||
803 | { 0xd002, 0, 5, 0x19 }, | ||
804 | { 0xd003, 0, 5, 0x1a }, | ||
805 | { 0xd004, 0, 5, 0x19 }, | ||
806 | { 0xd005, 0, 5, 0x1a }, | ||
807 | { 0xd00e, 0, 5, 0x10 }, | ||
808 | { 0xd00f, 0, 3, 0x04 }, | ||
809 | { 0xd00f, 3, 3, 0x05 }, | ||
810 | { 0xd010, 0, 3, 0x04 }, | ||
811 | { 0xd010, 3, 3, 0x05 }, | ||
812 | { 0xd016, 4, 4, 0x03 }, | ||
813 | { 0xd01f, 0, 6, 0x0a }, | ||
814 | { 0xd020, 0, 6, 0x0a }, | ||
815 | { 0x9bda, 0, 8, 0x01 }, | ||
816 | { 0x9be3, 0, 8, 0x01 }, | ||
817 | { 0xd1a0, 1, 1, 0x00 }, | ||
818 | { 0x9bbe, 0, 1, 0x01 }, | ||
819 | { 0x9bcc, 0, 1, 0x01 }, | ||
820 | { 0x9bb9, 0, 8, 0x00 }, | ||
821 | { 0x9bcd, 0, 8, 0x18 }, | ||
822 | { 0x9bff, 0, 8, 0x2c }, | ||
823 | { 0xd015, 0, 8, 0x46 }, | ||
824 | { 0xd016, 0, 1, 0x00 }, | ||
825 | { 0xd044, 0, 8, 0x46 }, | ||
826 | { 0xd045, 0, 1, 0x00 }, | ||
827 | { 0xd008, 0, 8, 0xdf }, | ||
828 | { 0xd009, 0, 2, 0x02 }, | ||
829 | { 0xd006, 0, 8, 0x44 }, | ||
830 | { 0xd007, 0, 2, 0x01 }, | ||
831 | { 0xd00c, 0, 8, 0x00 }, | ||
832 | { 0xd00d, 0, 2, 0x02 }, | ||
833 | { 0xd00a, 0, 8, 0xf6 }, | ||
834 | { 0xd00b, 0, 2, 0x01 }, | ||
835 | { 0x9bba, 0, 8, 0xf9 }, | ||
836 | { 0x9bc8, 0, 8, 0xaa }, | ||
837 | { 0x9bc3, 0, 8, 0xdf }, | ||
838 | { 0x9bc4, 0, 8, 0x02 }, | ||
839 | { 0x9bc5, 0, 8, 0x00 }, | ||
840 | { 0x9bc6, 0, 8, 0x02 }, | ||
841 | { 0x9bc9, 0, 8, 0xf0 }, | ||
842 | { 0xd011, 0, 8, 0x3c }, | ||
843 | { 0xd012, 0, 2, 0x01 }, | ||
844 | { 0xd013, 0, 8, 0xf7 }, | ||
845 | { 0xd014, 0, 2, 0x02 }, | ||
846 | { 0xd040, 0, 8, 0x0b }, | ||
847 | { 0xd041, 0, 2, 0x02 }, | ||
848 | { 0xd042, 0, 8, 0x4d }, | ||
849 | { 0xd043, 0, 2, 0x00 }, | ||
850 | { 0xd045, 1, 1, 0x00 }, | ||
851 | { 0x9bcf, 0, 1, 0x01 }, | ||
852 | { 0xd045, 2, 1, 0x01 }, | ||
853 | { 0xd04f, 0, 8, 0x9a }, | ||
854 | { 0xd050, 0, 1, 0x01 }, | ||
855 | { 0xd051, 0, 8, 0x5a }, | ||
856 | { 0xd052, 0, 1, 0x01 }, | ||
857 | { 0xd053, 0, 8, 0x50 }, | ||
858 | { 0xd054, 0, 8, 0x46 }, | ||
859 | { 0x9bd7, 0, 8, 0x0a }, | ||
860 | { 0x9bd8, 0, 8, 0x14 }, | ||
861 | { 0x9bd9, 0, 8, 0x08 }, | ||
862 | { 0x9bd0, 0, 8, 0xa8 }, | ||
863 | { 0x9be4, 0, 8, 0x7f }, | ||
864 | { 0x9bbd, 0, 8, 0xa8 }, | ||
865 | { 0x9be2, 0, 8, 0x20 }, | ||
866 | { 0x9bee, 0, 1, 0x01 }, | ||
867 | }; | ||
868 | |||
869 | #endif /* _AF9013_PRIV_ */ | ||
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c index 0b82cc2a1e16..eabf9a68e7ec 100644 --- a/drivers/media/dvb/frontends/au8522.c +++ b/drivers/media/dvb/frontends/au8522.c | |||
@@ -40,6 +40,8 @@ struct au8522_state { | |||
40 | u32 current_frequency; | 40 | u32 current_frequency; |
41 | fe_modulation_t current_modulation; | 41 | fe_modulation_t current_modulation; |
42 | 42 | ||
43 | u32 fe_status; | ||
44 | unsigned int led_state; | ||
43 | }; | 45 | }; |
44 | 46 | ||
45 | static int debug; | 47 | static int debug; |
@@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe) | |||
538 | return 0; | 540 | return 0; |
539 | } | 541 | } |
540 | 542 | ||
543 | static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) | ||
544 | { | ||
545 | struct au8522_led_config *led_config = state->config->led_cfg; | ||
546 | u8 val; | ||
547 | |||
548 | /* bail out if we cant control an LED */ | ||
549 | if (!led_config || !led_config->gpio_output || | ||
550 | !led_config->gpio_output_enable || !led_config->gpio_output_disable) | ||
551 | return 0; | ||
552 | |||
553 | val = au8522_readreg(state, 0x4000 | | ||
554 | (led_config->gpio_output & ~0xc000)); | ||
555 | if (onoff) { | ||
556 | /* enable GPIO output */ | ||
557 | val &= ~((led_config->gpio_output_enable >> 8) & 0xff); | ||
558 | val |= (led_config->gpio_output_enable & 0xff); | ||
559 | } else { | ||
560 | /* disable GPIO output */ | ||
561 | val &= ~((led_config->gpio_output_disable >> 8) & 0xff); | ||
562 | val |= (led_config->gpio_output_disable & 0xff); | ||
563 | } | ||
564 | return au8522_writereg(state, 0x8000 | | ||
565 | (led_config->gpio_output & ~0xc000), val); | ||
566 | } | ||
567 | |||
568 | /* led = 0 | off | ||
569 | * led = 1 | signal ok | ||
570 | * led = 2 | signal strong | ||
571 | * led < 0 | only light led if leds are currently off | ||
572 | */ | ||
573 | static int au8522_led_ctrl(struct au8522_state *state, int led) | ||
574 | { | ||
575 | struct au8522_led_config *led_config = state->config->led_cfg; | ||
576 | int i, ret = 0; | ||
577 | |||
578 | /* bail out if we cant control an LED */ | ||
579 | if (!led_config || !led_config->gpio_leds || | ||
580 | !led_config->num_led_states || !led_config->led_states) | ||
581 | return 0; | ||
582 | |||
583 | if (led < 0) { | ||
584 | /* if LED is already lit, then leave it as-is */ | ||
585 | if (state->led_state) | ||
586 | return 0; | ||
587 | else | ||
588 | led *= -1; | ||
589 | } | ||
590 | |||
591 | /* toggle LED if changing state */ | ||
592 | if (state->led_state != led) { | ||
593 | u8 val; | ||
594 | |||
595 | dprintk("%s: %d\n", __func__, led); | ||
596 | |||
597 | au8522_led_gpio_enable(state, 1); | ||
598 | |||
599 | val = au8522_readreg(state, 0x4000 | | ||
600 | (led_config->gpio_leds & ~0xc000)); | ||
601 | |||
602 | /* start with all leds off */ | ||
603 | for (i = 0; i < led_config->num_led_states; i++) | ||
604 | val &= ~led_config->led_states[i]; | ||
605 | |||
606 | /* set selected LED state */ | ||
607 | if (led < led_config->num_led_states) | ||
608 | val |= led_config->led_states[led]; | ||
609 | else if (led_config->num_led_states) | ||
610 | val |= | ||
611 | led_config->led_states[led_config->num_led_states - 1]; | ||
612 | |||
613 | ret = au8522_writereg(state, 0x8000 | | ||
614 | (led_config->gpio_leds & ~0xc000), val); | ||
615 | if (ret < 0) | ||
616 | return ret; | ||
617 | |||
618 | state->led_state = led; | ||
619 | |||
620 | if (led == 0) | ||
621 | au8522_led_gpio_enable(state, 0); | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
541 | static int au8522_sleep(struct dvb_frontend *fe) | 627 | static int au8522_sleep(struct dvb_frontend *fe) |
542 | { | 628 | { |
543 | struct au8522_state *state = fe->demodulator_priv; | 629 | struct au8522_state *state = fe->demodulator_priv; |
544 | dprintk("%s()\n", __func__); | 630 | dprintk("%s()\n", __func__); |
545 | 631 | ||
632 | /* turn off led */ | ||
633 | au8522_led_ctrl(state, 0); | ||
634 | |||
546 | state->current_frequency = 0; | 635 | state->current_frequency = 0; |
547 | 636 | ||
548 | return 0; | 637 | return 0; |
@@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) | |||
592 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; | 681 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; |
593 | break; | 682 | break; |
594 | } | 683 | } |
684 | state->fe_status = *status; | ||
685 | |||
686 | if (*status & FE_HAS_LOCK) | ||
687 | /* turn on LED, if it isn't on already */ | ||
688 | au8522_led_ctrl(state, -1); | ||
689 | else | ||
690 | /* turn off LED */ | ||
691 | au8522_led_ctrl(state, 0); | ||
595 | 692 | ||
596 | dprintk("%s() status 0x%08x\n", __func__, *status); | 693 | dprintk("%s() status 0x%08x\n", __func__, *status); |
597 | 694 | ||
598 | return 0; | 695 | return 0; |
599 | } | 696 | } |
600 | 697 | ||
698 | static int au8522_led_status(struct au8522_state *state, const u16 *snr) | ||
699 | { | ||
700 | struct au8522_led_config *led_config = state->config->led_cfg; | ||
701 | int led; | ||
702 | u16 strong; | ||
703 | |||
704 | /* bail out if we cant control an LED */ | ||
705 | if (!led_config) | ||
706 | return 0; | ||
707 | |||
708 | if (0 == (state->fe_status & FE_HAS_LOCK)) | ||
709 | return au8522_led_ctrl(state, 0); | ||
710 | else if (state->current_modulation == QAM_256) | ||
711 | strong = led_config->qam256_strong; | ||
712 | else if (state->current_modulation == QAM_64) | ||
713 | strong = led_config->qam64_strong; | ||
714 | else /* (state->current_modulation == VSB_8) */ | ||
715 | strong = led_config->vsb8_strong; | ||
716 | |||
717 | if (*snr >= strong) | ||
718 | led = 2; | ||
719 | else | ||
720 | led = 1; | ||
721 | |||
722 | if ((state->led_state) && | ||
723 | (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) | ||
724 | /* snr didn't change enough to bother | ||
725 | * changing the color of the led */ | ||
726 | return 0; | ||
727 | |||
728 | return au8522_led_ctrl(state, led); | ||
729 | } | ||
730 | |||
601 | static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) | 731 | static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) |
602 | { | 732 | { |
603 | struct au8522_state *state = fe->demodulator_priv; | 733 | struct au8522_state *state = fe->demodulator_priv; |
@@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) | |||
621 | au8522_readreg(state, 0x4311), | 751 | au8522_readreg(state, 0x4311), |
622 | snr); | 752 | snr); |
623 | 753 | ||
754 | if (state->config->led_cfg) | ||
755 | au8522_led_status(state, snr); | ||
756 | |||
624 | return ret; | 757 | return ret; |
625 | } | 758 | } |
626 | 759 | ||
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h index 595915ade8c3..7b94f554a093 100644 --- a/drivers/media/dvb/frontends/au8522.h +++ b/drivers/media/dvb/frontends/au8522.h | |||
@@ -30,6 +30,21 @@ enum au8522_if_freq { | |||
30 | AU8522_IF_3_25MHZ, | 30 | AU8522_IF_3_25MHZ, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct au8522_led_config { | ||
34 | u16 vsb8_strong; | ||
35 | u16 qam64_strong; | ||
36 | u16 qam256_strong; | ||
37 | |||
38 | u16 gpio_output; | ||
39 | /* unset hi bits, set low bits */ | ||
40 | u16 gpio_output_enable; | ||
41 | u16 gpio_output_disable; | ||
42 | |||
43 | u16 gpio_leds; | ||
44 | u8 *led_states; | ||
45 | unsigned int num_led_states; | ||
46 | }; | ||
47 | |||
33 | struct au8522_config { | 48 | struct au8522_config { |
34 | /* the demodulator's i2c address */ | 49 | /* the demodulator's i2c address */ |
35 | u8 demod_address; | 50 | u8 demod_address; |
@@ -39,6 +54,8 @@ struct au8522_config { | |||
39 | #define AU8522_DEMODLOCKING 1 | 54 | #define AU8522_DEMODLOCKING 1 |
40 | u8 status_mode; | 55 | u8 status_mode; |
41 | 56 | ||
57 | struct au8522_led_config *led_cfg; | ||
58 | |||
42 | enum au8522_if_freq vsb_if; | 59 | enum au8522_if_freq vsb_if; |
43 | enum au8522_if_freq qam_if; | 60 | enum au8522_if_freq qam_if; |
44 | }; | 61 | }; |
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index 1792adb23c4d..fdcceee91f3a 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h | |||
@@ -33,12 +33,17 @@ struct cx24110_config | |||
33 | u8 demod_address; | 33 | u8 demod_address; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) { | 36 | static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) |
37 | int r = 0; | 37 | { |
38 | u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)}; | 38 | u8 buf[] = { |
39 | (u8)((val >> 24) & 0xff), | ||
40 | (u8)((val >> 16) & 0xff), | ||
41 | (u8)((val >> 8) & 0xff) | ||
42 | }; | ||
43 | |||
39 | if (fe->ops.write) | 44 | if (fe->ops.write) |
40 | r = fe->ops.write(fe, buf, 3); | 45 | return fe->ops.write(fe, buf, 3); |
41 | return r; | 46 | return 0; |
42 | } | 47 | } |
43 | 48 | ||
44 | #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) | 49 | #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) |
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c new file mode 100644 index 000000000000..deb36f469ada --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.c | |||
@@ -0,0 +1,1423 @@ | |||
1 | /* | ||
2 | Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver | ||
3 | |||
4 | Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com> | ||
5 | Copyright (C) 2006-2007 Georg Acher | ||
6 | Copyright (C) 2007-2008 Darron Broad | ||
7 | March 2007 | ||
8 | Fixed some bugs. | ||
9 | Added diseqc support. | ||
10 | Added corrected signal strength support. | ||
11 | August 2007 | ||
12 | Sync with legacy version. | ||
13 | Some clean ups. | ||
14 | Copyright (C) 2008 Igor Liplianin | ||
15 | September, 9th 2008 | ||
16 | Fixed locking on high symbol rates (>30000). | ||
17 | Implement MPEG initialization parameter. | ||
18 | |||
19 | This program is free software; you can redistribute it and/or modify | ||
20 | it under the terms of the GNU General Public License as published by | ||
21 | the Free Software Foundation; either version 2 of the License, or | ||
22 | (at your option) any later version. | ||
23 | |||
24 | This program is distributed in the hope that it will be useful, | ||
25 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | GNU General Public License for more details. | ||
28 | |||
29 | You should have received a copy of the GNU General Public License | ||
30 | along with this program; if not, write to the Free Software | ||
31 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
32 | */ | ||
33 | |||
34 | #include <linux/slab.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/firmware.h> | ||
40 | |||
41 | #include "dvb_frontend.h" | ||
42 | #include "cx24116.h" | ||
43 | |||
44 | static int debug = 0; | ||
45 | #define dprintk(args...) \ | ||
46 | do { \ | ||
47 | if (debug) printk ("cx24116: " args); \ | ||
48 | } while (0) | ||
49 | |||
50 | #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" | ||
51 | #define CX24116_SEARCH_RANGE_KHZ 5000 | ||
52 | |||
53 | /* known registers */ | ||
54 | #define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ | ||
55 | #define CX24116_REG_EXECUTE (0x1f) /* execute command */ | ||
56 | #define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ | ||
57 | #define CX24116_REG_RESET (0x20) /* reset status > 0 */ | ||
58 | #define CX24116_REG_SIGNAL (0x9e) /* signal low */ | ||
59 | #define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ | ||
60 | #define CX24116_REG_QUALITY8 (0xa3) | ||
61 | #define CX24116_REG_QSTATUS (0xbc) | ||
62 | #define CX24116_REG_QUALITY0 (0xd5) | ||
63 | #define CX24116_REG_BER0 (0xc9) | ||
64 | #define CX24116_REG_BER8 (0xc8) | ||
65 | #define CX24116_REG_BER16 (0xc7) | ||
66 | #define CX24116_REG_BER24 (0xc6) | ||
67 | #define CX24116_REG_UCB0 (0xcb) | ||
68 | #define CX24116_REG_UCB8 (0xca) | ||
69 | #define CX24116_REG_CLKDIV (0xf3) | ||
70 | #define CX24116_REG_RATEDIV (0xf9) | ||
71 | #define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ | ||
72 | |||
73 | /* FECSTATUS bits */ | ||
74 | #define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */ | ||
75 | #define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */ | ||
76 | #define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ | ||
77 | #define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */ | ||
78 | |||
79 | /* arg buffer size */ | ||
80 | #define CX24116_ARGLEN (0x1e) | ||
81 | |||
82 | /* rolloff */ | ||
83 | #define CX24116_ROLLOFF_020 (0x00) | ||
84 | #define CX24116_ROLLOFF_025 (0x01) | ||
85 | #define CX24116_ROLLOFF_035 (0x02) | ||
86 | |||
87 | /* pilot bit */ | ||
88 | #define CX24116_PILOT_OFF (0x00) | ||
89 | #define CX24116_PILOT_ON (0x40) | ||
90 | |||
91 | /* signal status */ | ||
92 | #define CX24116_HAS_SIGNAL (0x01) | ||
93 | #define CX24116_HAS_CARRIER (0x02) | ||
94 | #define CX24116_HAS_VITERBI (0x04) | ||
95 | #define CX24116_HAS_SYNCLOCK (0x08) | ||
96 | #define CX24116_HAS_UNKNOWN1 (0x10) | ||
97 | #define CX24116_HAS_UNKNOWN2 (0x20) | ||
98 | #define CX24116_STATUS_MASK (0x3f) | ||
99 | #define CX24116_SIGNAL_MASK (0xc0) | ||
100 | |||
101 | #define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ | ||
102 | #define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ | ||
103 | #define CX24116_DISEQC_MESGCACHE (2) /* message cached */ | ||
104 | |||
105 | /* arg offset for DiSEqC */ | ||
106 | #define CX24116_DISEQC_BURST (1) | ||
107 | #define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ | ||
108 | #define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ | ||
109 | #define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ | ||
110 | #define CX24116_DISEQC_MSGLEN (5) | ||
111 | #define CX24116_DISEQC_MSGOFS (6) | ||
112 | |||
113 | /* DiSEqC burst */ | ||
114 | #define CX24116_DISEQC_MINI_A (0) | ||
115 | #define CX24116_DISEQC_MINI_B (1) | ||
116 | |||
117 | /* DiSEqC tone burst */ | ||
118 | static int toneburst = 1; | ||
119 | |||
120 | /* SNR measurements */ | ||
121 | static int esno_snr = 0; | ||
122 | |||
123 | enum cmds | ||
124 | { | ||
125 | CMD_SET_VCO = 0x10, | ||
126 | CMD_TUNEREQUEST = 0x11, | ||
127 | CMD_MPEGCONFIG = 0x13, | ||
128 | CMD_TUNERINIT = 0x14, | ||
129 | CMD_BANDWIDTH = 0x15, | ||
130 | CMD_GETAGC = 0x19, | ||
131 | CMD_LNBCONFIG = 0x20, | ||
132 | CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ | ||
133 | CMD_SET_TONEPRE = 0x22, | ||
134 | CMD_SET_TONE = 0x23, | ||
135 | CMD_UPDFWVERS = 0x35, | ||
136 | CMD_TUNERSLEEP = 0x36, | ||
137 | CMD_AGCCONTROL = 0x3b, /* Unknown */ | ||
138 | }; | ||
139 | |||
140 | /* The Demod/Tuner can't easily provide these, we cache them */ | ||
141 | struct cx24116_tuning | ||
142 | { | ||
143 | u32 frequency; | ||
144 | u32 symbol_rate; | ||
145 | fe_spectral_inversion_t inversion; | ||
146 | fe_code_rate_t fec; | ||
147 | |||
148 | fe_modulation_t modulation; | ||
149 | fe_pilot_t pilot; | ||
150 | fe_rolloff_t rolloff; | ||
151 | |||
152 | /* Demod values */ | ||
153 | u8 fec_val; | ||
154 | u8 fec_mask; | ||
155 | u8 inversion_val; | ||
156 | u8 pilot_val; | ||
157 | u8 rolloff_val; | ||
158 | }; | ||
159 | |||
160 | /* Basic commands that are sent to the firmware */ | ||
161 | struct cx24116_cmd | ||
162 | { | ||
163 | u8 len; | ||
164 | u8 args[CX24116_ARGLEN]; | ||
165 | }; | ||
166 | |||
167 | struct cx24116_state | ||
168 | { | ||
169 | struct i2c_adapter* i2c; | ||
170 | const struct cx24116_config* config; | ||
171 | |||
172 | struct dvb_frontend frontend; | ||
173 | |||
174 | struct cx24116_tuning dcur; | ||
175 | struct cx24116_tuning dnxt; | ||
176 | |||
177 | u8 skip_fw_load; | ||
178 | u8 burst; | ||
179 | struct cx24116_cmd dsec_cmd; | ||
180 | }; | ||
181 | |||
182 | static int cx24116_writereg(struct cx24116_state* state, int reg, int data) | ||
183 | { | ||
184 | u8 buf[] = { reg, data }; | ||
185 | struct i2c_msg msg = { .addr = state->config->demod_address, | ||
186 | .flags = 0, .buf = buf, .len = 2 }; | ||
187 | int err; | ||
188 | |||
189 | if (debug>1) | ||
190 | printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", | ||
191 | __func__,reg, data); | ||
192 | |||
193 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
194 | printk("%s: writereg error(err == %i, reg == 0x%02x," | ||
195 | " value == 0x%02x)\n", __func__, err, reg, data); | ||
196 | return -EREMOTEIO; | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | /* Bulk byte writes to a single I2C address, for 32k firmware load */ | ||
203 | static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len) | ||
204 | { | ||
205 | int ret = -EREMOTEIO; | ||
206 | struct i2c_msg msg; | ||
207 | u8 *buf; | ||
208 | |||
209 | buf = kmalloc(len + 1, GFP_KERNEL); | ||
210 | if (buf == NULL) { | ||
211 | printk("Unable to kmalloc\n"); | ||
212 | ret = -ENOMEM; | ||
213 | goto error; | ||
214 | } | ||
215 | |||
216 | *(buf) = reg; | ||
217 | memcpy(buf + 1, data, len); | ||
218 | |||
219 | msg.addr = state->config->demod_address; | ||
220 | msg.flags = 0; | ||
221 | msg.buf = buf; | ||
222 | msg.len = len + 1; | ||
223 | |||
224 | if (debug>1) | ||
225 | printk("cx24116: %s: write regN 0x%02x, len = %d\n", | ||
226 | __func__,reg, len); | ||
227 | |||
228 | if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
229 | printk("%s: writereg error(err == %i, reg == 0x%02x\n", | ||
230 | __func__, ret, reg); | ||
231 | ret = -EREMOTEIO; | ||
232 | } | ||
233 | |||
234 | error: | ||
235 | kfree(buf); | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static int cx24116_readreg(struct cx24116_state* state, u8 reg) | ||
241 | { | ||
242 | int ret; | ||
243 | u8 b0[] = { reg }; | ||
244 | u8 b1[] = { 0 }; | ||
245 | struct i2c_msg msg[] = { | ||
246 | { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
247 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } | ||
248 | }; | ||
249 | |||
250 | ret = i2c_transfer(state->i2c, msg, 2); | ||
251 | |||
252 | if (ret != 2) { | ||
253 | printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | if (debug>1) | ||
258 | printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]); | ||
259 | |||
260 | return b1[0]; | ||
261 | } | ||
262 | |||
263 | static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion) | ||
264 | { | ||
265 | dprintk("%s(%d)\n", __func__, inversion); | ||
266 | |||
267 | switch (inversion) { | ||
268 | case INVERSION_OFF: | ||
269 | state->dnxt.inversion_val = 0x00; | ||
270 | break; | ||
271 | case INVERSION_ON: | ||
272 | state->dnxt.inversion_val = 0x04; | ||
273 | break; | ||
274 | case INVERSION_AUTO: | ||
275 | state->dnxt.inversion_val = 0x0C; | ||
276 | break; | ||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | state->dnxt.inversion = inversion; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * modfec (modulation and FEC) | ||
288 | * =========================== | ||
289 | * | ||
290 | * MOD FEC mask/val standard | ||
291 | * ---- -------- ----------- -------- | ||
292 | * QPSK FEC_1_2 0x02 0x02+X DVB-S | ||
293 | * QPSK FEC_2_3 0x04 0x02+X DVB-S | ||
294 | * QPSK FEC_3_4 0x08 0x02+X DVB-S | ||
295 | * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) | ||
296 | * QPSK FEC_5_6 0x20 0x02+X DVB-S | ||
297 | * QPSK FEC_6_7 0x40 0x02+X DVB-S | ||
298 | * QPSK FEC_7_8 0x80 0x02+X DVB-S | ||
299 | * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) | ||
300 | * QPSK AUTO 0xff 0x02+X DVB-S | ||
301 | * | ||
302 | * For DVB-S high byte probably represents FEC | ||
303 | * and low byte selects the modulator. The high | ||
304 | * byte is search range mask. Bit 5 may turn | ||
305 | * on DVB-S and remaining bits represent some | ||
306 | * kind of calibration (how/what i do not know). | ||
307 | * | ||
308 | * Eg.(2/3) szap "Zone Horror" | ||
309 | * | ||
310 | * mask/val = 0x04, 0x20 | ||
311 | * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK | ||
312 | * | ||
313 | * mask/val = 0x04, 0x30 | ||
314 | * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK | ||
315 | * | ||
316 | * After tuning FECSTATUS contains actual FEC | ||
317 | * in use numbered 1 through to 8 for 1/2 .. 2/3 etc | ||
318 | * | ||
319 | * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) | ||
320 | * | ||
321 | * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 | ||
322 | * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 | ||
323 | * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 | ||
324 | * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 | ||
325 | * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 | ||
326 | * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 | ||
327 | * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 | ||
328 | * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 | ||
329 | * | ||
330 | * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 | ||
331 | * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 | ||
332 | * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 | ||
333 | * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 | ||
334 | * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 | ||
335 | * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 | ||
336 | * | ||
337 | * For DVB-S2 low bytes selects both modulator | ||
338 | * and FEC. High byte is meaningless here. To | ||
339 | * set pilot, bit 6 (0x40) is set. When inspecting | ||
340 | * FECSTATUS bit 7 (0x80) represents the pilot | ||
341 | * selection whilst not tuned. When tuned, actual FEC | ||
342 | * in use is found in FECSTATUS as per above. Pilot | ||
343 | * value is reset. | ||
344 | */ | ||
345 | |||
346 | /* A table of modulation, fec and configuration bytes for the demod. | ||
347 | * Not all S2 mmodulation schemes are support and not all rates with | ||
348 | * a scheme are support. Especially, no auto detect when in S2 mode. | ||
349 | */ | ||
350 | struct cx24116_modfec { | ||
351 | fe_delivery_system_t delivery_system; | ||
352 | fe_modulation_t modulation; | ||
353 | fe_code_rate_t fec; | ||
354 | u8 mask; /* In DVBS mode this is used to autodetect */ | ||
355 | u8 val; /* Passed to the firmware to indicate mode selection */ | ||
356 | } CX24116_MODFEC_MODES[] = { | ||
357 | /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ | ||
358 | |||
359 | /*mod fec mask val */ | ||
360 | { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, | ||
361 | { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ | ||
362 | { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ | ||
363 | { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ | ||
364 | { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ | ||
365 | { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ | ||
366 | { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ | ||
367 | { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ | ||
368 | { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ | ||
369 | { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, | ||
370 | /* NBC-QPSK */ | ||
371 | { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, | ||
372 | { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, | ||
373 | { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, | ||
374 | { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, | ||
375 | { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, | ||
376 | { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, | ||
377 | { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, | ||
378 | { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, | ||
379 | /* 8PSK */ | ||
380 | { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, | ||
381 | { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, | ||
382 | { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, | ||
383 | { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, | ||
384 | { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, | ||
385 | { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, | ||
386 | /* | ||
387 | * `val' can be found in the FECSTATUS register when tuning. | ||
388 | * FECSTATUS will give the actual FEC in use if tuning was successful. | ||
389 | */ | ||
390 | }; | ||
391 | |||
392 | static int cx24116_lookup_fecmod(struct cx24116_state* state, | ||
393 | fe_modulation_t m, fe_code_rate_t f) | ||
394 | { | ||
395 | int i, ret = -EOPNOTSUPP; | ||
396 | |||
397 | dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); | ||
398 | |||
399 | for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++) | ||
400 | { | ||
401 | if( (m == CX24116_MODFEC_MODES[i].modulation) && | ||
402 | (f == CX24116_MODFEC_MODES[i].fec) ) | ||
403 | { | ||
404 | ret = i; | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec) | ||
413 | { | ||
414 | int ret = 0; | ||
415 | |||
416 | dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); | ||
417 | |||
418 | ret = cx24116_lookup_fecmod(state, mod, fec); | ||
419 | |||
420 | if(ret < 0) | ||
421 | return ret; | ||
422 | |||
423 | state->dnxt.fec = fec; | ||
424 | state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; | ||
425 | state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; | ||
426 | dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, | ||
427 | state->dnxt.fec_mask, state->dnxt.fec_val); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) | ||
433 | { | ||
434 | dprintk("%s(%d)\n", __func__, rate); | ||
435 | |||
436 | /* check if symbol rate is within limits */ | ||
437 | if ((rate > state->frontend.ops.info.symbol_rate_max) || | ||
438 | (rate < state->frontend.ops.info.symbol_rate_min)) { | ||
439 | dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); | ||
440 | return -EOPNOTSUPP; | ||
441 | } | ||
442 | |||
443 | state->dnxt.symbol_rate = rate; | ||
444 | dprintk("%s() symbol_rate = %d\n", __func__, rate); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw); | ||
450 | |||
451 | static int cx24116_firmware_ondemand(struct dvb_frontend* fe) | ||
452 | { | ||
453 | struct cx24116_state *state = fe->demodulator_priv; | ||
454 | const struct firmware *fw; | ||
455 | int ret = 0; | ||
456 | |||
457 | dprintk("%s()\n",__func__); | ||
458 | |||
459 | if (cx24116_readreg(state, 0x20) > 0) | ||
460 | { | ||
461 | |||
462 | if (state->skip_fw_load) | ||
463 | return 0; | ||
464 | |||
465 | /* Load firmware */ | ||
466 | /* request the firmware, this will block until someone uploads it */ | ||
467 | printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); | ||
468 | ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev); | ||
469 | printk("%s: Waiting for firmware upload(2)...\n", __func__); | ||
470 | if (ret) { | ||
471 | printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | /* Make sure we don't recurse back through here during loading */ | ||
476 | state->skip_fw_load = 1; | ||
477 | |||
478 | ret = cx24116_load_firmware(fe, fw); | ||
479 | if (ret) | ||
480 | printk("%s: Writing firmware to device failed\n", __func__); | ||
481 | |||
482 | release_firmware(fw); | ||
483 | |||
484 | printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed"); | ||
485 | |||
486 | /* Ensure firmware is always loaded if required */ | ||
487 | state->skip_fw_load = 0; | ||
488 | } | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | /* Take a basic firmware command structure, format it and forward it for processing */ | ||
494 | static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) | ||
495 | { | ||
496 | struct cx24116_state *state = fe->demodulator_priv; | ||
497 | int i, ret; | ||
498 | |||
499 | dprintk("%s()\n", __func__); | ||
500 | |||
501 | /* Load the firmware if required */ | ||
502 | if ( (ret = cx24116_firmware_ondemand(fe)) != 0) | ||
503 | { | ||
504 | printk("%s(): Unable initialise the firmware\n", __func__); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | /* Write the command */ | ||
509 | for(i = 0; i < cmd->len ; i++) | ||
510 | { | ||
511 | dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); | ||
512 | cx24116_writereg(state, i, cmd->args[i]); | ||
513 | } | ||
514 | |||
515 | /* Start execution and wait for cmd to terminate */ | ||
516 | cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); | ||
517 | while( cx24116_readreg(state, CX24116_REG_EXECUTE) ) | ||
518 | { | ||
519 | msleep(10); | ||
520 | if(i++ > 64) | ||
521 | { | ||
522 | /* Avoid looping forever if the firmware does no respond */ | ||
523 | printk("%s() Firmware not responding\n", __func__); | ||
524 | return -EREMOTEIO; | ||
525 | } | ||
526 | } | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | ||
531 | { | ||
532 | struct cx24116_state* state = fe->demodulator_priv; | ||
533 | struct cx24116_cmd cmd; | ||
534 | int i, ret; | ||
535 | unsigned char vers[4]; | ||
536 | |||
537 | dprintk("%s\n", __func__); | ||
538 | dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n" | ||
539 | ,fw->size | ||
540 | ,fw->data[0] | ||
541 | ,fw->data[1] | ||
542 | ,fw->data[ fw->size-2 ] | ||
543 | ,fw->data[ fw->size-1 ] | ||
544 | ); | ||
545 | |||
546 | /* Toggle 88x SRST pin to reset demod */ | ||
547 | if (state->config->reset_device) | ||
548 | state->config->reset_device(fe); | ||
549 | |||
550 | /* Begin the firmware load process */ | ||
551 | /* Prepare the demod, load the firmware, cleanup after load */ | ||
552 | |||
553 | /* Init PLL */ | ||
554 | cx24116_writereg(state, 0xE5, 0x00); | ||
555 | cx24116_writereg(state, 0xF1, 0x08); | ||
556 | cx24116_writereg(state, 0xF2, 0x13); | ||
557 | |||
558 | /* Start PLL */ | ||
559 | cx24116_writereg(state, 0xe0, 0x03); | ||
560 | cx24116_writereg(state, 0xe0, 0x00); | ||
561 | |||
562 | /* Unknown */ | ||
563 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); | ||
564 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); | ||
565 | |||
566 | /* Unknown */ | ||
567 | cx24116_writereg(state, 0xF0, 0x03); | ||
568 | cx24116_writereg(state, 0xF4, 0x81); | ||
569 | cx24116_writereg(state, 0xF5, 0x00); | ||
570 | cx24116_writereg(state, 0xF6, 0x00); | ||
571 | |||
572 | /* write the entire firmware as one transaction */ | ||
573 | cx24116_writeregN(state, 0xF7, fw->data, fw->size); | ||
574 | |||
575 | cx24116_writereg(state, 0xF4, 0x10); | ||
576 | cx24116_writereg(state, 0xF0, 0x00); | ||
577 | cx24116_writereg(state, 0xF8, 0x06); | ||
578 | |||
579 | /* Firmware CMD 10: VCO config */ | ||
580 | cmd.args[0x00] = CMD_SET_VCO; | ||
581 | cmd.args[0x01] = 0x05; | ||
582 | cmd.args[0x02] = 0xdc; | ||
583 | cmd.args[0x03] = 0xda; | ||
584 | cmd.args[0x04] = 0xae; | ||
585 | cmd.args[0x05] = 0xaa; | ||
586 | cmd.args[0x06] = 0x04; | ||
587 | cmd.args[0x07] = 0x9d; | ||
588 | cmd.args[0x08] = 0xfc; | ||
589 | cmd.args[0x09] = 0x06; | ||
590 | cmd.len= 0x0a; | ||
591 | ret = cx24116_cmd_execute(fe, &cmd); | ||
592 | if (ret != 0) | ||
593 | return ret; | ||
594 | |||
595 | cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); | ||
596 | |||
597 | /* Firmware CMD 14: Tuner config */ | ||
598 | cmd.args[0x00] = CMD_TUNERINIT; | ||
599 | cmd.args[0x01] = 0x00; | ||
600 | cmd.args[0x02] = 0x00; | ||
601 | cmd.len= 0x03; | ||
602 | ret = cx24116_cmd_execute(fe, &cmd); | ||
603 | if (ret != 0) | ||
604 | return ret; | ||
605 | |||
606 | cx24116_writereg(state, 0xe5, 0x00); | ||
607 | |||
608 | /* Firmware CMD 13: MPEG config */ | ||
609 | cmd.args[0x00] = CMD_MPEGCONFIG; | ||
610 | cmd.args[0x01] = 0x01; | ||
611 | cmd.args[0x02] = 0x75; | ||
612 | cmd.args[0x03] = 0x00; | ||
613 | if (state->config->mpg_clk_pos_pol) | ||
614 | cmd.args[0x04] = state->config->mpg_clk_pos_pol; | ||
615 | else | ||
616 | cmd.args[0x04] = 0x02; | ||
617 | cmd.args[0x05] = 0x00; | ||
618 | cmd.len= 0x06; | ||
619 | ret = cx24116_cmd_execute(fe, &cmd); | ||
620 | if (ret != 0) | ||
621 | return ret; | ||
622 | |||
623 | /* Firmware CMD 35: Get firmware version */ | ||
624 | cmd.args[0x00] = CMD_UPDFWVERS; | ||
625 | cmd.len= 0x02; | ||
626 | for(i=0; i<4; i++) { | ||
627 | cmd.args[0x01] = i; | ||
628 | ret = cx24116_cmd_execute(fe, &cmd); | ||
629 | if (ret != 0) | ||
630 | return ret; | ||
631 | vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX); | ||
632 | } | ||
633 | printk("%s: FW version %i.%i.%i.%i\n", __func__, | ||
634 | vers[0], vers[1], vers[2], vers[3]); | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
640 | { | ||
641 | /* The isl6421 module will override this function in the fops. */ | ||
642 | dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__); | ||
643 | |||
644 | return -EOPNOTSUPP; | ||
645 | } | ||
646 | |||
647 | static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
648 | { | ||
649 | struct cx24116_state *state = fe->demodulator_priv; | ||
650 | |||
651 | int lock = cx24116_readreg(state, CX24116_REG_SSTATUS); | ||
652 | |||
653 | dprintk("%s: status = 0x%02x\n", __func__, lock); | ||
654 | |||
655 | *status = 0; | ||
656 | |||
657 | if (lock & CX24116_HAS_SIGNAL) | ||
658 | *status |= FE_HAS_SIGNAL; | ||
659 | if (lock & CX24116_HAS_CARRIER) | ||
660 | *status |= FE_HAS_CARRIER; | ||
661 | if (lock & CX24116_HAS_VITERBI) | ||
662 | *status |= FE_HAS_VITERBI; | ||
663 | if (lock & CX24116_HAS_SYNCLOCK) | ||
664 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber) | ||
670 | { | ||
671 | struct cx24116_state *state = fe->demodulator_priv; | ||
672 | |||
673 | dprintk("%s()\n", __func__); | ||
674 | |||
675 | *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) | | ||
676 | ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) | | ||
677 | ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) | | ||
678 | cx24116_readreg(state, CX24116_REG_BER0 ); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* TODO Determine function and scale appropriately */ | ||
684 | static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
685 | { | ||
686 | struct cx24116_state *state = fe->demodulator_priv; | ||
687 | struct cx24116_cmd cmd; | ||
688 | int ret; | ||
689 | u16 sig_reading; | ||
690 | |||
691 | dprintk("%s()\n", __func__); | ||
692 | |||
693 | /* Firmware CMD 19: Get AGC */ | ||
694 | cmd.args[0x00] = CMD_GETAGC; | ||
695 | cmd.len= 0x01; | ||
696 | ret = cx24116_cmd_execute(fe, &cmd); | ||
697 | if (ret != 0) | ||
698 | return ret; | ||
699 | |||
700 | sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) | | ||
701 | ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 ); | ||
702 | *signal_strength= 0 - sig_reading; | ||
703 | |||
704 | dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ | ||
710 | static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) | ||
711 | { | ||
712 | struct cx24116_state *state = fe->demodulator_priv; | ||
713 | u8 snr_reading; | ||
714 | static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ | ||
715 | 0x00000,0x0199A,0x03333,0x04ccD,0x06667, | ||
716 | 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, | ||
717 | 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; | ||
718 | |||
719 | dprintk("%s()\n", __func__); | ||
720 | |||
721 | snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); | ||
722 | |||
723 | if(snr_reading >= 0xa0 /* 100% */) | ||
724 | *snr = 0xffff; | ||
725 | else | ||
726 | *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] + | ||
727 | ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 ); | ||
728 | |||
729 | dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, | ||
730 | snr_reading, *snr); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* The reelbox patches show the value in the registers represents | ||
736 | * ESNO, from 0->30db (values 0->300). We provide this value by | ||
737 | * default. | ||
738 | */ | ||
739 | static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) | ||
740 | { | ||
741 | struct cx24116_state *state = fe->demodulator_priv; | ||
742 | |||
743 | dprintk("%s()\n", __func__); | ||
744 | |||
745 | *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | | ||
746 | cx24116_readreg(state, CX24116_REG_QUALITY0); | ||
747 | |||
748 | dprintk("%s: raw 0x%04x\n", __func__, *snr); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) | ||
754 | { | ||
755 | if (esno_snr == 1) | ||
756 | return cx24116_read_snr_esno(fe, snr); | ||
757 | else | ||
758 | return cx24116_read_snr_pct(fe, snr); | ||
759 | } | ||
760 | |||
761 | static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
762 | { | ||
763 | struct cx24116_state *state = fe->demodulator_priv; | ||
764 | |||
765 | dprintk("%s()\n", __func__); | ||
766 | |||
767 | *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) | | ||
768 | cx24116_readreg(state, CX24116_REG_UCB0); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | /* Overwrite the current tuning params, we are about to tune */ | ||
774 | static void cx24116_clone_params(struct dvb_frontend* fe) | ||
775 | { | ||
776 | struct cx24116_state *state = fe->demodulator_priv; | ||
777 | memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); | ||
778 | } | ||
779 | |||
780 | /* Wait for LNB */ | ||
781 | static int cx24116_wait_for_lnb(struct dvb_frontend* fe) | ||
782 | { | ||
783 | struct cx24116_state *state = fe->demodulator_priv; | ||
784 | int i; | ||
785 | |||
786 | dprintk("%s() qstatus = 0x%02x\n", __func__, | ||
787 | cx24116_readreg(state, CX24116_REG_QSTATUS)); | ||
788 | |||
789 | /* Wait for up to 300 ms */ | ||
790 | for(i = 0; i < 30 ; i++) { | ||
791 | if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) | ||
792 | return 0; | ||
793 | msleep(10); | ||
794 | } | ||
795 | |||
796 | dprintk("%s(): LNB not ready\n", __func__); | ||
797 | |||
798 | return -ETIMEDOUT; /* -EBUSY ? */ | ||
799 | } | ||
800 | |||
801 | static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
802 | { | ||
803 | struct cx24116_cmd cmd; | ||
804 | int ret; | ||
805 | |||
806 | dprintk("%s(%d)\n", __func__, tone); | ||
807 | if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) { | ||
808 | printk("%s: Invalid, tone=%d\n", __func__, tone); | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | /* Wait for LNB ready */ | ||
813 | ret = cx24116_wait_for_lnb(fe); | ||
814 | if(ret != 0) | ||
815 | return ret; | ||
816 | |||
817 | /* Min delay time after DiSEqC send */ | ||
818 | msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ | ||
819 | |||
820 | /* This is always done before the tone is set */ | ||
821 | cmd.args[0x00] = CMD_SET_TONEPRE; | ||
822 | cmd.args[0x01] = 0x00; | ||
823 | cmd.len= 0x02; | ||
824 | ret = cx24116_cmd_execute(fe, &cmd); | ||
825 | if (ret != 0) | ||
826 | return ret; | ||
827 | |||
828 | /* Now we set the tone */ | ||
829 | cmd.args[0x00] = CMD_SET_TONE; | ||
830 | cmd.args[0x01] = 0x00; | ||
831 | cmd.args[0x02] = 0x00; | ||
832 | |||
833 | switch (tone) { | ||
834 | case SEC_TONE_ON: | ||
835 | dprintk("%s: setting tone on\n", __func__); | ||
836 | cmd.args[0x03] = 0x01; | ||
837 | break; | ||
838 | case SEC_TONE_OFF: | ||
839 | dprintk("%s: setting tone off\n",__func__); | ||
840 | cmd.args[0x03] = 0x00; | ||
841 | break; | ||
842 | } | ||
843 | cmd.len= 0x04; | ||
844 | |||
845 | /* Min delay time before DiSEqC send */ | ||
846 | msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ | ||
847 | |||
848 | return cx24116_cmd_execute(fe, &cmd); | ||
849 | } | ||
850 | |||
851 | /* Initialise DiSEqC */ | ||
852 | static int cx24116_diseqc_init(struct dvb_frontend* fe) | ||
853 | { | ||
854 | struct cx24116_state *state = fe->demodulator_priv; | ||
855 | struct cx24116_cmd cmd; | ||
856 | int ret; | ||
857 | |||
858 | /* Firmware CMD 20: LNB/DiSEqC config */ | ||
859 | cmd.args[0x00] = CMD_LNBCONFIG; | ||
860 | cmd.args[0x01] = 0x00; | ||
861 | cmd.args[0x02] = 0x10; | ||
862 | cmd.args[0x03] = 0x00; | ||
863 | cmd.args[0x04] = 0x8f; | ||
864 | cmd.args[0x05] = 0x28; | ||
865 | cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; | ||
866 | cmd.args[0x07] = 0x01; | ||
867 | cmd.len= 0x08; | ||
868 | ret = cx24116_cmd_execute(fe, &cmd); | ||
869 | if (ret != 0) | ||
870 | return ret; | ||
871 | |||
872 | /* Prepare a DiSEqC command */ | ||
873 | state->dsec_cmd.args[0x00] = CMD_LNBSEND; | ||
874 | |||
875 | /* DiSEqC burst */ | ||
876 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; | ||
877 | |||
878 | /* Unknown */ | ||
879 | state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; | ||
880 | state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; | ||
881 | state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */ | ||
882 | |||
883 | /* DiSEqC message length */ | ||
884 | state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; | ||
885 | |||
886 | /* Command length */ | ||
887 | state->dsec_cmd.len= CX24116_DISEQC_MSGOFS; | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | /* Send DiSEqC message with derived burst (hack) || previous burst */ | ||
893 | static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d) | ||
894 | { | ||
895 | struct cx24116_state *state = fe->demodulator_priv; | ||
896 | int i, ret; | ||
897 | |||
898 | /* Dump DiSEqC message */ | ||
899 | if (debug) { | ||
900 | printk("cx24116: %s(", __func__); | ||
901 | for(i = 0 ; i < d->msg_len ;) { | ||
902 | printk("0x%02x", d->msg[i]); | ||
903 | if(++i < d->msg_len) | ||
904 | printk(", "); | ||
905 | } | ||
906 | printk(") toneburst=%d\n", toneburst); | ||
907 | } | ||
908 | |||
909 | /* Validate length */ | ||
910 | if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) | ||
911 | return -EINVAL; | ||
912 | |||
913 | /* DiSEqC message */ | ||
914 | for (i = 0; i < d->msg_len; i++) | ||
915 | state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; | ||
916 | |||
917 | /* DiSEqC message length */ | ||
918 | state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; | ||
919 | |||
920 | /* Command length */ | ||
921 | state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; | ||
922 | |||
923 | /* DiSEqC toneburst */ | ||
924 | if(toneburst == CX24116_DISEQC_MESGCACHE) | ||
925 | /* Message is cached */ | ||
926 | return 0; | ||
927 | |||
928 | else if(toneburst == CX24116_DISEQC_TONEOFF) | ||
929 | /* Message is sent without burst */ | ||
930 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; | ||
931 | |||
932 | else if(toneburst == CX24116_DISEQC_TONECACHE) { | ||
933 | /* | ||
934 | * Message is sent with derived else cached burst | ||
935 | * | ||
936 | * WRITE PORT GROUP COMMAND 38 | ||
937 | * | ||
938 | * 0/A/A: E0 10 38 F0..F3 | ||
939 | * 1/B/B: E0 10 38 F4..F7 | ||
940 | * 2/C/A: E0 10 38 F8..FB | ||
941 | * 3/D/B: E0 10 38 FC..FF | ||
942 | * | ||
943 | * databyte[3]= 8421:8421 | ||
944 | * ABCD:WXYZ | ||
945 | * CLR :SET | ||
946 | * | ||
947 | * WX= PORT SELECT 0..3 (X=TONEBURST) | ||
948 | * Y = VOLTAGE (0=13V, 1=18V) | ||
949 | * Z = BAND (0=LOW, 1=HIGH(22K)) | ||
950 | */ | ||
951 | if(d->msg_len >= 4 && d->msg[2] == 0x38) | ||
952 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2); | ||
953 | if(debug) | ||
954 | dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]); | ||
955 | } | ||
956 | |||
957 | /* Wait for LNB ready */ | ||
958 | ret = cx24116_wait_for_lnb(fe); | ||
959 | if(ret != 0) | ||
960 | return ret; | ||
961 | |||
962 | /* Wait for voltage/min repeat delay */ | ||
963 | msleep(100); | ||
964 | |||
965 | /* Command */ | ||
966 | ret = cx24116_cmd_execute(fe, &state->dsec_cmd); | ||
967 | if(ret != 0) | ||
968 | return ret; | ||
969 | /* | ||
970 | * Wait for send | ||
971 | * | ||
972 | * Eutelsat spec: | ||
973 | * >15ms delay + (XXX determine if FW does this, see set_tone) | ||
974 | * 13.5ms per byte + | ||
975 | * >15ms delay + | ||
976 | * 12.5ms burst + | ||
977 | * >15ms delay (XXX determine if FW does this, see set_tone) | ||
978 | */ | ||
979 | msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) ); | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /* Send DiSEqC burst */ | ||
985 | static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) | ||
986 | { | ||
987 | struct cx24116_state *state = fe->demodulator_priv; | ||
988 | int ret; | ||
989 | |||
990 | dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst); | ||
991 | |||
992 | /* DiSEqC burst */ | ||
993 | if (burst == SEC_MINI_A) | ||
994 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; | ||
995 | else if(burst == SEC_MINI_B) | ||
996 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; | ||
997 | else | ||
998 | return -EINVAL; | ||
999 | |||
1000 | /* DiSEqC toneburst */ | ||
1001 | if(toneburst != CX24116_DISEQC_MESGCACHE) | ||
1002 | /* Burst is cached */ | ||
1003 | return 0; | ||
1004 | |||
1005 | /* Burst is to be sent with cached message */ | ||
1006 | |||
1007 | /* Wait for LNB ready */ | ||
1008 | ret = cx24116_wait_for_lnb(fe); | ||
1009 | if(ret != 0) | ||
1010 | return ret; | ||
1011 | |||
1012 | /* Wait for voltage/min repeat delay */ | ||
1013 | msleep(100); | ||
1014 | |||
1015 | /* Command */ | ||
1016 | ret = cx24116_cmd_execute(fe, &state->dsec_cmd); | ||
1017 | if(ret != 0) | ||
1018 | return ret; | ||
1019 | |||
1020 | /* | ||
1021 | * Wait for send | ||
1022 | * | ||
1023 | * Eutelsat spec: | ||
1024 | * >15ms delay + (XXX determine if FW does this, see set_tone) | ||
1025 | * 13.5ms per byte + | ||
1026 | * >15ms delay + | ||
1027 | * 12.5ms burst + | ||
1028 | * >15ms delay (XXX determine if FW does this, see set_tone) | ||
1029 | */ | ||
1030 | msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static void cx24116_release(struct dvb_frontend* fe) | ||
1036 | { | ||
1037 | struct cx24116_state* state = fe->demodulator_priv; | ||
1038 | dprintk("%s\n",__func__); | ||
1039 | kfree(state); | ||
1040 | } | ||
1041 | |||
1042 | static struct dvb_frontend_ops cx24116_ops; | ||
1043 | |||
1044 | struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
1045 | struct i2c_adapter* i2c) | ||
1046 | { | ||
1047 | struct cx24116_state* state = NULL; | ||
1048 | int ret; | ||
1049 | |||
1050 | dprintk("%s\n",__func__); | ||
1051 | |||
1052 | /* allocate memory for the internal state */ | ||
1053 | state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); | ||
1054 | if (state == NULL) { | ||
1055 | printk("Unable to kmalloc\n"); | ||
1056 | goto error1; | ||
1057 | } | ||
1058 | |||
1059 | /* setup the state */ | ||
1060 | memset(state, 0, sizeof(struct cx24116_state)); | ||
1061 | |||
1062 | state->config = config; | ||
1063 | state->i2c = i2c; | ||
1064 | |||
1065 | /* check if the demod is present */ | ||
1066 | ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); | ||
1067 | if (ret != 0x0501) { | ||
1068 | printk("Invalid probe, probably not a CX24116 device\n"); | ||
1069 | goto error2; | ||
1070 | } | ||
1071 | |||
1072 | /* create dvb_frontend */ | ||
1073 | memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops)); | ||
1074 | state->frontend.demodulator_priv = state; | ||
1075 | return &state->frontend; | ||
1076 | |||
1077 | error2: kfree(state); | ||
1078 | error1: return NULL; | ||
1079 | } | ||
1080 | /* | ||
1081 | * Initialise or wake up device | ||
1082 | * | ||
1083 | * Power config will reset and load initial firmware if required | ||
1084 | */ | ||
1085 | static int cx24116_initfe(struct dvb_frontend* fe) | ||
1086 | { | ||
1087 | struct cx24116_state* state = fe->demodulator_priv; | ||
1088 | struct cx24116_cmd cmd; | ||
1089 | int ret; | ||
1090 | |||
1091 | dprintk("%s()\n",__func__); | ||
1092 | |||
1093 | /* Power on */ | ||
1094 | cx24116_writereg(state, 0xe0, 0); | ||
1095 | cx24116_writereg(state, 0xe1, 0); | ||
1096 | cx24116_writereg(state, 0xea, 0); | ||
1097 | |||
1098 | /* Firmware CMD 36: Power config */ | ||
1099 | cmd.args[0x00] = CMD_TUNERSLEEP; | ||
1100 | cmd.args[0x01] = 0; | ||
1101 | cmd.len= 0x02; | ||
1102 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1103 | if(ret != 0) | ||
1104 | return ret; | ||
1105 | |||
1106 | return cx24116_diseqc_init(fe); | ||
1107 | } | ||
1108 | |||
1109 | /* | ||
1110 | * Put device to sleep | ||
1111 | */ | ||
1112 | static int cx24116_sleep(struct dvb_frontend* fe) | ||
1113 | { | ||
1114 | struct cx24116_state* state = fe->demodulator_priv; | ||
1115 | struct cx24116_cmd cmd; | ||
1116 | int ret; | ||
1117 | |||
1118 | dprintk("%s()\n",__func__); | ||
1119 | |||
1120 | /* Firmware CMD 36: Power config */ | ||
1121 | cmd.args[0x00] = CMD_TUNERSLEEP; | ||
1122 | cmd.args[0x01] = 1; | ||
1123 | cmd.len= 0x02; | ||
1124 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1125 | if(ret != 0) | ||
1126 | return ret; | ||
1127 | |||
1128 | /* Power off (Shutdown clocks) */ | ||
1129 | cx24116_writereg(state, 0xea, 0xff); | ||
1130 | cx24116_writereg(state, 0xe1, 1); | ||
1131 | cx24116_writereg(state, 0xe0, 1); | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp) | ||
1137 | { | ||
1138 | dprintk("%s(..)\n", __func__); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp) | ||
1143 | { | ||
1144 | dprintk("%s(..)\n", __func__); | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | /* dvb-core told us to tune, the tv property cache will be complete, | ||
1149 | * it's safe for is to pull values and use them for tuning purposes. | ||
1150 | */ | ||
1151 | static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
1152 | { | ||
1153 | struct cx24116_state *state = fe->demodulator_priv; | ||
1154 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1155 | struct cx24116_cmd cmd; | ||
1156 | fe_status_t tunerstat; | ||
1157 | int i, status, ret, retune; | ||
1158 | |||
1159 | dprintk("%s()\n",__func__); | ||
1160 | |||
1161 | switch(c->delivery_system) { | ||
1162 | case SYS_DVBS: | ||
1163 | dprintk("%s: DVB-S delivery system selected\n",__func__); | ||
1164 | |||
1165 | /* Only QPSK is supported for DVB-S */ | ||
1166 | if(c->modulation != QPSK) { | ||
1167 | dprintk("%s: unsupported modulation selected (%d)\n", | ||
1168 | __func__, c->modulation); | ||
1169 | return -EOPNOTSUPP; | ||
1170 | } | ||
1171 | |||
1172 | /* Pilot doesn't exist in DVB-S, turn bit off */ | ||
1173 | state->dnxt.pilot_val = CX24116_PILOT_OFF; | ||
1174 | retune = 1; | ||
1175 | |||
1176 | /* DVB-S only supports 0.35 */ | ||
1177 | if(c->rolloff != ROLLOFF_35) { | ||
1178 | dprintk("%s: unsupported rolloff selected (%d)\n", | ||
1179 | __func__, c->rolloff); | ||
1180 | return -EOPNOTSUPP; | ||
1181 | } | ||
1182 | state->dnxt.rolloff_val = CX24116_ROLLOFF_035; | ||
1183 | break; | ||
1184 | |||
1185 | case SYS_DVBS2: | ||
1186 | dprintk("%s: DVB-S2 delivery system selected\n",__func__); | ||
1187 | |||
1188 | /* | ||
1189 | * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, | ||
1190 | * but not hardware auto detection | ||
1191 | */ | ||
1192 | if(c->modulation != PSK_8 && c->modulation != QPSK) { | ||
1193 | dprintk("%s: unsupported modulation selected (%d)\n", | ||
1194 | __func__, c->modulation); | ||
1195 | return -EOPNOTSUPP; | ||
1196 | } | ||
1197 | |||
1198 | switch(c->pilot) { | ||
1199 | case PILOT_AUTO: /* Not supported but emulated */ | ||
1200 | retune = 2; /* Fall-through */ | ||
1201 | case PILOT_OFF: | ||
1202 | state->dnxt.pilot_val = CX24116_PILOT_OFF; | ||
1203 | break; | ||
1204 | case PILOT_ON: | ||
1205 | state->dnxt.pilot_val = CX24116_PILOT_ON; | ||
1206 | break; | ||
1207 | default: | ||
1208 | dprintk("%s: unsupported pilot mode selected (%d)\n", | ||
1209 | __func__, c->pilot); | ||
1210 | return -EOPNOTSUPP; | ||
1211 | } | ||
1212 | |||
1213 | switch(c->rolloff) { | ||
1214 | case ROLLOFF_20: | ||
1215 | state->dnxt.rolloff_val= CX24116_ROLLOFF_020; | ||
1216 | break; | ||
1217 | case ROLLOFF_25: | ||
1218 | state->dnxt.rolloff_val= CX24116_ROLLOFF_025; | ||
1219 | break; | ||
1220 | case ROLLOFF_35: | ||
1221 | state->dnxt.rolloff_val= CX24116_ROLLOFF_035; | ||
1222 | break; | ||
1223 | case ROLLOFF_AUTO: /* Rolloff must be explicit */ | ||
1224 | default: | ||
1225 | dprintk("%s: unsupported rolloff selected (%d)\n", | ||
1226 | __func__, c->rolloff); | ||
1227 | return -EOPNOTSUPP; | ||
1228 | } | ||
1229 | break; | ||
1230 | |||
1231 | default: | ||
1232 | dprintk("%s: unsupported delivery system selected (%d)\n", | ||
1233 | __func__, c->delivery_system); | ||
1234 | return -EOPNOTSUPP; | ||
1235 | } | ||
1236 | state->dnxt.modulation = c->modulation; | ||
1237 | state->dnxt.frequency = c->frequency; | ||
1238 | state->dnxt.pilot = c->pilot; | ||
1239 | state->dnxt.rolloff = c->rolloff; | ||
1240 | |||
1241 | if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) | ||
1242 | return ret; | ||
1243 | |||
1244 | /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ | ||
1245 | if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) | ||
1246 | return ret; | ||
1247 | |||
1248 | if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0) | ||
1249 | return ret; | ||
1250 | |||
1251 | /* discard the 'current' tuning parameters and prepare to tune */ | ||
1252 | cx24116_clone_params(fe); | ||
1253 | |||
1254 | dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); | ||
1255 | dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); | ||
1256 | dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, | ||
1257 | state->dcur.pilot, state->dcur.pilot_val); | ||
1258 | dprintk("%s: retune = %d\n", __func__, retune); | ||
1259 | dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, | ||
1260 | state->dcur.rolloff, state->dcur.rolloff_val); | ||
1261 | dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); | ||
1262 | dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, | ||
1263 | state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); | ||
1264 | dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, | ||
1265 | state->dcur.inversion, state->dcur.inversion_val); | ||
1266 | |||
1267 | /* This is also done in advise/acquire on HVR4000 but not on LITE */ | ||
1268 | if (state->config->set_ts_params) | ||
1269 | state->config->set_ts_params(fe, 0); | ||
1270 | |||
1271 | /* Set/Reset B/W */ | ||
1272 | cmd.args[0x00] = CMD_BANDWIDTH; | ||
1273 | cmd.args[0x01] = 0x01; | ||
1274 | cmd.len= 0x02; | ||
1275 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1276 | if (ret != 0) | ||
1277 | return ret; | ||
1278 | |||
1279 | /* Prepare a tune request */ | ||
1280 | cmd.args[0x00] = CMD_TUNEREQUEST; | ||
1281 | |||
1282 | /* Frequency */ | ||
1283 | cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; | ||
1284 | cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; | ||
1285 | cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); | ||
1286 | |||
1287 | /* Symbol Rate */ | ||
1288 | cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; | ||
1289 | cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); | ||
1290 | |||
1291 | /* Automatic Inversion */ | ||
1292 | cmd.args[0x06] = state->dcur.inversion_val; | ||
1293 | |||
1294 | /* Modulation / FEC / Pilot */ | ||
1295 | cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; | ||
1296 | |||
1297 | cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; | ||
1298 | cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; | ||
1299 | cmd.args[0x0a] = 0x00; | ||
1300 | cmd.args[0x0b] = 0x00; | ||
1301 | cmd.args[0x0c] = state->dcur.rolloff_val; | ||
1302 | cmd.args[0x0d] = state->dcur.fec_mask; | ||
1303 | |||
1304 | if (state->dcur.symbol_rate > 30000000) { | ||
1305 | cmd.args[0x0e] = 0x04; | ||
1306 | cmd.args[0x0f] = 0x00; | ||
1307 | cmd.args[0x10] = 0x01; | ||
1308 | cmd.args[0x11] = 0x77; | ||
1309 | cmd.args[0x12] = 0x36; | ||
1310 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); | ||
1311 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); | ||
1312 | } else { | ||
1313 | cmd.args[0x0e] = 0x06; | ||
1314 | cmd.args[0x0f] = 0x00; | ||
1315 | cmd.args[0x10] = 0x00; | ||
1316 | cmd.args[0x11] = 0xFA; | ||
1317 | cmd.args[0x12] = 0x24; | ||
1318 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); | ||
1319 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); | ||
1320 | } | ||
1321 | |||
1322 | cmd.len= 0x13; | ||
1323 | |||
1324 | /* We need to support pilot and non-pilot tuning in the | ||
1325 | * driver automatically. This is a workaround for because | ||
1326 | * the demod does not support autodetect. | ||
1327 | */ | ||
1328 | do { | ||
1329 | /* Reset status register */ | ||
1330 | status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK; | ||
1331 | cx24116_writereg(state, CX24116_REG_SSTATUS, status); | ||
1332 | |||
1333 | /* Tune */ | ||
1334 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1335 | if( ret != 0 ) | ||
1336 | break; | ||
1337 | |||
1338 | /* | ||
1339 | * Wait for up to 500 ms before retrying | ||
1340 | * | ||
1341 | * If we are able to tune then generally it occurs within 100ms. | ||
1342 | * If it takes longer, try a different toneburst setting. | ||
1343 | */ | ||
1344 | for(i = 0; i < 50 ; i++) { | ||
1345 | cx24116_read_status(fe, &tunerstat); | ||
1346 | status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); | ||
1347 | if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { | ||
1348 | dprintk("%s: Tuned\n",__func__); | ||
1349 | goto tuned; | ||
1350 | } | ||
1351 | msleep(10); | ||
1352 | } | ||
1353 | |||
1354 | dprintk("%s: Not tuned\n",__func__); | ||
1355 | |||
1356 | /* Toggle pilot bit when in auto-pilot */ | ||
1357 | if(state->dcur.pilot == PILOT_AUTO) | ||
1358 | cmd.args[0x07] ^= CX24116_PILOT_ON; | ||
1359 | } | ||
1360 | while(--retune); | ||
1361 | |||
1362 | tuned: /* Set/Reset B/W */ | ||
1363 | cmd.args[0x00] = CMD_BANDWIDTH; | ||
1364 | cmd.args[0x01] = 0x00; | ||
1365 | cmd.len= 0x02; | ||
1366 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1367 | if (ret != 0) | ||
1368 | return ret; | ||
1369 | |||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1373 | static struct dvb_frontend_ops cx24116_ops = { | ||
1374 | |||
1375 | .info = { | ||
1376 | .name = "Conexant CX24116/CX24118", | ||
1377 | .type = FE_QPSK, | ||
1378 | .frequency_min = 950000, | ||
1379 | .frequency_max = 2150000, | ||
1380 | .frequency_stepsize = 1011, /* kHz for QPSK frontends */ | ||
1381 | .frequency_tolerance = 5000, | ||
1382 | .symbol_rate_min = 1000000, | ||
1383 | .symbol_rate_max = 45000000, | ||
1384 | .caps = FE_CAN_INVERSION_AUTO | | ||
1385 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1386 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
1387 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1388 | FE_CAN_QPSK | FE_CAN_RECOVER | ||
1389 | }, | ||
1390 | |||
1391 | .release = cx24116_release, | ||
1392 | |||
1393 | .init = cx24116_initfe, | ||
1394 | .sleep = cx24116_sleep, | ||
1395 | .read_status = cx24116_read_status, | ||
1396 | .read_ber = cx24116_read_ber, | ||
1397 | .read_signal_strength = cx24116_read_signal_strength, | ||
1398 | .read_snr = cx24116_read_snr, | ||
1399 | .read_ucblocks = cx24116_read_ucblocks, | ||
1400 | .set_tone = cx24116_set_tone, | ||
1401 | .set_voltage = cx24116_set_voltage, | ||
1402 | .diseqc_send_master_cmd = cx24116_send_diseqc_msg, | ||
1403 | .diseqc_send_burst = cx24116_diseqc_send_burst, | ||
1404 | |||
1405 | .set_property = cx24116_set_property, | ||
1406 | .get_property = cx24116_get_property, | ||
1407 | .set_frontend = cx24116_set_frontend, | ||
1408 | }; | ||
1409 | |||
1410 | module_param(debug, int, 0644); | ||
1411 | MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); | ||
1412 | |||
1413 | module_param(toneburst, int, 0644); | ||
1414 | MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); | ||
1415 | |||
1416 | module_param(esno_snr, int, 0644); | ||
1417 | MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)"); | ||
1418 | |||
1419 | MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); | ||
1420 | MODULE_AUTHOR("Steven Toth"); | ||
1421 | MODULE_LICENSE("GPL"); | ||
1422 | |||
1423 | EXPORT_SYMBOL(cx24116_attach); | ||
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h new file mode 100644 index 000000000000..8dbcec268394 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver | ||
3 | |||
4 | Copyright (C) 2006 Steven Toth <stoth@linuxtv.com> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef CX24116_H | ||
22 | #define CX24116_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | |||
26 | struct cx24116_config | ||
27 | { | ||
28 | /* the demodulator's i2c address */ | ||
29 | u8 demod_address; | ||
30 | |||
31 | /* Need to set device param for start_dma */ | ||
32 | int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); | ||
33 | |||
34 | /* Need to reset device during firmware loading */ | ||
35 | int (*reset_device)(struct dvb_frontend* fe); | ||
36 | |||
37 | /* Need to set MPEG parameters */ | ||
38 | u8 mpg_clk_pos_pol:0x02; | ||
39 | }; | ||
40 | |||
41 | #if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE) | ||
42 | extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
43 | struct i2c_adapter* i2c); | ||
44 | #else | ||
45 | static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
46 | struct i2c_adapter* i2c) | ||
47 | { | ||
48 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
49 | return NULL; | ||
50 | } | ||
51 | #endif // CONFIG_DVB_CX24116 | ||
52 | |||
53 | #endif /* CX24116_H */ | ||
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index 3eedfdf505bc..21f2c5161af4 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h | |||
@@ -41,6 +41,7 @@ struct dib0070_config { | |||
41 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | 41 | extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, |
42 | struct i2c_adapter *i2c, | 42 | struct i2c_adapter *i2c, |
43 | struct dib0070_config *cfg); | 43 | struct dib0070_config *cfg); |
44 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); | ||
44 | #else | 45 | #else |
45 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | 46 | static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, |
46 | struct i2c_adapter *i2c, | 47 | struct i2c_adapter *i2c, |
@@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, | |||
49 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 50 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
50 | return NULL; | 51 | return NULL; |
51 | } | 52 | } |
53 | |||
54 | static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) | ||
55 | { | ||
56 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
57 | return -ENODEV; | ||
58 | } | ||
52 | #endif | 59 | #endif |
53 | 60 | ||
54 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); | 61 | extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); |
55 | extern u16 dib0070_wbd_offset(struct dvb_frontend *); | ||
56 | 62 | ||
57 | #endif | 63 | #endif |
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 5f1375e30dfc..0109720353bd 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c | |||
@@ -1284,7 +1284,10 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di | |||
1284 | } | 1284 | } |
1285 | EXPORT_SYMBOL(dib7000m_get_i2c_master); | 1285 | EXPORT_SYMBOL(dib7000m_get_i2c_master); |
1286 | 1286 | ||
1287 | int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[]) | 1287 | #if 0 |
1288 | /* used with some prototype boards */ | ||
1289 | int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, | ||
1290 | u8 default_addr, struct dib7000m_config cfg[]) | ||
1288 | { | 1291 | { |
1289 | struct dib7000m_state st = { .i2c_adap = i2c }; | 1292 | struct dib7000m_state st = { .i2c_adap = i2c }; |
1290 | int k = 0; | 1293 | int k = 0; |
@@ -1329,6 +1332,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau | |||
1329 | return 0; | 1332 | return 0; |
1330 | } | 1333 | } |
1331 | EXPORT_SYMBOL(dib7000m_i2c_enumeration); | 1334 | EXPORT_SYMBOL(dib7000m_i2c_enumeration); |
1335 | #endif | ||
1332 | 1336 | ||
1333 | static struct dvb_frontend_ops dib7000m_ops; | 1337 | static struct dvb_frontend_ops dib7000m_ops; |
1334 | struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) | 1338 | struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) |
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 1a0142e0d741..8217e5b38f47 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c | |||
@@ -1333,7 +1333,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, | |||
1333 | /* Ensure the output mode remains at the previous default if it's | 1333 | /* Ensure the output mode remains at the previous default if it's |
1334 | * not specifically set by the caller. | 1334 | * not specifically set by the caller. |
1335 | */ | 1335 | */ |
1336 | if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) | 1336 | if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && |
1337 | (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) | ||
1337 | st->cfg.output_mode = OUTMODE_MPEG2_FIFO; | 1338 | st->cfg.output_mode = OUTMODE_MPEG2_FIFO; |
1338 | 1339 | ||
1339 | demod = &st->demod; | 1340 | demod = &st->demod; |
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 07c4d12ed5b7..3e8126857127 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h | |||
@@ -41,6 +41,14 @@ struct dib7000p_config { | |||
41 | extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, | 41 | extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, |
42 | u8 i2c_addr, | 42 | u8 i2c_addr, |
43 | struct dib7000p_config *cfg); | 43 | struct dib7000p_config *cfg); |
44 | extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, | ||
45 | enum dibx000_i2c_interface, | ||
46 | int); | ||
47 | extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, | ||
48 | int no_of_demods, u8 default_addr, | ||
49 | struct dib7000p_config cfg[]); | ||
50 | extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); | ||
51 | extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); | ||
44 | #else | 52 | #else |
45 | static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, | 53 | static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, |
46 | u8 i2c_addr, | 54 | u8 i2c_addr, |
@@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, | |||
49 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 57 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
50 | return NULL; | 58 | return NULL; |
51 | } | 59 | } |
52 | #endif | ||
53 | 60 | ||
54 | extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); | 61 | static inline |
62 | struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, | ||
63 | enum dibx000_i2c_interface i, int x) | ||
64 | { | ||
65 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
66 | return NULL; | ||
67 | } | ||
68 | |||
69 | extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, | ||
70 | int no_of_demods, u8 default_addr, | ||
71 | struct dib7000p_config cfg[]) | ||
72 | { | ||
73 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
74 | return -ENODEV; | ||
75 | } | ||
76 | |||
77 | extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) | ||
78 | { | ||
79 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
80 | return -ENODEV; | ||
81 | } | ||
82 | |||
83 | extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) | ||
84 | { | ||
85 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
86 | return -ENODEV; | ||
87 | } | ||
88 | #endif | ||
55 | 89 | ||
56 | extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); | ||
57 | extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); | 90 | extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); |
58 | extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); | ||
59 | extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); | ||
60 | 91 | ||
61 | #endif | 92 | #endif |
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index 3cbed874a6f8..b9ca5c8d2dd9 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c | |||
@@ -38,35 +38,32 @@ static const char mod_name[] = "drx397xD"; | |||
38 | #define F_SET_0D0h 1 | 38 | #define F_SET_0D0h 1 |
39 | #define F_SET_0D4h 2 | 39 | #define F_SET_0D4h 2 |
40 | 40 | ||
41 | typedef enum fw_ix { | 41 | enum fw_ix { |
42 | #define _FW_ENTRY(a, b) b | 42 | #define _FW_ENTRY(a, b) b |
43 | #include "drx397xD_fw.h" | 43 | #include "drx397xD_fw.h" |
44 | } fw_ix_t; | 44 | }; |
45 | 45 | ||
46 | /* chip specifics */ | 46 | /* chip specifics */ |
47 | struct drx397xD_state { | 47 | struct drx397xD_state { |
48 | struct i2c_adapter *i2c; | 48 | struct i2c_adapter *i2c; |
49 | struct dvb_frontend frontend; | 49 | struct dvb_frontend frontend; |
50 | struct drx397xD_config config; | 50 | struct drx397xD_config config; |
51 | fw_ix_t chip_rev; | 51 | enum fw_ix chip_rev; |
52 | int flags; | 52 | int flags; |
53 | u32 bandwidth_parm; /* internal bandwidth conversions */ | 53 | u32 bandwidth_parm; /* internal bandwidth conversions */ |
54 | u32 f_osc; /* w90: actual osc frequency [Hz] */ | 54 | u32 f_osc; /* w90: actual osc frequency [Hz] */ |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /******************************************************************************* | 57 | /* Firmware */ |
58 | * Firmware | ||
59 | ******************************************************************************/ | ||
60 | |||
61 | static const char *blob_name[] = { | 58 | static const char *blob_name[] = { |
62 | #define _BLOB_ENTRY(a, b) a | 59 | #define _BLOB_ENTRY(a, b) a |
63 | #include "drx397xD_fw.h" | 60 | #include "drx397xD_fw.h" |
64 | }; | 61 | }; |
65 | 62 | ||
66 | typedef enum blob_ix { | 63 | enum blob_ix { |
67 | #define _BLOB_ENTRY(a, b) b | 64 | #define _BLOB_ENTRY(a, b) b |
68 | #include "drx397xD_fw.h" | 65 | #include "drx397xD_fw.h" |
69 | } blob_ix_t; | 66 | }; |
70 | 67 | ||
71 | static struct { | 68 | static struct { |
72 | const char *name; | 69 | const char *name; |
@@ -85,7 +82,7 @@ static struct { | |||
85 | }; | 82 | }; |
86 | 83 | ||
87 | /* use only with writer lock aquired */ | 84 | /* use only with writer lock aquired */ |
88 | static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) | 85 | static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix) |
89 | { | 86 | { |
90 | memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); | 87 | memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); |
91 | if (fw[ix].file) | 88 | if (fw[ix].file) |
@@ -94,9 +91,9 @@ static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) | |||
94 | 91 | ||
95 | static void drx_release_fw(struct drx397xD_state *s) | 92 | static void drx_release_fw(struct drx397xD_state *s) |
96 | { | 93 | { |
97 | fw_ix_t ix = s->chip_rev; | 94 | enum fw_ix ix = s->chip_rev; |
98 | 95 | ||
99 | pr_debug("%s\n", __FUNCTION__); | 96 | pr_debug("%s\n", __func__); |
100 | 97 | ||
101 | write_lock(&fw[ix].lock); | 98 | write_lock(&fw[ix].lock); |
102 | if (fw[ix].refcnt) { | 99 | if (fw[ix].refcnt) { |
@@ -107,13 +104,13 @@ static void drx_release_fw(struct drx397xD_state *s) | |||
107 | write_unlock(&fw[ix].lock); | 104 | write_unlock(&fw[ix].lock); |
108 | } | 105 | } |
109 | 106 | ||
110 | static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) | 107 | static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) |
111 | { | 108 | { |
112 | const u8 *data; | 109 | const u8 *data; |
113 | size_t size, len; | 110 | size_t size, len; |
114 | int i = 0, j, rc = -EINVAL; | 111 | int i = 0, j, rc = -EINVAL; |
115 | 112 | ||
116 | pr_debug("%s\n", __FUNCTION__); | 113 | pr_debug("%s\n", __func__); |
117 | 114 | ||
118 | if (ix < 0 || ix >= ARRAY_SIZE(fw)) | 115 | if (ix < 0 || ix >= ARRAY_SIZE(fw)) |
119 | return -EINVAL; | 116 | return -EINVAL; |
@@ -175,32 +172,34 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) | |||
175 | goto exit_corrupt; | 172 | goto exit_corrupt; |
176 | } | 173 | } |
177 | } while (i < size); | 174 | } while (i < size); |
178 | exit_corrupt: | 175 | |
176 | exit_corrupt: | ||
179 | printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); | 177 | printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); |
180 | exit_err: | 178 | exit_err: |
181 | _drx_release_fw(s, ix); | 179 | _drx_release_fw(s, ix); |
182 | fw[ix].refcnt--; | 180 | fw[ix].refcnt--; |
183 | exit_ok: | 181 | exit_ok: |
184 | fw[ix].refcnt++; | 182 | fw[ix].refcnt++; |
185 | write_unlock(&fw[ix].lock); | 183 | write_unlock(&fw[ix].lock); |
184 | |||
186 | return rc; | 185 | return rc; |
187 | } | 186 | } |
188 | 187 | ||
189 | /******************************************************************************* | 188 | /* i2c bus IO */ |
190 | * i2c bus IO | 189 | static int write_fw(struct drx397xD_state *s, enum blob_ix ix) |
191 | ******************************************************************************/ | ||
192 | |||
193 | static int write_fw(struct drx397xD_state *s, blob_ix_t ix) | ||
194 | { | 190 | { |
195 | struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 }; | ||
196 | const u8 *data; | 191 | const u8 *data; |
197 | int len, rc = 0, i = 0; | 192 | int len, rc = 0, i = 0; |
193 | struct i2c_msg msg = { | ||
194 | .addr = s->config.demod_address, | ||
195 | .flags = 0 | ||
196 | }; | ||
198 | 197 | ||
199 | if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { | 198 | if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { |
200 | pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__); | 199 | pr_debug("%s drx_fw_ix_t out of range\n", __func__); |
201 | return -EINVAL; | 200 | return -EINVAL; |
202 | } | 201 | } |
203 | pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]); | 202 | pr_debug("%s %s\n", __func__, blob_name[ix]); |
204 | 203 | ||
205 | read_lock(&fw[s->chip_rev].lock); | 204 | read_lock(&fw[s->chip_rev].lock); |
206 | data = fw[s->chip_rev].data[ix]; | 205 | data = fw[s->chip_rev].data[ix]; |
@@ -229,33 +228,33 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix) | |||
229 | goto exit_rc; | 228 | goto exit_rc; |
230 | } | 229 | } |
231 | } | 230 | } |
232 | exit_rc: | 231 | exit_rc: |
233 | read_unlock(&fw[s->chip_rev].lock); | 232 | read_unlock(&fw[s->chip_rev].lock); |
233 | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | /* Function is not endian safe, use the RD16 wrapper below */ | 237 | /* Function is not endian safe, use the RD16 wrapper below */ |
238 | static int _read16(struct drx397xD_state *s, u32 i2c_adr) | 238 | static int _read16(struct drx397xD_state *s, __le32 i2c_adr) |
239 | { | 239 | { |
240 | int rc; | 240 | int rc; |
241 | u8 a[4]; | 241 | u8 a[4]; |
242 | u16 v; | 242 | __le16 v; |
243 | struct i2c_msg msg[2] = { | 243 | struct i2c_msg msg[2] = { |
244 | { | 244 | { |
245 | .addr = s->config.demod_address, | 245 | .addr = s->config.demod_address, |
246 | .flags = 0, | 246 | .flags = 0, |
247 | .buf = a, | 247 | .buf = a, |
248 | .len = sizeof(a) | 248 | .len = sizeof(a) |
249 | } | 249 | }, { |
250 | , { | 250 | .addr = s->config.demod_address, |
251 | .addr = s->config.demod_address, | 251 | .flags = I2C_M_RD, |
252 | .flags = I2C_M_RD, | 252 | .buf = (u8 *)&v, |
253 | .buf = (u8 *) & v, | 253 | .len = sizeof(v) |
254 | .len = sizeof(v) | 254 | } |
255 | } | ||
256 | }; | 255 | }; |
257 | 256 | ||
258 | *(u32 *) a = i2c_adr; | 257 | *(__le32 *) a = i2c_adr; |
259 | 258 | ||
260 | rc = i2c_transfer(s->i2c, msg, 2); | 259 | rc = i2c_transfer(s->i2c, msg, 2); |
261 | if (rc != 2) | 260 | if (rc != 2) |
@@ -265,7 +264,7 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr) | |||
265 | } | 264 | } |
266 | 265 | ||
267 | /* Function is not endian safe, use the WR16.. wrappers below */ | 266 | /* Function is not endian safe, use the WR16.. wrappers below */ |
268 | static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) | 267 | static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val) |
269 | { | 268 | { |
270 | u8 a[6]; | 269 | u8 a[6]; |
271 | int rc; | 270 | int rc; |
@@ -276,28 +275,28 @@ static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) | |||
276 | .len = sizeof(a) | 275 | .len = sizeof(a) |
277 | }; | 276 | }; |
278 | 277 | ||
279 | *(u32 *) a = i2c_adr; | 278 | *(__le32 *)a = i2c_adr; |
280 | *(u16 *) & a[4] = val; | 279 | *(__le16 *)&a[4] = val; |
281 | 280 | ||
282 | rc = i2c_transfer(s->i2c, &msg, 1); | 281 | rc = i2c_transfer(s->i2c, &msg, 1); |
283 | if (rc != 1) | 282 | if (rc != 1) |
284 | return -EIO; | 283 | return -EIO; |
284 | |||
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | #define WR16(ss,adr, val) \ | 288 | #define WR16(ss, adr, val) \ |
289 | _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) | 289 | _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) |
290 | #define WR16_E0(ss,adr, val) \ | 290 | #define WR16_E0(ss, adr, val) \ |
291 | _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) | 291 | _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) |
292 | #define RD16(ss,adr) \ | 292 | #define RD16(ss, adr) \ |
293 | _read16(ss, I2C_ADR_C0(adr)) | 293 | _read16(ss, I2C_ADR_C0(adr)) |
294 | 294 | ||
295 | #define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc | 295 | #define EXIT_RC(cmd) \ |
296 | 296 | if ((rc = (cmd)) < 0) \ | |
297 | /******************************************************************************* | 297 | goto exit_rc |
298 | * Tuner callback | ||
299 | ******************************************************************************/ | ||
300 | 298 | ||
299 | /* Tuner callback */ | ||
301 | static int PLL_Set(struct drx397xD_state *s, | 300 | static int PLL_Set(struct drx397xD_state *s, |
302 | struct dvb_frontend_parameters *fep, int *df_tuner) | 301 | struct dvb_frontend_parameters *fep, int *df_tuner) |
303 | { | 302 | { |
@@ -305,7 +304,7 @@ static int PLL_Set(struct drx397xD_state *s, | |||
305 | u32 f_tuner, f = fep->frequency; | 304 | u32 f_tuner, f = fep->frequency; |
306 | int rc; | 305 | int rc; |
307 | 306 | ||
308 | pr_debug("%s\n", __FUNCTION__); | 307 | pr_debug("%s\n", __func__); |
309 | 308 | ||
310 | if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || | 309 | if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || |
311 | (f < s->frontend.ops.tuner_ops.info.frequency_min)) | 310 | (f < s->frontend.ops.tuner_ops.info.frequency_min)) |
@@ -325,28 +324,26 @@ static int PLL_Set(struct drx397xD_state *s, | |||
325 | return rc; | 324 | return rc; |
326 | 325 | ||
327 | *df_tuner = f_tuner - f; | 326 | *df_tuner = f_tuner - f; |
328 | pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f, | 327 | pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f, |
329 | f_tuner); | 328 | f_tuner); |
330 | 329 | ||
331 | return 0; | 330 | return 0; |
332 | } | 331 | } |
333 | 332 | ||
334 | /******************************************************************************* | 333 | /* Demodulator helper functions */ |
335 | * Demodulator helper functions | ||
336 | ******************************************************************************/ | ||
337 | |||
338 | static int SC_WaitForReady(struct drx397xD_state *s) | 334 | static int SC_WaitForReady(struct drx397xD_state *s) |
339 | { | 335 | { |
340 | int cnt = 1000; | 336 | int cnt = 1000; |
341 | int rc; | 337 | int rc; |
342 | 338 | ||
343 | pr_debug("%s\n", __FUNCTION__); | 339 | pr_debug("%s\n", __func__); |
344 | 340 | ||
345 | while (cnt--) { | 341 | while (cnt--) { |
346 | rc = RD16(s, 0x820043); | 342 | rc = RD16(s, 0x820043); |
347 | if (rc == 0) | 343 | if (rc == 0) |
348 | return 0; | 344 | return 0; |
349 | } | 345 | } |
346 | |||
350 | return -1; | 347 | return -1; |
351 | } | 348 | } |
352 | 349 | ||
@@ -354,13 +351,14 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd) | |||
354 | { | 351 | { |
355 | int rc; | 352 | int rc; |
356 | 353 | ||
357 | pr_debug("%s\n", __FUNCTION__); | 354 | pr_debug("%s\n", __func__); |
358 | 355 | ||
359 | WR16(s, 0x820043, cmd); | 356 | WR16(s, 0x820043, cmd); |
360 | SC_WaitForReady(s); | 357 | SC_WaitForReady(s); |
361 | rc = RD16(s, 0x820042); | 358 | rc = RD16(s, 0x820042); |
362 | if ((rc & 0xffff) == 0xffff) | 359 | if ((rc & 0xffff) == 0xffff) |
363 | return -1; | 360 | return -1; |
361 | |||
364 | return 0; | 362 | return 0; |
365 | } | 363 | } |
366 | 364 | ||
@@ -368,7 +366,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) | |||
368 | { | 366 | { |
369 | int rc, cnt = 1000; | 367 | int rc, cnt = 1000; |
370 | 368 | ||
371 | pr_debug("%s\n", __FUNCTION__); | 369 | pr_debug("%s\n", __func__); |
372 | 370 | ||
373 | rc = WR16(s, 0x420032, cmd); | 371 | rc = WR16(s, 0x420032, cmd); |
374 | if (rc < 0) | 372 | if (rc < 0) |
@@ -383,22 +381,24 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) | |||
383 | if (rc < 0) | 381 | if (rc < 0) |
384 | return rc; | 382 | return rc; |
385 | } while (--cnt); | 383 | } while (--cnt); |
384 | |||
386 | return rc; | 385 | return rc; |
387 | } | 386 | } |
388 | 387 | ||
389 | static int HI_CfgCommand(struct drx397xD_state *s) | 388 | static int HI_CfgCommand(struct drx397xD_state *s) |
390 | { | 389 | { |
391 | 390 | ||
392 | pr_debug("%s\n", __FUNCTION__); | 391 | pr_debug("%s\n", __func__); |
393 | 392 | ||
394 | WR16(s, 0x420033, 0x3973); | 393 | WR16(s, 0x420033, 0x3973); |
395 | WR16(s, 0x420034, s->config.w50); // code 4, log 4 | 394 | WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */ |
396 | WR16(s, 0x420035, s->config.w52); // code 15, log 9 | 395 | WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */ |
397 | WR16(s, 0x420036, s->config.demod_address << 1); | 396 | WR16(s, 0x420036, s->config.demod_address << 1); |
398 | WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1 | 397 | WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */ |
399 | // WR16(s, 0x420033, 0x3973); | 398 | /* WR16(s, 0x420033, 0x3973); */ |
400 | if ((s->config.w56 & 8) == 0) | 399 | if ((s->config.w56 & 8) == 0) |
401 | return HI_Command(s, 3); | 400 | return HI_Command(s, 3); |
401 | |||
402 | return WR16(s, 0x420032, 0x3); | 402 | return WR16(s, 0x420032, 0x3); |
403 | } | 403 | } |
404 | 404 | ||
@@ -419,7 +419,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) | |||
419 | u16 w0C = agc->w0C; | 419 | u16 w0C = agc->w0C; |
420 | int quot, rem, i, rc = -EINVAL; | 420 | int quot, rem, i, rc = -EINVAL; |
421 | 421 | ||
422 | pr_debug("%s\n", __FUNCTION__); | 422 | pr_debug("%s\n", __func__); |
423 | 423 | ||
424 | if (agc->w04 > 0x3ff) | 424 | if (agc->w04 > 0x3ff) |
425 | goto exit_rc; | 425 | goto exit_rc; |
@@ -468,7 +468,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) | |||
468 | i = slowIncrDecLUT_15272[rem / 28]; | 468 | i = slowIncrDecLUT_15272[rem / 28]; |
469 | EXIT_RC(WR16(s, 0x0c2002b, i)); | 469 | EXIT_RC(WR16(s, 0x0c2002b, i)); |
470 | rc = WR16(s, 0x0c2002c, i); | 470 | rc = WR16(s, 0x0c2002c, i); |
471 | exit_rc: | 471 | exit_rc: |
472 | return rc; | 472 | return rc; |
473 | } | 473 | } |
474 | 474 | ||
@@ -478,7 +478,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) | |||
478 | u16 w06 = agc->w06; | 478 | u16 w06 = agc->w06; |
479 | int rc = -1; | 479 | int rc = -1; |
480 | 480 | ||
481 | pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06); | 481 | pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06); |
482 | 482 | ||
483 | if (w04 > 0x3ff) | 483 | if (w04 > 0x3ff) |
484 | goto exit_rc; | 484 | goto exit_rc; |
@@ -498,7 +498,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) | |||
498 | rc &= ~2; | 498 | rc &= ~2; |
499 | break; | 499 | break; |
500 | case 0: | 500 | case 0: |
501 | // loc_8000659 | 501 | /* loc_8000659 */ |
502 | s->config.w9C &= ~2; | 502 | s->config.w9C &= ~2; |
503 | EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); | 503 | EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); |
504 | EXIT_RC(RD16(s, 0x0c20010)); | 504 | EXIT_RC(RD16(s, 0x0c20010)); |
@@ -522,7 +522,8 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) | |||
522 | rc |= 2; | 522 | rc |= 2; |
523 | } | 523 | } |
524 | rc = WR16(s, 0x0c20013, rc); | 524 | rc = WR16(s, 0x0c20013, rc); |
525 | exit_rc: | 525 | |
526 | exit_rc: | ||
526 | return rc; | 527 | return rc; |
527 | } | 528 | } |
528 | 529 | ||
@@ -554,7 +555,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) | |||
554 | int lockstat; | 555 | int lockstat; |
555 | u32 clk, clk_limit; | 556 | u32 clk, clk_limit; |
556 | 557 | ||
557 | pr_debug("%s\n", __FUNCTION__); | 558 | pr_debug("%s\n", __func__); |
558 | 559 | ||
559 | if (s->config.d5C == 0) { | 560 | if (s->config.d5C == 0) { |
560 | EXIT_RC(WR16(s, 0x08200e8, 0x010)); | 561 | EXIT_RC(WR16(s, 0x08200e8, 0x010)); |
@@ -598,11 +599,12 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) | |||
598 | 599 | ||
599 | if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { | 600 | if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { |
600 | s->f_osc = clk; | 601 | s->f_osc = clk; |
601 | pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__, | 602 | pr_debug("%s: osc %d %d [Hz]\n", __func__, |
602 | s->config.f_osc * 1000, clk - s->config.f_osc * 1000); | 603 | s->config.f_osc * 1000, clk - s->config.f_osc * 1000); |
603 | } | 604 | } |
604 | rc = WR16(s, 0x08200e8, 0); | 605 | rc = WR16(s, 0x08200e8, 0); |
605 | exit_rc: | 606 | |
607 | exit_rc: | ||
606 | return rc; | 608 | return rc; |
607 | } | 609 | } |
608 | 610 | ||
@@ -610,7 +612,7 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) | |||
610 | { | 612 | { |
611 | int rc, si, bp; | 613 | int rc, si, bp; |
612 | 614 | ||
613 | pr_debug("%s\n", __FUNCTION__); | 615 | pr_debug("%s\n", __func__); |
614 | 616 | ||
615 | si = s->config.wA0; | 617 | si = s->config.wA0; |
616 | if (s->config.w98 == 0) { | 618 | if (s->config.w98 == 0) { |
@@ -620,17 +622,17 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) | |||
620 | si &= ~1; | 622 | si &= ~1; |
621 | bp = 0x200; | 623 | bp = 0x200; |
622 | } | 624 | } |
623 | if (s->config.w9A == 0) { | 625 | if (s->config.w9A == 0) |
624 | si |= 0x80; | 626 | si |= 0x80; |
625 | } else { | 627 | else |
626 | si &= ~0x80; | 628 | si &= ~0x80; |
627 | } | ||
628 | 629 | ||
629 | EXIT_RC(WR16(s, 0x2150045, 0)); | 630 | EXIT_RC(WR16(s, 0x2150045, 0)); |
630 | EXIT_RC(WR16(s, 0x2150010, si)); | 631 | EXIT_RC(WR16(s, 0x2150010, si)); |
631 | EXIT_RC(WR16(s, 0x2150011, bp)); | 632 | EXIT_RC(WR16(s, 0x2150011, bp)); |
632 | rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); | 633 | rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); |
633 | exit_rc: | 634 | |
635 | exit_rc: | ||
634 | return rc; | 636 | return rc; |
635 | } | 637 | } |
636 | 638 | ||
@@ -646,7 +648,7 @@ static int drx_tune(struct drx397xD_state *s, | |||
646 | 648 | ||
647 | int rc, df_tuner; | 649 | int rc, df_tuner; |
648 | int a, b, c, d; | 650 | int a, b, c, d; |
649 | pr_debug("%s %d\n", __FUNCTION__, s->config.d60); | 651 | pr_debug("%s %d\n", __func__, s->config.d60); |
650 | 652 | ||
651 | if (s->config.d60 != 2) | 653 | if (s->config.d60 != 2) |
652 | goto set_tuner; | 654 | goto set_tuner; |
@@ -658,7 +660,7 @@ static int drx_tune(struct drx397xD_state *s, | |||
658 | rc = ConfigureMPEGOutput(s, 0); | 660 | rc = ConfigureMPEGOutput(s, 0); |
659 | if (rc < 0) | 661 | if (rc < 0) |
660 | goto set_tuner; | 662 | goto set_tuner; |
661 | set_tuner: | 663 | set_tuner: |
662 | 664 | ||
663 | rc = PLL_Set(s, fep, &df_tuner); | 665 | rc = PLL_Set(s, fep, &df_tuner); |
664 | if (rc < 0) { | 666 | if (rc < 0) { |
@@ -835,16 +837,16 @@ static int drx_tune(struct drx397xD_state *s, | |||
835 | rc = WR16(s, 0x2010012, 0); | 837 | rc = WR16(s, 0x2010012, 0); |
836 | if (rc < 0) | 838 | if (rc < 0) |
837 | goto exit_rc; | 839 | goto exit_rc; |
838 | // QPSK QAM16 QAM64 | 840 | /* QPSK QAM16 QAM64 */ |
839 | ebx = 0x19f; // 62 | 841 | ebx = 0x19f; /* 62 */ |
840 | ebp = 0x1fb; // 15 | 842 | ebp = 0x1fb; /* 15 */ |
841 | v20 = 0x16a; // 62 | 843 | v20 = 0x16a; /* 62 */ |
842 | v1E = 0x195; // 62 | 844 | v1E = 0x195; /* 62 */ |
843 | v16 = 0x1bb; // 15 | 845 | v16 = 0x1bb; /* 15 */ |
844 | v14 = 0x1ef; // 15 | 846 | v14 = 0x1ef; /* 15 */ |
845 | v12 = 5; // 16 | 847 | v12 = 5; /* 16 */ |
846 | v10 = 5; // 16 | 848 | v10 = 5; /* 16 */ |
847 | v0E = 5; // 16 | 849 | v0E = 5; /* 16 */ |
848 | } | 850 | } |
849 | 851 | ||
850 | switch (fep->u.ofdm.constellation) { | 852 | switch (fep->u.ofdm.constellation) { |
@@ -997,17 +999,17 @@ static int drx_tune(struct drx397xD_state *s, | |||
997 | case BANDWIDTH_8_MHZ: /* 0 */ | 999 | case BANDWIDTH_8_MHZ: /* 0 */ |
998 | case BANDWIDTH_AUTO: | 1000 | case BANDWIDTH_AUTO: |
999 | rc = WR16(s, 0x0c2003f, 0x32); | 1001 | rc = WR16(s, 0x0c2003f, 0x32); |
1000 | s->bandwidth_parm = ebx = 0x8b8249; // 9142857 | 1002 | s->bandwidth_parm = ebx = 0x8b8249; |
1001 | edx = 0; | 1003 | edx = 0; |
1002 | break; | 1004 | break; |
1003 | case BANDWIDTH_7_MHZ: | 1005 | case BANDWIDTH_7_MHZ: |
1004 | rc = WR16(s, 0x0c2003f, 0x3b); | 1006 | rc = WR16(s, 0x0c2003f, 0x3b); |
1005 | s->bandwidth_parm = ebx = 0x7a1200; // 8000000 | 1007 | s->bandwidth_parm = ebx = 0x7a1200; |
1006 | edx = 0x4807; | 1008 | edx = 0x4807; |
1007 | break; | 1009 | break; |
1008 | case BANDWIDTH_6_MHZ: | 1010 | case BANDWIDTH_6_MHZ: |
1009 | rc = WR16(s, 0x0c2003f, 0x47); | 1011 | rc = WR16(s, 0x0c2003f, 0x47); |
1010 | s->bandwidth_parm = ebx = 0x68a1b6; // 6857142 | 1012 | s->bandwidth_parm = ebx = 0x68a1b6; |
1011 | edx = 0x0f07; | 1013 | edx = 0x0f07; |
1012 | break; | 1014 | break; |
1013 | }; | 1015 | }; |
@@ -1060,8 +1062,6 @@ static int drx_tune(struct drx397xD_state *s, | |||
1060 | WR16(s, 0x0820040, 1); | 1062 | WR16(s, 0x0820040, 1); |
1061 | SC_SendCommand(s, 1); | 1063 | SC_SendCommand(s, 1); |
1062 | 1064 | ||
1063 | // rc = WR16(s, 0x2150000, 1); | ||
1064 | // if (rc < 0) goto exit_rc; | ||
1065 | 1065 | ||
1066 | rc = WR16(s, 0x2150000, 2); | 1066 | rc = WR16(s, 0x2150000, 2); |
1067 | rc = WR16(s, 0x2150016, a); | 1067 | rc = WR16(s, 0x2150016, a); |
@@ -1069,7 +1069,8 @@ static int drx_tune(struct drx397xD_state *s, | |||
1069 | rc = WR16(s, 0x2150036, 0); | 1069 | rc = WR16(s, 0x2150036, 0); |
1070 | rc = WR16(s, 0x2150000, 1); | 1070 | rc = WR16(s, 0x2150000, 1); |
1071 | s->config.d60 = 2; | 1071 | s->config.d60 = 2; |
1072 | exit_rc: | 1072 | |
1073 | exit_rc: | ||
1073 | return rc; | 1074 | return rc; |
1074 | } | 1075 | } |
1075 | 1076 | ||
@@ -1082,7 +1083,7 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1082 | struct drx397xD_state *s = fe->demodulator_priv; | 1083 | struct drx397xD_state *s = fe->demodulator_priv; |
1083 | int rc; | 1084 | int rc; |
1084 | 1085 | ||
1085 | pr_debug("%s\n", __FUNCTION__); | 1086 | pr_debug("%s\n", __func__); |
1086 | 1087 | ||
1087 | s->config.rfagc.d00 = 2; /* 0x7c */ | 1088 | s->config.rfagc.d00 = 2; /* 0x7c */ |
1088 | s->config.rfagc.w04 = 0; | 1089 | s->config.rfagc.w04 = 0; |
@@ -1102,18 +1103,18 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1102 | 1103 | ||
1103 | /* HI_CfgCommand */ | 1104 | /* HI_CfgCommand */ |
1104 | s->config.w50 = 4; | 1105 | s->config.w50 = 4; |
1105 | s->config.w52 = 9; // 0xf; | 1106 | s->config.w52 = 9; |
1106 | 1107 | ||
1107 | s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ | 1108 | s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ |
1108 | s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ | 1109 | s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ |
1109 | s->config.w92 = 12000; // 20000; | 1110 | s->config.w92 = 12000; |
1110 | 1111 | ||
1111 | s->config.w9C = 0x000e; | 1112 | s->config.w9C = 0x000e; |
1112 | s->config.w9E = 0x0000; | 1113 | s->config.w9E = 0x0000; |
1113 | 1114 | ||
1114 | /* ConfigureMPEGOutput params */ | 1115 | /* ConfigureMPEGOutput params */ |
1115 | s->config.wA0 = 4; | 1116 | s->config.wA0 = 4; |
1116 | s->config.w98 = 1; // 0; | 1117 | s->config.w98 = 1; |
1117 | s->config.w9A = 1; | 1118 | s->config.w9A = 1; |
1118 | 1119 | ||
1119 | /* get chip revision */ | 1120 | /* get chip revision */ |
@@ -1248,7 +1249,7 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1248 | rc = WR16(s, 0x0c20012, 1); | 1249 | rc = WR16(s, 0x0c20012, 1); |
1249 | } | 1250 | } |
1250 | 1251 | ||
1251 | write_DRXD_InitFE_1: | 1252 | write_DRXD_InitFE_1: |
1252 | 1253 | ||
1253 | rc = write_fw(s, DRXD_InitFE_1); | 1254 | rc = write_fw(s, DRXD_InitFE_1); |
1254 | if (rc < 0) | 1255 | if (rc < 0) |
@@ -1311,7 +1312,8 @@ static int drx397x_init(struct dvb_frontend *fe) | |||
1311 | s->config.d5C = 0; | 1312 | s->config.d5C = 0; |
1312 | s->config.d60 = 1; | 1313 | s->config.d60 = 1; |
1313 | s->config.d48 = 1; | 1314 | s->config.d48 = 1; |
1314 | error: | 1315 | |
1316 | error: | ||
1315 | return rc; | 1317 | return rc; |
1316 | } | 1318 | } |
1317 | 1319 | ||
@@ -1326,7 +1328,8 @@ static int drx397x_set_frontend(struct dvb_frontend *fe, | |||
1326 | { | 1328 | { |
1327 | struct drx397xD_state *s = fe->demodulator_priv; | 1329 | struct drx397xD_state *s = fe->demodulator_priv; |
1328 | 1330 | ||
1329 | s->config.s20d24 = 1; // 0; | 1331 | s->config.s20d24 = 1; |
1332 | |||
1330 | return drx_tune(s, params); | 1333 | return drx_tune(s, params); |
1331 | } | 1334 | } |
1332 | 1335 | ||
@@ -1337,18 +1340,16 @@ static int drx397x_get_tune_settings(struct dvb_frontend *fe, | |||
1337 | fe_tune_settings->min_delay_ms = 10000; | 1340 | fe_tune_settings->min_delay_ms = 10000; |
1338 | fe_tune_settings->step_size = 0; | 1341 | fe_tune_settings->step_size = 0; |
1339 | fe_tune_settings->max_drift = 0; | 1342 | fe_tune_settings->max_drift = 0; |
1343 | |||
1340 | return 0; | 1344 | return 0; |
1341 | } | 1345 | } |
1342 | 1346 | ||
1343 | static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) | 1347 | static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status) |
1344 | { | 1348 | { |
1345 | struct drx397xD_state *s = fe->demodulator_priv; | 1349 | struct drx397xD_state *s = fe->demodulator_priv; |
1346 | int lockstat; | 1350 | int lockstat; |
1347 | 1351 | ||
1348 | GetLockStatus(s, &lockstat); | 1352 | GetLockStatus(s, &lockstat); |
1349 | /* TODO */ | ||
1350 | // if (lockstat & 1) | ||
1351 | // CorrectSysClockDeviation(s); | ||
1352 | 1353 | ||
1353 | *status = 0; | 1354 | *status = 0; |
1354 | if (lockstat & 2) { | 1355 | if (lockstat & 2) { |
@@ -1356,9 +1357,8 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) | |||
1356 | ConfigureMPEGOutput(s, 1); | 1357 | ConfigureMPEGOutput(s, 1); |
1357 | *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; | 1358 | *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; |
1358 | } | 1359 | } |
1359 | if (lockstat & 4) { | 1360 | if (lockstat & 4) |
1360 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; | 1361 | *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; |
1361 | } | ||
1362 | 1362 | ||
1363 | return 0; | 1363 | return 0; |
1364 | } | 1364 | } |
@@ -1366,16 +1366,18 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) | |||
1366 | static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) | 1366 | static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) |
1367 | { | 1367 | { |
1368 | *ber = 0; | 1368 | *ber = 0; |
1369 | |||
1369 | return 0; | 1370 | return 0; |
1370 | } | 1371 | } |
1371 | 1372 | ||
1372 | static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr) | 1373 | static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr) |
1373 | { | 1374 | { |
1374 | *snr = 0; | 1375 | *snr = 0; |
1376 | |||
1375 | return 0; | 1377 | return 0; |
1376 | } | 1378 | } |
1377 | 1379 | ||
1378 | static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | 1380 | static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
1379 | { | 1381 | { |
1380 | struct drx397xD_state *s = fe->demodulator_priv; | 1382 | struct drx397xD_state *s = fe->demodulator_priv; |
1381 | int rc; | 1383 | int rc; |
@@ -1401,6 +1403,7 @@ static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | |||
1401 | * The following does the same but with less rounding errors: | 1403 | * The following does the same but with less rounding errors: |
1402 | */ | 1404 | */ |
1403 | *strength = ~(7720 + (rc * 30744 >> 10)); | 1405 | *strength = ~(7720 + (rc * 30744 >> 10)); |
1406 | |||
1404 | return 0; | 1407 | return 0; |
1405 | } | 1408 | } |
1406 | 1409 | ||
@@ -1408,6 +1411,7 @@ static int drx397x_read_ucblocks(struct dvb_frontend *fe, | |||
1408 | unsigned int *ucblocks) | 1411 | unsigned int *ucblocks) |
1409 | { | 1412 | { |
1410 | *ucblocks = 0; | 1413 | *ucblocks = 0; |
1414 | |||
1411 | return 0; | 1415 | return 0; |
1412 | } | 1416 | } |
1413 | 1417 | ||
@@ -1436,22 +1440,22 @@ static struct dvb_frontend_ops drx397x_ops = { | |||
1436 | .frequency_max = 855250000, | 1440 | .frequency_max = 855250000, |
1437 | .frequency_stepsize = 166667, | 1441 | .frequency_stepsize = 166667, |
1438 | .frequency_tolerance = 0, | 1442 | .frequency_tolerance = 0, |
1439 | .caps = /* 0x0C01B2EAE */ | 1443 | .caps = /* 0x0C01B2EAE */ |
1440 | FE_CAN_FEC_1_2 | // = 0x2, | 1444 | FE_CAN_FEC_1_2 | /* = 0x2, */ |
1441 | FE_CAN_FEC_2_3 | // = 0x4, | 1445 | FE_CAN_FEC_2_3 | /* = 0x4, */ |
1442 | FE_CAN_FEC_3_4 | // = 0x8, | 1446 | FE_CAN_FEC_3_4 | /* = 0x8, */ |
1443 | FE_CAN_FEC_5_6 | // = 0x20, | 1447 | FE_CAN_FEC_5_6 | /* = 0x20, */ |
1444 | FE_CAN_FEC_7_8 | // = 0x80, | 1448 | FE_CAN_FEC_7_8 | /* = 0x80, */ |
1445 | FE_CAN_FEC_AUTO | // = 0x200, | 1449 | FE_CAN_FEC_AUTO | /* = 0x200, */ |
1446 | FE_CAN_QPSK | // = 0x400, | 1450 | FE_CAN_QPSK | /* = 0x400, */ |
1447 | FE_CAN_QAM_16 | // = 0x800, | 1451 | FE_CAN_QAM_16 | /* = 0x800, */ |
1448 | FE_CAN_QAM_64 | // = 0x2000, | 1452 | FE_CAN_QAM_64 | /* = 0x2000, */ |
1449 | FE_CAN_QAM_AUTO | // = 0x10000, | 1453 | FE_CAN_QAM_AUTO | /* = 0x10000, */ |
1450 | FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000, | 1454 | FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */ |
1451 | FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000, | 1455 | FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */ |
1452 | FE_CAN_HIERARCHY_AUTO | // = 0x100000, | 1456 | FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */ |
1453 | FE_CAN_RECOVER | // = 0x40000000, | 1457 | FE_CAN_RECOVER | /* = 0x40000000, */ |
1454 | FE_CAN_MUTE_TS // = 0x80000000 | 1458 | FE_CAN_MUTE_TS /* = 0x80000000 */ |
1455 | }, | 1459 | }, |
1456 | 1460 | ||
1457 | .release = drx397x_release, | 1461 | .release = drx397x_release, |
@@ -1472,33 +1476,35 @@ static struct dvb_frontend_ops drx397x_ops = { | |||
1472 | struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, | 1476 | struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, |
1473 | struct i2c_adapter *i2c) | 1477 | struct i2c_adapter *i2c) |
1474 | { | 1478 | { |
1475 | struct drx397xD_state *s = NULL; | 1479 | struct drx397xD_state *state; |
1476 | 1480 | ||
1477 | /* allocate memory for the internal state */ | 1481 | /* allocate memory for the internal state */ |
1478 | s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); | 1482 | state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); |
1479 | if (s == NULL) | 1483 | if (!state) |
1480 | goto error; | 1484 | goto error; |
1481 | 1485 | ||
1482 | /* setup the state */ | 1486 | /* setup the state */ |
1483 | s->i2c = i2c; | 1487 | state->i2c = i2c; |
1484 | memcpy(&s->config, config, sizeof(struct drx397xD_config)); | 1488 | memcpy(&state->config, config, sizeof(struct drx397xD_config)); |
1485 | 1489 | ||
1486 | /* check if the demod is there */ | 1490 | /* check if the demod is there */ |
1487 | if (RD16(s, 0x2410019) < 0) | 1491 | if (RD16(state, 0x2410019) < 0) |
1488 | goto error; | 1492 | goto error; |
1489 | 1493 | ||
1490 | /* create dvb_frontend */ | 1494 | /* create dvb_frontend */ |
1491 | memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); | 1495 | memcpy(&state->frontend.ops, &drx397x_ops, |
1492 | s->frontend.demodulator_priv = s; | 1496 | sizeof(struct dvb_frontend_ops)); |
1497 | state->frontend.demodulator_priv = state; | ||
1498 | |||
1499 | return &state->frontend; | ||
1500 | error: | ||
1501 | kfree(state); | ||
1493 | 1502 | ||
1494 | return &s->frontend; | ||
1495 | error: | ||
1496 | kfree(s); | ||
1497 | return NULL; | 1503 | return NULL; |
1498 | } | 1504 | } |
1505 | EXPORT_SYMBOL(drx397xD_attach); | ||
1499 | 1506 | ||
1500 | MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); | 1507 | MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); |
1501 | MODULE_AUTHOR("Henk Vergonet"); | 1508 | MODULE_AUTHOR("Henk Vergonet"); |
1502 | MODULE_LICENSE("GPL"); | 1509 | MODULE_LICENSE("GPL"); |
1503 | 1510 | ||
1504 | EXPORT_SYMBOL(drx397xD_attach); | ||
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h index ddc7a07971b7..ba05d17290c6 100644 --- a/drivers/media/dvb/frontends/drx397xD.h +++ b/drivers/media/dvb/frontends/drx397xD.h | |||
@@ -28,7 +28,7 @@ | |||
28 | #define DRX_F_OFFSET 36000000 | 28 | #define DRX_F_OFFSET 36000000 |
29 | 29 | ||
30 | #define I2C_ADR_C0(x) \ | 30 | #define I2C_ADR_C0(x) \ |
31 | ( (u32)cpu_to_le32( \ | 31 | ( cpu_to_le32( \ |
32 | (u32)( \ | 32 | (u32)( \ |
33 | (((u32)(x) & (u32)0x000000ffUL) ) | \ | 33 | (((u32)(x) & (u32)0x000000ffUL) ) | \ |
34 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ | 34 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ |
@@ -38,7 +38,7 @@ | |||
38 | ) | 38 | ) |
39 | 39 | ||
40 | #define I2C_ADR_E0(x) \ | 40 | #define I2C_ADR_E0(x) \ |
41 | ( (u32)cpu_to_le32( \ | 41 | ( cpu_to_le32( \ |
42 | (u32)( \ | 42 | (u32)( \ |
43 | (((u32)(x) & (u32)0x000000ffUL) ) | \ | 43 | (((u32)(x) & (u32)0x000000ffUL) ) | \ |
44 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ | 44 | (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ |
@@ -122,7 +122,7 @@ extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config | |||
122 | static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, | 122 | static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, |
123 | struct i2c_adapter *i2c) | 123 | struct i2c_adapter *i2c) |
124 | { | 124 | { |
125 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | 125 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
126 | return NULL; | 126 | return NULL; |
127 | } | 127 | } |
128 | #endif /* CONFIG_DVB_DRX397XD */ | 128 | #endif /* CONFIG_DVB_DRX397XD */ |
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index fed09dfb2b7c..db8a937cc630 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c | |||
@@ -75,9 +75,10 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten | |||
75 | 75 | ||
76 | static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | 76 | static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) |
77 | { | 77 | { |
78 | if (fe->ops->tuner_ops->set_params) { | 78 | if (fe->ops.tuner_ops.set_params) { |
79 | fe->ops->tuner_ops->set_params(fe, p); | 79 | fe->ops.tuner_ops.set_params(fe, p); |
80 | if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0); | 80 | if (fe->ops.i2c_gate_ctrl) |
81 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
81 | } | 82 | } |
82 | 83 | ||
83 | return 0; | 84 | return 0; |
@@ -131,7 +132,7 @@ error: | |||
131 | 132 | ||
132 | static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; | 133 | static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; |
133 | 134 | ||
134 | struct dvb_frontend* dvb_dummy_fe_qpsk_attach() | 135 | struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) |
135 | { | 136 | { |
136 | struct dvb_dummy_fe_state* state = NULL; | 137 | struct dvb_dummy_fe_state* state = NULL; |
137 | 138 | ||
@@ -151,7 +152,7 @@ error: | |||
151 | 152 | ||
152 | static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; | 153 | static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; |
153 | 154 | ||
154 | struct dvb_frontend* dvb_dummy_fe_qam_attach() | 155 | struct dvb_frontend *dvb_dummy_fe_qam_attach(void) |
155 | { | 156 | { |
156 | struct dvb_dummy_fe_state* state = NULL; | 157 | struct dvb_dummy_fe_state* state = NULL; |
157 | 158 | ||
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h new file mode 100644 index 000000000000..fa79b7c83dd2 --- /dev/null +++ b/drivers/media/dvb/frontends/eds1547.h | |||
@@ -0,0 +1,133 @@ | |||
1 | /* eds1547.h Earda EDS-1547 tuner support | ||
2 | * | ||
3 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation, version 2. | ||
8 | * | ||
9 | * see Documentation/dvb/README.dvb-usb for more information | ||
10 | */ | ||
11 | |||
12 | #ifndef EDS1547 | ||
13 | #define EDS1547 | ||
14 | |||
15 | static u8 stv0288_earda_inittab[] = { | ||
16 | 0x01, 0x57, | ||
17 | 0x02, 0x20, | ||
18 | 0x03, 0x8e, | ||
19 | 0x04, 0x8e, | ||
20 | 0x05, 0x12, | ||
21 | 0x06, 0x00, | ||
22 | 0x07, 0x00, | ||
23 | 0x09, 0x00, | ||
24 | 0x0a, 0x04, | ||
25 | 0x0b, 0x00, | ||
26 | 0x0c, 0x00, | ||
27 | 0x0d, 0x00, | ||
28 | 0x0e, 0xd4, | ||
29 | 0x0f, 0x30, | ||
30 | 0x11, 0x44, | ||
31 | 0x12, 0x03, | ||
32 | 0x13, 0x48, | ||
33 | 0x14, 0x84, | ||
34 | 0x15, 0x45, | ||
35 | 0x16, 0xb7, | ||
36 | 0x17, 0x9c, | ||
37 | 0x18, 0x00, | ||
38 | 0x19, 0xa6, | ||
39 | 0x1a, 0x88, | ||
40 | 0x1b, 0x8f, | ||
41 | 0x1c, 0xf0, | ||
42 | 0x20, 0x0b, | ||
43 | 0x21, 0x54, | ||
44 | 0x22, 0x00, | ||
45 | 0x23, 0x00, | ||
46 | 0x2b, 0xff, | ||
47 | 0x2c, 0xf7, | ||
48 | 0x30, 0x00, | ||
49 | 0x31, 0x1e, | ||
50 | 0x32, 0x14, | ||
51 | 0x33, 0x0f, | ||
52 | 0x34, 0x09, | ||
53 | 0x35, 0x0c, | ||
54 | 0x36, 0x05, | ||
55 | 0x37, 0x2f, | ||
56 | 0x38, 0x16, | ||
57 | 0x39, 0xbd, | ||
58 | 0x3a, 0x00, | ||
59 | 0x3b, 0x13, | ||
60 | 0x3c, 0x11, | ||
61 | 0x3d, 0x30, | ||
62 | 0x40, 0x63, | ||
63 | 0x41, 0x04, | ||
64 | 0x42, 0x60, | ||
65 | 0x43, 0x00, | ||
66 | 0x44, 0x00, | ||
67 | 0x45, 0x00, | ||
68 | 0x46, 0x00, | ||
69 | 0x47, 0x00, | ||
70 | 0x4a, 0x00, | ||
71 | 0x50, 0x10, | ||
72 | 0x51, 0x36, | ||
73 | 0x52, 0x09, | ||
74 | 0x53, 0x94, | ||
75 | 0x54, 0x62, | ||
76 | 0x55, 0x29, | ||
77 | 0x56, 0x64, | ||
78 | 0x57, 0x2b, | ||
79 | 0x58, 0x54, | ||
80 | 0x59, 0x86, | ||
81 | 0x5a, 0x00, | ||
82 | 0x5b, 0x9b, | ||
83 | 0x5c, 0x08, | ||
84 | 0x5d, 0x7f, | ||
85 | 0x5e, 0x00, | ||
86 | 0x5f, 0xff, | ||
87 | 0x70, 0x00, | ||
88 | 0x71, 0x00, | ||
89 | 0x72, 0x00, | ||
90 | 0x74, 0x00, | ||
91 | 0x75, 0x00, | ||
92 | 0x76, 0x00, | ||
93 | 0x81, 0x00, | ||
94 | 0x82, 0x3f, | ||
95 | 0x83, 0x3f, | ||
96 | 0x84, 0x00, | ||
97 | 0x85, 0x00, | ||
98 | 0x88, 0x00, | ||
99 | 0x89, 0x00, | ||
100 | 0x8a, 0x00, | ||
101 | 0x8b, 0x00, | ||
102 | 0x8c, 0x00, | ||
103 | 0x90, 0x00, | ||
104 | 0x91, 0x00, | ||
105 | 0x92, 0x00, | ||
106 | 0x93, 0x00, | ||
107 | 0x94, 0x1c, | ||
108 | 0x97, 0x00, | ||
109 | 0xa0, 0x48, | ||
110 | 0xa1, 0x00, | ||
111 | 0xb0, 0xb8, | ||
112 | 0xb1, 0x3a, | ||
113 | 0xb2, 0x10, | ||
114 | 0xb3, 0x82, | ||
115 | 0xb4, 0x80, | ||
116 | 0xb5, 0x82, | ||
117 | 0xb6, 0x82, | ||
118 | 0xb7, 0x82, | ||
119 | 0xb8, 0x20, | ||
120 | 0xb9, 0x00, | ||
121 | 0xf0, 0x00, | ||
122 | 0xf1, 0x00, | ||
123 | 0xf2, 0xc0, | ||
124 | 0xff,0xff, | ||
125 | }; | ||
126 | |||
127 | static struct stv0288_config earda_config = { | ||
128 | .demod_address = 0x68, | ||
129 | .min_delay_ms = 100, | ||
130 | .inittab = stv0288_earda_inittab, | ||
131 | }; | ||
132 | |||
133 | #endif | ||
diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c new file mode 100644 index 000000000000..855852fddf22 --- /dev/null +++ b/drivers/media/dvb/frontends/lgs8gl5.c | |||
@@ -0,0 +1,454 @@ | |||
1 | /* | ||
2 | Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver | ||
3 | |||
4 | Copyright (C) 2008 Sirius International (Hong Kong) Limited | ||
5 | Timothy Lee <timothy.lee@siriushk.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | #include "lgs8gl5.h" | ||
30 | |||
31 | |||
32 | #define REG_RESET 0x02 | ||
33 | #define REG_RESET_OFF 0x01 | ||
34 | #define REG_03 0x03 | ||
35 | #define REG_04 0x04 | ||
36 | #define REG_07 0x07 | ||
37 | #define REG_09 0x09 | ||
38 | #define REG_0A 0x0a | ||
39 | #define REG_0B 0x0b | ||
40 | #define REG_0C 0x0c | ||
41 | #define REG_37 0x37 | ||
42 | #define REG_STRENGTH 0x4b | ||
43 | #define REG_STRENGTH_MASK 0x7f | ||
44 | #define REG_STRENGTH_CARRIER 0x80 | ||
45 | #define REG_INVERSION 0x7c | ||
46 | #define REG_INVERSION_ON 0x80 | ||
47 | #define REG_7D 0x7d | ||
48 | #define REG_7E 0x7e | ||
49 | #define REG_A2 0xa2 | ||
50 | #define REG_STATUS 0xa4 | ||
51 | #define REG_STATUS_SYNC 0x04 | ||
52 | #define REG_STATUS_LOCK 0x01 | ||
53 | |||
54 | |||
55 | struct lgs8gl5_state { | ||
56 | struct i2c_adapter *i2c; | ||
57 | const struct lgs8gl5_config *config; | ||
58 | struct dvb_frontend frontend; | ||
59 | }; | ||
60 | |||
61 | |||
62 | static int debug; | ||
63 | #define dprintk(args...) \ | ||
64 | do { \ | ||
65 | if (debug) \ | ||
66 | printk(KERN_DEBUG "lgs8gl5: " args); \ | ||
67 | } while (0) | ||
68 | |||
69 | |||
70 | /* Writes into demod's register */ | ||
71 | static int | ||
72 | lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) | ||
73 | { | ||
74 | int ret; | ||
75 | u8 buf[] = {reg, data}; | ||
76 | struct i2c_msg msg = { | ||
77 | .addr = state->config->demod_address, | ||
78 | .flags = 0, | ||
79 | .buf = buf, | ||
80 | .len = 2 | ||
81 | }; | ||
82 | |||
83 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
84 | if (ret != 1) | ||
85 | dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", | ||
86 | __func__, reg, data, ret); | ||
87 | return (ret != 1) ? -1 : 0; | ||
88 | } | ||
89 | |||
90 | |||
91 | /* Reads from demod's register */ | ||
92 | static int | ||
93 | lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) | ||
94 | { | ||
95 | int ret; | ||
96 | u8 b0[] = {reg}; | ||
97 | u8 b1[] = {0}; | ||
98 | struct i2c_msg msg[2] = { | ||
99 | { | ||
100 | .addr = state->config->demod_address, | ||
101 | .flags = 0, | ||
102 | .buf = b0, | ||
103 | .len = 1 | ||
104 | }, | ||
105 | { | ||
106 | .addr = state->config->demod_address, | ||
107 | .flags = I2C_M_RD, | ||
108 | .buf = b1, | ||
109 | .len = 1 | ||
110 | } | ||
111 | }; | ||
112 | |||
113 | ret = i2c_transfer(state->i2c, msg, 2); | ||
114 | if (ret != 2) | ||
115 | return -EIO; | ||
116 | |||
117 | return b1[0]; | ||
118 | } | ||
119 | |||
120 | |||
121 | static int | ||
122 | lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) | ||
123 | { | ||
124 | lgs8gl5_read_reg(state, reg); | ||
125 | lgs8gl5_write_reg(state, reg, data); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | |||
130 | /* Writes into alternate device's register */ | ||
131 | /* TODO: Find out what that device is for! */ | ||
132 | static int | ||
133 | lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) | ||
134 | { | ||
135 | int ret; | ||
136 | u8 b0[] = {reg}; | ||
137 | u8 b1[] = {0}; | ||
138 | u8 b2[] = {reg, data}; | ||
139 | struct i2c_msg msg[3] = { | ||
140 | { | ||
141 | .addr = state->config->demod_address + 2, | ||
142 | .flags = 0, | ||
143 | .buf = b0, | ||
144 | .len = 1 | ||
145 | }, | ||
146 | { | ||
147 | .addr = state->config->demod_address + 2, | ||
148 | .flags = I2C_M_RD, | ||
149 | .buf = b1, | ||
150 | .len = 1 | ||
151 | }, | ||
152 | { | ||
153 | .addr = state->config->demod_address + 2, | ||
154 | .flags = 0, | ||
155 | .buf = b2, | ||
156 | .len = 2 | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | ret = i2c_transfer(state->i2c, msg, 3); | ||
161 | return (ret != 3) ? -1 : 0; | ||
162 | } | ||
163 | |||
164 | |||
165 | static void | ||
166 | lgs8gl5_soft_reset(struct lgs8gl5_state *state) | ||
167 | { | ||
168 | u8 val; | ||
169 | |||
170 | dprintk("%s\n", __func__); | ||
171 | |||
172 | val = lgs8gl5_read_reg(state, REG_RESET); | ||
173 | lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); | ||
174 | lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); | ||
175 | msleep(5); | ||
176 | } | ||
177 | |||
178 | |||
179 | /* Starts demodulation */ | ||
180 | static void | ||
181 | lgs8gl5_start_demod(struct lgs8gl5_state *state) | ||
182 | { | ||
183 | u8 val; | ||
184 | int n; | ||
185 | |||
186 | dprintk("%s\n", __func__); | ||
187 | |||
188 | lgs8gl5_update_alt_reg(state, 0xc2, 0x28); | ||
189 | lgs8gl5_soft_reset(state); | ||
190 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
191 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
192 | lgs8gl5_write_reg(state, REG_09, 0x0e); | ||
193 | lgs8gl5_write_reg(state, REG_0A, 0xe5); | ||
194 | lgs8gl5_write_reg(state, REG_0B, 0x35); | ||
195 | lgs8gl5_write_reg(state, REG_0C, 0x30); | ||
196 | |||
197 | lgs8gl5_update_reg(state, REG_03, 0x00); | ||
198 | lgs8gl5_update_reg(state, REG_7E, 0x01); | ||
199 | lgs8gl5_update_alt_reg(state, 0xc5, 0x00); | ||
200 | lgs8gl5_update_reg(state, REG_04, 0x02); | ||
201 | lgs8gl5_update_reg(state, REG_37, 0x01); | ||
202 | lgs8gl5_soft_reset(state); | ||
203 | |||
204 | /* Wait for carrier */ | ||
205 | for (n = 0; n < 10; n++) { | ||
206 | val = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
207 | dprintk("Wait for carrier[%d] 0x%02X\n", n, val); | ||
208 | if (val & REG_STRENGTH_CARRIER) | ||
209 | break; | ||
210 | msleep(4); | ||
211 | } | ||
212 | if (!(val & REG_STRENGTH_CARRIER)) | ||
213 | return; | ||
214 | |||
215 | /* Wait for lock */ | ||
216 | for (n = 0; n < 20; n++) { | ||
217 | val = lgs8gl5_read_reg(state, REG_STATUS); | ||
218 | dprintk("Wait for lock[%d] 0x%02X\n", n, val); | ||
219 | if (val & REG_STATUS_LOCK) | ||
220 | break; | ||
221 | msleep(12); | ||
222 | } | ||
223 | if (!(val & REG_STATUS_LOCK)) | ||
224 | return; | ||
225 | |||
226 | lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); | ||
227 | lgs8gl5_soft_reset(state); | ||
228 | } | ||
229 | |||
230 | |||
231 | static int | ||
232 | lgs8gl5_init(struct dvb_frontend *fe) | ||
233 | { | ||
234 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
235 | |||
236 | dprintk("%s\n", __func__); | ||
237 | |||
238 | lgs8gl5_update_alt_reg(state, 0xc2, 0x28); | ||
239 | lgs8gl5_soft_reset(state); | ||
240 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
241 | lgs8gl5_update_reg(state, REG_07, 0x10); | ||
242 | lgs8gl5_write_reg(state, REG_09, 0x0e); | ||
243 | lgs8gl5_write_reg(state, REG_0A, 0xe5); | ||
244 | lgs8gl5_write_reg(state, REG_0B, 0x35); | ||
245 | lgs8gl5_write_reg(state, REG_0C, 0x30); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | |||
251 | static int | ||
252 | lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
253 | { | ||
254 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
255 | u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
256 | u8 flags = lgs8gl5_read_reg(state, REG_STATUS); | ||
257 | |||
258 | *status = 0; | ||
259 | |||
260 | if ((level & REG_STRENGTH_MASK) > 0) | ||
261 | *status |= FE_HAS_SIGNAL; | ||
262 | if (level & REG_STRENGTH_CARRIER) | ||
263 | *status |= FE_HAS_CARRIER; | ||
264 | if (flags & REG_STATUS_SYNC) | ||
265 | *status |= FE_HAS_SYNC; | ||
266 | if (flags & REG_STATUS_LOCK) | ||
267 | *status |= FE_HAS_LOCK; | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | |||
273 | static int | ||
274 | lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
275 | { | ||
276 | *ber = 0; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | |||
282 | static int | ||
283 | lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) | ||
284 | { | ||
285 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
286 | u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
287 | *signal_strength = (level & REG_STRENGTH_MASK) << 8; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | |||
293 | static int | ||
294 | lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
295 | { | ||
296 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
297 | u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); | ||
298 | *snr = (level & REG_STRENGTH_MASK) << 8; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | |||
304 | static int | ||
305 | lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
306 | { | ||
307 | *ucblocks = 0; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | |||
313 | static int | ||
314 | lgs8gl5_set_frontend(struct dvb_frontend *fe, | ||
315 | struct dvb_frontend_parameters *p) | ||
316 | { | ||
317 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
318 | |||
319 | dprintk("%s\n", __func__); | ||
320 | |||
321 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) | ||
322 | return -EINVAL; | ||
323 | |||
324 | if (fe->ops.tuner_ops.set_params) { | ||
325 | fe->ops.tuner_ops.set_params(fe, p); | ||
326 | if (fe->ops.i2c_gate_ctrl) | ||
327 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
328 | } | ||
329 | |||
330 | /* lgs8gl5_set_inversion(state, p->inversion); */ | ||
331 | |||
332 | lgs8gl5_start_demod(state); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | |||
338 | static int | ||
339 | lgs8gl5_get_frontend(struct dvb_frontend *fe, | ||
340 | struct dvb_frontend_parameters *p) | ||
341 | { | ||
342 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
343 | u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); | ||
344 | struct dvb_ofdm_parameters *o = &p->u.ofdm; | ||
345 | |||
346 | p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; | ||
347 | |||
348 | o->code_rate_HP = FEC_1_2; | ||
349 | o->code_rate_LP = FEC_7_8; | ||
350 | o->guard_interval = GUARD_INTERVAL_1_32; | ||
351 | o->transmission_mode = TRANSMISSION_MODE_2K; | ||
352 | o->constellation = QAM_64; | ||
353 | o->hierarchy_information = HIERARCHY_NONE; | ||
354 | o->bandwidth = BANDWIDTH_8_MHZ; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | |||
360 | static int | ||
361 | lgs8gl5_get_tune_settings(struct dvb_frontend *fe, | ||
362 | struct dvb_frontend_tune_settings *fesettings) | ||
363 | { | ||
364 | fesettings->min_delay_ms = 240; | ||
365 | fesettings->step_size = 0; | ||
366 | fesettings->max_drift = 0; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | |||
371 | static void | ||
372 | lgs8gl5_release(struct dvb_frontend *fe) | ||
373 | { | ||
374 | struct lgs8gl5_state *state = fe->demodulator_priv; | ||
375 | kfree(state); | ||
376 | } | ||
377 | |||
378 | |||
379 | static struct dvb_frontend_ops lgs8gl5_ops; | ||
380 | |||
381 | |||
382 | struct dvb_frontend* | ||
383 | lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) | ||
384 | { | ||
385 | struct lgs8gl5_state *state = NULL; | ||
386 | |||
387 | dprintk("%s\n", __func__); | ||
388 | |||
389 | /* Allocate memory for the internal state */ | ||
390 | state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); | ||
391 | if (state == NULL) | ||
392 | goto error; | ||
393 | |||
394 | /* Setup the state */ | ||
395 | state->config = config; | ||
396 | state->i2c = i2c; | ||
397 | |||
398 | /* Check if the demod is there */ | ||
399 | if (lgs8gl5_read_reg(state, REG_RESET) < 0) | ||
400 | goto error; | ||
401 | |||
402 | /* Create dvb_frontend */ | ||
403 | memcpy(&state->frontend.ops, &lgs8gl5_ops, | ||
404 | sizeof(struct dvb_frontend_ops)); | ||
405 | state->frontend.demodulator_priv = state; | ||
406 | return &state->frontend; | ||
407 | |||
408 | error: | ||
409 | kfree(state); | ||
410 | return NULL; | ||
411 | } | ||
412 | EXPORT_SYMBOL(lgs8gl5_attach); | ||
413 | |||
414 | |||
415 | static struct dvb_frontend_ops lgs8gl5_ops = { | ||
416 | .info = { | ||
417 | .name = "Legend Silicon LGS-8GL5 DMB-TH", | ||
418 | .type = FE_OFDM, | ||
419 | .frequency_min = 474000000, | ||
420 | .frequency_max = 858000000, | ||
421 | .frequency_stepsize = 10000, | ||
422 | .frequency_tolerance = 0, | ||
423 | .caps = FE_CAN_FEC_AUTO | | ||
424 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | | ||
425 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
426 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
427 | FE_CAN_BANDWIDTH_AUTO | | ||
428 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
429 | FE_CAN_HIERARCHY_AUTO | | ||
430 | FE_CAN_RECOVER | ||
431 | }, | ||
432 | |||
433 | .release = lgs8gl5_release, | ||
434 | |||
435 | .init = lgs8gl5_init, | ||
436 | |||
437 | .set_frontend = lgs8gl5_set_frontend, | ||
438 | .get_frontend = lgs8gl5_get_frontend, | ||
439 | .get_tune_settings = lgs8gl5_get_tune_settings, | ||
440 | |||
441 | .read_status = lgs8gl5_read_status, | ||
442 | .read_ber = lgs8gl5_read_ber, | ||
443 | .read_signal_strength = lgs8gl5_read_signal_strength, | ||
444 | .read_snr = lgs8gl5_read_snr, | ||
445 | .read_ucblocks = lgs8gl5_read_ucblocks, | ||
446 | }; | ||
447 | |||
448 | |||
449 | module_param(debug, int, 0644); | ||
450 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
451 | |||
452 | MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); | ||
453 | MODULE_AUTHOR("Timothy Lee"); | ||
454 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb/frontends/lgs8gl5.h new file mode 100644 index 000000000000..d14176787a7d --- /dev/null +++ b/drivers/media/dvb/frontends/lgs8gl5.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver | ||
3 | |||
4 | Copyright (C) 2008 Sirius International (Hong Kong) Limited | ||
5 | Timothy Lee <timothy.lee@siriushk.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef LGS8GL5_H | ||
24 | #define LGS8GL5_H | ||
25 | |||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | struct lgs8gl5_config { | ||
29 | /* the demodulator's i2c address */ | ||
30 | u8 demod_address; | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_DVB_LGS8GL5) || \ | ||
34 | (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) | ||
35 | extern struct dvb_frontend *lgs8gl5_attach( | ||
36 | const struct lgs8gl5_config *config, struct i2c_adapter *i2c); | ||
37 | #else | ||
38 | static inline struct dvb_frontend *lgs8gl5_attach( | ||
39 | const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { | ||
40 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
41 | return NULL; | ||
42 | } | ||
43 | #endif /* CONFIG_DVB_LGS8GL5 */ | ||
44 | |||
45 | #endif /* LGS8GL5_H */ | ||
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index af298358e822..a8429ebfa8a2 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c | |||
@@ -80,7 +80,7 @@ static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len) | 83 | static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) |
84 | { | 84 | { |
85 | int err; | 85 | int err; |
86 | struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; | 86 | 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, | |||
111 | return 0; | 111 | return 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len) | 114 | static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) |
115 | { | 115 | { |
116 | u8 reg2 [] = { reg }; | 116 | u8 reg2 [] = { reg }; |
117 | 117 | ||
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 6afe12aaca4e..16cf2fdd5d7d 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c | |||
@@ -88,7 +88,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf, | |||
88 | return 0; | 88 | return 0; |
89 | } | 89 | } |
90 | 90 | ||
91 | static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len) | 91 | static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len) |
92 | { | 92 | { |
93 | int err; | 93 | int err; |
94 | struct i2c_msg msg; | 94 | struct i2c_msg msg; |
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c new file mode 100644 index 000000000000..3ddbe69c45ce --- /dev/null +++ b/drivers/media/dvb/frontends/si21xx.c | |||
@@ -0,0 +1,974 @@ | |||
1 | /* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator | ||
2 | * | ||
3 | * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | */ | ||
11 | #include <linux/version.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/jiffies.h> | ||
18 | #include <asm/div64.h> | ||
19 | |||
20 | #include "dvb_frontend.h" | ||
21 | #include "si21xx.h" | ||
22 | |||
23 | #define REVISION_REG 0x00 | ||
24 | #define SYSTEM_MODE_REG 0x01 | ||
25 | #define TS_CTRL_REG_1 0x02 | ||
26 | #define TS_CTRL_REG_2 0x03 | ||
27 | #define PIN_CTRL_REG_1 0x04 | ||
28 | #define PIN_CTRL_REG_2 0x05 | ||
29 | #define LOCK_STATUS_REG_1 0x0f | ||
30 | #define LOCK_STATUS_REG_2 0x10 | ||
31 | #define ACQ_STATUS_REG 0x11 | ||
32 | #define ACQ_CTRL_REG_1 0x13 | ||
33 | #define ACQ_CTRL_REG_2 0x14 | ||
34 | #define PLL_DIVISOR_REG 0x15 | ||
35 | #define COARSE_TUNE_REG 0x16 | ||
36 | #define FINE_TUNE_REG_L 0x17 | ||
37 | #define FINE_TUNE_REG_H 0x18 | ||
38 | |||
39 | #define ANALOG_AGC_POWER_LEVEL_REG 0x28 | ||
40 | #define CFO_ESTIMATOR_CTRL_REG_1 0x29 | ||
41 | #define CFO_ESTIMATOR_CTRL_REG_2 0x2a | ||
42 | #define CFO_ESTIMATOR_CTRL_REG_3 0x2b | ||
43 | |||
44 | #define SYM_RATE_ESTIMATE_REG_L 0x31 | ||
45 | #define SYM_RATE_ESTIMATE_REG_M 0x32 | ||
46 | #define SYM_RATE_ESTIMATE_REG_H 0x33 | ||
47 | |||
48 | #define CFO_ESTIMATOR_OFFSET_REG_L 0x36 | ||
49 | #define CFO_ESTIMATOR_OFFSET_REG_H 0x37 | ||
50 | #define CFO_ERROR_REG_L 0x38 | ||
51 | #define CFO_ERROR_REG_H 0x39 | ||
52 | #define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a | ||
53 | |||
54 | #define SYM_RATE_REG_L 0x3f | ||
55 | #define SYM_RATE_REG_M 0x40 | ||
56 | #define SYM_RATE_REG_H 0x41 | ||
57 | #define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 | ||
58 | #define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 | ||
59 | |||
60 | #define C_N_ESTIMATOR_CTRL_REG 0x7c | ||
61 | #define C_N_ESTIMATOR_THRSHLD_REG 0x7d | ||
62 | #define C_N_ESTIMATOR_LEVEL_REG_L 0x7e | ||
63 | #define C_N_ESTIMATOR_LEVEL_REG_H 0x7f | ||
64 | |||
65 | #define BLIND_SCAN_CTRL_REG 0x80 | ||
66 | |||
67 | #define LSA_CTRL_REG_1 0x8D | ||
68 | #define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f | ||
69 | #define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 | ||
70 | #define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 | ||
71 | #define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 | ||
72 | #define INBAND_POWER_THRSHLD_REG 0x93 | ||
73 | #define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 | ||
74 | |||
75 | #define VIT_SRCH_CTRL_REG_1 0xa0 | ||
76 | #define VIT_SRCH_CTRL_REG_2 0xa1 | ||
77 | #define VIT_SRCH_CTRL_REG_3 0xa2 | ||
78 | #define VIT_SRCH_STATUS_REG 0xa3 | ||
79 | #define VITERBI_BER_COUNT_REG_L 0xab | ||
80 | #define REED_SOLOMON_CTRL_REG 0xb0 | ||
81 | #define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 | ||
82 | #define PRBS_CTRL_REG 0xb5 | ||
83 | |||
84 | #define LNB_CTRL_REG_1 0xc0 | ||
85 | #define LNB_CTRL_REG_2 0xc1 | ||
86 | #define LNB_CTRL_REG_3 0xc2 | ||
87 | #define LNB_CTRL_REG_4 0xc3 | ||
88 | #define LNB_CTRL_STATUS_REG 0xc4 | ||
89 | #define LNB_FIFO_REGS_0 0xc5 | ||
90 | #define LNB_FIFO_REGS_1 0xc6 | ||
91 | #define LNB_FIFO_REGS_2 0xc7 | ||
92 | #define LNB_FIFO_REGS_3 0xc8 | ||
93 | #define LNB_FIFO_REGS_4 0xc9 | ||
94 | #define LNB_FIFO_REGS_5 0xca | ||
95 | #define LNB_SUPPLY_CTRL_REG_1 0xcb | ||
96 | #define LNB_SUPPLY_CTRL_REG_2 0xcc | ||
97 | #define LNB_SUPPLY_CTRL_REG_3 0xcd | ||
98 | #define LNB_SUPPLY_CTRL_REG_4 0xce | ||
99 | #define LNB_SUPPLY_STATUS_REG 0xcf | ||
100 | |||
101 | #define FALSE 0 | ||
102 | #define TRUE 1 | ||
103 | #define FAIL -1 | ||
104 | #define PASS 0 | ||
105 | |||
106 | #define ALLOWABLE_FS_COUNT 10 | ||
107 | #define STATUS_BER 0 | ||
108 | #define STATUS_UCBLOCKS 1 | ||
109 | |||
110 | static int debug; | ||
111 | #define dprintk(args...) \ | ||
112 | do { \ | ||
113 | if (debug) \ | ||
114 | printk(KERN_DEBUG "si21xx: " args); \ | ||
115 | } while (0) | ||
116 | |||
117 | enum { | ||
118 | ACTIVE_HIGH, | ||
119 | ACTIVE_LOW | ||
120 | }; | ||
121 | enum { | ||
122 | BYTE_WIDE, | ||
123 | BIT_WIDE | ||
124 | }; | ||
125 | enum { | ||
126 | CLK_GAPPED_MODE, | ||
127 | CLK_CONTINUOUS_MODE | ||
128 | }; | ||
129 | enum { | ||
130 | RISING_EDGE, | ||
131 | FALLING_EDGE | ||
132 | }; | ||
133 | enum { | ||
134 | MSB_FIRST, | ||
135 | LSB_FIRST | ||
136 | }; | ||
137 | enum { | ||
138 | SERIAL, | ||
139 | PARALLEL | ||
140 | }; | ||
141 | |||
142 | struct si21xx_state { | ||
143 | struct i2c_adapter *i2c; | ||
144 | const struct si21xx_config *config; | ||
145 | struct dvb_frontend frontend; | ||
146 | u8 initialised:1; | ||
147 | int errmode; | ||
148 | int fs; /*Sampling rate of the ADC in MHz*/ | ||
149 | }; | ||
150 | |||
151 | /* register default initialization */ | ||
152 | static u8 serit_sp1511lhb_inittab[] = { | ||
153 | 0x01, 0x28, /* set i2c_inc_disable */ | ||
154 | 0x20, 0x03, | ||
155 | 0x27, 0x20, | ||
156 | 0xe0, 0x45, | ||
157 | 0xe1, 0x08, | ||
158 | 0xfe, 0x01, | ||
159 | 0x01, 0x28, | ||
160 | 0x89, 0x09, | ||
161 | 0x04, 0x80, | ||
162 | 0x05, 0x01, | ||
163 | 0x06, 0x00, | ||
164 | 0x20, 0x03, | ||
165 | 0x24, 0x88, | ||
166 | 0x29, 0x09, | ||
167 | 0x2a, 0x0f, | ||
168 | 0x2c, 0x10, | ||
169 | 0x2d, 0x19, | ||
170 | 0x2e, 0x08, | ||
171 | 0x2f, 0x10, | ||
172 | 0x30, 0x19, | ||
173 | 0x34, 0x20, | ||
174 | 0x35, 0x03, | ||
175 | 0x45, 0x02, | ||
176 | 0x46, 0x45, | ||
177 | 0x47, 0xd0, | ||
178 | 0x48, 0x00, | ||
179 | 0x49, 0x40, | ||
180 | 0x4a, 0x03, | ||
181 | 0x4c, 0xfd, | ||
182 | 0x4f, 0x2e, | ||
183 | 0x50, 0x2e, | ||
184 | 0x51, 0x10, | ||
185 | 0x52, 0x10, | ||
186 | 0x56, 0x92, | ||
187 | 0x59, 0x00, | ||
188 | 0x5a, 0x2d, | ||
189 | 0x5b, 0x33, | ||
190 | 0x5c, 0x1f, | ||
191 | 0x5f, 0x76, | ||
192 | 0x62, 0xc0, | ||
193 | 0x63, 0xc0, | ||
194 | 0x64, 0xf3, | ||
195 | 0x65, 0xf3, | ||
196 | 0x79, 0x40, | ||
197 | 0x6a, 0x40, | ||
198 | 0x6b, 0x0a, | ||
199 | 0x6c, 0x80, | ||
200 | 0x6d, 0x27, | ||
201 | 0x71, 0x06, | ||
202 | 0x75, 0x60, | ||
203 | 0x78, 0x00, | ||
204 | 0x79, 0xb5, | ||
205 | 0x7c, 0x05, | ||
206 | 0x7d, 0x1a, | ||
207 | 0x87, 0x55, | ||
208 | 0x88, 0x72, | ||
209 | 0x8f, 0x08, | ||
210 | 0x90, 0xe0, | ||
211 | 0x94, 0x40, | ||
212 | 0xa0, 0x3f, | ||
213 | 0xa1, 0xc0, | ||
214 | 0xa4, 0xcc, | ||
215 | 0xa5, 0x66, | ||
216 | 0xa6, 0x66, | ||
217 | 0xa7, 0x7b, | ||
218 | 0xa8, 0x7b, | ||
219 | 0xa9, 0x7b, | ||
220 | 0xaa, 0x9a, | ||
221 | 0xed, 0x04, | ||
222 | 0xad, 0x00, | ||
223 | 0xae, 0x03, | ||
224 | 0xcc, 0xab, | ||
225 | 0x01, 0x08, | ||
226 | 0xff, 0xff | ||
227 | }; | ||
228 | |||
229 | /* low level read/writes */ | ||
230 | static int si21_writeregs(struct si21xx_state *state, u8 reg1, | ||
231 | u8 *data, int len) | ||
232 | { | ||
233 | int ret; | ||
234 | u8 buf[60];/* = { reg1, data };*/ | ||
235 | struct i2c_msg msg = { | ||
236 | .addr = state->config->demod_address, | ||
237 | .flags = 0, | ||
238 | .buf = buf, | ||
239 | .len = len + 1 | ||
240 | }; | ||
241 | |||
242 | msg.buf[0] = reg1; | ||
243 | memcpy(msg.buf + 1, data, len); | ||
244 | |||
245 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
246 | |||
247 | if (ret != 1) | ||
248 | dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " | ||
249 | "ret == %i)\n", __func__, reg1, data[0], ret); | ||
250 | |||
251 | return (ret != 1) ? -EREMOTEIO : 0; | ||
252 | } | ||
253 | |||
254 | static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) | ||
255 | { | ||
256 | int ret; | ||
257 | u8 buf[] = { reg, data }; | ||
258 | struct i2c_msg msg = { | ||
259 | .addr = state->config->demod_address, | ||
260 | .flags = 0, | ||
261 | .buf = buf, | ||
262 | .len = 2 | ||
263 | }; | ||
264 | |||
265 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
266 | |||
267 | if (ret != 1) | ||
268 | dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " | ||
269 | "ret == %i)\n", __func__, reg, data, ret); | ||
270 | |||
271 | return (ret != 1) ? -EREMOTEIO : 0; | ||
272 | } | ||
273 | |||
274 | static int si21_write(struct dvb_frontend *fe, u8 *buf, int len) | ||
275 | { | ||
276 | struct si21xx_state *state = fe->demodulator_priv; | ||
277 | |||
278 | if (len != 2) | ||
279 | return -EINVAL; | ||
280 | |||
281 | return si21_writereg(state, buf[0], buf[1]); | ||
282 | } | ||
283 | |||
284 | static u8 si21_readreg(struct si21xx_state *state, u8 reg) | ||
285 | { | ||
286 | int ret; | ||
287 | u8 b0[] = { reg }; | ||
288 | u8 b1[] = { 0 }; | ||
289 | struct i2c_msg msg[] = { | ||
290 | { | ||
291 | .addr = state->config->demod_address, | ||
292 | .flags = 0, | ||
293 | .buf = b0, | ||
294 | .len = 1 | ||
295 | }, { | ||
296 | .addr = state->config->demod_address, | ||
297 | .flags = I2C_M_RD, | ||
298 | .buf = b1, | ||
299 | .len = 1 | ||
300 | } | ||
301 | }; | ||
302 | |||
303 | ret = i2c_transfer(state->i2c, msg, 2); | ||
304 | |||
305 | if (ret != 2) | ||
306 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", | ||
307 | __func__, reg, ret); | ||
308 | |||
309 | return b1[0]; | ||
310 | } | ||
311 | |||
312 | static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) | ||
313 | { | ||
314 | int ret; | ||
315 | struct i2c_msg msg[] = { | ||
316 | { | ||
317 | .addr = state->config->demod_address, | ||
318 | .flags = 0, | ||
319 | .buf = ®1, | ||
320 | .len = 1 | ||
321 | }, { | ||
322 | .addr = state->config->demod_address, | ||
323 | .flags = I2C_M_RD, | ||
324 | .buf = b, | ||
325 | .len = len | ||
326 | } | ||
327 | }; | ||
328 | |||
329 | ret = i2c_transfer(state->i2c, msg, 2); | ||
330 | |||
331 | if (ret != 2) | ||
332 | dprintk("%s: readreg error (ret == %i)\n", __func__, ret); | ||
333 | |||
334 | return ret == 2 ? 0 : -1; | ||
335 | } | ||
336 | |||
337 | static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) | ||
338 | { | ||
339 | unsigned long start = jiffies; | ||
340 | |||
341 | dprintk("%s\n", __func__); | ||
342 | |||
343 | while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { | ||
344 | if (jiffies - start > timeout) { | ||
345 | dprintk("%s: timeout!!\n", __func__); | ||
346 | return -ETIMEDOUT; | ||
347 | } | ||
348 | msleep(10); | ||
349 | }; | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) | ||
355 | { | ||
356 | struct si21xx_state *state = fe->demodulator_priv; | ||
357 | u32 sym_rate, data_rate; | ||
358 | int i; | ||
359 | u8 sym_rate_bytes[3]; | ||
360 | |||
361 | dprintk("%s : srate = %i\n", __func__ , srate); | ||
362 | |||
363 | if ((srate < 1000000) || (srate > 45000000)) | ||
364 | return -EINVAL; | ||
365 | |||
366 | data_rate = srate; | ||
367 | sym_rate = 0; | ||
368 | |||
369 | for (i = 0; i < 4; ++i) { | ||
370 | sym_rate /= 100; | ||
371 | sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / | ||
372 | state->fs; | ||
373 | data_rate /= 100; | ||
374 | } | ||
375 | for (i = 0; i < 3; ++i) | ||
376 | sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); | ||
377 | |||
378 | si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, | ||
384 | struct dvb_diseqc_master_cmd *m) | ||
385 | { | ||
386 | struct si21xx_state *state = fe->demodulator_priv; | ||
387 | u8 lnb_status; | ||
388 | u8 LNB_CTRL_1; | ||
389 | int status; | ||
390 | |||
391 | dprintk("%s\n", __func__); | ||
392 | |||
393 | status = PASS; | ||
394 | LNB_CTRL_1 = 0; | ||
395 | |||
396 | status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); | ||
397 | status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); | ||
398 | |||
399 | /*fill the FIFO*/ | ||
400 | status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); | ||
401 | |||
402 | LNB_CTRL_1 = (lnb_status & 0x70); | ||
403 | LNB_CTRL_1 |= m->msg_len; | ||
404 | |||
405 | LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ | ||
406 | |||
407 | status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); | ||
408 | |||
409 | return status; | ||
410 | } | ||
411 | |||
412 | static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, | ||
413 | fe_sec_mini_cmd_t burst) | ||
414 | { | ||
415 | struct si21xx_state *state = fe->demodulator_priv; | ||
416 | u8 val; | ||
417 | |||
418 | dprintk("%s\n", __func__); | ||
419 | |||
420 | if (si21xx_wait_diseqc_idle(state, 100) < 0) | ||
421 | return -ETIMEDOUT; | ||
422 | |||
423 | val = (0x80 | si21_readreg(state, 0xc1)); | ||
424 | if (si21_writereg(state, LNB_CTRL_REG_1, | ||
425 | burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) | ||
426 | return -EREMOTEIO; | ||
427 | |||
428 | if (si21xx_wait_diseqc_idle(state, 100) < 0) | ||
429 | return -ETIMEDOUT; | ||
430 | |||
431 | if (si21_writereg(state, LNB_CTRL_REG_1, val)) | ||
432 | return -EREMOTEIO; | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | /* 30.06.2008 */ | ||
437 | static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
438 | { | ||
439 | struct si21xx_state *state = fe->demodulator_priv; | ||
440 | u8 val; | ||
441 | |||
442 | dprintk("%s\n", __func__); | ||
443 | val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); | ||
444 | |||
445 | switch (tone) { | ||
446 | case SEC_TONE_ON: | ||
447 | return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); | ||
448 | |||
449 | case SEC_TONE_OFF: | ||
450 | return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); | ||
451 | |||
452 | default: | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) | ||
458 | { | ||
459 | struct si21xx_state *state = fe->demodulator_priv; | ||
460 | |||
461 | u8 val; | ||
462 | dprintk("%s: %s\n", __func__, | ||
463 | volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : | ||
464 | volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); | ||
465 | |||
466 | |||
467 | val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); | ||
468 | |||
469 | switch (volt) { | ||
470 | case SEC_VOLTAGE_18: | ||
471 | return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); | ||
472 | break; | ||
473 | case SEC_VOLTAGE_13: | ||
474 | return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); | ||
475 | break; | ||
476 | default: | ||
477 | return -EINVAL; | ||
478 | }; | ||
479 | } | ||
480 | |||
481 | static int si21xx_init(struct dvb_frontend *fe) | ||
482 | { | ||
483 | struct si21xx_state *state = fe->demodulator_priv; | ||
484 | int i; | ||
485 | int status = 0; | ||
486 | u8 reg1; | ||
487 | u8 val; | ||
488 | u8 reg2[2]; | ||
489 | |||
490 | dprintk("%s\n", __func__); | ||
491 | |||
492 | for (i = 0; ; i += 2) { | ||
493 | reg1 = serit_sp1511lhb_inittab[i]; | ||
494 | val = serit_sp1511lhb_inittab[i+1]; | ||
495 | if (reg1 == 0xff && val == 0xff) | ||
496 | break; | ||
497 | si21_writeregs(state, reg1, &val, 1); | ||
498 | } | ||
499 | |||
500 | /*DVB QPSK SYSTEM MODE REG*/ | ||
501 | reg1 = 0x08; | ||
502 | si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); | ||
503 | |||
504 | /*transport stream config*/ | ||
505 | /* | ||
506 | mode = PARALLEL; | ||
507 | sdata_form = LSB_FIRST; | ||
508 | clk_edge = FALLING_EDGE; | ||
509 | clk_mode = CLK_GAPPED_MODE; | ||
510 | strt_len = BYTE_WIDE; | ||
511 | sync_pol = ACTIVE_HIGH; | ||
512 | val_pol = ACTIVE_HIGH; | ||
513 | err_pol = ACTIVE_HIGH; | ||
514 | sclk_rate = 0x00; | ||
515 | parity = 0x00 ; | ||
516 | data_delay = 0x00; | ||
517 | clk_delay = 0x00; | ||
518 | pclk_smooth = 0x00; | ||
519 | */ | ||
520 | reg2[0] = | ||
521 | PARALLEL + (LSB_FIRST << 1) | ||
522 | + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) | ||
523 | + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) | ||
524 | + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); | ||
525 | |||
526 | reg2[1] = 0; | ||
527 | /* sclk_rate + (parity << 2) | ||
528 | + (data_delay << 3) + (clk_delay << 4) | ||
529 | + (pclk_smooth << 5); | ||
530 | */ | ||
531 | status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); | ||
532 | if (status != 0) | ||
533 | dprintk(" %s : TS Set Error\n", __func__); | ||
534 | |||
535 | return 0; | ||
536 | |||
537 | } | ||
538 | |||
539 | static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
540 | { | ||
541 | struct si21xx_state *state = fe->demodulator_priv; | ||
542 | u8 regs_read[2]; | ||
543 | u8 reg_read; | ||
544 | u8 i; | ||
545 | u8 lock; | ||
546 | u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); | ||
547 | |||
548 | si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); | ||
549 | reg_read = 0; | ||
550 | |||
551 | for (i = 0; i < 7; ++i) | ||
552 | reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); | ||
553 | |||
554 | lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); | ||
555 | |||
556 | dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); | ||
557 | *status = 0; | ||
558 | |||
559 | if (signal > 10) | ||
560 | *status |= FE_HAS_SIGNAL; | ||
561 | |||
562 | if (lock & 0x2) | ||
563 | *status |= FE_HAS_CARRIER; | ||
564 | |||
565 | if (lock & 0x20) | ||
566 | *status |= FE_HAS_VITERBI; | ||
567 | |||
568 | if (lock & 0x40) | ||
569 | *status |= FE_HAS_SYNC; | ||
570 | |||
571 | if ((lock & 0x7b) == 0x7b) | ||
572 | *status |= FE_HAS_LOCK; | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
578 | { | ||
579 | struct si21xx_state *state = fe->demodulator_priv; | ||
580 | |||
581 | /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, | ||
582 | (u8*)agclevel, 0x01);*/ | ||
583 | |||
584 | u16 signal = (3 * si21_readreg(state, 0x27) * | ||
585 | si21_readreg(state, 0x28)); | ||
586 | |||
587 | dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, | ||
588 | si21_readreg(state, 0x27), | ||
589 | si21_readreg(state, 0x28), (int) signal); | ||
590 | |||
591 | signal <<= 4; | ||
592 | *strength = signal; | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | static int si21_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
598 | { | ||
599 | struct si21xx_state *state = fe->demodulator_priv; | ||
600 | |||
601 | dprintk("%s\n", __func__); | ||
602 | |||
603 | if (state->errmode != STATUS_BER) | ||
604 | return 0; | ||
605 | |||
606 | *ber = (si21_readreg(state, 0x1d) << 8) | | ||
607 | si21_readreg(state, 0x1e); | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int si21_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
613 | { | ||
614 | struct si21xx_state *state = fe->demodulator_priv; | ||
615 | |||
616 | s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | | ||
617 | si21_readreg(state, 0x25)); | ||
618 | xsnr = 3 * (xsnr - 0xa100); | ||
619 | *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; | ||
620 | |||
621 | dprintk("%s\n", __func__); | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
627 | { | ||
628 | struct si21xx_state *state = fe->demodulator_priv; | ||
629 | |||
630 | dprintk("%s\n", __func__); | ||
631 | |||
632 | if (state->errmode != STATUS_UCBLOCKS) | ||
633 | *ucblocks = 0; | ||
634 | else | ||
635 | *ucblocks = (si21_readreg(state, 0x1d) << 8) | | ||
636 | si21_readreg(state, 0x1e); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | /* initiates a channel acquisition sequence | ||
642 | using the specified symbol rate and code rate */ | ||
643 | static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, | ||
644 | fe_code_rate_t crate) | ||
645 | { | ||
646 | |||
647 | struct si21xx_state *state = fe->demodulator_priv; | ||
648 | u8 coderates[] = { | ||
649 | 0x0, 0x01, 0x02, 0x04, 0x00, | ||
650 | 0x8, 0x10, 0x20, 0x00, 0x3f | ||
651 | }; | ||
652 | |||
653 | u8 coderate_ptr; | ||
654 | int status; | ||
655 | u8 start_acq = 0x80; | ||
656 | u8 reg, regs[3]; | ||
657 | |||
658 | dprintk("%s\n", __func__); | ||
659 | |||
660 | status = PASS; | ||
661 | coderate_ptr = coderates[crate]; | ||
662 | |||
663 | si21xx_set_symbolrate(fe, symbrate); | ||
664 | |||
665 | /* write code rates to use in the Viterbi search */ | ||
666 | status |= si21_writeregs(state, | ||
667 | VIT_SRCH_CTRL_REG_1, | ||
668 | &coderate_ptr, 0x01); | ||
669 | |||
670 | /* clear acq_start bit */ | ||
671 | status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); | ||
672 | reg &= ~start_acq; | ||
673 | status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); | ||
674 | |||
675 | /* use new Carrier Frequency Offset Estimator (QuickLock) */ | ||
676 | regs[0] = 0xCB; | ||
677 | regs[1] = 0x40; | ||
678 | regs[2] = 0xCB; | ||
679 | |||
680 | status |= si21_writeregs(state, | ||
681 | TWO_DB_BNDWDTH_THRSHLD_REG, | ||
682 | ®s[0], 0x03); | ||
683 | reg = 0x56; | ||
684 | status |= si21_writeregs(state, | ||
685 | LSA_CTRL_REG_1, ®, 1); | ||
686 | reg = 0x05; | ||
687 | status |= si21_writeregs(state, | ||
688 | BLIND_SCAN_CTRL_REG, ®, 1); | ||
689 | /* start automatic acq */ | ||
690 | status |= si21_writeregs(state, | ||
691 | ACQ_CTRL_REG_2, &start_acq, 0x01); | ||
692 | |||
693 | return status; | ||
694 | } | ||
695 | |||
696 | static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
697 | { | ||
698 | dprintk("%s(..)\n", __func__); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
703 | { | ||
704 | dprintk("%s(..)\n", __func__); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int si21xx_set_frontend(struct dvb_frontend *fe, | ||
709 | struct dvb_frontend_parameters *dfp) | ||
710 | { | ||
711 | struct si21xx_state *state = fe->demodulator_priv; | ||
712 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
713 | |||
714 | /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) | ||
715 | datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ | ||
716 | |||
717 | /* in MHz */ | ||
718 | unsigned char coarse_tune_freq; | ||
719 | int fine_tune_freq; | ||
720 | unsigned char sample_rate = 0; | ||
721 | /* boolean */ | ||
722 | unsigned int inband_interferer_ind; | ||
723 | |||
724 | /* INTERMEDIATE VALUES */ | ||
725 | int icoarse_tune_freq; /* MHz */ | ||
726 | int ifine_tune_freq; /* MHz */ | ||
727 | unsigned int band_high; | ||
728 | unsigned int band_low; | ||
729 | unsigned int x1; | ||
730 | unsigned int x2; | ||
731 | int i; | ||
732 | unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = { | ||
733 | FALSE, FALSE, FALSE, FALSE, FALSE, | ||
734 | FALSE, FALSE, FALSE, FALSE, FALSE | ||
735 | }; | ||
736 | unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = { | ||
737 | FALSE, FALSE, FALSE, FALSE, FALSE, | ||
738 | FALSE, FALSE, FALSE, FALSE, FALSE | ||
739 | }; | ||
740 | |||
741 | int status; | ||
742 | |||
743 | /* allowable sample rates for ADC in MHz */ | ||
744 | int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, | ||
745 | 196, 204, 205, 206, 207 | ||
746 | }; | ||
747 | /* in MHz */ | ||
748 | int if_limit_high; | ||
749 | int if_limit_low; | ||
750 | int lnb_lo; | ||
751 | int lnb_uncertanity; | ||
752 | |||
753 | int rf_freq; | ||
754 | int data_rate; | ||
755 | unsigned char regs[4]; | ||
756 | |||
757 | dprintk("%s : FE_SET_FRONTEND\n", __func__); | ||
758 | |||
759 | if (c->delivery_system != SYS_DVBS) { | ||
760 | dprintk("%s: unsupported delivery system selected (%d)\n", | ||
761 | __func__, c->delivery_system); | ||
762 | return -EOPNOTSUPP; | ||
763 | } | ||
764 | |||
765 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) | ||
766 | inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE; | ||
767 | |||
768 | if_limit_high = -700000; | ||
769 | if_limit_low = -100000; | ||
770 | /* in MHz */ | ||
771 | lnb_lo = 0; | ||
772 | lnb_uncertanity = 0; | ||
773 | |||
774 | rf_freq = 10 * c->frequency ; | ||
775 | data_rate = c->symbol_rate / 100; | ||
776 | |||
777 | status = PASS; | ||
778 | |||
779 | band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) | ||
780 | + (data_rate * 135)) / 200; | ||
781 | |||
782 | band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) | ||
783 | + (data_rate * 135)) / 200; | ||
784 | |||
785 | |||
786 | icoarse_tune_freq = 100000 * | ||
787 | (((rf_freq - lnb_lo) - | ||
788 | (if_limit_low + if_limit_high) / 2) | ||
789 | / 100000); | ||
790 | |||
791 | ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; | ||
792 | |||
793 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
794 | x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * | ||
795 | (afs[i] * 2500) + afs[i] * 2500; | ||
796 | |||
797 | x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * | ||
798 | (afs[i] * 2500); | ||
799 | |||
800 | if (((band_low < x1) && (x1 < band_high)) || | ||
801 | ((band_low < x2) && (x2 < band_high))) | ||
802 | inband_interferer_div4[i] = TRUE; | ||
803 | |||
804 | } | ||
805 | |||
806 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
807 | x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * | ||
808 | (afs[i] * 5000) + afs[i] * 5000; | ||
809 | |||
810 | x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * | ||
811 | (afs[i] * 5000); | ||
812 | |||
813 | if (((band_low < x1) && (x1 < band_high)) || | ||
814 | ((band_low < x2) && (x2 < band_high))) | ||
815 | inband_interferer_div2[i] = TRUE; | ||
816 | } | ||
817 | |||
818 | inband_interferer_ind = TRUE; | ||
819 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) | ||
820 | inband_interferer_ind &= inband_interferer_div2[i] | | ||
821 | inband_interferer_div4[i]; | ||
822 | |||
823 | if (inband_interferer_ind) { | ||
824 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
825 | if (inband_interferer_div2[i] == FALSE) { | ||
826 | sample_rate = (u8) afs[i]; | ||
827 | break; | ||
828 | } | ||
829 | } | ||
830 | } else { | ||
831 | for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { | ||
832 | if ((inband_interferer_div2[i] | | ||
833 | inband_interferer_div4[i]) == FALSE) { | ||
834 | sample_rate = (u8) afs[i]; | ||
835 | break; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | } | ||
840 | |||
841 | if (sample_rate > 207 || sample_rate < 192) | ||
842 | sample_rate = 200; | ||
843 | |||
844 | fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / | ||
845 | ((sample_rate) * 1000)); | ||
846 | |||
847 | coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); | ||
848 | |||
849 | regs[0] = sample_rate; | ||
850 | regs[1] = coarse_tune_freq; | ||
851 | regs[2] = fine_tune_freq & 0xFF; | ||
852 | regs[3] = fine_tune_freq >> 8 & 0xFF; | ||
853 | |||
854 | status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); | ||
855 | |||
856 | state->fs = sample_rate;/*ADC MHz*/ | ||
857 | si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); | ||
858 | |||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | static int si21xx_sleep(struct dvb_frontend *fe) | ||
863 | { | ||
864 | struct si21xx_state *state = fe->demodulator_priv; | ||
865 | u8 regdata; | ||
866 | |||
867 | dprintk("%s\n", __func__); | ||
868 | |||
869 | si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); | ||
870 | regdata |= 1 << 6; | ||
871 | si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); | ||
872 | state->initialised = 0; | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static void si21xx_release(struct dvb_frontend *fe) | ||
878 | { | ||
879 | struct si21xx_state *state = fe->demodulator_priv; | ||
880 | |||
881 | dprintk("%s\n", __func__); | ||
882 | |||
883 | kfree(state); | ||
884 | } | ||
885 | |||
886 | static struct dvb_frontend_ops si21xx_ops = { | ||
887 | |||
888 | .info = { | ||
889 | .name = "SL SI21XX DVB-S", | ||
890 | .type = FE_QPSK, | ||
891 | .frequency_min = 950000, | ||
892 | .frequency_max = 2150000, | ||
893 | .frequency_stepsize = 125, /* kHz for QPSK frontends */ | ||
894 | .frequency_tolerance = 0, | ||
895 | .symbol_rate_min = 1000000, | ||
896 | .symbol_rate_max = 45000000, | ||
897 | .symbol_rate_tolerance = 500, /* ppm */ | ||
898 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
899 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
900 | FE_CAN_QPSK | | ||
901 | FE_CAN_FEC_AUTO | ||
902 | }, | ||
903 | |||
904 | .release = si21xx_release, | ||
905 | .init = si21xx_init, | ||
906 | .sleep = si21xx_sleep, | ||
907 | .write = si21_write, | ||
908 | .read_status = si21_read_status, | ||
909 | .read_ber = si21_read_ber, | ||
910 | .read_signal_strength = si21_read_signal_strength, | ||
911 | .read_snr = si21_read_snr, | ||
912 | .read_ucblocks = si21_read_ucblocks, | ||
913 | .diseqc_send_master_cmd = si21xx_send_diseqc_msg, | ||
914 | .diseqc_send_burst = si21xx_send_diseqc_burst, | ||
915 | .set_tone = si21xx_set_tone, | ||
916 | .set_voltage = si21xx_set_voltage, | ||
917 | |||
918 | .set_property = si21xx_set_property, | ||
919 | .get_property = si21xx_get_property, | ||
920 | .set_frontend = si21xx_set_frontend, | ||
921 | }; | ||
922 | |||
923 | struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, | ||
924 | struct i2c_adapter *i2c) | ||
925 | { | ||
926 | struct si21xx_state *state = NULL; | ||
927 | int id; | ||
928 | |||
929 | dprintk("%s\n", __func__); | ||
930 | |||
931 | /* allocate memory for the internal state */ | ||
932 | state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL); | ||
933 | if (state == NULL) | ||
934 | goto error; | ||
935 | |||
936 | /* setup the state */ | ||
937 | state->config = config; | ||
938 | state->i2c = i2c; | ||
939 | state->initialised = 0; | ||
940 | state->errmode = STATUS_BER; | ||
941 | |||
942 | /* check if the demod is there */ | ||
943 | id = si21_readreg(state, SYSTEM_MODE_REG); | ||
944 | si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ | ||
945 | msleep(200); | ||
946 | id = si21_readreg(state, 0x00); | ||
947 | |||
948 | /* register 0x00 contains: | ||
949 | 0x34 for SI2107 | ||
950 | 0x24 for SI2108 | ||
951 | 0x14 for SI2109 | ||
952 | 0x04 for SI2110 | ||
953 | */ | ||
954 | if (id != 0x04 && id != 0x14) | ||
955 | goto error; | ||
956 | |||
957 | /* create dvb_frontend */ | ||
958 | memcpy(&state->frontend.ops, &si21xx_ops, | ||
959 | sizeof(struct dvb_frontend_ops)); | ||
960 | state->frontend.demodulator_priv = state; | ||
961 | return &state->frontend; | ||
962 | |||
963 | error: | ||
964 | kfree(state); | ||
965 | return NULL; | ||
966 | } | ||
967 | EXPORT_SYMBOL(si21xx_attach); | ||
968 | |||
969 | module_param(debug, int, 0644); | ||
970 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
971 | |||
972 | MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); | ||
973 | MODULE_AUTHOR("Igor M. Liplianin"); | ||
974 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb/frontends/si21xx.h new file mode 100644 index 000000000000..141b5b8a5f63 --- /dev/null +++ b/drivers/media/dvb/frontends/si21xx.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef SI21XX_H | ||
2 | #define SI21XX_H | ||
3 | |||
4 | #include <linux/dvb/frontend.h> | ||
5 | #include "dvb_frontend.h" | ||
6 | |||
7 | struct si21xx_config { | ||
8 | /* the demodulator's i2c address */ | ||
9 | u8 demod_address; | ||
10 | |||
11 | /* minimum delay before retuning */ | ||
12 | int min_delay_ms; | ||
13 | }; | ||
14 | |||
15 | #if defined(CONFIG_DVB_SI21XX) || \ | ||
16 | (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE)) | ||
17 | extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, | ||
18 | struct i2c_adapter *i2c); | ||
19 | #else | ||
20 | static inline struct dvb_frontend *si21xx_attach( | ||
21 | const struct si21xx_config *config, struct i2c_adapter *i2c) | ||
22 | { | ||
23 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
24 | return NULL; | ||
25 | } | ||
26 | #endif | ||
27 | |||
28 | static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val) | ||
29 | { | ||
30 | int r = 0; | ||
31 | u8 buf[] = {reg, val}; | ||
32 | if (fe->ops.write) | ||
33 | r = fe->ops.write(fe, buf, 2); | ||
34 | return r; | ||
35 | } | ||
36 | |||
37 | #endif | ||
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 4543609e1816..559509ab4dab 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c | |||
@@ -337,7 +337,8 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, | |||
337 | struct dvb_frontend_parameters *p) | 337 | struct dvb_frontend_parameters *p) |
338 | { | 338 | { |
339 | struct sp887x_state* state = fe->demodulator_priv; | 339 | struct sp887x_state* state = fe->demodulator_priv; |
340 | int actual_freq, err; | 340 | unsigned actual_freq; |
341 | int err; | ||
341 | u16 val, reg0xc05; | 342 | u16 val, reg0xc05; |
342 | 343 | ||
343 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && | 344 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && |
diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c new file mode 100644 index 000000000000..0e2cb0df1441 --- /dev/null +++ b/drivers/media/dvb/frontends/stb6000.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | Driver for ST STB6000 DVBS Silicon tuner | ||
3 | |||
4 | Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include <asm/types.h> | ||
26 | |||
27 | #include "stb6000.h" | ||
28 | |||
29 | static int debug; | ||
30 | #define dprintk(args...) \ | ||
31 | do { \ | ||
32 | if (debug) \ | ||
33 | printk(KERN_DEBUG "stb6000: " args); \ | ||
34 | } while (0) | ||
35 | |||
36 | struct stb6000_priv { | ||
37 | /* i2c details */ | ||
38 | int i2c_address; | ||
39 | struct i2c_adapter *i2c; | ||
40 | u32 frequency; | ||
41 | }; | ||
42 | |||
43 | static int stb6000_release(struct dvb_frontend *fe) | ||
44 | { | ||
45 | kfree(fe->tuner_priv); | ||
46 | fe->tuner_priv = NULL; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int stb6000_sleep(struct dvb_frontend *fe) | ||
51 | { | ||
52 | struct stb6000_priv *priv = fe->tuner_priv; | ||
53 | int ret; | ||
54 | u8 buf[] = { 10, 0 }; | ||
55 | struct i2c_msg msg = { | ||
56 | .addr = priv->i2c_address, | ||
57 | .flags = 0, | ||
58 | .buf = buf, | ||
59 | .len = 2 | ||
60 | }; | ||
61 | |||
62 | dprintk("%s:\n", __func__); | ||
63 | |||
64 | if (fe->ops.i2c_gate_ctrl) | ||
65 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
66 | |||
67 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
68 | if (ret != 1) | ||
69 | dprintk("%s: i2c error\n", __func__); | ||
70 | |||
71 | if (fe->ops.i2c_gate_ctrl) | ||
72 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
73 | |||
74 | return (ret == 1) ? 0 : ret; | ||
75 | } | ||
76 | |||
77 | static int stb6000_set_params(struct dvb_frontend *fe, | ||
78 | struct dvb_frontend_parameters *params) | ||
79 | { | ||
80 | struct stb6000_priv *priv = fe->tuner_priv; | ||
81 | unsigned int n, m; | ||
82 | int ret; | ||
83 | u32 freq_mhz; | ||
84 | int bandwidth; | ||
85 | u8 buf[12]; | ||
86 | struct i2c_msg msg = { | ||
87 | .addr = priv->i2c_address, | ||
88 | .flags = 0, | ||
89 | .buf = buf, | ||
90 | .len = 12 | ||
91 | }; | ||
92 | |||
93 | dprintk("%s:\n", __func__); | ||
94 | |||
95 | freq_mhz = params->frequency / 1000; | ||
96 | bandwidth = params->u.qpsk.symbol_rate / 1000000; | ||
97 | |||
98 | if (bandwidth > 31) | ||
99 | bandwidth = 31; | ||
100 | |||
101 | if ((freq_mhz > 949) && (freq_mhz < 2151)) { | ||
102 | buf[0] = 0x01; | ||
103 | buf[1] = 0xac; | ||
104 | if (freq_mhz < 1950) | ||
105 | buf[1] = 0xaa; | ||
106 | if (freq_mhz < 1800) | ||
107 | buf[1] = 0xa8; | ||
108 | if (freq_mhz < 1650) | ||
109 | buf[1] = 0xa6; | ||
110 | if (freq_mhz < 1530) | ||
111 | buf[1] = 0xa5; | ||
112 | if (freq_mhz < 1470) | ||
113 | buf[1] = 0xa4; | ||
114 | if (freq_mhz < 1370) | ||
115 | buf[1] = 0xa2; | ||
116 | if (freq_mhz < 1300) | ||
117 | buf[1] = 0xa1; | ||
118 | if (freq_mhz < 1200) | ||
119 | buf[1] = 0xa0; | ||
120 | if (freq_mhz < 1075) | ||
121 | buf[1] = 0xbc; | ||
122 | if (freq_mhz < 1000) | ||
123 | buf[1] = 0xba; | ||
124 | if (freq_mhz < 1075) { | ||
125 | n = freq_mhz / 8; /* vco=lo*4 */ | ||
126 | m = 2; | ||
127 | } else { | ||
128 | n = freq_mhz / 16; /* vco=lo*2 */ | ||
129 | m = 1; | ||
130 | } | ||
131 | buf[2] = n >> 1; | ||
132 | buf[3] = (unsigned char)(((n & 1) << 7) | | ||
133 | (m * freq_mhz - n * 16) | 0x60); | ||
134 | buf[4] = 0x04; | ||
135 | buf[5] = 0x0e; | ||
136 | |||
137 | buf[6] = (unsigned char)(bandwidth); | ||
138 | |||
139 | buf[7] = 0xd8; | ||
140 | buf[8] = 0xd0; | ||
141 | buf[9] = 0x50; | ||
142 | buf[10] = 0xeb; | ||
143 | buf[11] = 0x4f; | ||
144 | |||
145 | if (fe->ops.i2c_gate_ctrl) | ||
146 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
147 | |||
148 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
149 | if (ret != 1) | ||
150 | dprintk("%s: i2c error\n", __func__); | ||
151 | |||
152 | udelay(10); | ||
153 | if (fe->ops.i2c_gate_ctrl) | ||
154 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
155 | |||
156 | buf[0] = 0x07; | ||
157 | buf[1] = 0xdf; | ||
158 | buf[2] = 0xd0; | ||
159 | buf[3] = 0x50; | ||
160 | buf[4] = 0xfb; | ||
161 | msg.len = 5; | ||
162 | |||
163 | if (fe->ops.i2c_gate_ctrl) | ||
164 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
165 | |||
166 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
167 | if (ret != 1) | ||
168 | dprintk("%s: i2c error\n", __func__); | ||
169 | |||
170 | udelay(10); | ||
171 | if (fe->ops.i2c_gate_ctrl) | ||
172 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
173 | |||
174 | priv->frequency = freq_mhz * 1000; | ||
175 | |||
176 | return (ret == 1) ? 0 : ret; | ||
177 | } | ||
178 | return -1; | ||
179 | } | ||
180 | |||
181 | static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
182 | { | ||
183 | struct stb6000_priv *priv = fe->tuner_priv; | ||
184 | *frequency = priv->frequency; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct dvb_tuner_ops stb6000_tuner_ops = { | ||
189 | .info = { | ||
190 | .name = "ST STB6000", | ||
191 | .frequency_min = 950000, | ||
192 | .frequency_max = 2150000 | ||
193 | }, | ||
194 | .release = stb6000_release, | ||
195 | .sleep = stb6000_sleep, | ||
196 | .set_params = stb6000_set_params, | ||
197 | .get_frequency = stb6000_get_frequency, | ||
198 | }; | ||
199 | |||
200 | struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, | ||
201 | struct i2c_adapter *i2c) | ||
202 | { | ||
203 | struct stb6000_priv *priv = NULL; | ||
204 | u8 b0[] = { 0 }; | ||
205 | u8 b1[] = { 0, 0 }; | ||
206 | struct i2c_msg msg[2] = { | ||
207 | { | ||
208 | .addr = addr, | ||
209 | .flags = 0, | ||
210 | .buf = b0, | ||
211 | .len = 0 | ||
212 | }, { | ||
213 | .addr = addr, | ||
214 | .flags = I2C_M_RD, | ||
215 | .buf = b1, | ||
216 | .len = 2 | ||
217 | } | ||
218 | }; | ||
219 | int ret; | ||
220 | |||
221 | dprintk("%s:\n", __func__); | ||
222 | |||
223 | if (fe->ops.i2c_gate_ctrl) | ||
224 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
225 | |||
226 | /* is some i2c device here ? */ | ||
227 | ret = i2c_transfer(i2c, msg, 2); | ||
228 | if (fe->ops.i2c_gate_ctrl) | ||
229 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
230 | |||
231 | if (ret != 2) | ||
232 | return NULL; | ||
233 | |||
234 | priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL); | ||
235 | if (priv == NULL) | ||
236 | return NULL; | ||
237 | |||
238 | priv->i2c_address = addr; | ||
239 | priv->i2c = i2c; | ||
240 | |||
241 | memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, | ||
242 | sizeof(struct dvb_tuner_ops)); | ||
243 | |||
244 | fe->tuner_priv = priv; | ||
245 | |||
246 | return fe; | ||
247 | } | ||
248 | EXPORT_SYMBOL(stb6000_attach); | ||
249 | |||
250 | module_param(debug, int, 0644); | ||
251 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
252 | |||
253 | MODULE_DESCRIPTION("DVB STB6000 driver"); | ||
254 | MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>"); | ||
255 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb/frontends/stb6000.h new file mode 100644 index 000000000000..7be479c22d5b --- /dev/null +++ b/drivers/media/dvb/frontends/stb6000.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | Driver for ST stb6000 DVBS Silicon tuner | ||
3 | |||
4 | Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef __DVB_STB6000_H__ | ||
24 | #define __DVB_STB6000_H__ | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include "dvb_frontend.h" | ||
28 | |||
29 | /** | ||
30 | * Attach a stb6000 tuner to the supplied frontend structure. | ||
31 | * | ||
32 | * @param fe Frontend to attach to. | ||
33 | * @param addr i2c address of the tuner. | ||
34 | * @param i2c i2c adapter to use. | ||
35 | * @return FE pointer on success, NULL on failure. | ||
36 | */ | ||
37 | #if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \ | ||
38 | && defined(MODULE)) | ||
39 | extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, | ||
40 | struct i2c_adapter *i2c); | ||
41 | #else | ||
42 | static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, | ||
43 | int addr, | ||
44 | struct i2c_adapter *i2c) | ||
45 | { | ||
46 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
47 | return NULL; | ||
48 | } | ||
49 | #endif /* CONFIG_DVB_STB6000 */ | ||
50 | |||
51 | #endif /* __DVB_STB6000_H__ */ | ||
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c new file mode 100644 index 000000000000..ff1194de34c0 --- /dev/null +++ b/drivers/media/dvb/frontends/stv0288.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /* | ||
2 | Driver for ST STV0288 demodulator | ||
3 | Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de | ||
4 | for Reel Multimedia | ||
5 | Copyright (C) 2008 TurboSight.com, Bob Liu <bob@turbosight.com> | ||
6 | Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> | ||
7 | Removed stb6000 specific tuner code and revised some | ||
8 | procedures. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/jiffies.h> | ||
32 | #include <asm/div64.h> | ||
33 | |||
34 | #include "dvb_frontend.h" | ||
35 | #include "stv0288.h" | ||
36 | |||
37 | struct stv0288_state { | ||
38 | struct i2c_adapter *i2c; | ||
39 | const struct stv0288_config *config; | ||
40 | struct dvb_frontend frontend; | ||
41 | |||
42 | u8 initialised:1; | ||
43 | u32 tuner_frequency; | ||
44 | u32 symbol_rate; | ||
45 | fe_code_rate_t fec_inner; | ||
46 | int errmode; | ||
47 | }; | ||
48 | |||
49 | #define STATUS_BER 0 | ||
50 | #define STATUS_UCBLOCKS 1 | ||
51 | |||
52 | static int debug; | ||
53 | static int debug_legacy_dish_switch; | ||
54 | #define dprintk(args...) \ | ||
55 | do { \ | ||
56 | if (debug) \ | ||
57 | printk(KERN_DEBUG "stv0288: " args); \ | ||
58 | } while (0) | ||
59 | |||
60 | |||
61 | static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) | ||
62 | { | ||
63 | int ret; | ||
64 | u8 buf[] = { reg, data }; | ||
65 | struct i2c_msg msg = { | ||
66 | .addr = state->config->demod_address, | ||
67 | .flags = 0, | ||
68 | .buf = buf, | ||
69 | .len = 2 | ||
70 | }; | ||
71 | |||
72 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
73 | |||
74 | if (ret != 1) | ||
75 | dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " | ||
76 | "ret == %i)\n", __func__, reg, data, ret); | ||
77 | |||
78 | return (ret != 1) ? -EREMOTEIO : 0; | ||
79 | } | ||
80 | |||
81 | static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len) | ||
82 | { | ||
83 | struct stv0288_state *state = fe->demodulator_priv; | ||
84 | |||
85 | if (len != 2) | ||
86 | return -EINVAL; | ||
87 | |||
88 | return stv0288_writeregI(state, buf[0], buf[1]); | ||
89 | } | ||
90 | |||
91 | static u8 stv0288_readreg(struct stv0288_state *state, u8 reg) | ||
92 | { | ||
93 | int ret; | ||
94 | u8 b0[] = { reg }; | ||
95 | u8 b1[] = { 0 }; | ||
96 | struct i2c_msg msg[] = { | ||
97 | { | ||
98 | .addr = state->config->demod_address, | ||
99 | .flags = 0, | ||
100 | .buf = b0, | ||
101 | .len = 1 | ||
102 | }, { | ||
103 | .addr = state->config->demod_address, | ||
104 | .flags = I2C_M_RD, | ||
105 | .buf = b1, | ||
106 | .len = 1 | ||
107 | } | ||
108 | }; | ||
109 | |||
110 | ret = i2c_transfer(state->i2c, msg, 2); | ||
111 | |||
112 | if (ret != 2) | ||
113 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", | ||
114 | __func__, reg, ret); | ||
115 | |||
116 | return b1[0]; | ||
117 | } | ||
118 | |||
119 | static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) | ||
120 | { | ||
121 | struct stv0288_state *state = fe->demodulator_priv; | ||
122 | unsigned int temp; | ||
123 | unsigned char b[3]; | ||
124 | |||
125 | if ((srate < 1000000) || (srate > 45000000)) | ||
126 | return -EINVAL; | ||
127 | |||
128 | temp = (unsigned int)srate / 1000; | ||
129 | |||
130 | temp = temp * 32768; | ||
131 | temp = temp / 25; | ||
132 | temp = temp / 125; | ||
133 | b[0] = (unsigned char)((temp >> 12) & 0xff); | ||
134 | b[1] = (unsigned char)((temp >> 4) & 0xff); | ||
135 | b[2] = (unsigned char)((temp << 4) & 0xf0); | ||
136 | stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ | ||
137 | stv0288_writeregI(state, 0x29, 0); /* SFRM */ | ||
138 | stv0288_writeregI(state, 0x2a, 0); /* SFRL */ | ||
139 | |||
140 | stv0288_writeregI(state, 0x28, b[0]); | ||
141 | stv0288_writeregI(state, 0x29, b[1]); | ||
142 | stv0288_writeregI(state, 0x2a, b[2]); | ||
143 | dprintk("stv0288: stv0288_set_symbolrate\n"); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, | ||
149 | struct dvb_diseqc_master_cmd *m) | ||
150 | { | ||
151 | struct stv0288_state *state = fe->demodulator_priv; | ||
152 | |||
153 | int i; | ||
154 | |||
155 | dprintk("%s\n", __func__); | ||
156 | |||
157 | stv0288_writeregI(state, 0x09, 0); | ||
158 | msleep(30); | ||
159 | stv0288_writeregI(state, 0x05, 0x16); | ||
160 | |||
161 | for (i = 0; i < m->msg_len; i++) { | ||
162 | if (stv0288_writeregI(state, 0x06, m->msg[i])) | ||
163 | return -EREMOTEIO; | ||
164 | msleep(12); | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, | ||
171 | fe_sec_mini_cmd_t burst) | ||
172 | { | ||
173 | struct stv0288_state *state = fe->demodulator_priv; | ||
174 | |||
175 | dprintk("%s\n", __func__); | ||
176 | |||
177 | if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */ | ||
178 | return -EREMOTEIO; | ||
179 | |||
180 | if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff)) | ||
181 | return -EREMOTEIO; | ||
182 | |||
183 | if (stv0288_writeregI(state, 0x06, 0x12)) | ||
184 | return -EREMOTEIO; | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | ||
190 | { | ||
191 | struct stv0288_state *state = fe->demodulator_priv; | ||
192 | |||
193 | switch (tone) { | ||
194 | case SEC_TONE_ON: | ||
195 | if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */ | ||
196 | return -EREMOTEIO; | ||
197 | return stv0288_writeregI(state, 0x06, 0xff); | ||
198 | |||
199 | case SEC_TONE_OFF: | ||
200 | if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */ | ||
201 | return -EREMOTEIO; | ||
202 | return stv0288_writeregI(state, 0x06, 0x00); | ||
203 | |||
204 | default: | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | static u8 stv0288_inittab[] = { | ||
210 | 0x01, 0x15, | ||
211 | 0x02, 0x20, | ||
212 | 0x09, 0x0, | ||
213 | 0x0a, 0x4, | ||
214 | 0x0b, 0x0, | ||
215 | 0x0c, 0x0, | ||
216 | 0x0d, 0x0, | ||
217 | 0x0e, 0xd4, | ||
218 | 0x0f, 0x30, | ||
219 | 0x11, 0x80, | ||
220 | 0x12, 0x03, | ||
221 | 0x13, 0x48, | ||
222 | 0x14, 0x84, | ||
223 | 0x15, 0x45, | ||
224 | 0x16, 0xb7, | ||
225 | 0x17, 0x9c, | ||
226 | 0x18, 0x0, | ||
227 | 0x19, 0xa6, | ||
228 | 0x1a, 0x88, | ||
229 | 0x1b, 0x8f, | ||
230 | 0x1c, 0xf0, | ||
231 | 0x20, 0x0b, | ||
232 | 0x21, 0x54, | ||
233 | 0x22, 0x0, | ||
234 | 0x23, 0x0, | ||
235 | 0x2b, 0xff, | ||
236 | 0x2c, 0xf7, | ||
237 | 0x30, 0x0, | ||
238 | 0x31, 0x1e, | ||
239 | 0x32, 0x14, | ||
240 | 0x33, 0x0f, | ||
241 | 0x34, 0x09, | ||
242 | 0x35, 0x0c, | ||
243 | 0x36, 0x05, | ||
244 | 0x37, 0x2f, | ||
245 | 0x38, 0x16, | ||
246 | 0x39, 0xbe, | ||
247 | 0x3a, 0x0, | ||
248 | 0x3b, 0x13, | ||
249 | 0x3c, 0x11, | ||
250 | 0x3d, 0x30, | ||
251 | 0x40, 0x63, | ||
252 | 0x41, 0x04, | ||
253 | 0x42, 0x60, | ||
254 | 0x43, 0x00, | ||
255 | 0x44, 0x00, | ||
256 | 0x45, 0x00, | ||
257 | 0x46, 0x00, | ||
258 | 0x47, 0x00, | ||
259 | 0x4a, 0x00, | ||
260 | 0x50, 0x10, | ||
261 | 0x51, 0x38, | ||
262 | 0x52, 0x21, | ||
263 | 0x58, 0x54, | ||
264 | 0x59, 0x86, | ||
265 | 0x5a, 0x0, | ||
266 | 0x5b, 0x9b, | ||
267 | 0x5c, 0x08, | ||
268 | 0x5d, 0x7f, | ||
269 | 0x5e, 0x0, | ||
270 | 0x5f, 0xff, | ||
271 | 0x70, 0x0, | ||
272 | 0x71, 0x0, | ||
273 | 0x72, 0x0, | ||
274 | 0x74, 0x0, | ||
275 | 0x75, 0x0, | ||
276 | 0x76, 0x0, | ||
277 | 0x81, 0x0, | ||
278 | 0x82, 0x3f, | ||
279 | 0x83, 0x3f, | ||
280 | 0x84, 0x0, | ||
281 | 0x85, 0x0, | ||
282 | 0x88, 0x0, | ||
283 | 0x89, 0x0, | ||
284 | 0x8a, 0x0, | ||
285 | 0x8b, 0x0, | ||
286 | 0x8c, 0x0, | ||
287 | 0x90, 0x0, | ||
288 | 0x91, 0x0, | ||
289 | 0x92, 0x0, | ||
290 | 0x93, 0x0, | ||
291 | 0x94, 0x1c, | ||
292 | 0x97, 0x0, | ||
293 | 0xa0, 0x48, | ||
294 | 0xa1, 0x0, | ||
295 | 0xb0, 0xb8, | ||
296 | 0xb1, 0x3a, | ||
297 | 0xb2, 0x10, | ||
298 | 0xb3, 0x82, | ||
299 | 0xb4, 0x80, | ||
300 | 0xb5, 0x82, | ||
301 | 0xb6, 0x82, | ||
302 | 0xb7, 0x82, | ||
303 | 0xb8, 0x20, | ||
304 | 0xb9, 0x0, | ||
305 | 0xf0, 0x0, | ||
306 | 0xf1, 0x0, | ||
307 | 0xf2, 0xc0, | ||
308 | 0x51, 0x36, | ||
309 | 0x52, 0x09, | ||
310 | 0x53, 0x94, | ||
311 | 0x54, 0x62, | ||
312 | 0x55, 0x29, | ||
313 | 0x56, 0x64, | ||
314 | 0x57, 0x2b, | ||
315 | 0xff, 0xff, | ||
316 | }; | ||
317 | |||
318 | static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) | ||
319 | { | ||
320 | dprintk("%s: %s\n", __func__, | ||
321 | volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : | ||
322 | volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int stv0288_init(struct dvb_frontend *fe) | ||
328 | { | ||
329 | struct stv0288_state *state = fe->demodulator_priv; | ||
330 | int i; | ||
331 | u8 reg; | ||
332 | u8 val; | ||
333 | |||
334 | dprintk("stv0288: init chip\n"); | ||
335 | stv0288_writeregI(state, 0x41, 0x04); | ||
336 | msleep(50); | ||
337 | |||
338 | /* we have default inittab */ | ||
339 | if (state->config->inittab == NULL) { | ||
340 | for (i = 0; !(stv0288_inittab[i] == 0xff && | ||
341 | stv0288_inittab[i + 1] == 0xff); i += 2) | ||
342 | stv0288_writeregI(state, stv0288_inittab[i], | ||
343 | stv0288_inittab[i + 1]); | ||
344 | } else { | ||
345 | for (i = 0; ; i += 2) { | ||
346 | reg = state->config->inittab[i]; | ||
347 | val = state->config->inittab[i+1]; | ||
348 | if (reg == 0xff && val == 0xff) | ||
349 | break; | ||
350 | stv0288_writeregI(state, reg, val); | ||
351 | } | ||
352 | } | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
357 | { | ||
358 | struct stv0288_state *state = fe->demodulator_priv; | ||
359 | |||
360 | u8 sync = stv0288_readreg(state, 0x24); | ||
361 | if (sync == 255) | ||
362 | sync = 0; | ||
363 | |||
364 | dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); | ||
365 | |||
366 | *status = 0; | ||
367 | |||
368 | if ((sync & 0x08) == 0x08) { | ||
369 | *status |= FE_HAS_LOCK; | ||
370 | dprintk("stv0288 has locked\n"); | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
377 | { | ||
378 | struct stv0288_state *state = fe->demodulator_priv; | ||
379 | |||
380 | if (state->errmode != STATUS_BER) | ||
381 | return 0; | ||
382 | *ber = (stv0288_readreg(state, 0x26) << 8) | | ||
383 | stv0288_readreg(state, 0x27); | ||
384 | dprintk("stv0288_read_ber %d\n", *ber); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | |||
390 | static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | ||
391 | { | ||
392 | struct stv0288_state *state = fe->demodulator_priv; | ||
393 | |||
394 | s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8)); | ||
395 | |||
396 | |||
397 | signal = signal * 5 / 4; | ||
398 | *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; | ||
399 | dprintk("stv0288_read_signal_strength %d\n", *strength); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | static int stv0288_sleep(struct dvb_frontend *fe) | ||
404 | { | ||
405 | struct stv0288_state *state = fe->demodulator_priv; | ||
406 | |||
407 | stv0288_writeregI(state, 0x41, 0x84); | ||
408 | state->initialised = 0; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
413 | { | ||
414 | struct stv0288_state *state = fe->demodulator_priv; | ||
415 | |||
416 | s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8) | ||
417 | | stv0288_readreg(state, 0x2e)); | ||
418 | xsnr = 3 * (xsnr - 0xa100); | ||
419 | *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; | ||
420 | dprintk("stv0288_read_snr %d\n", *snr); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
426 | { | ||
427 | struct stv0288_state *state = fe->demodulator_priv; | ||
428 | |||
429 | if (state->errmode != STATUS_BER) | ||
430 | return 0; | ||
431 | *ucblocks = (stv0288_readreg(state, 0x26) << 8) | | ||
432 | stv0288_readreg(state, 0x27); | ||
433 | dprintk("stv0288_read_ber %d\n", *ucblocks); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
439 | { | ||
440 | dprintk("%s(..)\n", __func__); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) | ||
445 | { | ||
446 | dprintk("%s(..)\n", __func__); | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int stv0288_set_frontend(struct dvb_frontend *fe, | ||
451 | struct dvb_frontend_parameters *dfp) | ||
452 | { | ||
453 | struct stv0288_state *state = fe->demodulator_priv; | ||
454 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
455 | |||
456 | char tm; | ||
457 | unsigned char tda[3]; | ||
458 | |||
459 | dprintk("%s : FE_SET_FRONTEND\n", __func__); | ||
460 | |||
461 | if (c->delivery_system != SYS_DVBS) { | ||
462 | dprintk("%s: unsupported delivery " | ||
463 | "system selected (%d)\n", | ||
464 | __func__, c->delivery_system); | ||
465 | return -EOPNOTSUPP; | ||
466 | } | ||
467 | |||
468 | if (state->config->set_ts_params) | ||
469 | state->config->set_ts_params(fe, 0); | ||
470 | |||
471 | /* only frequency & symbol_rate are used for tuner*/ | ||
472 | dfp->frequency = c->frequency; | ||
473 | dfp->u.qpsk.symbol_rate = c->symbol_rate; | ||
474 | if (fe->ops.tuner_ops.set_params) { | ||
475 | fe->ops.tuner_ops.set_params(fe, dfp); | ||
476 | if (fe->ops.i2c_gate_ctrl) | ||
477 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
478 | } | ||
479 | |||
480 | udelay(10); | ||
481 | stv0288_set_symbolrate(fe, c->symbol_rate); | ||
482 | /* Carrier lock control register */ | ||
483 | stv0288_writeregI(state, 0x15, 0xc5); | ||
484 | |||
485 | tda[0] = 0x2b; /* CFRM */ | ||
486 | tda[2] = 0x0; /* CFRL */ | ||
487 | for (tm = -6; tm < 7;) { | ||
488 | /* Viterbi status */ | ||
489 | if (stv0288_readreg(state, 0x24) & 0x80) | ||
490 | break; | ||
491 | |||
492 | tda[2] += 40; | ||
493 | if (tda[2] < 40) | ||
494 | tm++; | ||
495 | tda[1] = (unsigned char)tm; | ||
496 | stv0288_writeregI(state, 0x2b, tda[1]); | ||
497 | stv0288_writeregI(state, 0x2c, tda[2]); | ||
498 | udelay(30); | ||
499 | } | ||
500 | |||
501 | state->tuner_frequency = c->frequency; | ||
502 | state->fec_inner = FEC_AUTO; | ||
503 | state->symbol_rate = c->symbol_rate; | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
509 | { | ||
510 | struct stv0288_state *state = fe->demodulator_priv; | ||
511 | |||
512 | if (enable) | ||
513 | stv0288_writeregI(state, 0x01, 0xb5); | ||
514 | else | ||
515 | stv0288_writeregI(state, 0x01, 0x35); | ||
516 | |||
517 | udelay(1); | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static void stv0288_release(struct dvb_frontend *fe) | ||
523 | { | ||
524 | struct stv0288_state *state = fe->demodulator_priv; | ||
525 | kfree(state); | ||
526 | } | ||
527 | |||
528 | static struct dvb_frontend_ops stv0288_ops = { | ||
529 | |||
530 | .info = { | ||
531 | .name = "ST STV0288 DVB-S", | ||
532 | .type = FE_QPSK, | ||
533 | .frequency_min = 950000, | ||
534 | .frequency_max = 2150000, | ||
535 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | ||
536 | .frequency_tolerance = 0, | ||
537 | .symbol_rate_min = 1000000, | ||
538 | .symbol_rate_max = 45000000, | ||
539 | .symbol_rate_tolerance = 500, /* ppm */ | ||
540 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
541 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
542 | FE_CAN_QPSK | | ||
543 | FE_CAN_FEC_AUTO | ||
544 | }, | ||
545 | |||
546 | .release = stv0288_release, | ||
547 | .init = stv0288_init, | ||
548 | .sleep = stv0288_sleep, | ||
549 | .write = stv0288_write, | ||
550 | .i2c_gate_ctrl = stv0288_i2c_gate_ctrl, | ||
551 | .read_status = stv0288_read_status, | ||
552 | .read_ber = stv0288_read_ber, | ||
553 | .read_signal_strength = stv0288_read_signal_strength, | ||
554 | .read_snr = stv0288_read_snr, | ||
555 | .read_ucblocks = stv0288_read_ucblocks, | ||
556 | .diseqc_send_master_cmd = stv0288_send_diseqc_msg, | ||
557 | .diseqc_send_burst = stv0288_send_diseqc_burst, | ||
558 | .set_tone = stv0288_set_tone, | ||
559 | .set_voltage = stv0288_set_voltage, | ||
560 | |||
561 | .set_property = stv0288_set_property, | ||
562 | .get_property = stv0288_get_property, | ||
563 | .set_frontend = stv0288_set_frontend, | ||
564 | }; | ||
565 | |||
566 | struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, | ||
567 | struct i2c_adapter *i2c) | ||
568 | { | ||
569 | struct stv0288_state *state = NULL; | ||
570 | int id; | ||
571 | |||
572 | /* allocate memory for the internal state */ | ||
573 | state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL); | ||
574 | if (state == NULL) | ||
575 | goto error; | ||
576 | |||
577 | /* setup the state */ | ||
578 | state->config = config; | ||
579 | state->i2c = i2c; | ||
580 | state->initialised = 0; | ||
581 | state->tuner_frequency = 0; | ||
582 | state->symbol_rate = 0; | ||
583 | state->fec_inner = 0; | ||
584 | state->errmode = STATUS_BER; | ||
585 | |||
586 | stv0288_writeregI(state, 0x41, 0x04); | ||
587 | msleep(200); | ||
588 | id = stv0288_readreg(state, 0x00); | ||
589 | dprintk("stv0288 id %x\n", id); | ||
590 | |||
591 | /* register 0x00 contains 0x11 for STV0288 */ | ||
592 | if (id != 0x11) | ||
593 | goto error; | ||
594 | |||
595 | /* create dvb_frontend */ | ||
596 | memcpy(&state->frontend.ops, &stv0288_ops, | ||
597 | sizeof(struct dvb_frontend_ops)); | ||
598 | state->frontend.demodulator_priv = state; | ||
599 | return &state->frontend; | ||
600 | |||
601 | error: | ||
602 | kfree(state); | ||
603 | |||
604 | return NULL; | ||
605 | } | ||
606 | EXPORT_SYMBOL(stv0288_attach); | ||
607 | |||
608 | module_param(debug_legacy_dish_switch, int, 0444); | ||
609 | MODULE_PARM_DESC(debug_legacy_dish_switch, | ||
610 | "Enable timing analysis for Dish Network legacy switches"); | ||
611 | |||
612 | module_param(debug, int, 0644); | ||
613 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
614 | |||
615 | MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver"); | ||
616 | MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin"); | ||
617 | MODULE_LICENSE("GPL"); | ||
618 | |||
diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h new file mode 100644 index 000000000000..f2b53db0606d --- /dev/null +++ b/drivers/media/dvb/frontends/stv0288.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | Driver for ST STV0288 demodulator | ||
3 | |||
4 | Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de | ||
5 | for Reel Multimedia | ||
6 | Copyright (C) 2008 TurboSight.com, <bob@turbosight.com> | ||
7 | Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by> | ||
8 | Removed stb6000 specific tuner code and revised some | ||
9 | procedures. | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | |||
25 | */ | ||
26 | |||
27 | #ifndef STV0288_H | ||
28 | #define STV0288_H | ||
29 | |||
30 | #include <linux/dvb/frontend.h> | ||
31 | #include "dvb_frontend.h" | ||
32 | |||
33 | struct stv0288_config { | ||
34 | /* the demodulator's i2c address */ | ||
35 | u8 demod_address; | ||
36 | |||
37 | u8* inittab; | ||
38 | |||
39 | /* minimum delay before retuning */ | ||
40 | int min_delay_ms; | ||
41 | |||
42 | int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); | ||
43 | }; | ||
44 | |||
45 | #if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \ | ||
46 | defined(MODULE)) | ||
47 | extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, | ||
48 | struct i2c_adapter *i2c); | ||
49 | #else | ||
50 | static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, | ||
51 | struct i2c_adapter *i2c) | ||
52 | { | ||
53 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
54 | return NULL; | ||
55 | } | ||
56 | #endif /* CONFIG_DVB_STV0288 */ | ||
57 | |||
58 | static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val) | ||
59 | { | ||
60 | int r = 0; | ||
61 | u8 buf[] = { reg, val }; | ||
62 | if (fe->ops.write) | ||
63 | r = fe->ops.write(fe, buf, 2); | ||
64 | return r; | ||
65 | } | ||
66 | |||
67 | #endif /* STV0288_H */ | ||
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 35435bef8e79..6c1cb1973c6e 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c | |||
@@ -559,6 +559,8 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par | |||
559 | int invval = 0; | 559 | int invval = 0; |
560 | 560 | ||
561 | dprintk ("%s : FE_SET_FRONTEND\n", __func__); | 561 | dprintk ("%s : FE_SET_FRONTEND\n", __func__); |
562 | if (state->config->set_ts_params) | ||
563 | state->config->set_ts_params(fe, 0); | ||
562 | 564 | ||
563 | // set the inversion | 565 | // set the inversion |
564 | if (p->inversion == INVERSION_OFF) invval = 0; | 566 | if (p->inversion == INVERSION_OFF) invval = 0; |
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 3282f43022f5..0fd96e22b650 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h | |||
@@ -89,15 +89,18 @@ struct stv0299_config | |||
89 | int min_delay_ms; | 89 | int min_delay_ms; |
90 | 90 | ||
91 | /* Set the symbol rate */ | 91 | /* Set the symbol rate */ |
92 | int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); | 92 | int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio); |
93 | |||
94 | /* Set device param to start dma */ | ||
95 | int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); | ||
93 | }; | 96 | }; |
94 | 97 | ||
95 | #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) | 98 | #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) |
96 | extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, | 99 | extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, |
97 | struct i2c_adapter* i2c); | 100 | struct i2c_adapter *i2c); |
98 | #else | 101 | #else |
99 | static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, | 102 | static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, |
100 | struct i2c_adapter* i2c) | 103 | struct i2c_adapter *i2c) |
101 | { | 104 | { |
102 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 105 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); |
103 | return NULL; | 106 | return NULL; |
diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h new file mode 100644 index 000000000000..51f170678650 --- /dev/null +++ b/drivers/media/dvb/frontends/tdhd1.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * tdhd1.h - ALPS TDHD1-204A tuner support | ||
3 | * | ||
4 | * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2 | ||
10 | * of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
21 | * | ||
22 | * | ||
23 | * The project's page is at http://www.linuxtv.org | ||
24 | */ | ||
25 | |||
26 | #ifndef TDHD1_H | ||
27 | #define TDHD1_H | ||
28 | |||
29 | #include "tda1004x.h" | ||
30 | |||
31 | static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name); | ||
32 | |||
33 | static struct tda1004x_config alps_tdhd1_204a_config = { | ||
34 | .demod_address = 0x8, | ||
35 | .invert = 1, | ||
36 | .invert_oclk = 0, | ||
37 | .xtal_freq = TDA10046_XTAL_4M, | ||
38 | .agc_config = TDA10046_AGC_DEFAULT, | ||
39 | .if_freq = TDA10046_FREQ_3617, | ||
40 | .request_firmware = alps_tdhd1_204_request_firmware | ||
41 | }; | ||
42 | |||
43 | static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
44 | { | ||
45 | struct i2c_adapter *i2c = fe->tuner_priv; | ||
46 | u8 data[4]; | ||
47 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
48 | u32 div; | ||
49 | |||
50 | div = (params->frequency + 36166666) / 166666; | ||
51 | |||
52 | data[0] = (div >> 8) & 0x7f; | ||
53 | data[1] = div & 0xff; | ||
54 | data[2] = 0x85; | ||
55 | |||
56 | if (params->frequency >= 174000000 && params->frequency <= 230000000) | ||
57 | data[3] = 0x02; | ||
58 | else if (params->frequency >= 470000000 && params->frequency <= 823000000) | ||
59 | data[3] = 0x0C; | ||
60 | else if (params->frequency > 823000000 && params->frequency <= 862000000) | ||
61 | data[3] = 0x8C; | ||
62 | else | ||
63 | return -EINVAL; | ||
64 | |||
65 | if (fe->ops.i2c_gate_ctrl) | ||
66 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
67 | if (i2c_transfer(i2c, &msg, 1) != 1) | ||
68 | return -EIO; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | #endif /* TDHD1_H */ | ||
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 41b5a988b619..867027ceab3e 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig | |||
@@ -86,6 +86,7 @@ config DVB_BUDGET | |||
86 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE | 86 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE |
87 | select DVB_TDA826X if !DVB_FE_CUSTOMISE | 87 | select DVB_TDA826X if !DVB_FE_CUSTOMISE |
88 | select DVB_LNBP21 if !DVB_FE_CUSTOMISE | 88 | select DVB_LNBP21 if !DVB_FE_CUSTOMISE |
89 | select DVB_TDA1004X if !DVB_FE_CUSTOMISE | ||
89 | help | 90 | help |
90 | Support for simple SAA7146 based DVB cards (so called Budget- | 91 | Support for simple SAA7146 based DVB cards (so called Budget- |
91 | or Nova-PCI cards) without onboard MPEG2 decoder, and without | 92 | or Nova-PCI cards) without onboard MPEG2 decoder, and without |
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 0777e8f9544b..c7c770c28988 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c | |||
@@ -88,6 +88,7 @@ static int budgetpatch; | |||
88 | static int wss_cfg_4_3 = 0x4008; | 88 | static int wss_cfg_4_3 = 0x4008; |
89 | static int wss_cfg_16_9 = 0x0007; | 89 | static int wss_cfg_16_9 = 0x0007; |
90 | static int tv_standard; | 90 | static int tv_standard; |
91 | static int full_ts; | ||
91 | 92 | ||
92 | module_param_named(debug, av7110_debug, int, 0644); | 93 | module_param_named(debug, av7110_debug, int, 0644); |
93 | MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); | 94 | MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); |
@@ -106,6 +107,8 @@ module_param(volume, int, 0444); | |||
106 | MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); | 107 | MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); |
107 | module_param(budgetpatch, int, 0444); | 108 | module_param(budgetpatch, int, 0444); |
108 | MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); | 109 | MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); |
110 | module_param(full_ts, int, 0444); | ||
111 | MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); | ||
109 | module_param(wss_cfg_4_3, int, 0444); | 112 | module_param(wss_cfg_4_3, int, 0444); |
110 | MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); | 113 | MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); |
111 | module_param(wss_cfg_16_9, int, 0444); | 114 | module_param(wss_cfg_16_9, int, 0444); |
@@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); | |||
116 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 119 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
117 | 120 | ||
118 | static void restart_feeds(struct av7110 *av7110); | 121 | static void restart_feeds(struct av7110 *av7110); |
122 | static int budget_start_feed(struct dvb_demux_feed *feed); | ||
123 | static int budget_stop_feed(struct dvb_demux_feed *feed); | ||
119 | 124 | ||
120 | static int av7110_num; | 125 | static int av7110_num; |
121 | 126 | ||
@@ -376,9 +381,9 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir, | |||
376 | irdebi(av7110, DEBISWAB, addr, 0, len); | 381 | irdebi(av7110, DEBISWAB, addr, 0, len); |
377 | } | 382 | } |
378 | 383 | ||
379 | static void debiirq(unsigned long data) | 384 | static void debiirq(unsigned long cookie) |
380 | { | 385 | { |
381 | struct av7110 *av7110 = (struct av7110 *) data; | 386 | struct av7110 *av7110 = (struct av7110 *)cookie; |
382 | int type = av7110->debitype; | 387 | int type = av7110->debitype; |
383 | int handle = (type >> 8) & 0x1f; | 388 | int handle = (type >> 8) & 0x1f; |
384 | unsigned int xfer = 0; | 389 | unsigned int xfer = 0; |
@@ -487,9 +492,9 @@ debi_done: | |||
487 | } | 492 | } |
488 | 493 | ||
489 | /* irq from av7110 firmware writing the mailbox register in the DPRAM */ | 494 | /* irq from av7110 firmware writing the mailbox register in the DPRAM */ |
490 | static void gpioirq(unsigned long data) | 495 | static void gpioirq(unsigned long cookie) |
491 | { | 496 | { |
492 | struct av7110 *av7110 = (struct av7110 *) data; | 497 | struct av7110 *av7110 = (struct av7110 *)cookie; |
493 | u32 rxbuf, txbuf; | 498 | u32 rxbuf, txbuf; |
494 | int len; | 499 | int len; |
495 | 500 | ||
@@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) | |||
806 | 811 | ||
807 | dprintk(4, "%p\n", av7110); | 812 | dprintk(4, "%p\n", av7110); |
808 | 813 | ||
814 | if (av7110->full_ts) | ||
815 | return 0; | ||
816 | |||
809 | if (dvbdmxfilter->type == DMX_TYPE_SEC) { | 817 | if (dvbdmxfilter->type == DMX_TYPE_SEC) { |
810 | if (hw_sections) { | 818 | if (hw_sections) { |
811 | buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | | 819 | buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | |
@@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) | |||
854 | 862 | ||
855 | dprintk(4, "%p\n", av7110); | 863 | dprintk(4, "%p\n", av7110); |
856 | 864 | ||
865 | if (av7110->full_ts) | ||
866 | return 0; | ||
867 | |||
857 | handle = dvbdmxfilter->hw_handle; | 868 | handle = dvbdmxfilter->hw_handle; |
858 | if (handle >= 32) { | 869 | if (handle >= 32) { |
859 | printk("%s tried to stop invalid filter %04x, filter type = %x\n", | 870 | 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) | |||
913 | return ret; | 924 | return ret; |
914 | } | 925 | } |
915 | 926 | ||
916 | if ((dvbdmxfeed->ts_type & TS_PACKET)) { | 927 | if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { |
917 | if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) | 928 | if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) |
918 | ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); | 929 | ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); |
919 | if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) | 930 | if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) |
@@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) | |||
974 | if (!demux->dmx.frontend) | 985 | if (!demux->dmx.frontend) |
975 | return -EINVAL; | 986 | return -EINVAL; |
976 | 987 | ||
977 | if (feed->pid > 0x1fff) | 988 | if (!av7110->full_ts && feed->pid > 0x1fff) |
978 | return -EINVAL; | 989 | return -EINVAL; |
979 | 990 | ||
980 | if (feed->type == DMX_TYPE_TS) { | 991 | if (feed->type == DMX_TYPE_TS) { |
@@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) | |||
1003 | } | 1014 | } |
1004 | } | 1015 | } |
1005 | 1016 | ||
1006 | else if (feed->type == DMX_TYPE_SEC) { | 1017 | if (av7110->full_ts) { |
1018 | budget_start_feed(feed); | ||
1019 | return ret; | ||
1020 | } | ||
1021 | |||
1022 | if (feed->type == DMX_TYPE_SEC) { | ||
1007 | int i; | 1023 | int i; |
1008 | 1024 | ||
1009 | for (i = 0; i < demux->filternum; i++) { | 1025 | for (i = 0; i < demux->filternum; i++) { |
@@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) | |||
1050 | ret = StopHWFilter(feed->filter); | 1066 | ret = StopHWFilter(feed->filter); |
1051 | } | 1067 | } |
1052 | 1068 | ||
1053 | if (!ret && feed->type == DMX_TYPE_SEC) { | 1069 | if (av7110->full_ts) { |
1070 | budget_stop_feed(feed); | ||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
1074 | if (feed->type == DMX_TYPE_SEC) { | ||
1054 | for (i = 0; i<demux->filternum; i++) { | 1075 | for (i = 0; i<demux->filternum; i++) { |
1055 | if (demux->filter[i].state == DMX_STATE_GO && | 1076 | if (demux->filter[i].state == DMX_STATE_GO && |
1056 | demux->filter[i].filter.parent == &feed->feed.sec) { | 1077 | demux->filter[i].filter.parent == &feed->feed.sec) { |
@@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110) | |||
1074 | struct dvb_demux *dvbdmx = &av7110->demux; | 1095 | struct dvb_demux *dvbdmx = &av7110->demux; |
1075 | struct dvb_demux_feed *feed; | 1096 | struct dvb_demux_feed *feed; |
1076 | int mode; | 1097 | int mode; |
1098 | int feeding; | ||
1077 | int i, j; | 1099 | int i, j; |
1078 | 1100 | ||
1079 | dprintk(4, "%p\n", av7110); | 1101 | dprintk(4, "%p\n", av7110); |
@@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110) | |||
1082 | av7110->playing = 0; | 1104 | av7110->playing = 0; |
1083 | av7110->rec_mode = 0; | 1105 | av7110->rec_mode = 0; |
1084 | 1106 | ||
1107 | feeding = av7110->feeding1; /* full_ts mod */ | ||
1108 | |||
1085 | for (i = 0; i < dvbdmx->feednum; i++) { | 1109 | for (i = 0; i < dvbdmx->feednum; i++) { |
1086 | feed = &dvbdmx->feed[i]; | 1110 | feed = &dvbdmx->feed[i]; |
1087 | if (feed->state == DMX_STATE_GO) { | 1111 | if (feed->state == DMX_STATE_GO) { |
@@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110) | |||
1099 | } | 1123 | } |
1100 | } | 1124 | } |
1101 | 1125 | ||
1126 | av7110->feeding1 = feeding; /* full_ts mod */ | ||
1127 | |||
1102 | if (mode) | 1128 | if (mode) |
1103 | av7110_av_start_play(av7110, mode); | 1129 | av7110_av_start_play(av7110, mode); |
1104 | } | 1130 | } |
@@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget) | |||
1197 | 1223 | ||
1198 | if (budget->feeding1) | 1224 | if (budget->feeding1) |
1199 | return ++budget->feeding1; | 1225 | return ++budget->feeding1; |
1200 | memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); | 1226 | memset(budget->grabbing, 0x00, TS_BUFLEN); |
1201 | budget->ttbp = 0; | 1227 | budget->ttbp = 0; |
1228 | SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ | ||
1202 | SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ | 1229 | SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ |
1203 | saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ | 1230 | saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ |
1204 | return ++budget->feeding1; | 1231 | return ++budget->feeding1; |
@@ -1233,18 +1260,14 @@ static int budget_stop_feed(struct dvb_demux_feed *feed) | |||
1233 | return status; | 1260 | return status; |
1234 | } | 1261 | } |
1235 | 1262 | ||
1236 | static void vpeirq(unsigned long data) | 1263 | static void vpeirq(unsigned long cookie) |
1237 | { | 1264 | { |
1238 | struct av7110 *budget = (struct av7110 *) data; | 1265 | struct av7110 *budget = (struct av7110 *)cookie; |
1239 | u8 *mem = (u8 *) (budget->grabbing); | 1266 | u8 *mem = (u8 *) (budget->grabbing); |
1240 | u32 olddma = budget->ttbp; | 1267 | u32 olddma = budget->ttbp; |
1241 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); | 1268 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); |
1269 | struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; | ||
1242 | 1270 | ||
1243 | if (!budgetpatch) { | ||
1244 | printk("av7110.c: vpeirq() called while budgetpatch disabled!" | ||
1245 | " check saa7146 IER register\n"); | ||
1246 | BUG(); | ||
1247 | } | ||
1248 | /* nearest lower position divisible by 188 */ | 1271 | /* nearest lower position divisible by 188 */ |
1249 | newdma -= newdma % 188; | 1272 | newdma -= newdma % 188; |
1250 | 1273 | ||
@@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data) | |||
1268 | 1291 | ||
1269 | if (newdma > olddma) | 1292 | if (newdma > olddma) |
1270 | /* no wraparound, dump olddma..newdma */ | 1293 | /* no wraparound, dump olddma..newdma */ |
1271 | dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188); | 1294 | dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); |
1272 | else { | 1295 | else { |
1273 | /* wraparound, dump olddma..buflen and 0..newdma */ | 1296 | /* wraparound, dump olddma..buflen and 0..newdma */ |
1274 | dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188); | 1297 | dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); |
1275 | dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188); | 1298 | dvb_dmx_swfilter_packets(demux, mem, newdma / 188); |
1276 | } | 1299 | } |
1277 | } | 1300 | } |
1278 | 1301 | ||
@@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110) | |||
1294 | for (i = 0; i < 32; i++) | 1317 | for (i = 0; i < 32; i++) |
1295 | av7110->handle2filter[i] = NULL; | 1318 | av7110->handle2filter[i] = NULL; |
1296 | 1319 | ||
1297 | dvbdemux->filternum = 32; | 1320 | dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; |
1298 | dvbdemux->feednum = 32; | 1321 | dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; |
1299 | dvbdemux->start_feed = av7110_start_feed; | 1322 | dvbdemux->start_feed = av7110_start_feed; |
1300 | dvbdemux->stop_feed = av7110_stop_feed; | 1323 | dvbdemux->stop_feed = av7110_stop_feed; |
1301 | dvbdemux->write_to_decoder = av7110_write_to_decoder; | 1324 | dvbdemux->write_to_decoder = av7110_write_to_decoder; |
@@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110) | |||
1305 | dvb_dmx_init(&av7110->demux); | 1328 | dvb_dmx_init(&av7110->demux); |
1306 | av7110->demux.dmx.get_stc = dvb_get_stc; | 1329 | av7110->demux.dmx.get_stc = dvb_get_stc; |
1307 | 1330 | ||
1308 | av7110->dmxdev.filternum = 32; | 1331 | av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; |
1309 | av7110->dmxdev.demux = &dvbdemux->dmx; | 1332 | av7110->dmxdev.demux = &dvbdemux->dmx; |
1310 | av7110->dmxdev.capabilities = 0; | 1333 | av7110->dmxdev.capabilities = 0; |
1311 | 1334 | ||
@@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) | |||
1422 | return i2c_transfer(&av7110->i2c_adap, &msgs, 1); | 1445 | return i2c_transfer(&av7110->i2c_adap, &msgs, 1); |
1423 | } | 1446 | } |
1424 | 1447 | ||
1425 | #if 0 | ||
1426 | u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) | 1448 | u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) |
1427 | { | 1449 | { |
1428 | u8 mm1[] = {0x00}; | 1450 | u8 mm1[] = {0x00}; |
@@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) | |||
1439 | 1461 | ||
1440 | return mm2[0]; | 1462 | return mm2[0]; |
1441 | } | 1463 | } |
1442 | #endif | ||
1443 | 1464 | ||
1444 | /**************************************************************************** | 1465 | /**************************************************************************** |
1445 | * INITIALIZATION | 1466 | * INITIALIZATION |
@@ -2256,7 +2277,7 @@ static int frontend_init(struct av7110 *av7110) | |||
2256 | if (!av7110->fe) { | 2277 | if (!av7110->fe) { |
2257 | /* FIXME: propagate the failure code from the lower layers */ | 2278 | /* FIXME: propagate the failure code from the lower layers */ |
2258 | ret = -ENOMEM; | 2279 | ret = -ENOMEM; |
2259 | printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", | 2280 | printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", |
2260 | av7110->dev->pci->vendor, | 2281 | av7110->dev->pci->vendor, |
2261 | av7110->dev->pci->device, | 2282 | av7110->dev->pci->device, |
2262 | av7110->dev->pci->subsystem_vendor, | 2283 | av7110->dev->pci->subsystem_vendor, |
@@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, | |||
2484 | av7110->dvb_adapter.proposed_mac); | 2505 | av7110->dvb_adapter.proposed_mac); |
2485 | ret = -ENOMEM; | 2506 | ret = -ENOMEM; |
2486 | 2507 | ||
2487 | if (budgetpatch) { | 2508 | /* full-ts mod? */ |
2509 | if (full_ts) | ||
2510 | av7110->full_ts = true; | ||
2511 | |||
2512 | /* check for full-ts flag in eeprom */ | ||
2513 | if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { | ||
2514 | u8 flags = i2c_readreg(av7110, 0xaa, 2); | ||
2515 | if (flags != 0xff && (flags & 0x01)) | ||
2516 | av7110->full_ts = true; | ||
2517 | } | ||
2518 | |||
2519 | if (av7110->full_ts) { | ||
2520 | printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); | ||
2521 | spin_lock_init(&av7110->feedlock1); | ||
2522 | av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, | ||
2523 | &av7110->pt); | ||
2524 | if (!av7110->grabbing) | ||
2525 | goto err_i2c_del_3; | ||
2526 | |||
2527 | saa7146_write(dev, DD1_STREAM_B, 0x00000000); | ||
2528 | saa7146_write(dev, MC2, (MASK_10 | MASK_26)); | ||
2529 | |||
2530 | saa7146_write(dev, DD1_INIT, 0x00000600); | ||
2531 | saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); | ||
2532 | |||
2533 | saa7146_write(dev, BRS_CTRL, 0x60000000); | ||
2534 | saa7146_write(dev, MC2, MASK_08 | MASK_24); | ||
2535 | |||
2536 | /* dma3 */ | ||
2537 | saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); | ||
2538 | saa7146_write(dev, BASE_ODD3, 0); | ||
2539 | saa7146_write(dev, BASE_EVEN3, 0); | ||
2540 | saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); | ||
2541 | saa7146_write(dev, PITCH3, TS_WIDTH); | ||
2542 | saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); | ||
2543 | saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); | ||
2544 | saa7146_write(dev, MC2, MASK_04 | MASK_20); | ||
2545 | |||
2546 | tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); | ||
2547 | |||
2548 | } else if (budgetpatch) { | ||
2488 | spin_lock_init(&av7110->feedlock1); | 2549 | spin_lock_init(&av7110->feedlock1); |
2489 | av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, | 2550 | av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, |
2490 | &av7110->pt); | 2551 | &av7110->pt); |
@@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa) | |||
2710 | #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) | 2771 | #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) |
2711 | av7110_ir_exit(av7110); | 2772 | av7110_ir_exit(av7110); |
2712 | #endif | 2773 | #endif |
2713 | if (budgetpatch) { | 2774 | if (budgetpatch || av7110->full_ts) { |
2714 | /* Disable RPS1 */ | 2775 | if (budgetpatch) { |
2715 | saa7146_write(saa, MC1, MASK_29); | 2776 | /* Disable RPS1 */ |
2716 | /* VSYNC LOW (inactive) */ | 2777 | saa7146_write(saa, MC1, MASK_29); |
2717 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); | 2778 | /* VSYNC LOW (inactive) */ |
2779 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); | ||
2780 | } | ||
2718 | saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ | 2781 | saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ |
2719 | SAA7146_IER_DISABLE(saa, MASK_10); | 2782 | SAA7146_IER_DISABLE(saa, MASK_10); |
2720 | SAA7146_ISR_CLEAR(saa, MASK_10); | 2783 | SAA7146_ISR_CLEAR(saa, MASK_10); |
@@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr) | |||
2794 | tasklet_schedule(&av7110->gpio_tasklet); | 2857 | tasklet_schedule(&av7110->gpio_tasklet); |
2795 | } | 2858 | } |
2796 | 2859 | ||
2797 | if ((*isr & MASK_10) && budgetpatch) | 2860 | if (*isr & MASK_10) |
2798 | tasklet_schedule(&av7110->vpe_tasklet); | 2861 | tasklet_schedule(&av7110->vpe_tasklet); |
2799 | } | 2862 | } |
2800 | 2863 | ||
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 55f23ddcb994..d85b8512ac30 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h | |||
@@ -192,6 +192,7 @@ struct av7110 { | |||
192 | unsigned char *grabbing; | 192 | unsigned char *grabbing; |
193 | struct saa7146_pgtable pt; | 193 | struct saa7146_pgtable pt; |
194 | struct tasklet_struct vpe_tasklet; | 194 | struct tasklet_struct vpe_tasklet; |
195 | bool full_ts; | ||
195 | 196 | ||
196 | int fe_synced; | 197 | int fe_synced; |
197 | struct mutex pid_mutex; | 198 | struct mutex pid_mutex; |
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 184647ad1c7c..bdc62acf2099 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l | |||
788 | 788 | ||
789 | dprintk(2, "av7110:%p, \n", av7110); | 789 | dprintk(2, "av7110:%p, \n", av7110); |
790 | 790 | ||
791 | if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) | ||
792 | return 0; | ||
793 | |||
791 | switch (feed->pes_type) { | 794 | switch (feed->pes_type) { |
792 | case 0: | 795 | case 0: |
793 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) | 796 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index b7d1f2f18d3a..1032ea77837e 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c | |||
@@ -57,6 +57,8 @@ | |||
57 | #define SLOTSTATUS_READY 8 | 57 | #define SLOTSTATUS_READY 8 |
58 | #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) | 58 | #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) |
59 | 59 | ||
60 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
61 | |||
60 | struct budget_av { | 62 | struct budget_av { |
61 | struct budget budget; | 63 | struct budget budget; |
62 | struct video_device *vd; | 64 | struct video_device *vd; |
@@ -1049,7 +1051,7 @@ static void frontend_init(struct budget_av *budget_av) | |||
1049 | 1051 | ||
1050 | if (fe == NULL) { | 1052 | if (fe == NULL) { |
1051 | printk(KERN_ERR "budget-av: A frontend driver was not found " | 1053 | printk(KERN_ERR "budget-av: A frontend driver was not found " |
1052 | "for device %04x/%04x subsystem %04x/%04x\n", | 1054 | "for device [%04x:%04x] subsystem [%04x:%04x]\n", |
1053 | saa->pci->vendor, | 1055 | saa->pci->vendor, |
1054 | saa->pci->device, | 1056 | saa->pci->device, |
1055 | saa->pci->subsystem_vendor, | 1057 | saa->pci->subsystem_vendor, |
@@ -1127,7 +1129,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio | |||
1127 | 1129 | ||
1128 | dev->ext_priv = budget_av; | 1130 | dev->ext_priv = budget_av; |
1129 | 1131 | ||
1130 | if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) { | 1132 | err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, |
1133 | adapter_nr); | ||
1134 | if (err) { | ||
1131 | kfree(budget_av); | 1135 | kfree(budget_av); |
1132 | return err; | 1136 | return err; |
1133 | } | 1137 | } |
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 060e7c785326..0a5aad45435d 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c | |||
@@ -92,6 +92,8 @@ static int ir_debug; | |||
92 | module_param(ir_debug, int, 0644); | 92 | module_param(ir_debug, int, 0644); |
93 | MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); | 93 | MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); |
94 | 94 | ||
95 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
96 | |||
95 | struct budget_ci_ir { | 97 | struct budget_ci_ir { |
96 | struct input_dev *dev; | 98 | struct input_dev *dev; |
97 | struct tasklet_struct msp430_irq_tasklet; | 99 | struct tasklet_struct msp430_irq_tasklet; |
@@ -1153,7 +1155,7 @@ static void frontend_init(struct budget_ci *budget_ci) | |||
1153 | } | 1155 | } |
1154 | 1156 | ||
1155 | if (budget_ci->budget.dvb_frontend == NULL) { | 1157 | if (budget_ci->budget.dvb_frontend == NULL) { |
1156 | printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", | 1158 | printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", |
1157 | budget_ci->budget.dev->pci->vendor, | 1159 | budget_ci->budget.dev->pci->vendor, |
1158 | budget_ci->budget.dev->pci->device, | 1160 | budget_ci->budget.dev->pci->device, |
1159 | budget_ci->budget.dev->pci->subsystem_vendor, | 1161 | budget_ci->budget.dev->pci->subsystem_vendor, |
@@ -1183,7 +1185,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio | |||
1183 | 1185 | ||
1184 | dev->ext_priv = budget_ci; | 1186 | dev->ext_priv = budget_ci; |
1185 | 1187 | ||
1186 | err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE); | 1188 | err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, |
1189 | adapter_nr); | ||
1187 | if (err) | 1190 | if (err) |
1188 | goto out2; | 1191 | goto out2; |
1189 | 1192 | ||
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 6f4ddb643fee..ba18e56d5f11 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c | |||
@@ -57,8 +57,6 @@ module_param_named(bufsize, dma_buffer_size, int, 0444); | |||
57 | MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); | 57 | MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); |
58 | MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); | 58 | MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); |
59 | 59 | ||
60 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
61 | |||
62 | /**************************************************************************** | 60 | /**************************************************************************** |
63 | * TT budget / WinTV Nova | 61 | * TT budget / WinTV Nova |
64 | ****************************************************************************/ | 62 | ****************************************************************************/ |
@@ -411,7 +409,7 @@ static void budget_unregister(struct budget *budget) | |||
411 | 409 | ||
412 | int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | 410 | int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, |
413 | struct saa7146_pci_extension_data *info, | 411 | struct saa7146_pci_extension_data *info, |
414 | struct module *owner) | 412 | struct module *owner, short *adapter_nums) |
415 | { | 413 | { |
416 | int ret = 0; | 414 | int ret = 0; |
417 | struct budget_info *bi = info->ext_priv; | 415 | struct budget_info *bi = info->ext_priv; |
@@ -474,7 +472,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | |||
474 | printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); | 472 | printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); |
475 | 473 | ||
476 | ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, | 474 | ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, |
477 | owner, &budget->dev->pci->dev, adapter_nr); | 475 | owner, &budget->dev->pci->dev, adapter_nums); |
478 | if (ret < 0) | 476 | if (ret < 0) |
479 | return ret; | 477 | return ret; |
480 | 478 | ||
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index aa5ed4ef19f2..60136688a9a4 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c | |||
@@ -39,6 +39,8 @@ | |||
39 | 39 | ||
40 | #include "bsru6.h" | 40 | #include "bsru6.h" |
41 | 41 | ||
42 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
43 | |||
42 | #define budget_patch budget | 44 | #define budget_patch budget |
43 | 45 | ||
44 | static struct saa7146_extension budget_extension; | 46 | static struct saa7146_extension budget_extension; |
@@ -360,7 +362,7 @@ static void frontend_init(struct budget_patch* budget) | |||
360 | } | 362 | } |
361 | 363 | ||
362 | if (budget->dvb_frontend == NULL) { | 364 | if (budget->dvb_frontend == NULL) { |
363 | printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", | 365 | printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", |
364 | budget->dev->pci->vendor, | 366 | budget->dev->pci->vendor, |
365 | budget->dev->pci->device, | 367 | budget->dev->pci->device, |
366 | budget->dev->pci->subsystem_vendor, | 368 | budget->dev->pci->subsystem_vendor, |
@@ -592,8 +594,9 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte | |||
592 | 594 | ||
593 | dprintk(2, "budget: %p\n", budget); | 595 | dprintk(2, "budget: %p\n", budget); |
594 | 596 | ||
595 | if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { | 597 | err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); |
596 | kfree (budget); | 598 | if (err) { |
599 | kfree(budget); | ||
597 | return err; | 600 | return err; |
598 | } | 601 | } |
599 | 602 | ||
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index f0068996ac07..1638e1d9f538 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c | |||
@@ -46,11 +46,14 @@ | |||
46 | #include "lnbp21.h" | 46 | #include "lnbp21.h" |
47 | #include "bsru6.h" | 47 | #include "bsru6.h" |
48 | #include "bsbe1.h" | 48 | #include "bsbe1.h" |
49 | #include "tdhd1.h" | ||
49 | 50 | ||
50 | static int diseqc_method; | 51 | static int diseqc_method; |
51 | module_param(diseqc_method, int, 0444); | 52 | module_param(diseqc_method, int, 0444); |
52 | MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); | 53 | MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); |
53 | 54 | ||
55 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
56 | |||
54 | static void Set22K (struct budget *budget, int state) | 57 | static void Set22K (struct budget *budget, int state) |
55 | { | 58 | { |
56 | struct saa7146_dev *dev=budget->dev; | 59 | struct saa7146_dev *dev=budget->dev; |
@@ -390,6 +393,13 @@ static struct stv0299_config alps_bsbe1_config_activy = { | |||
390 | .set_symbol_rate = alps_bsbe1_set_symbol_rate, | 393 | .set_symbol_rate = alps_bsbe1_set_symbol_rate, |
391 | }; | 394 | }; |
392 | 395 | ||
396 | static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) | ||
397 | { | ||
398 | struct budget *budget = (struct budget *)fe->dvb->priv; | ||
399 | |||
400 | return request_firmware(fw, name, &budget->dev->pci->dev); | ||
401 | } | ||
402 | |||
393 | 403 | ||
394 | static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) | 404 | static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) |
395 | { | 405 | { |
@@ -511,6 +521,14 @@ static void frontend_init(struct budget *budget) | |||
511 | } | 521 | } |
512 | break; | 522 | break; |
513 | 523 | ||
524 | case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ | ||
525 | budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); | ||
526 | if (budget->dvb_frontend) { | ||
527 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; | ||
528 | budget->dvb_frontend->tuner_priv = &budget->i2c_adap; | ||
529 | } | ||
530 | break; | ||
531 | |||
514 | case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ | 532 | case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ |
515 | budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); | 533 | budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); |
516 | if (budget->dvb_frontend) { | 534 | if (budget->dvb_frontend) { |
@@ -550,7 +568,7 @@ static void frontend_init(struct budget *budget) | |||
550 | } | 568 | } |
551 | 569 | ||
552 | if (budget->dvb_frontend == NULL) { | 570 | if (budget->dvb_frontend == NULL) { |
553 | printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", | 571 | printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", |
554 | budget->dev->pci->vendor, | 572 | budget->dev->pci->vendor, |
555 | budget->dev->pci->device, | 573 | budget->dev->pci->device, |
556 | budget->dev->pci->subsystem_vendor, | 574 | budget->dev->pci->subsystem_vendor, |
@@ -582,7 +600,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_ | |||
582 | 600 | ||
583 | dev->ext_priv = budget; | 601 | dev->ext_priv = budget; |
584 | 602 | ||
585 | if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { | 603 | err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); |
604 | if (err) { | ||
586 | printk("==> failed\n"); | 605 | printk("==> failed\n"); |
587 | kfree (budget); | 606 | kfree (budget); |
588 | return err; | 607 | return err; |
@@ -624,6 +643,7 @@ MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); | |||
624 | MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); | 643 | MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); |
625 | MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); | 644 | MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); |
626 | MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); | 645 | MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); |
646 | MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); | ||
627 | 647 | ||
628 | static struct pci_device_id pci_tbl[] = { | 648 | static struct pci_device_id pci_tbl[] = { |
629 | MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), | 649 | MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), |
@@ -634,6 +654,7 @@ static struct pci_device_id pci_tbl[] = { | |||
634 | MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), | 654 | MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), |
635 | MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), | 655 | MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), |
636 | MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), | 656 | MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), |
657 | MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), | ||
637 | MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), | 658 | MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), |
638 | { | 659 | { |
639 | .vendor = 0, | 660 | .vendor = 0, |
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index dd450b739bff..86435bf16260 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h | |||
@@ -109,7 +109,7 @@ static struct saa7146_pci_extension_data x_var = { \ | |||
109 | 109 | ||
110 | extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, | 110 | extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, |
111 | struct saa7146_pci_extension_data *info, | 111 | struct saa7146_pci_extension_data *info, |
112 | struct module *owner); | 112 | struct module *owner, short *adapter_nums); |
113 | extern void ttpci_budget_init_hooks(struct budget *budget); | 113 | extern void ttpci_budget_init_hooks(struct budget *budget); |
114 | extern int ttpci_budget_deinit(struct budget *budget); | 114 | extern int ttpci_budget_deinit(struct budget *budget); |
115 | extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); | 115 | extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); |
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index e6c9cd2e3b94..66ab0c6e9783 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | |||
@@ -1614,7 +1614,7 @@ static void frontend_init(struct ttusb* ttusb) | |||
1614 | } | 1614 | } |
1615 | 1615 | ||
1616 | if (ttusb->fe == NULL) { | 1616 | if (ttusb->fe == NULL) { |
1617 | printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n", | 1617 | printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", |
1618 | le16_to_cpu(ttusb->dev->descriptor.idVendor), | 1618 | le16_to_cpu(ttusb->dev->descriptor.idVendor), |
1619 | le16_to_cpu(ttusb->dev->descriptor.idProduct)); | 1619 | le16_to_cpu(ttusb->dev->descriptor.idProduct)); |
1620 | } else { | 1620 | } else { |
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index de5829b863fd..ab33fec8a19f 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c | |||
@@ -1665,7 +1665,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, | |||
1665 | } | 1665 | } |
1666 | 1666 | ||
1667 | if (dec->fe == NULL) { | 1667 | if (dec->fe == NULL) { |
1668 | printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n", | 1668 | printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", |
1669 | le16_to_cpu(dec->udev->descriptor.idVendor), | 1669 | le16_to_cpu(dec->udev->descriptor.idVendor), |
1670 | le16_to_cpu(dec->udev->descriptor.idProduct)); | 1670 | le16_to_cpu(dec->udev->descriptor.idProduct)); |
1671 | } else { | 1671 | } else { |
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 443af24097f3..21260aad1e54 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c | |||
@@ -38,7 +38,17 @@ struct ttusbdecfe_state { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | 40 | ||
41 | static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) | 41 | static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe, |
42 | fe_status_t *status) | ||
43 | { | ||
44 | *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | | ||
45 | FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | |||
50 | static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, | ||
51 | fe_status_t *status) | ||
42 | { | 52 | { |
43 | struct ttusbdecfe_state* state = fe->demodulator_priv; | 53 | struct ttusbdecfe_state* state = fe->demodulator_priv; |
44 | u8 b[] = { 0x00, 0x00, 0x00, 0x00, | 54 | u8 b[] = { 0x00, 0x00, 0x00, 0x00, |
@@ -251,7 +261,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { | |||
251 | 261 | ||
252 | .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, | 262 | .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, |
253 | 263 | ||
254 | .read_status = ttusbdecfe_read_status, | 264 | .read_status = ttusbdecfe_dvbt_read_status, |
255 | }; | 265 | }; |
256 | 266 | ||
257 | static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { | 267 | static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { |
@@ -273,7 +283,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { | |||
273 | 283 | ||
274 | .set_frontend = ttusbdecfe_dvbs_set_frontend, | 284 | .set_frontend = ttusbdecfe_dvbs_set_frontend, |
275 | 285 | ||
276 | .read_status = ttusbdecfe_read_status, | 286 | .read_status = ttusbdecfe_dvbs_read_status, |
277 | 287 | ||
278 | .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, | 288 | .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, |
279 | .set_voltage = ttusbdecfe_dvbs_set_voltage, | 289 | .set_voltage = ttusbdecfe_dvbs_set_voltage, |