Commit c81c8b68 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman Committed by Stefan Richter

DVB: add firesat driver

Original code written by Christian Dolzer <c.dolzer@digital-everywhere.com>

Cleaned up by Greg.

Major cleanup and reorg by Manu Abraham <manu@linuxtv.org>

Additions also by Ben Backx <ben@bbackx.com>

Cc: Christian Dolzer <c.dolzer@digital-everywhere.com>
Cc: Andreas Monitzer <andy@monitzer.com>
Cc: Manu Abraham <manu@linuxtv.org>
Cc: Fabio De Lorenzo <delorenzo.fabio@gmail.com>
Cc: Robert Berger <robert.berger@reliableembeddedsystems.com>
Signed-off-by: default avatarBen Backx <ben@bbackx.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>

Added missing dependency to dvb/firesat/Kconfig,
Reported-by: default avatarRandy Dunlap <randy.dunlap@oracle.com>

Tweaked dvb/Makefile.
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent f7e603ad
......@@ -51,6 +51,8 @@ comment "Supported SDMC DM1105 Adapters"
depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/dm1105/Kconfig"
source "drivers/media/dvb/firesat/Kconfig"
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
......
......@@ -3,3 +3,5 @@
#
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
obj-$(CONFIG_DVB_FIRESAT) += firesat/
config DVB_FIRESAT
tristate "FireSAT devices"
depends on DVB_CORE && IEEE1394 && INPUT
help
Support for external IEEE1394 adapters designed by Digital Everywhere and
produced by El Gato, shipped under the brand name 'FireDTV/FloppyDTV'.
These devices don't have a MPEG decoder built in, so you need
an external software decoder to watch TV.
Say Y if you own such a device and want to use it.
firesat-objs := firesat_1394.o \
firesat_dvb.o \
firesat_fe.o \
avc_api.o \
cmp.o \
firesat-rc.o \
firesat-ci.o
obj-$(CONFIG_DVB_FIRESAT) += firesat.o
EXTRA_CFLAGS := -Idrivers/ieee1394
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
This diff is collapsed.
This diff is collapsed.
#include "cmp.h"
#include <ieee1394.h>
#include <nodemgr.h>
#include <highlevel.h>
#include <ohci1394.h>
#include <hosts.h>
#include <ieee1394_core.h>
#include <ieee1394_transactions.h>
#include "avc_api.h"
typedef struct _OPCR
{
BYTE PTPConnCount : 6 ; // Point to point connect. counter
BYTE BrConnCount : 1 ; // Broadcast connection counter
BYTE OnLine : 1 ; // On Line
BYTE ChNr : 6 ; // Channel number
BYTE Res : 2 ; // Reserved
BYTE PayloadHi : 2 ; // Payoad high bits
BYTE OvhdID : 4 ; // Overhead ID
BYTE DataRate : 2 ; // Data Rate
BYTE PayloadLo ; // Payoad low byte
} OPCR ;
#define FIRESAT_SPEED IEEE1394_SPEED_400
/* hpsb_lock is being removed from the kernel-source,
* therefor we define our own 'firesat_hpsb_lock'*/
int send_packet_and_wait(struct hpsb_packet *packet);
int firesat_hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, int extcode, quadlet_t * data, quadlet_t arg) {
struct hpsb_packet *packet;
int retval = 0;
BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
if (!packet)
return -ENOMEM;
packet->generation = generation;
retval = send_packet_and_wait(packet);
if (retval < 0)
goto hpsb_lock_fail;
retval = hpsb_packet_success(packet);
if (retval == 0) {
*data = packet->data[0];
}
hpsb_lock_fail:
hpsb_free_tlabel(packet);
hpsb_free_packet(packet);
return retval;
}
static int cmp_read(struct firesat *firesat, void *buffer, u64 addr, size_t length) {
int ret;
if(down_interruptible(&firesat->avc_sem))
return -EINTR;
ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
addr, buffer, length);
up(&firesat->avc_sem);
return ret;
}
static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, quadlet_t arg, int ext_tcode) {
int ret;
if(down_interruptible(&firesat->avc_sem))
return -EINTR;
ret = firesat_hpsb_lock(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
addr, ext_tcode, data, arg);
up(&firesat->avc_sem);
return ret;
}
//try establishing a point-to-point connection (may be interrupted by a busreset
int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
unsigned int BWU; //bandwidth to allocate
quadlet_t old_oPCR,test_oPCR = 0x0;
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);
if (result < 0) {
printk("%s: cannot read oPCR\n", __func__);
return result;
} else {
printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR);
do {
OPCR *hilf= (OPCR*) &test_oPCR;
if (!hilf->OnLine) {
printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
return -EBUSY;
} else {
quadlet_t new_oPCR;
old_oPCR=test_oPCR;
if (hilf->PTPConnCount) {
if (hilf->ChNr != iso_channel) {
printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
return -EBUSY;
} else
printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
BWU=0; //we allocate no bandwidth (is this necessary?)
} else {
hilf->ChNr=iso_channel;
hilf->DataRate=FIRESAT_SPEED;
hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
BWU=hilf->OvhdID?hilf->OvhdID*32:512;
BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
/* if (allocate_1394_resources(iso_channel,BWU))
{
cout << "Allocation of resources failed\n";
return -2;
}*/
}
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);
result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
if (result < 0) {
printk("%s: cannot compare_swap oPCR\n",__func__);
return result;
}
if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
{
printk("%s: change of oPCR failed -> freeing resources\n",__func__);
// hilf= (OPCR*) &new_oPCR;
// unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
// BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
/* if (deallocate_1394_resources(iso_channel,BWU))
{
cout << "Deallocation of resources failed\n";
return -3;
}*/
}
}
}
while (old_oPCR != test_oPCR);
}
return 0;
}
//try breaking a point-to-point connection (may be interrupted by a busreset
int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
quadlet_t old_oPCR,test_oPCR;
u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
printk(KERN_INFO "%s\n",__func__);
if (result < 0) {
printk("%s: cannot read oPCR\n", __func__);
return result;
} else {
do {
OPCR *hilf= (OPCR*) &test_oPCR;
if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
return -EINVAL;
} else {
quadlet_t new_oPCR;
old_oPCR=test_oPCR;
hilf->PTPConnCount--;
new_oPCR=test_oPCR;
// printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
if (result < 0) {
printk("%s: cannot compare_swap oPCR\n",__func__);
return result;
}
}
} while (old_oPCR != test_oPCR);
/* hilf = (OPCR*) &old_oPCR;
if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
cout << "deallocating 1394 resources\n";
unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
if (deallocate_1394_resources(iso_channel,BWU))
{
cout << "Deallocation of resources failed\n";
return -3;
}
}*/
}
return 0;
}
static void complete_packet(void *data) {
complete((struct completion *) data);
}
int send_packet_and_wait(struct hpsb_packet *packet) {
struct completion done;
int retval;
init_completion(&done);
hpsb_set_packet_complete_task(packet, complete_packet, &done);
retval = hpsb_send_packet(packet);
if (retval == 0)
wait_for_completion(&done);
return retval;
}
#ifndef __FIRESAT__CMP_H_
#define __FIRESAT__CMP_H_
#include "firesat.h"
extern int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel);
extern int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel);
#endif
#include "firesat-ci.h"
#include "firesat.h"
#include "avc_api.h"
#include <linux/dvb/ca.h>
#include <dvbdev.h>
/*
static int firesat_ca_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) {
//struct firesat *firesat = (struct firesat*)((struct dvb_device*)file->private_data)->priv;
int err;
// printk(KERN_INFO "%s: ioctl %d\n",__func__,cmd);
switch(cmd) {
case CA_RESET:
// TODO: Needs to be implemented with new AVC Vendor commands
break;
case CA_GET_CAP: {
ca_caps_t *cap=(ca_caps_t*)parg;
cap->slot_num = 1;
cap->slot_type = CA_CI_LINK;
cap->descr_num = 1;
cap->descr_type = CA_DSS;
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;
}
err = 0;
break;
}
default:
err=-EINVAL;
}
return err;
}
*/
static int firesat_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) {
//return dvb_usercopy(inode, file, cmd, arg, firesat_ca_do_ioctl);
return dvb_generic_ioctl(inode, file, cmd, arg);
}
static int firesat_ca_io_open(struct inode *inode, struct file *file) {
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__);
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__);
return POLLIN;
}
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,
.open = firesat_ca_io_open,
.release = firesat_ca_io_release,
.poll = firesat_ca_io_poll,
};
static struct dvb_device firesat_ca = {
.priv = NULL,
.users = 1,
.readers = 1,
.writers = 1,
.fops = &firesat_ca_fops,
};
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;
// avoid unnecessary delays, we're not talking to the CI yet anyways
return 0;
}
void firesat_ca_release(struct firesat *firesat) {
dvb_unregister_device(firesat->cadev);
}
#ifndef __FIRESAT_CA_H
#define __FIRESAT_CA_H
#include "firesat.h"
int firesat_ca_init(struct firesat *firesat);
void firesat_ca_release(struct firesat *firesat);
#endif
#include "firesat.h"
#include "firesat-rc.h"
#include <linux/input.h>
static u16 firesat_irtable[] = {
KEY_ESC,
KEY_F9,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_I,
KEY_0,
KEY_ENTER,
KEY_RED,
KEY_UP,
KEY_GREEN,
KEY_F10,
KEY_SPACE,
KEY_F11,
KEY_YELLOW,
KEY_DOWN,
KEY_BLUE,
KEY_Z,
KEY_P,
KEY_PAGEDOWN,
KEY_LEFT,
KEY_W,
KEY_RIGHT,
KEY_P,
KEY_M,
KEY_R,
KEY_V,
KEY_C,
0
};
static struct input_dev firesat_idev;
int firesat_register_rc(void)
{
int index;
memset(&firesat_idev, 0, sizeof(firesat_idev));
firesat_idev.evbit[0] = BIT(EV_KEY);
for (index = 0; firesat_irtable[index] != 0; index++)
set_bit(firesat_irtable[index], firesat_idev.keybit);
return input_register_device(&firesat_idev);
}
int firesat_unregister_rc(void)
{
input_unregister_device(&firesat_idev);
return 0;
}
int firesat_got_remotecontrolcode(u16 code)
{
u16 keycode;
if (code > 0x4500 && code < 0x4520)
keycode = firesat_irtable[code - 0x4501];
else if (code > 0x453f && code < 0x4543)
keycode = firesat_irtable[code - 0x4521];
else {
printk(KERN_DEBUG "%s: invalid key code 0x%04x\n", __func__,
code);
return -EINVAL;
}
input_report_key(&firesat_idev, keycode, 1);
input_report_key(&firesat_idev, keycode, 0);
return 0;
}
#ifndef __FIRESAT_LIRC_H
#define __FIRESAT_LIRC_H
extern int firesat_register_rc(void);
extern int firesat_unregister_rc(void);
extern int firesat_got_remotecontrolcode(u16 code);
#endif
#ifndef __FIRESAT_H
#define __FIRESAT_H
#include "dvb_frontend.h"
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_net.h"
#include <linux/semaphore.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
enum model_type {
FireSAT_DVB_S = 1,
FireSAT_DVB_C = 2,
FireSAT_DVB_T = 3
};
struct firesat {
struct dvb_demux dvb_demux;
char *model_name;
/* DVB bits */
struct dvb_adapter *adapter;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dmx_frontend frontend;
struct dvb_net dvbnet;
struct dvb_frontend_info *frontend_info;
struct dvb_frontend *fe;
struct dvb_device *cadev;
int has_ci;
struct semaphore avc_sem;
atomic_t avc_reply_received;
atomic_t reschedule_remotecontrol;
struct firesat_channel {
struct firesat *firesat;
struct dvb_demux_feed *dvbdmxfeed;
int active;
int id;
int pid;
int type; /* 1 - TS, 2 - Filter */
} channel[16];
struct semaphore demux_sem;
/* needed by avc_api */
void *respfrm;
int resp_length;
// nodeid_t nodeid;
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;
fe_sec_voltage_t voltage;
fe_sec_tone_mode_t tone;
int isochannel;
struct list_head list;
};
extern struct list_head firesat_list;
extern spinlock_t firesat_list_lock;
/* firesat_dvb.c */
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);
/* firesat_fe.c */
extern int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe);
#endif
This diff is collapsed.
#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 <linux/interrupt.h>
#include <linux/semaphore.h>
#include <ieee1394_hotplug.h>
#include <nodemgr.h>
#include <highlevel.h>
#include <ohci1394.h>
#include <hosts.h>
#include <dvbdev.h>
#include "firesat.h"
#include "avc_api.h"
#include "cmp.h"
#include "firesat-rc.h"
#include "firesat-ci.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat)
{
int k;
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);
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;
}
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",__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);
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:
//Dirty fix to keep firesat->channel pid-list up to date
for(k=0;k<16;k++){
if(firesat->channel[k].active == 0)
firesat->channel[k].pid =
dvbdmxfeed->pid;
break;
}
channel = firesat_channel_allocate(firesat);
break;
default:
printk("%s: invalid pes type %u\n",__func__, dvbdmxfeed->pes_type);
return -EINVAL;
}
} else {
channel = firesat_channel_allocate(firesat);
}
if (!channel) {
printk("%s: busy!\n", __func__);
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(dvbdmxfeed->pid == 8192) {
if((k=AVCTuner_GetTS(firesat))) {
firesat_channel_release(firesat, channel);
printk("%s: AVCTuner_GetTS failed with error %d\n",
__func__,k);
return k;
}
}
else {
if((k=AVCTuner_SetPIDs(firesat, pidc, pids))) {
firesat_channel_release(firesat, channel);
printk("%s: AVCTuner_SetPIDs failed with error %d\n",
__func__,k);
return k;
}
}
return 0;
}
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", __func__, 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)
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);
return k;
}
((struct firesat_channel *)dvbdmxfeed->priv)->active = 0;
up(&firesat->demux_sem);
return 0;
}
int firesat_dvbdev_init(struct firesat *firesat,
struct device *dev,
struct dvb_frontend *fe)
{
int result;
firesat->has_ci = 1; // TEMP workaround
#if 0
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",
__func__, firesat->type,subunit);
firesat->model_name = "Unknown";
firesat->frontend_info = NULL;
}
#endif
/* // ------- CRAP -----------
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;
}
*/
//initialising firesat->adapter before calling dvb_register_adapter
if (!(firesat->adapter = kmalloc(sizeof (struct dvb_adapter), GFP_KERNEL))) {
printk("%s: couldn't allocate memory.\n", __func__);
kfree(firesat->adapter);
kfree(firesat);
return -ENOMEM;
}
if ((result = dvb_register_adapter(firesat->adapter,
firesat->model_name,
THIS_MODULE,
dev, adapter_nr)) < 0) {
printk("%s: dvb_register_adapter failed: error %d\n", __func__, result);
#if 0
/* ### cleanup */
spin_lock_irqsave(&firesat_list_lock, flags);
list_del(&firesat->list);
spin_unlock_irqrestore(&firesat_list_lock, flags);
#endif
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", __func__,
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",
__func__, 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", __func__,
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", __func__,
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);
// fe->ops = firesat_ops;
// fe->dvb = firesat->adapter;
firesat_frontend_attach(firesat, fe);
fe->sec_priv = firesat; //IMPORTANT, functions depend on this!!!
if ((result= dvb_register_frontend(firesat->adapter, fe)) < 0) {
printk("%s: dvb_register_frontend_new failed: error %d\n", __func__, result);
/* ### cleanup */
return result;
}
if (firesat->has_ci)
firesat_ca_init(firesat);
return 0;
}
#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 <linux/interrupt.h>
#include <linux/semaphore.h>
#include <ieee1394_hotplug.h>
#include <nodemgr.h>
#include <highlevel.h>
#include <ohci1394.h>
#include <hosts.h>
#include <dvbdev.h>
#include "firesat.h"
#include "avc_api.h"
#include "cmp.h"
#include "firesat-rc.h"
#include "firesat-ci.h"
static int firesat_dvb_init(struct dvb_frontend *fe)
{
struct firesat *firesat = fe->sec_priv;
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;
}
static int firesat_sleep(struct dvb_frontend *fe)
{
struct firesat *firesat = fe->sec_priv;
//FIXME hpsb_unlisten_channel(&firesat_highlevel, firesat->host, firesat->isochannel);
try_CMPBreakPPconnection(firesat, firesat->subunit, firesat->isochannel);
firesat->isochannel = -1;
return 0;
}
static int firesat_diseqc_send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
struct firesat *firesat = fe->sec_priv;
return AVCLNBControl(firesat, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE,
LNBCONTROL_DONTCARE, 1, cmd);
}
static int firesat_diseqc_send_burst(struct dvb_frontend *fe,
fe_sec_mini_cmd_t minicmd)
{
return 0;
}
static int firesat_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
struct firesat *firesat = fe->sec_priv;
firesat->tone = tone;
return 0;
}
static int firesat_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
{
struct firesat *firesat = fe->sec_priv;
firesat->voltage = voltage;
return 0;
}
static int firesat_read_status (struct dvb_frontend *fe, fe_status_t *status)
{
struct firesat *firesat = fe->sec_priv;
ANTENNA_INPUT_INFO info;
if (AVCTunerStatus(firesat, &info))
return -EINVAL;
if (info.NoRF)
*status = 0;
else
*status = *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)
{
struct firesat *firesat = fe->sec_priv;
ANTENNA_INPUT_INFO info;
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);
return 0;
}
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;
return 0;
}
static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr)
{
return -EOPNOTSUPP;
}
static int firesat_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
{
return -EOPNOTSUPP;
}
static int firesat_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct firesat *firesat = fe->sec_priv;
if (AVCTuner_DSD(firesat, params, NULL) != ACCEPTED)
return -EINVAL;
else
return 0; //not sure of this...
}
static int firesat_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
return -EOPNOTSUPP;
}
static struct dvb_frontend_info firesat_S_frontend_info;
static struct dvb_frontend_info firesat_C_frontend_info;
static struct dvb_frontend_info firesat_T_frontend_info;
static struct dvb_frontend_ops firesat_ops = {
.init = firesat_dvb_init,
.sleep = firesat_sleep,
.set_frontend = firesat_set_frontend,
.get_frontend = firesat_get_frontend,
.read_status = firesat_read_status,
.read_ber = firesat_read_ber,
.read_signal_strength = firesat_read_signal_strength,
.read_snr = firesat_read_snr,
.read_ucblocks = firesat_read_uncorrected_blocks,
.diseqc_send_master_cmd = firesat_diseqc_send_master_cmd,
.diseqc_send_burst = firesat_diseqc_send_burst,
.set_tone = firesat_set_tone,
.set_voltage = firesat_set_voltage,
};
int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe)
{
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",
// __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->dvb = firesat->adapter;
return 0;
}
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,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment