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