firesat: update isochronous interface, add CI support
authorHenrik Kurelid <henke@kurelid.se>
Fri, 1 Aug 2008 08:00:45 +0000 (10:00 +0200)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Tue, 24 Feb 2009 13:51:26 +0000 (14:51 +0100)
I have finally managed to get the CI support for the card working. The
implementation is a bare minimum to get encrypted channels to work in
kaffeine. It works fine with my T/CI card. Now and then I get an AVC
timeout and have to retune a channel in order to get it to work. Once
the CAM seemed to hang so I needed to remove and insert it again. I.e.
there are a number of glitches.

The latest version contains the following changes:

  - Implemented the new hpsb iso interface so that data can be received
    from the card
  - Reduced some timers for demux setup which caused scanning to timeout
  - Added possibility to unload driver
  - Added support for getting C/N ratio
  - Added two debug parameters to the driver; ca_debug and
    avc_comm_debug.
  - Added CI support that works for me in kaffeine
  - Started working on CI MMI support. It now supports:
      o Enter menu
      o Receiving MMI objects
  - Added support for 64-bit platforms
  - Corrected DVB-C modulations problems

Signed-off-by: Henrik Kurelid <henrik@kurelid.se>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (rebased, whitespace)
drivers/media/dvb/firesat/Makefile
drivers/media/dvb/firesat/avc_api.c
drivers/media/dvb/firesat/avc_api.h
drivers/media/dvb/firesat/cmp.c
drivers/media/dvb/firesat/firesat-ci.c
drivers/media/dvb/firesat/firesat.h
drivers/media/dvb/firesat/firesat_1394.c
drivers/media/dvb/firesat/firesat_dvb.c
drivers/media/dvb/firesat/firesat_fe.c
drivers/media/dvb/firesat/firesat_iso.c [new file with mode: 0644]

index fdf86870f1fd5a910841d9a0e68c9b02b1f5c084..be7701b817c9b77ec8f9aeedf33e2ffd315a09d7 100644 (file)
@@ -1,6 +1,7 @@
 firesat-objs := firesat_1394.o \
                firesat_dvb.o   \
                firesat_fe.o    \
+               firesat_iso.o   \
                avc_api.o       \
                cmp.o           \
                firesat-rc.o    \
index cd79c806ecc77fc4f749df069abd168d9c4688f3..273c7235dd90ccc361a0505650c0d47747c23be7 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2004 Andreas Monitzer <andy@monitzer.com>
  * Copyright (c) 2008 Ben Backx <ben@bbackx.com>
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License as
@@ -15,6 +16,7 @@
 #include <nodemgr.h>
 #include <asm/byteorder.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include "avc_api.h"
 #include "firesat-rc.h"
 
 #define COMMAND_REGISTER                               0xFFFFF0000B00ULL
 #define PCR_BASE_ADDRESS                               0xFFFFF0000900ULL
 
+static unsigned int avc_comm_debug = 0;
+module_param(avc_comm_debug, int, 0644);
+MODULE_PARM_DESC(avc_comm_debug, "debug logging of AV/C communication, default is 0 (no)");
+
 static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal);
 
 /* Frees an allocated packet */
@@ -47,7 +53,124 @@ static int avc_down_timeout(atomic_t *done, int timeout)
        return ((i > 0) ? 0:1);
 }
 
-static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) {
+static const char* get_ctype_string(__u8 ctype)
+{
+       switch(ctype)
+       {
+       case 0:
+               return "CONTROL";
+       case 1:
+               return "STATUS";
+       case 2:
+               return "SPECIFIC_INQUIRY";
+       case 3:
+               return "NOTIFY";
+       case 4:
+               return "GENERAL_INQUIRY";
+       }
+       return "UNKNOWN";
+}
+
+static const char* get_resp_string(__u8 ctype)
+{
+       switch(ctype)
+       {
+       case 8:
+               return "NOT_IMPLEMENTED";
+       case 9:
+               return "ACCEPTED";
+       case 10:
+               return "REJECTED";
+       case 11:
+               return "IN_TRANSITION";
+       case 12:
+               return "IMPLEMENTED_STABLE";
+       case 13:
+               return "CHANGED";
+       case 15:
+               return "INTERIM";
+       }
+       return "UNKNOWN";
+}
+
+static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type)
+{
+       if (subunit_id == 7 && subunit_type == 0x1F)
+               return "Unit";
+       if (subunit_id == 0 && subunit_type == 0x05)
+               return "Tuner(0)";
+       return "Unsupported";
+}
+
+static const char* get_opcode_string(__u8 opcode)
+{
+       switch(opcode)
+       {
+       case 0x02:
+               return "PlugInfo";
+       case 0x08:
+               return "OpenDescriptor";
+       case 0x09:
+               return "ReadDescriptor";
+       case 0x18:
+               return "OutputPlugSignalFormat";
+       case 0x31:
+               return "SubunitInfo";
+       case 0x30:
+               return "UnitInfo";
+       case 0xB2:
+               return "Power";
+       case 0xC8:
+               return "DirectSelectInformationType";
+       case 0xCB:
+               return "DirectSelectData";
+       case 0x00:
+               return "Vendor";
+
+       }
+       return "Unknown";
+}
+
+static void log_command_frame(const AVCCmdFrm *CmdFrm)
+{
+       int k;
+       printk(KERN_INFO "AV/C Command Frame:\n");
+       printk("CommandType=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), "
+              "length=%d\n", get_ctype_string(CmdFrm->ctype),
+              get_subunit_address(CmdFrm->suid, CmdFrm->sutyp),
+              CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode),
+              CmdFrm->opcode, CmdFrm->length);
+       for(k = 0; k < CmdFrm->length - 3; k++) {
+               if (k % 5 != 0)
+                       printk(", ");
+               else if (k != 0)
+                       printk("\n");
+               printk("operand[%d] = %02X", k, CmdFrm->operand[k]);
+       }
+       printk("\n");
+}
+
+static void log_response_frame(const AVCRspFrm *RspFrm)
+{
+       int k;
+       printk(KERN_INFO "AV/C Response Frame:\n");
+       printk("Response=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), "
+              "length=%d\n", get_resp_string(RspFrm->resp),
+              get_subunit_address(RspFrm->suid, RspFrm->sutyp),
+              RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode),
+              RspFrm->opcode, RspFrm->length);
+       for(k = 0; k < RspFrm->length - 3; k++) {
+               if (k % 5 != 0)
+                       printk(", ");
+               else if (k != 0)
+                       printk("\n");
+               printk("operand[%d] = %02X", k, RspFrm->operand[k]);
+       }
+       printk("\n");
+}
+
+static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm,
+                     AVCRspFrm *RspFrm) {
        struct hpsb_packet *packet;
        struct node_entry *ne;
 
@@ -58,39 +181,50 @@ static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFr
        }
 
        /* need all input data */
-       if(!firesat || !ne || !CmdFrm)
+       if(!firesat || !ne || !CmdFrm) {
+               printk("%s: missing input data!\n",__func__);
                return -EINVAL;
+       }
 
-//     printk(KERN_INFO "AVCWrite command %x\n",CmdFrm->opcode);
-
-//     for(k=0;k<CmdFrm->length;k++)
-//             printk(KERN_INFO "CmdFrm[%d] = %08x\n", k, ((quadlet_t*)CmdFrm)[k]);
-
-       packet=hpsb_make_writepacket(ne->host, ne->nodeid, COMMAND_REGISTER,
-                       (quadlet_t*)CmdFrm, CmdFrm->length);
-
-       hpsb_set_packet_complete_task(packet, (void (*)(void*))avc_free_packet,
-                                 packet);
-
-       hpsb_node_fill_packet(ne, packet);
+       if (avc_comm_debug == 1) {
+               log_command_frame(CmdFrm);
+       }
 
        if(RspFrm)
                atomic_set(&firesat->avc_reply_received, 0);
 
+       packet=hpsb_make_writepacket(ne->host, ne->nodeid,
+                                    COMMAND_REGISTER,
+                                    (quadlet_t*)CmdFrm,
+                                    CmdFrm->length);
+       hpsb_set_packet_complete_task(packet,
+                                     (void (*)(void*))avc_free_packet,
+                                     packet);
+       hpsb_node_fill_packet(ne, packet);
+
        if (hpsb_send_packet(packet) < 0) {
                avc_free_packet(packet);
                atomic_set(&firesat->avc_reply_received, 1);
+               printk("%s: send failed!\n",__func__);
                return -EIO;
        }
 
        if(RspFrm) {
-               if(avc_down_timeout(&firesat->avc_reply_received,HZ/2)) {
-               printk("%s: timeout waiting for avc response\n",__func__);
+               // AV/C specs say that answers should be send within
+               // 150 ms so let's time out after 200 ms
+               if(avc_down_timeout(&firesat->avc_reply_received,
+                                   HZ / 5)) {
+                       printk("%s: timeout waiting for avc response\n",
+                              __func__);
                        atomic_set(&firesat->avc_reply_received, 1);
-               return -ETIMEDOUT;
-       }
-
-               memcpy(RspFrm,firesat->respfrm,firesat->resp_length);
+                       return -ETIMEDOUT;
+               }
+               memcpy(RspFrm, firesat->respfrm,
+                      firesat->resp_length);
+               RspFrm->length = firesat->resp_length;
+               if (avc_comm_debug == 1) {
+                       log_response_frame(RspFrm);
+               }
        }
 
        return 0;
@@ -137,6 +271,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) {
 
        // remote control handling
 
+#if 0
        AVCRspFrm *RspFrm = (AVCRspFrm*)data;
 
        if(/*RspFrm->length >= 8 && ###*/
@@ -155,21 +290,21 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) {
                        printk(KERN_INFO "%s: remote control result = %d\n",__func__, RspFrm->resp);
                return 0;
        }
-
+#endif
        if(atomic_read(&firesat->avc_reply_received) == 1) {
                printk("%s: received out-of-order AVC response, ignored\n",__func__);
                return -EINVAL;
        }
 //     AVCRspFrm *resp=(AVCRspFrm *)data;
 //     int k;
-/*
-       printk(KERN_INFO "resp=0x%x\n",resp->resp);
-       printk(KERN_INFO "cts=0x%x\n",resp->cts);
-       printk(KERN_INFO "suid=0x%x\n",resp->suid);
-       printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp);
-       printk(KERN_INFO "opcode=0x%x\n",resp->opcode);
-       printk(KERN_INFO "length=%d\n",resp->length);
-*/
+
+//     printk(KERN_INFO "resp=0x%x\n",resp->resp);
+//     printk(KERN_INFO "cts=0x%x\n",resp->cts);
+//     printk(KERN_INFO "suid=0x%x\n",resp->suid);
+//     printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp);
+//     printk(KERN_INFO "opcode=0x%x\n",resp->opcode);
+//     printk(KERN_INFO "length=%d\n",resp->length);
+
 //     for(k=0;k<2;k++)
 //             printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]);
 
@@ -183,6 +318,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) {
 
 // tuning command for setting the relative LNB frequency (not supported by the AVC standard)
 static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) {
+
        memset(CmdFrm, 0, sizeof(AVCCmdFrm));
 
        CmdFrm->cts = AVC;
@@ -249,7 +385,7 @@ static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_param
        CmdFrm->length = 16;
 }
 
