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