summaryrefslogtreecommitdiff
path: root/v4l_experimental/firesat/firesat.c
diff options
context:
space:
mode:
Diffstat (limited to 'v4l_experimental/firesat/firesat.c')
-rw-r--r--v4l_experimental/firesat/firesat.c917
1 files changed, 917 insertions, 0 deletions
diff --git a/v4l_experimental/firesat/firesat.c b/v4l_experimental/firesat/firesat.c
new file mode 100644
index 000000000..167c5a709
--- /dev/null
+++ b/v4l_experimental/firesat/firesat.c
@@ -0,0 +1,917 @@
+/*
+ * FireSAT DVB driver
+ *
+ * Copyright (c) 2004 Andreas Monitzer <andy@monitzer.com>
+ *
+ * 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>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/errno.h>
+#include <asm/semaphore.h>
+#include <ieee1394_hotplug.h>
+#include <nodemgr.h>
+#include <highlevel.h>
+#include <ohci1394.h>
+#include <hosts.h>
+
+/*#include "dvb_frontend.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>*/
+#include "firesat.h"
+#include "avc_api.h"
+#include "cmp.h"
+#include "firesat-rc.h"
+#include "firesat-ci.h"
+
+#define FIRESAT_Vendor_ID 0x001287
+
+/*** HOTPLUG STUFF **********************************************************/
+/*
+ * Export information about protocols/devices supported by this driver.
+ */
+static struct ieee1394_device_id firesat_id_table[] = {
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+ .model_id = 0x11,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+ .model_id = 0x12,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x13,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x14,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x21,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x22,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x23,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x24,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x25,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x26,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x27,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x34,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x35,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ {
+ .match_flags = /*IEEE1394_MATCH_VENDOR_ID |*/ IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
+// .vendor_id = FIRESAT_Vendor_ID & 0xffffff,
+// .vendor_id = 0x000000,
+ .model_id = 0x36,
+ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+ .version = AVC_SW_VERSION_ENTRY & 0xffffff
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(ieee1394, firesat_id_table);
+
+/* list of all firesat devices */
+LIST_HEAD(firesat_list);
+spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED;
+
+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,
+ int cts, u8 *data, size_t length);
+
+static struct hpsb_highlevel firesat_highlevel = {
+ .name = "FireSAT",
+ .add_host = firesat_add_host,
+ .remove_host = firesat_remove_host,
+ .host_reset = firesat_host_reset,
+ .iso_receive = iso_receive,
+ .fcp_request = fcp_request,
+};
+
+
+static struct dvb_frontend_info firesat_S_frontend_info = {
+ .name = "FireSAT DVB-S Frontend",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 40000000,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO | FE_CAN_QPSK,
+};
+
+static struct dvb_frontend_info firesat_C_frontend_info = {
+ .name = "FireSAT DVB-C Frontend",
+ .type = FE_QAM,
+ .frequency_min = 47000000,
+ .frequency_max = 866000000,
+ .frequency_stepsize = 62500,
+ .symbol_rate_min = 870000,
+ .symbol_rate_max = 6900000,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO,
+};
+
+static struct dvb_frontend_info firesat_T_frontend_info = {
+ .name = "FireSAT DVB-T Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 49000000,
+ .frequency_max = 861000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_2_3 |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+};
+
+static void firesat_add_host (struct hpsb_host *host) {
+ struct ti_ohci *ohci;
+// printk(KERN_INFO "FireSAT add_host (nodeid = 0x%x)\n",host->node_id);
+
+ /* We only work with the OHCI-1394 driver */
+ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
+ return;
+
+ ohci = (struct ti_ohci *)host->hostdata;
+
+ if (!hpsb_create_hostinfo(&firesat_highlevel, host, 0)) {
+ printk(KERN_ERR "Cannot allocate hostinfo\n");
+ return;
+ }
+
+ hpsb_set_hostinfo(&firesat_highlevel, host, ohci);
+ hpsb_set_hostinfo_key(&firesat_highlevel, host, ohci->host->id);
+}
+
+static void firesat_remove_host (struct hpsb_host *host) {
+// printk(KERN_INFO "FireSAT remove_host (nodeid = 0x%x)\n",host->node_id);
+}
+
+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;
+ };
+};
+
+static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
+ size_t length) {
+// printk(KERN_INFO "FireSAT iso_receive: channel %d, length = %d\n", channel, length);
+
+ if(length <= 12)
+ return; // ignore empty packets
+ else {
+ struct firesat *firesat=NULL;
+ struct firesat *firesat_entry;
+ unsigned long flags;
+
+ 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",__FUNCTION__, length, data[0],data[1],data[2],data[3],data[4]);
+
+ while (count--) {
+
+ if(buf[sizeof(quadlet_t) /*timestamp*/] == 0x47)
+ dvb_dmx_swfilter_packet(&firesat->demux, &buf[sizeof(quadlet_t)]);
+ else
+ printk("%s: invalid packet, skipping\n", __FUNCTION__);
+ buf += 188 + sizeof(quadlet_t) /* timestamp */;
+ }
+ }
+ }
+}
+
+static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, size_t length) {
+// printk(KERN_INFO "FireSAT fcp_request length=%d\n",length);
+ if(length>0 && ((data[0] & 0xF0) >> 4) == 0) {
+ struct firesat *firesat=NULL;
+ struct firesat *firesat_entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ list_for_each_entry(firesat_entry,&firesat_list,list) {
+ if(firesat_entry->host == host && firesat_entry->nodeentry->nodeid == nodeid && (firesat_entry->subunit == (data[1]&0x7) || (firesat_entry->subunit == 0 && (data[1]&0x7) == 0x7))) {
+ firesat=firesat_entry;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+
+ if(firesat)
+ AVCRecv(firesat,data,length);
+ else
+ printk("%s: received fcp request from unknown source, ignored\n",__FUNCTION__);
+ } // else ignore
+}
+
+static int firesat_frontend_ioctl(struct dvb_frontend *frontend,
+ unsigned int cmd, void *arg) {
+ struct firesat *firesat=frontend->data;
+
+ switch(cmd) {
+ case FE_INIT:
+ firesat->isochannel = firesat->adapter->num << 1 | (firesat->subunit & 0x1); // ### ask IRM
+ try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel);
+ hpsb_listen_channel(&firesat_highlevel, firesat->host, firesat->isochannel);
+ break;
+ case FE_SLEEP:
+ hpsb_unlisten_channel(&firesat_highlevel, firesat->host, firesat->isochannel);
+ try_CMPBreakPPconnection(firesat, firesat->subunit, firesat->isochannel);
+ firesat->isochannel = -1;
+ break;
+ case FE_GET_INFO:
+// printk(KERN_INFO "FE_GET_INFO\n");
+ memcpy(arg, firesat->frontend_info,
+ sizeof (struct dvb_frontend_info));
+ break;
+ case FE_DISEQC_RESET_OVERLOAD:
+ case FE_DISEQC_RECV_SLAVE_REPLY:
+ return -EOPNOTSUPP;
+ case FE_DISEQC_SEND_MASTER_CMD:
+ return AVCLNBControl(firesat, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 1, (struct dvb_diseqc_master_cmd *)arg);
+ return 0;
+ case FE_DISEQC_SEND_BURST:
+ return 0;
+// return AVCLNBControl(firesat, LNBCONTROL_DONTCARE, (((fe_sec_mini_cmd_t)arg)==SEC_MINI_A)?0:1, LNBCONTROL_DONTCARE, 0, NULL);
+ case FE_SET_TONE:
+// return AVCLNBControl(firesat, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, (((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?1:0, 0, NULL);
+ firesat->tone = (fe_sec_tone_mode_t)arg;
+ return 0;
+ case FE_SET_VOLTAGE:
+// printk(KERN_INFO "FE_SET_VOLTAGE\n");
+ firesat->voltage=(fe_sec_voltage_t) arg;
+ return 0;
+// return AVCLNBControl(firesat, ((fe_sec_voltage_t) arg, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 0, NULL);
+ case FE_ENABLE_HIGH_LNB_VOLTAGE:
+ return -EOPNOTSUPP;
+ case FE_READ_STATUS: {
+ ANTENNA_INPUT_INFO info;
+ fe_status_t *status = (fe_status_t *)arg;
+// printk(KERN_INFO "%s: FE_READ_STATUS\n", __FUNCTION__);
+
+ if(AVCTunerStatus(firesat,&info)) {
+ return -EINVAL;
+ }
+// printk(KERN_INFO "%s: NoRF=%c\n",__FUNCTION__,info.NoRF?'y':'n');
+ if(info.NoRF)
+ *status = 0;
+ else
+ *status = *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+
+ break;
+ }
+ case FE_READ_BER: {
+ ANTENNA_INPUT_INFO info;
+ u32 *ber = (u32 *)arg;
+// printk(KERN_INFO "%s: FE_READ_BER\n", __FUNCTION__);
+
+ if(AVCTunerStatus(firesat,&info)) {
+ return -EINVAL;
+ }
+
+// *ber = *(u32*)info.BER; /* might need some byte ordering correction */
+ *ber = ((info.BER[0] << 24) & 0xFF) | ((info.BER[1] << 16) & 0xFF) | ((info.BER[2] << 8) & 0xFF) | (info.BER[3] & 0xFF);
+
+ break;
+ }
+ case FE_READ_SIGNAL_STRENGTH: {
+ ANTENNA_INPUT_INFO info;
+ u16 *signal = (u16 *)arg;
+// printk(KERN_INFO "%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
+
+ if(AVCTunerStatus(firesat,&info)) {
+ return -EINVAL;
+ }
+
+ *signal = info.SignalStrength;
+
+ break;
+ }
+ case FE_READ_SNR:
+ case FE_READ_UNCORRECTED_BLOCKS:
+ return -EOPNOTSUPP;
+ case FE_SET_FRONTEND: {
+ struct dvb_frontend_parameters *p =
+ (struct dvb_frontend_parameters *)arg;
+// printk(KERN_INFO "FE_GET_INFO\n");
+
+// printk(KERN_INFO "%s: FE_SET_FRONTEND\n", __FUNCTION__);
+
+// printk(KERN_INFO " frequency->%d\n", p->frequency);
+// printk(KERN_INFO " symbol_rate->%d\n",p->u.qam.symbol_rate);
+// printk(KERN_INFO " inversion->%d\n", p->inversion);
+
+// if(AVCTuner_DSIT(firesat, 0/*###*/, p, NULL))
+// return -EINVAL;
+ if(AVCTuner_DSD(firesat, p, NULL) != ACCEPTED)
+ return -EINVAL;
+
+ break;
+ }
+ case FE_GET_FRONTEND:
+ case FE_GET_EVENT:
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) {
+ int k;
+
+ printk(KERN_INFO "%s\n",__FUNCTION__);
+
+ 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",__FUNCTION__,k,firesat->channel[k].active,firesat->channel[k].pid);
+ if(firesat->channel[k].active == 0) {
+ firesat->channel[k].active = 1;
+ up(&firesat->demux_sem);
+ return &firesat->channel[k];
+ }
+ }
+
+ up(&firesat->demux_sem);
+ return NULL; // no more channels available
+}
+
+static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[]) {
+ int k, l=0;
+
+ if(down_interruptible(&firesat->demux_sem))
+ return -EINTR;
+
+ for(k=0;k<16;k++)
+ if(firesat->channel[k].active == 1)
+ pid[l++] = firesat->channel[k].pid;
+
+ up(&firesat->demux_sem);
+
+ *pidc = l;
+
+ return 0;
+}
+
+static int firesat_channel_release(struct firesat *firesat, struct firesat_channel *channel) {
+ if(down_interruptible(&firesat->demux_sem))
+ return -EINTR;
+
+ channel->active = 0;
+
+ up(&firesat->demux_sem);
+ return 0;
+}
+
+static int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) {
+ struct firesat *firesat=(struct firesat*)dvbdmxfeed->demux->priv;
+ struct firesat_channel *channel;
+ int pidc,k;
+ u16 pids[16];
+
+ printk(KERN_INFO "%s (pid %u)\n",__FUNCTION__,dvbdmxfeed->pid);
+
+ switch (dvbdmxfeed->type) {
+ case DMX_TYPE_TS:
+ case DMX_TYPE_SEC:
+ break;
+ default:
+ printk("%s: invalid type %u\n",__FUNCTION__,dvbdmxfeed->type);
+ return -EINVAL;
+ }
+
+ if (dvbdmxfeed->type == DMX_TYPE_TS) {
+ switch (dvbdmxfeed->pes_type) {
+ case DMX_TS_PES_VIDEO:
+ case DMX_TS_PES_AUDIO:
+ case DMX_TS_PES_TELETEXT:
+ case DMX_TS_PES_PCR:
+ case DMX_TS_PES_OTHER:
+ channel = firesat_channel_allocate(firesat);
+ break;
+ default:
+ printk("%s: invalid pes type %u\n",__FUNCTION__,dvbdmxfeed->pes_type);
+ return -EINVAL;
+ }
+ } else {
+ channel = firesat_channel_allocate(firesat);
+ }
+
+ if(!channel) {
+ printk("%s: busy!\n",__FUNCTION__);
+ return -EBUSY;
+ }
+
+ dvbdmxfeed->priv = channel;
+
+ channel->dvbdmxfeed = dvbdmxfeed;
+ channel->pid = dvbdmxfeed->pid;
+ channel->type = dvbdmxfeed->type;
+ channel->firesat = firesat;
+
+ if(firesat_channel_collect(firesat, &pidc, pids)) {
+ firesat_channel_release(firesat, channel);
+ return -EINTR;
+ }
+
+ if((k=AVCTuner_SetPIDs(firesat, pidc, pids))) {
+ firesat_channel_release(firesat, channel);
+ printk("%s: AVCTuner failed with error %d\n",__FUNCTION__,k);
+ return k;
+ }
+
+ return 0;
+}
+
+static int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) {
+ struct dvb_demux *demux = dvbdmxfeed->demux;
+ struct firesat *firesat=(struct firesat*)demux->priv;
+ int k, l=0;
+ u16 pids[16];
+
+ printk(KERN_INFO "%s (pid %u)\n",__FUNCTION__,dvbdmxfeed->pid);
+
+ if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) &&
+ (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
+ if (dvbdmxfeed->ts_type & TS_DECODER) {
+ if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
+ !demux->pesfilter[dvbdmxfeed->pes_type])
+ return -EINVAL;
+ demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
+ demux->pesfilter[dvbdmxfeed->pes_type] = 0;
+ }
+ if (!(dvbdmxfeed->ts_type & TS_DECODER &&
+ dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) {
+ return 0;
+ }
+ }
+
+ if(down_interruptible(&firesat->demux_sem))
+ return -EINTR;
+
+ // list except channel to be removed
+ for(k=0;k<16;k++)
+ if(firesat->channel[k].active == 1 && &firesat->channel[k] != (struct firesat_channel*)dvbdmxfeed->priv)
+ pids[l++] = firesat->channel[k].pid;
+
+ if((k=AVCTuner_SetPIDs(firesat, l, pids))) {
+ up(&firesat->demux_sem);
+ return k;
+ }
+
+ ((struct firesat_channel*)dvbdmxfeed->priv)->active = 0;
+
+ up(&firesat->demux_sem);
+
+ return 0;
+}
+
+static int firesat_probe(struct device *dev) {
+ struct unit_directory *ud=container_of(dev, struct unit_directory, device);
+ struct firesat *firesat;
+ unsigned long flags;
+ int result;
+ unsigned char subunitcount=0xff,subunit;
+ struct firesat **firesats=kmalloc(sizeof(void*)*2,GFP_KERNEL);
+
+ if(!firesats) {
+ printk("%s: couldn't allocate memory.\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+// printk(KERN_INFO "FireSAT: Detected device with GUID %08lx%04lx%04lx\n",(unsigned long)((ud->ne->guid)>>32),(unsigned long)(ud->ne->guid & 0xFFFF),(unsigned long)ud->ne->guid_vendor_id);
+ printk(KERN_INFO "%s: loading device\n", __FUNCTION__);
+
+ firesats[0]=NULL;
+ firesats[1]=NULL;
+
+ ud->device.driver_data = firesats;
+
+ for(subunit=0;subunit<subunitcount;subunit++) {
+ if (!(firesat = kmalloc(sizeof(struct firesat), GFP_KERNEL))) {
+ printk("%s: couldn't allocate memory.\n", __FUNCTION__);
+ kfree(firesats);
+ return -ENOMEM;
+ }
+
+ memset(firesat, 0, sizeof(struct firesat));
+ firesat->host=ud->ne->host;
+ firesat->guid=ud->ne->guid;
+ firesat->guid_vendor_id=ud->ne->guid_vendor_id;
+ firesat->nodeentry=ud->ne;
+ firesat->isochannel=-1;
+ firesat->tone = 0xff;
+ firesat->voltage = 0xff;
+ if(!(firesat->respfrm = kmalloc(sizeof(AVCRspFrm), GFP_KERNEL))) {
+ printk("%s: couldn't allocate memory.\n", __FUNCTION__);
+ kfree(firesat);
+ return -ENOMEM;
+ }
+
+ sema_init(&firesat->avc_sem, 1);
+ atomic_set(&firesat->avc_reply_received, 1);
+ sema_init(&firesat->demux_sem, 1);
+ atomic_set(&firesat->reschedule_remotecontrol, 0);
+
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ INIT_LIST_HEAD(&firesat->list);
+ list_add_tail(&firesat->list, &firesat_list);
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+
+ if(subunit == 0) {
+ firesat->subunit = 0x7; // 0x7 = don't care
+ if(AVCSubUnitInfo(firesat, &subunitcount)) {
+ printk("%s: AVC subunit info command failed.\n",__FUNCTION__);
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ list_del(&firesat->list);
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+ kfree(firesat);
+ return -EIO;
+ }
+ }
+
+ printk(KERN_INFO "%s: subunit count = %d\n",__FUNCTION__,subunitcount);
+
+ firesat->subunit=subunit;
+
+ if(AVCIdentifySubunit(firesat,NULL,(int*)&firesat->type,&firesat->has_ci)) {
+ printk("%s: cannot identify subunit %d\n",__FUNCTION__,subunit);
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ list_del(&firesat->list);
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+ kfree(firesat);
+ continue;
+ }
+ firesat->has_ci=1; // TEMP workaround
+
+ switch(firesat->type) {
+ case FireSAT_DVB_S:
+ firesat->model_name="FireSAT DVB-S";
+ firesat->frontend_info=&firesat_S_frontend_info;
+ break;
+ case FireSAT_DVB_C:
+ firesat->model_name="FireSAT DVB-C";
+ firesat->frontend_info=&firesat_C_frontend_info;
+ break;
+ case FireSAT_DVB_T:
+ firesat->model_name="FireSAT DVB-T";
+ firesat->frontend_info=&firesat_T_frontend_info;
+ break;
+ default:
+ printk("%s: unknown model type 0x%x on subunit %d!\n",__FUNCTION__,firesat->type,subunit);
+ firesat->model_name="Unknown";
+ firesat->frontend_info=NULL;
+ }
+ if(!firesat->frontend_info) {
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ list_del(&firesat->list);
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+ kfree(firesat);
+ continue;
+ }
+
+ if ((result = dvb_register_adapter(&firesat->adapter,
+ firesat->model_name, THIS_MODULE)) < 0) {
+ printk("%s: dvb_register_adapter failed: error %d\n",
+ __FUNCTION__, result);
+
+ /* ### cleanup */
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ list_del(&firesat->list);
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+ kfree(firesat);
+
+ return result;
+ }
+
+ firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/;
+
+ firesat->demux.priv = (void *)firesat;
+ firesat->demux.filternum = 16;
+ firesat->demux.feednum = 16;
+ firesat->demux.start_feed = firesat_start_feed;
+ firesat->demux.stop_feed = firesat_stop_feed;
+
+ firesat->demux.write_to_decoder = NULL;
+
+ if ((result = dvb_dmx_init(&firesat->demux)) < 0) {
+ printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+ result);
+
+ dvb_unregister_adapter(firesat->adapter);
+
+ return result;
+ }
+
+ firesat->dmxdev.filternum = 16;
+ firesat->dmxdev.demux = &firesat->demux.dmx;
+ firesat->dmxdev.capabilities = 0;
+
+ if ((result = dvb_dmxdev_init(&firesat->dmxdev, firesat->adapter)) < 0) {
+ printk("%s: dvb_dmxdev_init failed: error %d\n",
+ __FUNCTION__, result);
+
+ dvb_dmx_release(&firesat->demux);
+ dvb_unregister_adapter(firesat->adapter);
+
+ return result;
+ }
+
+ firesat->frontend.source = DMX_FRONTEND_0;
+
+ if ((result = firesat->demux.dmx.add_frontend(&firesat->demux.dmx,
+ &firesat->frontend)) < 0) {
+ printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+ result);
+
+ dvb_dmxdev_release(&firesat->dmxdev);
+ dvb_dmx_release(&firesat->demux);
+ dvb_unregister_adapter(firesat->adapter);
+
+ return result;
+ }
+
+ if ((result = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx,
+ &firesat->frontend)) < 0) {
+ printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,
+ result);
+
+ firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, &firesat->frontend);
+ dvb_dmxdev_release(&firesat->dmxdev);
+ dvb_dmx_release(&firesat->demux);
+ dvb_unregister_adapter(firesat->adapter);
+
+ return result;
+ }
+
+ dvb_net_init(firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx);
+
+ if((result= dvb_register_frontend(firesat_frontend_ioctl,firesat->adapter,firesat,firesat->frontend_info,THIS_MODULE)) < 0) {
+ printk("%s: dvb_register_frontend_new failed: error %d\n", __FUNCTION__, result);
+ /* ### cleanup */
+
+ return result;
+ }
+
+ if(firesat->has_ci)
+ firesat_ca_init(firesat);
+
+ firesats[subunit] = firesat;
+ } // loop fuer alle tuner am board
+
+ if(firesats[0])
+ AVCRegisterRemoteControl(firesats[0]);
+
+ return 0;
+}
+
+static int firesat_remove(struct device *dev) {
+ struct unit_directory *ud=container_of(dev, struct unit_directory, device);
+ struct firesat **firesats=ud->device.driver_data;
+
+ if(firesats) {
+ int k;
+ for(k=0;k<2;k++)
+ if(firesats[k]) {
+ unsigned long flags;
+ if(firesats[k]->has_ci)
+ firesat_ca_release(firesats[k]);
+ dvb_unregister_frontend(firesat_frontend_ioctl,firesats[k]->adapter);
+
+ 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);
+ dvb_dmxdev_release(&firesats[k]->dmxdev);
+ dvb_dmx_release(&firesats[k]->demux);
+ dvb_unregister_adapter(firesats[k]->adapter);
+
+ spin_lock_irqsave(&firesat_list_lock, flags);
+ list_del(&firesats[k]->list);
+ spin_unlock_irqrestore(&firesat_list_lock, flags);
+
+ kfree(firesats[k]->respfrm);
+ kfree(firesats[k]);
+ }
+ kfree(firesats);
+ } else
+ printk("%s: can't get firesat handle\n",__FUNCTION__);
+
+ printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id);
+ return 0;
+}
+
+static int firesat_update(struct unit_directory *ud) {
+// printk(KERN_INFO "FireSAT: Found device with vendor id 0x%x, model id 0x%x\n", ud->vendor_id,ud->model_id);
+ struct firesat **firesats=ud->device.driver_data;
+ int k;
+ // loop over subunits
+
+ for(k=0;k<2;k++)
+ if(firesats[k]) {
+ firesats[k]->nodeentry=ud->ne;
+
+ if(firesats[k]->isochannel >= 0)
+ try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel);
+ }
+
+ return 0;
+}
+
+static struct hpsb_protocol_driver firesat_driver = {
+ .name = "FireSAT DVB",
+ .id_table = firesat_id_table,
+ .update = firesat_update,
+ .driver = {
+ .name = "firesat",
+ .bus = &ieee1394_bus_type,
+ .probe = firesat_probe,
+ .remove = firesat_remove,
+ },
+};
+
+static int __init firesat_init(void)
+{
+ int ret;
+ printk("FireSAT loaded\n");
+ hpsb_register_highlevel(&firesat_highlevel);
+ ret = hpsb_register_protocol(&firesat_driver);
+ if(ret) {
+ printk(KERN_ERR "FireSAT: failed to register protocol\n");
+ hpsb_unregister_highlevel(&firesat_highlevel);
+ return ret;
+ }
+
+ if((ret=firesat_register_rc()))
+ printk("%s: firesat_register_rc return error code %d (ignored)\n",__FUNCTION__,ret);
+
+ return 0;
+}
+
+static void __exit firesat_exit(void){
+ firesat_unregister_rc();
+
+ hpsb_unregister_protocol(&firesat_driver);
+ hpsb_unregister_highlevel(&firesat_highlevel);
+ printk("FireSAT quit\n");
+}
+
+module_init(firesat_init);
+module_exit(firesat_exit);
+
+MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
+MODULE_DESCRIPTION("FireSAT DVB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("FireSAT DVB");