-int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, BYTE *status) {
+int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) {
        AVCCmdFrm CmdFrm;
        AVCRspFrm RspFrm;
        M_VALID_FLAGS flags;
@@ -274,21 +410,15 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params
                        flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO);
                        flags.Bits_T.NetworkId = 0;
                } else {
-                       flags.Bits.Modulation = 0;
-                       if(firesat->type == FireSAT_DVB_S) {
-                               flags.Bits.FEC_inner = 1;
-                       } else if(firesat->type == FireSAT_DVB_C) {
-                               flags.Bits.FEC_inner = 0;
-                       }
+                       flags.Bits.Modulation =
+                               (params->u.qam.modulation != QAM_AUTO);
+                       flags.Bits.FEC_inner =
+                               (params->u.qam.fec_inner != FEC_AUTO);
                        flags.Bits.FEC_outer = 0;
                        flags.Bits.Symbol_Rate = 1;
                        flags.Bits.Frequency = 1;
                        flags.Bits.Orbital_Pos = 0;
-                       if(firesat->type == FireSAT_DVB_S) {
-                               flags.Bits.Polarisation = 1;
-                       } else if(firesat->type == FireSAT_DVB_C) {
-                               flags.Bits.Polarisation = 0;
-                       }
+                       flags.Bits.Polarisation = 0;
                        flags.Bits.reserved_fields = 0;
                        flags.Bits.reserved1 = 0;
                        flags.Bits.Network_ID = 0;
@@ -306,15 +436,18 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params
                CmdFrm.operand[1]  = 0xD2; // subfunction replace
                CmdFrm.operand[2]  = 0x20; // system id = DVB
                CmdFrm.operand[3]  = 0x00; // antenna number
-               CmdFrm.operand[4]  = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length
+               // system_specific_multiplex selection_length
+               CmdFrm.operand[4]  = (firesat->type == FireSAT_DVB_T)?0x0c:0x11;
                CmdFrm.operand[5]  = flags.Valid_Word.ByteHi; // valid_flags [0]
                CmdFrm.operand[6]  = flags.Valid_Word.ByteLo; // valid_flags [1]
 
                if(firesat->type == FireSAT_DVB_T) {
                        CmdFrm.operand[7]  = 0x0;
                        CmdFrm.operand[8]  = (params->frequency/10) >> 24;
-                       CmdFrm.operand[9]  = ((params->frequency/10) >> 16) & 0xFF;
-                       CmdFrm.operand[10] = ((params->frequency/10) >>  8) & 0xFF;
+                       CmdFrm.operand[9]  =
+                               ((params->frequency/10) >> 16) & 0xFF;
+                       CmdFrm.operand[10] =
+                               ((params->frequency/10) >>  8) & 0xFF;
                        CmdFrm.operand[11] = (params->frequency/10) & 0xFF;
                        switch(params->u.ofdm.bandwidth) {
                        case BANDWIDTH_7_MHZ:
@@ -416,28 +549,24 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params
                        CmdFrm.operand[16] = 0x00; // network_ID[1]
                        CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted
 
-                       CmdFrm.length = 20;
+                       CmdFrm.length = 24;
                } else {
                        CmdFrm.operand[7]  = 0x00;
-                       CmdFrm.operand[8]  = (((firesat->voltage==SEC_VOLTAGE_18)?0:1)<<6); /* 0 = H, 1 = V */
+                       CmdFrm.operand[8]  = 0x00;
                        CmdFrm.operand[9]  = 0x00;
                        CmdFrm.operand[10] = 0x00;
 
-                       if(firesat->type == FireSAT_DVB_S) {
-                               /* ### relative frequency -> absolute frequency */
-                               CmdFrm.operand[11] = (((params->frequency/4) >> 16) & 0xFF) | (2 << 6);
-                               CmdFrm.operand[12] = ((params->frequency/4) >> 8) & 0xFF;
-                               CmdFrm.operand[13] = (params->frequency/4) & 0xFF;
-                       } else if(firesat->type == FireSAT_DVB_C) {
-                               CmdFrm.operand[11] = (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6);
-                               CmdFrm.operand[12] = ((params->frequency/4000) >> 8) & 0xFF;
-                               CmdFrm.operand[13] = (params->frequency/4000) & 0xFF;
-                       }
-
-                       CmdFrm.operand[14] = ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF;
-                       CmdFrm.operand[15] = ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF;
-                       CmdFrm.operand[16] = ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0;
-
+                       CmdFrm.operand[11] =
+                               (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6);
+                       CmdFrm.operand[12] =
+                               ((params->frequency/4000) >> 8) & 0xFF;
+                       CmdFrm.operand[13] = (params->frequency/4000) & 0xFF;
+                       CmdFrm.operand[14] =
+                               ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF;
+                       CmdFrm.operand[15] =
+                               ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF;
+                       CmdFrm.operand[16] =
+                               ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0;
                        CmdFrm.operand[17] = 0x00;
                        switch(params->u.qpsk.fec_inner) {
                        case FEC_1_2:
@@ -455,35 +584,35 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params
                        case FEC_7_8:
                                CmdFrm.operand[18] = 0x5;
                                break;
-                       case FEC_4_5:
                        case FEC_8_9:
+                               CmdFrm.operand[18] = 0x6;
+                               break;
+                       case FEC_4_5:
+                               CmdFrm.operand[18] = 0x8;
+                               break;
                        case FEC_AUTO:
                        default:
                                CmdFrm.operand[18] = 0x0;
                        }
-                       if(firesat->type == FireSAT_DVB_S) {
+                       switch(params->u.qam.modulation) {
+                       case QAM_16:
                                CmdFrm.operand[19] = 0x08; // modulation
-                       } else if(firesat->type == FireSAT_DVB_C) {
-                               switch(params->u.qam.modulation) {
-                               case QAM_16:
-                                       CmdFrm.operand[19] = 0x08; // modulation
-                                       break;
-                               case QAM_32:
-                                       CmdFrm.operand[19] = 0x10; // modulation
-                                       break;
-                               case QAM_64:
-                                       CmdFrm.operand[19] = 0x18; // modulation
-                                       break;
-                               case QAM_128:
-                                       CmdFrm.operand[19] = 0x20; // modulation
-                                       break;
-                               case QAM_256:
-                                       CmdFrm.operand[19] = 0x28; // modulation
-                                       break;
-                               case QAM_AUTO:
-                               default:
-                                       CmdFrm.operand[19] = 0x00; // modulation
-                               }
+                               break;
+                       case QAM_32:
+                               CmdFrm.operand[19] = 0x10; // modulation
+                               break;
+                       case QAM_64:
+                               CmdFrm.operand[19] = 0x18; // modulation
+                               break;
+                       case QAM_128:
+                               CmdFrm.operand[19] = 0x20; // modulation
+                               break;
+                       case QAM_256:
+                               CmdFrm.operand[19] = 0x28; // modulation
+                               break;
+                       case QAM_AUTO:
+                       default:
+                               CmdFrm.operand[19] = 0x00; // modulation
                        }
                        CmdFrm.operand[20] = 0x00;
                        CmdFrm.operand[21] = 0x00;
@@ -496,7 +625,6 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params
        if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
                return k;
 
-//     msleep(250);
        mdelay(500);
 
        if(status)
@@ -504,13 +632,12 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params
        return 0;
 }
 
-int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) {
+int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[])
+{
        AVCCmdFrm CmdFrm;
        AVCRspFrm RspFrm;
        int pos,k;
 
-       printk(KERN_INFO "%s\n", __func__);
-
        if(pidc > 16 && pidc != 0xFF)
                return -EINVAL;
 
@@ -526,49 +653,11 @@ int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) {
        CmdFrm.operand[1]  = 0xD2; // subfunction replace
        CmdFrm.operand[2]  = 0x20; // system id = DVB
        CmdFrm.operand[3]  = 0x00; // antenna number
-       CmdFrm.operand[4]  = 0x11; // system_specific_multiplex selection_length
-       CmdFrm.operand[5]  = 0x00; // valid_flags [0]
-       CmdFrm.operand[6]  = 0x00; // valid_flags [1]
-
-       if(firesat->type == FireSAT_DVB_T) {
-/*             CmdFrm.operand[7]  = 0x00;
-               CmdFrm.operand[8]  = 0x00;//(params->frequency/10) >> 24;
-               CmdFrm.operand[9]  = 0x00;//((params->frequency/10) >> 16) & 0xFF;
-               CmdFrm.operand[10] = 0x00;//((params->frequency/10) >>  8) & 0xFF;
-               CmdFrm.operand[11] = 0x00;//(params->frequency/10) & 0xFF;
-               CmdFrm.operand[12] = 0x00;
-               CmdFrm.operand[13] = 0x00;
-               CmdFrm.operand[14] = 0x00;
-
-               CmdFrm.operand[15] = 0x00; // network_ID[0]
-               CmdFrm.operand[16] = 0x00; // network_ID[1]
-*/             CmdFrm.operand[17] = pidc; // Nr_of_dsd_sel_specs
-
-               pos=18;
-       } else {
-/*             CmdFrm.operand[7]  = 0x00;
-               CmdFrm.operand[8]  = 0x00;
-               CmdFrm.operand[9]  = 0x00;
-               CmdFrm.operand[10] = 0x00;
-
-               CmdFrm.operand[11] = 0x00;//(((params->frequency/4) >> 16) & 0xFF) | (2 << 6);
-               CmdFrm.operand[12] = 0x00;//((params->frequency/4) >> 8) & 0xFF;
-               CmdFrm.operand[13] = 0x00;//(params->frequency/4) & 0xFF;
-
-               CmdFrm.operand[14] = 0x00;//((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF;
-               CmdFrm.operand[15] = 0x00;//((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF;
-               CmdFrm.operand[16] = 0x00;//((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0;
-
-               CmdFrm.operand[17] = 0x00;
-               CmdFrm.operand[18] = 0x00;
-               CmdFrm.operand[19] = 0x00; // modulation
-               CmdFrm.operand[20] = 0x00;
-               CmdFrm.operand[21] = 0x00;*/
-               CmdFrm.operand[22] = pidc; // Nr_of_dsd_sel_specs
-
-               pos=23;
-       }
-       if(pidc != 0xFF)
+       CmdFrm.operand[4]  = 0x00; // system_specific_multiplex selection_length
+       CmdFrm.operand[5]  = pidc; // Nr_of_dsd_sel_specs
+
+       pos=6;
+       if(pidc != 0xFF) {
                for(k=0;k<pidc;k++) {
                        CmdFrm.operand[pos++] = 0x13; // flowfunction relay
                        CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID
@@ -577,17 +666,16 @@ int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) {
                        CmdFrm.operand[pos++] = 0x00; // tableID
                        CmdFrm.operand[pos++] = 0x00; // filter_length
                }
+       }
 
        CmdFrm.length = pos+3;
-
        if((pos+3)%4)
                CmdFrm.length += 4 - ((pos+3)%4);
 
        if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
                return k;
 
-       mdelay(250);
-
+       mdelay(50);
        return 0;
 }
 
@@ -596,7 +684,7 @@ int AVCTuner_GetTS(struct firesat *firesat){
        AVCRspFrm RspFrm;
        int k;
 
-       printk(KERN_INFO "%s\n", __func__);
+       //printk(KERN_INFO "%s\n", __func__);
 
        memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
 
@@ -612,20 +700,21 @@ int AVCTuner_GetTS(struct firesat *firesat){
        CmdFrm.operand[3]  = 0x20; // system id = DVB
        CmdFrm.operand[4]  = 0x00; // antenna number
        CmdFrm.operand[5]  = 0x0;  // system_specific_search_flags
-       CmdFrm.operand[6]  = 0x11; // system_specific_multiplex selection_length
+       CmdFrm.operand[6]  = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length
        CmdFrm.operand[7]  = 0x00; // valid_flags [0]
        CmdFrm.operand[8]  = 0x00; // valid_flags [1]
-       CmdFrm.operand[24] = 0x00; // nr_of_dsit_sel_specs (always 0)
+       CmdFrm.operand[7 + (firesat->type == FireSAT_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0)
 
-       CmdFrm.length = 28;
+       CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28;
 
-       if((k=AVCWrite(firesat, &CmdFrm, &RspFrm))) return k;
+       if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm)))
+               return k;
 
        mdelay(250);
        return 0;
 }
 
-int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport, int *has_ci) {
+int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport) {
        AVCCmdFrm CmdFrm;
        AVCRspFrm RspFrm;
 
@@ -660,8 +749,6 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr
        }
        if(systemId)
                *systemId = RspFrm.operand[7];
