firesat: avc resend
[linux-2.6-block.git] / drivers / media / dvb / firesat / avc_api.c
1 /*
2  * FireSAT AVC driver
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 "firesat.h"
15 #include <ieee1394_transactions.h>
16 #include <nodemgr.h>
17 #include <asm/byteorder.h>
18 #include <linux/delay.h>
19 #include <linux/crc32.h>
20 #include "avc_api.h"
21 #include "firesat-rc.h"
22
23 #define RESPONSE_REGISTER                               0xFFFFF0000D00ULL
24 #define COMMAND_REGISTER                                0xFFFFF0000B00ULL
25 #define PCR_BASE_ADDRESS                                0xFFFFF0000900ULL
26
27 static unsigned int avc_comm_debug = 0;
28 module_param(avc_comm_debug, int, 0644);
29 MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)");
30
31 static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal);
32
33 /* Frees an allocated packet */
34 static void avc_free_packet(struct hpsb_packet *packet)
35 {
36         hpsb_free_tlabel(packet);
37         hpsb_free_packet(packet);
38 }
39
40 static const char* get_ctype_string(__u8 ctype)
41 {
42         switch(ctype)
43         {
44         case 0:
45                 return "CONTROL";
46         case 1:
47                 return "STATUS";
48         case 2:
49                 return "SPECIFIC_INQUIRY";
50         case 3:
51                 return "NOTIFY";
52         case 4:
53                 return "GENERAL_INQUIRY";
54         }
55         return "UNKNOWN";
56 }
57
58 static const char* get_resp_string(__u8 ctype)
59 {
60         switch(ctype)
61         {
62         case 8:
63                 return "NOT_IMPLEMENTED";
64         case 9:
65                 return "ACCEPTED";
66         case 10:
67                 return "REJECTED";
68         case 11:
69                 return "IN_TRANSITION";
70         case 12:
71                 return "IMPLEMENTED_STABLE";
72         case 13:
73                 return "CHANGED";
74         case 15:
75                 return "INTERIM";
76         }
77         return "UNKNOWN";
78 }
79
80 static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type)
81 {
82         if (subunit_id == 7 && subunit_type == 0x1F)
83                 return "Unit";
84         if (subunit_id == 0 && subunit_type == 0x05)
85                 return "Tuner(0)";
86         return "Unsupported";
87 }
88
89 static const char* get_opcode_string(__u8 opcode)
90 {
91         switch(opcode)
92         {
93         case 0x02:
94                 return "PlugInfo";
95         case 0x08:
96                 return "OpenDescriptor";
97         case 0x09:
98                 return "ReadDescriptor";
99         case 0x18:
100                 return "OutputPlugSignalFormat";
101         case 0x31:
102                 return "SubunitInfo";
103         case 0x30:
104                 return "UnitInfo";
105         case 0xB2:
106                 return "Power";
107         case 0xC8:
108                 return "DirectSelectInformationType";
109         case 0xCB:
110                 return "DirectSelectData";
111         case 0x00:
112                 return "Vendor";
113
114         }
115         return "Unknown";
116 }
117
118 static void log_command_frame(const AVCCmdFrm *CmdFrm)
119 {
120         int k;
121         printk(KERN_INFO "AV/C Command Frame:\n");
122         printk(KERN_INFO "CommandType=%s, Address=%s(0x%02X,0x%02X), "
123                "opcode=%s(0x%02X), length=%d\n",
124                get_ctype_string(CmdFrm->ctype),
125                get_subunit_address(CmdFrm->suid, CmdFrm->sutyp),
126                CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode),
127                CmdFrm->opcode, CmdFrm->length);
128         if (avc_comm_debug > 1) {
129                 for(k = 0; k < CmdFrm->length - 3; k++) {
130                         if (k % 5 != 0)
131                                 printk(", ");
132                         else if (k != 0)
133                                 printk("\n");
134                         printk(KERN_INFO "operand[%d] = %02X", k,
135                                CmdFrm->operand[k]);
136                 }
137                 printk(KERN_INFO "\n");
138         }
139 }
140
141 static void log_response_frame(const AVCRspFrm *RspFrm)
142 {
143         int k;
144         printk(KERN_INFO "AV/C Response Frame:\n");
145         printk(KERN_INFO "Response=%s, Address=%s(0x%02X,0x%02X), "
146                "opcode=%s(0x%02X), length=%d\n", get_resp_string(RspFrm->resp),
147                get_subunit_address(RspFrm->suid, RspFrm->sutyp),
148                RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode),
149                RspFrm->opcode, RspFrm->length);
150         if (avc_comm_debug > 1) {
151                 for(k = 0; k < RspFrm->length - 3; k++) {
152                         if (k % 5 != 0)
153                                 printk(KERN_INFO ", ");
154                         else if (k != 0)
155                                 printk(KERN_INFO "\n");
156                         printk(KERN_INFO "operand[%d] = %02X", k,
157                                RspFrm->operand[k]);
158                 }
159                 printk(KERN_INFO "\n");
160         }
161 }
162
163 static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm,
164                       AVCRspFrm *RspFrm) {
165         struct hpsb_packet *packet;
166         struct node_entry *ne;
167         int num_tries = 0;
168         int packet_ok = 0;
169
170         ne = firesat->nodeentry;
171         if(!ne) {
172                 printk(KERN_ERR "%s: lost node!\n",__func__);
173                 return -EIO;
174         }
175
176         /* need all input data */
177         if(!firesat || !ne || !CmdFrm) {
178                 printk(KERN_ERR "%s: missing input data!\n",__func__);
179                 return -EINVAL;
180         }
181
182         if (avc_comm_debug > 0) {
183                 log_command_frame(CmdFrm);
184         }
185
186         if(RspFrm)
187                 atomic_set(&firesat->avc_reply_received, 0);
188
189         while (packet_ok == 0 && num_tries < 6) {
190                 num_tries++;
191                 packet_ok = 1;
192                 packet = hpsb_make_writepacket(ne->host, ne->nodeid,
193                                                COMMAND_REGISTER,
194                                                (quadlet_t*)CmdFrm,
195                                                CmdFrm->length);
196                 hpsb_set_packet_complete_task(packet,
197                                               (void (*)(void*))avc_free_packet,
198                                               packet);
199                 hpsb_node_fill_packet(ne, packet);
200
201                 if (hpsb_send_packet(packet) < 0) {
202                         avc_free_packet(packet);
203                         atomic_set(&firesat->avc_reply_received, 1);
204                         printk(KERN_ERR "%s: send failed!\n",__func__);
205                         return -EIO;
206                 }
207
208                 if(RspFrm) {
209                         // AV/C specs say that answers should be send within
210                         // 150 ms so let's time out after 200 ms
211                         if (wait_event_timeout(firesat->avc_wait,
212                                                atomic_read(&firesat->avc_reply_received) == 1,
213                                                HZ / 5) == 0) {
214                                 packet_ok = 0;
215                         }
216                         else {
217                                 memcpy(RspFrm, firesat->respfrm,
218                                        firesat->resp_length);
219                                 RspFrm->length = firesat->resp_length;
220                                 if (avc_comm_debug > 0) {
221                                         log_response_frame(RspFrm);
222                                 }
223                         }
224                 }
225         }
226         if (packet_ok == 0) {
227                 printk(KERN_ERR "%s: AV/C response timed out 6 times.\n",
228                        __func__);
229                 return -ETIMEDOUT;
230         }
231
232         return 0;
233 }
234
235 int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) {
236         int ret;
237         if(down_interruptible(&firesat->avc_sem))
238                 return -EINTR;
239
240         ret = __AVCWrite(firesat, CmdFrm, RspFrm);
241
242         up(&firesat->avc_sem);
243         return ret;
244 }
245
246 static void do_schedule_remotecontrol(unsigned long ignored);
247 DECLARE_TASKLET(schedule_remotecontrol, do_schedule_remotecontrol, 0);
248
249 static void do_schedule_remotecontrol(unsigned long ignored) {
250         struct firesat *firesat;
251         unsigned long flags;
252
253         spin_lock_irqsave(&firesat_list_lock, flags);
254         list_for_each_entry(firesat,&firesat_list,list) {
255                 if(atomic_read(&firesat->reschedule_remotecontrol) == 1) {
256                         if(down_trylock(&firesat->avc_sem))
257                                 tasklet_schedule(&schedule_remotecontrol);
258                         else {
259                                 if(__AVCRegisterRemoteControl(firesat, 1) == 0)
260                                         atomic_set(&firesat->reschedule_remotecontrol, 0);
261                                 else
262                                         tasklet_schedule(&schedule_remotecontrol);
263
264                                 up(&firesat->avc_sem);
265                         }
266                 }
267         }
268         spin_unlock_irqrestore(&firesat_list_lock, flags);
269 }
270
271 int AVCRecv(struct firesat *firesat, u8 *data, size_t length) {
272 //      printk(KERN_INFO "%s\n",__func__);
273
274         // remote control handling
275
276 #if 0
277         AVCRspFrm *RspFrm = (AVCRspFrm*)data;
278
279         if(/*RspFrm->length >= 8 && ###*/
280                         ((RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
281                         RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
282                         RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2)) &&
283                         RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
284                 if(RspFrm->resp == CHANGED) {
285 //                      printk(KERN_INFO "%s: code = %02x %02x\n",__func__,RspFrm->operand[4],RspFrm->operand[5]);
286                         firesat_got_remotecontrolcode((((u16)RspFrm->operand[4]) << 8) | ((u16)RspFrm->operand[5]));
287
288                         // schedule
289                         atomic_set(&firesat->reschedule_remotecontrol, 1);
290                         tasklet_schedule(&schedule_remotecontrol);
291                 } else if(RspFrm->resp != INTERIM)
292                         printk(KERN_INFO "%s: remote control result = %d\n",__func__, RspFrm->resp);
293                 return 0;
294         }
295 #endif
296         if(atomic_read(&firesat->avc_reply_received) == 1) {
297                 printk(KERN_ERR "%s: received out-of-order AVC response, "
298                        "ignored\n",__func__);
299                 return -EINVAL;
300         }
301 //      AVCRspFrm *resp=(AVCRspFrm *)data;
302 //      int k;
303
304 //      printk(KERN_INFO "resp=0x%x\n",resp->resp);
305 //      printk(KERN_INFO "cts=0x%x\n",resp->cts);
306 //      printk(KERN_INFO "suid=0x%x\n",resp->suid);
307 //      printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp);
308 //      printk(KERN_INFO "opcode=0x%x\n",resp->opcode);
309 //      printk(KERN_INFO "length=%d\n",resp->length);
310
311 //      for(k=0;k<2;k++)
312 //              printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]);
313
314         memcpy(firesat->respfrm,data,length);
315         firesat->resp_length=length;
316
317         atomic_set(&firesat->avc_reply_received, 1);
318         wake_up(&firesat->avc_wait);
319
320         return 0;
321 }
322
323 // tuning command for setting the relative LNB frequency (not supported by the AVC standard)
324 static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) {
325
326         memset(CmdFrm, 0, sizeof(AVCCmdFrm));
327
328         CmdFrm->cts = AVC;
329         CmdFrm->ctype = CONTROL;
330         CmdFrm->sutyp = 0x5;
331         CmdFrm->suid = firesat->subunit;
332         CmdFrm->opcode = VENDOR;
333
334         CmdFrm->operand[0]=SFE_VENDOR_DE_COMPANYID_0;
335         CmdFrm->operand[1]=SFE_VENDOR_DE_COMPANYID_1;
336         CmdFrm->operand[2]=SFE_VENDOR_DE_COMPANYID_2;
337         CmdFrm->operand[3]=SFE_VENDOR_OPCODE_TUNE_QPSK;
338
339         printk(KERN_INFO "%s: tuning to frequency %u\n",__func__,params->frequency);
340
341         CmdFrm->operand[4] = (params->frequency >> 24) & 0xFF;
342         CmdFrm->operand[5] = (params->frequency >> 16) & 0xFF;
343         CmdFrm->operand[6] = (params->frequency >> 8) & 0xFF;
344         CmdFrm->operand[7] = params->frequency & 0xFF;
345
346         printk(KERN_INFO "%s: symbol rate = %uBd\n",__func__,params->u.qpsk.symbol_rate);
347
348         CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate/1000) >> 8) & 0xFF;
349         CmdFrm->operand[9] = (params->u.qpsk.symbol_rate/1000) & 0xFF;
350
351         switch(params->u.qpsk.fec_inner) {
352         case FEC_1_2:
353                 CmdFrm->operand[10] = 0x1;
354                 break;
355         case FEC_2_3:
356                 CmdFrm->operand[10] = 0x2;
357                 break;
358         case FEC_3_4:
359                 CmdFrm->operand[10] = 0x3;
360                 break;
361         case FEC_5_6:
362                 CmdFrm->operand[10] = 0x4;
363                 break;
364         case FEC_7_8:
365                 CmdFrm->operand[10] = 0x5;
366                 break;
367         case FEC_4_5:
368         case FEC_8_9:
369         case FEC_AUTO:
370         default:
371                 CmdFrm->operand[10] = 0x0;
372         }
373
374         if(firesat->voltage == 0xff)
375                 CmdFrm->operand[11] = 0xff;
376         else
377                 CmdFrm->operand[11] = (firesat->voltage==SEC_VOLTAGE_18)?0:1; // polarisation
378         if(firesat->tone == 0xff)
379                 CmdFrm->operand[12] = 0xff;
380         else
381                 CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band
382
383         if (firesat->type == FireSAT_DVB_S2) {
384                 CmdFrm->operand[13] = 0x1;
385                 CmdFrm->operand[14] = 0xFF;
386                 CmdFrm->operand[15] = 0xFF;
387         }
388
389         CmdFrm->length = 16;
390 }
391
392 int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) {
393         AVCCmdFrm CmdFrm;
394         AVCRspFrm RspFrm;
395         M_VALID_FLAGS flags;
396         int k;
397
398 //      printk(KERN_INFO "%s\n", __func__);
399
400         if (firesat->type == FireSAT_DVB_S || firesat->type == FireSAT_DVB_S2)
401                 AVCTuner_tuneQPSK(firesat, params, &CmdFrm);
402         else {
403                 if(firesat->type == FireSAT_DVB_T) {
404                         flags.Bits_T.GuardInterval = (params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO);
405                         flags.Bits_T.CodeRateLPStream = (params->u.ofdm.code_rate_LP != FEC_AUTO);
406                         flags.Bits_T.CodeRateHPStream = (params->u.ofdm.code_rate_HP != FEC_AUTO);
407                         flags.Bits_T.HierarchyInfo = (params->u.ofdm.hierarchy_information != HIERARCHY_AUTO);
408                         flags.Bits_T.Constellation = (params->u.ofdm.constellation != QAM_AUTO);
409                         flags.Bits_T.Bandwidth = (params->u.ofdm.bandwidth != BANDWIDTH_AUTO);
410                         flags.Bits_T.CenterFrequency = 1;
411                         flags.Bits_T.reserved1 = 0;
412                         flags.Bits_T.reserved2 = 0;
413                         flags.Bits_T.OtherFrequencyFlag = 0;
414                         flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO);
415                         flags.Bits_T.NetworkId = 0;
416                 } else {
417                         flags.Bits.Modulation =
418                                 (params->u.qam.modulation != QAM_AUTO);
419                         flags.Bits.FEC_inner =
420                                 (params->u.qam.fec_inner != FEC_AUTO);
421                         flags.Bits.FEC_outer = 0;
422                         flags.Bits.Symbol_Rate = 1;
423                         flags.Bits.Frequency = 1;
424                         flags.Bits.Orbital_Pos = 0;
425                         flags.Bits.Polarisation = 0;
426                         flags.Bits.reserved_fields = 0;
427                         flags.Bits.reserved1 = 0;
428                         flags.Bits.Network_ID = 0;
429                 }
430
431                 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
432
433                 CmdFrm.cts      = AVC;
434                 CmdFrm.ctype    = CONTROL;
435                 CmdFrm.sutyp    = 0x5;
436                 CmdFrm.suid     = firesat->subunit;
437                 CmdFrm.opcode   = DSD;
438
439                 CmdFrm.operand[0]  = 0; // source plug
440                 CmdFrm.operand[1]  = 0xD2; // subfunction replace
441                 CmdFrm.operand[2]  = 0x20; // system id = DVB
442                 CmdFrm.operand[3]  = 0x00; // antenna number
443                 // system_specific_multiplex selection_length
444                 CmdFrm.operand[4]  = (firesat->type == FireSAT_DVB_T)?0x0c:0x11;
445                 CmdFrm.operand[5]  = flags.Valid_Word.ByteHi; // valid_flags [0]
446                 CmdFrm.operand[6]  = flags.Valid_Word.ByteLo; // valid_flags [1]
447
448                 if(firesat->type == FireSAT_DVB_T) {
449                         CmdFrm.operand[7]  = 0x0;
450                         CmdFrm.operand[8]  = (params->frequency/10) >> 24;
451                         CmdFrm.operand[9]  =
452                                 ((params->frequency/10) >> 16) & 0xFF;
453                         CmdFrm.operand[10] =
454                                 ((params->frequency/10) >>  8) & 0xFF;
455                         CmdFrm.operand[11] = (params->frequency/10) & 0xFF;
456                         switch(params->u.ofdm.bandwidth) {
457                         case BANDWIDTH_7_MHZ:
458                                 CmdFrm.operand[12] = 0x20;
459                                 break;
460                         case BANDWIDTH_8_MHZ:
461                         case BANDWIDTH_6_MHZ: // not defined by AVC spec
462                         case BANDWIDTH_AUTO:
463                         default:
464                                 CmdFrm.operand[12] = 0x00;
465                         }
466                         switch(params->u.ofdm.constellation) {
467                         case QAM_16:
468                                 CmdFrm.operand[13] = 1 << 6;
469                                 break;
470                         case QAM_64:
471                                 CmdFrm.operand[13] = 2 << 6;
472                                 break;
473                         case QPSK:
474                         default:
475                                 CmdFrm.operand[13] = 0x00;
476                         }
477                         switch(params->u.ofdm.hierarchy_information) {
478                         case HIERARCHY_1:
479                                 CmdFrm.operand[13] |= 1 << 3;
480                                 break;
481                         case HIERARCHY_2:
482                                 CmdFrm.operand[13] |= 2 << 3;
483                                 break;
484                         case HIERARCHY_4:
485                                 CmdFrm.operand[13] |= 3 << 3;
486                                 break;
487                         case HIERARCHY_AUTO:
488                         case HIERARCHY_NONE:
489                         default:
490                                 break;
491                         }
492                         switch(params->u.ofdm.code_rate_HP) {
493                         case FEC_2_3:
494                                 CmdFrm.operand[13] |= 1;
495                                 break;
496                         case FEC_3_4:
497                                 CmdFrm.operand[13] |= 2;
498                                 break;
499                         case FEC_5_6:
500                                 CmdFrm.operand[13] |= 3;
501                                 break;
502                         case FEC_7_8:
503                                 CmdFrm.operand[13] |= 4;
504                                 break;
505                         case FEC_1_2:
506                         default:
507                                 break;
508                         }
509                         switch(params->u.ofdm.code_rate_LP) {
510                         case FEC_2_3:
511                                 CmdFrm.operand[14] = 1 << 5;
512                                 break;
513                         case FEC_3_4:
514                                 CmdFrm.operand[14] = 2 << 5;
515                                 break;
516                         case FEC_5_6:
517                                 CmdFrm.operand[14] = 3 << 5;
518                                 break;
519                         case FEC_7_8:
520                                 CmdFrm.operand[14] = 4 << 5;
521                                 break;
522                         case FEC_1_2:
523                         default:
524                                 CmdFrm.operand[14] = 0x00;
525                                 break;
526                         }
527                         switch(params->u.ofdm.guard_interval) {
528                         case GUARD_INTERVAL_1_16:
529                                 CmdFrm.operand[14] |= 1 << 3;
530                                 break;
531                         case GUARD_INTERVAL_1_8:
532                                 CmdFrm.operand[14] |= 2 << 3;
533                                 break;
534                         case GUARD_INTERVAL_1_4:
535                                 CmdFrm.operand[14] |= 3 << 3;
536                                 break;
537                         case GUARD_INTERVAL_1_32:
538                         case GUARD_INTERVAL_AUTO:
539                         default:
540                                 break;
541                         }
542                         switch(params->u.ofdm.transmission_mode) {
543                         case TRANSMISSION_MODE_8K:
544                                 CmdFrm.operand[14] |= 1 << 1;
545                                 break;
546                         case TRANSMISSION_MODE_2K:
547                         case TRANSMISSION_MODE_AUTO:
548                         default:
549                                 break;
550                         }
551
552                         CmdFrm.operand[15] = 0x00; // network_ID[0]
553                         CmdFrm.operand[16] = 0x00; // network_ID[1]
554                         CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted
555
556                         CmdFrm.length = 24;
557                 } else {
558                         CmdFrm.operand[7]  = 0x00;
559                         CmdFrm.operand[8]  = 0x00;
560                         CmdFrm.operand[9]  = 0x00;
561                         CmdFrm.operand[10] = 0x00;
562
563                         CmdFrm.operand[11] =
564                                 (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6);
565                         CmdFrm.operand[12] =
566                                 ((params->frequency/4000) >> 8) & 0xFF;
567                         CmdFrm.operand[13] = (params->frequency/4000) & 0xFF;
568                         CmdFrm.operand[14] =
569                                 ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF;
570                         CmdFrm.operand[15] =
571                                 ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF;
572                         CmdFrm.operand[16] =
573                                 ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0;
574                         CmdFrm.operand[17] = 0x00;
575                         switch(params->u.qpsk.fec_inner) {
576                         case FEC_1_2:
577                                 CmdFrm.operand[18] = 0x1;
578                                 break;
579                         case FEC_2_3:
580                                 CmdFrm.operand[18] = 0x2;
581                                 break;
582                         case FEC_3_4:
583                                 CmdFrm.operand[18] = 0x3;
584                                 break;
585                         case FEC_5_6:
586                                 CmdFrm.operand[18] = 0x4;
587                                 break;
588                         case FEC_7_8:
589                                 CmdFrm.operand[18] = 0x5;
590                                 break;
591                         case FEC_8_9:
592                                 CmdFrm.operand[18] = 0x6;
593                                 break;
594                         case FEC_4_5:
595                                 CmdFrm.operand[18] = 0x8;
596                                 break;
597                         case FEC_AUTO:
598                         default:
599                                 CmdFrm.operand[18] = 0x0;
600                         }
601                         switch(params->u.qam.modulation) {
602                         case QAM_16:
603                                 CmdFrm.operand[19] = 0x08; // modulation
604                                 break;
605                         case QAM_32:
606                                 CmdFrm.operand[19] = 0x10; // modulation
607                                 break;
608                         case QAM_64:
609                                 CmdFrm.operand[19] = 0x18; // modulation
610                                 break;
611                         case QAM_128:
612                                 CmdFrm.operand[19] = 0x20; // modulation
613                                 break;
614                         case QAM_256:
615                                 CmdFrm.operand[19] = 0x28; // modulation
616                                 break;
617                         case QAM_AUTO:
618                         default:
619                                 CmdFrm.operand[19] = 0x00; // modulation
620                         }
621                         CmdFrm.operand[20] = 0x00;
622                         CmdFrm.operand[21] = 0x00;
623                         CmdFrm.operand[22] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted
624
625                         CmdFrm.length=28;
626                 }
627         } // AVCTuner_DSD_direct
628
629         if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
630                 return k;
631
632         mdelay(500);
633
634         if(status)
635                 *status=RspFrm.operand[2];
636         return 0;
637 }
638
639 int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[])
640 {
641         AVCCmdFrm CmdFrm;
642         AVCRspFrm RspFrm;
643         int pos,k;
644
645         if(pidc > 16 && pidc != 0xFF)
646                 return -EINVAL;
647
648         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
649
650         CmdFrm.cts      = AVC;
651         CmdFrm.ctype    = CONTROL;
652         CmdFrm.sutyp    = 0x5;
653         CmdFrm.suid     = firesat->subunit;
654         CmdFrm.opcode   = DSD;
655
656         CmdFrm.operand[0]  = 0; // source plug
657         CmdFrm.operand[1]  = 0xD2; // subfunction replace
658         CmdFrm.operand[2]  = 0x20; // system id = DVB
659         CmdFrm.operand[3]  = 0x00; // antenna number
660         CmdFrm.operand[4]  = 0x00; // system_specific_multiplex selection_length
661         CmdFrm.operand[5]  = pidc; // Nr_of_dsd_sel_specs
662
663         pos=6;
664         if(pidc != 0xFF) {
665                 for(k=0;k<pidc;k++) {
666                         CmdFrm.operand[pos++] = 0x13; // flowfunction relay
667                         CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID
668                         CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F;
669                         CmdFrm.operand[pos++] = pid[k] & 0xFF;
670                         CmdFrm.operand[pos++] = 0x00; // tableID
671                         CmdFrm.operand[pos++] = 0x00; // filter_length
672                 }
673         }
674
675         CmdFrm.length = pos+3;
676         if((pos+3)%4)
677                 CmdFrm.length += 4 - ((pos+3)%4);
678
679         if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
680                 return k;
681
682         mdelay(50);
683         return 0;
684 }
685
686 int AVCTuner_GetTS(struct firesat *firesat){
687         AVCCmdFrm CmdFrm;
688         AVCRspFrm RspFrm;
689         int k;
690
691         //printk(KERN_INFO "%s\n", __func__);
692
693         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
694
695         CmdFrm.cts              = AVC;
696         CmdFrm.ctype    = CONTROL;
697         CmdFrm.sutyp    = 0x5;
698         CmdFrm.suid             = firesat->subunit;
699         CmdFrm.opcode   = DSIT;
700
701         CmdFrm.operand[0]  = 0; // source plug
702         CmdFrm.operand[1]  = 0xD2; // subfunction replace
703         CmdFrm.operand[2]  = 0xFF; //status
704         CmdFrm.operand[3]  = 0x20; // system id = DVB
705         CmdFrm.operand[4]  = 0x00; // antenna number
706         CmdFrm.operand[5]  = 0x0;  // system_specific_search_flags
707         CmdFrm.operand[6]  = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length
708         CmdFrm.operand[7]  = 0x00; // valid_flags [0]
709         CmdFrm.operand[8]  = 0x00; // valid_flags [1]
710         CmdFrm.operand[7 + (firesat->type == FireSAT_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0)
711
712         CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28;
713
714         if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm)))
715                 return k;
716
717         mdelay(250);
718         return 0;
719 }
720
721 int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport) {
722         AVCCmdFrm CmdFrm;
723         AVCRspFrm RspFrm;
724
725         memset(&CmdFrm,0,sizeof(AVCCmdFrm));
726
727         CmdFrm.cts = AVC;
728         CmdFrm.ctype = CONTROL;
729         CmdFrm.sutyp = 0x5; // tuner
730         CmdFrm.suid = firesat->subunit;
731         CmdFrm.opcode = READ_DESCRIPTOR;
732
733         CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER;
734         CmdFrm.operand[1]=0xff;
735         CmdFrm.operand[2]=0x00;
736         CmdFrm.operand[3]=0x00; // length highbyte
737         CmdFrm.operand[4]=0x08; // length lowbyte
738         CmdFrm.operand[5]=0x00; // offset highbyte
739         CmdFrm.operand[6]=0x0d; // offset lowbyte
740
741         CmdFrm.length=12;
742
743         if(AVCWrite(firesat,&CmdFrm,&RspFrm)<0)
744                 return -EIO;
745
746         if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
747                 printk(KERN_ERR "%s: AVCWrite returned error code %d\n",
748                        __func__, RspFrm.resp);
749                 return -EINVAL;
750         }
751         if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) {
752                 printk(KERN_ERR "%s: Invalid response length\n", __func__);
753                 return -EINVAL;
754         }
755         if(systemId)
756                 *systemId = RspFrm.operand[7];
757         return 0;
758 }
759
760 int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info) {
761         AVCCmdFrm CmdFrm;
762         AVCRspFrm RspFrm;
763         int length;
764
765         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
766
767         CmdFrm.cts=AVC;
768         CmdFrm.ctype=CONTROL;
769         CmdFrm.sutyp=0x05; // tuner
770         CmdFrm.suid=firesat->subunit;
771         CmdFrm.opcode=READ_DESCRIPTOR;
772
773         CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS;
774         CmdFrm.operand[1]=0xff; //read_result_status
775         CmdFrm.operand[2]=0x00; // reserver
776         CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8;
777         CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF;
778         CmdFrm.operand[5]=0x00;
779         CmdFrm.operand[6]=0x00;
780         CmdFrm.length=12;
781         if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
782                 return -EIO;
783
784         if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
785                 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
786                        __func__, RspFrm.resp);
787                 return -EINVAL;
788         }
789
790         length = RspFrm.operand[9];
791         if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO))
792         {
793                 memcpy(antenna_input_info, &RspFrm.operand[10],
794                        sizeof(ANTENNA_INPUT_INFO));
795                 return 0;
796         }
797         printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned "
798                "from AVC\n", __func__, RspFrm.operand[1], length);
799         return -EINVAL;
800 }
801
802 int AVCLNBControl(struct firesat *firesat, char voltage, char burst,
803                   char conttone, char nrdiseq,
804                   struct dvb_diseqc_master_cmd *diseqcmd)
805 {
806         AVCCmdFrm CmdFrm;
807         AVCRspFrm RspFrm;
808         int i,j;
809
810         printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",
811                __func__, voltage, burst, conttone);
812
813         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
814
815         CmdFrm.cts=AVC;
816         CmdFrm.ctype=CONTROL;
817         CmdFrm.sutyp=0x05;
818         CmdFrm.suid=firesat->subunit;
819         CmdFrm.opcode=VENDOR;
820
821         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
822         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
823         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
824         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL;
825
826         CmdFrm.operand[4]=voltage;
827         CmdFrm.operand[5]=nrdiseq;
828
829         i=6;
830
831         for(j=0;j<nrdiseq;j++) {
832                 int k;
833                 printk(KERN_INFO "%s: diseq %d len %x\n",
834                        __func__, j, diseqcmd[j].msg_len);
835                 CmdFrm.operand[i++]=diseqcmd[j].msg_len;
836
837                 for(k=0;k<diseqcmd[j].msg_len;k++) {
838                         printk(KERN_INFO "%s: diseq %d msg[%d] = %x\n",
839                                __func__, j, k, diseqcmd[j].msg[k]);
840                         CmdFrm.operand[i++]=diseqcmd[j].msg[k];
841                 }
842         }
843
844         CmdFrm.operand[i++]=burst;
845         CmdFrm.operand[i++]=conttone;
846
847         CmdFrm.length=i+3;
848         if((i+3)%4)
849                 CmdFrm.length += 4 - ((i+3)%4);
850
851 /*      for(j=0;j<CmdFrm.length;j++)
852                 printk(KERN_INFO "%s: CmdFrm.operand[%d]=0x%x\n",__func__,j,CmdFrm.operand[j]);
853
854         printk(KERN_INFO "%s: cmdfrm.length = %u\n",__func__,CmdFrm.length);
855         */
856         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
857                 return -EIO;
858
859         if(RspFrm.resp != ACCEPTED) {
860                 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
861                        __func__, RspFrm.resp);
862                 return -EINVAL;
863         }
864
865         return 0;
866 }
867
868 int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount)
869 {
870         AVCCmdFrm CmdFrm;
871         AVCRspFrm RspFrm;
872
873         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
874
875         CmdFrm.cts = AVC;
876         CmdFrm.ctype = STATUS;
877         CmdFrm.sutyp = 0x1f;
878         CmdFrm.suid = 0x7;
879         CmdFrm.opcode = SUBUNIT_Info;
880
881         CmdFrm.operand[0] = 0x07;
882         CmdFrm.operand[1] = 0xff;
883         CmdFrm.operand[2] = 0xff;
884         CmdFrm.operand[3] = 0xff;
885         CmdFrm.operand[4] = 0xff;
886
887         CmdFrm.length = 8;
888
889         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
890                 return -EIO;
891
892         if(RspFrm.resp != STABLE) {
893                 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
894                        __func__, RspFrm.resp);
895                 return -EINVAL;
896         }
897
898         if(subunitcount)
899                 *subunitcount = (RspFrm.operand[1] & 0x7) + 1;
900
901         return 0;
902 }
903
904 static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal)
905 {
906         AVCCmdFrm CmdFrm;
907
908 //      printk(KERN_INFO "%s\n",__func__);
909
910         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
911
912         CmdFrm.cts = AVC;
913         CmdFrm.ctype = NOTIFY;
914         CmdFrm.sutyp = 0x1f;
915         CmdFrm.suid = 0x7;
916         CmdFrm.opcode = VENDOR;
917
918         CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0;
919         CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1;
920         CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2;
921         CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
922
923         CmdFrm.length = 8;
924
925         if(internal) {
926                 if(__AVCWrite(firesat,&CmdFrm,NULL) < 0)
927                         return -EIO;
928         } else
929                 if(AVCWrite(firesat,&CmdFrm,NULL) < 0)
930                         return -EIO;
931
932         return 0;
933 }
934
935 int AVCRegisterRemoteControl(struct firesat*firesat)
936 {
937         return __AVCRegisterRemoteControl(firesat, 0);
938 }
939
940 int AVCTuner_Host2Ca(struct firesat *firesat)
941 {
942
943         AVCCmdFrm CmdFrm;
944         AVCRspFrm RspFrm;
945
946         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
947         CmdFrm.cts = AVC;
948         CmdFrm.ctype = CONTROL;
949         CmdFrm.sutyp = 0x5;
950         CmdFrm.suid = firesat->subunit;
951         CmdFrm.opcode = VENDOR;
952
953         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
954         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
955         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
956         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
957         CmdFrm.operand[4] = 0; // slot
958         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
959         CmdFrm.operand[6] = 0; // more/last
960         CmdFrm.operand[7] = 0; // length
961         CmdFrm.length = 12;
962
963         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
964                 return -EIO;
965
966         return 0;
967 }
968
969 static int get_ca_object_pos(AVCRspFrm *RspFrm)
970 {
971         int length = 1;
972
973         // Check length of length field
974         if (RspFrm->operand[7] & 0x80)
975                 length = (RspFrm->operand[7] & 0x7F) + 1;
976         return length + 7;
977 }
978
979 static int get_ca_object_length(AVCRspFrm *RspFrm)
980 {
981         int size = 0;
982         int i;
983
984         if (RspFrm->operand[7] & 0x80) {
985                 for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) {
986                         size <<= 8;
987                         size += RspFrm->operand[8 + i];
988                 }
989         }
990         return RspFrm->operand[7];
991 }
992
993 int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length)
994 {
995         AVCCmdFrm CmdFrm;
996         AVCRspFrm RspFrm;
997         int pos;
998
999         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1000         CmdFrm.cts = AVC;
1001         CmdFrm.ctype = STATUS;
1002         CmdFrm.sutyp = 0x5;
1003         CmdFrm.suid = firesat->subunit;
1004         CmdFrm.opcode = VENDOR;
1005
1006         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1007         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1008         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1009         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1010         CmdFrm.operand[4] = 0; // slot
1011         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
1012         CmdFrm.length = 12;
1013
1014         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1015                 return -EIO;
1016
1017
1018         pos = get_ca_object_pos(&RspFrm);
1019         app_info[0] = (TAG_APP_INFO >> 16) & 0xFF;
1020         app_info[1] = (TAG_APP_INFO >> 8) & 0xFF;
1021         app_info[2] = (TAG_APP_INFO >> 0) & 0xFF;
1022         app_info[3] = 6 + RspFrm.operand[pos + 4];
1023         app_info[4] = 0x01;
1024         memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]);
1025         *length = app_info[3] + 4;
1026
1027         return 0;
1028 }
1029
1030 int avc_ca_info(struct firesat *firesat, char *app_info, int *length)
1031 {
1032         AVCCmdFrm CmdFrm;
1033         AVCRspFrm RspFrm;
1034         int pos;
1035
1036         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1037         CmdFrm.cts = AVC;
1038         CmdFrm.ctype = STATUS;
1039         CmdFrm.sutyp = 0x5;
1040         CmdFrm.suid = firesat->subunit;
1041         CmdFrm.opcode = VENDOR;
1042
1043         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1044         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1045         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1046         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1047         CmdFrm.operand[4] = 0; // slot
1048         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
1049         CmdFrm.length = 12;
1050
1051         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1052                 return -EIO;
1053
1054         pos = get_ca_object_pos(&RspFrm);
1055         app_info[0] = (TAG_CA_INFO >> 16) & 0xFF;
1056         app_info[1] = (TAG_CA_INFO >> 8) & 0xFF;
1057         app_info[2] = (TAG_CA_INFO >> 0) & 0xFF;
1058         app_info[3] = 2;
1059         app_info[4] = app_info[5];
1060         app_info[5] = app_info[6];
1061         *length = app_info[3] + 4;
1062
1063         return 0;
1064 }
1065
1066 int avc_ca_reset(struct firesat *firesat)
1067 {
1068         AVCCmdFrm CmdFrm;
1069         AVCRspFrm RspFrm;
1070
1071         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1072         CmdFrm.cts = AVC;
1073         CmdFrm.ctype = CONTROL;
1074         CmdFrm.sutyp = 0x5;
1075         CmdFrm.suid = firesat->subunit;
1076         CmdFrm.opcode = VENDOR;
1077
1078         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1079         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1080         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1081         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
1082         CmdFrm.operand[4] = 0; // slot
1083         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag
1084         CmdFrm.operand[6] = 0; // more/last
1085         CmdFrm.operand[7] = 1; // length
1086         CmdFrm.operand[8] = 0; // force hardware reset
1087         CmdFrm.length = 12;
1088
1089         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1090                 return -EIO;
1091
1092         return 0;
1093 }
1094
1095 int avc_ca_pmt(struct firesat *firesat, char *msg, int length)
1096 {
1097         AVCCmdFrm CmdFrm;
1098         AVCRspFrm RspFrm;
1099         int list_management;
1100         int program_info_length;
1101         int pmt_cmd_id;
1102         int read_pos;
1103         int write_pos;
1104         int es_info_length;
1105         int crc32_csum;
1106
1107         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1108         CmdFrm.cts = AVC;
1109         CmdFrm.ctype = CONTROL;
1110         CmdFrm.sutyp = 0x5;
1111         CmdFrm.suid = firesat->subunit;
1112         CmdFrm.opcode = VENDOR;
1113
1114         if (msg[0] != LIST_MANAGEMENT_ONLY) {
1115                 printk(KERN_INFO "%s: list_management %d not support. "
1116                        "Forcing list_management to \"only\" (3). \n",
1117                        __func__, msg[0]);
1118                 msg[0] = LIST_MANAGEMENT_ONLY;
1119         }
1120         // We take the cmd_id from the programme level only!
1121         list_management = msg[0];
1122         program_info_length = ((msg[4] & 0x0F) << 8) + msg[5];
1123         if (program_info_length > 0)
1124                 program_info_length--; // Remove pmt_cmd_id
1125         pmt_cmd_id = msg[6];
1126
1127         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1128         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1129         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1130         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
1131         CmdFrm.operand[4] = 0; // slot
1132         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag
1133         CmdFrm.operand[6] = 0; // more/last
1134         //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length
1135         CmdFrm.operand[8] = list_management;
1136         CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble
1137
1138         // TS program map table
1139
1140         // Table id=2
1141         CmdFrm.operand[10] = 0x02;
1142         // Section syntax + length
1143         CmdFrm.operand[11] = 0x80;
1144         //CmdFrm.operand[12] = XXXprogram_info_length + 12;
1145         // Program number
1146         CmdFrm.operand[13] = msg[1];
1147         CmdFrm.operand[14] = msg[2];
1148         // Version number=0 + current/next=1
1149         CmdFrm.operand[15] = 0x01;
1150         // Section number=0
1151         CmdFrm.operand[16] = 0x00;
1152         // Last section number=0
1153         CmdFrm.operand[17] = 0x00;
1154         // PCR_PID=1FFF
1155         CmdFrm.operand[18] = 0x1F;
1156         CmdFrm.operand[19] = 0xFF;
1157         // Program info length
1158         CmdFrm.operand[20] = (program_info_length >> 8);
1159         CmdFrm.operand[21] = (program_info_length & 0xFF);
1160         // CA descriptors at programme level
1161         read_pos = 6;
1162         write_pos = 22;
1163         if (program_info_length > 0) {
1164 /*              printk(KERN_INFO "Copying descriptors at programme level.\n"); */
1165                 pmt_cmd_id = msg[read_pos++];
1166                 if (pmt_cmd_id != 1 && pmt_cmd_id !=4) {
1167                         printk(KERN_ERR "Invalid pmt_cmd_id=%d.\n",
1168                                pmt_cmd_id);
1169                 }
1170                 memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
1171                        program_info_length);
1172                 read_pos += program_info_length;
1173                 write_pos += program_info_length;
1174         }
1175         while (read_pos < length) {
1176 /*              printk(KERN_INFO "Copying descriptors at stream level for " */
1177 /*                     "stream type %d.\n", msg[read_pos]); */
1178                 CmdFrm.operand[write_pos++] = msg[read_pos++];
1179                 CmdFrm.operand[write_pos++] = msg[read_pos++];
1180                 CmdFrm.operand[write_pos++] = msg[read_pos++];
1181                 es_info_length =
1182                         ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1];
1183                 read_pos += 2;
1184                 if (es_info_length > 0)
1185                         es_info_length--; // Remove pmt_cmd_id
1186                 CmdFrm.operand[write_pos++] = es_info_length >> 8;
1187                 CmdFrm.operand[write_pos++] = es_info_length & 0xFF;
1188                 if (es_info_length > 0) {
1189                         pmt_cmd_id = msg[read_pos++];
1190                         if (pmt_cmd_id != 1 && pmt_cmd_id !=4) {
1191                                 printk(KERN_ERR "Invalid pmt_cmd_id=%d at "
1192                                        "stream level.\n", pmt_cmd_id);
1193                         }
1194                         memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
1195                                es_info_length);
1196                         read_pos += es_info_length;
1197                         write_pos += es_info_length;
1198                 }
1199         }
1200
1201         // CRC
1202         CmdFrm.operand[write_pos++] = 0x00;
1203         CmdFrm.operand[write_pos++] = 0x00;
1204         CmdFrm.operand[write_pos++] = 0x00;
1205         CmdFrm.operand[write_pos++] = 0x00;
1206
1207         CmdFrm.operand[7] = write_pos - 8;
1208         CmdFrm.operand[12] = write_pos - 13;
1209
1210         crc32_csum = crc32_be(0, &CmdFrm.operand[10],
1211                            CmdFrm.operand[12] - 1);
1212         CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF;
1213         CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF;
1214         CmdFrm.operand[write_pos - 2] = (crc32_csum >>  8) & 0xFF;
1215         CmdFrm.operand[write_pos - 1] = (crc32_csum >>  0) & 0xFF;
1216
1217         CmdFrm.length = write_pos + 3;
1218         if ((write_pos + 3) % 4)
1219                 CmdFrm.length += 4 - ((write_pos + 3) % 4);
1220
1221         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1222                 return -EIO;
1223
1224         if (RspFrm.resp != ACCEPTED) {
1225                 printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp);
1226                 return -EFAULT;
1227         }
1228
1229         return 0;
1230
1231 }
1232
1233 int avc_ca_get_time_date(struct firesat *firesat, int *interval)
1234 {
1235         AVCCmdFrm CmdFrm;
1236         AVCRspFrm RspFrm;
1237
1238         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1239         CmdFrm.cts = AVC;
1240         CmdFrm.ctype = STATUS;
1241         CmdFrm.sutyp = 0x5;
1242         CmdFrm.suid = firesat->subunit;
1243         CmdFrm.opcode = VENDOR;
1244
1245         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1246         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1247         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1248         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1249         CmdFrm.operand[4] = 0; // slot
1250         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag
1251         CmdFrm.operand[6] = 0; // more/last
1252         CmdFrm.operand[7] = 0; // length
1253         CmdFrm.length = 12;
1254
1255         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1256                 return -EIO;
1257
1258         *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)];
1259
1260         return 0;
1261 }
1262
1263 int avc_ca_enter_menu(struct firesat *firesat)
1264 {
1265         AVCCmdFrm CmdFrm;
1266         AVCRspFrm RspFrm;
1267
1268         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1269         CmdFrm.cts = AVC;
1270         CmdFrm.ctype = STATUS;
1271         CmdFrm.sutyp = 0x5;
1272         CmdFrm.suid = firesat->subunit;
1273         CmdFrm.opcode = VENDOR;
1274
1275         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1276         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1277         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1278         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
1279         CmdFrm.operand[4] = 0; // slot
1280         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
1281         CmdFrm.operand[6] = 0; // more/last
1282         CmdFrm.operand[7] = 0; // length
1283         CmdFrm.length = 12;
1284
1285         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1286                 return -EIO;
1287
1288         return 0;
1289 }
1290
1291 int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length)
1292 {
1293         AVCCmdFrm CmdFrm;
1294         AVCRspFrm RspFrm;
1295
1296         memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1297         CmdFrm.cts = AVC;
1298         CmdFrm.ctype = STATUS;
1299         CmdFrm.sutyp = 0x5;
1300         CmdFrm.suid = firesat->subunit;
1301         CmdFrm.opcode = VENDOR;
1302
1303         CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
1304         CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
1305         CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
1306         CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
1307         CmdFrm.operand[4] = 0; // slot
1308         CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI;
1309         CmdFrm.operand[6] = 0; // more/last
1310         CmdFrm.operand[7] = 0; // length
1311         CmdFrm.length = 12;
1312
1313         if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1314                 return -EIO;
1315
1316         *length = get_ca_object_length(&RspFrm);
1317         memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length);
1318
1319         return 0;
1320 }