aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/cinergyT2
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/dvb/cinergyT2
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/media/dvb/cinergyT2')
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig85
-rw-r--r--drivers/media/dvb/cinergyT2/Makefile3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c965
3 files changed, 1053 insertions, 0 deletions
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
new file mode 100644
index 000000000000..226714085f58
--- /dev/null
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -0,0 +1,85 @@
1config DVB_CINERGYT2
2 tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
3 depends on DVB_CORE && USB
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 receiption 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 "yes"
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 "100"
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
new file mode 100644
index 000000000000..c51aece20f9f
--- /dev/null
+++ b/drivers/media/dvb/cinergyT2/Makefile
@@ -0,0 +1,3 @@
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
new file mode 100644
index 000000000000..f1f539761371
--- /dev/null
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -0,0 +1,965 @@
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/config.h>
26#include <linux/init.h>
27#include <linux/module.h>
28#include <linux/version.h>
29#include <linux/slab.h>
30#include <linux/usb.h>
31#include <linux/pci.h>
32#include <linux/input.h>
33#include <linux/dvb/frontend.h>
34
35#include "dmxdev.h"
36#include "dvb_demux.h"
37#include "dvb_net.h"
38
39
40#ifdef CONFIG_DVB_CINERGYT2_TUNING
41 #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT)
42 #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE)
43 #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL)
44 #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
45 #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL)
46 #define ENABLE_RC (1)
47 #endif
48#else
49 #define STREAM_URB_COUNT (32)
50 #define STREAM_BUF_SIZE (512) /* bytes */
51 #define ENABLE_RC (1)
52 #define RC_QUERY_INTERVAL (100) /* milliseconds */
53 #define QUERY_INTERVAL (333) /* milliseconds */
54#endif
55
56#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
57
58static int debug;
59module_param_named(debug, debug, int, 0644);
60MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
61
62#define dprintk(level, args...) \
63do { \
64 if ((debug & level)) { \
65 printk("%s: %s(): ", __stringify(KBUILD_MODNAME), \
66 __FUNCTION__); \
67 printk(args); } \
68} while (0)
69
70enum cinergyt2_ep1_cmd {
71 CINERGYT2_EP1_PID_TABLE_RESET = 0x01,
72 CINERGYT2_EP1_PID_SETUP = 0x02,
73 CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03,
74 CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04,
75 CINERGYT2_EP1_GET_TUNER_STATUS = 0x05,
76 CINERGYT2_EP1_START_SCAN = 0x06,
77 CINERGYT2_EP1_CONTINUE_SCAN = 0x07,
78 CINERGYT2_EP1_GET_RC_EVENTS = 0x08,
79 CINERGYT2_EP1_SLEEP_MODE = 0x09
80};
81
82struct dvbt_set_parameters_msg {
83 uint8_t cmd;
84 uint32_t freq;
85 uint8_t bandwidth;
86 uint16_t tps;
87 uint8_t flags;
88} __attribute__((packed));
89
90struct dvbt_get_status_msg {
91 uint32_t freq;
92 uint8_t bandwidth;
93 uint16_t tps;
94 uint8_t flags;
95 uint16_t gain;
96 uint8_t snr;
97 uint32_t viterbi_error_rate;
98 uint32_t rs_error_rate;
99 uint32_t uncorrected_block_count;
100 uint8_t lock_bits;
101 uint8_t prev_lock_bits;
102} __attribute__((packed));
103
104static struct dvb_frontend_info cinergyt2_fe_info = {
105 .name = DRIVER_NAME,
106 .type = FE_OFDM,
107 .frequency_min = 174000000,
108 .frequency_max = 862000000,
109 .frequency_stepsize = 166667,
110 .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
111 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
112 FE_CAN_FEC_AUTO |
113 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
114 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
115 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS
116};
117
118struct cinergyt2 {
119 struct dvb_demux demux;
120 struct usb_device *udev;
121 struct semaphore sem;
122 struct dvb_adapter *adapter;
123 struct dvb_device *fedev;
124 struct dmxdev dmxdev;
125 struct dvb_net dvbnet;
126
127 int streaming;
128 int sleeping;
129
130 struct dvbt_set_parameters_msg param;
131 struct dvbt_get_status_msg status;
132 struct work_struct query_work;
133
134 wait_queue_head_t poll_wq;
135 int pending_fe_events;
136
137 void *streambuf;
138 dma_addr_t streambuf_dmahandle;
139 struct urb *stream_urb [STREAM_URB_COUNT];
140
141#ifdef ENABLE_RC
142 struct input_dev rc_input_dev;
143 struct work_struct rc_query_work;
144 int rc_input_event;
145#endif
146};
147
148enum {
149 CINERGYT2_RC_EVENT_TYPE_NONE = 0x00,
150 CINERGYT2_RC_EVENT_TYPE_NEC = 0x01,
151 CINERGYT2_RC_EVENT_TYPE_RC5 = 0x02
152};
153
154struct cinergyt2_rc_event {
155 char type;
156 uint32_t value;
157} __attribute__((packed));
158
159static const uint32_t rc_keys [] = {
160 CINERGYT2_RC_EVENT_TYPE_NEC, 0xfe01eb04, KEY_POWER,
161 CINERGYT2_RC_EVENT_TYPE_NEC, 0xfd02eb04, KEY_1,
162 CINERGYT2_RC_EVENT_TYPE_NEC, 0xfc03eb04, KEY_2,
163 CINERGYT2_RC_EVENT_TYPE_NEC, 0xfb04eb04, KEY_3,
164 CINERGYT2_RC_EVENT_TYPE_NEC, 0xfa05eb04, KEY_4,
165 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf906eb04, KEY_5,
166 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf807eb04, KEY_6,
167 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf708eb04, KEY_7,
168 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf609eb04, KEY_8,
169 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf50aeb04, KEY_9,
170 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf30ceb04, KEY_0,
171 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf40beb04, KEY_VIDEO,
172 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf20deb04, KEY_REFRESH,
173 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf10eeb04, KEY_SELECT,
174 CINERGYT2_RC_EVENT_TYPE_NEC, 0xf00feb04, KEY_EPG,
175 CINERGYT2_RC_EVENT_TYPE_NEC, 0xef10eb04, KEY_UP,
176 CINERGYT2_RC_EVENT_TYPE_NEC, 0xeb14eb04, KEY_DOWN,
177 CINERGYT2_RC_EVENT_TYPE_NEC, 0xee11eb04, KEY_LEFT,
178 CINERGYT2_RC_EVENT_TYPE_NEC, 0xec13eb04, KEY_RIGHT,
179 CINERGYT2_RC_EVENT_TYPE_NEC, 0xed12eb04, KEY_OK,
180 CINERGYT2_RC_EVENT_TYPE_NEC, 0xea15eb04, KEY_TEXT,
181 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe916eb04, KEY_INFO,
182 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe817eb04, KEY_RED,
183 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe718eb04, KEY_GREEN,
184 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe619eb04, KEY_YELLOW,
185 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe51aeb04, KEY_BLUE,
186 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe31ceb04, KEY_VOLUMEUP,
187 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe11eeb04, KEY_VOLUMEDOWN,
188 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe21deb04, KEY_MUTE,
189 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe41beb04, KEY_CHANNELUP,
190 CINERGYT2_RC_EVENT_TYPE_NEC, 0xe01feb04, KEY_CHANNELDOWN,
191 CINERGYT2_RC_EVENT_TYPE_NEC, 0xbf40eb04, KEY_PAUSE,
192 CINERGYT2_RC_EVENT_TYPE_NEC, 0xb34ceb04, KEY_PLAY,
193 CINERGYT2_RC_EVENT_TYPE_NEC, 0xa758eb04, KEY_RECORD,
194 CINERGYT2_RC_EVENT_TYPE_NEC, 0xab54eb04, KEY_PREVIOUS,
195 CINERGYT2_RC_EVENT_TYPE_NEC, 0xb748eb04, KEY_STOP,
196 CINERGYT2_RC_EVENT_TYPE_NEC, 0xa35ceb04, KEY_NEXT
197};
198
199static int cinergyt2_command (struct cinergyt2 *cinergyt2,
200 char *send_buf, int send_buf_len,
201 char *recv_buf, int recv_buf_len)
202{
203 int actual_len;
204 char dummy;
205 int ret;
206
207 ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
208 send_buf, send_buf_len, &actual_len, 1000);
209
210 if (ret)
211 dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
212
213 if (!recv_buf)
214 recv_buf = &dummy;
215
216 ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
217 recv_buf, recv_buf_len, &actual_len, 1000);
218
219 if (ret)
220 dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
221
222 return ret ? ret : actual_len;
223}
224
225static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable)
226{
227 char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
228 cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
229}
230
231static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
232{
233 char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 };
234 cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
235 cinergyt2->sleeping = sleep;
236}
237
238static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs);
239
240static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
241{
242 int err;
243
244 usb_fill_bulk_urb(urb,
245 cinergyt2->udev,
246 usb_rcvbulkpipe(cinergyt2->udev, 0x2),
247 urb->transfer_buffer,
248 STREAM_BUF_SIZE,
249 cinergyt2_stream_irq,
250 cinergyt2);
251
252 if ((err = usb_submit_urb(urb, GFP_ATOMIC)))
253 dprintk(1, "urb submission failed (err = %i)!\n", err);
254
255 return err;
256}
257
258static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs)
259{
260 struct cinergyt2 *cinergyt2 = urb->context;
261
262 if (urb->actual_length > 0)
263 dvb_dmx_swfilter(&cinergyt2->demux,
264 urb->transfer_buffer, urb->actual_length);
265
266 if (cinergyt2->streaming)
267 cinergyt2_submit_stream_urb(cinergyt2, urb);
268}
269
270static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2)
271{
272 int i;
273
274 for (i=0; i<STREAM_URB_COUNT; i++)
275 if (cinergyt2->stream_urb[i])
276 usb_free_urb(cinergyt2->stream_urb[i]);
277
278 pci_free_consistent(NULL, STREAM_URB_COUNT*STREAM_BUF_SIZE,
279 cinergyt2->streambuf, cinergyt2->streambuf_dmahandle);
280}
281
282static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2)
283{
284 int i;
285
286 cinergyt2->streambuf = pci_alloc_consistent(NULL,
287 STREAM_URB_COUNT*STREAM_BUF_SIZE,
288 &cinergyt2->streambuf_dmahandle);
289 if (!cinergyt2->streambuf) {
290 dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n");
291 return -ENOMEM;
292 }
293
294 memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE);
295
296 for (i=0; i<STREAM_URB_COUNT; i++) {
297 struct urb *urb;
298
299 if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
300 dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n");
301 cinergyt2_free_stream_urbs(cinergyt2);
302 return -ENOMEM;
303 }
304
305 urb->transfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE;
306 urb->transfer_buffer_length = STREAM_BUF_SIZE;
307
308 cinergyt2->stream_urb[i] = urb;
309 }
310
311 return 0;
312}
313
314static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2)
315{
316 int i;
317
318 cinergyt2_control_stream_transfer(cinergyt2, 0);
319
320 for (i=0; i<STREAM_URB_COUNT; i++)
321 if (cinergyt2->stream_urb[i])
322 usb_kill_urb(cinergyt2->stream_urb[i]);
323}
324
325static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2)
326{
327 int i, err;
328
329 for (i=0; i<STREAM_URB_COUNT; i++) {
330 if ((err = cinergyt2_submit_stream_urb(cinergyt2, cinergyt2->stream_urb[i]))) {
331 cinergyt2_stop_stream_xfer(cinergyt2);
332 dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err);
333 return err;
334 }
335 }
336
337 cinergyt2_control_stream_transfer(cinergyt2, 1);
338 return 0;
339}
340
341static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
342{
343 struct dvb_demux *demux = dvbdmxfeed->demux;
344 struct cinergyt2 *cinergyt2 = demux->priv;
345
346 if (down_interruptible(&cinergyt2->sem))
347 return -ERESTARTSYS;
348
349 if (cinergyt2->streaming == 0)
350 cinergyt2_start_stream_xfer(cinergyt2);
351
352 cinergyt2->streaming++;
353 up(&cinergyt2->sem);
354 return 0;
355}
356
357static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
358{
359 struct dvb_demux *demux = dvbdmxfeed->demux;
360 struct cinergyt2 *cinergyt2 = demux->priv;
361
362 if (down_interruptible(&cinergyt2->sem))
363 return -ERESTARTSYS;
364
365 if (--cinergyt2->streaming == 0)
366 cinergyt2_stop_stream_xfer(cinergyt2);
367
368 up(&cinergyt2->sem);
369 return 0;
370}
371
372/**
373 * convert linux-dvb frontend parameter set into TPS.
374 * See ETSI ETS-300744, section 4.6.2, table 9 for details.
375 *
376 * This function is probably reusable and may better get placed in a support
377 * library.
378 *
379 * We replace errornous fields by default TPS fields (the ones with value 0).
380 */
381static uint16_t compute_tps (struct dvb_frontend_parameters *p)
382{
383 struct dvb_ofdm_parameters *op = &p->u.ofdm;
384 uint16_t tps = 0;
385
386 switch (op->code_rate_HP) {
387 case FEC_2_3:
388 tps |= (1 << 7);
389 break;
390 case FEC_3_4:
391 tps |= (2 << 7);
392 break;
393 case FEC_5_6:
394 tps |= (3 << 7);
395 break;
396 case FEC_7_8:
397 tps |= (4 << 7);
398 break;
399 case FEC_1_2:
400 case FEC_AUTO:
401 default:
402 /* tps |= (0 << 7) */;
403 }
404
405 switch (op->code_rate_LP) {
406 case FEC_2_3:
407 tps |= (1 << 4);
408 break;
409 case FEC_3_4:
410 tps |= (2 << 4);
411 break;
412 case FEC_5_6:
413 tps |= (3 << 4);
414 break;
415 case FEC_7_8:
416 tps |= (4 << 4);
417 break;
418 case FEC_1_2:
419 case FEC_AUTO:
420 default:
421 /* tps |= (0 << 4) */;
422 }
423
424 switch (op->constellation) {
425 case QAM_16:
426 tps |= (1 << 13);
427 break;
428 case QAM_64:
429 tps |= (2 << 13);
430 break;
431 case QPSK:
432 default:
433 /* tps |= (0 << 13) */;
434 }
435
436 switch (op->transmission_mode) {
437 case TRANSMISSION_MODE_8K:
438 tps |= (1 << 0);
439 break;
440 case TRANSMISSION_MODE_2K:
441 default:
442 /* tps |= (0 << 0) */;
443 }
444
445 switch (op->guard_interval) {
446 case GUARD_INTERVAL_1_16:
447 tps |= (1 << 2);
448 break;
449 case GUARD_INTERVAL_1_8:
450 tps |= (2 << 2);
451 break;
452 case GUARD_INTERVAL_1_4:
453 tps |= (3 << 2);
454 break;
455 case GUARD_INTERVAL_1_32:
456 default:
457 /* tps |= (0 << 2) */;
458 }
459
460 switch (op->hierarchy_information) {
461 case HIERARCHY_1:
462 tps |= (1 << 10);
463 break;
464 case HIERARCHY_2:
465 tps |= (2 << 10);
466 break;
467 case HIERARCHY_4:
468 tps |= (3 << 10);
469 break;
470 case HIERARCHY_NONE:
471 default:
472 /* tps |= (0 << 10) */;
473 }
474
475 return tps;
476}
477
478static int cinergyt2_open (struct inode *inode, struct file *file)
479{
480 struct dvb_device *dvbdev = file->private_data;
481 struct cinergyt2 *cinergyt2 = dvbdev->priv;
482 int err;
483
484 if ((err = dvb_generic_open(inode, file)))
485 return err;
486
487 if (down_interruptible(&cinergyt2->sem))
488 return -ERESTARTSYS;
489
490 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
491 cinergyt2_sleep(cinergyt2, 0);
492 schedule_delayed_work(&cinergyt2->query_work, HZ/2);
493 }
494
495 up(&cinergyt2->sem);
496 return 0;
497}
498
499static int cinergyt2_release (struct inode *inode, struct file *file)
500{
501 struct dvb_device *dvbdev = file->private_data;
502 struct cinergyt2 *cinergyt2 = dvbdev->priv;
503
504 if (down_interruptible(&cinergyt2->sem))
505 return -ERESTARTSYS;
506
507 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
508 cancel_delayed_work(&cinergyt2->query_work);
509 flush_scheduled_work();
510 cinergyt2_sleep(cinergyt2, 1);
511 }
512
513 up(&cinergyt2->sem);
514
515 return dvb_generic_release(inode, file);
516}
517
518static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
519{
520 struct dvb_device *dvbdev = file->private_data;
521 struct cinergyt2 *cinergyt2 = dvbdev->priv;
522 poll_wait(file, &cinergyt2->poll_wq, wait);
523 return (POLLIN | POLLRDNORM | POLLPRI);
524}
525
526
527static int cinergyt2_ioctl (struct inode *inode, struct file *file,
528 unsigned cmd, unsigned long arg)
529{
530 struct dvb_device *dvbdev = file->private_data;
531 struct cinergyt2 *cinergyt2 = dvbdev->priv;
532 struct dvbt_get_status_msg *stat = &cinergyt2->status;
533 fe_status_t status = 0;
534
535 switch (cmd) {
536 case FE_GET_INFO:
537 return copy_to_user((void __user*) arg, &cinergyt2_fe_info,
538 sizeof(struct dvb_frontend_info));
539
540 case FE_READ_STATUS:
541 if (0xffff - le16_to_cpu(stat->gain) > 30)
542 status |= FE_HAS_SIGNAL;
543 if (stat->lock_bits & (1 << 6))
544 status |= FE_HAS_LOCK;
545 if (stat->lock_bits & (1 << 5))
546 status |= FE_HAS_SYNC;
547 if (stat->lock_bits & (1 << 4))
548 status |= FE_HAS_CARRIER;
549 if (stat->lock_bits & (1 << 1))
550 status |= FE_HAS_VITERBI;
551
552 return copy_to_user((void __user*) arg, &status, sizeof(status));
553
554 case FE_READ_BER:
555 return put_user(le32_to_cpu(stat->viterbi_error_rate),
556 (__u32 __user *) arg);
557
558 case FE_READ_SIGNAL_STRENGTH:
559 return put_user(0xffff - le16_to_cpu(stat->gain),
560 (__u16 __user *) arg);
561
562 case FE_READ_SNR:
563 return put_user((stat->snr << 8) | stat->snr,
564 (__u16 __user *) arg);
565
566 case FE_READ_UNCORRECTED_BLOCKS:
567 /* UNC are already converted to host byte order... */
568 return put_user(stat->uncorrected_block_count,
569 (__u32 __user *) arg);
570
571 case FE_SET_FRONTEND:
572 {
573 struct dvbt_set_parameters_msg *param = &cinergyt2->param;
574 struct dvb_frontend_parameters p;
575 int err;
576
577 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
578 return -EPERM;
579
580 if (copy_from_user(&p, (void __user*) arg, sizeof(p)))
581 return -EFAULT;
582
583 if (down_interruptible(&cinergyt2->sem))
584 return -ERESTARTSYS;
585
586 param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
587 param->tps = cpu_to_le16(compute_tps(&p));
588 param->freq = cpu_to_le32(p.frequency / 1000);
589 param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
590
591 stat->lock_bits = 0;
592 cinergyt2->pending_fe_events++;
593 wake_up_interruptible(&cinergyt2->poll_wq);
594
595 err = cinergyt2_command(cinergyt2,
596 (char *) param, sizeof(*param),
597 NULL, 0);
598
599 up(&cinergyt2->sem);
600
601 return (err < 0) ? err : 0;
602 }
603
604 case FE_GET_FRONTEND:
605 /**
606 * trivial to implement (see struct dvbt_get_status_msg).
607 * equivalent to FE_READ ioctls, but needs
608 * TPS -> linux-dvb parameter set conversion. Feel free
609 * to implement this and send us a patch if you need this
610 * functionality.
611 */
612 break;
613
614 case FE_GET_EVENT:
615 {
616 /**
617 * for now we only fill the status field. the parameters
618 * are trivial to fill as soon FE_GET_FRONTEND is done.
619 */
620 struct dvb_frontend_event __user *e = (void __user *) arg;
621 if (cinergyt2->pending_fe_events == 0) {
622 if (file->f_flags & O_NONBLOCK)
623 return -EWOULDBLOCK;
624 wait_event_interruptible(cinergyt2->poll_wq,
625 cinergyt2->pending_fe_events > 0);
626 }
627 cinergyt2->pending_fe_events = 0;
628 return cinergyt2_ioctl(inode, file, FE_READ_STATUS,
629 (unsigned long) &e->status);
630 }
631
632 default:
633 ;
634 }
635
636 return -EINVAL;
637}
638
639static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
640{
641 struct dvb_device *dvbdev = file->private_data;
642 struct cinergyt2 *cinergyt2 = dvbdev->priv;
643 int ret = 0;
644
645 lock_kernel();
646
647 if (vma->vm_flags & (VM_WRITE | VM_EXEC)) {
648 ret = -EPERM;
649 goto bailout;
650 }
651
652 if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) {
653 ret = -EINVAL;
654 goto bailout;
655 }
656
657 vma->vm_flags |= (VM_IO | VM_DONTCOPY);
658 vma->vm_file = file;
659
660 ret = remap_pfn_range(vma, vma->vm_start,
661 virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT,
662 vma->vm_end - vma->vm_start,
663 vma->vm_page_prot) ? -EAGAIN : 0;
664bailout:
665 unlock_kernel();
666 return ret;
667}
668
669static struct file_operations cinergyt2_fops = {
670 .owner = THIS_MODULE,
671 .ioctl = cinergyt2_ioctl,
672 .poll = cinergyt2_poll,
673 .open = cinergyt2_open,
674 .release = cinergyt2_release,
675 .mmap = cinergyt2_mmap
676};
677
678static struct dvb_device cinergyt2_fe_template = {
679 .users = ~0,
680 .writers = 1,
681 .readers = (~0)-1,
682 .fops = &cinergyt2_fops
683};
684
685#ifdef ENABLE_RC
686static void cinergyt2_query_rc (void *data)
687{
688 struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data;
689 char buf [1] = { CINERGYT2_EP1_GET_RC_EVENTS };
690 struct cinergyt2_rc_event rc_events[12];
691 int n, len;
692
693 if (down_interruptible(&cinergyt2->sem))
694 return;
695
696 len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
697 (char *) rc_events, sizeof(rc_events));
698
699 for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) {
700 int i;
701
702 if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
703 rc_events[n].value == ~0)
704 {
705 /**
706 * keyrepeat bit. If we would handle this properly
707 * we would need to emit down events as long the
708 * keyrepeat goes, a up event if no further
709 * repeat bits occur. Would need a timer to implement
710 * and no other driver does this, so we simply
711 * emit the last key up/down sequence again.
712 */
713 } else {
714 cinergyt2->rc_input_event = KEY_MAX;
715 for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) {
716 if (rc_keys[i+0] == rc_events[n].type &&
717 rc_keys[i+1] == rc_events[n].value)
718 {
719 cinergyt2->rc_input_event = rc_keys[i+2];
720 break;
721 }
722 }
723 }
724
725 if (cinergyt2->rc_input_event != KEY_MAX) {
726 input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1);
727 input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0);
728 input_sync(&cinergyt2->rc_input_dev);
729 }
730 }
731
732 schedule_delayed_work(&cinergyt2->rc_query_work,
733 msecs_to_jiffies(RC_QUERY_INTERVAL));
734
735 up(&cinergyt2->sem);
736}
737#endif
738
739static void cinergyt2_query (void *data)
740{
741 struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data;
742 char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS };
743 struct dvbt_get_status_msg *s = &cinergyt2->status;
744 uint8_t lock_bits;
745 uint32_t unc;
746
747 if (down_interruptible(&cinergyt2->sem))
748 return;
749
750 unc = s->uncorrected_block_count;
751 lock_bits = s->lock_bits;
752
753 cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s));
754
755 unc += le32_to_cpu(s->uncorrected_block_count);
756 s->uncorrected_block_count = unc;
757
758 if (lock_bits != s->lock_bits) {
759 wake_up_interruptible(&cinergyt2->poll_wq);
760 cinergyt2->pending_fe_events++;
761 }
762
763 schedule_delayed_work(&cinergyt2->query_work,
764 msecs_to_jiffies(QUERY_INTERVAL));
765
766 up(&cinergyt2->sem);
767}
768
769static int cinergyt2_probe (struct usb_interface *intf,
770 const struct usb_device_id *id)
771{
772 struct cinergyt2 *cinergyt2;
773 int i, err;
774
775 if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
776 dprintk(1, "out of memory?!?\n");
777 return -ENOMEM;
778 }
779
780 memset (cinergyt2, 0, sizeof (struct cinergyt2));
781 usb_set_intfdata (intf, (void *) cinergyt2);
782
783 init_MUTEX(&cinergyt2->sem);
784 init_waitqueue_head (&cinergyt2->poll_wq);
785 INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2);
786
787 cinergyt2->udev = interface_to_usbdev(intf);
788 cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
789
790 if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) {
791 dprintk(1, "unable to allocate stream urbs\n");
792 kfree(cinergyt2);
793 return -ENOMEM;
794 }
795
796 dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE);
797
798 cinergyt2->demux.priv = cinergyt2;
799 cinergyt2->demux.filternum = 256;
800 cinergyt2->demux.feednum = 256;
801 cinergyt2->demux.start_feed = cinergyt2_start_feed;
802 cinergyt2->demux.stop_feed = cinergyt2_stop_feed;
803 cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING |
804 DMX_SECTION_FILTERING |
805 DMX_MEMORY_BASED_FILTERING;
806
807 if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
808 dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
809 goto bailout;
810 }
811
812 cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum;
813 cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx;
814 cinergyt2->dmxdev.capabilities = 0;
815
816 if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, cinergyt2->adapter)) < 0) {
817 dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
818 goto bailout;
819 }
820
821 if (dvb_net_init(cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
822 dprintk(1, "dvb_net_init() failed!\n");
823
824 dvb_register_device(cinergyt2->adapter, &cinergyt2->fedev,
825 &cinergyt2_fe_template, cinergyt2,
826 DVB_DEVICE_FRONTEND);
827
828#ifdef ENABLE_RC
829 init_input_dev(&cinergyt2->rc_input_dev);
830
831 cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY);
832 cinergyt2->rc_input_dev.keycodesize = sizeof(unsigned char);
833 cinergyt2->rc_input_dev.keycodemax = KEY_MAX;
834 cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control";
835
836 for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3)
837 set_bit(rc_keys[i+2], cinergyt2->rc_input_dev.keybit);
838
839 input_register_device(&cinergyt2->rc_input_dev);
840
841 cinergyt2->rc_input_event = KEY_MAX;
842
843 INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2);
844 schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
845#endif
846 return 0;
847
848bailout:
849 dvb_dmxdev_release(&cinergyt2->dmxdev);
850 dvb_dmx_release(&cinergyt2->demux);
851 dvb_unregister_adapter (cinergyt2->adapter);
852 cinergyt2_free_stream_urbs (cinergyt2);
853 kfree(cinergyt2);
854 return -ENOMEM;
855}
856
857static void cinergyt2_disconnect (struct usb_interface *intf)
858{
859 struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
860
861 if (down_interruptible(&cinergyt2->sem))
862 return;
863
864#ifdef ENABLE_RC
865 cancel_delayed_work(&cinergyt2->rc_query_work);
866 flush_scheduled_work();
867 input_unregister_device(&cinergyt2->rc_input_dev);
868#endif
869
870 cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
871 dvb_net_release(&cinergyt2->dvbnet);
872 dvb_dmxdev_release(&cinergyt2->dmxdev);
873 dvb_dmx_release(&cinergyt2->demux);
874 dvb_unregister_device(cinergyt2->fedev);
875 dvb_unregister_adapter(cinergyt2->adapter);
876
877 cinergyt2_free_stream_urbs(cinergyt2);
878 up(&cinergyt2->sem);
879 kfree(cinergyt2);
880}
881
882static int cinergyt2_suspend (struct usb_interface *intf, u32 state)
883{
884 struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
885
886 if (down_interruptible(&cinergyt2->sem))
887 return -ERESTARTSYS;
888
889 if (state > 0) { /* state 0 seems to mean DEVICE_PM_ON */
890 struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
891#ifdef ENABLE_RC
892 cancel_delayed_work(&cinergyt2->rc_query_work);
893#endif
894 cancel_delayed_work(&cinergyt2->query_work);
895 if (cinergyt2->streaming)
896 cinergyt2_stop_stream_xfer(cinergyt2);
897 flush_scheduled_work();
898 cinergyt2_sleep(cinergyt2, 1);
899 }
900
901 up(&cinergyt2->sem);
902 return 0;
903}
904
905static int cinergyt2_resume (struct usb_interface *intf)
906{
907 struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
908 struct dvbt_set_parameters_msg *param = &cinergyt2->param;
909
910 if (down_interruptible(&cinergyt2->sem))
911 return -ERESTARTSYS;
912
913 if (!cinergyt2->sleeping) {
914 cinergyt2_sleep(cinergyt2, 0);
915 cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
916 if (cinergyt2->streaming)
917 cinergyt2_start_stream_xfer(cinergyt2);
918 schedule_delayed_work(&cinergyt2->query_work, HZ/2);
919 }
920
921#ifdef ENABLE_RC
922 schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
923#endif
924 up(&cinergyt2->sem);
925 return 0;
926}
927
928static const struct usb_device_id cinergyt2_table [] __devinitdata = {
929 { USB_DEVICE(0x0ccd, 0x0038) },
930 { 0 }
931};
932
933MODULE_DEVICE_TABLE(usb, cinergyt2_table);
934
935static struct usb_driver cinergyt2_driver = {
936 .owner = THIS_MODULE,
937 .name = "cinergyT2",
938 .probe = cinergyt2_probe,
939 .disconnect = cinergyt2_disconnect,
940 .suspend = cinergyt2_suspend,
941 .resume = cinergyt2_resume,
942 .id_table = cinergyt2_table
943};
944
945static int __init cinergyt2_init (void)
946{
947 int err;
948
949 if ((err = usb_register(&cinergyt2_driver)) < 0)
950 dprintk(1, "usb_register() failed! (err %i)\n", err);
951
952 return err;
953}
954
955static void __exit cinergyt2_exit (void)
956{
957 usb_deregister(&cinergyt2_driver);
958}
959
960module_init (cinergyt2_init);
961module_exit (cinergyt2_exit);
962
963MODULE_LICENSE("GPL");
964MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
965