-       if(has_ci)
-               *has_ci = (RspFrm.operand[14] >> 4) & 0x1;
        return 0;
 }
 
@@ -679,14 +766,13 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in
        CmdFrm.opcode=READ_DESCRIPTOR;
 
        CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS;
-       CmdFrm.operand[1]=0xff;
-       CmdFrm.operand[2]=0x00;
-       CmdFrm.operand[3]=sizeof(ANTENNA_INPUT_INFO) >> 8;
-       CmdFrm.operand[4]=sizeof(ANTENNA_INPUT_INFO) & 0xFF;
+       CmdFrm.operand[1]=0xff; //read_result_status
+       CmdFrm.operand[2]=0x00; // reserver
+       CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8;
+       CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF;
        CmdFrm.operand[5]=0x00;
-       CmdFrm.operand[6]=0x03;
+       CmdFrm.operand[6]=0x00;
        CmdFrm.length=12;
-       //Absenden des AVC request und warten auf response
        if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
                return -EIO;
 
@@ -695,10 +781,11 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in
                return -EINVAL;
        }
 
-       length = (RspFrm.operand[3] << 8) + RspFrm.operand[4];
-       if(length == sizeof(ANTENNA_INPUT_INFO))
+       length = RspFrm.operand[9];
+       if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO))
        {
-               memcpy(antenna_input_info,&RspFrm.operand[7],length);
+               memcpy(antenna_input_info, &RspFrm.operand[10],
+                      sizeof(ANTENNA_INPUT_INFO));
                return 0;
        }
        printk("%s: invalid info returned from AVC\n",__func__);
@@ -837,3 +924,384 @@ int AVCRegisterRemoteControl(struct firesat*firesat)
 {
        return __AVCRegisterRemoteControl(firesat, 0);
 }
+
+int AVCTuner_Host2Ca(struct firesat *firesat)
+{
+
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = CONTROL;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
+       CmdFrm.operand[6] = 0; // more/last
+       CmdFrm.operand[7] = 0; // length
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+static int get_ca_object_pos(AVCRspFrm *RspFrm)
+{
+       int length = 1;
+
+       // Check length of length field
+       if (RspFrm->operand[7] & 0x80)
+               length = (RspFrm->operand[7] & 0x7F) + 1;
+       return length + 7;
+}
+
+static int get_ca_object_length(AVCRspFrm *RspFrm)
+{
+       int size = 0;
+       int i;
+
+       if (RspFrm->operand[7] & 0x80) {
+               for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) {
+                       size <<= 8;
+                       size += RspFrm->operand[8 + i];
+               }
+       }
+       return RspFrm->operand[7];
+}
+
+int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+       int pos;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = STATUS;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+
+       pos = get_ca_object_pos(&RspFrm);
+       app_info[0] = (TAG_APP_INFO >> 16) & 0xFF;
+       app_info[1] = (TAG_APP_INFO >> 8) & 0xFF;
+       app_info[2] = (TAG_APP_INFO >> 0) & 0xFF;
+       app_info[3] = 6 + RspFrm.operand[pos + 4];
+       app_info[4] = 0x01;
+       memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]);
+       *length = app_info[3] + 4;
+
+       return 0;
+}
+
+int avc_ca_info(struct firesat *firesat, char *app_info, int *length)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+       int pos;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = STATUS;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       pos = get_ca_object_pos(&RspFrm);
+       app_info[0] = (TAG_CA_INFO >> 16) & 0xFF;
+       app_info[1] = (TAG_CA_INFO >> 8) & 0xFF;
+       app_info[2] = (TAG_CA_INFO >> 0) & 0xFF;
+       app_info[3] = 2;
+       app_info[4] = app_info[5];
+       app_info[5] = app_info[6];
+       *length = app_info[3] + 4;
+
+       return 0;
+}
+
+int avc_ca_reset(struct firesat *firesat)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = CONTROL;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag
+       CmdFrm.operand[6] = 0; // more/last
+       CmdFrm.operand[7] = 1; // length
+       CmdFrm.operand[8] = 0; // force hardware reset
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+int avc_ca_pmt(struct firesat *firesat, char *msg, int length)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+       int list_management;
+       int program_info_length;
+       int pmt_cmd_id;
+       int read_pos;
+       int write_pos;
+       int es_info_length;
+       int crc32_csum;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = CONTROL;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       if (msg[0] != LIST_MANAGEMENT_ONLY) {
+               printk(KERN_ERR "The only list_manasgement parameter that is "
+                      "supported by the firesat driver is \"only\" (3).");
+               return -EFAULT;
+       }
+       // We take the cmd_id from the programme level only!
+       list_management = msg[0];
+       program_info_length = ((msg[4] & 0x0F) << 8) + msg[5];
+       if (program_info_length > 0)
+               program_info_length--; // Remove pmt_cmd_id
+       pmt_cmd_id = msg[6];
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag
+       CmdFrm.operand[6] = 0; // more/last
+       //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length
+       CmdFrm.operand[8] = list_management;
+       CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble
+
+       // TS program map table
+
+       // Table id=2
+       CmdFrm.operand[10] = 0x02;
+       // Section syntax + length
+       CmdFrm.operand[11] = 0x80;
+       //CmdFrm.operand[12] = XXXprogram_info_length + 12;
+       // Program number
+       CmdFrm.operand[13] = msg[1];
+       CmdFrm.operand[14] = msg[2];
+       // Version number=0 + current/next=1
+       CmdFrm.operand[15] = 0x01;
+       // Section number=0
+       CmdFrm.operand[16] = 0x00;
+       // Last section number=0
+       CmdFrm.operand[17] = 0x00;
+       // PCR_PID=1FFF
+       CmdFrm.operand[18] = 0x1F;
+       CmdFrm.operand[19] = 0xFF;
+       // Program info length
+       CmdFrm.operand[20] = (program_info_length >> 8);
+       CmdFrm.operand[21] = (program_info_length & 0xFF);
+       // CA descriptors at programme level
+       read_pos = 6;
+       write_pos = 22;
+       if (program_info_length > 0) {
+/*             printk(KERN_INFO "Copying descriptors at programme level.\n"); */
+               pmt_cmd_id = msg[read_pos++];
+               if (pmt_cmd_id != 1 && pmt_cmd_id !=4) {
+                       printk(KERN_ERR "Invalid pmt_cmd_id=%d.\n",
+                              pmt_cmd_id);
+               }
+               memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
+                      program_info_length);
+               read_pos += program_info_length;
+               write_pos += program_info_length;
+       }
+       while (read_pos < length) {
+/*             printk(KERN_INFO "Copying descriptors at stream level for " */
+/*                    "stream type %d.\n", msg[read_pos]); */
+               CmdFrm.operand[write_pos++] = msg[read_pos++];
+               CmdFrm.operand[write_pos++] = msg[read_pos++];
+               CmdFrm.operand[write_pos++] = msg[read_pos++];
+               es_info_length =
+                       ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1];
+               read_pos += 2;
+               if (es_info_length > 0)
+                       es_info_length--; // Remove pmt_cmd_id
+               CmdFrm.operand[write_pos++] = es_info_length >> 8;
+               CmdFrm.operand[write_pos++] = es_info_length & 0xFF;
+               if (es_info_length > 0) {
+                       pmt_cmd_id = msg[read_pos++];
+                       if (pmt_cmd_id != 1 && pmt_cmd_id !=4) {
+                               printk(KERN_ERR "Invalid pmt_cmd_id=%d at "
+                                      "stream level.\n", pmt_cmd_id);
+                       }
+                       memcpy(&CmdFrm.operand[write_pos], &msg[read_pos],
+                              es_info_length);
+                       read_pos += es_info_length;
+                       write_pos += es_info_length;
+               }
+       }
+
+       // CRC
+       CmdFrm.operand[write_pos++] = 0x00;
+       CmdFrm.operand[write_pos++] = 0x00;
+       CmdFrm.operand[write_pos++] = 0x00;
+       CmdFrm.operand[write_pos++] = 0x00;
+
+       CmdFrm.operand[7] = write_pos - 8;
+       CmdFrm.operand[12] = write_pos - 13;
+
+       crc32_csum = crc32_be(0, &CmdFrm.operand[10],
+                          CmdFrm.operand[12] - 1);
+       CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF;
+       CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF;
+       CmdFrm.operand[write_pos - 2] = (crc32_csum >>  8) & 0xFF;
+       CmdFrm.operand[write_pos - 1] = (crc32_csum >>  0) & 0xFF;
+
+       CmdFrm.length = write_pos + 3;
+       if ((write_pos + 3) % 4)
+               CmdFrm.length += 4 - ((write_pos + 3) % 4);
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       if (RspFrm.resp != ACCEPTED) {
+               printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp);
+               return -EFAULT;
+       }
+
+       return 0;
+
+}
+
+int avc_ca_get_time_date(struct firesat *firesat, int *interval)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = STATUS;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag
+       CmdFrm.operand[6] = 0; // more/last
+       CmdFrm.operand[7] = 0; // length
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)];
+
+       return 0;
+}
+
+int avc_ca_enter_menu(struct firesat *firesat)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = STATUS;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
+       CmdFrm.operand[6] = 0; // more/last
+       CmdFrm.operand[7] = 0; // length
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length)
+{
+       AVCCmdFrm CmdFrm;
+       AVCRspFrm RspFrm;
+
+       memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
+       CmdFrm.cts = AVC;
+       CmdFrm.ctype = STATUS;
+       CmdFrm.sutyp = 0x5;
+       CmdFrm.suid = firesat->subunit;
+       CmdFrm.opcode = VENDOR;
+
+       CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0;
+       CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1;
+       CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2;
+       CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST;
+       CmdFrm.operand[4] = 0; // slot
+       CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI;
+       CmdFrm.operand[6] = 0; // more/last
+       CmdFrm.operand[7] = 0; // length
+       CmdFrm.length = 12;
+
+       if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0)
+               return -EIO;
+
+       *length = get_ca_object_length(&RspFrm);
+       memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length);
+
+       return 0;
+}
index f9a190adcd37c2b79996d0c7f3c386c913375d68..041665685903f7e46f5768b8e81ea9208ed49221 100644 (file)
@@ -4,6 +4,7 @@
     begin                : Wed May 1 2000
     copyright            : (C) 2000 by Manfred Weihs
     copyright            : (C) 2003 by Philipp Gutgsell
+    copyright            : (C) 2008 by Henrik Kurelid (henrik@kurelid.se)
     email                : 0014guph@edu.fh-kaernten.ac.at
  ***************************************************************************/
 
 
 #include <linux/dvb/frontend.h>
 
