blob: 1f3d1fbf446c2d87b47f7d0f3fe5f4a0f1fbbca8 [file] [log] [blame]
Stefan Richter15490792009-02-23 14:21:10 +01001/*
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
Tommy Jonssond2fd44a2010-09-12 16:03:45 -030027#include <dvb_frontend.h>
28
Stefan Richter15490792009-02-23 14:21:10 +010029#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 {
Stefan Richter15490792009-02-23 14:21:10 +010079 u8 ctype;
80 u8 subunit;
81 u8 opcode;
82 u8 operand[509];
83};
84
85struct avc_response_frame {
Stefan Richter15490792009-02-23 14:21:10 +010086 u8 response;
87 u8 subunit;
88 u8 opcode;
89 u8 operand[509];
90};
91
Stefan Richter1e4348c2009-11-18 16:03:31 -030092#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
Henrik Kurelid15344772009-08-01 08:04:06 -0300107#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
Stefan Richter15490792009-02-23 14:21:10 +0100118
119static int avc_debug;
120module_param_named(debug, avc_debug, int, 0644);
Stefan Richter96e242a2009-08-01 08:05:16 -0300121MODULE_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)");
Stefan Richter15490792009-02-23 14:21:10 +0100134
135static const char *debug_fcp_ctype(unsigned int ctype)
136{
137 static const char *ctypes[] = {
138 [0x0] = "CONTROL", [0x1] = "STATUS",
139 [0x2] = "SPECIFIC INQUIRY", [0x3] = "NOTIFY",
140 [0x4] = "GENERAL INQUIRY", [0x8] = "NOT IMPLEMENTED",
141 [0x9] = "ACCEPTED", [0xa] = "REJECTED",
142 [0xb] = "IN TRANSITION", [0xc] = "IMPLEMENTED/STABLE",
143 [0xd] = "CHANGED", [0xf] = "INTERIM",
144 };
145 const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL;
146
147 return ret ? ret : "?";
148}
149
150static const char *debug_fcp_opcode(unsigned int opcode,
Stefan Richter40cf65d2009-03-05 19:13:43 +0100151 const u8 *data, int length)
Stefan Richter15490792009-02-23 14:21:10 +0100152{
153 switch (opcode) {
Stefan Richter96e242a2009-08-01 08:05:16 -0300154 case AVC_OPCODE_VENDOR:
155 break;
156 case AVC_OPCODE_READ_DESCRIPTOR:
157 return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ?
158 "ReadDescriptor" : NULL;
159 case AVC_OPCODE_DSIT:
160 return avc_debug & AVC_DEBUG_DSIT ?
161 "DirectSelectInfo.Type" : NULL;
162 case AVC_OPCODE_DSD:
163 return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL;
164 default:
165 return "Unknown";
Stefan Richter15490792009-02-23 14:21:10 +0100166 }
167
168 if (length < 7 ||
169 data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
170 data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
171 data[5] != SFE_VENDOR_DE_COMPANYID_2)
Stefan Richter96e242a2009-08-01 08:05:16 -0300172 return "Vendor/Unknown";
Stefan Richter15490792009-02-23 14:21:10 +0100173
174 switch (data[6]) {
Stefan Richter96e242a2009-08-01 08:05:16 -0300175 case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL:
176 return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ?
177 "RegisterRC" : NULL;
178 case SFE_VENDOR_OPCODE_LNB_CONTROL:
179 return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL;
180 case SFE_VENDOR_OPCODE_TUNE_QPSK:
181 return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL;
182 case SFE_VENDOR_OPCODE_TUNE_QPSK2:
183 return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL;
184 case SFE_VENDOR_OPCODE_HOST2CA:
185 return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL;
186 case SFE_VENDOR_OPCODE_CA2HOST:
187 return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL;
Stefan Richter15490792009-02-23 14:21:10 +0100188 }
Stefan Richter96e242a2009-08-01 08:05:16 -0300189 return "Vendor/Unknown";
Henrik Kurelid15344772009-08-01 08:04:06 -0300190}
191
Stefan Richter40cf65d2009-03-05 19:13:43 +0100192static void debug_fcp(const u8 *data, int length)
Stefan Richter15490792009-02-23 14:21:10 +0100193{
Stefan Richter96e242a2009-08-01 08:05:16 -0300194 unsigned int subunit_type, subunit_id, opcode;
195 const char *op, *prefix;
Stefan Richter15490792009-02-23 14:21:10 +0100196
Stefan Richter96e242a2009-08-01 08:05:16 -0300197 prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
Henrik Kurelid15344772009-08-01 08:04:06 -0300198 subunit_type = data[1] >> 3;
Stefan Richter96e242a2009-08-01 08:05:16 -0300199 subunit_id = data[1] & 7;
200 opcode = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
201 op = debug_fcp_opcode(opcode, data, length);
202
203 if (op) {
Stefan Richter14edcd52009-04-01 17:25:00 -0300204 printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
Stefan Richter15490792009-02-23 14:21:10 +0100205 prefix, subunit_type, subunit_id, length,
Stefan Richter96e242a2009-08-01 08:05:16 -0300206 debug_fcp_ctype(data[0]), op);
Henrik Kurelid15344772009-08-01 08:04:06 -0300207 if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
208 print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE,
209 16, 1, data, length, false);
Stefan Richter15490792009-02-23 14:21:10 +0100210 }
Henrik Kurelid15344772009-08-01 08:04:06 -0300211}
Stefan Richter15490792009-02-23 14:21:10 +0100212
Henrik Kurelid15344772009-08-01 08:04:06 -0300213static void debug_pmt(char *msg, int length)
214{
215 printk(KERN_INFO "APP PMT -> l=%d\n", length);
216 print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE,
217 16, 1, msg, length, false);
Stefan Richter15490792009-02-23 14:21:10 +0100218}
219
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300220static int avc_write(struct firedtv *fdtv)
Stefan Richter15490792009-02-23 14:21:10 +0100221{
222 int err, retry;
223
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300224 fdtv->avc_reply_received = false;
Stefan Richter15490792009-02-23 14:21:10 +0100225
226 for (retry = 0; retry < 6; retry++) {
227 if (unlikely(avc_debug))
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300228 debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
Stefan Richter15490792009-02-23 14:21:10 +0100229
230 err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300231 fdtv->avc_data, fdtv->avc_data_length);
Stefan Richter15490792009-02-23 14:21:10 +0100232 if (err) {
Stefan Richter15490792009-02-23 14:21:10 +0100233 dev_err(fdtv->device, "FCP command write failed\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300234
Stefan Richter15490792009-02-23 14:21:10 +0100235 return err;
236 }
237
Stefan Richter15490792009-02-23 14:21:10 +0100238 /*
239 * AV/C specs say that answers should be sent within 150 ms.
240 * Time out after 200 ms.
241 */
242 if (wait_event_timeout(fdtv->avc_wait,
243 fdtv->avc_reply_received,
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300244 msecs_to_jiffies(200)) != 0)
Stefan Richter15490792009-02-23 14:21:10 +0100245 return 0;
Stefan Richter15490792009-02-23 14:21:10 +0100246 }
247 dev_err(fdtv->device, "FCP response timed out\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300248
Stefan Richter15490792009-02-23 14:21:10 +0100249 return -ETIMEDOUT;
250}
251
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300252static bool is_register_rc(struct avc_response_frame *r)
Stefan Richter15490792009-02-23 14:21:10 +0100253{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300254 return r->opcode == AVC_OPCODE_VENDOR &&
255 r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
256 r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
257 r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
258 r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
Stefan Richter15490792009-02-23 14:21:10 +0100259}
260
261int avc_recv(struct firedtv *fdtv, void *data, size_t length)
262{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300263 struct avc_response_frame *r = data;
Stefan Richter15490792009-02-23 14:21:10 +0100264
265 if (unlikely(avc_debug))
266 debug_fcp(data, length);
267
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300268 if (length >= 8 && is_register_rc(r)) {
269 switch (r->response) {
270 case AVC_RESPONSE_CHANGED:
271 fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
Stefan Richter15490792009-02-23 14:21:10 +0100272 schedule_work(&fdtv->remote_ctrl_work);
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300273 break;
274 case AVC_RESPONSE_INTERIM:
275 if (is_register_rc((void *)fdtv->avc_data))
276 goto wake;
277 break;
278 default:
Stefan Richter15490792009-02-23 14:21:10 +0100279 dev_info(fdtv->device,
280 "remote control result = %d\n", r->response);
281 }
282 return 0;
283 }
284
285 if (fdtv->avc_reply_received) {
286 dev_err(fdtv->device, "out-of-order AVC response, ignored\n");
287 return -EIO;
288 }
289
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300290 memcpy(fdtv->avc_data, data, length);
291 fdtv->avc_data_length = length;
292wake:
Stefan Richter15490792009-02-23 14:21:10 +0100293 fdtv->avc_reply_received = true;
294 wake_up(&fdtv->avc_wait);
295
296 return 0;
297}
298
Henrik Kurelid166987c2009-08-01 08:02:38 -0300299static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
300{
301 int i, n, pos = 1;
302
303 for (i = 0, n = 0; i < 16; i++) {
304 if (test_bit(i, &fdtv->channel_active)) {
305 operand[pos++] = 0x13; /* flowfunction relay */
306 operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
307 operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f;
308 operand[pos++] = fdtv->channel_pid[i] & 0xff;
309 operand[pos++] = 0x00; /* tableID */
310 operand[pos++] = 0x00; /* filter_length */
311 n++;
312 }
313 }
314 operand[0] = n;
315
316 return pos;
317}
318
Stefan Richter15490792009-02-23 14:21:10 +0100319/*
320 * tuning command for setting the relative LNB frequency
321 * (not supported by the AVC standard)
322 */
Stefan Richter1e4348c2009-11-18 16:03:31 -0300323static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
324 struct dvb_frontend_parameters *params)
Stefan Richter15490792009-02-23 14:21:10 +0100325{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300326 struct avc_command_frame *c = (void *)fdtv->avc_data;
327
Stefan Richter15490792009-02-23 14:21:10 +0100328 c->opcode = AVC_OPCODE_VENDOR;
329
330 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
331 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
332 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
Beat Michel Liechti32a0f482009-03-26 22:36:52 +0100333 if (fdtv->type == FIREDTV_DVB_S2)
334 c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2;
335 else
336 c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
Stefan Richter15490792009-02-23 14:21:10 +0100337
338 c->operand[4] = (params->frequency >> 24) & 0xff;
339 c->operand[5] = (params->frequency >> 16) & 0xff;
340 c->operand[6] = (params->frequency >> 8) & 0xff;
341 c->operand[7] = params->frequency & 0xff;
342
343 c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff;
344 c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff;
345
346 switch (params->u.qpsk.fec_inner) {
347 case FEC_1_2: c->operand[10] = 0x1; break;
348 case FEC_2_3: c->operand[10] = 0x2; break;
349 case FEC_3_4: c->operand[10] = 0x3; break;
350 case FEC_5_6: c->operand[10] = 0x4; break;
351 case FEC_7_8: c->operand[10] = 0x5; break;
352 case FEC_4_5:
353 case FEC_8_9:
354 case FEC_AUTO:
355 default: c->operand[10] = 0x0;
356 }
357
358 if (fdtv->voltage == 0xff)
359 c->operand[11] = 0xff;
360 else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */
361 c->operand[11] = 0;
362 else
363 c->operand[11] = 1;
364
365 if (fdtv->tone == 0xff)
366 c->operand[12] = 0xff;
367 else if (fdtv->tone == SEC_TONE_ON) /* band */
368 c->operand[12] = 1;
369 else
370 c->operand[12] = 0;
371
372 if (fdtv->type == FIREDTV_DVB_S2) {
Tommy Jonssond2fd44a2010-09-12 16:03:45 -0300373 if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
374 switch (fdtv->fe.dtv_property_cache.modulation) {
375 case QAM_16: c->operand[13] = 0x1; break;
376 case QPSK: c->operand[13] = 0x2; break;
377 case PSK_8: c->operand[13] = 0x3; break;
378 default: c->operand[13] = 0x2; break;
379 }
380 switch (fdtv->fe.dtv_property_cache.rolloff) {
381 case ROLLOFF_AUTO: c->operand[14] = 0x2; break;
382 case ROLLOFF_35: c->operand[14] = 0x2; break;
383 case ROLLOFF_20: c->operand[14] = 0x0; break;
384 case ROLLOFF_25: c->operand[14] = 0x1; break;
385 /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */
386 }
387 switch (fdtv->fe.dtv_property_cache.pilot) {
388 case PILOT_AUTO: c->operand[15] = 0x0; break;
389 case PILOT_OFF: c->operand[15] = 0x0; break;
390 case PILOT_ON: c->operand[15] = 0x1; break;
391 }
392 } else {
393 c->operand[13] = 0x1; /* auto modulation */
394 c->operand[14] = 0xff; /* disable rolloff */
395 c->operand[15] = 0xff; /* disable pilot */
396 }
Stefan Richter1e4348c2009-11-18 16:03:31 -0300397 return 16;
Stefan Richter15490792009-02-23 14:21:10 +0100398 } else {
Stefan Richter1e4348c2009-11-18 16:03:31 -0300399 return 13;
Stefan Richter15490792009-02-23 14:21:10 +0100400 }
401}
402
Stefan Richter1e4348c2009-11-18 16:03:31 -0300403static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
404 struct dvb_frontend_parameters *params)
Stefan Richter15490792009-02-23 14:21:10 +0100405{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300406 struct avc_command_frame *c = (void *)fdtv->avc_data;
407
Stefan Richter15490792009-02-23 14:21:10 +0100408 c->opcode = AVC_OPCODE_DSD;
409
410 c->operand[0] = 0; /* source plug */
411 c->operand[1] = 0xd2; /* subfunction replace */
412 c->operand[2] = 0x20; /* system id = DVB */
413 c->operand[3] = 0x00; /* antenna number */
414 c->operand[4] = 0x11; /* system_specific_multiplex selection_length */
415
416 /* multiplex_valid_flags, high byte */
417 c->operand[5] = 0 << 7 /* reserved */
418 | 0 << 6 /* Polarisation */
419 | 0 << 5 /* Orbital_Pos */
420 | 1 << 4 /* Frequency */
421 | 1 << 3 /* Symbol_Rate */
422 | 0 << 2 /* FEC_outer */
423 | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0)
424 | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0);
425
426 /* multiplex_valid_flags, low byte */
427 c->operand[6] = 0 << 7 /* NetworkID */
428 | 0 << 0 /* reserved */ ;
429
430 c->operand[7] = 0x00;
431 c->operand[8] = 0x00;
432 c->operand[9] = 0x00;
433 c->operand[10] = 0x00;
434
435 c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6);
436 c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff;
437 c->operand[13] = (params->frequency / 4000) & 0xff;
438 c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff;
439 c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff;
440 c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0;
441 c->operand[17] = 0x00;
442
443 switch (params->u.qpsk.fec_inner) {
444 case FEC_1_2: c->operand[18] = 0x1; break;
445 case FEC_2_3: c->operand[18] = 0x2; break;
446 case FEC_3_4: c->operand[18] = 0x3; break;
447 case FEC_5_6: c->operand[18] = 0x4; break;
448 case FEC_7_8: c->operand[18] = 0x5; break;
449 case FEC_8_9: c->operand[18] = 0x6; break;
450 case FEC_4_5: c->operand[18] = 0x8; break;
451 case FEC_AUTO:
452 default: c->operand[18] = 0x0;
453 }
454
455 switch (params->u.qam.modulation) {
456 case QAM_16: c->operand[19] = 0x08; break;
457 case QAM_32: c->operand[19] = 0x10; break;
458 case QAM_64: c->operand[19] = 0x18; break;
459 case QAM_128: c->operand[19] = 0x20; break;
460 case QAM_256: c->operand[19] = 0x28; break;
461 case QAM_AUTO:
462 default: c->operand[19] = 0x00;
463 }
464
465 c->operand[20] = 0x00;
466 c->operand[21] = 0x00;
Stefan Richter15490792009-02-23 14:21:10 +0100467
Stefan Richter1e4348c2009-11-18 16:03:31 -0300468 return 22 + add_pid_filter(fdtv, &c->operand[22]);
Stefan Richter15490792009-02-23 14:21:10 +0100469}
470
Stefan Richter1e4348c2009-11-18 16:03:31 -0300471static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
472 struct dvb_frontend_parameters *params)
Stefan Richter15490792009-02-23 14:21:10 +0100473{
474 struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300475 struct avc_command_frame *c = (void *)fdtv->avc_data;
Stefan Richter15490792009-02-23 14:21:10 +0100476
477 c->opcode = AVC_OPCODE_DSD;
478
479 c->operand[0] = 0; /* source plug */
480 c->operand[1] = 0xd2; /* subfunction replace */
481 c->operand[2] = 0x20; /* system id = DVB */
482 c->operand[3] = 0x00; /* antenna number */
483 c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */
484
485 /* multiplex_valid_flags, high byte */
486 c->operand[5] =
487 0 << 7 /* reserved */
488 | 1 << 6 /* CenterFrequency */
489 | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0)
490 | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0)
491 | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0)
492 | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0)
493 | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0)
494 | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0);
495
496 /* multiplex_valid_flags, low byte */
497 c->operand[6] =
498 0 << 7 /* NetworkID */
499 | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
500 | 0 << 5 /* OtherFrequencyFlag */
501 | 0 << 0 /* reserved */ ;
502
503 c->operand[7] = 0x0;
504 c->operand[8] = (params->frequency / 10) >> 24;
505 c->operand[9] = ((params->frequency / 10) >> 16) & 0xff;
506 c->operand[10] = ((params->frequency / 10) >> 8) & 0xff;
507 c->operand[11] = (params->frequency / 10) & 0xff;
508
509 switch (ofdm->bandwidth) {
510 case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break;
511 case BANDWIDTH_8_MHZ:
512 case BANDWIDTH_6_MHZ: /* not defined by AVC spec */
513 case BANDWIDTH_AUTO:
514 default: c->operand[12] = 0x00;
515 }
516
517 switch (ofdm->constellation) {
518 case QAM_16: c->operand[13] = 1 << 6; break;
519 case QAM_64: c->operand[13] = 2 << 6; break;
520 case QPSK:
521 default: c->operand[13] = 0x00;
522 }
523
524 switch (ofdm->hierarchy_information) {
525 case HIERARCHY_1: c->operand[13] |= 1 << 3; break;
526 case HIERARCHY_2: c->operand[13] |= 2 << 3; break;
527 case HIERARCHY_4: c->operand[13] |= 3 << 3; break;
528 case HIERARCHY_AUTO:
529 case HIERARCHY_NONE:
530 default: break;
531 }
532
533 switch (ofdm->code_rate_HP) {
534 case FEC_2_3: c->operand[13] |= 1; break;
535 case FEC_3_4: c->operand[13] |= 2; break;
536 case FEC_5_6: c->operand[13] |= 3; break;
537 case FEC_7_8: c->operand[13] |= 4; break;
538 case FEC_1_2:
539 default: break;
540 }
541
542 switch (ofdm->code_rate_LP) {
543 case FEC_2_3: c->operand[14] = 1 << 5; break;
544 case FEC_3_4: c->operand[14] = 2 << 5; break;
545 case FEC_5_6: c->operand[14] = 3 << 5; break;
546 case FEC_7_8: c->operand[14] = 4 << 5; break;
547 case FEC_1_2:
548 default: c->operand[14] = 0x00; break;
549 }
550
551 switch (ofdm->guard_interval) {
552 case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break;
553 case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break;
554 case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break;
555 case GUARD_INTERVAL_1_32:
556 case GUARD_INTERVAL_AUTO:
557 default: break;
558 }
559
560 switch (ofdm->transmission_mode) {
561 case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break;
562 case TRANSMISSION_MODE_2K:
563 case TRANSMISSION_MODE_AUTO:
564 default: break;
565 }
566
567 c->operand[15] = 0x00; /* network_ID[0] */
568 c->operand[16] = 0x00; /* network_ID[1] */
Stefan Richter15490792009-02-23 14:21:10 +0100569
Stefan Richter1e4348c2009-11-18 16:03:31 -0300570 return 17 + add_pid_filter(fdtv, &c->operand[17]);
Stefan Richter15490792009-02-23 14:21:10 +0100571}
572
573int avc_tuner_dsd(struct firedtv *fdtv,
574 struct dvb_frontend_parameters *params)
575{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300576 struct avc_command_frame *c = (void *)fdtv->avc_data;
Stefan Richter1e4348c2009-11-18 16:03:31 -0300577 int pos, ret;
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300578
Stefan Richter6385c5b2009-11-18 16:03:03 -0300579 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100580
Stefan Richter15490792009-02-23 14:21:10 +0100581 c->ctype = AVC_CTYPE_CONTROL;
582 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
583
584 switch (fdtv->type) {
585 case FIREDTV_DVB_S:
Stefan Richter1e4348c2009-11-18 16:03:31 -0300586 case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
587 case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
588 case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
Stefan Richter15490792009-02-23 14:21:10 +0100589 default:
590 BUG();
591 }
Stefan Richter1e4348c2009-11-18 16:03:31 -0300592 pad_operands(c, pos);
593
594 fdtv->avc_data_length = ALIGN(3 + pos, 4);
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300595 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +0100596#if 0
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300597 /*
598 * FIXME:
599 * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
600 * Check for AVC_RESPONSE_ACCEPTED here instead?
601 */
Stefan Richter15490792009-02-23 14:21:10 +0100602 if (status)
603 *status = r->operand[2];
604#endif
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300605 mutex_unlock(&fdtv->avc_mutex);
606
607 if (ret == 0)
608 msleep(500);
609
610 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100611}
612
613int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
614{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300615 struct avc_command_frame *c = (void *)fdtv->avc_data;
616 int ret, pos, k;
Stefan Richter15490792009-02-23 14:21:10 +0100617
618 if (pidc > 16 && pidc != 0xff)
619 return -EINVAL;
620
Stefan Richter6385c5b2009-11-18 16:03:03 -0300621 mutex_lock(&fdtv->avc_mutex);
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300622
Stefan Richter15490792009-02-23 14:21:10 +0100623 c->ctype = AVC_CTYPE_CONTROL;
624 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
625 c->opcode = AVC_OPCODE_DSD;
626
627 c->operand[0] = 0; /* source plug */
628 c->operand[1] = 0xd2; /* subfunction replace */
629 c->operand[2] = 0x20; /* system id = DVB */
630 c->operand[3] = 0x00; /* antenna number */
631 c->operand[4] = 0x00; /* system_specific_multiplex selection_length */
632 c->operand[5] = pidc; /* Nr_of_dsd_sel_specs */
633
634 pos = 6;
635 if (pidc != 0xff)
636 for (k = 0; k < pidc; k++) {
637 c->operand[pos++] = 0x13; /* flowfunction relay */
638 c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
639 c->operand[pos++] = (pid[k] >> 8) & 0x1f;
640 c->operand[pos++] = pid[k] & 0xff;
641 c->operand[pos++] = 0x00; /* tableID */
642 c->operand[pos++] = 0x00; /* filter_length */
643 }
Stefan Richter1e4348c2009-11-18 16:03:31 -0300644 pad_operands(c, pos);
Stefan Richter15490792009-02-23 14:21:10 +0100645
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300646 fdtv->avc_data_length = ALIGN(3 + pos, 4);
647 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +0100648
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300649 /* FIXME: check response code? */
Stefan Richter15490792009-02-23 14:21:10 +0100650
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300651 mutex_unlock(&fdtv->avc_mutex);
652
653 if (ret == 0)
654 msleep(50);
655
656 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100657}
658
659int avc_tuner_get_ts(struct firedtv *fdtv)
660{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300661 struct avc_command_frame *c = (void *)fdtv->avc_data;
662 int ret, sl;
663
Stefan Richter6385c5b2009-11-18 16:03:03 -0300664 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100665
Stefan Richter15490792009-02-23 14:21:10 +0100666 c->ctype = AVC_CTYPE_CONTROL;
667 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
668 c->opcode = AVC_OPCODE_DSIT;
669
670 sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11;
671
672 c->operand[0] = 0; /* source plug */
673 c->operand[1] = 0xd2; /* subfunction replace */
674 c->operand[2] = 0xff; /* status */
675 c->operand[3] = 0x20; /* system id = DVB */
676 c->operand[4] = 0x00; /* antenna number */
677 c->operand[5] = 0x0; /* system_specific_search_flags */
678 c->operand[6] = sl; /* system_specific_multiplex selection_length */
Stefan Richter1e4348c2009-11-18 16:03:31 -0300679 /*
680 * operand[7]: valid_flags[0]
681 * operand[8]: valid_flags[1]
682 * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
683 */
684 clear_operands(c, 7, 24);
Stefan Richter15490792009-02-23 14:21:10 +0100685
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300686 fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
687 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +0100688
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300689 /* FIXME: check response code? */
Stefan Richter15490792009-02-23 14:21:10 +0100690
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300691 mutex_unlock(&fdtv->avc_mutex);
692
693 if (ret == 0)
694 msleep(250);
695
696 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100697}
698
699int avc_identify_subunit(struct firedtv *fdtv)
700{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300701 struct avc_command_frame *c = (void *)fdtv->avc_data;
702 struct avc_response_frame *r = (void *)fdtv->avc_data;
703 int ret;
704
Stefan Richter6385c5b2009-11-18 16:03:03 -0300705 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100706
Stefan Richter15490792009-02-23 14:21:10 +0100707 c->ctype = AVC_CTYPE_CONTROL;
708 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
709 c->opcode = AVC_OPCODE_READ_DESCRIPTOR;
710
711 c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER;
712 c->operand[1] = 0xff;
713 c->operand[2] = 0x00;
714 c->operand[3] = 0x00; /* length highbyte */
715 c->operand[4] = 0x08; /* length lowbyte */
716 c->operand[5] = 0x00; /* offset highbyte */
717 c->operand[6] = 0x0d; /* offset lowbyte */
Stefan Richter1e4348c2009-11-18 16:03:31 -0300718 clear_operands(c, 7, 8); /* padding */
Stefan Richter15490792009-02-23 14:21:10 +0100719
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300720 fdtv->avc_data_length = 12;
721 ret = avc_write(fdtv);
722 if (ret < 0)
723 goto out;
Stefan Richter15490792009-02-23 14:21:10 +0100724
725 if ((r->response != AVC_RESPONSE_STABLE &&
726 r->response != AVC_RESPONSE_ACCEPTED) ||
727 (r->operand[3] << 8) + r->operand[4] != 8) {
728 dev_err(fdtv->device, "cannot read subunit identifier\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300729 ret = -EINVAL;
Stefan Richter15490792009-02-23 14:21:10 +0100730 }
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300731out:
732 mutex_unlock(&fdtv->avc_mutex);
733
734 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100735}
736
737#define SIZEOF_ANTENNA_INPUT_INFO 22
738
739int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
740{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300741 struct avc_command_frame *c = (void *)fdtv->avc_data;
742 struct avc_response_frame *r = (void *)fdtv->avc_data;
743 int length, ret;
744
Stefan Richter6385c5b2009-11-18 16:03:03 -0300745 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100746
Stefan Richter15490792009-02-23 14:21:10 +0100747 c->ctype = AVC_CTYPE_CONTROL;
748 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
749 c->opcode = AVC_OPCODE_READ_DESCRIPTOR;
750
751 c->operand[0] = DESCRIPTOR_TUNER_STATUS;
752 c->operand[1] = 0xff; /* read_result_status */
Stefan Richter1e4348c2009-11-18 16:03:31 -0300753 /*
754 * operand[2]: reserved
755 * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
756 * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
757 */
758 clear_operands(c, 2, 31);
Stefan Richter15490792009-02-23 14:21:10 +0100759
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300760 fdtv->avc_data_length = 12;
761 ret = avc_write(fdtv);
762 if (ret < 0)
763 goto out;
Stefan Richter15490792009-02-23 14:21:10 +0100764
765 if (r->response != AVC_RESPONSE_STABLE &&
766 r->response != AVC_RESPONSE_ACCEPTED) {
767 dev_err(fdtv->device, "cannot read tuner status\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300768 ret = -EINVAL;
769 goto out;
Stefan Richter15490792009-02-23 14:21:10 +0100770 }
771
772 length = r->operand[9];
773 if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
774 dev_err(fdtv->device, "got invalid tuner status\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300775 ret = -EINVAL;
776 goto out;
Stefan Richter15490792009-02-23 14:21:10 +0100777 }
778
779 stat->active_system = r->operand[10];
780 stat->searching = r->operand[11] >> 7 & 1;
781 stat->moving = r->operand[11] >> 6 & 1;
782 stat->no_rf = r->operand[11] >> 5 & 1;
783 stat->input = r->operand[12] >> 7 & 1;
784 stat->selected_antenna = r->operand[12] & 0x7f;
785 stat->ber = r->operand[13] << 24 |
786 r->operand[14] << 16 |
787 r->operand[15] << 8 |
788 r->operand[16];
789 stat->signal_strength = r->operand[17];
790 stat->raster_frequency = r->operand[18] >> 6 & 2;
791 stat->rf_frequency = (r->operand[18] & 0x3f) << 16 |
792 r->operand[19] << 8 |
793 r->operand[20];
794 stat->man_dep_info_length = r->operand[21];
795 stat->front_end_error = r->operand[22] >> 4 & 1;
796 stat->antenna_error = r->operand[22] >> 3 & 1;
797 stat->front_end_power_status = r->operand[22] >> 1 & 1;
798 stat->power_supply = r->operand[22] & 1;
799 stat->carrier_noise_ratio = r->operand[23] << 8 |
800 r->operand[24];
801 stat->power_supply_voltage = r->operand[27];
802 stat->antenna_voltage = r->operand[28];
803 stat->firewire_bus_voltage = r->operand[29];
804 stat->ca_mmi = r->operand[30] & 1;
805 stat->ca_pmt_reply = r->operand[31] >> 7 & 1;
806 stat->ca_date_time_request = r->operand[31] >> 6 & 1;
807 stat->ca_application_info = r->operand[31] >> 5 & 1;
808 stat->ca_module_present_status = r->operand[31] >> 4 & 1;
809 stat->ca_dvb_flag = r->operand[31] >> 3 & 1;
810 stat->ca_error_flag = r->operand[31] >> 2 & 1;
811 stat->ca_initialization_status = r->operand[31] >> 1 & 1;
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300812out:
813 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100814
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300815 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100816}
817
818int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
819 char conttone, char nrdiseq,
820 struct dvb_diseqc_master_cmd *diseqcmd)
821{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300822 struct avc_command_frame *c = (void *)fdtv->avc_data;
823 struct avc_response_frame *r = (void *)fdtv->avc_data;
Stefan Richter1e4348c2009-11-18 16:03:31 -0300824 int pos, j, k, ret;
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300825
Stefan Richter6385c5b2009-11-18 16:03:03 -0300826 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100827
Stefan Richter15490792009-02-23 14:21:10 +0100828 c->ctype = AVC_CTYPE_CONTROL;
829 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
830 c->opcode = AVC_OPCODE_VENDOR;
831
832 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
833 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
834 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
835 c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
Stefan Richter15490792009-02-23 14:21:10 +0100836 c->operand[4] = voltage;
837 c->operand[5] = nrdiseq;
838
Stefan Richter1e4348c2009-11-18 16:03:31 -0300839 pos = 6;
Stefan Richter15490792009-02-23 14:21:10 +0100840 for (j = 0; j < nrdiseq; j++) {
Stefan Richter1e4348c2009-11-18 16:03:31 -0300841 c->operand[pos++] = diseqcmd[j].msg_len;
Stefan Richter15490792009-02-23 14:21:10 +0100842
843 for (k = 0; k < diseqcmd[j].msg_len; k++)
Stefan Richter1e4348c2009-11-18 16:03:31 -0300844 c->operand[pos++] = diseqcmd[j].msg[k];
Stefan Richter15490792009-02-23 14:21:10 +0100845 }
Stefan Richter1e4348c2009-11-18 16:03:31 -0300846 c->operand[pos++] = burst;
847 c->operand[pos++] = conttone;
848 pad_operands(c, pos);
Stefan Richter15490792009-02-23 14:21:10 +0100849
Stefan Richter1e4348c2009-11-18 16:03:31 -0300850 fdtv->avc_data_length = ALIGN(3 + pos, 4);
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300851 ret = avc_write(fdtv);
852 if (ret < 0)
853 goto out;
Stefan Richter15490792009-02-23 14:21:10 +0100854
855 if (r->response != AVC_RESPONSE_ACCEPTED) {
856 dev_err(fdtv->device, "LNB control failed\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300857 ret = -EINVAL;
Stefan Richter15490792009-02-23 14:21:10 +0100858 }
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300859out:
860 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100861
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300862 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100863}
864
865int avc_register_remote_control(struct firedtv *fdtv)
866{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300867 struct avc_command_frame *c = (void *)fdtv->avc_data;
868 int ret;
869
Stefan Richter6385c5b2009-11-18 16:03:03 -0300870 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100871
Stefan Richter15490792009-02-23 14:21:10 +0100872 c->ctype = AVC_CTYPE_NOTIFY;
873 c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
874 c->opcode = AVC_OPCODE_VENDOR;
875
876 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
877 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
878 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
879 c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
Stefan Richter1e4348c2009-11-18 16:03:31 -0300880 c->operand[4] = 0; /* padding */
Stefan Richter15490792009-02-23 14:21:10 +0100881
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300882 fdtv->avc_data_length = 8;
883 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +0100884
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300885 /* FIXME: check response code? */
886
887 mutex_unlock(&fdtv->avc_mutex);
888
889 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100890}
891
892void avc_remote_ctrl_work(struct work_struct *work)
893{
894 struct firedtv *fdtv =
895 container_of(work, struct firedtv, remote_ctrl_work);
896
897 /* Should it be rescheduled in failure cases? */
898 avc_register_remote_control(fdtv);
899}
900
901#if 0 /* FIXME: unused */
902int avc_tuner_host2ca(struct firedtv *fdtv)
903{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300904 struct avc_command_frame *c = (void *)fdtv->avc_data;
905 int ret;
906
Stefan Richter6385c5b2009-11-18 16:03:03 -0300907 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100908
Stefan Richter15490792009-02-23 14:21:10 +0100909 c->ctype = AVC_CTYPE_CONTROL;
910 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
911 c->opcode = AVC_OPCODE_VENDOR;
912
913 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
914 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
915 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
916 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
917 c->operand[4] = 0; /* slot */
918 c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
Stefan Richter1e4348c2009-11-18 16:03:31 -0300919 clear_operands(c, 6, 8);
Stefan Richter15490792009-02-23 14:21:10 +0100920
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300921 fdtv->avc_data_length = 12;
922 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +0100923
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300924 /* FIXME: check response code? */
Stefan Richter15490792009-02-23 14:21:10 +0100925
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300926 mutex_unlock(&fdtv->avc_mutex);
927
928 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100929}
930#endif
931
932static int get_ca_object_pos(struct avc_response_frame *r)
933{
934 int length = 1;
935
936 /* Check length of length field */
937 if (r->operand[7] & 0x80)
938 length = (r->operand[7] & 0x7f) + 1;
939 return length + 7;
940}
941
942static int get_ca_object_length(struct avc_response_frame *r)
943{
944#if 0 /* FIXME: unused */
945 int size = 0;
946 int i;
947
948 if (r->operand[7] & 0x80)
949 for (i = 0; i < (r->operand[7] & 0x7f); i++) {
950 size <<= 8;
951 size += r->operand[8 + i];
952 }
953#endif
954 return r->operand[7];
955}
956
957int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
958{
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300959 struct avc_command_frame *c = (void *)fdtv->avc_data;
960 struct avc_response_frame *r = (void *)fdtv->avc_data;
961 int pos, ret;
962
Stefan Richter6385c5b2009-11-18 16:03:03 -0300963 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100964
Stefan Richter15490792009-02-23 14:21:10 +0100965 c->ctype = AVC_CTYPE_STATUS;
966 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
967 c->opcode = AVC_OPCODE_VENDOR;
968
969 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
970 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
971 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
972 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
973 c->operand[4] = 0; /* slot */
974 c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
Stefan Richter1e4348c2009-11-18 16:03:31 -0300975 clear_operands(c, 6, LAST_OPERAND);
Stefan Richter15490792009-02-23 14:21:10 +0100976
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300977 fdtv->avc_data_length = 12;
978 ret = avc_write(fdtv);
979 if (ret < 0)
980 goto out;
Stefan Richter15490792009-02-23 14:21:10 +0100981
982 /* FIXME: check response code and validate response data */
983
984 pos = get_ca_object_pos(r);
985 app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff;
986 app_info[1] = (EN50221_TAG_APP_INFO >> 8) & 0xff;
987 app_info[2] = (EN50221_TAG_APP_INFO >> 0) & 0xff;
988 app_info[3] = 6 + r->operand[pos + 4];
989 app_info[4] = 0x01;
990 memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
991 *len = app_info[3] + 4;
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300992out:
993 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +0100994
Stefan Richter3fb80ef2009-11-18 16:02:01 -0300995 return ret;
Stefan Richter15490792009-02-23 14:21:10 +0100996}
997
998int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
999{
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001000 struct avc_command_frame *c = (void *)fdtv->avc_data;
1001 struct avc_response_frame *r = (void *)fdtv->avc_data;
1002 int pos, ret;
1003
Stefan Richter6385c5b2009-11-18 16:03:03 -03001004 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001005
Stefan Richter15490792009-02-23 14:21:10 +01001006 c->ctype = AVC_CTYPE_STATUS;
1007 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1008 c->opcode = AVC_OPCODE_VENDOR;
1009
1010 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1011 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1012 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1013 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1014 c->operand[4] = 0; /* slot */
1015 c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
Stefan Richter1e4348c2009-11-18 16:03:31 -03001016 clear_operands(c, 6, LAST_OPERAND);
Stefan Richter15490792009-02-23 14:21:10 +01001017
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001018 fdtv->avc_data_length = 12;
1019 ret = avc_write(fdtv);
1020 if (ret < 0)
1021 goto out;
Stefan Richter15490792009-02-23 14:21:10 +01001022
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001023 /* FIXME: check response code and validate response data */
Stefan Richter15490792009-02-23 14:21:10 +01001024
1025 pos = get_ca_object_pos(r);
1026 app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
1027 app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff;
1028 app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff;
1029 app_info[3] = 2;
1030 app_info[4] = r->operand[pos + 0];
1031 app_info[5] = r->operand[pos + 1];
1032 *len = app_info[3] + 4;
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001033out:
1034 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001035
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001036 return ret;
Stefan Richter15490792009-02-23 14:21:10 +01001037}
1038
1039int avc_ca_reset(struct firedtv *fdtv)
1040{
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001041 struct avc_command_frame *c = (void *)fdtv->avc_data;
1042 int ret;
1043
Stefan Richter6385c5b2009-11-18 16:03:03 -03001044 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001045
Stefan Richter15490792009-02-23 14:21:10 +01001046 c->ctype = AVC_CTYPE_CONTROL;
1047 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1048 c->opcode = AVC_OPCODE_VENDOR;
1049
1050 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1051 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1052 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1053 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1054 c->operand[4] = 0; /* slot */
1055 c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */
1056 c->operand[6] = 0; /* more/last */
1057 c->operand[7] = 1; /* length */
1058 c->operand[8] = 0; /* force hardware reset */
1059
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001060 fdtv->avc_data_length = 12;
1061 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +01001062
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001063 /* FIXME: check response code? */
Stefan Richter15490792009-02-23 14:21:10 +01001064
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001065 mutex_unlock(&fdtv->avc_mutex);
1066
1067 return ret;
Stefan Richter15490792009-02-23 14:21:10 +01001068}
1069
1070int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
1071{
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001072 struct avc_command_frame *c = (void *)fdtv->avc_data;
1073 struct avc_response_frame *r = (void *)fdtv->avc_data;
Stefan Richter15490792009-02-23 14:21:10 +01001074 int list_management;
1075 int program_info_length;
1076 int pmt_cmd_id;
1077 int read_pos;
1078 int write_pos;
1079 int es_info_length;
1080 int crc32_csum;
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001081 int ret;
Stefan Richter15490792009-02-23 14:21:10 +01001082
Henrik Kurelid15344772009-08-01 08:04:06 -03001083 if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
1084 debug_pmt(msg, length);
1085
Stefan Richter6385c5b2009-11-18 16:03:03 -03001086 mutex_lock(&fdtv->avc_mutex);
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001087
Stefan Richter15490792009-02-23 14:21:10 +01001088 c->ctype = AVC_CTYPE_CONTROL;
1089 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1090 c->opcode = AVC_OPCODE_VENDOR;
1091
1092 if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) {
1093 dev_info(fdtv->device, "forcing list_management to ONLY\n");
1094 msg[0] = EN50221_LIST_MANAGEMENT_ONLY;
1095 }
1096 /* We take the cmd_id from the programme level only! */
1097 list_management = msg[0];
1098 program_info_length = ((msg[4] & 0x0f) << 8) + msg[5];
1099 if (program_info_length > 0)
1100 program_info_length--; /* Remove pmt_cmd_id */
1101 pmt_cmd_id = msg[6];
1102
1103 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1104 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1105 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1106 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1107 c->operand[4] = 0; /* slot */
1108 c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */
1109 c->operand[6] = 0; /* more/last */
Henrik Kurelidc94115f2009-10-03 05:37:58 -03001110 /* Use three bytes for length field in case length > 127 */
1111 c->operand[10] = list_management;
1112 c->operand[11] = 0x01; /* pmt_cmd=OK_descramble */
Stefan Richter15490792009-02-23 14:21:10 +01001113
1114 /* TS program map table */
1115
Henrik Kurelidc94115f2009-10-03 05:37:58 -03001116 c->operand[12] = 0x02; /* Table id=2 */
1117 c->operand[13] = 0x80; /* Section syntax + length */
Stefan Richter1e4348c2009-11-18 16:03:31 -03001118
Henrik Kurelidc94115f2009-10-03 05:37:58 -03001119 c->operand[15] = msg[1]; /* Program number */
1120 c->operand[16] = msg[2];
Henrik Kurelidad5e9b92009-07-21 13:45:50 -03001121 c->operand[17] = msg[3]; /* Version number and current/next */
Henrik Kurelidc94115f2009-10-03 05:37:58 -03001122 c->operand[18] = 0x00; /* Section number=0 */
1123 c->operand[19] = 0x00; /* Last section number=0 */
1124 c->operand[20] = 0x1f; /* PCR_PID=1FFF */
1125 c->operand[21] = 0xff;
1126 c->operand[22] = (program_info_length >> 8); /* Program info length */
1127 c->operand[23] = (program_info_length & 0xff);
Stefan Richter15490792009-02-23 14:21:10 +01001128
1129 /* CA descriptors at programme level */
1130 read_pos = 6;
Henrik Kurelidc94115f2009-10-03 05:37:58 -03001131 write_pos = 24;
Stefan Richter15490792009-02-23 14:21:10 +01001132 if (program_info_length > 0) {
1133 pmt_cmd_id = msg[read_pos++];
1134 if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
1135 dev_err(fdtv->device,
1136 "invalid pmt_cmd_id %d\n", pmt_cmd_id);
1137
1138 memcpy(&c->operand[write_pos], &msg[read_pos],
1139 program_info_length);
1140 read_pos += program_info_length;
1141 write_pos += program_info_length;
1142 }
1143 while (read_pos < length) {
1144 c->operand[write_pos++] = msg[read_pos++];
1145 c->operand[write_pos++] = msg[read_pos++];
1146 c->operand[write_pos++] = msg[read_pos++];
1147 es_info_length =
1148 ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1];
1149 read_pos += 2;
1150 if (es_info_length > 0)
1151 es_info_length--; /* Remove pmt_cmd_id */
1152 c->operand[write_pos++] = es_info_length >> 8;
1153 c->operand[write_pos++] = es_info_length & 0xff;
1154 if (es_info_length > 0) {
1155 pmt_cmd_id = msg[read_pos++];
1156 if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
1157 dev_err(fdtv->device, "invalid pmt_cmd_id %d "
1158 "at stream level\n", pmt_cmd_id);
1159
1160 memcpy(&c->operand[write_pos], &msg[read_pos],
1161 es_info_length);
1162 read_pos += es_info_length;
1163 write_pos += es_info_length;
1164 }
1165 }
Stefan Richter1e4348c2009-11-18 16:03:31 -03001166 write_pos += 4; /* CRC */
Stefan Richter15490792009-02-23 14:21:10 +01001167
Henrik Kurelidc94115f2009-10-03 05:37:58 -03001168 c->operand[7] = 0x82;
1169 c->operand[8] = (write_pos - 10) >> 8;
1170 c->operand[9] = (write_pos - 10) & 0xff;
1171 c->operand[14] = write_pos - 15;
Stefan Richter15490792009-02-23 14:21:10 +01001172
1173 crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1);
1174 c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff;
1175 c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
1176 c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff;
1177 c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff;
Stefan Richter1e4348c2009-11-18 16:03:31 -03001178 pad_operands(c, write_pos);
Stefan Richter15490792009-02-23 14:21:10 +01001179
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001180 fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
1181 ret = avc_write(fdtv);
1182 if (ret < 0)
1183 goto out;
Stefan Richter15490792009-02-23 14:21:10 +01001184
1185 if (r->response != AVC_RESPONSE_ACCEPTED) {
1186 dev_err(fdtv->device,
1187 "CA PMT failed with response 0x%x\n", r->response);
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001188 ret = -EFAULT;
Stefan Richter15490792009-02-23 14:21:10 +01001189 }
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001190out:
1191 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001192
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001193 return ret;
Stefan Richter15490792009-02-23 14:21:10 +01001194}
1195
1196int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
1197{
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001198 struct avc_command_frame *c = (void *)fdtv->avc_data;
1199 struct avc_response_frame *r = (void *)fdtv->avc_data;
1200 int ret;
1201
Stefan Richter6385c5b2009-11-18 16:03:03 -03001202 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001203
Stefan Richter15490792009-02-23 14:21:10 +01001204 c->ctype = AVC_CTYPE_STATUS;
1205 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1206 c->opcode = AVC_OPCODE_VENDOR;
1207
1208 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1209 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1210 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1211 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1212 c->operand[4] = 0; /* slot */
1213 c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
Stefan Richter1e4348c2009-11-18 16:03:31 -03001214 clear_operands(c, 6, LAST_OPERAND);
Stefan Richter15490792009-02-23 14:21:10 +01001215
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001216 fdtv->avc_data_length = 12;
1217 ret = avc_write(fdtv);
1218 if (ret < 0)
1219 goto out;
Stefan Richter15490792009-02-23 14:21:10 +01001220
1221 /* FIXME: check response code and validate response data */
1222
1223 *interval = r->operand[get_ca_object_pos(r)];
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001224out:
1225 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001226
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001227 return ret;
Stefan Richter15490792009-02-23 14:21:10 +01001228}
1229
1230int avc_ca_enter_menu(struct firedtv *fdtv)
1231{
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001232 struct avc_command_frame *c = (void *)fdtv->avc_data;
1233 int ret;
1234
Stefan Richter6385c5b2009-11-18 16:03:03 -03001235 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001236
Stefan Richter15490792009-02-23 14:21:10 +01001237 c->ctype = AVC_CTYPE_STATUS;
1238 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1239 c->opcode = AVC_OPCODE_VENDOR;
1240
1241 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1242 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1243 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1244 c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1245 c->operand[4] = 0; /* slot */
1246 c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
Stefan Richter1e4348c2009-11-18 16:03:31 -03001247 clear_operands(c, 6, 8);
Stefan Richter15490792009-02-23 14:21:10 +01001248
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001249 fdtv->avc_data_length = 12;
1250 ret = avc_write(fdtv);
Stefan Richter15490792009-02-23 14:21:10 +01001251
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001252 /* FIXME: check response code? */
Stefan Richter15490792009-02-23 14:21:10 +01001253
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001254 mutex_unlock(&fdtv->avc_mutex);
1255
1256 return ret;
Stefan Richter15490792009-02-23 14:21:10 +01001257}
1258
1259int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
1260{
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001261 struct avc_command_frame *c = (void *)fdtv->avc_data;
1262 struct avc_response_frame *r = (void *)fdtv->avc_data;
1263 int ret;
1264
Stefan Richter6385c5b2009-11-18 16:03:03 -03001265 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001266
Stefan Richter15490792009-02-23 14:21:10 +01001267 c->ctype = AVC_CTYPE_STATUS;
1268 c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1269 c->opcode = AVC_OPCODE_VENDOR;
1270
1271 c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1272 c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1273 c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1274 c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1275 c->operand[4] = 0; /* slot */
1276 c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
Stefan Richter1e4348c2009-11-18 16:03:31 -03001277 clear_operands(c, 6, LAST_OPERAND);
Stefan Richter15490792009-02-23 14:21:10 +01001278
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001279 fdtv->avc_data_length = 12;
1280 ret = avc_write(fdtv);
1281 if (ret < 0)
1282 goto out;
Stefan Richter15490792009-02-23 14:21:10 +01001283
1284 /* FIXME: check response code and validate response data */
1285
1286 *len = get_ca_object_length(r);
1287 memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001288out:
1289 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001290
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001291 return ret;
Stefan Richter15490792009-02-23 14:21:10 +01001292}
1293
1294#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
1295
Stefan Richter53756592009-11-18 16:01:34 -03001296static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
Stefan Richter15490792009-02-23 14:21:10 +01001297{
1298 int ret;
1299
Stefan Richter6385c5b2009-11-18 16:03:03 -03001300 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001301
Stefan Richter53756592009-11-18 16:01:34 -03001302 ret = fdtv->backend->read(fdtv, addr, data);
Stefan Richter15490792009-02-23 14:21:10 +01001303 if (ret < 0)
1304 dev_err(fdtv->device, "CMP: read I/O error\n");
1305
1306 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001307
Stefan Richter15490792009-02-23 14:21:10 +01001308 return ret;
1309}
1310
Stefan Richter054286b2009-11-08 18:29:08 -03001311static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
Stefan Richter15490792009-02-23 14:21:10 +01001312{
1313 int ret;
1314
Stefan Richter6385c5b2009-11-18 16:03:03 -03001315 mutex_lock(&fdtv->avc_mutex);
Stefan Richter15490792009-02-23 14:21:10 +01001316
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001317 /* data[] is stack-allocated and should not be DMA-mapped. */
1318 memcpy(fdtv->avc_data, data, 8);
1319
1320 ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
Stefan Richter15490792009-02-23 14:21:10 +01001321 if (ret < 0)
1322 dev_err(fdtv->device, "CMP: lock I/O error\n");
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001323 else
1324 memcpy(data, fdtv->avc_data, 8);
Stefan Richter15490792009-02-23 14:21:10 +01001325
1326 mutex_unlock(&fdtv->avc_mutex);
Stefan Richter3fb80ef2009-11-18 16:02:01 -03001327
Stefan Richter15490792009-02-23 14:21:10 +01001328 return ret;
1329}
1330
1331static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
1332{
1333 return (be32_to_cpu(opcr) >> shift) & mask;
1334}
1335
1336static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
1337{
1338 *opcr &= ~cpu_to_be32(mask << shift);
1339 *opcr |= cpu_to_be32((value & mask) << shift);
1340}
1341
1342#define get_opcr_online(v) get_opcr((v), 0x1, 31)
1343#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24)
1344#define get_opcr_channel(v) get_opcr((v), 0x3f, 16)
1345
1346#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
1347#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16)
1348#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14)
1349#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10)
1350
1351int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
1352{
Stefan Richter054286b2009-11-08 18:29:08 -03001353 __be32 old_opcr, opcr[2];
Stefan Richter15490792009-02-23 14:21:10 +01001354 u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
1355 int attempts = 0;
1356 int ret;
1357
Stefan Richter53756592009-11-18 16:01:34 -03001358 ret = cmp_read(fdtv, opcr_address, opcr);
Stefan Richter15490792009-02-23 14:21:10 +01001359 if (ret < 0)
1360 return ret;
1361
1362repeat:
Stefan Richter054286b2009-11-08 18:29:08 -03001363 if (!get_opcr_online(*opcr)) {
Stefan Richter15490792009-02-23 14:21:10 +01001364 dev_err(fdtv->device, "CMP: output offline\n");
1365 return -EBUSY;
1366 }
1367
Stefan Richter054286b2009-11-08 18:29:08 -03001368 old_opcr = *opcr;
Stefan Richter15490792009-02-23 14:21:10 +01001369
Stefan Richter054286b2009-11-08 18:29:08 -03001370 if (get_opcr_p2p_connections(*opcr)) {
1371 if (get_opcr_channel(*opcr) != channel) {
Stefan Richter15490792009-02-23 14:21:10 +01001372 dev_err(fdtv->device, "CMP: cannot change channel\n");
1373 return -EBUSY;
1374 }
1375 dev_info(fdtv->device, "CMP: overlaying connection\n");
1376
1377 /* We don't allocate isochronous resources. */
1378 } else {
Stefan Richter054286b2009-11-08 18:29:08 -03001379 set_opcr_channel(opcr, channel);
1380 set_opcr_data_rate(opcr, 2); /* S400 */
Stefan Richter15490792009-02-23 14:21:10 +01001381
1382 /* FIXME: this is for the worst case - optimize */
Stefan Richter054286b2009-11-08 18:29:08 -03001383 set_opcr_overhead_id(opcr, 0);
Stefan Richter15490792009-02-23 14:21:10 +01001384
1385 /*
1386 * FIXME: allocate isochronous channel and bandwidth at IRM
1387 * fdtv->backend->alloc_resources(fdtv, channels_mask, bw);
1388 */
1389 }
1390
Stefan Richter054286b2009-11-08 18:29:08 -03001391 set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
Stefan Richter15490792009-02-23 14:21:10 +01001392
Stefan Richter054286b2009-11-08 18:29:08 -03001393 opcr[1] = *opcr;
1394 opcr[0] = old_opcr;
1395
1396 ret = cmp_lock(fdtv, opcr_address, opcr);
Stefan Richter15490792009-02-23 14:21:10 +01001397 if (ret < 0)
1398 return ret;
1399
Stefan Richter054286b2009-11-08 18:29:08 -03001400 if (old_opcr != *opcr) {
Stefan Richter15490792009-02-23 14:21:10 +01001401 /*
1402 * FIXME: if old_opcr.P2P_Connections > 0,
1403 * deallocate isochronous channel and bandwidth at IRM
1404 * if (...)
1405 * fdtv->backend->dealloc_resources(fdtv, channel, bw);
1406 */
1407
1408 if (++attempts < 6) /* arbitrary limit */
1409 goto repeat;
1410 return -EBUSY;
1411 }
1412
1413 return 0;
1414}
1415
1416void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
1417{
Stefan Richter054286b2009-11-08 18:29:08 -03001418 __be32 old_opcr, opcr[2];
Stefan Richter15490792009-02-23 14:21:10 +01001419 u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
1420 int attempts = 0;
1421
Stefan Richter53756592009-11-18 16:01:34 -03001422 if (cmp_read(fdtv, opcr_address, opcr) < 0)
Stefan Richter15490792009-02-23 14:21:10 +01001423 return;
1424
1425repeat:
Stefan Richter054286b2009-11-08 18:29:08 -03001426 if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) ||
1427 get_opcr_channel(*opcr) != channel) {
Stefan Richter15490792009-02-23 14:21:10 +01001428 dev_err(fdtv->device, "CMP: no connection to break\n");
1429 return;
1430 }
1431
Stefan Richter054286b2009-11-08 18:29:08 -03001432 old_opcr = *opcr;
1433 set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1);
Stefan Richter15490792009-02-23 14:21:10 +01001434
Stefan Richter054286b2009-11-08 18:29:08 -03001435 opcr[1] = *opcr;
1436 opcr[0] = old_opcr;
1437
1438 if (cmp_lock(fdtv, opcr_address, opcr) < 0)
Stefan Richter15490792009-02-23 14:21:10 +01001439 return;
1440
Stefan Richter054286b2009-11-08 18:29:08 -03001441 if (old_opcr != *opcr) {
Stefan Richter15490792009-02-23 14:21:10 +01001442 /*
1443 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
1444 * owner, deallocate isochronous channel and bandwidth at IRM
1445 * if (...)
1446 * fdtv->backend->dealloc_resources(fdtv, channel, bw);
1447 */
1448
1449 if (++attempts < 6) /* arbitrary limit */
1450 goto repeat;
1451 }
1452}