blob: 6337f9f21d0f8b93e79081f22a8fc5cd1c4b58e0 [file] [log] [blame]
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -08001/*
Stefan Richter612262a2008-08-26 00:17:30 +02002 * FireDTV driver (formerly known as FireSAT)
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -08003 *
Stefan Richter612262a2008-08-26 00:17:30 +02004 * 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>
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -08007 *
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
Stefan Richter612262a2008-08-26 00:17:30 +020014#include <linux/crc32.h>
15#include <linux/delay.h>
16#include <linux/kernel.h>
17#include <linux/moduleparam.h>
18#include <linux/mutex.h>
19#include <linux/wait.h>
20#include <linux/workqueue.h>
21#include <asm/atomic.h>
22
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080023#include <ieee1394_transactions.h>
24#include <nodemgr.h>
Stefan Richter612262a2008-08-26 00:17:30 +020025
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080026#include "avc_api.h"
Stefan Richter612262a2008-08-26 00:17:30 +020027#include "firesat.h"
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080028#include "firesat-rc.h"
29
30#define RESPONSE_REGISTER 0xFFFFF0000D00ULL
31#define COMMAND_REGISTER 0xFFFFF0000B00ULL
32#define PCR_BASE_ADDRESS 0xFFFFF0000900ULL
33
Henrik Kureliddf4846c2008-08-01 10:00:45 +020034static unsigned int avc_comm_debug = 0;
35module_param(avc_comm_debug, int, 0644);
Henrik Kurelid81c67b72008-08-24 15:20:07 +020036MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)");
Henrik Kureliddf4846c2008-08-01 10:00:45 +020037
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -080038/* Frees an allocated packet */
39static void avc_free_packet(struct hpsb_packet *packet)
40{
41 hpsb_free_tlabel(packet);
42 hpsb_free_packet(packet);
43}
44
Henrik Kureliddf4846c2008-08-01 10:00:45 +020045static const char* get_ctype_string(__u8 ctype)
46{
47 switch(ctype)
48 {
49 case 0:
50 return "CONTROL";
51 case 1:
52 return "STATUS";
53 case 2:
54 return "SPECIFIC_INQUIRY";
55 case 3:
56 return "NOTIFY";
57 case 4:
58 return "GENERAL_INQUIRY";
59 }
60 return "UNKNOWN";
61}
62
63static const char* get_resp_string(__u8 ctype)
64{
65 switch(ctype)
66 {
67 case 8:
68 return "NOT_IMPLEMENTED";
69 case 9:
70 return "ACCEPTED";
71 case 10:
72 return "REJECTED";
73 case 11:
74 return "IN_TRANSITION";
75 case 12:
76 return "IMPLEMENTED_STABLE";
77 case 13:
78 return "CHANGED";
79 case 15:
80 return "INTERIM";
81 }
82 return "UNKNOWN";
83}
84
85static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type)
86{
87 if (subunit_id == 7 && subunit_type == 0x1F)
88 return "Unit";
89 if (subunit_id == 0 && subunit_type == 0x05)
90 return "Tuner(0)";
91 return "Unsupported";
92}
93
94static const char* get_opcode_string(__u8 opcode)
95{
96 switch(opcode)
97 {
98 case 0x02:
99 return "PlugInfo";
100 case 0x08:
101 return "OpenDescriptor";
102 case 0x09:
103 return "ReadDescriptor";
104 case 0x18:
105 return "OutputPlugSignalFormat";
106 case 0x31:
107 return "SubunitInfo";
108 case 0x30:
109 return "UnitInfo";
110 case 0xB2:
111 return "Power";
112 case 0xC8:
113 return "DirectSelectInformationType";
114 case 0xCB:
115 return "DirectSelectData";
116 case 0x00:
117 return "Vendor";
118
119 }
120 return "Unknown";
121}
122
123static void log_command_frame(const AVCCmdFrm *CmdFrm)
124{
125 int k;
126 printk(KERN_INFO "AV/C Command Frame:\n");
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200127 printk(KERN_INFO "CommandType=%s, Address=%s(0x%02X,0x%02X), "
128 "opcode=%s(0x%02X), length=%d\n",
129 get_ctype_string(CmdFrm->ctype),
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200130 get_subunit_address(CmdFrm->suid, CmdFrm->sutyp),
131 CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode),
132 CmdFrm->opcode, CmdFrm->length);
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200133 if (avc_comm_debug > 1) {
134 for(k = 0; k < CmdFrm->length - 3; k++) {
135 if (k % 5 != 0)
136 printk(", ");
137 else if (k != 0)
138 printk("\n");
139 printk(KERN_INFO "operand[%d] = %02X", k,
140 CmdFrm->operand[k]);
141 }
142 printk(KERN_INFO "\n");
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200143 }
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200144}
145
146static void log_response_frame(const AVCRspFrm *RspFrm)
147{
148 int k;
149 printk(KERN_INFO "AV/C Response Frame:\n");
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200150 printk(KERN_INFO "Response=%s, Address=%s(0x%02X,0x%02X), "
151 "opcode=%s(0x%02X), length=%d\n", get_resp_string(RspFrm->resp),
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200152 get_subunit_address(RspFrm->suid, RspFrm->sutyp),
153 RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode),
154 RspFrm->opcode, RspFrm->length);
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200155 if (avc_comm_debug > 1) {
156 for(k = 0; k < RspFrm->length - 3; k++) {
157 if (k % 5 != 0)
158 printk(KERN_INFO ", ");
159 else if (k != 0)
160 printk(KERN_INFO "\n");
161 printk(KERN_INFO "operand[%d] = %02X", k,
162 RspFrm->operand[k]);
163 }
164 printk(KERN_INFO "\n");
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200165 }
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200166}
167
168static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm,
169 AVCRspFrm *RspFrm) {
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800170 struct hpsb_packet *packet;
171 struct node_entry *ne;
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200172 int num_tries = 0;
173 int packet_ok = 0;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800174
175 ne = firesat->nodeentry;
176 if(!ne) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200177 printk(KERN_ERR "%s: lost node!\n",__func__);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800178 return -EIO;
179 }
180
181 /* need all input data */
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200182 if(!firesat || !ne || !CmdFrm) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200183 printk(KERN_ERR "%s: missing input data!\n",__func__);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800184 return -EINVAL;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200185 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800186
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200187 if (avc_comm_debug > 0) {
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200188 log_command_frame(CmdFrm);
189 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800190
191 if(RspFrm)
192 atomic_set(&firesat->avc_reply_received, 0);
193
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200194 while (packet_ok == 0 && num_tries < 6) {
195 num_tries++;
196 packet_ok = 1;
197 packet = hpsb_make_writepacket(ne->host, ne->nodeid,
198 COMMAND_REGISTER,
199 (quadlet_t*)CmdFrm,
200 CmdFrm->length);
201 hpsb_set_packet_complete_task(packet,
202 (void (*)(void*))avc_free_packet,
203 packet);
204 hpsb_node_fill_packet(ne, packet);
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200205
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200206 if (hpsb_send_packet(packet) < 0) {
207 avc_free_packet(packet);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800208 atomic_set(&firesat->avc_reply_received, 1);
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200209 printk(KERN_ERR "%s: send failed!\n",__func__);
210 return -EIO;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200211 }
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200212
213 if(RspFrm) {
214 // AV/C specs say that answers should be send within
215 // 150 ms so let's time out after 200 ms
216 if (wait_event_timeout(firesat->avc_wait,
217 atomic_read(&firesat->avc_reply_received) == 1,
218 HZ / 5) == 0) {
219 packet_ok = 0;
220 }
221 else {
222 memcpy(RspFrm, firesat->respfrm,
223 firesat->resp_length);
224 RspFrm->length = firesat->resp_length;
225 if (avc_comm_debug > 0) {
226 log_response_frame(RspFrm);
227 }
228 }
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200229 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800230 }
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200231 if (packet_ok == 0) {
232 printk(KERN_ERR "%s: AV/C response timed out 6 times.\n",
233 __func__);
234 return -ETIMEDOUT;
235 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800236
237 return 0;
238}
239
Stefan Richter612262a2008-08-26 00:17:30 +0200240int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm)
241{
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800242 int ret;
Stefan Richter612262a2008-08-26 00:17:30 +0200243
244 if (mutex_lock_interruptible(&firesat->avc_mutex))
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800245 return -EINTR;
246
247 ret = __AVCWrite(firesat, CmdFrm, RspFrm);
248
Stefan Richter612262a2008-08-26 00:17:30 +0200249 mutex_unlock(&firesat->avc_mutex);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800250 return ret;
251}
252
Stefan Richter612262a2008-08-26 00:17:30 +0200253int AVCRecv(struct firesat *firesat, u8 *data, size_t length)
254{
255 AVCRspFrm *RspFrm = (AVCRspFrm *)data;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800256
Stefan Richter612262a2008-08-26 00:17:30 +0200257 if (length >= 8 &&
258 RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
259 RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
260 RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
261 RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
262 if (RspFrm->resp == CHANGED) {
263 firesat_handle_rc(RspFrm->operand[4] << 8 |
264 RspFrm->operand[5]);
265 schedule_work(&firesat->remote_ctrl_work);
266 } else if (RspFrm->resp != INTERIM) {
267 printk(KERN_INFO "firedtv: remote control result = "
268 "%d\n", RspFrm->resp);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800269 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800270 return 0;
271 }
Stefan Richter612262a2008-08-26 00:17:30 +0200272
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800273 if(atomic_read(&firesat->avc_reply_received) == 1) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200274 printk(KERN_ERR "%s: received out-of-order AVC response, "
275 "ignored\n",__func__);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800276 return -EINVAL;
277 }
278// AVCRspFrm *resp=(AVCRspFrm *)data;
279// int k;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200280
281// printk(KERN_INFO "resp=0x%x\n",resp->resp);
282// printk(KERN_INFO "cts=0x%x\n",resp->cts);
283// printk(KERN_INFO "suid=0x%x\n",resp->suid);
284// printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp);
285// printk(KERN_INFO "opcode=0x%x\n",resp->opcode);
286// printk(KERN_INFO "length=%d\n",resp->length);
287
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800288// for(k=0;k<2;k++)
289// printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]);
290
291 memcpy(firesat->respfrm,data,length);
292 firesat->resp_length=length;
293
294 atomic_set(&firesat->avc_reply_received, 1);
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200295 wake_up(&firesat->avc_wait);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800296
297 return 0;
298}
299
300// tuning command for setting the relative LNB frequency (not supported by the AVC standard)
301static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) {
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200302
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800303 memset(CmdFrm, 0, sizeof(AVCCmdFrm));
304
305 CmdFrm->cts = AVC;
306 CmdFrm->ctype = CONTROL;
307 CmdFrm->sutyp = 0x5;
308 CmdFrm->suid = firesat->subunit;
309 CmdFrm->opcode = VENDOR;
310
311 CmdFrm->operand[0]=SFE_VENDOR_DE_COMPANYID_0;
312 CmdFrm->operand[1]=SFE_VENDOR_DE_COMPANYID_1;
313 CmdFrm->operand[2]=SFE_VENDOR_DE_COMPANYID_2;
314 CmdFrm->operand[3]=SFE_VENDOR_OPCODE_TUNE_QPSK;
315
316 printk(KERN_INFO "%s: tuning to frequency %u\n",__func__,params->frequency);
317
318 CmdFrm->operand[4] = (params->frequency >> 24) & 0xFF;
319 CmdFrm->operand[5] = (params->frequency >> 16) & 0xFF;
320 CmdFrm->operand[6] = (params->frequency >> 8) & 0xFF;
321 CmdFrm->operand[7] = params->frequency & 0xFF;
322
323 printk(KERN_INFO "%s: symbol rate = %uBd\n",__func__,params->u.qpsk.symbol_rate);
324
325 CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate/1000) >> 8) & 0xFF;
326 CmdFrm->operand[9] = (params->u.qpsk.symbol_rate/1000) & 0xFF;
327
328 switch(params->u.qpsk.fec_inner) {
329 case FEC_1_2:
330 CmdFrm->operand[10] = 0x1;
331 break;
332 case FEC_2_3:
333 CmdFrm->operand[10] = 0x2;
334 break;
335 case FEC_3_4:
336 CmdFrm->operand[10] = 0x3;
337 break;
338 case FEC_5_6:
339 CmdFrm->operand[10] = 0x4;
340 break;
341 case FEC_7_8:
342 CmdFrm->operand[10] = 0x5;
343 break;
344 case FEC_4_5:
345 case FEC_8_9:
346 case FEC_AUTO:
347 default:
348 CmdFrm->operand[10] = 0x0;
349 }
350
351 if(firesat->voltage == 0xff)
352 CmdFrm->operand[11] = 0xff;
353 else
354 CmdFrm->operand[11] = (firesat->voltage==SEC_VOLTAGE_18)?0:1; // polarisation
355 if(firesat->tone == 0xff)
356 CmdFrm->operand[12] = 0xff;
357 else
358 CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band
359
Ben Backx2c228612008-08-09 14:35:55 +0200360 if (firesat->type == FireSAT_DVB_S2) {
361 CmdFrm->operand[13] = 0x1;
362 CmdFrm->operand[14] = 0xFF;
363 CmdFrm->operand[15] = 0xFF;
364 }
365
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800366 CmdFrm->length = 16;
367}
368
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200369int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) {
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800370 AVCCmdFrm CmdFrm;
371 AVCRspFrm RspFrm;
372 M_VALID_FLAGS flags;
373 int k;
374
375// printk(KERN_INFO "%s\n", __func__);
376
Ben Backxf1bbb432008-06-22 16:00:53 +0200377 if (firesat->type == FireSAT_DVB_S || firesat->type == FireSAT_DVB_S2)
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800378 AVCTuner_tuneQPSK(firesat, params, &CmdFrm);
379 else {
380 if(firesat->type == FireSAT_DVB_T) {
381 flags.Bits_T.GuardInterval = (params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO);
382 flags.Bits_T.CodeRateLPStream = (params->u.ofdm.code_rate_LP != FEC_AUTO);
383 flags.Bits_T.CodeRateHPStream = (params->u.ofdm.code_rate_HP != FEC_AUTO);
384 flags.Bits_T.HierarchyInfo = (params->u.ofdm.hierarchy_information != HIERARCHY_AUTO);
385 flags.Bits_T.Constellation = (params->u.ofdm.constellation != QAM_AUTO);
386 flags.Bits_T.Bandwidth = (params->u.ofdm.bandwidth != BANDWIDTH_AUTO);
387 flags.Bits_T.CenterFrequency = 1;
388 flags.Bits_T.reserved1 = 0;
389 flags.Bits_T.reserved2 = 0;
390 flags.Bits_T.OtherFrequencyFlag = 0;
391 flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO);
392 flags.Bits_T.NetworkId = 0;
393 } else {
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200394 flags.Bits.Modulation =
395 (params->u.qam.modulation != QAM_AUTO);
396 flags.Bits.FEC_inner =
397 (params->u.qam.fec_inner != FEC_AUTO);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800398 flags.Bits.FEC_outer = 0;
399 flags.Bits.Symbol_Rate = 1;
400 flags.Bits.Frequency = 1;
401 flags.Bits.Orbital_Pos = 0;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200402 flags.Bits.Polarisation = 0;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800403 flags.Bits.reserved_fields = 0;
404 flags.Bits.reserved1 = 0;
405 flags.Bits.Network_ID = 0;
406 }
407
408 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
409
410 CmdFrm.cts = AVC;
411 CmdFrm.ctype = CONTROL;
412 CmdFrm.sutyp = 0x5;
413 CmdFrm.suid = firesat->subunit;
414 CmdFrm.opcode = DSD;
415
416 CmdFrm.operand[0] = 0; // source plug
417 CmdFrm.operand[1] = 0xD2; // subfunction replace
418 CmdFrm.operand[2] = 0x20; // system id = DVB
419 CmdFrm.operand[3] = 0x00; // antenna number
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200420 // system_specific_multiplex selection_length
421 CmdFrm.operand[4] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800422 CmdFrm.operand[5] = flags.Valid_Word.ByteHi; // valid_flags [0]
423 CmdFrm.operand[6] = flags.Valid_Word.ByteLo; // valid_flags [1]
424
425 if(firesat->type == FireSAT_DVB_T) {
426 CmdFrm.operand[7] = 0x0;
427 CmdFrm.operand[8] = (params->frequency/10) >> 24;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200428 CmdFrm.operand[9] =
429 ((params->frequency/10) >> 16) & 0xFF;
430 CmdFrm.operand[10] =
431 ((params->frequency/10) >> 8) & 0xFF;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800432 CmdFrm.operand[11] = (params->frequency/10) & 0xFF;
433 switch(params->u.ofdm.bandwidth) {
434 case BANDWIDTH_7_MHZ:
435 CmdFrm.operand[12] = 0x20;
436 break;
437 case BANDWIDTH_8_MHZ:
438 case BANDWIDTH_6_MHZ: // not defined by AVC spec
439 case BANDWIDTH_AUTO:
440 default:
441 CmdFrm.operand[12] = 0x00;
442 }
443 switch(params->u.ofdm.constellation) {
444 case QAM_16:
445 CmdFrm.operand[13] = 1 << 6;
446 break;
447 case QAM_64:
448 CmdFrm.operand[13] = 2 << 6;
449 break;
450 case QPSK:
451 default:
452 CmdFrm.operand[13] = 0x00;
453 }
454 switch(params->u.ofdm.hierarchy_information) {
455 case HIERARCHY_1:
456 CmdFrm.operand[13] |= 1 << 3;
457 break;
458 case HIERARCHY_2:
459 CmdFrm.operand[13] |= 2 << 3;
460 break;
461 case HIERARCHY_4:
462 CmdFrm.operand[13] |= 3 << 3;
463 break;
464 case HIERARCHY_AUTO:
465 case HIERARCHY_NONE:
466 default:
467 break;
468 }
469 switch(params->u.ofdm.code_rate_HP) {
470 case FEC_2_3:
471 CmdFrm.operand[13] |= 1;
472 break;
473 case FEC_3_4:
474 CmdFrm.operand[13] |= 2;
475 break;
476 case FEC_5_6:
477 CmdFrm.operand[13] |= 3;
478 break;
479 case FEC_7_8:
480 CmdFrm.operand[13] |= 4;
481 break;
482 case FEC_1_2:
483 default:
484 break;
485 }
486 switch(params->u.ofdm.code_rate_LP) {
487 case FEC_2_3:
488 CmdFrm.operand[14] = 1 << 5;
489 break;
490 case FEC_3_4:
491 CmdFrm.operand[14] = 2 << 5;
492 break;
493 case FEC_5_6:
494 CmdFrm.operand[14] = 3 << 5;
495 break;
496 case FEC_7_8:
497 CmdFrm.operand[14] = 4 << 5;
498 break;
499 case FEC_1_2:
500 default:
501 CmdFrm.operand[14] = 0x00;
502 break;
503 }
504 switch(params->u.ofdm.guard_interval) {
505 case GUARD_INTERVAL_1_16:
506 CmdFrm.operand[14] |= 1 << 3;
507 break;
508 case GUARD_INTERVAL_1_8:
509 CmdFrm.operand[14] |= 2 << 3;
510 break;
511 case GUARD_INTERVAL_1_4:
512 CmdFrm.operand[14] |= 3 << 3;
513 break;
514 case GUARD_INTERVAL_1_32:
515 case GUARD_INTERVAL_AUTO:
516 default:
517 break;
518 }
519 switch(params->u.ofdm.transmission_mode) {
520 case TRANSMISSION_MODE_8K:
521 CmdFrm.operand[14] |= 1 << 1;
522 break;
523 case TRANSMISSION_MODE_2K:
524 case TRANSMISSION_MODE_AUTO:
525 default:
526 break;
527 }
528
529 CmdFrm.operand[15] = 0x00; // network_ID[0]
530 CmdFrm.operand[16] = 0x00; // network_ID[1]
531 CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted
532
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200533 CmdFrm.length = 24;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800534 } else {
535 CmdFrm.operand[7] = 0x00;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200536 CmdFrm.operand[8] = 0x00;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800537 CmdFrm.operand[9] = 0x00;
538 CmdFrm.operand[10] = 0x00;
539
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200540 CmdFrm.operand[11] =
541 (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6);
542 CmdFrm.operand[12] =
543 ((params->frequency/4000) >> 8) & 0xFF;
544 CmdFrm.operand[13] = (params->frequency/4000) & 0xFF;
545 CmdFrm.operand[14] =
546 ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF;
547 CmdFrm.operand[15] =
548 ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF;
549 CmdFrm.operand[16] =
550 ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800551 CmdFrm.operand[17] = 0x00;
552 switch(params->u.qpsk.fec_inner) {
553 case FEC_1_2:
554 CmdFrm.operand[18] = 0x1;
555 break;
556 case FEC_2_3:
557 CmdFrm.operand[18] = 0x2;
558 break;
559 case FEC_3_4:
560 CmdFrm.operand[18] = 0x3;
561 break;
562 case FEC_5_6:
563 CmdFrm.operand[18] = 0x4;
564 break;
565 case FEC_7_8:
566 CmdFrm.operand[18] = 0x5;
567 break;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800568 case FEC_8_9:
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200569 CmdFrm.operand[18] = 0x6;
570 break;
571 case FEC_4_5:
572 CmdFrm.operand[18] = 0x8;
573 break;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800574 case FEC_AUTO:
575 default:
576 CmdFrm.operand[18] = 0x0;
577 }
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200578 switch(params->u.qam.modulation) {
579 case QAM_16:
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800580 CmdFrm.operand[19] = 0x08; // modulation
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200581 break;
582 case QAM_32:
583 CmdFrm.operand[19] = 0x10; // modulation
584 break;
585 case QAM_64:
586 CmdFrm.operand[19] = 0x18; // modulation
587 break;
588 case QAM_128:
589 CmdFrm.operand[19] = 0x20; // modulation
590 break;
591 case QAM_256:
592 CmdFrm.operand[19] = 0x28; // modulation
593 break;
594 case QAM_AUTO:
595 default:
596 CmdFrm.operand[19] = 0x00; // modulation
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800597 }
598 CmdFrm.operand[20] = 0x00;
599 CmdFrm.operand[21] = 0x00;
600 CmdFrm.operand[22] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted
601
602 CmdFrm.length=28;
603 }
604 } // AVCTuner_DSD_direct
605
606 if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
607 return k;
608
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800609 mdelay(500);
610
611 if(status)
612 *status=RspFrm.operand[2];
613 return 0;
614}
615
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200616int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[])
617{
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800618 AVCCmdFrm CmdFrm;
619 AVCRspFrm RspFrm;
620 int pos,k;
621
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800622 if(pidc > 16 && pidc != 0xFF)
623 return -EINVAL;
624
625 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
626
627 CmdFrm.cts = AVC;
628 CmdFrm.ctype = CONTROL;
629 CmdFrm.sutyp = 0x5;
630 CmdFrm.suid = firesat->subunit;
631 CmdFrm.opcode = DSD;
632
633 CmdFrm.operand[0] = 0; // source plug
634 CmdFrm.operand[1] = 0xD2; // subfunction replace
635 CmdFrm.operand[2] = 0x20; // system id = DVB
636 CmdFrm.operand[3] = 0x00; // antenna number
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200637 CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length
638 CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800639
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200640 pos=6;
641 if(pidc != 0xFF) {
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800642 for(k=0;k<pidc;k++) {
643 CmdFrm.operand[pos++] = 0x13; // flowfunction relay
644 CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID
645 CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F;
646 CmdFrm.operand[pos++] = pid[k] & 0xFF;
647 CmdFrm.operand[pos++] = 0x00; // tableID
648 CmdFrm.operand[pos++] = 0x00; // filter_length
649 }
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200650 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800651
652 CmdFrm.length = pos+3;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800653 if((pos+3)%4)
654 CmdFrm.length += 4 - ((pos+3)%4);
655
656 if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
657 return k;
658
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200659 mdelay(50);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800660 return 0;
661}
662
663int AVCTuner_GetTS(struct firesat *firesat){
664 AVCCmdFrm CmdFrm;
665 AVCRspFrm RspFrm;
666 int k;
667
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200668 //printk(KERN_INFO "%s\n", __func__);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800669
670 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
671
672 CmdFrm.cts = AVC;
673 CmdFrm.ctype = CONTROL;
674 CmdFrm.sutyp = 0x5;
675 CmdFrm.suid = firesat->subunit;
676 CmdFrm.opcode = DSIT;
677
678 CmdFrm.operand[0] = 0; // source plug
679 CmdFrm.operand[1] = 0xD2; // subfunction replace
680 CmdFrm.operand[2] = 0xFF; //status
681 CmdFrm.operand[3] = 0x20; // system id = DVB
682 CmdFrm.operand[4] = 0x00; // antenna number
683 CmdFrm.operand[5] = 0x0; // system_specific_search_flags
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200684 CmdFrm.operand[6] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800685 CmdFrm.operand[7] = 0x00; // valid_flags [0]
686 CmdFrm.operand[8] = 0x00; // valid_flags [1]
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200687 CmdFrm.operand[7 + (firesat->type == FireSAT_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0)
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800688
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200689 CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800690
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200691 if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm)))
692 return k;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800693
694 mdelay(250);
695 return 0;
696}
697
Stefan Richter612262a2008-08-26 00:17:30 +0200698int AVCIdentifySubunit(struct firesat *firesat)
699{
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800700 AVCCmdFrm CmdFrm;
701 AVCRspFrm RspFrm;
702
703 memset(&CmdFrm,0,sizeof(AVCCmdFrm));
704
705 CmdFrm.cts = AVC;
706 CmdFrm.ctype = CONTROL;
707 CmdFrm.sutyp = 0x5; // tuner
708 CmdFrm.suid = firesat->subunit;
709 CmdFrm.opcode = READ_DESCRIPTOR;
710
711 CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER;
712 CmdFrm.operand[1]=0xff;
713 CmdFrm.operand[2]=0x00;
714 CmdFrm.operand[3]=0x00; // length highbyte
715 CmdFrm.operand[4]=0x08; // length lowbyte
716 CmdFrm.operand[5]=0x00; // offset highbyte
717 CmdFrm.operand[6]=0x0d; // offset lowbyte
718
719 CmdFrm.length=12;
720
721 if(AVCWrite(firesat,&CmdFrm,&RspFrm)<0)
722 return -EIO;
723
724 if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200725 printk(KERN_ERR "%s: AVCWrite returned error code %d\n",
726 __func__, RspFrm.resp);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800727 return -EINVAL;
728 }
729 if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200730 printk(KERN_ERR "%s: Invalid response length\n", __func__);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800731 return -EINVAL;
732 }
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800733 return 0;
734}
735
736int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info) {
737 AVCCmdFrm CmdFrm;
738 AVCRspFrm RspFrm;
739 int length;
740
741 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
742
743 CmdFrm.cts=AVC;
744 CmdFrm.ctype=CONTROL;
745 CmdFrm.sutyp=0x05; // tuner
746 CmdFrm.suid=firesat->subunit;
747 CmdFrm.opcode=READ_DESCRIPTOR;
748
749 CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200750 CmdFrm.operand[1]=0xff; //read_result_status
751 CmdFrm.operand[2]=0x00; // reserver
752 CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8;
753 CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800754 CmdFrm.operand[5]=0x00;
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200755 CmdFrm.operand[6]=0x00;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800756 CmdFrm.length=12;
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800757 if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
758 return -EIO;
759
760 if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200761 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
762 __func__, RspFrm.resp);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800763 return -EINVAL;
764 }
765
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200766 length = RspFrm.operand[9];
767 if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO))
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800768 {
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200769 memcpy(antenna_input_info, &RspFrm.operand[10],
770 sizeof(ANTENNA_INPUT_INFO));
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800771 return 0;
772 }
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200773 printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned "
774 "from AVC\n", __func__, RspFrm.operand[1], length);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800775 return -EINVAL;
776}
777
778int AVCLNBControl(struct firesat *firesat, char voltage, char burst,
779 char conttone, char nrdiseq,
780 struct dvb_diseqc_master_cmd *diseqcmd)
781{
782 AVCCmdFrm CmdFrm;
783 AVCRspFrm RspFrm;
784 int i,j;
785
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200786 printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",
787 __func__, voltage, burst, conttone);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800788
789 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
790
791 CmdFrm.cts=AVC;
792 CmdFrm.ctype=CONTROL;
793 CmdFrm.sutyp=0x05;
794 CmdFrm.suid=firesat->subunit;
795 CmdFrm.opcode=VENDOR;
796
797 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
798 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
799 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
800 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL;
801
802 CmdFrm.operand[4]=voltage;
803 CmdFrm.operand[5]=nrdiseq;
804
805 i=6;
806
807 for(j=0;j<nrdiseq;j++) {
808 int k;
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200809 printk(KERN_INFO "%s: diseq %d len %x\n",
810 __func__, j, diseqcmd[j].msg_len);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800811 CmdFrm.operand[i++]=diseqcmd[j].msg_len;
812
813 for(k=0;k<diseqcmd[j].msg_len;k++) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200814 printk(KERN_INFO "%s: diseq %d msg[%d] = %x\n",
815 __func__, j, k, diseqcmd[j].msg[k]);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800816 CmdFrm.operand[i++]=diseqcmd[j].msg[k];
817 }
818 }
819
820 CmdFrm.operand[i++]=burst;
821 CmdFrm.operand[i++]=conttone;
822
823 CmdFrm.length=i+3;
824 if((i+3)%4)
825 CmdFrm.length += 4 - ((i+3)%4);
826
827/* for(j=0;j<CmdFrm.length;j++)
828 printk(KERN_INFO "%s: CmdFrm.operand[%d]=0x%x\n",__func__,j,CmdFrm.operand[j]);
829
830 printk(KERN_INFO "%s: cmdfrm.length = %u\n",__func__,CmdFrm.length);
831 */
832 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
833 return -EIO;
834
835 if(RspFrm.resp != ACCEPTED) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200836 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
837 __func__, RspFrm.resp);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800838 return -EINVAL;
839 }
840
841 return 0;
842}
843
844int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount)
845{
846 AVCCmdFrm CmdFrm;
847 AVCRspFrm RspFrm;
848
849 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
850
851 CmdFrm.cts = AVC;
852 CmdFrm.ctype = STATUS;
853 CmdFrm.sutyp = 0x1f;
854 CmdFrm.suid = 0x7;
855 CmdFrm.opcode = SUBUNIT_Info;
856
857 CmdFrm.operand[0] = 0x07;
858 CmdFrm.operand[1] = 0xff;
859 CmdFrm.operand[2] = 0xff;
860 CmdFrm.operand[3] = 0xff;
861 CmdFrm.operand[4] = 0xff;
862
863 CmdFrm.length = 8;
864
865 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
866 return -EIO;
867
868 if(RspFrm.resp != STABLE) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +0200869 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
870 __func__, RspFrm.resp);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800871 return -EINVAL;
872 }
873
874 if(subunitcount)
875 *subunitcount = (RspFrm.operand[1] & 0x7) + 1;
876
877 return 0;
878}
879
Stefan Richter612262a2008-08-26 00:17:30 +0200880int AVCRegisterRemoteControl(struct firesat *firesat)
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800881{
882 AVCCmdFrm CmdFrm;
883
884// printk(KERN_INFO "%s\n",__func__);
885
886 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
887
888 CmdFrm.cts = AVC;
889 CmdFrm.ctype = NOTIFY;
890 CmdFrm.sutyp = 0x1f;
891 CmdFrm.suid = 0x7;
892 CmdFrm.opcode = VENDOR;
893
894 CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0;
895 CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1;
896 CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2;
897 CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
898
899 CmdFrm.length = 8;
900
Stefan Richter612262a2008-08-26 00:17:30 +0200901 return AVCWrite(firesat, &CmdFrm, NULL);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800902}
903
Stefan Richter612262a2008-08-26 00:17:30 +0200904void avc_remote_ctrl_work(struct work_struct *work)
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800905{
Stefan Richter612262a2008-08-26 00:17:30 +0200906 struct firesat *firesat =
907 container_of(work, struct firesat, remote_ctrl_work);
908
909 /* Should it be rescheduled in failure cases? */
910 AVCRegisterRemoteControl(firesat);
Greg Kroah-Hartmanc81c8b62008-03-06 21:30:23 -0800911}
Henrik Kureliddf4846c2008-08-01 10:00:45 +0200912
913int AVCTuner_Host2Ca(struct firesat *firesat)
914{
915
916 AVCCmdFrm CmdFrm;
917 AVCRspFrm RspFrm;
918
919 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
920 CmdFrm.cts = AVC;
921 CmdFrm.ctype = CONTROL;
922 CmdFrm.sutyp = 0x5;
923 CmdFrm.suid = firesat->subunit;
924 CmdFrm.opcode = VENDOR;
925
926 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
927 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
928 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
929 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
930 CmdFrm.operand[4] = 0; // slot
931 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
932 CmdFrm.operand[6] = 0; // more/last
933 CmdFrm.operand[7] = 0; // length
934 CmdFrm.length = 12;
935
936 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
937 return -EIO;
938
939 return 0;
940}
941
942static int get_ca_object_pos(AVCRspFrm *RspFrm)
943{
944 int length = 1;
945
946 // Check length of length field
947 if (RspFrm->operand[7] & 0x80)
948 length = (RspFrm->operand[7] & 0x7F) + 1;
949 return length + 7;
950}
951
952static int get_ca_object_length(AVCRspFrm *RspFrm)
953{
954 int size = 0;
955 int i;
956
957 if (RspFrm->operand[7] & 0x80) {
958 for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) {
959 size <<= 8;
960 size += RspFrm->operand[8 + i];
961 }
962 }
963 return RspFrm->operand[7];
964}
965
966int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length)
967{
968 AVCCmdFrm CmdFrm;
969 AVCRspFrm RspFrm;
970 int pos;
971
972 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
973 CmdFrm.cts = AVC;
974 CmdFrm.ctype = STATUS;
975 CmdFrm.sutyp = 0x5;
976 CmdFrm.suid = firesat->subunit;
977 CmdFrm.opcode = VENDOR;
978
979 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
980 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
981 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
982 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
983 CmdFrm.operand[4] = 0; // slot
984 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
985 CmdFrm.length = 12;
986
987 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
988 return -EIO;
989
990
991 pos = get_ca_object_pos(&RspFrm);
992 app_info[0] = (TAG_APP_INFO >> 16) & 0xFF;
993 app_info[1] = (TAG_APP_INFO >> 8) & 0xFF;
994 app_info[2] = (TAG_APP_INFO >> 0) & 0xFF;
995 app_info[3] = 6 + RspFrm.operand[pos + 4];
996 app_info[4] = 0x01;
997 memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]);
998 *length = app_info[3] + 4;
999
1000 return 0;
1001}
1002
1003int avc_ca_info(struct firesat *firesat, char *app_info, int *length)
1004{
1005 AVCCmdFrm CmdFrm;
1006 AVCRspFrm RspFrm;
1007 int pos;
1008
1009 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1010 CmdFrm.cts = AVC;
1011 CmdFrm.ctype = STATUS;
1012 CmdFrm.sutyp = 0x5;
1013 CmdFrm.suid = firesat->subunit;
1014 CmdFrm.opcode = VENDOR;
1015
1016 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1017 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1018 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1019 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1020 CmdFrm.operand[4] = 0; // slot
1021 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
1022 CmdFrm.length = 12;
1023
1024 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1025 return -EIO;
1026
1027 pos = get_ca_object_pos(&RspFrm);
1028 app_info[0] = (TAG_CA_INFO >> 16) & 0xFF;
1029 app_info[1] = (TAG_CA_INFO >> 8) & 0xFF;
1030 app_info[2] = (TAG_CA_INFO >> 0) & 0xFF;
1031 app_info[3] = 2;
1032 app_info[4] = app_info[5];
1033 app_info[5] = app_info[6];
1034 *length = app_info[3] + 4;
1035
1036 return 0;
1037}
1038
1039int avc_ca_reset(struct firesat *firesat)
1040{
1041 AVCCmdFrm CmdFrm;
1042 AVCRspFrm RspFrm;
1043
1044 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1045 CmdFrm.cts = AVC;
1046 CmdFrm.ctype = CONTROL;
1047 CmdFrm.sutyp = 0x5;
1048 CmdFrm.suid = firesat->subunit;
1049 CmdFrm.opcode = VENDOR;
1050
1051 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1052 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1053 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1054 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
1055 CmdFrm.operand[4] = 0; // slot
1056 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag
1057 CmdFrm.operand[6] = 0; // more/last
1058 CmdFrm.operand[7] = 1; // length
1059 CmdFrm.operand[8] = 0; // force hardware reset
1060 CmdFrm.length = 12;
1061
1062 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1063 return -EIO;
1064
1065 return 0;
1066}
1067
1068int avc_ca_pmt(struct firesat *firesat, char *msg, int length)
1069{
1070 AVCCmdFrm CmdFrm;
1071 AVCRspFrm RspFrm;
1072 int list_management;
1073 int program_info_length;
1074 int pmt_cmd_id;
1075 int read_pos;
1076 int write_pos;
1077 int es_info_length;
1078 int crc32_csum;
1079
1080 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1081 CmdFrm.cts = AVC;
1082 CmdFrm.ctype = CONTROL;
1083 CmdFrm.sutyp = 0x5;
1084 CmdFrm.suid = firesat->subunit;
1085 CmdFrm.opcode = VENDOR;
1086
1087 if (msg[0] != LIST_MANAGEMENT_ONLY) {
Henrik Kurelid81c67b72008-08-24 15:20:07 +02001088 printk(KERN_INFO "%s: list_management %d not support. "
1089 "Forcing list_management to \"only\" (3). \n",
1090 __func__, msg[0]);
1091 msg[0] = LIST_MANAGEMENT_ONLY;
Henrik Kureliddf4846c2008-08-01 10:00:45 +02001092 }
1093 // We take the cmd_id from the programme level only!
1094 list_management = msg[0];
1095 program_info_length = ((msg[4] & 0x0F) << 8) + msg[5];
1096 if (program_info_length > 0)
1097 program_info_length--; // Remove pmt_cmd_id
1098 pmt_cmd_id = msg[6];
1099
1100 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1101 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1102 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1103 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
1104 CmdFrm.operand[4] = 0; // slot
1105 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag
1106 CmdFrm.operand[6] = 0; // more/last
1107 //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length
1108 CmdFrm.operand[8] = list_management;
1109 CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble
1110
1111 // TS program map table
1112
1113 // Table id=2
1114 CmdFrm.operand[10] = 0x02;
1115 // Section syntax + length
1116 CmdFrm.operand[11] = 0x80;
1117 //CmdFrm.operand[12] = XXXprogram_info_length + 12;
1118 // Program number
1119 CmdFrm.operand[13] = msg[1];
1120 CmdFrm.operand[14] = msg[2];
1121 // Version number=0 + current/next=1
1122 CmdFrm.operand[15] = 0x01;
1123 // Section number=0
1124 CmdFrm.operand[16] = 0x00;
1125 // Last section number=0
1126 CmdFrm.operand[17] = 0x00;
1127 // PCR_PID=1FFF
1128 CmdFrm.operand[18] = 0x1F;
1129 CmdFrm.operand[19] = 0xFF;
1130 // Program info length
1131 CmdFrm.operand[20] = (program_info_length >> 8);
1132 CmdFrm.operand[21] = (program_info_length & 0xFF);
1133 // CA descriptors at programme level
1134 read_pos = 6;
1135 write_pos = 22;
1136 if (program_info_length > 0) {
1137/* printk(KERN_INFO "Copying descriptors at programme level.\n"); */
1138 pmt_cmd_id = msg[read_pos++];
1139 if (pmt_cmd_id != 1 && pmt_cmd_id !=4) {
1140 printk(KERN_ERR "Invalid pmt_cmd_id=%d.\n",
1141 pmt_cmd_id);
1142 }
1143 memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
1144 program_info_length);
1145 read_pos += program_info_length;
1146 write_pos += program_info_length;
1147 }
1148 while (read_pos < length) {
1149/* printk(KERN_INFO "Copying descriptors at stream level for " */
1150/* "stream type %d.\n", msg[read_pos]); */
1151 CmdFrm.operand[write_pos++] = msg[read_pos++];
1152 CmdFrm.operand[write_pos++] = msg[read_pos++];
1153 CmdFrm.operand[write_pos++] = msg[read_pos++];
1154 es_info_length =
1155 ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1];
1156 read_pos += 2;
1157 if (es_info_length > 0)
1158 es_info_length--; // Remove pmt_cmd_id
1159 CmdFrm.operand[write_pos++] = es_info_length >> 8;
1160 CmdFrm.operand[write_pos++] = es_info_length & 0xFF;
1161 if (es_info_length > 0) {
1162 pmt_cmd_id = msg[read_pos++];
1163 if (pmt_cmd_id != 1 && pmt_cmd_id !=4) {
1164 printk(KERN_ERR "Invalid pmt_cmd_id=%d at "
1165 "stream level.\n", pmt_cmd_id);
1166 }
1167 memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
1168 es_info_length);
1169 read_pos += es_info_length;
1170 write_pos += es_info_length;
1171 }
1172 }
1173
1174 // CRC
1175 CmdFrm.operand[write_pos++] = 0x00;
1176 CmdFrm.operand[write_pos++] = 0x00;
1177 CmdFrm.operand[write_pos++] = 0x00;
1178 CmdFrm.operand[write_pos++] = 0x00;
1179
1180 CmdFrm.operand[7] = write_pos - 8;
1181 CmdFrm.operand[12] = write_pos - 13;
1182
1183 crc32_csum = crc32_be(0, &CmdFrm.operand[10],
1184 CmdFrm.operand[12] - 1);
1185 CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF;
1186 CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF;
1187 CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF;
1188 CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF;
1189
1190 CmdFrm.length = write_pos + 3;
1191 if ((write_pos + 3) % 4)
1192 CmdFrm.length += 4 - ((write_pos + 3) % 4);
1193
1194 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1195 return -EIO;
1196
1197 if (RspFrm.resp != ACCEPTED) {
1198 printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp);
1199 return -EFAULT;
1200 }
1201
1202 return 0;
1203
1204}
1205
1206int avc_ca_get_time_date(struct firesat *firesat, int *interval)
1207{
1208 AVCCmdFrm CmdFrm;
1209 AVCRspFrm RspFrm;
1210
1211 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1212 CmdFrm.cts = AVC;
1213 CmdFrm.ctype = STATUS;
1214 CmdFrm.sutyp = 0x5;
1215 CmdFrm.suid = firesat->subunit;
1216 CmdFrm.opcode = VENDOR;
1217
1218 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1219 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1220 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1221 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1222 CmdFrm.operand[4] = 0; // slot
1223 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag
1224 CmdFrm.operand[6] = 0; // more/last
1225 CmdFrm.operand[7] = 0; // length
1226 CmdFrm.length = 12;
1227
1228 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1229 return -EIO;
1230
1231 *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)];
1232
1233 return 0;
1234}
1235
1236int avc_ca_enter_menu(struct firesat *firesat)
1237{
1238 AVCCmdFrm CmdFrm;
1239 AVCRspFrm RspFrm;
1240
1241 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1242 CmdFrm.cts = AVC;
1243 CmdFrm.ctype = STATUS;
1244 CmdFrm.sutyp = 0x5;
1245 CmdFrm.suid = firesat->subunit;
1246 CmdFrm.opcode = VENDOR;
1247
1248 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1249 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1250 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1251 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
1252 CmdFrm.operand[4] = 0; // slot
1253 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
1254 CmdFrm.operand[6] = 0; // more/last
1255 CmdFrm.operand[7] = 0; // length
1256 CmdFrm.length = 12;
1257
1258 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1259 return -EIO;
1260
1261 return 0;
1262}
1263
1264int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length)
1265{
1266 AVCCmdFrm CmdFrm;
1267 AVCRspFrm RspFrm;
1268
1269 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1270 CmdFrm.cts = AVC;
1271 CmdFrm.ctype = STATUS;
1272 CmdFrm.sutyp = 0x5;
1273 CmdFrm.suid = firesat->subunit;
1274 CmdFrm.opcode = VENDOR;
1275
1276 CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1277 CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1278 CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1279 CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1280 CmdFrm.operand[4] = 0; // slot
1281 CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI;
1282 CmdFrm.operand[6] = 0; // more/last
1283 CmdFrm.operand[7] = 0; // length
1284 CmdFrm.length = 12;
1285
1286 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1287 return -EIO;
1288
1289 *length = get_ca_object_length(&RspFrm);
1290 memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length);
1291
1292 return 0;
1293}