2 * FireDTV driver (formerly known as FireSAT)
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>
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.
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>
23 #include <ieee1394_transactions.h>
28 #include "firesat-rc.h"
30 #define RESPONSE_REGISTER 0xFFFFF0000D00ULL
31 #define COMMAND_REGISTER 0xFFFFF0000B00ULL
32 #define PCR_BASE_ADDRESS 0xFFFFF0000900ULL
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)");
38 /* Frees an allocated packet */
39 static void avc_free_packet(struct hpsb_packet *packet)
41 hpsb_free_tlabel(packet);
42 hpsb_free_packet(packet);
45 static const char* get_ctype_string(__u8 ctype)
54 return "SPECIFIC_INQUIRY";
58 return "GENERAL_INQUIRY";
63 static const char* get_resp_string(__u8 ctype)
68 return "NOT_IMPLEMENTED";
74 return "IN_TRANSITION";
76 return "IMPLEMENTED_STABLE";
85 static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type)
87 if (subunit_id == 7 && subunit_type == 0x1F)
89 if (subunit_id == 0 && subunit_type == 0x05)
94 static const char* get_opcode_string(__u8 opcode)
101 return "OpenDescriptor";
103 return "ReadDescriptor";
105 return "OutputPlugSignalFormat";
107 return "SubunitInfo";
113 return "DirectSelectInformationType";
115 return "DirectSelectData";
123 static void log_command_frame(const AVCCmdFrm *CmdFrm)
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++) {
139 printk(KERN_INFO "operand[%d] = %02X", k,
142 printk(KERN_INFO "\n");
146 static void log_response_frame(const AVCRspFrm *RspFrm)
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++) {
158 printk(KERN_INFO ", ");
160 printk(KERN_INFO "\n");
161 printk(KERN_INFO "operand[%d] = %02X", k,
164 printk(KERN_INFO "\n");
168 static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm,
170 struct hpsb_packet *packet;
171 struct node_entry *ne;
175 ne = firesat->nodeentry;
177 printk(KERN_ERR "%s: lost node!\n",__func__);
181 /* need all input data */
182 if(!firesat || !ne || !CmdFrm) {
183 printk(KERN_ERR "%s: missing input data!\n",__func__);
187 if (avc_comm_debug > 0) {
188 log_command_frame(CmdFrm);
192 atomic_set(&firesat->avc_reply_received, 0);
194 while (packet_ok == 0 && num_tries < 6) {
197 packet = hpsb_make_writepacket(ne->host, ne->nodeid,
201 hpsb_set_packet_complete_task(packet,
202 (void (*)(void*))avc_free_packet,
204 hpsb_node_fill_packet(ne, packet);
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__);
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,
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);
231 if (packet_ok == 0) {
232 printk(KERN_ERR "%s: AV/C response timed out 6 times.\n",
240 int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm)
244 if (mutex_lock_interruptible(&firesat->avc_mutex))
247 ret = __AVCWrite(firesat, CmdFrm, RspFrm);
249 mutex_unlock(&firesat->avc_mutex);
253 int AVCRecv(struct firesat *firesat, u8 *data, size_t length)
255 AVCRspFrm *RspFrm = (AVCRspFrm *)data;
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 |
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);
273 if(atomic_read(&firesat->avc_reply_received) == 1) {
274 printk(KERN_ERR "%s: received out-of-order AVC response, "
275 "ignored\n",__func__);
278 // AVCRspFrm *resp=(AVCRspFrm *)data;
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);
289 // printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]);
291 memcpy(firesat->respfrm,data,length);
292 firesat->resp_length=length;
294 atomic_set(&firesat->avc_reply_received, 1);
295 wake_up(&firesat->avc_wait);
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) {
303 memset(CmdFrm, 0, sizeof(AVCCmdFrm));
306 CmdFrm->ctype = CONTROL;
308 CmdFrm->suid = firesat->subunit;
309 CmdFrm->opcode = VENDOR;
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;
316 printk(KERN_INFO "%s: tuning to frequency %u\n",__func__,params->frequency);
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;
323 printk(KERN_INFO "%s: symbol rate = %uBd\n",__func__,params->u.qpsk.symbol_rate);
325 CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate/1000) >> 8) & 0xFF;
326 CmdFrm->operand[9] = (params->u.qpsk.symbol_rate/1000) & 0xFF;
328 switch(params->u.qpsk.fec_inner) {
330 CmdFrm->operand[10] = 0x1;
333 CmdFrm->operand[10] = 0x2;
336 CmdFrm->operand[10] = 0x3;
339 CmdFrm->operand[10] = 0x4;
342 CmdFrm->operand[10] = 0x5;
348 CmdFrm->operand[10] = 0x0;
351 if(firesat->voltage == 0xff)
352 CmdFrm->operand[11] = 0xff;
354 CmdFrm->operand[11] = (firesat->voltage==SEC_VOLTAGE_18)?0:1; // polarisation
355 if(firesat->tone == 0xff)
356 CmdFrm->operand[12] = 0xff;
358 CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band
360 if (firesat->type == FireSAT_DVB_S2) {
361 CmdFrm->operand[13] = 0x1;
362 CmdFrm->operand[14] = 0xFF;
363 CmdFrm->operand[15] = 0xFF;
369 int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) {
375 // printk(KERN_INFO "%s\n", __func__);
377 if (firesat->type == FireSAT_DVB_S || firesat->type == FireSAT_DVB_S2)
378 AVCTuner_tuneQPSK(firesat, params, &CmdFrm);
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;
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;
408 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
411 CmdFrm.ctype = CONTROL;
413 CmdFrm.suid = firesat->subunit;
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]
425 if(firesat->type == FireSAT_DVB_T) {
426 CmdFrm.operand[7] = 0x0;
427 CmdFrm.operand[8] = (params->frequency/10) >> 24;
429 ((params->frequency/10) >> 16) & 0xFF;
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;
437 case BANDWIDTH_8_MHZ:
438 case BANDWIDTH_6_MHZ: // not defined by AVC spec
441 CmdFrm.operand[12] = 0x00;
443 switch(params->u.ofdm.constellation) {
445 CmdFrm.operand[13] = 1 << 6;
448 CmdFrm.operand[13] = 2 << 6;
452 CmdFrm.operand[13] = 0x00;
454 switch(params->u.ofdm.hierarchy_information) {
456 CmdFrm.operand[13] |= 1 << 3;
459 CmdFrm.operand[13] |= 2 << 3;
462 CmdFrm.operand[13] |= 3 << 3;
469 switch(params->u.ofdm.code_rate_HP) {
471 CmdFrm.operand[13] |= 1;
474 CmdFrm.operand[13] |= 2;
477 CmdFrm.operand[13] |= 3;
480 CmdFrm.operand[13] |= 4;
486 switch(params->u.ofdm.code_rate_LP) {
488 CmdFrm.operand[14] = 1 << 5;
491 CmdFrm.operand[14] = 2 << 5;
494 CmdFrm.operand[14] = 3 << 5;
497 CmdFrm.operand[14] = 4 << 5;
501 CmdFrm.operand[14] = 0x00;
504 switch(params->u.ofdm.guard_interval) {
505 case GUARD_INTERVAL_1_16:
506 CmdFrm.operand[14] |= 1 << 3;
508 case GUARD_INTERVAL_1_8:
509 CmdFrm.operand[14] |= 2 << 3;
511 case GUARD_INTERVAL_1_4:
512 CmdFrm.operand[14] |= 3 << 3;
514 case GUARD_INTERVAL_1_32:
515 case GUARD_INTERVAL_AUTO:
519 switch(params->u.ofdm.transmission_mode) {
520 case TRANSMISSION_MODE_8K:
521 CmdFrm.operand[14] |= 1 << 1;
523 case TRANSMISSION_MODE_2K:
524 case TRANSMISSION_MODE_AUTO:
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
535 CmdFrm.operand[7] = 0x00;
536 CmdFrm.operand[8] = 0x00;
537 CmdFrm.operand[9] = 0x00;
538 CmdFrm.operand[10] = 0x00;
541 (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6);
543 ((params->frequency/4000) >> 8) & 0xFF;
544 CmdFrm.operand[13] = (params->frequency/4000) & 0xFF;
546 ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF;
548 ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF;
550 ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0;
551 CmdFrm.operand[17] = 0x00;
552 switch(params->u.qpsk.fec_inner) {
554 CmdFrm.operand[18] = 0x1;
557 CmdFrm.operand[18] = 0x2;
560 CmdFrm.operand[18] = 0x3;
563 CmdFrm.operand[18] = 0x4;
566 CmdFrm.operand[18] = 0x5;
569 CmdFrm.operand[18] = 0x6;
572 CmdFrm.operand[18] = 0x8;
576 CmdFrm.operand[18] = 0x0;
578 switch(params->u.qam.modulation) {
580 CmdFrm.operand[19] = 0x08; // modulation
583 CmdFrm.operand[19] = 0x10; // modulation
586 CmdFrm.operand[19] = 0x18; // modulation
589 CmdFrm.operand[19] = 0x20; // modulation
592 CmdFrm.operand[19] = 0x28; // modulation
596 CmdFrm.operand[19] = 0x00; // modulation
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
604 } // AVCTuner_DSD_direct
606 if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
612 *status=RspFrm.operand[2];
616 int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[])
622 if(pidc > 16 && pidc != 0xFF)
625 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
628 CmdFrm.ctype = CONTROL;
630 CmdFrm.suid = firesat->subunit;
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
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
652 CmdFrm.length = pos+3;
654 CmdFrm.length += 4 - ((pos+3)%4);
656 if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
663 int AVCTuner_GetTS(struct firesat *firesat){
668 //printk(KERN_INFO "%s\n", __func__);
670 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
673 CmdFrm.ctype = CONTROL;
675 CmdFrm.suid = firesat->subunit;
676 CmdFrm.opcode = DSIT;
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)
689 CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28;
691 if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm)))
698 int AVCIdentifySubunit(struct firesat *firesat)
703 memset(&CmdFrm,0,sizeof(AVCCmdFrm));
706 CmdFrm.ctype = CONTROL;
707 CmdFrm.sutyp = 0x5; // tuner
708 CmdFrm.suid = firesat->subunit;
709 CmdFrm.opcode = READ_DESCRIPTOR;
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
721 if(AVCWrite(firesat,&CmdFrm,&RspFrm)<0)
724 if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
725 printk(KERN_ERR "%s: AVCWrite returned error code %d\n",
726 __func__, RspFrm.resp);
729 if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) {
730 printk(KERN_ERR "%s: Invalid response length\n", __func__);
736 int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info) {
741 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
744 CmdFrm.ctype=CONTROL;
745 CmdFrm.sutyp=0x05; // tuner
746 CmdFrm.suid=firesat->subunit;
747 CmdFrm.opcode=READ_DESCRIPTOR;
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;
757 if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
760 if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
761 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
762 __func__, RspFrm.resp);
766 length = RspFrm.operand[9];
767 if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO))
769 memcpy(antenna_input_info, &RspFrm.operand[10],
770 sizeof(ANTENNA_INPUT_INFO));
773 printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned "
774 "from AVC\n", __func__, RspFrm.operand[1], length);
778 int AVCLNBControl(struct firesat *firesat, char voltage, char burst,
779 char conttone, char nrdiseq,
780 struct dvb_diseqc_master_cmd *diseqcmd)
786 printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",
787 __func__, voltage, burst, conttone);
789 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
792 CmdFrm.ctype=CONTROL;
794 CmdFrm.suid=firesat->subunit;
795 CmdFrm.opcode=VENDOR;
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;
802 CmdFrm.operand[4]=voltage;
803 CmdFrm.operand[5]=nrdiseq;
807 for(j=0;j<nrdiseq;j++) {
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;
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];
820 CmdFrm.operand[i++]=burst;
821 CmdFrm.operand[i++]=conttone;
825 CmdFrm.length += 4 - ((i+3)%4);
827 /* for(j=0;j<CmdFrm.length;j++)
828 printk(KERN_INFO "%s: CmdFrm.operand[%d]=0x%x\n",__func__,j,CmdFrm.operand[j]);
830 printk(KERN_INFO "%s: cmdfrm.length = %u\n",__func__,CmdFrm.length);
832 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
835 if(RspFrm.resp != ACCEPTED) {
836 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
837 __func__, RspFrm.resp);
844 int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount)
849 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
852 CmdFrm.ctype = STATUS;
855 CmdFrm.opcode = SUBUNIT_Info;
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;
865 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
868 if(RspFrm.resp != STABLE) {
869 printk(KERN_ERR "%s: AVCWrite returned code %d\n",
870 __func__, RspFrm.resp);
875 *subunitcount = (RspFrm.operand[1] & 0x7) + 1;
880 int AVCRegisterRemoteControl(struct firesat *firesat)
884 // printk(KERN_INFO "%s\n",__func__);
886 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
889 CmdFrm.ctype = NOTIFY;
892 CmdFrm.opcode = VENDOR;
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;
901 return AVCWrite(firesat, &CmdFrm, NULL);
904 void avc_remote_ctrl_work(struct work_struct *work)
906 struct firesat *firesat =
907 container_of(work, struct firesat, remote_ctrl_work);
909 /* Should it be rescheduled in failure cases? */
910 AVCRegisterRemoteControl(firesat);
913 int AVCTuner_Host2Ca(struct firesat *firesat)
919 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
921 CmdFrm.ctype = CONTROL;
923 CmdFrm.suid = firesat->subunit;
924 CmdFrm.opcode = VENDOR;
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
936 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
942 static int get_ca_object_pos(AVCRspFrm *RspFrm)
946 // Check length of length field
947 if (RspFrm->operand[7] & 0x80)
948 length = (RspFrm->operand[7] & 0x7F) + 1;
952 static int get_ca_object_length(AVCRspFrm *RspFrm)
957 if (RspFrm->operand[7] & 0x80) {
958 for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) {
960 size += RspFrm->operand[8 + i];
963 return RspFrm->operand[7];
966 int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length)
972 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
974 CmdFrm.ctype = STATUS;
976 CmdFrm.suid = firesat->subunit;
977 CmdFrm.opcode = VENDOR;
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
987 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
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];
997 memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]);
998 *length = app_info[3] + 4;
1003 int avc_ca_info(struct firesat *firesat, char *app_info, int *length)
1009 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1011 CmdFrm.ctype = STATUS;
1013 CmdFrm.suid = firesat->subunit;
1014 CmdFrm.opcode = VENDOR;
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
1024 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
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;
1032 app_info[4] = app_info[5];
1033 app_info[5] = app_info[6];
1034 *length = app_info[3] + 4;
1039 int avc_ca_reset(struct firesat *firesat)
1044 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1046 CmdFrm.ctype = CONTROL;
1048 CmdFrm.suid = firesat->subunit;
1049 CmdFrm.opcode = VENDOR;
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
1062 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1068 int avc_ca_pmt(struct firesat *firesat, char *msg, int length)
1072 int list_management;
1073 int program_info_length;
1080 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1082 CmdFrm.ctype = CONTROL;
1084 CmdFrm.suid = firesat->subunit;
1085 CmdFrm.opcode = VENDOR;
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",
1091 msg[0] = LIST_MANAGEMENT_ONLY;
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];
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
1111 // TS program map table
1114 CmdFrm.operand[10] = 0x02;
1115 // Section syntax + length
1116 CmdFrm.operand[11] = 0x80;
1117 //CmdFrm.operand[12] = XXXprogram_info_length + 12;
1119 CmdFrm.operand[13] = msg[1];
1120 CmdFrm.operand[14] = msg[2];
1121 // Version number=0 + current/next=1
1122 CmdFrm.operand[15] = 0x01;
1124 CmdFrm.operand[16] = 0x00;
1125 // Last section number=0
1126 CmdFrm.operand[17] = 0x00;
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
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",
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;
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++];
1155 ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1];
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);
1167 memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
1169 read_pos += es_info_length;
1170 write_pos += es_info_length;
1175 CmdFrm.operand[write_pos++] = 0x00;
1176 CmdFrm.operand[write_pos++] = 0x00;
1177 CmdFrm.operand[write_pos++] = 0x00;
1178 CmdFrm.operand[write_pos++] = 0x00;
1180 CmdFrm.operand[7] = write_pos - 8;
1181 CmdFrm.operand[12] = write_pos - 13;
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;
1190 CmdFrm.length = write_pos + 3;
1191 if ((write_pos + 3) % 4)
1192 CmdFrm.length += 4 - ((write_pos + 3) % 4);
1194 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1197 if (RspFrm.resp != ACCEPTED) {
1198 printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp);
1206 int avc_ca_get_time_date(struct firesat *firesat, int *interval)
1211 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1213 CmdFrm.ctype = STATUS;
1215 CmdFrm.suid = firesat->subunit;
1216 CmdFrm.opcode = VENDOR;
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
1228 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1231 *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)];
1236 int avc_ca_enter_menu(struct firesat *firesat)
1241 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1243 CmdFrm.ctype = STATUS;
1245 CmdFrm.suid = firesat->subunit;
1246 CmdFrm.opcode = VENDOR;
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
1258 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1264 int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length)
1269 memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
1271 CmdFrm.ctype = STATUS;
1273 CmdFrm.suid = firesat->subunit;
1274 CmdFrm.opcode = VENDOR;
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
1286 if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
1289 *length = get_ca_object_length(&RspFrm);
1290 memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length);