aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb
diff options
context:
space:
mode:
authorTomi Orava <tomimo@ncircle.nullnet.fi>2008-09-18 23:48:31 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-12 07:37:14 -0400
commit986bd1e58b18c09b753f797df19251804bfe3e84 (patch)
tree35bef912485680a527d01339dccda3ce62fbf7a7 /drivers/media/dvb
parent07c6bb9e6e5c9b8d0f697493cdd3978fc193ca90 (diff)
V4L/DVB (9107): Alternative version of Terratec Cinergy T2 driver
Alternative version of the Terratec Cinergy T2 driver that uses the dvb framework. Signed-off-by: Tomi Orava <tomimo@ncircle.nullnet.fi> Signed-off-by: Thierry MERLE <thierry.merle@free.fr> [mchehab@redhat.com: fix dvb Makefile] Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r--drivers/media/dvb/Kconfig1
-rw-r--r--drivers/media/dvb/Makefile2
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig85
-rw-r--r--drivers/media/dvb/cinergyT2/Makefile3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c1105
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig8
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile4
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-core.c230
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-fe.c351
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2.h95
10 files changed, 689 insertions, 1195 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 14488f644792..0bcd852576d6 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -20,7 +20,6 @@ comment "Supported USB Adapters"
20source "drivers/media/dvb/dvb-usb/Kconfig" 20source "drivers/media/dvb/dvb-usb/Kconfig"
21source "drivers/media/dvb/ttusb-budget/Kconfig" 21source "drivers/media/dvb/ttusb-budget/Kconfig"
22source "drivers/media/dvb/ttusb-dec/Kconfig" 22source "drivers/media/dvb/ttusb-dec/Kconfig"
23source "drivers/media/dvb/cinergyT2/Kconfig"
24source "drivers/media/dvb/siano/Kconfig" 23source "drivers/media/dvb/siano/Kconfig"
25 24
26comment "Supported FlexCopII (B2C2) Adapters" 25comment "Supported FlexCopII (B2C2) Adapters"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index ea953a03e24d..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
5obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/ dm1105/ 5obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
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 @@
1config 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
10config 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
21config 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
36config 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
49config 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
64config 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
77config 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 @@
1obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
2
3EXTRA_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
57static int debug;
58module_param_named(debug, debug, int, 0644);
59MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
60
61DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
62
63#define dprintk(level, args...) \
64do { \
65 if ((debug & level)) { \
66 printk("%s: %s(): ", KBUILD_MODNAME, \
67 __func__); \
68 printk(args); } \
69} while (0)
70
71enum 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
83struct 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
91struct 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
105static 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
119struct 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
156enum {
157 CINERGYT2_RC_EVENT_TYPE_NONE = 0x00,
158 CINERGYT2_RC_EVENT_TYPE_NEC = 0x01,
159 CINERGYT2_RC_EVENT_TYPE_RC5 = 0x02
160};
161
162struct cinergyt2_rc_event {
163 char type;
164 __le32 value;
165} __attribute__((packed));
166
167static 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
207static 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
233static 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
239static 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
246static void cinergyt2_stream_irq (struct urb *urb);
247
248static 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
266static 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
278static 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
289static 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
320static 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
330static 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
346static 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
364static 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 */
390static 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
487static 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
513out_unlock2:
514 mutex_unlock(&cinergyt2->sem);
515out_unlock1:
516 mutex_unlock(&cinergyt2->wq_sem);
517out:
518 return err;
519}
520
521static 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
533static 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
558static 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
580static 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
702static 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;
727bailout:
728 unlock_kernel();
729 return ret;
730}
731
732static 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
741static 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
750static 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
816out:
817 schedule_delayed_work(&cinergyt2->rc_query_work,
818 msecs_to_jiffies(RC_QUERY_INTERVAL));
819
820 mutex_unlock(&cinergyt2->sem);
821}
822
823static 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
864static 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
870static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2)
871{
872 cancel_rearming_delayed_work(&cinergyt2->rc_query_work);
873}
874
875static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2)
876{
877 schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
878}
879
880#else
881
882static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; }
883static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { }
884static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { }
885static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { }
886
887#endif /* ENABLE_RC */
888
889static 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
918static 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
989bailout:
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
999static 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
1014static 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
1037static 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);
1064out_unlock1:
1065 mutex_unlock(&cinergyt2->wq_sem);
1066out:
1067 return err;
1068}
1069
1070static const struct usb_device_id cinergyt2_table [] __devinitdata = {
1071 { USB_DEVICE(0x0ccd, 0x0038) },
1072 { 0 }
1073};
1074
1075MODULE_DEVICE_TABLE(usb, cinergyt2_table);
1076
1077static 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
1086static 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
1096static void __exit cinergyt2_exit (void)
1097{
1098 usb_deregister(&cinergyt2_driver);
1099}
1100
1101module_init (cinergyt2_init);
1102module_exit (cinergyt2_exit);
1103
1104MODULE_LICENSE("GPL");
1105MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 241c9ab54b1b..57bb470bd064 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -259,6 +259,14 @@ config DVB_USB_DW2102
259 Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers 259 Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
260 and the TeVii S650. 260 and the TeVii S650.
261 261
262config DVB_USB_CINERGY_T2
263 tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
264 depends on DVB_USB
265 help
266 Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
267
268 Say Y if you own such a device and want to use it.
269
262config DVB_USB_ANYSEE 270config DVB_USB_ANYSEE
263 tristate "Anysee DVB-T/C USB2.0 support" 271 tristate "Anysee DVB-T/C USB2.0 support"
264 depends on DVB_USB 272 depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index ece8c9dfed18..3122b7cc2c23 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -73,6 +73,10 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
73dvb-usb-af9015-objs = af9015.o 73dvb-usb-af9015-objs = af9015.o
74obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o 74obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
75 75
76dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
77obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
78
79
76EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ 80EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
77# due to tuner-xc3028 81# due to tuner-xc3028
78EXTRA_CFLAGS += -Idrivers/media/common/tuners 82EXTRA_CFLAGS += -Idrivers/media/common/tuners
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..25863033c480
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -0,0 +1,230 @@
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 */
34int dvb_usb_cinergyt2_debug;
35int disable_remote;
36
37module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
38MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
39 "(or-able)).");
40
41DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
42
43
44/* We are missing a release hook with usb_device data */
45struct dvb_usb_device *cinergyt2_usb_device;
46
47static struct dvb_usb_device_properties cinergyt2_properties;
48
49static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
50{
51 char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
52 char result[64];
53 return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
54 sizeof(result), 0);
55}
56
57static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
58{
59 char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
60 char state[3];
61 return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
62}
63
64static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
65{
66 char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
67 char state[3];
68 int ret;
69
70 adap->fe = cinergyt2_fe_attach(adap->dev);
71
72 ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
73 sizeof(state), 0);
74 if (ret < 0) {
75 deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
76 "state info\n");
77 }
78
79 /* Copy this pointer as we are gonna need it in the release phase */
80 cinergyt2_usb_device = adap->dev;
81
82 return 0;
83}
84
85static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
86 { 0x04, 0x01, KEY_POWER },
87 { 0x04, 0x02, KEY_1 },
88 { 0x04, 0x03, KEY_2 },
89 { 0x04, 0x04, KEY_3 },
90 { 0x04, 0x05, KEY_4 },
91 { 0x04, 0x06, KEY_5 },
92 { 0x04, 0x07, KEY_6 },
93 { 0x04, 0x08, KEY_7 },
94 { 0x04, 0x09, KEY_8 },
95 { 0x04, 0x0a, KEY_9 },
96 { 0x04, 0x0c, KEY_0 },
97 { 0x04, 0x0b, KEY_VIDEO },
98 { 0x04, 0x0d, KEY_REFRESH },
99 { 0x04, 0x0e, KEY_SELECT },
100 { 0x04, 0x0f, KEY_EPG },
101 { 0x04, 0x10, KEY_UP },
102 { 0x04, 0x14, KEY_DOWN },
103 { 0x04, 0x11, KEY_LEFT },
104 { 0x04, 0x13, KEY_RIGHT },
105 { 0x04, 0x12, KEY_OK },
106 { 0x04, 0x15, KEY_TEXT },
107 { 0x04, 0x16, KEY_INFO },
108 { 0x04, 0x17, KEY_RED },
109 { 0x04, 0x18, KEY_GREEN },
110 { 0x04, 0x19, KEY_YELLOW },
111 { 0x04, 0x1a, KEY_BLUE },
112 { 0x04, 0x1c, KEY_VOLUMEUP },
113 { 0x04, 0x1e, KEY_VOLUMEDOWN },
114 { 0x04, 0x1d, KEY_MUTE },
115 { 0x04, 0x1b, KEY_CHANNELUP },
116 { 0x04, 0x1f, KEY_CHANNELDOWN },
117 { 0x04, 0x40, KEY_PAUSE },
118 { 0x04, 0x4c, KEY_PLAY },
119 { 0x04, 0x58, KEY_RECORD },
120 { 0x04, 0x54, KEY_PREVIOUS },
121 { 0x04, 0x48, KEY_STOP },
122 { 0x04, 0x5c, KEY_NEXT }
123};
124
125static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
126{
127 u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
128 *state = REMOTE_NO_KEY_PRESSED;
129
130 dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
131 if (key[4] == 0xff)
132 return 0;
133
134 /* hack to pass checksum on the custom field (is set to 0xeb) */
135 key[2] = ~0x04;
136 dvb_usb_nec_rc_key_to_event(d, key, event, state);
137 if (key[0] != 0)
138 deb_info("key: %x %x %x %x %x\n",
139 key[0], key[1], key[2], key[3], key[4]);
140
141 return 0;
142}
143
144static int cinergyt2_usb_probe(struct usb_interface *intf,
145 const struct usb_device_id *id)
146{
147 return dvb_usb_device_init(intf, &cinergyt2_properties,
148 THIS_MODULE, NULL, adapter_nr);
149}
150
151
152static struct usb_device_id cinergyt2_usb_table[] = {
153 { USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
154 { 0 }
155};
156
157MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
158
159static struct dvb_usb_device_properties cinergyt2_properties = {
160
161 .num_adapters = 1,
162 .adapter = {
163 {
164 .streaming_ctrl = cinergyt2_streaming_ctrl,
165 .frontend_attach = cinergyt2_frontend_attach,
166
167 /* parameter for the MPEG2-data transfer */
168 .stream = {
169 .type = USB_BULK,
170 .count = 5,
171 .endpoint = 0x02,
172 .u = {
173 .bulk = {
174 .buffersize = 512,
175 }
176 }
177 },
178 }
179 },
180
181 .power_ctrl = cinergyt2_power_ctrl,
182
183 .rc_interval = 50,
184 .rc_key_map = cinergyt2_rc_keys,
185 .rc_key_map_size = ARRAY_SIZE(cinergyt2_rc_keys),
186 .rc_query = cinergyt2_rc_query,
187
188 .generic_bulk_ctrl_endpoint = 1,
189
190 .num_device_descs = 1,
191 .devices = {
192 { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
193 .cold_ids = {NULL},
194 .warm_ids = { &cinergyt2_usb_table[0], NULL },
195 },
196 { NULL },
197 }
198};
199
200
201static struct usb_driver cinergyt2_driver = {
202 .name = "cinergyT2",
203 .probe = cinergyt2_usb_probe,
204 .disconnect = dvb_usb_device_exit,
205 .id_table = cinergyt2_usb_table
206};
207
208static int __init cinergyt2_usb_init(void)
209{
210 int err;
211
212 err = usb_register(&cinergyt2_driver);
213 if (err) {
214 err("usb_register() failed! (err %i)\n", err);
215 return err;
216 }
217 return 0;
218}
219
220static void __exit cinergyt2_usb_exit(void)
221{
222 usb_deregister(&cinergyt2_driver);
223}
224
225module_init(cinergyt2_usb_init);
226module_exit(cinergyt2_usb_exit);
227
228MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
229MODULE_LICENSE("GPL");
230MODULE_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
43static 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
140struct cinergyt2_fe_state {
141 struct dvb_frontend fe;
142 struct dvb_usb_device *d;
143};
144
145static 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
178static 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
194static 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
212static 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
231static 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
248static int cinergyt2_fe_init(struct dvb_frontend *fe)
249{
250 return 0;
251}
252
253static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
254{
255 deb_info("cinergyt2_fe_sleep() Called\n");
256 return 0;
257}
258
259static 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
266static 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 *)&param, 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
288static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
289 struct dvb_frontend_parameters *fep)
290{
291 return 0;
292}
293
294static 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
301static struct dvb_frontend_ops cinergyt2_fe_ops;
302
303struct 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
317static 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
40extern 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
54enum 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
68struct 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
83struct 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
92extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
93
94#endif /* _DVB_USB_CINERGYT2_H_ */
95