firesat: update isochronous interface, add CI support

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)
diff --git a/drivers/media/dvb/firesat/Makefile b/drivers/media/dvb/firesat/Makefile
index fdf8687..be7701b 100644
--- a/drivers/media/dvb/firesat/Makefile
+++ b/drivers/media/dvb/firesat/Makefile
@@ -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	\
diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c
index cd79c80..273c723 100644
--- a/drivers/media/dvb/firesat/avc_api.c
+++ b/drivers/media/dvb/firesat/avc_api.c
@@ -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"
 
@@ -22,6 +24,10 @@
 #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 @@
 	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 @@
 	}
 
 	/* 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 @@
 
 	// remote control handling
 
+#if 0
 	AVCRspFrm *RspFrm = (AVCRspFrm*)data;
 
 	if(/*RspFrm->length >= 8 && ###*/
@@ -155,21 +290,21 @@
 			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 @@
 
 // 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 @@
 	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 @@
 			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 @@
 		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 @@
 			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 @@
 			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 @@
 	if((k=AVCWrite(firesat,&CmdFrm,&RspFrm)))
 		return k;
 
-//	msleep(250);
 	mdelay(500);
 
 	if(status)
@@ -504,13 +632,12 @@
 	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 @@
 	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]
+	CmdFrm.operand[4]  = 0x00; // system_specific_multiplex selection_length
+	CmdFrm.operand[5]  = pidc; // Nr_of_dsd_sel_specs
 
-	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)
+	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 @@
 			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 @@
 	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 @@
 	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 @@
 	}
 	if(systemId)
 		*systemId = RspFrm.operand[7];
-	if(has_ci)
-		*has_ci = (RspFrm.operand[14] >> 4) & 0x1;
 	return 0;
 }
 
@@ -679,14 +766,13 @@
 	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 @@
 		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 @@
 {
 	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;
+}
diff --git a/drivers/media/dvb/firesat/avc_api.h b/drivers/media/dvb/firesat/avc_api.h
index f9a190a..0416656 100644
--- a/drivers/media/dvb/firesat/avc_api.h
+++ b/drivers/media/dvb/firesat/avc_api.h
@@ -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
  ***************************************************************************/
 
@@ -27,12 +28,10 @@
 
 #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 _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 _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 _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 @@
 #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 @@
 #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 {
-	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
 {
 #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
 {
-		 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 @@
 	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 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
 
diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c
index 37b91f3..a1291caa 100644
--- a/drivers/media/dvb/firesat/cmp.c
+++ b/drivers/media/dvb/firesat/cmp.c
@@ -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>
@@ -10,18 +22,18 @@
 
 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 @@
 	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 @@
 
 				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 @@
 	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__);
diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c
index 862d955..821048d 100644
--- a/drivers/media/dvb/firesat/firesat-ci.c
+++ b/drivers/media/dvb/firesat/firesat-ci.c
@@ -1,66 +1,303 @@
+/*
+ * 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
-		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;
+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;
+}
 
-		err = 0;
-		break;
+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);
 	}
-	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;
+	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;
+	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 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:
-			err=-EINVAL;
+		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, 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_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:
+		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_io_open(struct inode *inode, struct file *file) {
-	printk(KERN_INFO "%s!\n",__func__);
+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)
+{
+	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 @@
 	.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 @@
 	.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);
 }
diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h
index d1e2ce3..1beed17 100644
--- a/drivers/media/dvb/firesat/firesat.h
+++ b/drivers/media/dvb/firesat/firesat.h
@@ -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
 
@@ -6,15 +18,108 @@
 #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 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 @@
 	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 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 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 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
diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c
index dcac70a..04ad316 100644
--- a/drivers/media/dvb/firesat/firesat_1394.c
+++ b/drivers/media/dvb/firesat/firesat_1394.c
@@ -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_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 @@
 	.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 @@
     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 @@
 			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 @@
 	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 @@
 		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 @@
 		}
 		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_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 @@
 	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 @@
 				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]);
diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c
index 38aad08..9e87402 100644
--- a/drivers/media/dvb/firesat/firesat_dvb.c
+++ b/drivers/media/dvb/firesat/firesat_dvb.c
@@ -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 @@
 {
 	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 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 @@
 			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 @@
 	}
 
 	if (!channel) {
-		printk("%s: busy!\n", __func__);
+		printk(KERN_ERR "%s: busy!\n", __func__);
 		return -EBUSY;
 	}
 
@@ -131,22 +144,23 @@
 
 	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 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 @@
 
 	// 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 result;
 
-		firesat->has_ci = 1; // TEMP workaround
-
 #if 0
 		switch (firesat->type) {
 		case FireSAT_DVB_S:
@@ -254,7 +267,7 @@
 			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 @@
 			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 @@
 			return result;
 		}
 
-		if (firesat->has_ci)
 			firesat_ca_init(firesat);
 
 		return 0;
 }
+
+
diff --git a/drivers/media/dvb/firesat/firesat_fe.c b/drivers/media/dvb/firesat/firesat_fe.c
index f7abd38..1c86c3e 100644
--- a/drivers/media/dvb/firesat/firesat_fe.c
+++ b/drivers/media/dvb/firesat/firesat_fe.c
@@ -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>
@@ -22,22 +33,29 @@
 
 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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 		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
index 0000000..15e23cf
--- /dev/null
+++ b/drivers/media/dvb/firesat/firesat_iso.c
@@ -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));
+	}
+}
+