aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/firewire
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/dvb/firewire
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/media/dvb/firewire')
-rw-r--r--drivers/media/dvb/firewire/Kconfig19
-rw-r--r--drivers/media/dvb/firewire/Makefile6
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c1457
-rw-r--r--drivers/media/dvb/firewire/firedtv-ci.c258
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c245
-rw-r--r--drivers/media/dvb/firewire/firedtv-fe.c273
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c430
-rw-r--r--drivers/media/dvb/firewire/firedtv-rc.c196
-rw-r--r--drivers/media/dvb/firewire/firedtv.h168
9 files changed, 3052 insertions, 0 deletions
diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig
new file mode 100644
index 00000000000..f3e9448c395
--- /dev/null
+++ b/drivers/media/dvb/firewire/Kconfig
@@ -0,0 +1,19 @@
1config DVB_FIREDTV
2 tristate "FireDTV and FloppyDTV"
3 depends on DVB_CORE && FIREWIRE
4 help
5 Support for DVB receivers from Digital Everywhere
6 which are connected via IEEE 1394 (FireWire).
7
8 These devices don't have an MPEG decoder built in,
9 so you need an external software decoder to watch TV.
10
11 To compile this driver as a module, say M here:
12 the module will be called firedtv.
13
14if DVB_FIREDTV
15
16config DVB_FIREDTV_INPUT
17 def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
18
19endif # DVB_FIREDTV
diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile
new file mode 100644
index 00000000000..357b3aab186
--- /dev/null
+++ b/drivers/media/dvb/firewire/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
2
3firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
4firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
5
6ccflags-y += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
new file mode 100644
index 00000000000..489ae824586
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -0,0 +1,1457 @@
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Ben Backx <ben@bbackx.com>
6 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 */
13
14#include <linux/bug.h>
15#include <linux/crc32.h>
16#include <linux/delay.h>
17#include <linux/device.h>
18#include <linux/jiffies.h>
19#include <linux/kernel.h>
20#include <linux/moduleparam.h>
21#include <linux/mutex.h>
22#include <linux/string.h>
23#include <linux/stringify.h>
24#include <linux/wait.h>
25#include <linux/workqueue.h>
26
27#include <dvb_frontend.h>
28
29#include "firedtv.h"
30
31#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL
32
33#define AVC_CTYPE_CONTROL 0x0
34#define AVC_CTYPE_STATUS 0x1
35#define AVC_CTYPE_NOTIFY 0x3
36
37#define AVC_RESPONSE_ACCEPTED 0x9
38#define AVC_RESPONSE_STABLE 0xc
39#define AVC_RESPONSE_CHANGED 0xd
40#define AVC_RESPONSE_INTERIM 0xf
41
42#define AVC_SUBUNIT_TYPE_TUNER (0x05 << 3)
43#define AVC_SUBUNIT_TYPE_UNIT (0x1f << 3)
44
45#define AVC_OPCODE_VENDOR 0x00
46#define AVC_OPCODE_READ_DESCRIPTOR 0x09
47#define AVC_OPCODE_DSIT 0xc8
48#define AVC_OPCODE_DSD 0xcb
49
50#define DESCRIPTOR_TUNER_STATUS 0x80
51#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00
52
53#define SFE_VENDOR_DE_COMPANYID_0 0x00 /* OUI of Digital Everywhere */
54#define SFE_VENDOR_DE_COMPANYID_1 0x12
55#define SFE_VENDOR_DE_COMPANYID_2 0x87
56
57#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a
58#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52
59#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 /* for DVB-S */
60
61#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00
62#define SFE_VENDOR_OPCODE_HOST2CA 0x56
63#define SFE_VENDOR_OPCODE_CA2HOST 0x57
64#define SFE_VENDOR_OPCODE_CISTATUS 0x59
65#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 /* for DVB-S2 */
66
67#define SFE_VENDOR_TAG_CA_RESET 0x00
68#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01
69#define SFE_VENDOR_TAG_CA_PMT 0x02
70#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04
71#define SFE_VENDOR_TAG_CA_MMI 0x05
72#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07
73
74#define EN50221_LIST_MANAGEMENT_ONLY 0x03
75#define EN50221_TAG_APP_INFO 0x9f8021
76#define EN50221_TAG_CA_INFO 0x9f8031
77
78struct avc_command_frame {
79 u8 ctype;
80 u8 subunit;
81 u8 opcode;
82 u8 operand[509];
83};
84
85struct avc_response_frame {
86 u8 response;
87 u8 subunit;
88 u8 opcode;
89 u8 operand[509];
90};
91
92#define LAST_OPERAND (509 - 1)
93
94static inline void clear_operands(struct avc_command_frame *c, int from, int to)
95{
96 memset(&c->operand[from], 0, to - from + 1);
97}
98
99static void pad_operands(struct avc_command_frame *c, int from)
100{
101 int to = ALIGN(from, 4);
102
103 if (from <= to && to <= LAST_OPERAND)
104 clear_operands(c, from, to);
105}
106
107#define AVC_DEBUG_READ_DESCRIPTOR 0x0001
108#define AVC_DEBUG_DSIT 0x0002
109#define AVC_DEBUG_DSD 0x0004
110#define AVC_DEBUG_REGISTER_REMOTE_CONTROL 0x0008
111#define AVC_DEBUG_LNB_CONTROL 0x0010
112#define AVC_DEBUG_TUNE_QPSK 0x0020
113#define AVC_DEBUG_TUNE_QPSK2 0x0040
114#define AVC_DEBUG_HOST2CA 0x0080
115#define AVC_DEBUG_CA2HOST 0x0100
116#define AVC_DEBUG_APPLICATION_PMT 0x4000
117#define AVC_DEBUG_FCP_PAYLOADS 0x8000
118
119static int avc_debug;
120module_param_named(debug, avc_debug, int, 0644);
121MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
122 ", FCP subactions"
123 ": READ DESCRIPTOR = " __stringify(AVC_DEBUG_READ_DESCRIPTOR)
124 ", DSIT = " __stringify(AVC_DEBUG_DSIT)
125 ", REGISTER_REMOTE_CONTROL = " __stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL)
126 ", LNB CONTROL = " __stringify(AVC_DEBUG_LNB_CONTROL)
127 ", TUNE QPSK = " __stringify(AVC_DEBUG_TUNE_QPSK)
128 ", TUNE QPSK2 = " __stringify(AVC_DEBUG_TUNE_QPSK2)
129 ", HOST2CA = " __stringify(AVC_DEBUG_HOST2CA)
130 ", CA2HOST = " __stringify(AVC_DEBUG_CA2HOST)
131 "; Application sent PMT = " __stringify(AVC_DEBUG_APPLICATION_PMT)
132 ", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS)
133 ", or a combination, or all = -1)");
134
135/*
136 * This is a workaround since there is no vendor specific command to retrieve
137 * ca_info using AVC. If this parameter is not used, ca_system_id will be
138 * filled with application_manufacturer from ca_app_info.
139 * Digital Everywhere have said that adding ca_info is on their TODO list.
140 */
141static unsigned int num_fake_ca_system_ids;
142static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
143module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
144MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
145 "does not have the same ca_system_id as your CAS, you can "
146 "override what ca_system_ids are presented to the "
147 "application by setting this field to an array of ids.");
148
149static const char *debug_fcp_ctype(unsigned int ctype)
150{
151 static const char *ctypes[] = {
152 [0x0] = "CONTROL", [0x1] = "STATUS",
153 [0x2] = "SPECIFIC INQUIRY", [0x3] = "NOTIFY",
154 [0x4] = "GENERAL INQUIRY", [0x8] = "NOT IMPLEMENTED",
155 [0x9] = "ACCEPTED", [0xa] = "REJECTED",
156 [0xb] = "IN TRANSITION", [0xc] = "IMPLEMENTED/STABLE",
157 [0xd] = "CHANGED", [0xf] = "INTERIM",
158 };
159 const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL;
160
161 return ret ? ret : "?";
162}
163
164static const char *debug_fcp_opcode(unsigned int opcode,
165 const u8 *data, int length)
166{
167 switch (opcode) {
168 case AVC_OPCODE_VENDOR:
169 break;
170 case AVC_OPCODE_READ_DESCRIPTOR:
171 return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ?
172 "ReadDescriptor" : NULL;
173 case AVC_OPCODE_DSIT:
174 return avc_debug & AVC_DEBUG_DSIT ?
175 "DirectSelectInfo.Type" : NULL;
176 case AVC_OPCODE_DSD:
177 return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL;
178 default:
179 return "Unknown";
180 }
181
182 if (length < 7 ||
183 data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
184 data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
185 data[5] != SFE_VENDOR_DE_COMPANYID_2)
186 return "Vendor/Unknown";
187
188 switch (data[6]) {
189 case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL:
190 return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ?
191 "RegisterRC" : NULL;
192 case SFE_VENDOR_OPCODE_LNB_CONTROL:
193 return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL;
194 case SFE_VENDOR_OPCODE_TUNE_QPSK:
195 return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL;
196 case SFE_VENDOR_OPCODE_TUNE_QPSK2:
197 return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL;
198 case SFE_VENDOR_OPCODE_HOST2CA:
199 return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL;
200 case SFE_VENDOR_OPCODE_CA2HOST:
201 return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL;
202 }
203 return "Vendor/Unknown";
204}
205
206static void debug_fcp(const u8 *data, int length)
207{
208 unsigned int subunit_type, subunit_id, opcode;
209 const char *op, *prefix;
210
211 prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
212 subunit_type = data[1] >> 3;
213 subunit_id = data[1] & 7;
214 opcode = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
215 op = debug_fcp_opcode(opcode, data, length);
216
217 if (op) {
218 printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
219 prefix, subunit_type, subunit_id, length,
220 debug_fcp_ctype(data[0]), op);
221 if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
222 print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE,
223 16, 1, data, length, false);
224 }
225}
226
227static void debug_pmt(char *msg, int length)
228{
229 printk(KERN_INFO "APP PMT -> l=%d\n", length);
230 print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE,
231 16, 1, msg, length, false);
232}
233
234static int avc_write(struct firedtv *fdtv)
235{
236 int err, retry;
237
238 fdtv->avc_reply_received = false;
239
240 for (retry = 0; retry < 6; retry++) {
241 if (unlikely(avc_debug))
242 debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
243
244 err = fdtv_write(fdtv, FCP_COMMAND_REGISTER,
245 fdtv->avc_data, fdtv->avc_data_length);
246 if (err) {
247 dev_err(fdtv->device, "FCP command write failed\n");
248
249 return err;
250 }
251
252 /*
253 * AV/C specs say that answers should be sent within 150 ms.
254 * Time out after 200 ms.
255 */
256 if (wait_event_timeout(fdtv->avc_wait,
257 fdtv->avc_reply_received,
258 msecs_to_jiffies(200)) != 0)
259 return 0;
260 }
261 dev_err(fdtv->device, "FCP response timed out\n");
262
263 return -ETIMEDOUT;
264}
265
266static bool is_register_rc(struct avc_response_frame *r)
267{
268 return r->opcode == AVC_OPCODE_VENDOR &&
269 r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
270 r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
271 r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
272 r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
273}
274
275int avc_recv(struct firedtv *fdtv, void *data, size_t length)
276{
277 struct avc_response_frame *r = data;
278
279 if (unlikely(avc_debug))
280 debug_fcp(data, length);
281
282 if (length >= 8 && is_register_rc(r)) {
283 switch (r->response) {
284 case AVC_RESPONSE_CHANGED:
285 fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
286 schedule_work(&fdtv->remote_ctrl_work);
287 break;
288 case AVC_RESPONSE_INTERIM:
289 if (is_register_rc((void *)fdtv->avc_data))
290 goto wake;
291 break;
292 default:
293 dev_info(fdtv->device,
294 "remote control result = %d\n", r->response);
295 }
296 return 0;
297 }
298
299 if (fdtv->avc_reply_received) {
300 dev_err(fdtv->device, "out-of-order AVC response, ignored\n");
301 return -EIO;
302 }
303
304 memcpy(fdtv->avc_data, data, length);
305 fdtv->avc_data_length = length;
306wake:
307 fdtv->avc_reply_received = true;
308 wake_up(&fdtv->avc_wait);
309
310 return 0;
311}
312
313static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
314{
315 int i, n, pos = 1;
316
317 for (i = 0, n = 0; i < 16; i++) {
318 if (test_bit(i, &fdtv->channel_active)) {
319 operand[pos++] = 0x13; /* flowfunction relay */
320 operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
321 operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f;
322 operand[pos++] = fdtv->channel_pid[i] & 0xff;
323 operand[pos++] = 0x00; /* tableID */
324 operand[pos++] = 0x00; /* filter_length */
325 n++;
326 }
327 }
328 operand[0] = n;
329
330 return pos;
331}
332
333/*
334 * tuning command for setting the relative LNB frequency
335 * (not supported by the AVC standard)
336 */
337static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
338 struct dvb_frontend_parameters *params)
339{
340 struct avc_command_frame *c = (void *)fdtv->avc_data;
341
342 c->opcode = AVC_OPCODE_VENDOR;
343
344 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
345 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
346 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
347 if (fdtv->type == FIREDTV_DVB_S2)
348 c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2;
349 else
350 c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
351
352 c->operand[4] = (params->frequency >> 24) & 0xff;
353 c->operand[5] = (params->frequency >> 16) & 0xff;
354 c->operand[6] = (params->frequency >> 8) & 0xff;
355 c->operand[7] = params->frequency & 0xff;
356
357 c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff;
358 c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff;
359
360 switch (params->u.qpsk.fec_inner) {
361 case FEC_1_2: c->operand[10] = 0x1; break;
362 case FEC_2_3: c->operand[10] = 0x2; break;
363 case FEC_3_4: c->operand[10] = 0x3; break;
364 case FEC_5_6: c->operand[10] = 0x4; break;
365 case FEC_7_8: c->operand[10] = 0x5; break;
366 case FEC_4_5:
367 case FEC_8_9:
368 case FEC_AUTO:
369 default: c->operand[10] = 0x0;
370 }
371
372 if (fdtv->voltage == 0xff)
373 c->operand[11] = 0xff;
374 else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */
375 c->operand[11] = 0;
376 else
377 c->operand[11] = 1;
378
379 if (fdtv->tone == 0xff)
380 c->operand[12] = 0xff;
381 else if (fdtv->tone == SEC_TONE_ON) /* band */
382 c->operand[12] = 1;
383 else
384 c->operand[12] = 0;
385
386 if (fdtv->type == FIREDTV_DVB_S2) {
387 if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
388 switch (fdtv->fe.dtv_property_cache.modulation) {
389 case QAM_16: c->operand[13] = 0x1; break;
390 case QPSK: c->operand[13] = 0x2; break;
391 case PSK_8: c->operand[13] = 0x3; break;
392 default: c->operand[13] = 0x2; break;
393 }
394 switch (fdtv->fe.dtv_property_cache.rolloff) {
395 case ROLLOFF_AUTO: c->operand[14] = 0x2; break;
396 case ROLLOFF_35: c->operand[14] = 0x2; break;
397 case ROLLOFF_20: c->operand[14] = 0x0; break;
398 case ROLLOFF_25: c->operand[14] = 0x1; break;
399 /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */
400 }
401 switch (fdtv->fe.dtv_property_cache.pilot) {
402 case PILOT_AUTO: c->operand[15] = 0x0; break;
403 case PILOT_OFF: c->operand[15] = 0x0; break;
404 case PILOT_ON: c->operand[15] = 0x1; break;
405 }
406 } else {
407 c->operand[13] = 0x1; /* auto modulation */
408 c->operand[14] = 0xff; /* disable rolloff */
409 c->operand[15] = 0xff; /* disable pilot */
410 }
411 return 16;
412 } else {
413 return 13;
414 }
415}
416
417static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
418 struct dvb_frontend_parameters *params)
419{
420 struct avc_command_frame *c = (void *)fdtv->avc_data;
421
422 c->opcode = AVC_OPCODE_DSD;
423
424 c->operand[0] = 0; /* source plug */
425 c->operand[1] = 0xd2; /* subfunction replace */
426 c->operand[2] = 0x20; /* system id = DVB */
427 c->operand[3] = 0x00; /* antenna number */
428 c->operand[4] = 0x11; /* system_specific_multiplex selection_length */
429
430 /* multiplex_valid_flags, high byte */
431 c->operand[5] = 0 << 7 /* reserved */
432 | 0 << 6 /* Polarisation */
433 | 0 << 5 /* Orbital_Pos */
434 | 1 << 4 /* Frequency */
435 | 1 << 3 /* Symbol_Rate */
436 | 0 << 2 /* FEC_outer */
437 | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0)
438 | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0);
439
440 /* multiplex_valid_flags, low byte */
441 c->operand[6] = 0 << 7 /* NetworkID */
442 | 0 << 0 /* reserved */ ;
443
444 c->operand[7] = 0x00;
445 c->operand[8] = 0x00;
446 c->operand[9] = 0x00;
447 c->operand[10] = 0x00;
448
449 c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6);
450 c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff;
451 c->operand[13] = (params->frequency / 4000) & 0xff;
452 c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff;
453 c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff;
454 c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0;
455 c->operand[17] = 0x00;
456
457 switch (params->u.qpsk.fec_inner) {
458 case FEC_1_2: c->operand[18] = 0x1; break;
459 case FEC_2_3: c->operand[18] = 0x2; break;
460 case FEC_3_4: c->operand[18] = 0x3; break;
461 case FEC_5_6: c->operand[18] = 0x4; break;
462 case FEC_7_8: c->operand[18] = 0x5; break;
463 case FEC_8_9: c->operand[18] = 0x6; break;
464 case FEC_4_5: c->operand[18] = 0x8; break;
465 case FEC_AUTO:
466 default: c->operand[18] = 0x0;
467 }
468
469 switch (params->u.qam.modulation) {
470 case QAM_16: c->operand[19] = 0x08; break;
471 case QAM_32: c->operand[19] = 0x10; break;
472 case QAM_64: c->operand[19] = 0x18; break;
473 case QAM_128: c->operand[19] = 0x20; break;
474 case QAM_256: c->operand[19] = 0x28; break;
475 case QAM_AUTO:
476 default: c->operand[19] = 0x00;
477 }
478
479 c->operand[20] = 0x00;
480 c->operand[21] = 0x00;
481
482 return 22 + add_pid_filter(fdtv, &c->operand[22]);
483}
484
485static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
486 struct dvb_frontend_parameters *params)
487{
488 struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
489 struct avc_command_frame *c = (void *)fdtv->avc_data;
490
491 c->opcode = AVC_OPCODE_DSD;
492
493 c->operand[0] = 0; /* source plug */
494 c->operand[1] = 0xd2; /* subfunction replace */
495 c->operand[2] = 0x20; /* system id = DVB */
496 c->operand[3] = 0x00; /* antenna number */
497 c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */
498
499 /* multiplex_valid_flags, high byte */
500 c->operand[5] =
501 0 << 7 /* reserved */
502 | 1 << 6 /* CenterFrequency */
503 | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0)
504 | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0)
505 | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0)
506 | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0)
507 | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0)
508 | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0);
509
510 /* multiplex_valid_flags, low byte */
511 c->operand[6] =
512 0 << 7 /* NetworkID */
513 | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
514 | 0 << 5 /* OtherFrequencyFlag */
515 | 0 << 0 /* reserved */ ;
516
517 c->operand[7] = 0x0;
518 c->operand[8] = (params->frequency / 10) >> 24;
519 c->operand[9] = ((params->frequency / 10) >> 16) & 0xff;
520 c->operand[10] = ((params->frequency / 10) >> 8) & 0xff;
521 c->operand[11] = (params->frequency / 10) & 0xff;
522
523 switch (ofdm->bandwidth) {
524 case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break;
525 case BANDWIDTH_8_MHZ:
526 case BANDWIDTH_6_MHZ: /* not defined by AVC spec */
527 case BANDWIDTH_AUTO:
528 default: c->operand[12] = 0x00;
529 }
530
531 switch (ofdm->constellation) {
532 case QAM_16: c->operand[13] = 1 << 6; break;
533 case QAM_64: c->operand[13] = 2 << 6; break;
534 case QPSK:
535 default: c->operand[13] = 0x00;
536 }
537
538 switch (ofdm->hierarchy_information) {
539 case HIERARCHY_1: c->operand[13] |= 1 << 3; break;
540 case HIERARCHY_2: c->operand[13] |= 2 << 3; break;
541 case HIERARCHY_4: c->operand[13] |= 3 << 3; break;
542 case HIERARCHY_AUTO:
543 case HIERARCHY_NONE:
544 default: break;
545 }
546
547 switch (ofdm->code_rate_HP) {
548 case FEC_2_3: c->operand[13] |= 1; break;
549 case FEC_3_4: c->operand[13] |= 2; break;
550 case FEC_5_6: c->operand[13] |= 3; break;
551 case FEC_7_8: c->operand[13] |= 4; break;
552 case FEC_1_2:
553 default: break;
554 }
555
556 switch (ofdm->code_rate_LP) {
557 case FEC_2_3: c->operand[14] = 1 << 5; break;
558 case FEC_3_4: c->operand[14] = 2 << 5; break;
559 case FEC_5_6: c->operand[14] = 3 << 5; break;
560 case FEC_7_8: c->operand[14] = 4 << 5; break;
561 case FEC_1_2:
562 default: c->operand[14] = 0x00; break;
563 }
564
565 switch (ofdm->guard_interval) {
566 case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break;
567 case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break;
568 case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break;
569 case GUARD_INTERVAL_1_32:
570 case GUARD_INTERVAL_AUTO:
571 default: break;
572 }
573
574 switch (ofdm->transmission_mode) {
575 case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break;
576 case TRANSMISSION_MODE_2K:
577 case TRANSMISSION_MODE_AUTO:
578 default: break;
579 }
580
581 c->operand[15] = 0x00; /* network_ID[0] */
582 c->operand[16] = 0x00; /* network_ID[1] */
583
584 return 17 + add_pid_filter(fdtv, &c->operand[17]);
585}
586
587int avc_tuner_dsd(struct firedtv *fdtv,
588 struct dvb_frontend_parameters *params)
589{
590 struct avc_command_frame *c = (void *)fdtv->avc_data;
591 int pos, ret;
592
593 mutex_lock(&fdtv->avc_mutex);
594
595 c->ctype = AVC_CTYPE_CONTROL;
596 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
597
598 switch (fdtv->type) {
599 case FIREDTV_DVB_S:
600 case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
601 case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
602 case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
603 default:
604 BUG();
605 }
606 pad_operands(c, pos);
607
608 fdtv->avc_data_length = ALIGN(3 + pos, 4);
609 ret = avc_write(fdtv);
610#if 0
611 /*
612 * FIXME:
613 * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
614 * Check for AVC_RESPONSE_ACCEPTED here instead?
615 */
616 if (status)
617 *status = r->operand[2];
618#endif
619 mutex_unlock(&fdtv->avc_mutex);
620
621 if (ret == 0)
622 msleep(500);
623
624 return ret;
625}
626
627int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
628{
629 struct avc_command_frame *c = (void *)fdtv->avc_data;
630 int ret, pos, k;
631
632 if (pidc > 16 && pidc != 0xff)
633 return -EINVAL;
634
635 mutex_lock(&fdtv->avc_mutex);
636
637 c->ctype = AVC_CTYPE_CONTROL;
638 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
639 c->opcode = AVC_OPCODE_DSD;
640
641 c->operand[0] = 0; /* source plug */
642 c->operand[1] = 0xd2; /* subfunction replace */
643 c->operand[2] = 0x20; /* system id = DVB */
644 c->operand[3] = 0x00; /* antenna number */
645 c->operand[4] = 0x00; /* system_specific_multiplex selection_length */
646 c->operand[5] = pidc; /* Nr_of_dsd_sel_specs */
647
648 pos = 6;
649 if (pidc != 0xff)
650 for (k = 0; k < pidc; k++) {
651 c->operand[pos++] = 0x13; /* flowfunction relay */
652 c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
653 c->operand[pos++] = (pid[k] >> 8) & 0x1f;
654 c->operand[pos++] = pid[k] & 0xff;
655 c->operand[pos++] = 0x00; /* tableID */
656 c->operand[pos++] = 0x00; /* filter_length */
657 }
658 pad_operands(c, pos);
659
660 fdtv->avc_data_length = ALIGN(3 + pos, 4);
661 ret = avc_write(fdtv);
662
663 /* FIXME: check response code? */
664
665 mutex_unlock(&fdtv->avc_mutex);
666
667 if (ret == 0)
668 msleep(50);
669
670 return ret;
671}
672
673int avc_tuner_get_ts(struct firedtv *fdtv)
674{
675 struct avc_command_frame *c = (void *)fdtv->avc_data;
676 int ret, sl;
677
678 mutex_lock(&fdtv->avc_mutex);
679
680 c->ctype = AVC_CTYPE_CONTROL;
681 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
682 c->opcode = AVC_OPCODE_DSIT;
683
684 sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11;
685
686 c->operand[0] = 0; /* source plug */
687 c->operand[1] = 0xd2; /* subfunction replace */
688 c->operand[2] = 0xff; /* status */
689 c->operand[3] = 0x20; /* system id = DVB */
690 c->operand[4] = 0x00; /* antenna number */
691 c->operand[5] = 0x0; /* system_specific_search_flags */
692 c->operand[6] = sl; /* system_specific_multiplex selection_length */
693 /*
694 * operand[7]: valid_flags[0]
695 * operand[8]: valid_flags[1]
696 * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
697 */
698 clear_operands(c, 7, 24);
699
700 fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
701 ret = avc_write(fdtv);
702
703 /* FIXME: check response code? */
704
705 mutex_unlock(&fdtv->avc_mutex);
706
707 if (ret == 0)
708 msleep(250);
709
710 return ret;
711}
712
713int avc_identify_subunit(struct firedtv *fdtv)
714{
715 struct avc_command_frame *c = (void *)fdtv->avc_data;
716 struct avc_response_frame *r = (void *)fdtv->avc_data;
717 int ret;
718
719 mutex_lock(&fdtv->avc_mutex);
720
721 c->ctype = AVC_CTYPE_CONTROL;
722 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
723 c->opcode = AVC_OPCODE_READ_DESCRIPTOR;
724
725 c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER;
726 c->operand[1] = 0xff;
727 c->operand[2] = 0x00;
728 c->operand[3] = 0x00; /* length highbyte */
729 c->operand[4] = 0x08; /* length lowbyte */
730 c->operand[5] = 0x00; /* offset highbyte */
731 c->operand[6] = 0x0d; /* offset lowbyte */
732 clear_operands(c, 7, 8); /* padding */
733
734 fdtv->avc_data_length = 12;
735 ret = avc_write(fdtv);
736 if (ret < 0)
737 goto out;
738
739 if ((r->response != AVC_RESPONSE_STABLE &&
740 r->response != AVC_RESPONSE_ACCEPTED) ||
741 (r->operand[3] << 8) + r->operand[4] != 8) {
742 dev_err(fdtv->device, "cannot read subunit identifier\n");
743 ret = -EINVAL;
744 }
745out:
746 mutex_unlock(&fdtv->avc_mutex);
747
748 return ret;
749}
750
751#define SIZEOF_ANTENNA_INPUT_INFO 22
752
753int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
754{
755 struct avc_command_frame *c = (void *)fdtv->avc_data;
756 struct avc_response_frame *r = (void *)fdtv->avc_data;
757 int length, ret;
758
759 mutex_lock(&fdtv->avc_mutex);
760
761 c->ctype = AVC_CTYPE_CONTROL;
762 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
763 c->opcode = AVC_OPCODE_READ_DESCRIPTOR;
764
765 c->operand[0] = DESCRIPTOR_TUNER_STATUS;
766 c->operand[1] = 0xff; /* read_result_status */
767 /*
768 * operand[2]: reserved
769 * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
770 * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
771 */
772 clear_operands(c, 2, 31);
773
774 fdtv->avc_data_length = 12;
775 ret = avc_write(fdtv);
776 if (ret < 0)
777 goto out;
778
779 if (r->response != AVC_RESPONSE_STABLE &&
780 r->response != AVC_RESPONSE_ACCEPTED) {
781 dev_err(fdtv->device, "cannot read tuner status\n");
782 ret = -EINVAL;
783 goto out;
784 }
785
786 length = r->operand[9];
787 if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
788 dev_err(fdtv->device, "got invalid tuner status\n");
789 ret = -EINVAL;
790 goto out;
791 }
792
793 stat->active_system = r->operand[10];
794 stat->searching = r->operand[11] >> 7 & 1;
795 stat->moving = r->operand[11] >> 6 & 1;
796 stat->no_rf = r->operand[11] >> 5 & 1;
797 stat->input = r->operand[12] >> 7 & 1;
798 stat->selected_antenna = r->operand[12] & 0x7f;
799 stat->ber = r->operand[13] << 24 |
800 r->operand[14] << 16 |
801 r->operand[15] << 8 |
802 r->operand[16];
803 stat->signal_strength = r->operand[17];
804 stat->raster_frequency = r->operand[18] >> 6 & 2;
805 stat->rf_frequency = (r->operand[18] & 0x3f) << 16 |
806 r->operand[19] << 8 |
807 r->operand[20];
808 stat->man_dep_info_length = r->operand[21];
809 stat->front_end_error = r->operand[22] >> 4 & 1;
810 stat->antenna_error = r->operand[22] >> 3 & 1;
811 stat->front_end_power_status = r->operand[22] >> 1 & 1;
812 stat->power_supply = r->operand[22] & 1;
813 stat->carrier_noise_ratio = r->operand[23] << 8 |
814 r->operand[24];
815 stat->power_supply_voltage = r->operand[27];
816 stat->antenna_voltage = r->operand[28];
817 stat->firewire_bus_voltage = r->operand[29];
818 stat->ca_mmi = r->operand[30] & 1;
819 stat->ca_pmt_reply = r->operand[31] >> 7 & 1;
820 stat->ca_date_time_request = r->operand[31] >> 6 & 1;
821 stat->ca_application_info = r->operand[31] >> 5 & 1;
822 stat->ca_module_present_status = r->operand[31] >> 4 & 1;
823 stat->ca_dvb_flag = r->operand[31] >> 3 & 1;
824 stat->ca_error_flag = r->operand[31] >> 2 & 1;
825 stat->ca_initialization_status = r->operand[31] >> 1 & 1;
826out:
827 mutex_unlock(&fdtv->avc_mutex);
828
829 return ret;
830}
831
832int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
833 char conttone, char nrdiseq,
834 struct dvb_diseqc_master_cmd *diseqcmd)
835{
836 struct avc_command_frame *c = (void *)fdtv->avc_data;
837 struct avc_response_frame *r = (void *)fdtv->avc_data;
838 int pos, j, k, ret;
839
840 mutex_lock(&fdtv->avc_mutex);
841
842 c->ctype = AVC_CTYPE_CONTROL;
843 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
844 c->opcode = AVC_OPCODE_VENDOR;
845
846 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
847 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
848 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
849 c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
850 c->operand[4] = voltage;
851 c->operand[5] = nrdiseq;
852
853 pos = 6;
854 for (j = 0; j < nrdiseq; j++) {
855 c->operand[pos++] = diseqcmd[j].msg_len;
856
857 for (k = 0; k < diseqcmd[j].msg_len; k++)
858 c->operand[pos++] = diseqcmd[j].msg[k];
859 }
860 c->operand[pos++] = burst;
861 c->operand[pos++] = conttone;
862 pad_operands(c, pos);
863
864 fdtv->avc_data_length = ALIGN(3 + pos, 4);
865 ret = avc_write(fdtv);
866 if (ret < 0)
867 goto out;
868
869 if (r->response != AVC_RESPONSE_ACCEPTED) {
870 dev_err(fdtv->device, "LNB control failed\n");
871 ret = -EINVAL;
872 }
873out:
874 mutex_unlock(&fdtv->avc_mutex);
875
876 return ret;
877}
878
879int avc_register_remote_control(struct firedtv *fdtv)
880{
881 struct avc_command_frame *c = (void *)fdtv->avc_data;
882 int ret;
883
884 mutex_lock(&fdtv->avc_mutex);
885
886 c->ctype = AVC_CTYPE_NOTIFY;
887 c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
888 c->opcode = AVC_OPCODE_VENDOR;
889
890 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
891 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
892 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
893 c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
894 c->operand[4] = 0; /* padding */
895
896 fdtv->avc_data_length = 8;
897 ret = avc_write(fdtv);
898
899 /* FIXME: check response code? */
900
901 mutex_unlock(&fdtv->avc_mutex);
902
903 return ret;
904}
905
906void avc_remote_ctrl_work(struct work_struct *work)
907{
908 struct firedtv *fdtv =
909 container_of(work, struct firedtv, remote_ctrl_work);
910
911 /* Should it be rescheduled in failure cases? */
912 avc_register_remote_control(fdtv);
913}
914
915#if 0 /* FIXME: unused */
916int avc_tuner_host2ca(struct firedtv *fdtv)
917{
918 struct avc_command_frame *c = (void *)fdtv->avc_data;
919 int ret;
920
921 mutex_lock(&fdtv->avc_mutex);
922
923 c->ctype = AVC_CTYPE_CONTROL;
924 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
925 c->opcode = AVC_OPCODE_VENDOR;
926
927 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
928 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
929 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
930 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
931 c->operand[4] = 0; /* slot */
932 c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
933 clear_operands(c, 6, 8);
934
935 fdtv->avc_data_length = 12;
936 ret = avc_write(fdtv);
937
938 /* FIXME: check response code? */
939
940 mutex_unlock(&fdtv->avc_mutex);
941
942 return ret;
943}
944#endif
945
946static int get_ca_object_pos(struct avc_response_frame *r)
947{
948 int length = 1;
949
950 /* Check length of length field */
951 if (r->operand[7] & 0x80)
952 length = (r->operand[7] & 0x7f) + 1;
953 return length + 7;
954}
955
956static int get_ca_object_length(struct avc_response_frame *r)
957{
958#if 0 /* FIXME: unused */
959 int size = 0;
960 int i;
961
962 if (r->operand[7] & 0x80)
963 for (i = 0; i < (r->operand[7] & 0x7f); i++) {
964 size <<= 8;
965 size += r->operand[8 + i];
966 }
967#endif
968 return r->operand[7];
969}
970
971int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
972{
973 struct avc_command_frame *c = (void *)fdtv->avc_data;
974 struct avc_response_frame *r = (void *)fdtv->avc_data;
975 int pos, ret;
976
977 mutex_lock(&fdtv->avc_mutex);
978
979 c->ctype = AVC_CTYPE_STATUS;
980 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
981 c->opcode = AVC_OPCODE_VENDOR;
982
983 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
984 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
985 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
986 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
987 c->operand[4] = 0; /* slot */
988 c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
989 clear_operands(c, 6, LAST_OPERAND);
990
991 fdtv->avc_data_length = 12;
992 ret = avc_write(fdtv);
993 if (ret < 0)
994 goto out;
995
996 /* FIXME: check response code and validate response data */
997
998 pos = get_ca_object_pos(r);
999 app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff;
1000 app_info[1] = (EN50221_TAG_APP_INFO >> 8) & 0xff;
1001 app_info[2] = (EN50221_TAG_APP_INFO >> 0) & 0xff;
1002 app_info[3] = 6 + r->operand[pos + 4];
1003 app_info[4] = 0x01;
1004 memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
1005 *len = app_info[3] + 4;
1006out:
1007 mutex_unlock(&fdtv->avc_mutex);
1008
1009 return ret;
1010}
1011
1012int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
1013{
1014 struct avc_command_frame *c = (void *)fdtv->avc_data;
1015 struct avc_response_frame *r = (void *)fdtv->avc_data;
1016 int i, pos, ret;
1017
1018 mutex_lock(&fdtv->avc_mutex);
1019
1020 c->ctype = AVC_CTYPE_STATUS;
1021 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1022 c->opcode = AVC_OPCODE_VENDOR;
1023
1024 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1025 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1026 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1027 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1028 c->operand[4] = 0; /* slot */
1029 c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
1030 clear_operands(c, 6, LAST_OPERAND);
1031
1032 fdtv->avc_data_length = 12;
1033 ret = avc_write(fdtv);
1034 if (ret < 0)
1035 goto out;
1036
1037 /* FIXME: check response code and validate response data */
1038
1039 pos = get_ca_object_pos(r);
1040 app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
1041 app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff;
1042 app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff;
1043 if (num_fake_ca_system_ids == 0) {
1044 app_info[3] = 2;
1045 app_info[4] = r->operand[pos + 0];
1046 app_info[5] = r->operand[pos + 1];
1047 } else {
1048 app_info[3] = num_fake_ca_system_ids * 2;
1049 for (i = 0; i < num_fake_ca_system_ids; i++) {
1050 app_info[4 + i * 2] =
1051 (fake_ca_system_ids[i] >> 8) & 0xff;
1052 app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
1053 }
1054 }
1055 *len = app_info[3] + 4;
1056out:
1057 mutex_unlock(&fdtv->avc_mutex);
1058
1059 return ret;
1060}
1061
1062int avc_ca_reset(struct firedtv *fdtv)
1063{
1064 struct avc_command_frame *c = (void *)fdtv->avc_data;
1065 int ret;
1066
1067 mutex_lock(&fdtv->avc_mutex);
1068
1069 c->ctype = AVC_CTYPE_CONTROL;
1070 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1071 c->opcode = AVC_OPCODE_VENDOR;
1072
1073 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1074 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1075 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1076 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1077 c->operand[4] = 0; /* slot */
1078 c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */
1079 c->operand[6] = 0; /* more/last */
1080 c->operand[7] = 1; /* length */
1081 c->operand[8] = 0; /* force hardware reset */
1082
1083 fdtv->avc_data_length = 12;
1084 ret = avc_write(fdtv);
1085
1086 /* FIXME: check response code? */
1087
1088 mutex_unlock(&fdtv->avc_mutex);
1089
1090 return ret;
1091}
1092
1093int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
1094{
1095 struct avc_command_frame *c = (void *)fdtv->avc_data;
1096 struct avc_response_frame *r = (void *)fdtv->avc_data;
1097 int list_management;
1098 int program_info_length;
1099 int pmt_cmd_id;
1100 int read_pos;
1101 int write_pos;
1102 int es_info_length;
1103 int crc32_csum;
1104 int ret;
1105
1106 if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
1107 debug_pmt(msg, length);
1108
1109 mutex_lock(&fdtv->avc_mutex);
1110
1111 c->ctype = AVC_CTYPE_CONTROL;
1112 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1113 c->opcode = AVC_OPCODE_VENDOR;
1114
1115 if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) {
1116 dev_info(fdtv->device, "forcing list_management to ONLY\n");
1117 msg[0] = EN50221_LIST_MANAGEMENT_ONLY;
1118 }
1119 /* We take the cmd_id from the programme level only! */
1120 list_management = msg[0];
1121 program_info_length = ((msg[4] & 0x0f) << 8) + msg[5];
1122 if (program_info_length > 0)
1123 program_info_length--; /* Remove pmt_cmd_id */
1124 pmt_cmd_id = msg[6];
1125
1126 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1127 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1128 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1129 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1130 c->operand[4] = 0; /* slot */
1131 c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */
1132 c->operand[6] = 0; /* more/last */
1133 /* Use three bytes for length field in case length > 127 */
1134 c->operand[10] = list_management;
1135 c->operand[11] = 0x01; /* pmt_cmd=OK_descramble */
1136
1137 /* TS program map table */
1138
1139 c->operand[12] = 0x02; /* Table id=2 */
1140 c->operand[13] = 0x80; /* Section syntax + length */
1141
1142 c->operand[15] = msg[1]; /* Program number */
1143 c->operand[16] = msg[2];
1144 c->operand[17] = msg[3]; /* Version number and current/next */
1145 c->operand[18] = 0x00; /* Section number=0 */
1146 c->operand[19] = 0x00; /* Last section number=0 */
1147 c->operand[20] = 0x1f; /* PCR_PID=1FFF */
1148 c->operand[21] = 0xff;
1149 c->operand[22] = (program_info_length >> 8); /* Program info length */
1150 c->operand[23] = (program_info_length & 0xff);
1151
1152 /* CA descriptors at programme level */
1153 read_pos = 6;
1154 write_pos = 24;
1155 if (program_info_length > 0) {
1156 pmt_cmd_id = msg[read_pos++];
1157 if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
1158 dev_err(fdtv->device,
1159 "invalid pmt_cmd_id %d\n", pmt_cmd_id);
1160
1161 memcpy(&c->operand[write_pos], &msg[read_pos],
1162 program_info_length);
1163 read_pos += program_info_length;
1164 write_pos += program_info_length;
1165 }
1166 while (read_pos < length) {
1167 c->operand[write_pos++] = msg[read_pos++];
1168 c->operand[write_pos++] = msg[read_pos++];
1169 c->operand[write_pos++] = msg[read_pos++];
1170 es_info_length =
1171 ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1];
1172 read_pos += 2;
1173 if (es_info_length > 0)
1174 es_info_length--; /* Remove pmt_cmd_id */
1175 c->operand[write_pos++] = es_info_length >> 8;
1176 c->operand[write_pos++] = es_info_length & 0xff;
1177 if (es_info_length > 0) {
1178 pmt_cmd_id = msg[read_pos++];
1179 if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
1180 dev_err(fdtv->device, "invalid pmt_cmd_id %d "
1181 "at stream level\n", pmt_cmd_id);
1182
1183 memcpy(&c->operand[write_pos], &msg[read_pos],
1184 es_info_length);
1185 read_pos += es_info_length;
1186 write_pos += es_info_length;
1187 }
1188 }
1189 write_pos += 4; /* CRC */
1190
1191 c->operand[7] = 0x82;
1192 c->operand[8] = (write_pos - 10) >> 8;
1193 c->operand[9] = (write_pos - 10) & 0xff;
1194 c->operand[14] = write_pos - 15;
1195
1196 crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1);
1197 c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff;
1198 c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
1199 c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff;
1200 c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff;
1201 pad_operands(c, write_pos);
1202
1203 fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
1204 ret = avc_write(fdtv);
1205 if (ret < 0)
1206 goto out;
1207
1208 if (r->response != AVC_RESPONSE_ACCEPTED) {
1209 dev_err(fdtv->device,
1210 "CA PMT failed with response 0x%x\n", r->response);
1211 ret = -EACCES;
1212 }
1213out:
1214 mutex_unlock(&fdtv->avc_mutex);
1215
1216 return ret;
1217}
1218
1219int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
1220{
1221 struct avc_command_frame *c = (void *)fdtv->avc_data;
1222 struct avc_response_frame *r = (void *)fdtv->avc_data;
1223 int ret;
1224
1225 mutex_lock(&fdtv->avc_mutex);
1226
1227 c->ctype = AVC_CTYPE_STATUS;
1228 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1229 c->opcode = AVC_OPCODE_VENDOR;
1230
1231 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1232 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1233 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1234 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1235 c->operand[4] = 0; /* slot */
1236 c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
1237 clear_operands(c, 6, LAST_OPERAND);
1238
1239 fdtv->avc_data_length = 12;
1240 ret = avc_write(fdtv);
1241 if (ret < 0)
1242 goto out;
1243
1244 /* FIXME: check response code and validate response data */
1245
1246 *interval = r->operand[get_ca_object_pos(r)];
1247out:
1248 mutex_unlock(&fdtv->avc_mutex);
1249
1250 return ret;
1251}
1252
1253int avc_ca_enter_menu(struct firedtv *fdtv)
1254{
1255 struct avc_command_frame *c = (void *)fdtv->avc_data;
1256 int ret;
1257
1258 mutex_lock(&fdtv->avc_mutex);
1259
1260 c->ctype = AVC_CTYPE_STATUS;
1261 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1262 c->opcode = AVC_OPCODE_VENDOR;
1263
1264 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1265 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1266 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1267 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1268 c->operand[4] = 0; /* slot */
1269 c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
1270 clear_operands(c, 6, 8);
1271
1272 fdtv->avc_data_length = 12;
1273 ret = avc_write(fdtv);
1274
1275 /* FIXME: check response code? */
1276
1277 mutex_unlock(&fdtv->avc_mutex);
1278
1279 return ret;
1280}
1281
1282int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
1283{
1284 struct avc_command_frame *c = (void *)fdtv->avc_data;
1285 struct avc_response_frame *r = (void *)fdtv->avc_data;
1286 int ret;
1287
1288 mutex_lock(&fdtv->avc_mutex);
1289
1290 c->ctype = AVC_CTYPE_STATUS;
1291 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1292 c->opcode = AVC_OPCODE_VENDOR;
1293
1294 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1295 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1296 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1297 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1298 c->operand[4] = 0; /* slot */
1299 c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
1300 clear_operands(c, 6, LAST_OPERAND);
1301
1302 fdtv->avc_data_length = 12;
1303 ret = avc_write(fdtv);
1304 if (ret < 0)
1305 goto out;
1306
1307 /* FIXME: check response code and validate response data */
1308
1309 *len = get_ca_object_length(r);
1310 memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
1311out:
1312 mutex_unlock(&fdtv->avc_mutex);
1313
1314 return ret;
1315}
1316
1317#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
1318
1319static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
1320{
1321 int ret;
1322
1323 ret = fdtv_read(fdtv, addr, data);
1324 if (ret < 0)
1325 dev_err(fdtv->device, "CMP: read I/O error\n");
1326
1327 return ret;
1328}
1329
1330static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
1331{
1332 int ret;
1333
1334 ret = fdtv_lock(fdtv, addr, data);
1335 if (ret < 0)
1336 dev_err(fdtv->device, "CMP: lock I/O error\n");
1337
1338 return ret;
1339}
1340
1341static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
1342{
1343 return (be32_to_cpu(opcr) >> shift) & mask;
1344}
1345
1346static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
1347{
1348 *opcr &= ~cpu_to_be32(mask << shift);
1349 *opcr |= cpu_to_be32((value & mask) << shift);
1350}
1351
1352#define get_opcr_online(v) get_opcr((v), 0x1, 31)
1353#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24)
1354#define get_opcr_channel(v) get_opcr((v), 0x3f, 16)
1355
1356#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
1357#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16)
1358#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14)
1359#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10)
1360
1361int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
1362{
1363 __be32 old_opcr, opcr[2];
1364 u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
1365 int attempts = 0;
1366 int ret;
1367
1368 ret = cmp_read(fdtv, opcr_address, opcr);
1369 if (ret < 0)
1370 return ret;
1371
1372repeat:
1373 if (!get_opcr_online(*opcr)) {
1374 dev_err(fdtv->device, "CMP: output offline\n");
1375 return -EBUSY;
1376 }
1377
1378 old_opcr = *opcr;
1379
1380 if (get_opcr_p2p_connections(*opcr)) {
1381 if (get_opcr_channel(*opcr) != channel) {
1382 dev_err(fdtv->device, "CMP: cannot change channel\n");
1383 return -EBUSY;
1384 }
1385 dev_info(fdtv->device, "CMP: overlaying connection\n");
1386
1387 /* We don't allocate isochronous resources. */
1388 } else {
1389 set_opcr_channel(opcr, channel);
1390 set_opcr_data_rate(opcr, 2); /* S400 */
1391
1392 /* FIXME: this is for the worst case - optimize */
1393 set_opcr_overhead_id(opcr, 0);
1394
1395 /* FIXME: allocate isochronous channel and bandwidth at IRM */
1396 }
1397
1398 set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
1399
1400 opcr[1] = *opcr;
1401 opcr[0] = old_opcr;
1402
1403 ret = cmp_lock(fdtv, opcr_address, opcr);
1404 if (ret < 0)
1405 return ret;
1406
1407 if (old_opcr != *opcr) {
1408 /*
1409 * FIXME: if old_opcr.P2P_Connections > 0,
1410 * deallocate isochronous channel and bandwidth at IRM
1411 */
1412
1413 if (++attempts < 6) /* arbitrary limit */
1414 goto repeat;
1415 return -EBUSY;
1416 }
1417
1418 return 0;
1419}
1420
1421void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
1422{
1423 __be32 old_opcr, opcr[2];
1424 u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
1425 int attempts = 0;
1426
1427 if (cmp_read(fdtv, opcr_address, opcr) < 0)
1428 return;
1429
1430repeat:
1431 if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) ||
1432 get_opcr_channel(*opcr) != channel) {
1433 dev_err(fdtv->device, "CMP: no connection to break\n");
1434 return;
1435 }
1436
1437 old_opcr = *opcr;
1438 set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1);
1439
1440 opcr[1] = *opcr;
1441 opcr[0] = old_opcr;
1442
1443 if (cmp_lock(fdtv, opcr_address, opcr) < 0)
1444 return;
1445
1446 if (old_opcr != *opcr) {
1447 /*
1448 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
1449 * owner, deallocate isochronous channel and bandwidth at IRM
1450 * if (...)
1451 * fdtv->backend->dealloc_resources(fdtv, channel, bw);
1452 */
1453
1454 if (++attempts < 6) /* arbitrary limit */
1455 goto repeat;
1456 }
1457}
diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c
new file mode 100644
index 00000000000..e5ebdbfe8c1
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-ci.c
@@ -0,0 +1,258 @@
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
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 as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 */
12
13#include <linux/device.h>
14#include <linux/dvb/ca.h>
15#include <linux/fs.h>
16#include <linux/module.h>
17
18#include <dvbdev.h>
19
20#include "firedtv.h"
21
22#define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020
23#define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030
24#define EN50221_TAG_CA_PMT 0x9f8032
25#define EN50221_TAG_ENTER_MENU 0x9f8022
26
27static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
28{
29 return stat->ca_initialization_status == 1 &&
30 stat->ca_error_flag == 0 &&
31 stat->ca_dvb_flag == 1 &&
32 stat->ca_module_present_status == 1;
33}
34
35static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
36{
37 int flags = 0;
38
39 if (stat->ca_module_present_status == 1)
40 flags |= CA_CI_MODULE_PRESENT;
41 if (stat->ca_initialization_status == 1 &&
42 stat->ca_error_flag == 0 &&
43 stat->ca_dvb_flag == 1)
44 flags |= CA_CI_MODULE_READY;
45 return flags;
46}
47
48static int fdtv_ca_get_caps(void *arg)
49{
50 struct ca_caps *cap = arg;
51
52 cap->slot_num = 1;
53 cap->slot_type = CA_CI;
54 cap->descr_num = 1;
55 cap->descr_type = CA_ECD;
56 return 0;
57}
58
59static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
60{
61 struct firedtv_tuner_status stat;
62 struct ca_slot_info *slot = arg;
63 int err;
64
65 err = avc_tuner_status(fdtv, &stat);
66 if (err)
67 return err;
68
69 if (slot->num != 0)
70 return -EACCES;
71
72 slot->type = CA_CI;
73 slot->flags = fdtv_get_ca_flags(&stat);
74 return 0;
75}
76
77static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
78{
79 struct ca_msg *reply = arg;
80
81 return avc_ca_app_info(fdtv, reply->msg, &reply->length);
82}
83
84static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
85{
86 struct ca_msg *reply = arg;
87
88 return avc_ca_info(fdtv, reply->msg, &reply->length);
89}
90
91static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
92{
93 struct ca_msg *reply = arg;
94
95 return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
96}
97
98static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
99{
100 struct firedtv_tuner_status stat;
101 int err;
102
103 switch (fdtv->ca_last_command) {
104 case EN50221_TAG_APP_INFO_ENQUIRY:
105 err = fdtv_ca_app_info(fdtv, arg);
106 break;
107 case EN50221_TAG_CA_INFO_ENQUIRY:
108 err = fdtv_ca_info(fdtv, arg);
109 break;
110 default:
111 err = avc_tuner_status(fdtv, &stat);
112 if (err)
113 break;
114 if (stat.ca_mmi == 1)
115 err = fdtv_ca_get_mmi(fdtv, arg);
116 else {
117 dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
118 fdtv->ca_last_command);
119 err = -EACCES;
120 }
121 }
122 fdtv->ca_last_command = 0;
123 return err;
124}
125
126static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
127{
128 struct ca_msg *msg = arg;
129 int data_pos;
130 int data_length;
131 int i;
132
133 data_pos = 4;
134 if (msg->msg[3] & 0x80) {
135 data_length = 0;
136 for (i = 0; i < (msg->msg[3] & 0x7f); i++)
137 data_length = (data_length << 8) + msg->msg[data_pos++];
138 } else {
139 data_length = msg->msg[3];
140 }
141
142 return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
143}
144
145static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
146{
147 struct ca_msg *msg = arg;
148 int err;
149
150 /* Do we need a semaphore for this? */
151 fdtv->ca_last_command =
152 (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
153 switch (fdtv->ca_last_command) {
154 case EN50221_TAG_CA_PMT:
155 err = fdtv_ca_pmt(fdtv, arg);
156 break;
157 case EN50221_TAG_APP_INFO_ENQUIRY:
158 /* handled in ca_get_msg */
159 err = 0;
160 break;
161 case EN50221_TAG_CA_INFO_ENQUIRY:
162 /* handled in ca_get_msg */
163 err = 0;
164 break;
165 case EN50221_TAG_ENTER_MENU:
166 err = avc_ca_enter_menu(fdtv);
167 break;
168 default:
169 dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
170 fdtv->ca_last_command);
171 err = -EACCES;
172 }
173 return err;
174}
175
176static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
177{
178 struct dvb_device *dvbdev = file->private_data;
179 struct firedtv *fdtv = dvbdev->priv;
180 struct firedtv_tuner_status stat;
181 int err;
182
183 switch (cmd) {
184 case CA_RESET:
185 err = avc_ca_reset(fdtv);
186 break;
187 case CA_GET_CAP:
188 err = fdtv_ca_get_caps(arg);
189 break;
190 case CA_GET_SLOT_INFO:
191 err = fdtv_ca_get_slot_info(fdtv, arg);
192 break;
193 case CA_GET_MSG:
194 err = fdtv_ca_get_msg(fdtv, arg);
195 break;
196 case CA_SEND_MSG:
197 err = fdtv_ca_send_msg(fdtv, arg);
198 break;
199 default:
200 dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
201 err = -EOPNOTSUPP;
202 }
203
204 /* FIXME Is this necessary? */
205 avc_tuner_status(fdtv, &stat);
206
207 return err;
208}
209
210static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
211{
212 return POLLIN;
213}
214
215static const struct file_operations fdtv_ca_fops = {
216 .owner = THIS_MODULE,
217 .unlocked_ioctl = dvb_generic_ioctl,
218 .open = dvb_generic_open,
219 .release = dvb_generic_release,
220 .poll = fdtv_ca_io_poll,
221 .llseek = noop_llseek,
222};
223
224static struct dvb_device fdtv_ca = {
225 .users = 1,
226 .readers = 1,
227 .writers = 1,
228 .fops = &fdtv_ca_fops,
229 .kernel_ioctl = fdtv_ca_ioctl,
230};
231
232int fdtv_ca_register(struct firedtv *fdtv)
233{
234 struct firedtv_tuner_status stat;
235 int err;
236
237 if (avc_tuner_status(fdtv, &stat))
238 return -EINVAL;
239
240 if (!fdtv_ca_ready(&stat))
241 return -EFAULT;
242
243 err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
244 &fdtv_ca, fdtv, DVB_DEVICE_CA);
245
246 if (stat.ca_application_info == 0)
247 dev_err(fdtv->device, "CaApplicationInfo is not set\n");
248 if (stat.ca_date_time_request == 1)
249 avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
250
251 return err;
252}
253
254void fdtv_ca_release(struct firedtv *fdtv)
255{
256 if (fdtv->cadev)
257 dvb_unregister_device(fdtv->cadev);
258}
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
new file mode 100644
index 00000000000..fd8bbbfa5c5
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -0,0 +1,245 @@
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
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 as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 */
12
13#include <linux/bitops.h>
14#include <linux/device.h>
15#include <linux/errno.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/types.h>
20
21#include <dmxdev.h>
22#include <dvb_demux.h>
23#include <dvbdev.h>
24#include <dvb_frontend.h>
25
26#include "firedtv.h"
27
28static int alloc_channel(struct firedtv *fdtv)
29{
30 int i;
31
32 for (i = 0; i < 16; i++)
33 if (!__test_and_set_bit(i, &fdtv->channel_active))
34 break;
35 return i;
36}
37
38static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
39{
40 int i, n;
41
42 for (i = 0, n = 0; i < 16; i++)
43 if (test_bit(i, &fdtv->channel_active))
44 pid[n++] = fdtv->channel_pid[i];
45 *pidc = n;
46}
47
48static inline void dealloc_channel(struct firedtv *fdtv, int i)
49{
50 __clear_bit(i, &fdtv->channel_active);
51}
52
53int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
54{
55 struct firedtv *fdtv = dvbdmxfeed->demux->priv;
56 int pidc, c, ret;
57 u16 pids[16];
58
59 switch (dvbdmxfeed->type) {
60 case DMX_TYPE_TS:
61 case DMX_TYPE_SEC:
62 break;
63 default:
64 dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
65 dvbdmxfeed->type);
66 return -EINVAL;
67 }
68
69 if (mutex_lock_interruptible(&fdtv->demux_mutex))
70 return -EINTR;
71
72 if (dvbdmxfeed->type == DMX_TYPE_TS) {
73 switch (dvbdmxfeed->pes_type) {
74 case DMX_TS_PES_VIDEO:
75 case DMX_TS_PES_AUDIO:
76 case DMX_TS_PES_TELETEXT:
77 case DMX_TS_PES_PCR:
78 case DMX_TS_PES_OTHER:
79 c = alloc_channel(fdtv);
80 break;
81 default:
82 dev_err(fdtv->device,
83 "can't start dmx feed: invalid pes type %u\n",
84 dvbdmxfeed->pes_type);
85 ret = -EINVAL;
86 goto out;
87 }
88 } else {
89 c = alloc_channel(fdtv);
90 }
91
92 if (c > 15) {
93 dev_err(fdtv->device, "can't start dmx feed: busy\n");
94 ret = -EBUSY;
95 goto out;
96 }
97
98 dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
99 fdtv->channel_pid[c] = dvbdmxfeed->pid;
100 collect_channels(fdtv, &pidc, pids);
101
102 if (dvbdmxfeed->pid == 8192) {
103 ret = avc_tuner_get_ts(fdtv);
104 if (ret) {
105 dealloc_channel(fdtv, c);
106 dev_err(fdtv->device, "can't get TS\n");
107 goto out;
108 }
109 } else {
110 ret = avc_tuner_set_pids(fdtv, pidc, pids);
111 if (ret) {
112 dealloc_channel(fdtv, c);
113 dev_err(fdtv->device, "can't set PIDs\n");
114 goto out;
115 }
116 }
117out:
118 mutex_unlock(&fdtv->demux_mutex);
119
120 return ret;
121}
122
123int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
124{
125 struct dvb_demux *demux = dvbdmxfeed->demux;
126 struct firedtv *fdtv = demux->priv;
127 int pidc, c, ret;
128 u16 pids[16];
129
130 if (dvbdmxfeed->type == DMX_TYPE_TS &&
131 !((dvbdmxfeed->ts_type & TS_PACKET) &&
132 (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
133
134 if (dvbdmxfeed->ts_type & TS_DECODER) {
135 if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
136 !demux->pesfilter[dvbdmxfeed->pes_type])
137 return -EINVAL;
138
139 demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
140 demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
141 }
142
143 if (!(dvbdmxfeed->ts_type & TS_DECODER &&
144 dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
145 return 0;
146 }
147
148 if (mutex_lock_interruptible(&fdtv->demux_mutex))
149 return -EINTR;
150
151 c = (unsigned long)dvbdmxfeed->priv;
152 dealloc_channel(fdtv, c);
153 collect_channels(fdtv, &pidc, pids);
154
155 ret = avc_tuner_set_pids(fdtv, pidc, pids);
156
157 mutex_unlock(&fdtv->demux_mutex);
158
159 return ret;
160}
161
162DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
163
164int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
165{
166 int err;
167
168 err = dvb_register_adapter(&fdtv->adapter, name,
169 THIS_MODULE, fdtv->device, adapter_nr);
170 if (err < 0)
171 goto fail_log;
172
173 /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
174 fdtv->demux.dmx.capabilities = 0;
175
176 fdtv->demux.priv = fdtv;
177 fdtv->demux.filternum = 16;
178 fdtv->demux.feednum = 16;
179 fdtv->demux.start_feed = fdtv_start_feed;
180 fdtv->demux.stop_feed = fdtv_stop_feed;
181 fdtv->demux.write_to_decoder = NULL;
182
183 err = dvb_dmx_init(&fdtv->demux);
184 if (err)
185 goto fail_unreg_adapter;
186
187 fdtv->dmxdev.filternum = 16;
188 fdtv->dmxdev.demux = &fdtv->demux.dmx;
189 fdtv->dmxdev.capabilities = 0;
190
191 err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
192 if (err)
193 goto fail_dmx_release;
194
195 fdtv->frontend.source = DMX_FRONTEND_0;
196
197 err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
198 if (err)
199 goto fail_dmxdev_release;
200
201 err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
202 &fdtv->frontend);
203 if (err)
204 goto fail_rem_frontend;
205
206 dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
207
208 fdtv_frontend_init(fdtv, name);
209 err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
210 if (err)
211 goto fail_net_release;
212
213 err = fdtv_ca_register(fdtv);
214 if (err)
215 dev_info(fdtv->device,
216 "Conditional Access Module not enabled\n");
217 return 0;
218
219fail_net_release:
220 dvb_net_release(&fdtv->dvbnet);
221 fdtv->demux.dmx.close(&fdtv->demux.dmx);
222fail_rem_frontend:
223 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
224fail_dmxdev_release:
225 dvb_dmxdev_release(&fdtv->dmxdev);
226fail_dmx_release:
227 dvb_dmx_release(&fdtv->demux);
228fail_unreg_adapter:
229 dvb_unregister_adapter(&fdtv->adapter);
230fail_log:
231 dev_err(fdtv->device, "DVB initialization failed\n");
232 return err;
233}
234
235void fdtv_dvb_unregister(struct firedtv *fdtv)
236{
237 fdtv_ca_release(fdtv);
238 dvb_unregister_frontend(&fdtv->fe);
239 dvb_net_release(&fdtv->dvbnet);
240 fdtv->demux.dmx.close(&fdtv->demux.dmx);
241 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
242 dvb_dmxdev_release(&fdtv->dmxdev);
243 dvb_dmx_release(&fdtv->demux);
244 dvb_unregister_adapter(&fdtv->adapter);
245}
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c
new file mode 100644
index 00000000000..8748a61be73
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-fe.c
@@ -0,0 +1,273 @@
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
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 as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 */
12
13#include <linux/device.h>
14#include <linux/errno.h>
15#include <linux/kernel.h>
16#include <linux/string.h>
17#include <linux/types.h>
18
19#include <dvb_frontend.h>
20
21#include "firedtv.h"
22
23static int fdtv_dvb_init(struct dvb_frontend *fe)
24{
25 struct firedtv *fdtv = fe->sec_priv;
26 int err;
27
28 /* FIXME - allocate free channel at IRM */
29 fdtv->isochannel = fdtv->adapter.num;
30
31 err = cmp_establish_pp_connection(fdtv, fdtv->subunit,
32 fdtv->isochannel);
33 if (err) {
34 dev_err(fdtv->device,
35 "could not establish point to point connection\n");
36 return err;
37 }
38
39 return fdtv_start_iso(fdtv);
40}
41
42static int fdtv_sleep(struct dvb_frontend *fe)
43{
44 struct firedtv *fdtv = fe->sec_priv;
45
46 fdtv_stop_iso(fdtv);
47 cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel);
48 fdtv->isochannel = -1;
49 return 0;
50}
51
52#define LNBCONTROL_DONTCARE 0xff
53
54static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe,
55 struct dvb_diseqc_master_cmd *cmd)
56{
57 struct firedtv *fdtv = fe->sec_priv;
58
59 return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE,
60 LNBCONTROL_DONTCARE, 1, cmd);
61}
62
63static int fdtv_diseqc_send_burst(struct dvb_frontend *fe,
64 fe_sec_mini_cmd_t minicmd)
65{
66 return 0;
67}
68
69static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
70{
71 struct firedtv *fdtv = fe->sec_priv;
72
73 fdtv->tone = tone;
74 return 0;
75}
76
77static int fdtv_set_voltage(struct dvb_frontend *fe,
78 fe_sec_voltage_t voltage)
79{
80 struct firedtv *fdtv = fe->sec_priv;
81
82 fdtv->voltage = voltage;
83 return 0;
84}
85
86static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status)
87{
88 struct firedtv *fdtv = fe->sec_priv;
89 struct firedtv_tuner_status stat;
90
91 if (avc_tuner_status(fdtv, &stat))
92 return -EINVAL;
93
94 if (stat.no_rf)
95 *status = 0;
96 else
97 *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC |
98 FE_HAS_CARRIER | FE_HAS_LOCK;
99 return 0;
100}
101
102static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber)
103{
104 struct firedtv *fdtv = fe->sec_priv;
105 struct firedtv_tuner_status stat;
106
107 if (avc_tuner_status(fdtv, &stat))
108 return -EINVAL;
109
110 *ber = stat.ber;
111 return 0;
112}
113
114static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
115{
116 struct firedtv *fdtv = fe->sec_priv;
117 struct firedtv_tuner_status stat;
118
119 if (avc_tuner_status(fdtv, &stat))
120 return -EINVAL;
121
122 *strength = stat.signal_strength << 8;
123 return 0;
124}
125
126static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr)
127{
128 struct firedtv *fdtv = fe->sec_priv;
129 struct firedtv_tuner_status stat;
130
131 if (avc_tuner_status(fdtv, &stat))
132 return -EINVAL;
133
134 /* C/N[dB] = -10 * log10(snr / 65535) */
135 *snr = stat.carrier_noise_ratio * 257;
136 return 0;
137}
138
139static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
140{
141 return -EOPNOTSUPP;
142}
143
144static int fdtv_set_frontend(struct dvb_frontend *fe,
145 struct dvb_frontend_parameters *params)
146{
147 struct firedtv *fdtv = fe->sec_priv;
148
149 return avc_tuner_dsd(fdtv, params);
150}
151
152static int fdtv_get_frontend(struct dvb_frontend *fe,
153 struct dvb_frontend_parameters *params)
154{
155 return -EOPNOTSUPP;
156}
157
158static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
159{
160 return 0;
161}
162
163static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
164{
165 return 0;
166}
167
168void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
169{
170 struct dvb_frontend_ops *ops = &fdtv->fe.ops;
171 struct dvb_frontend_info *fi = &ops->info;
172
173 ops->init = fdtv_dvb_init;
174 ops->sleep = fdtv_sleep;
175
176 ops->set_frontend = fdtv_set_frontend;
177 ops->get_frontend = fdtv_get_frontend;
178
179 ops->get_property = fdtv_get_property;
180 ops->set_property = fdtv_set_property;
181
182 ops->read_status = fdtv_read_status;
183 ops->read_ber = fdtv_read_ber;
184 ops->read_signal_strength = fdtv_read_signal_strength;
185 ops->read_snr = fdtv_read_snr;
186 ops->read_ucblocks = fdtv_read_uncorrected_blocks;
187
188 ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd;
189 ops->diseqc_send_burst = fdtv_diseqc_send_burst;
190 ops->set_tone = fdtv_set_tone;
191 ops->set_voltage = fdtv_set_voltage;
192
193 switch (fdtv->type) {
194 case FIREDTV_DVB_S:
195 fi->type = FE_QPSK;
196
197 fi->frequency_min = 950000;
198 fi->frequency_max = 2150000;
199 fi->frequency_stepsize = 125;
200 fi->symbol_rate_min = 1000000;
201 fi->symbol_rate_max = 40000000;
202
203 fi->caps = FE_CAN_INVERSION_AUTO |
204 FE_CAN_FEC_1_2 |
205 FE_CAN_FEC_2_3 |
206 FE_CAN_FEC_3_4 |
207 FE_CAN_FEC_5_6 |
208 FE_CAN_FEC_7_8 |
209 FE_CAN_FEC_AUTO |
210 FE_CAN_QPSK;
211 break;
212
213 case FIREDTV_DVB_S2:
214 fi->type = FE_QPSK;
215
216 fi->frequency_min = 950000;
217 fi->frequency_max = 2150000;
218 fi->frequency_stepsize = 125;
219 fi->symbol_rate_min = 1000000;
220 fi->symbol_rate_max = 40000000;
221
222 fi->caps = FE_CAN_INVERSION_AUTO |
223 FE_CAN_FEC_1_2 |
224 FE_CAN_FEC_2_3 |
225 FE_CAN_FEC_3_4 |
226 FE_CAN_FEC_5_6 |
227 FE_CAN_FEC_7_8 |
228 FE_CAN_FEC_AUTO |
229 FE_CAN_QPSK |
230 FE_CAN_2G_MODULATION;
231 break;
232
233 case FIREDTV_DVB_C:
234 fi->type = FE_QAM;
235
236 fi->frequency_min = 47000000;
237 fi->frequency_max = 866000000;
238 fi->frequency_stepsize = 62500;
239 fi->symbol_rate_min = 870000;
240 fi->symbol_rate_max = 6900000;
241
242 fi->caps = FE_CAN_INVERSION_AUTO |
243 FE_CAN_QAM_16 |
244 FE_CAN_QAM_32 |
245 FE_CAN_QAM_64 |
246 FE_CAN_QAM_128 |
247 FE_CAN_QAM_256 |
248 FE_CAN_QAM_AUTO;
249 break;
250
251 case FIREDTV_DVB_T:
252 fi->type = FE_OFDM;
253
254 fi->frequency_min = 49000000;
255 fi->frequency_max = 861000000;
256 fi->frequency_stepsize = 62500;
257
258 fi->caps = FE_CAN_INVERSION_AUTO |
259 FE_CAN_FEC_2_3 |
260 FE_CAN_TRANSMISSION_MODE_AUTO |
261 FE_CAN_GUARD_INTERVAL_AUTO |
262 FE_CAN_HIERARCHY_AUTO;
263 break;
264
265 default:
266 dev_err(fdtv->device, "no frontend for model type %d\n",
267 fdtv->type);
268 }
269 strcpy(fi->name, name);
270
271 fdtv->fe.dvb = &fdtv->adapter;
272 fdtv->fe.sec_priv = fdtv;
273}
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
new file mode 100644
index 00000000000..864b6274c72
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -0,0 +1,430 @@
1/*
2 * FireDTV driver -- firewire I/O backend
3 */
4
5#include <linux/device.h>
6#include <linux/errno.h>
7#include <linux/firewire.h>
8#include <linux/firewire-constants.h>
9#include <linux/kernel.h>
10#include <linux/list.h>
11#include <linux/mm.h>
12#include <linux/mod_devicetable.h>
13#include <linux/module.h>
14#include <linux/mutex.h>
15#include <linux/slab.h>
16#include <linux/spinlock.h>
17#include <linux/string.h>
18#include <linux/types.h>
19#include <linux/wait.h>
20#include <linux/workqueue.h>
21
22#include <asm/page.h>
23#include <asm/system.h>
24
25#include <dvb_demux.h>
26
27#include "firedtv.h"
28
29static LIST_HEAD(node_list);
30static DEFINE_SPINLOCK(node_list_lock);
31
32static inline struct fw_device *device_of(struct firedtv *fdtv)
33{
34 return fw_device(fdtv->device->parent);
35}
36
37static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
38 int tcode)
39{
40 struct fw_device *device = device_of(fdtv);
41 int rcode, generation = device->generation;
42
43 smp_rmb(); /* node_id vs. generation */
44
45 rcode = fw_run_transaction(device->card, tcode, device->node_id,
46 generation, device->max_speed, addr, data, len);
47
48 return rcode != RCODE_COMPLETE ? -EIO : 0;
49}
50
51int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data)
52{
53 return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
54}
55
56int fdtv_read(struct firedtv *fdtv, u64 addr, void *data)
57{
58 return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
59}
60
61int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
62{
63 return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
64}
65
66#define ISO_HEADER_SIZE 4
67#define CIP_HEADER_SIZE 8
68#define MPEG2_TS_HEADER_SIZE 4
69#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188)
70
71#define MAX_PACKET_SIZE 1024 /* 776, rounded up to 2^n */
72#define PACKETS_PER_PAGE (PAGE_SIZE / MAX_PACKET_SIZE)
73#define N_PACKETS 64 /* buffer size */
74#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
75#define IRQ_INTERVAL 16
76
77struct fdtv_ir_context {
78 struct fw_iso_context *context;
79 struct fw_iso_buffer buffer;
80 int interrupt_packet;
81 int current_packet;
82 char *pages[N_PAGES];
83};
84
85static int queue_iso(struct fdtv_ir_context *ctx, int index)
86{
87 struct fw_iso_packet p;
88
89 p.payload_length = MAX_PACKET_SIZE;
90 p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1));
91 p.skip = 0;
92 p.header_length = ISO_HEADER_SIZE;
93
94 return fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
95 index * MAX_PACKET_SIZE);
96}
97
98static void handle_iso(struct fw_iso_context *context, u32 cycle,
99 size_t header_length, void *header, void *data)
100{
101 struct firedtv *fdtv = data;
102 struct fdtv_ir_context *ctx = fdtv->ir_context;
103 __be32 *h, *h_end;
104 int length, err, i = ctx->current_packet;
105 char *p, *p_end;
106
107 for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
108 length = be32_to_cpup(h) >> 16;
109 if (unlikely(length > MAX_PACKET_SIZE)) {
110 dev_err(fdtv->device, "length = %d\n", length);
111 length = MAX_PACKET_SIZE;
112 }
113
114 p = ctx->pages[i / PACKETS_PER_PAGE]
115 + (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE;
116 p_end = p + length;
117
118 for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
119 p += MPEG2_TS_SOURCE_PACKET_SIZE)
120 dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
121
122 err = queue_iso(ctx, i);
123 if (unlikely(err))
124 dev_err(fdtv->device, "requeue failed\n");
125
126 i = (i + 1) & (N_PACKETS - 1);
127 }
128 fw_iso_context_queue_flush(ctx->context);
129 ctx->current_packet = i;
130}
131
132int fdtv_start_iso(struct firedtv *fdtv)
133{
134 struct fdtv_ir_context *ctx;
135 struct fw_device *device = device_of(fdtv);
136 int i, err;
137
138 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
139 if (!ctx)
140 return -ENOMEM;
141
142 ctx->context = fw_iso_context_create(device->card,
143 FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
144 device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
145 if (IS_ERR(ctx->context)) {
146 err = PTR_ERR(ctx->context);
147 goto fail_free;
148 }
149
150 err = fw_iso_buffer_init(&ctx->buffer, device->card,
151 N_PAGES, DMA_FROM_DEVICE);
152 if (err)
153 goto fail_context_destroy;
154
155 ctx->interrupt_packet = 0;
156 ctx->current_packet = 0;
157
158 for (i = 0; i < N_PAGES; i++)
159 ctx->pages[i] = page_address(ctx->buffer.pages[i]);
160
161 for (i = 0; i < N_PACKETS; i++) {
162 err = queue_iso(ctx, i);
163 if (err)
164 goto fail;
165 }
166
167 err = fw_iso_context_start(ctx->context, -1, 0,
168 FW_ISO_CONTEXT_MATCH_ALL_TAGS);
169 if (err)
170 goto fail;
171
172 fdtv->ir_context = ctx;
173
174 return 0;
175fail:
176 fw_iso_buffer_destroy(&ctx->buffer, device->card);
177fail_context_destroy:
178 fw_iso_context_destroy(ctx->context);
179fail_free:
180 kfree(ctx);
181
182 return err;
183}
184
185void fdtv_stop_iso(struct firedtv *fdtv)
186{
187 struct fdtv_ir_context *ctx = fdtv->ir_context;
188
189 fw_iso_context_stop(ctx->context);
190 fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
191 fw_iso_context_destroy(ctx->context);
192 kfree(ctx);
193}
194
195static void handle_fcp(struct fw_card *card, struct fw_request *request,
196 int tcode, int destination, int source, int generation,
197 unsigned long long offset, void *payload, size_t length,
198 void *callback_data)
199{
200 struct firedtv *f, *fdtv = NULL;
201 struct fw_device *device;
202 unsigned long flags;
203 int su;
204
205 if (length < 2 || (((u8 *)payload)[0] & 0xf0) != 0)
206 return;
207
208 su = ((u8 *)payload)[1] & 0x7;
209
210 spin_lock_irqsave(&node_list_lock, flags);
211 list_for_each_entry(f, &node_list, list) {
212 device = device_of(f);
213 if (device->generation != generation)
214 continue;
215
216 smp_rmb(); /* node_id vs. generation */
217
218 if (device->card == card &&
219 device->node_id == source &&
220 (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
221 fdtv = f;
222 break;
223 }
224 }
225 spin_unlock_irqrestore(&node_list_lock, flags);
226
227 if (fdtv)
228 avc_recv(fdtv, payload, length);
229}
230
231static struct fw_address_handler fcp_handler = {
232 .length = CSR_FCP_END - CSR_FCP_RESPONSE,
233 .address_callback = handle_fcp,
234};
235
236static const struct fw_address_region fcp_region = {
237 .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
238 .end = CSR_REGISTER_BASE + CSR_FCP_END,
239};
240
241static const char * const model_names[] = {
242 [FIREDTV_UNKNOWN] = "unknown type",
243 [FIREDTV_DVB_S] = "FireDTV S/CI",
244 [FIREDTV_DVB_C] = "FireDTV C/CI",
245 [FIREDTV_DVB_T] = "FireDTV T/CI",
246 [FIREDTV_DVB_S2] = "FireDTV S2 ",
247};
248
249/* Adjust the template string if models with longer names appear. */
250#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
251
252static int node_probe(struct device *dev)
253{
254 struct firedtv *fdtv;
255 char name[MAX_MODEL_NAME_LEN];
256 int name_len, i, err;
257
258 fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
259 if (!fdtv)
260 return -ENOMEM;
261
262 dev_set_drvdata(dev, fdtv);
263 fdtv->device = dev;
264 fdtv->isochannel = -1;
265 fdtv->voltage = 0xff;
266 fdtv->tone = 0xff;
267
268 mutex_init(&fdtv->avc_mutex);
269 init_waitqueue_head(&fdtv->avc_wait);
270 mutex_init(&fdtv->demux_mutex);
271 INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
272
273 name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
274 name, sizeof(name));
275 for (i = ARRAY_SIZE(model_names); --i; )
276 if (strlen(model_names[i]) <= name_len &&
277 strncmp(name, model_names[i], name_len) == 0)
278 break;
279 fdtv->type = i;
280
281 err = fdtv_register_rc(fdtv, dev);
282 if (err)
283 goto fail_free;
284
285 spin_lock_irq(&node_list_lock);
286 list_add_tail(&fdtv->list, &node_list);
287 spin_unlock_irq(&node_list_lock);
288
289 err = avc_identify_subunit(fdtv);
290 if (err)
291 goto fail;
292
293 err = fdtv_dvb_register(fdtv, model_names[fdtv->type]);
294 if (err)
295 goto fail;
296
297 avc_register_remote_control(fdtv);
298
299 return 0;
300fail:
301 spin_lock_irq(&node_list_lock);
302 list_del(&fdtv->list);
303 spin_unlock_irq(&node_list_lock);
304 fdtv_unregister_rc(fdtv);
305fail_free:
306 kfree(fdtv);
307
308 return err;
309}
310
311static int node_remove(struct device *dev)
312{
313 struct firedtv *fdtv = dev_get_drvdata(dev);
314
315 fdtv_dvb_unregister(fdtv);
316
317 spin_lock_irq(&node_list_lock);
318 list_del(&fdtv->list);
319 spin_unlock_irq(&node_list_lock);
320
321 fdtv_unregister_rc(fdtv);
322
323 kfree(fdtv);
324 return 0;
325}
326
327static void node_update(struct fw_unit *unit)
328{
329 struct firedtv *fdtv = dev_get_drvdata(&unit->device);
330
331 if (fdtv->isochannel >= 0)
332 cmp_establish_pp_connection(fdtv, fdtv->subunit,
333 fdtv->isochannel);
334}
335
336#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
337 IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
338
339#define DIGITAL_EVERYWHERE_OUI 0x001287
340#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
341#define AVC_SW_VERSION_ENTRY 0x010001
342
343static const struct ieee1394_device_id fdtv_id_table[] = {
344 {
345 /* FloppyDTV S/CI and FloppyDTV S2 */
346 .match_flags = MATCH_FLAGS,
347 .vendor_id = DIGITAL_EVERYWHERE_OUI,
348 .model_id = 0x000024,
349 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
350 .version = AVC_SW_VERSION_ENTRY,
351 }, {
352 /* FloppyDTV T/CI */
353 .match_flags = MATCH_FLAGS,
354 .vendor_id = DIGITAL_EVERYWHERE_OUI,
355 .model_id = 0x000025,
356 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
357 .version = AVC_SW_VERSION_ENTRY,
358 }, {
359 /* FloppyDTV C/CI */
360 .match_flags = MATCH_FLAGS,
361 .vendor_id = DIGITAL_EVERYWHERE_OUI,
362 .model_id = 0x000026,
363 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
364 .version = AVC_SW_VERSION_ENTRY,
365 }, {
366 /* FireDTV S/CI and FloppyDTV S2 */
367 .match_flags = MATCH_FLAGS,
368 .vendor_id = DIGITAL_EVERYWHERE_OUI,
369 .model_id = 0x000034,
370 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
371 .version = AVC_SW_VERSION_ENTRY,
372 }, {
373 /* FireDTV T/CI */
374 .match_flags = MATCH_FLAGS,
375 .vendor_id = DIGITAL_EVERYWHERE_OUI,
376 .model_id = 0x000035,
377 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
378 .version = AVC_SW_VERSION_ENTRY,
379 }, {
380 /* FireDTV C/CI */
381 .match_flags = MATCH_FLAGS,
382 .vendor_id = DIGITAL_EVERYWHERE_OUI,
383 .model_id = 0x000036,
384 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY,
385 .version = AVC_SW_VERSION_ENTRY,
386 }, {}
387};
388MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
389
390static struct fw_driver fdtv_driver = {
391 .driver = {
392 .owner = THIS_MODULE,
393 .name = "firedtv",
394 .bus = &fw_bus_type,
395 .probe = node_probe,
396 .remove = node_remove,
397 },
398 .update = node_update,
399 .id_table = fdtv_id_table,
400};
401
402static int __init fdtv_init(void)
403{
404 int ret;
405
406 ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
407 if (ret < 0)
408 return ret;
409
410 ret = driver_register(&fdtv_driver.driver);
411 if (ret < 0)
412 fw_core_remove_address_handler(&fcp_handler);
413
414 return ret;
415}
416
417static void __exit fdtv_exit(void)
418{
419 driver_unregister(&fdtv_driver.driver);
420 fw_core_remove_address_handler(&fcp_handler);
421}
422
423module_init(fdtv_init);
424module_exit(fdtv_exit);
425
426MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
427MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
428MODULE_DESCRIPTION("FireDTV DVB Driver");
429MODULE_LICENSE("GPL");
430MODULE_SUPPORTED_DEVICE("FireDTV DVB");
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c
new file mode 100644
index 00000000000..f82d4a93feb
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-rc.c
@@ -0,0 +1,196 @@
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
10 */
11
12#include <linux/bitops.h>
13#include <linux/input.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/string.h>
17#include <linux/types.h>
18#include <linux/workqueue.h>
19
20#include "firedtv.h"
21
22/* fixed table with older keycodes, geared towards MythTV */
23static const u16 oldtable[] = {
24
25 /* code from device: 0x4501...0x451f */
26
27 KEY_ESC,
28 KEY_F9,
29 KEY_1,
30 KEY_2,
31 KEY_3,
32 KEY_4,
33 KEY_5,
34 KEY_6,
35 KEY_7,
36 KEY_8,
37 KEY_9,
38 KEY_I,
39 KEY_0,
40 KEY_ENTER,
41 KEY_RED,
42 KEY_UP,
43 KEY_GREEN,
44 KEY_F10,
45 KEY_SPACE,
46 KEY_F11,
47 KEY_YELLOW,
48 KEY_DOWN,
49 KEY_BLUE,
50 KEY_Z,
51 KEY_P,
52 KEY_PAGEDOWN,
53 KEY_LEFT,
54 KEY_W,
55 KEY_RIGHT,
56 KEY_P,
57 KEY_M,
58
59 /* code from device: 0x4540...0x4542 */
60
61 KEY_R,
62 KEY_V,
63 KEY_C,
64};
65
66/* user-modifiable table for a remote as sold in 2008 */
67static const u16 keytable[] = {
68
69 /* code from device: 0x0300...0x031f */
70
71 [0x00] = KEY_POWER,
72 [0x01] = KEY_SLEEP,
73 [0x02] = KEY_STOP,
74 [0x03] = KEY_OK,
75 [0x04] = KEY_RIGHT,
76 [0x05] = KEY_1,
77 [0x06] = KEY_2,
78 [0x07] = KEY_3,
79 [0x08] = KEY_LEFT,
80 [0x09] = KEY_4,
81 [0x0a] = KEY_5,
82 [0x0b] = KEY_6,
83 [0x0c] = KEY_UP,
84 [0x0d] = KEY_7,
85 [0x0e] = KEY_8,
86 [0x0f] = KEY_9,
87 [0x10] = KEY_DOWN,
88 [0x11] = KEY_TITLE, /* "OSD" - fixme */
89 [0x12] = KEY_0,
90 [0x13] = KEY_F20, /* "16:9" - fixme */
91 [0x14] = KEY_SCREEN, /* "FULL" - fixme */
92 [0x15] = KEY_MUTE,
93 [0x16] = KEY_SUBTITLE,
94 [0x17] = KEY_RECORD,
95 [0x18] = KEY_TEXT,
96 [0x19] = KEY_AUDIO,
97 [0x1a] = KEY_RED,
98 [0x1b] = KEY_PREVIOUS,
99 [0x1c] = KEY_REWIND,
100 [0x1d] = KEY_PLAYPAUSE,
101 [0x1e] = KEY_NEXT,
102 [0x1f] = KEY_VOLUMEUP,
103
104 /* code from device: 0x0340...0x0354 */
105
106 [0x20] = KEY_CHANNELUP,
107 [0x21] = KEY_F21, /* "4:3" - fixme */
108 [0x22] = KEY_TV,
109 [0x23] = KEY_DVD,
110 [0x24] = KEY_VCR,
111 [0x25] = KEY_AUX,
112 [0x26] = KEY_GREEN,
113 [0x27] = KEY_YELLOW,
114 [0x28] = KEY_BLUE,
115 [0x29] = KEY_CHANNEL, /* "CH.LIST" */
116 [0x2a] = KEY_VENDOR, /* "CI" - fixme */
117 [0x2b] = KEY_VOLUMEDOWN,
118 [0x2c] = KEY_CHANNELDOWN,
119 [0x2d] = KEY_LAST,
120 [0x2e] = KEY_INFO,
121 [0x2f] = KEY_FORWARD,
122 [0x30] = KEY_LIST,
123 [0x31] = KEY_FAVORITES,
124 [0x32] = KEY_MENU,
125 [0x33] = KEY_EPG,
126 [0x34] = KEY_EXIT,
127};
128
129int fdtv_register_rc(struct firedtv *fdtv, struct device *dev)
130{
131 struct input_dev *idev;
132 int i, err;
133
134 idev = input_allocate_device();
135 if (!idev)
136 return -ENOMEM;
137
138 fdtv->remote_ctrl_dev = idev;
139 idev->name = "FireDTV remote control";
140 idev->dev.parent = dev;
141 idev->evbit[0] = BIT_MASK(EV_KEY);
142 idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL);
143 if (!idev->keycode) {
144 err = -ENOMEM;
145 goto fail;
146 }
147 idev->keycodesize = sizeof(keytable[0]);
148 idev->keycodemax = ARRAY_SIZE(keytable);
149
150 for (i = 0; i < ARRAY_SIZE(keytable); i++)
151 set_bit(keytable[i], idev->keybit);
152
153 err = input_register_device(idev);
154 if (err)
155 goto fail_free_keymap;
156
157 return 0;
158
159fail_free_keymap:
160 kfree(idev->keycode);
161fail:
162 input_free_device(idev);
163 return err;
164}
165
166void fdtv_unregister_rc(struct firedtv *fdtv)
167{
168 cancel_work_sync(&fdtv->remote_ctrl_work);
169 kfree(fdtv->remote_ctrl_dev->keycode);
170 input_unregister_device(fdtv->remote_ctrl_dev);
171}
172
173void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
174{
175 struct input_dev *idev = fdtv->remote_ctrl_dev;
176 u16 *keycode = idev->keycode;
177
178 if (code >= 0x0300 && code <= 0x031f)
179 code = keycode[code - 0x0300];
180 else if (code >= 0x0340 && code <= 0x0354)
181 code = keycode[code - 0x0320];
182 else if (code >= 0x4501 && code <= 0x451f)
183 code = oldtable[code - 0x4501];
184 else if (code >= 0x4540 && code <= 0x4542)
185 code = oldtable[code - 0x4521];
186 else {
187 printk(KERN_DEBUG "firedtv: invalid key code 0x%04x "
188 "from remote control\n", code);
189 return;
190 }
191
192 input_report_key(idev, code, 1);
193 input_sync(idev);
194 input_report_key(idev, code, 0);
195 input_sync(idev);
196}
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
new file mode 100644
index 00000000000..bd00b04e079
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -0,0 +1,168 @@
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
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 as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 */
12
13#ifndef _FIREDTV_H
14#define _FIREDTV_H
15
16#include <linux/dvb/dmx.h>
17#include <linux/dvb/frontend.h>
18#include <linux/list.h>
19#include <linux/mod_devicetable.h>
20#include <linux/mutex.h>
21#include <linux/spinlock_types.h>
22#include <linux/types.h>
23#include <linux/wait.h>
24#include <linux/workqueue.h>
25
26#include <demux.h>
27#include <dmxdev.h>
28#include <dvb_demux.h>
29#include <dvb_frontend.h>
30#include <dvb_net.h>
31#include <dvbdev.h>
32
33struct firedtv_tuner_status {
34 unsigned active_system:8;
35 unsigned searching:1;
36 unsigned moving:1;
37 unsigned no_rf:1;
38 unsigned input:1;
39 unsigned selected_antenna:7;
40 unsigned ber:32;
41 unsigned signal_strength:8;
42 unsigned raster_frequency:2;
43 unsigned rf_frequency:22;
44 unsigned man_dep_info_length:8;
45 unsigned front_end_error:1;
46 unsigned antenna_error:1;
47 unsigned front_end_power_status:1;
48 unsigned power_supply:1;
49 unsigned carrier_noise_ratio:16;
50 unsigned power_supply_voltage:8;
51 unsigned antenna_voltage:8;
52 unsigned firewire_bus_voltage:8;
53 unsigned ca_mmi:1;
54 unsigned ca_pmt_reply:1;
55 unsigned ca_date_time_request:1;
56 unsigned ca_application_info:1;
57 unsigned ca_module_present_status:1;
58 unsigned ca_dvb_flag:1;
59 unsigned ca_error_flag:1;
60 unsigned ca_initialization_status:1;
61};
62
63enum model_type {
64 FIREDTV_UNKNOWN = 0,
65 FIREDTV_DVB_S = 1,
66 FIREDTV_DVB_C = 2,
67 FIREDTV_DVB_T = 3,
68 FIREDTV_DVB_S2 = 4,
69};
70
71struct device;
72struct input_dev;
73struct fdtv_ir_context;
74
75struct firedtv {
76 struct device *device;
77 struct list_head list;
78
79 struct dvb_adapter adapter;
80 struct dmxdev dmxdev;
81 struct dvb_demux demux;
82 struct dmx_frontend frontend;
83 struct dvb_net dvbnet;
84 struct dvb_frontend fe;
85
86 struct dvb_device *cadev;
87 int ca_last_command;
88 int ca_time_interval;
89
90 struct mutex avc_mutex;
91 wait_queue_head_t avc_wait;
92 bool avc_reply_received;
93 struct work_struct remote_ctrl_work;
94 struct input_dev *remote_ctrl_dev;
95
96 enum model_type type;
97 char subunit;
98 char isochannel;
99 struct fdtv_ir_context *ir_context;
100
101 fe_sec_voltage_t voltage;
102 fe_sec_tone_mode_t tone;
103
104 struct mutex demux_mutex;
105 unsigned long channel_active;
106 u16 channel_pid[16];
107
108 int avc_data_length;
109 u8 avc_data[512];
110};
111
112/* firedtv-avc.c */
113int avc_recv(struct firedtv *fdtv, void *data, size_t length);
114int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
115struct dvb_frontend_parameters;
116int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params);
117int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
118int avc_tuner_get_ts(struct firedtv *fdtv);
119int avc_identify_subunit(struct firedtv *fdtv);
120struct dvb_diseqc_master_cmd;
121int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
122 char conttone, char nrdiseq,
123 struct dvb_diseqc_master_cmd *diseqcmd);
124void avc_remote_ctrl_work(struct work_struct *work);
125int avc_register_remote_control(struct firedtv *fdtv);
126int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
127int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
128int avc_ca_reset(struct firedtv *fdtv);
129int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
130int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
131int avc_ca_enter_menu(struct firedtv *fdtv);
132int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len);
133int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel);
134void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel);
135
136/* firedtv-ci.c */
137int fdtv_ca_register(struct firedtv *fdtv);
138void fdtv_ca_release(struct firedtv *fdtv);
139
140/* firedtv-dvb.c */
141int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed);
142int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
143int fdtv_dvb_register(struct firedtv *fdtv, const char *name);
144void fdtv_dvb_unregister(struct firedtv *fdtv);
145
146/* firedtv-fe.c */
147void fdtv_frontend_init(struct firedtv *fdtv, const char *name);
148
149/* firedtv-fw.c */
150int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data);
151int fdtv_read(struct firedtv *fdtv, u64 addr, void *data);
152int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len);
153int fdtv_start_iso(struct firedtv *fdtv);
154void fdtv_stop_iso(struct firedtv *fdtv);
155
156/* firedtv-rc.c */
157#ifdef CONFIG_DVB_FIREDTV_INPUT
158int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
159void fdtv_unregister_rc(struct firedtv *fdtv);
160void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code);
161#else
162static inline int fdtv_register_rc(struct firedtv *fdtv,
163 struct device *dev) { return 0; }
164static inline void fdtv_unregister_rc(struct firedtv *fdtv) {}
165static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {}
166#endif
167
168#endif /* _FIREDTV_H */