From df4846c35247a0d038c5359d502cddd59d04bc40 Mon Sep 17 00:00:00 2001 From: Henrik Kurelid Date: Fri, 1 Aug 2008 10:00:45 +0200 Subject: [PATCH] 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 Signed-off-by: Stefan Richter (rebased, whitespace) --- drivers/media/dvb/firesat/Makefile | 1 + drivers/media/dvb/firesat/avc_api.c | 770 +++++++++++++++++++++++++------ drivers/media/dvb/firesat/avc_api.h | 296 +++++++----- drivers/media/dvb/firesat/cmp.c | 40 +- drivers/media/dvb/firesat/firesat-ci.c | 342 ++++++++++++-- drivers/media/dvb/firesat/firesat.h | 174 ++++++- drivers/media/dvb/firesat/firesat_1394.c | 123 +---- drivers/media/dvb/firesat/firesat_dvb.c | 49 +- drivers/media/dvb/firesat/firesat_fe.c | 80 ++-- drivers/media/dvb/firesat/firesat_iso.c | 106 +++++ 10 files changed, 1487 insertions(+), 494 deletions(-) create mode 100644 drivers/media/dvb/firesat/firesat_iso.c 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 * Copyright (c) 2008 Ben Backx + * Copyright (c) 2008 Henrik Kurelid * * 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 #include #include +#include #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 @@ 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;klength;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 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; +} 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 -#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 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 + * + * 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 #include @@ -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 @@ 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__); 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 + * + * 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 #include -/* -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); } 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 + * + * 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 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) #include +#endif #include #include +#include + +#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 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 * Copyright (c) 2007-2008 Ben Backx + * Copyright (c) 2008 Henrik Kurelid * * 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 #include #include -#include #include #include #include @@ -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]); 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 + * + * 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 #include #include @@ -6,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -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; } + + 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 + * + * 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 #include #include @@ -6,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -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 @@ 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 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 + * + * 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)); + } +} + -- 2.7.4