-#define BYTE   unsigned char
-#define WORD   unsigned short
-#define DWORD  unsigned long
-#define ULONG  unsigned long
-#define LONG   long
-
+/*************************************************************
+       Constants from EN510221
+**************************************************************/
+#define LIST_MANAGEMENT_ONLY 0x03
 
 /*************************************************************
        FCP Address range
@@ -68,12 +67,12 @@ typedef struct {
 typedef struct _AVCCmdFrm
 {
                // AV/C command frame
-       BYTE ctype  : 4 ;   // command type
-       BYTE cts    : 4 ;   // always 0x0 for AVC
-       BYTE suid   : 3 ;   // subunit ID
-       BYTE sutyp  : 5 ;   // subunit_typ
-       BYTE opcode : 8 ;   // opcode
-       BYTE operand[509] ; // array of operands [1-507]
+       __u8 ctype  : 4 ;   // command type
+       __u8 cts    : 4 ;   // always 0x0 for AVC
+       __u8 suid   : 3 ;   // subunit ID
+       __u8 sutyp  : 5 ;   // subunit_typ
+       __u8 opcode : 8 ;   // opcode
+       __u8 operand[509] ; // array of operands [1-507]
        int length;         //length of the command frame
 } AVCCmdFrm ;
 
@@ -81,12 +80,12 @@ typedef struct _AVCCmdFrm
 typedef struct _AVCRspFrm
 {
         // AV/C response frame
-       BYTE resp               : 4 ;   // response type
-       BYTE cts                : 4 ;   // always 0x0 for AVC
-       BYTE suid               : 3 ;   // subunit ID
-       BYTE sutyp      : 5 ;   // subunit_typ
-       BYTE opcode     : 8 ;   // opcode
-       BYTE operand[509] ; // array of operands [1-507]
+       __u8 resp               : 4 ;   // response type
+       __u8 cts                : 4 ;   // always 0x0 for AVC
+       __u8 suid               : 3 ;   // subunit ID
+       __u8 sutyp      : 5 ;   // subunit_typ
+       __u8 opcode     : 8 ;   // opcode
+       __u8 operand[509] ; // array of operands [1-507]
        int length;         //length of the response frame
 } AVCRspFrm ;
 
@@ -94,23 +93,23 @@ typedef struct _AVCRspFrm
 
 typedef struct _AVCCmdFrm
 {
-       BYTE cts:4;
-       BYTE ctype:4;
-       BYTE sutyp:5;
-       BYTE suid:3;
-       BYTE opcode;
-       BYTE operand[509];
+       __u8 cts:4;
+       __u8 ctype:4;
+       __u8 sutyp:5;
+       __u8 suid:3;
+       __u8 opcode;
+       __u8 operand[509];
        int length;
 } AVCCmdFrm;
 
 typedef struct _AVCRspFrm
 {
-       BYTE cts:4;
-       BYTE resp:4;
-       BYTE sutyp:5;
-       BYTE suid:3;
-       BYTE opcode;
-       BYTE operand[509];
+       __u8 cts:4;
+       __u8 resp:4;
+       __u8 sutyp:5;
+       __u8 suid:3;
+       __u8 opcode;
+       __u8 operand[509];
        int length;
 } AVCRspFrm;
 
@@ -197,6 +196,14 @@ typedef struct _AVCRspFrm
 #define SFE_VENDOR_OPCODE_CISTATUS                             0x59
 #define SFE_VENDOR_OPCODE_TUNE_QPSK2                   0x60 // QPSK command for DVB-S2 devices
 
+// CA Tags
+#define SFE_VENDOR_TAG_CA_RESET                        0x00
+#define SFE_VENDOR_TAG_CA_APPLICATION_INFO     0x01
+#define SFE_VENDOR_TAG_CA_PMT                  0x02
+#define SFE_VENDOR_TAG_CA_DATE_TIME            0x04
+#define SFE_VENDOR_TAG_CA_MMI                  0x05
+#define SFE_VENDOR_TAG_CA_ENTER_MENU           0x07
+
 
 //AVCTuner DVB identifier service_ID
 #define DVB 0x20
@@ -209,8 +216,8 @@ typedef struct _AVCRspFrm
 #define Tuner_Status_Descriptor                                 0x80
 
 typedef struct {
-       BYTE          Subunit_Type;
-       BYTE          Max_Subunit_ID;
+       __u8          Subunit_Type;
+       __u8          Max_Subunit_ID;
 } SUBUNIT_INFO;
 
 /*************************************************************
@@ -220,12 +227,12 @@ typedef struct {
 **************************************************************/
 
 typedef struct {
-       BYTE  Byte0;
-       BYTE  Byte1;
-       BYTE  Byte2;
-       BYTE  Byte3;
-       BYTE  Byte4;
-       BYTE  Byte5;
+       __u8  Byte0;
+       __u8  Byte1;
+       __u8  Byte2;
+       __u8  Byte3;
+       __u8  Byte4;
+       __u8  Byte5;
 }OBJECT_ID;
 
 /*************************************************************
@@ -234,14 +241,14 @@ typedef struct {
 typedef struct
 {
 #ifdef __LITTLE_ENDIAN
-       BYTE       RF_frequency_hByte:6;
-       BYTE       raster_Frequency:2;//Bit7,6 raster frequency
+       __u8       RF_frequency_hByte:6;
+       __u8       raster_Frequency:2;//Bit7,6 raster frequency
 #else
-       BYTE raster_Frequency:2;
-       BYTE RF_frequency_hByte:6;
+       __u8 raster_Frequency:2;
+       __u8 RF_frequency_hByte:6;
 #endif
-       BYTE       RF_frequency_mByte;
-       BYTE       RF_frequency_lByte;
+       __u8       RF_frequency_mByte;
+       __u8       RF_frequency_lByte;
 
 }FREQUENCY;
 
@@ -249,63 +256,63 @@ typedef struct
 
 typedef struct
 {
-                BYTE        Modulation     :1;
-                BYTE        FEC_inner      :1;
-                BYTE        FEC_outer      :1;
-                BYTE        Symbol_Rate    :1;
-                BYTE        Frequency      :1;
-                BYTE        Orbital_Pos        :1;
-                BYTE        Polarisation       :1;
-                BYTE        reserved_fields :1;
-                BYTE        reserved1          :7;
-                BYTE        Network_ID :1;
+                __u8        Modulation     :1;
+                __u8        FEC_inner      :1;
+                __u8        FEC_outer      :1;
+                __u8        Symbol_Rate    :1;
+                __u8        Frequency      :1;
+                __u8        Orbital_Pos        :1;
+                __u8        Polarisation       :1;
+                __u8        reserved_fields :1;
+                __u8        reserved1          :7;
+                __u8        Network_ID :1;
 
 }MULTIPLEX_VALID_FLAGS;
 
 typedef struct
 {
-       BYTE    GuardInterval:1;
-       BYTE    CodeRateLPStream:1;
-       BYTE    CodeRateHPStream:1;
-       BYTE    HierarchyInfo:1;
-       BYTE    Constellation:1;
-       BYTE    Bandwidth:1;
-       BYTE    CenterFrequency:1;
-       BYTE    reserved1:1;
-       BYTE    reserved2:5;
-       BYTE    OtherFrequencyFlag:1;
-       BYTE    TransmissionMode:1;
-       BYTE    NetworkId:1;
+       __u8    GuardInterval:1;
+       __u8    CodeRateLPStream:1;
+       __u8    CodeRateHPStream:1;
+       __u8    HierarchyInfo:1;
+       __u8    Constellation:1;
+       __u8    Bandwidth:1;
+       __u8    CenterFrequency:1;
+       __u8    reserved1:1;
+       __u8    reserved2:5;
+       __u8    OtherFrequencyFlag:1;
+       __u8    TransmissionMode:1;
+       __u8    NetworkId:1;
 }MULTIPLEX_VALID_FLAGS_DVBT;
 
 #else
 
 typedef struct {
-       BYTE reserved_fields:1;
-       BYTE Polarisation:1;
-       BYTE Orbital_Pos:1;
-       BYTE Frequency:1;
-       BYTE Symbol_Rate:1;
-       BYTE FEC_outer:1;
-       BYTE FEC_inner:1;
-       BYTE Modulation:1;
-       BYTE Network_ID:1;
-       BYTE reserved1:7;
+       __u8 reserved_fields:1;
+       __u8 Polarisation:1;
+       __u8 Orbital_Pos:1;
+       __u8 Frequency:1;
+       __u8 Symbol_Rate:1;
+       __u8 FEC_outer:1;
+       __u8 FEC_inner:1;
+       __u8 Modulation:1;
+       __u8 Network_ID:1;
+       __u8 reserved1:7;
 }MULTIPLEX_VALID_FLAGS;
 
 typedef struct {
-       BYTE reserved1:1;
-       BYTE CenterFrequency:1;
-       BYTE Bandwidth:1;
-       BYTE Constellation:1;
-       BYTE HierarchyInfo:1;
-       BYTE CodeRateHPStream:1;
-       BYTE CodeRateLPStream:1;
-       BYTE GuardInterval:1;
-       BYTE NetworkId:1;
-       BYTE TransmissionMode:1;
-       BYTE OtherFrequencyFlag:1;
-       BYTE reserved2:5;
+       __u8 reserved1:1;
+       __u8 CenterFrequency:1;
+       __u8 Bandwidth:1;
+       __u8 Constellation:1;
+       __u8 HierarchyInfo:1;
+       __u8 CodeRateHPStream:1;
+       __u8 CodeRateLPStream:1;
+       __u8 GuardInterval:1;
+       __u8 NetworkId:1;
+       __u8 TransmissionMode:1;
+       __u8 OtherFrequencyFlag:1;
+       __u8 reserved2:5;
 }MULTIPLEX_VALID_FLAGS_DVBT;
 
 #endif
@@ -314,47 +321,98 @@ typedef union {
        MULTIPLEX_VALID_FLAGS Bits;
        MULTIPLEX_VALID_FLAGS_DVBT Bits_T;
        struct {
-               BYTE    ByteHi;
-               BYTE    ByteLo;
+               __u8    ByteHi;
+               __u8    ByteLo;
        } Valid_Word;
 } M_VALID_FLAGS;
 
 typedef struct
 {
 #ifdef __LITTLE_ENDIAN
-  BYTE      ActiveSystem;
-  BYTE      reserved:5;
-  BYTE      NoRF:1;
-  BYTE      Moving:1;
-  BYTE      Searching:1;
+  __u8      ActiveSystem;
+  __u8      reserved:5;
+  __u8      NoRF:1;
+  __u8      Moving:1;
+  __u8      Searching:1;
 
-  BYTE      SelectedAntenna:7;
-  BYTE      Input:1;
+  __u8      SelectedAntenna:7;
+  __u8      Input:1;
 
-  BYTE      BER[4];
+  __u8      BER[4];
 
-  BYTE      SignalStrength;
+  __u8      SignalStrength;
   FREQUENCY Frequency;
 
-  BYTE      ManDepInfoLength;
+  __u8      ManDepInfoLength;
+
+  __u8 PowerSupply:1;
+  __u8 FrontEndPowerStatus:1;
+  __u8 reserved3:1;
+  __u8 AntennaError:1;
+  __u8 FrontEndError:1;
+  __u8 reserved2:3;
+
+  __u8 CarrierNoiseRatio[2];
+  __u8 reserved4[2];
+  __u8 PowerSupplyVoltage;
+  __u8 AntennaVoltage;
+  __u8 FirewireBusVoltage;
+
+  __u8 CaMmi:1;
+  __u8 reserved5:7;
+
+  __u8 reserved6:1;
+  __u8 CaInitializationStatus:1;
+  __u8 CaErrorFlag:1;
+  __u8 CaDvbFlag:1;
+  __u8 CaModulePresentStatus:1;
+  __u8 CaApplicationInfo:1;
+  __u8 CaDateTimeRequest:1;
+  __u8 CaPmtReply:1;
+
 #else
-  BYTE ActiveSystem;
-  BYTE Searching:1;
-  BYTE Moving:1;
-  BYTE NoRF:1;
-  BYTE reserved:5;
+  __u8 ActiveSystem;
+  __u8 Searching:1;
+  __u8 Moving:1;
+  __u8 NoRF:1;
+  __u8 reserved:5;
 
-  BYTE Input:1;
-  BYTE SelectedAntenna:7;
+  __u8 Input:1;
+  __u8 SelectedAntenna:7;
 
-  BYTE BER[4];
+  __u8 BER[4];
 
-  BYTE SignalStrength;
+  __u8 SignalStrength;
   FREQUENCY Frequency;
 
-  BYTE ManDepInfoLength;
+  __u8 ManDepInfoLength;
+
+  __u8 reserved2:3;
+  __u8 FrontEndError:1;
+  __u8 AntennaError:1;
+  __u8 reserved3:1;
+  __u8 FrontEndPowerStatus:1;
+  __u8 PowerSupply:1;
+
+  __u8 CarrierNoiseRatio[2];
+  __u8 reserved4[2];
+  __u8 PowerSupplyVoltage;
+  __u8 AntennaVoltage;
+  __u8 FirewireBusVoltage;
+
+  __u8 reserved5:7;
+  __u8 CaMmi:1;
+  __u8 CaPmtReply:1;
+  __u8 CaDateTimeRequest:1;
+  __u8 CaApplicationInfo:1;
+  __u8 CaModulePresentStatus:1;
+  __u8 CaDvbFlag:1;
+  __u8 CaErrorFlag:1;
+  __u8 CaInitializationStatus:1;
+  __u8 reserved6:1;
+
 #endif
-} ANTENNA_INPUT_INFO; // 11 Byte
+} ANTENNA_INPUT_INFO; // 22 Byte
 
 #define LNBCONTROL_DONTCARE 0xff
 
@@ -365,17 +423,27 @@ extern int AVCRecv(struct firesat *firesat, u8 *data, size_t length);
 extern int AVCTuner_DSIT(struct firesat *firesat,
                            int Source_Plug,
                                                   struct dvb_frontend_parameters *params,
-                           BYTE *status);
+                           __u8 *status);
 
 extern int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info);
-extern int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, BYTE *status);
+extern int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status);
 extern int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]);
 extern int AVCTuner_GetTS(struct firesat *firesat);
 
-extern int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport, int *has_ci);
+extern int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport);
 extern int AVCLNBControl(struct firesat *firesat, char voltage, char burst, char conttone, char nrdiseq, struct dvb_diseqc_master_cmd *diseqcmd);
 extern int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount);
 extern int AVCRegisterRemoteControl(struct firesat *firesat);
+extern int AVCTuner_Host2Ca(struct firesat *firesat);
+extern int avc_ca_app_info(struct firesat *firesat, char *app_info,
+                          int *length);
+extern int avc_ca_info(struct firesat *firesat, char *app_info, int *length);
+extern int avc_ca_reset(struct firesat *firesat);
+extern int avc_ca_pmt(struct firesat *firesat, char *app_info, int length);
+extern int avc_ca_get_time_date(struct firesat *firesat, int *interval);
+extern int avc_ca_enter_menu(struct firesat *firesat);
+extern int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object,
+                         int *length);
 
 #endif
 
index 37b91f3f7ff157192c31a22219fa101fdb0b6a8d..a1291caa0674af2f2b52000791a189fd0688b13b 100644 (file)
@@ -1,3 +1,15 @@
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) ?
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
 #include "cmp.h"
 #include <ieee1394.h>
 #include <nodemgr.h>
 
 typedef struct _OPCR
 {
-       BYTE PTPConnCount    : 6 ; // Point to point connect. counter
-       BYTE BrConnCount     : 1 ; // Broadcast connection counter
-       BYTE OnLine          : 1 ; // On Line
+       __u8 PTPConnCount    : 6 ; // Point to point connect. counter
+       __u8 BrConnCount     : 1 ; // Broadcast connection counter
+       __u8 OnLine          : 1 ; // On Line
 
-       BYTE ChNr            : 6 ; // Channel number
-       BYTE Res             : 2 ; // Reserved
+       __u8 ChNr            : 6 ; // Channel number
+       __u8 Res             : 2 ; // Reserved
 
-       BYTE PayloadHi       : 2 ; // Payoad high bits
-       BYTE OvhdID          : 4 ; // Overhead ID
-       BYTE DataRate        : 2 ; // Data Rate
+       __u8 PayloadHi       : 2 ; // Payoad high bits
+       __u8 OvhdID          : 4 ; // Overhead ID
+       __u8 DataRate        : 2 ; // Data Rate
 
-       BYTE PayloadLo           ; // Payoad low byte
+       __u8 PayloadLo           ; // Payoad low byte
 } OPCR ;
 
 #define FIRESAT_SPEED IEEE1394_SPEED_400
@@ -94,13 +106,13 @@ int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int i
        u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
        int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
 
-       printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid);
+/*     printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
 
        if (result < 0) {
                printk("%s: cannot read oPCR\n", __func__);
                return result;
        } else {
-               printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR);
+/*             printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
                do {
                        OPCR *hilf= (OPCR*) &test_oPCR;
 
@@ -134,8 +146,8 @@ int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int i
 
                                hilf->PTPConnCount++;
                                new_oPCR=test_oPCR;
-                               printk(KERN_INFO "%s: trying compare_swap...\n",__func__);
-                               printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR);
+/*                             printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
+/*                             printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
                                result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
 
                                if (result < 0) {
@@ -169,7 +181,7 @@ int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_ch
        u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
        int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
 
-       printk(KERN_INFO "%s\n",__func__);
+/*     printk(KERN_INFO "%s\n",__func__); */
 
        if (result < 0) {
                printk("%s: cannot read oPCR\n", __func__);
index 862d9553c5bcde3725ffbf8fe4925b40972133f9..821048db283b3cbec0a15862de711fbdbc3a4916 100644 (file)
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
 #include "firesat-ci.h"
 #include "firesat.h"
 #include "avc_api.h"
 
 #include <linux/dvb/ca.h>
 #include <dvbdev.h>
-/*
-static int firesat_ca_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) {
-       //struct firesat *firesat = (struct firesat*)((struct dvb_device*)file->private_data)->priv;
-       int err;
 
-//     printk(KERN_INFO "%s: ioctl %d\n",__func__,cmd);
+static unsigned int ca_debug = 0;
+module_param(ca_debug, int, 0644);
+MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)");
 
-       switch(cmd) {
-       case CA_RESET:
-               // TODO: Needs to be implemented with new AVC Vendor commands
+static int firesat_ca_ready(ANTENNA_INPUT_INFO *info)
+{
+       if (ca_debug != 0)
+               printk("%s: CaMmi=%d, CaInit=%d, CaError=%d, CaDvb=%d, "
+                      "CaModule=%d, CaAppInfo=%d, CaDateTime=%d, "
+                      "CaPmt=%d\n", __func__, info->CaMmi,
+                      info->CaInitializationStatus, info->CaErrorFlag,
+                      info->CaDvbFlag, info->CaModulePresentStatus,
+                      info->CaApplicationInfo,
+                      info->CaDateTimeRequest, info->CaPmtReply);
+       return info->CaInitializationStatus == 1 &&
+               info->CaErrorFlag == 0 &&
+               info->CaDvbFlag == 1 &&
+               info->CaModulePresentStatus == 1;
+}
+
+static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info)
+{
+       int flags = 0;
+       if (info->CaModulePresentStatus == 1)
+               flags |= CA_CI_MODULE_PRESENT;
+       if (info->CaInitializationStatus == 1 &&
+           info->CaErrorFlag == 0 &&
+           info->CaDvbFlag == 1)
+               flags |= CA_CI_MODULE_READY;
+       return flags;
+}
+
+static int firesat_ca_reset(struct firesat *firesat)
+{
+       if (ca_debug)
+               printk(KERN_INFO "%s: ioctl CA_RESET\n", __func__);
+       if (avc_ca_reset(firesat))
+               return -EFAULT;
+       return 0;
+}
+
+static int firesat_ca_get_caps(struct firesat *firesat, void *arg)
+{
+       struct ca_caps *cap_p = (struct ca_caps*)arg;
+       int err = 0;
+
+       cap_p->slot_num = 1;
+       cap_p->slot_type = CA_CI;
+       cap_p->descr_num = 1;
+       cap_p->descr_type = CA_ECD;
+       if (ca_debug)
+               printk(KERN_INFO "%s: ioctl CA_GET_CAP\n", __func__);
+       return err;
+}
+
+static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg)
+{
+       ANTENNA_INPUT_INFO info;
+       struct ca_slot_info *slot_p = (struct ca_slot_info*)arg;
+
+       if (ca_debug)
+               printk(KERN_INFO "%s: ioctl CA_GET_SLOT_INFO on slot %d.\n",
+                      __func__, slot_p->num);
+       if (AVCTunerStatus(firesat, &info))
+               return -EFAULT;
+
+       if (slot_p->num == 0) {
+               slot_p->type = CA_CI;
+               slot_p->flags = firesat_get_ca_flags(&info);
+       }
+       else {
+               return -EFAULT;
+       }
+       return 0;
+}
+
+static int firesat_ca_app_info(struct firesat *firesat, void *arg)
+{
+       struct ca_msg *reply_p = (struct ca_msg*)arg;
+       int i;
+
+       if (avc_ca_app_info(firesat, reply_p->msg, &reply_p->length))
+               return -EFAULT;
+       if (ca_debug) {
+               printk(KERN_INFO "%s: Creating TAG_APP_INFO message:",
+                      __func__);
+               for (i = 0; i < reply_p->length; i++)
+                       printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
+               printk("\n");
+               }
+       return 0;
+}
+
+static int firesat_ca_info(struct firesat *firesat, void *arg)
+{
+       struct ca_msg *reply_p = (struct ca_msg*)arg;
+       int i;
+
+       if (avc_ca_info(firesat, reply_p->msg, &reply_p->length))
+               return -EFAULT;
+       if (ca_debug) {
+               printk(KERN_INFO "%s: Creating TAG_CA_INFO message:",
+                      __func__);
+               for (i = 0; i < reply_p->length; i++)
+                       printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
+               printk("\n");
+       }
+       return 0;
+}
+
+static int firesat_ca_get_mmi(struct firesat *firesat, void *arg)
+{
+       struct ca_msg *reply_p = (struct ca_msg*)arg;
+       int i;
+
+       if (avc_ca_get_mmi(firesat, reply_p->msg, &reply_p->length))
+               return -EFAULT;
+       if (ca_debug) {
+               printk(KERN_INFO "%s: Creating MMI reply INFO message:",
+                      __func__);
+               for (i = 0; i < reply_p->length; i++)
+                       printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
+               printk("\n");
+       }
+       return 0;
+}
+
+static int firesat_ca_get_msg(struct firesat *firesat, void *arg)
+{
+       int err;
+       ANTENNA_INPUT_INFO info;
+
+       switch (firesat->ca_last_command) {
+       case TAG_APP_INFO_ENQUIRY:
+               err = firesat_ca_app_info(firesat, arg);
+               break;
+       case TAG_CA_INFO_ENQUIRY:
+               err = firesat_ca_info(firesat, arg);
                break;
-       case CA_GET_CAP: {
-               ca_caps_t *cap=(ca_caps_t*)parg;
-               cap->slot_num = 1;
-               cap->slot_type = CA_CI_LINK;
-               cap->descr_num = 1;
-               cap->descr_type = CA_DSS;
+       default:
+               if (AVCTunerStatus(firesat, &info))
+                       err = -EFAULT;
+               else if (info.CaMmi == 1) {
+                       err = firesat_ca_get_mmi(firesat, arg);
+               }
+               else {
+                       printk(KERN_INFO "%s: Unhandled message 0x%08X\n",
+                              __func__, firesat->ca_last_command);
+                       err = -EFAULT;
+               }
+       }
+       firesat->ca_last_command = 0;
+       return err;
+}
 
+static int firesat_ca_pmt(struct firesat *firesat, void *arg)
+{
+       struct ca_msg *msg_p = (struct ca_msg*)arg;
+       int data_pos;
+
+       if (msg_p->msg[3] & 0x80)
+               data_pos = (msg_p->msg[4] && 0x7F) + 4;
+       else
+               data_pos = 4;
+       if (avc_ca_pmt(firesat, &msg_p->msg[data_pos],
+                      msg_p->length - data_pos))
+               return -EFAULT;
+       return 0;
+}
+
+static int firesat_ca_send_msg(struct firesat *firesat, void *arg)
+{
+       int err;
+       struct ca_msg *msg_p = (struct ca_msg*)arg;
+
+       // Do we need a semaphore for this?
+       firesat->ca_last_command =
+               (msg_p->msg[0] << 16) + (msg_p->msg[1] << 8) + msg_p->msg[2];
+       switch (firesat->ca_last_command) {
+       case TAG_CA_PMT:
+               if (ca_debug != 0)
+                       printk(KERN_INFO "%s: Message received: TAG_CA_PMT\n",
+                              __func__);
+               err = firesat_ca_pmt(firesat, arg);
+               break;
+       case TAG_APP_INFO_ENQUIRY:
+               // This is all handled in ca_get_msg
+               if (ca_debug != 0)
+                       printk(KERN_INFO "%s: Message received: "
+                              "TAG_APP_INFO_ENQUIRY\n", __func__);
                err = 0;
                break;
-       }
-       case CA_GET_SLOT_INFO: {
-               ca_slot_info_t *slot=(ca_slot_info_t*)parg;
-               if(slot->num == 0) {
-                       slot->type = CA_CI | CA_CI_LINK | CA_DESCR;
-                       slot->flags = CA_CI_MODULE_PRESENT | CA_CI_MODULE_READY;
-               } else {
-                       slot->type = 0;
-                       slot->flags = 0;
-               }
+       case TAG_CA_INFO_ENQUIRY:
+               // This is all handled in ca_get_msg
+               if (ca_debug != 0)
+                       printk(KERN_INFO "%s: Message received: "
+                              "TAG_CA_APP_INFO_ENQUIRY\n", __func__);
                err = 0;
                break;
+       case TAG_ENTER_MENU:
+               if (ca_debug != 0)
+                       printk(KERN_INFO "%s: Entering CA menu.\n", __func__);
+               err = avc_ca_enter_menu(firesat);
+               break;
+       default:
+               printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n",
+                      __func__, firesat->ca_last_command);
+               err = -EFAULT;
        }
+       return err;
+}
+
+static int firesat_ca_ioctl(struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg)
+{
+       struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
+       struct firesat *firesat = dvbdev->priv;
+       int err;
+       ANTENNA_INPUT_INFO info;
+
+       switch(cmd) {
+       case CA_RESET:
+               err = firesat_ca_reset(firesat);
+               break;
+       case CA_GET_CAP:
+               err = firesat_ca_get_caps(firesat, arg);
+               break;
+       case CA_GET_SLOT_INFO:
+               err = firesat_ca_get_slot_info(firesat, arg);
+               break;
+       case CA_GET_MSG:
+               err = firesat_ca_get_msg(firesat, arg);
+               break;
+       case CA_SEND_MSG:
+               err = firesat_ca_send_msg(firesat, arg);
+               break;
        default:
-                       err=-EINVAL;
+               printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__,
+                      cmd);
+               err = -EOPNOTSUPP;
        }
+
+       if (AVCTunerStatus(firesat, &info))
+               return err;
+
+       firesat_ca_ready(&info);
+
        return err;
 }
-*/
 
-static int firesat_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) {
-       //return dvb_usercopy(inode, file, cmd, arg, firesat_ca_do_ioctl);
-       return dvb_generic_ioctl(inode, file, cmd, arg);
+static int firesat_get_date_time_request(struct firesat *firesat)
+{
+       if (ca_debug)
+               printk(KERN_INFO "%s: Retrieving Time/Date request\n",
+                      __func__);
+       if (avc_ca_get_time_date(firesat, &firesat->ca_time_interval))
+               return -EFAULT;
+       if (ca_debug)
+               printk(KERN_INFO "%s: Time/Date interval is %d\n",
+                      __func__, firesat->ca_time_interval);
+
+       return 0;
 }
 
-static int firesat_ca_io_open(struct inode *inode, struct file *file) {
-       printk(KERN_INFO "%s!\n",__func__);
+static int firesat_ca_io_open(struct inode *inode, struct file *file)
+{
+       if (ca_debug != 0)
+               printk(KERN_INFO "%s\n",__func__);
        return dvb_generic_open(inode, file);
 }
 
-static int firesat_ca_io_release(struct inode *inode, struct file *file) {
-       printk(KERN_INFO "%s!\n",__func__);
+static int firesat_ca_io_release(struct inode *inode, struct file *file)
+{
+       if (ca_debug != 0)
+               printk(KERN_INFO "%s\n",__func__);
        return dvb_generic_release(inode, file);
 }
 
-static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) {
-//     printk(KERN_INFO "%s!\n",__func__);
+static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait)
+{
+       if (ca_debug != 0)
+               printk(KERN_INFO "%s\n",__func__);
        return POLLIN;
 }
 
@@ -68,7 +305,7 @@ static struct file_operations firesat_ca_fops = {
        .owner = THIS_MODULE,
        .read = NULL, // There is no low level read anymore
        .write = NULL, // There is no low level write anymore
-       .ioctl = firesat_ca_ioctl,
+       .ioctl = dvb_generic_ioctl,
        .open = firesat_ca_io_open,
        .release = firesat_ca_io_release,
        .poll = firesat_ca_io_poll,
@@ -80,16 +317,37 @@ static struct dvb_device firesat_ca = {
        .readers = 1,
        .writers = 1,
        .fops = &firesat_ca_fops,
+       .kernel_ioctl = firesat_ca_ioctl,
 };
 
-int firesat_ca_init(struct firesat *firesat) {
-       int ret = dvb_register_device(firesat->adapter, &firesat->cadev, &firesat_ca, firesat, DVB_DEVICE_CA);
-       if(ret) return ret;
+int firesat_ca_init(struct firesat *firesat)
+{
+       int err;
+       ANTENNA_INPUT_INFO info;
 
-       // avoid unnecessary delays, we're not talking to the CI yet anyways
-       return 0;
+       if (AVCTunerStatus(firesat, &info))
+               return -EINVAL;
+
+       if (firesat_ca_ready(&info)) {
+               err = dvb_register_device(firesat->adapter,
+                                             &firesat->cadev,
+                                             &firesat_ca, firesat,
+                                             DVB_DEVICE_CA);
+
+               if (info.CaApplicationInfo == 0)
+                       printk(KERN_ERR "%s: CaApplicationInfo is not set.\n",
+                              __func__);
+               if (info.CaDateTimeRequest == 1)
+                       firesat_get_date_time_request(firesat);
+       }
+       else
+               err = -EFAULT;
+
+       return err;
 }
 
-void firesat_ca_release(struct firesat *firesat) {
+void firesat_ca_release(struct firesat *firesat)
+{
+       if (firesat->cadev)
        dvb_unregister_device(firesat->cadev);
 }
index d1e2ce37063e1f1487a3284134a11b92b7097cc7..1beed177d98bce8a48059ac313fc1ed7f87109c9 100644 (file)
@@ -1,3 +1,15 @@
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) ?
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
 #ifndef __FIRESAT_H
 #define __FIRESAT_H
 
 #include "dvb_demux.h"
 #include "dvb_net.h"
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
 #include <linux/semaphore.h>
+#endif
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/dmx.h>
+#include <iso.h>
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w, v)
+#else
+#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w)
+#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(x)
+#endif
+
+/*****************************************************************
+ * CA message command constants from en50221_app_tags.h of libdvb
+ *****************************************************************/
+/*     Resource Manager                */
+#define TAG_PROFILE_ENQUIRY            0x9f8010
+#define TAG_PROFILE                    0x9f8011
+#define TAG_PROFILE_CHANGE             0x9f8012
+
+/*     Application Info                */
+#define TAG_APP_INFO_ENQUIRY           0x9f8020
+#define TAG_APP_INFO                   0x9f8021
+#define TAG_ENTER_MENU                 0x9f8022
+
+/*     CA Support                      */
+#define TAG_CA_INFO_ENQUIRY            0x9f8030
+#define TAG_CA_INFO                    0x9f8031
+#define TAG_CA_PMT                     0x9f8032
+#define TAG_CA_PMT_REPLY               0x9f8033
+
+/*     Host Control                    */
+#define TAG_TUNE                       0x9f8400
+#define TAG_REPLACE                    0x9f8401
+#define TAG_CLEAR_REPLACE              0x9f8402
+#define TAG_ASK_RELEASE                        0x9f8403
+
+/*     Date and Time                   */
+#define TAG_DATE_TIME_ENQUIRY          0x9f8440
+#define TAG_DATE_TIME                  0x9f8441
+
+/*     Man Machine Interface (MMI)     */
+#define TAG_CLOSE_MMI                  0x9f8800
+#define TAG_DISPLAY_CONTROL            0x9f8801
+#define TAG_DISPLAY_REPLY              0x9f8802
+#define TAG_TEXT_LAST                  0x9f8803
+#define TAG_TEXT_MORE                  0x9f8804
+#define TAG_KEYPAD_CONTROL             0x9f8805
+#define TAG_KEYPRESS                   0x9f8806
+#define TAG_ENQUIRY                    0x9f8807
+#define TAG_ANSWER                     0x9f8808
+#define TAG_MENU_LAST                  0x9f8809
+#define TAG_MENU_MORE                  0x9f880a
+#define TAG_MENU_ANSWER                        0x9f880b
+#define TAG_LIST_LAST                  0x9f880c
+#define TAG_LIST_MORE                  0x9f880d
+#define TAG_SUBTITLE_SEGMENT_LAST      0x9f880e
+#define TAG_SUBTITLE_SEGMENT_MORE      0x9f880f
+#define TAG_DISPLAY_MESSAGE            0x9f8810
+#define TAG_SCENE_END_MARK             0x9f8811
+#define TAG_SCENE_DONE                 0x9f8812
+#define TAG_SCENE_CONTROL              0x9f8813
+#define TAG_SUBTITLE_DOWNLOAD_LAST     0x9f8814
+#define TAG_SUBTITLE_DOWNLOAD_MORE     0x9f8815
+#define TAG_FLUSH_DOWNLOAD             0x9f8816
+#define TAG_DOWNLOAD_REPLY             0x9f8817
+
+/*     Low Speed Communications        */
+#define TAG_COMMS_COMMAND              0x9f8c00
+#define TAG_CONNECTION_DESCRIPTOR      0x9f8c01
+#define TAG_COMMS_REPLY                        0x9f8c02
+#define TAG_COMMS_SEND_LAST            0x9f8c03
+#define TAG_COMMS_SEND_MORE            0x9f8c04
+#define TAG_COMMS_RECV_LAST            0x9f8c05
+#define TAG_COMMS_RECV_MORE            0x9f8c06
+
+/* Authentication */
+#define TAG_AUTH_REQ                   0x9f8200
+#define TAG_AUTH_RESP                  0x9f8201
+
+/* Teletext */
+#define TAG_TELETEXT_EBU               0x9f9000
+
+/* Smartcard */
+#define TAG_SMARTCARD_COMMAND          0x9f8e00
+#define TAG_SMARTCARD_REPLY            0x9f8e01
+#define TAG_SMARTCARD_SEND             0x9f8e02
+#define TAG_SMARTCARD_RCV              0x9f8e03
+
+/* EPG */
+#define TAG_EPG_ENQUIRY                0x9f8f00
+#define TAG_EPG_REPLY                  0x9f8f01
+
 
 enum model_type {
-    FireSAT_DVB_S = 1,
-    FireSAT_DVB_C = 2,
-    FireSAT_DVB_T = 3,
-    FireSAT_DVB_S2 = 4
+       FireSAT_DVB_S = 1,
+       FireSAT_DVB_C = 2,
+       FireSAT_DVB_T = 3,
+       FireSAT_DVB_S2 = 4
 };
 
 struct firesat {
@@ -31,12 +136,13 @@ struct firesat {
        struct dvb_frontend             *fe;
 
        struct dvb_device               *cadev;
-       int                             has_ci;
+       int                             ca_last_command;
+       int                             ca_time_interval;
 
        struct semaphore                avc_sem;
-       atomic_t                                avc_reply_received;
+       atomic_t                        avc_reply_received;
 
-       atomic_t                                reschedule_remotecontrol;
+       atomic_t                        reschedule_remotecontrol;
 
        struct firesat_channel {
                struct firesat *firesat;
@@ -53,20 +159,54 @@ struct firesat {
        void *respfrm;
        int resp_length;
 
-//    nodeid_t nodeid;
-    struct hpsb_host *host;
+       struct hpsb_host *host;
        u64 guid;                       /* GUID of this node */
        u32 guid_vendor_id;             /* Top 24bits of guid */
        struct node_entry *nodeentry;
 
-    enum model_type type;
-    char subunit;
+       enum model_type type;
+       char subunit;
        fe_sec_voltage_t voltage;
        fe_sec_tone_mode_t tone;
 
        int isochannel;
+       struct hpsb_iso *iso_handle;
+
+       struct list_head list;
+};
+
+struct firewireheader {
+       union {
+               struct {
+                       __u8 tcode:4;
+                       __u8 sy:4;
+                       __u8 tag:2;
+                       __u8 channel:6;
+
+                       __u8 length_l;
+                       __u8 length_h;
+               } hdr;
+               __u32 val;
+       };
+};
 
-    struct list_head list;
+struct CIPHeader {
+       union {
+               struct {
+                       __u8 syncbits:2;
+                       __u8 sid:6;
+                       __u8 dbs;
+                       __u8 fn:2;
+                       __u8 qpc:3;
+                       __u8 sph:1;
+                       __u8 rsv:2;
+                       __u8 dbc;
+                       __u8 syncbits2:2;
+                       __u8 fmt:6;
+                       __u32 fdf:24;
+               } cip;
+               __u64 val;
+       };
 };
 
 extern struct list_head firesat_list;
@@ -76,11 +216,15 @@ extern spinlock_t firesat_list_lock;
 extern int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed);
 extern int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
 extern int firesat_dvbdev_init(struct firesat *firesat,
-                               struct device *dev,
-                               struct dvb_frontend *fe);
+                              struct device *dev,
+                              struct dvb_frontend *fe);
 
 /* firesat_fe.c */
-extern int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe);
+extern int firesat_frontend_attach(struct firesat *firesat,
+                                  struct dvb_frontend *fe);
 
+/* firesat_iso.c */
+extern int setup_iso_channel(struct firesat *firesat);
+extern void tear_down_iso_channel(struct firesat *firesat);
 
 #endif
index dcac70a2991ef58805f04b97c4f90b5a84a13479..04ad31666fb9439fc29f3a7cb34817fed6303b03 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2004 Andreas Monitzer <andy@monitzer.com>
  * Copyright (c) 2007-2008 Ben Backx <ben@bbackx.com>
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License as
@@ -18,7 +19,6 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
-#include <linux/semaphore.h>
 #include <ieee1394_hotplug.h>
 #include <nodemgr.h>
 #include <highlevel.h>
@@ -79,11 +79,6 @@ static void firesat_add_host(struct hpsb_host *host);
 static void firesat_remove_host(struct hpsb_host *host);
 static void firesat_host_reset(struct hpsb_host *host);
 
-/*
-static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
-                       size_t length);
-*/
-
 static void fcp_request(struct hpsb_host *host,
                        int nodeid,
                        int direction,
@@ -96,7 +91,6 @@ static struct hpsb_highlevel firesat_highlevel = {
        .add_host       = firesat_add_host,
        .remove_host    = firesat_remove_host,
        .host_reset     = firesat_host_reset,
-// FIXME       .iso_receive =  iso_receive,
        .fcp_request    = fcp_request,
 };
 
@@ -127,100 +121,6 @@ static void firesat_host_reset(struct hpsb_host *host)
     printk(KERN_INFO "FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host->node_id,host->nodes_active);
 }
 
-struct firewireheader {
-    union {
-       struct {
-           unsigned char tcode:4;
-           unsigned char sy:4;
-           unsigned char tag:2;
-           unsigned char channel:6;
-
-           unsigned char length_l;
-           unsigned char length_h;
-       } hdr;
-       unsigned long val;
-    };
-};
-
-struct CIPHeader {
-    union {
-       struct {
-           unsigned char syncbits:2;
-           unsigned char sid:6;
-           unsigned char dbs;
-           unsigned char fn:2;
-           unsigned char qpc:3;
-           unsigned char sph:1;
-           unsigned char rsv:2;
-           unsigned char dbc;
-           unsigned char syncbits2:2;
-           unsigned char fmt:6;
-           unsigned long fdf:24;
-       } cip;
-       unsigned long long val;
-    };
-};
-
-struct MPEG2Header {
-    union {
-       struct {
-           unsigned char sync; // must be 0x47
-           unsigned char transport_error_indicator:1;
-           unsigned char payload_unit_start_indicator:1;
-           unsigned char transport_priority:1;
-           unsigned short pid:13;
-           unsigned char transport_scrambling_control:2;
-           unsigned char adaption_field_control:2;
-           unsigned char continuity_counter:4;
-       } hdr;
-       unsigned long val;
-    };
-};
-
-#if 0
-static void iso_receive(struct hpsb_host *host,
-                       int channel,
-                       quadlet_t *data,
-                       size_t length)
-{
-       struct firesat *firesat = NULL;
-       struct firesat *firesat_entry;
-       unsigned long flags;
-
-//    printk(KERN_INFO "FireSAT iso_receive: channel %d, length = %d\n", channel, length);
-
-       if (length <= 12)
-               return; // ignore empty packets
-       else {
-
-               spin_lock_irqsave(&firesat_list_lock, flags);
-               list_for_each_entry(firesat_entry,&firesat_list,list) {
-                       if(firesat_entry->host == host && firesat_entry->isochannel == channel) {
-                               firesat=firesat_entry;
-                               break;
-                       }
-               }
-               spin_unlock_irqrestore(&firesat_list_lock, flags);
-
-               if (firesat) {
-                       char *buf= ((char*)data) + sizeof(struct firewireheader)+sizeof(struct CIPHeader);
-                       int count = (length-sizeof(struct CIPHeader)) / 192;
-
-//                     printk(KERN_INFO "%s: length = %u\n data[0] = %08x\n data[1] = %08x\n data[2] = %08x\n data[3] = %08x\n data[4] = %08x\n",__func__, length, data[0],data[1],data[2],data[3],data[4]);
-
-                       while (count--) {
-
-                               if (buf[sizeof(quadlet_t) /*timestamp*/] == 0x47)
-                                       dvb_dmx_swfilter_packets(&firesat->demux, &buf[sizeof(quadlet_t)], 1);
-                               else
-                                       printk("%s: invalid packet, skipping\n", __func__);
-                               buf += 188 + sizeof (quadlet_t) /* timestamp */;
-                       }
-               }
-       }
-}
-#endif
-
 static void fcp_request(struct hpsb_host *host,
                        int nodeid,
                        int direction,
@@ -251,7 +151,9 @@ static void fcp_request(struct hpsb_host *host,
                        AVCRecv(firesat,data,length);
                else
                        printk("%s: received fcp request from unknown source, ignored\n", __func__);
-       } // else ignore
+       }
+       else
+         printk("%s: received invalid fcp request, ignored\n", __func__);
 }
 
 static int firesat_probe(struct device *dev)
@@ -260,7 +162,6 @@ static int firesat_probe(struct device *dev)
        struct firesat *firesat;
        struct dvb_frontend *fe;
        unsigned long flags;
-       int result;
        unsigned char subunitcount = 0xff, subunit;
        struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL);
        int kv_len;
@@ -298,6 +199,7 @@ static int firesat_probe(struct device *dev)
                firesat->isochannel     = -1;
                firesat->tone           = 0xff;
                firesat->voltage        = 0xff;
+               firesat->fe             = fe;
 
                if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) {
                        printk("%s: couldn't allocate memory.\n", __func__);
@@ -357,7 +259,7 @@ static int firesat_probe(struct device *dev)
                }
                kfree(kv_buf);
 
-               if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type, &firesat->has_ci)) {
+               if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type)) {
                        printk("%s: cannot identify subunit %d\n", __func__, subunit);
                        spin_lock_irqsave(&firesat_list_lock, flags);
                        list_del(&firesat->list);
@@ -382,7 +284,6 @@ static int firesat_probe(struct device *dev)
 static int firesat_remove(struct device *dev)
 {
        struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-       struct dvb_frontend* fe;
        struct firesat **firesats = ud->device.driver_data;
        int k;
        unsigned long flags;
@@ -390,18 +291,9 @@ static int firesat_remove(struct device *dev)
        if (firesats) {
                for (k = 0; k < 2; k++)
                        if (firesats[k]) {
-                               if (firesats[k]->has_ci)
                                        firesat_ca_release(firesats[k]);
 
-#if 0
-                               if (!(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
-                                       fe->ops = firesat_ops;
-                                       fe->dvb = firesats[k]->adapter;
-
-                                       dvb_unregister_frontend(fe);
-                                       kfree(fe);
-                               }
-#endif
+                               dvb_unregister_frontend(firesats[k]->fe);
                                dvb_net_release(&firesats[k]->dvbnet);
                                firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx);
                                firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend);
@@ -413,6 +305,7 @@ static int firesat_remove(struct device *dev)
                                list_del(&firesats[k]->list);
                                spin_unlock_irqrestore(&firesat_list_lock, flags);
 
+                               kfree(firesats[k]->fe);
                                kfree(firesats[k]->adapter);
                                kfree(firesats[k]->respfrm);
                                kfree(firesats[k]);
index 38aad0812881877c44afe6300d6f13726a546a84..9e87402289a6465e53668133a4ea4a3ace970995 100644 (file)
@@ -1,3 +1,15 @@
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) ?
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
@@ -6,7 +18,6 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
-#include <linux/semaphore.h>
 #include <ieee1394_hotplug.h>
 #include <nodemgr.h>
 #include <highlevel.h>
@@ -26,13 +37,13 @@ static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat)
 {
        int k;
 
-       printk(KERN_INFO "%s\n", __func__);
+       //printk(KERN_INFO "%s\n", __func__);
 
        if (down_interruptible(&firesat->demux_sem))
                return NULL;
 
        for (k = 0; k < 16; k++) {
-               printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid);
+               //printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid);
 
                if (firesat->channel[k].active == 0) {
                        firesat->channel[k].active = 1;
@@ -82,14 +93,15 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        int pidc,k;
        u16 pids[16];
 
-       printk(KERN_INFO "%s (pid %u)\n",__func__,dvbdmxfeed->pid);
+//     printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
 
        switch (dvbdmxfeed->type) {
        case DMX_TYPE_TS:
        case DMX_TYPE_SEC:
                break;
        default:
-               printk("%s: invalid type %u\n",__func__,dvbdmxfeed->type);
+               printk(KERN_ERR "%s: invalid type %u\n",
+                      __func__, dvbdmxfeed->type);
                return -EINVAL;
        }
 
@@ -110,7 +122,8 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
                        channel = firesat_channel_allocate(firesat);
                        break;
                default:
-                       printk("%s: invalid pes type %u\n",__func__, dvbdmxfeed->pes_type);
+                       printk(KERN_ERR "%s: invalid pes type %u\n",
+                              __func__, dvbdmxfeed->pes_type);
                        return -EINVAL;
                }
        } else {
@@ -118,7 +131,7 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        }
 
        if (!channel) {
-               printk("%s: busy!\n", __func__);
+               printk(KERN_ERR "%s: busy!\n", __func__);
                return -EBUSY;
        }
 
@@ -131,22 +144,23 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 
        if (firesat_channel_collect(firesat, &pidc, pids)) {
                firesat_channel_release(firesat, channel);
+               printk(KERN_ERR "%s: could not collect pids!\n", __func__);
                return -EINTR;
        }
 
        if(dvbdmxfeed->pid == 8192) {
-               if((k=AVCTuner_GetTS(firesat))) {
+               if((k = AVCTuner_GetTS(firesat))) {
                        firesat_channel_release(firesat, channel);
                        printk("%s: AVCTuner_GetTS failed with error %d\n",
-                               __func__,k);
+                              __func__, k);
                        return k;
                }
        }
        else {
-               if((k=AVCTuner_SetPIDs(firesat, pidc, pids))) {
+               if((k = AVCTuner_SetPIDs(firesat, pidc, pids))) {
                        firesat_channel_release(firesat, channel);
                        printk("%s: AVCTuner_SetPIDs failed with error %d\n",
-                               __func__,k);
+                              __func__, k);
                        return k;
                }
        }
@@ -161,7 +175,7 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        int k, l = 0;
        u16 pids[16];
 
-       printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
+       //printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
 
        if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) &&
                                (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
@@ -189,12 +203,13 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 
        // list except channel to be removed
        for (k = 0; k < 16; k++)
-               if (firesat->channel[k].active == 1)
+               if (firesat->channel[k].active == 1) {
                        if (&firesat->channel[k] !=
                                (struct firesat_channel *)dvbdmxfeed->priv)
                                pids[l++] = firesat->channel[k].pid;
                        else
                                firesat->channel[k].active = 0;
+               }
 
        if ((k = AVCTuner_SetPIDs(firesat, l, pids))) {
                up(&firesat->demux_sem);
@@ -214,8 +229,6 @@ int firesat_dvbdev_init(struct firesat *firesat,
 {
        int result;
 
-               firesat->has_ci = 1; // TEMP workaround
-
 #if 0
                switch (firesat->type) {
                case FireSAT_DVB_S:
@@ -254,7 +267,7 @@ int firesat_dvbdev_init(struct firesat *firesat,
                        return -ENOMEM;
                }
 
-               if ((result = dvb_register_adapter(firesat->adapter,
+               if ((result = DVB_REGISTER_ADAPTER(firesat->adapter,
                                                   firesat->model_name,
                                                   THIS_MODULE,
                                                   dev, adapter_nr)) < 0) {
@@ -271,6 +284,7 @@ int firesat_dvbdev_init(struct firesat *firesat,
                        return result;
                }
 
+               memset(&firesat->demux, 0, sizeof(struct dvb_demux));
                firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/;
 
                firesat->demux.priv             = (void *)firesat;
@@ -343,8 +357,9 @@ int firesat_dvbdev_init(struct firesat *firesat,
                        return result;
                }
 
-               if (firesat->has_ci)
                        firesat_ca_init(firesat);
 
                return 0;
 }
+
+
index f7abd38f0014a1517dba8b432713f6ca291115d3..1c86c3e613734d5db9f28b6ccb299aed7049817b 100644 (file)
@@ -1,3 +1,15 @@
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) ?
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
@@ -6,7 +18,6 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
-#include <linux/semaphore.h>
 #include <ieee1394_hotplug.h>
 #include <nodemgr.h>
 #include <highlevel.h>
 
 static int firesat_dvb_init(struct dvb_frontend *fe)
 {
+       int result;
        struct firesat *firesat = fe->sec_priv;
-       printk("fdi: 1\n");
+//     printk("fdi: 1\n");
        firesat->isochannel = firesat->adapter->num; //<< 1 | (firesat->subunit & 0x1); // ### ask IRM
-       printk("fdi: 2\n");
-       try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel);
-       printk("fdi: 3\n");
-//FIXME        hpsb_listen_channel(&firesat_highlevel, firesat->host, firesat->isochannel);
-       printk("fdi: 4\n");
-       return 0;
+//     printk("fdi: 2\n");
+       result = try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel);
+       if (result != 0) {
+               printk(KERN_ERR "Could not establish point to point "
+                      "connection.\n");
+               return -1;
+       }
+//     printk("fdi: 3\n");
+
+       result = setup_iso_channel(firesat);
+//     printk("fdi: 4. Result was %d\n", result);
+       return result;
 }
 
 static int firesat_sleep(struct dvb_frontend *fe)
 {
        struct firesat *firesat = fe->sec_priv;
 
-//FIXME        hpsb_unlisten_channel(&firesat_highlevel, firesat->host, firesat->isochannel);
+       tear_down_iso_channel(firesat);
        try_CMPBreakPPconnection(firesat, firesat->subunit, firesat->isochannel);
        firesat->isochannel = -1;
        return 0;
@@ -83,19 +101,20 @@ static int firesat_read_status (struct dvb_frontend *fe, fe_status_t *status)
        if (AVCTunerStatus(firesat, &info))
                return -EINVAL;
 
-       if (info.NoRF)
+       if (info.NoRF) {
                *status = 0;
-       else
-               *status = *status = FE_HAS_SIGNAL       |
-                                   FE_HAS_VITERBI      |
-                                   FE_HAS_SYNC         |
-                                   FE_HAS_CARRIER      |
-                                   FE_HAS_LOCK;
+       } else {
+               *status = FE_HAS_SIGNAL |
+                       FE_HAS_VITERBI  |
+                       FE_HAS_SYNC     |
+                       FE_HAS_CARRIER  |
+                       FE_HAS_LOCK;
+       }
 
        return 0;
 }
 
-static int firesat_read_ber (struct dvb_frontend *fe, u32 *ber)
+static int firesat_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct firesat *firesat = fe->sec_priv;
        ANTENNA_INPUT_INFO info;
@@ -103,10 +122,10 @@ static int firesat_read_ber (struct dvb_frontend *fe, u32 *ber)
        if (AVCTunerStatus(firesat, &info))
                return -EINVAL;
 
-       *ber = ((info.BER[0] << 24) & 0xff)     |
-              ((info.BER[1] << 16) & 0xff)     |
-              ((info.BER[2] << 8) & 0xff)      |
-               (info.BER[3] & 0xff);
+       *ber = (info.BER[0] << 24) |
+               (info.BER[1] << 16) |
+               (info.BER[2] <<  8) |
+               info.BER[3];
 
        return 0;
 }
@@ -115,19 +134,29 @@ static int firesat_read_signal_strength (struct dvb_frontend *fe, u16 *strength)
 {
        struct firesat *firesat = fe->sec_priv;
        ANTENNA_INPUT_INFO info;
-       u16 *signal = strength;
 
        if (AVCTunerStatus(firesat, &info))
                return -EINVAL;
 
-       *signal = info.SignalStrength;
+       *strength = info.SignalStrength << 8;
 
        return 0;
 }
 
 static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       return -EOPNOTSUPP;
+       struct firesat *firesat = fe->sec_priv;
+       ANTENNA_INPUT_INFO info;
+
+       if (AVCTunerStatus(firesat, &info))
+               return -EINVAL;
+
+       *snr = (info.CarrierNoiseRatio[0] << 8) +
+               info.CarrierNoiseRatio[1];
+       *snr *= 257;
+       // C/N[dB] = -10 * log10(snr / 65535)
+
+       return 0;
 }
 
 static int firesat_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -192,14 +221,13 @@ int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe)
                firesat->frontend_info = &firesat_T_frontend_info;
                break;
        default:
-//             printk("%s: unknown model type 0x%x on subunit %d!\n",
-//                     __func__, firesat->type,subunit);
                printk("%s: unknown model type 0x%x !\n",
                        __func__, firesat->type);
                firesat->model_name = "Unknown";
                firesat->frontend_info = NULL;
        }
        fe->ops = firesat_ops;
+       fe->ops.info = *(firesat->frontend_info);
        fe->dvb = firesat->adapter;
 
        return 0;
diff --git a/drivers/media/dvb/firesat/firesat_iso.c b/drivers/media/dvb/firesat/firesat_iso.c
new file mode 100644 (file)
index 0000000..15e23cf
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include "firesat.h"
+
+static void rawiso_activity_cb(struct hpsb_iso *iso);
+
+void tear_down_iso_channel(struct firesat *firesat)
+{
+       if (firesat->iso_handle != NULL) {
+               hpsb_iso_stop(firesat->iso_handle);
+               hpsb_iso_shutdown(firesat->iso_handle);
+       }
+       firesat->iso_handle = NULL;
+}
+
+int setup_iso_channel(struct firesat *firesat)
+{
+       int result;
+       firesat->iso_handle =
+               hpsb_iso_recv_init(firesat->host,
+                                  256 * 200, //data_buf_size,
+                                  256, //buf_packets,
+                                  firesat->isochannel,
+                                  HPSB_ISO_DMA_DEFAULT, //dma_mode,
+                                  -1, //stat.config.irq_interval,
+                                  rawiso_activity_cb);
+       if (firesat->iso_handle == NULL) {
+               printk(KERN_ERR "Cannot initialize iso receive.\n");
+               return -EINVAL;
+       }
+       result = hpsb_iso_recv_start(firesat->iso_handle, -1, -1, 0);
+       if (result != 0) {
+               printk(KERN_ERR "Cannot start iso receive.\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void rawiso_activity_cb(struct hpsb_iso *iso)
+{
+       unsigned int num;
+       unsigned int i;
+/*     unsigned int j; */
+       unsigned int packet;
+       unsigned long flags;
+       struct firesat *firesat = NULL;
+       struct firesat *firesat_iterator;
+
+       spin_lock_irqsave(&firesat_list_lock, flags);
+       list_for_each_entry(firesat_iterator, &firesat_list, list) {
+               if(firesat_iterator->iso_handle == iso) {
+                       firesat = firesat_iterator;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&firesat_list_lock, flags);
+
+       if (firesat) {
+               packet = iso->first_packet;
+               num = hpsb_iso_n_ready(iso);
+               for (i = 0; i < num; i++,
+                            packet = (packet + 1) % iso->buf_packets) {
+                       unsigned char *buf =
+                               dma_region_i(&iso->data_buf, unsigned char,
+                                            iso->infos[packet].offset +
+                                            sizeof(struct CIPHeader));
+                       int count = (iso->infos[packet].len -
+                                    sizeof(struct CIPHeader)) /
+                               (188 + sizeof(struct firewireheader));
+                       if (iso->infos[packet].len <= sizeof(struct CIPHeader))
+                               continue; // ignore empty packet
+/*                     printk("%s: Handling packets (%d): ", __func__, */
+/*                            iso->infos[packet].len); */
+/*                     for (j = 0; j < iso->infos[packet].len - */
+/*                                  sizeof(struct CIPHeader); j++) */
+/*                             printk("%02X,", buf[j]); */
+/*                     printk("\n"); */
+                       while (count --) {
+                               if (buf[sizeof(struct firewireheader)] == 0x47)
+                                       dvb_dmx_swfilter_packets(&firesat->demux,
+                                                                &buf[sizeof(struct firewireheader)], 1);
+                               else
+                                       printk("%s: invalid packet, skipping\n", __func__);
+                               buf += 188 + sizeof(struct firewireheader);
+
+                       }
+
+               }
+               hpsb_iso_recv_release_packets(iso, num);
+       }
+       else {
+               printk("%s: packets for unknown iso channel, skipping\n",
+                      __func__);
+               hpsb_iso_recv_release_packets(iso, hpsb_iso_n_ready(iso));
+       }
+}
+