Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
51
drivers/media/dvb/Kconfig
Normal file
51
drivers/media/dvb/Kconfig
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Multimedia device configuration
|
||||
#
|
||||
|
||||
menu "Digital Video Broadcasting Devices"
|
||||
|
||||
config DVB
|
||||
bool "DVB For Linux"
|
||||
depends on NET && INET
|
||||
---help---
|
||||
Support Digital Video Broadcasting hardware. Enable this if you
|
||||
own a DVB adapter and want to use it or if you compile Linux for
|
||||
a digital SetTopBox.
|
||||
|
||||
API specs and user tools are available from <http://www.linuxtv.org/>.
|
||||
|
||||
Please report problems regarding this driver to the LinuxDVB
|
||||
mailing list.
|
||||
|
||||
If unsure say N.
|
||||
|
||||
source "drivers/media/dvb/dvb-core/Kconfig"
|
||||
|
||||
comment "Supported SAA7146 based PCI Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/ttpci/Kconfig"
|
||||
|
||||
comment "Supported USB Adapters"
|
||||
depends on DVB_CORE && USB && I2C
|
||||
source "drivers/media/dvb/dvb-usb/Kconfig"
|
||||
source "drivers/media/dvb/ttusb-budget/Kconfig"
|
||||
source "drivers/media/dvb/ttusb-dec/Kconfig"
|
||||
source "drivers/media/dvb/cinergyT2/Kconfig"
|
||||
|
||||
comment "Supported FlexCopII (B2C2) Adapters"
|
||||
depends on DVB_CORE && (PCI || USB) && I2C
|
||||
source "drivers/media/dvb/b2c2/Kconfig"
|
||||
|
||||
comment "Supported BT878 Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/bt8xx/Kconfig"
|
||||
|
||||
comment "Supported Pluto2 Adapters"
|
||||
depends on DVB_CORE && PCI && I2C
|
||||
source "drivers/media/dvb/pluto2/Kconfig"
|
||||
|
||||
comment "Supported DVB Frontends"
|
||||
depends on DVB_CORE
|
||||
source "drivers/media/dvb/frontends/Kconfig"
|
||||
|
||||
endmenu
|
||||
5
drivers/media/dvb/Makefile
Normal file
5
drivers/media/dvb/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for the kernel multimedia device drivers.
|
||||
#
|
||||
|
||||
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
|
||||
40
drivers/media/dvb/b2c2/Kconfig
Normal file
40
drivers/media/dvb/b2c2/Kconfig
Normal file
@@ -0,0 +1,40 @@
|
||||
config DVB_B2C2_FLEXCOP
|
||||
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
|
||||
depends on DVB_CORE && I2C
|
||||
select DVB_PLL
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT312 if !DVB_FE_CUSTOMISE
|
||||
select DVB_NXT200X if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0297 if !DVB_FE_CUSTOMISE
|
||||
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for the digital TV receiver chip made by B2C2 Inc. included in
|
||||
Technisats PCI cards and USB boxes.
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
config DVB_B2C2_FLEXCOP_PCI
|
||||
tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
|
||||
depends on DVB_B2C2_FLEXCOP && PCI && I2C
|
||||
help
|
||||
Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
config DVB_B2C2_FLEXCOP_USB
|
||||
tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
|
||||
depends on DVB_B2C2_FLEXCOP && USB && I2C
|
||||
help
|
||||
Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
config DVB_B2C2_FLEXCOP_DEBUG
|
||||
bool "Enable debug for the B2C2 FlexCop drivers"
|
||||
depends on DVB_B2C2_FLEXCOP
|
||||
help
|
||||
Say Y if you want to enable the module option to control debug messages
|
||||
of all B2C2 FlexCop drivers.
|
||||
12
drivers/media/dvb/b2c2/Makefile
Normal file
12
drivers/media/dvb/b2c2/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
|
||||
flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o \
|
||||
flexcop-dma.o
|
||||
obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
|
||||
|
||||
b2c2-flexcop-pci-objs = flexcop-pci.o
|
||||
obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
|
||||
|
||||
b2c2-flexcop-usb-objs = flexcop-usb.o
|
||||
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
|
||||
|
||||
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
165
drivers/media/dvb/b2c2/flexcop-common.h
Normal file
165
drivers/media/dvb/b2c2/flexcop-common.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-common.h - common header file for device-specific source files also.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#ifndef __FLEXCOP_COMMON_H__
|
||||
#define __FLEXCOP_COMMON_H__
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "flexcop-reg.h"
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_filter.h"
|
||||
#include "dvb_net.h"
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#define FC_MAX_FEED 256
|
||||
|
||||
#ifndef FC_LOG_PREFIX
|
||||
#warning please define a log prefix for your file, using a default one
|
||||
#define FC_LOG_PREFIX "b2c2-undef"
|
||||
#endif
|
||||
|
||||
/* Steal from usb.h */
|
||||
#undef err
|
||||
#define err(format, arg...) printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
#undef info
|
||||
#define info(format, arg...) printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
#undef warn
|
||||
#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
|
||||
struct flexcop_dma {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
u8 *cpu_addr0;
|
||||
dma_addr_t dma_addr0;
|
||||
u8 *cpu_addr1;
|
||||
dma_addr_t dma_addr1;
|
||||
u32 size; /* size of each address in bytes */
|
||||
};
|
||||
|
||||
/* Control structure for data definitions that are common to
|
||||
* the B2C2-based PCI and USB devices.
|
||||
*/
|
||||
struct flexcop_device {
|
||||
/* general */
|
||||
struct device *dev; /* for firmware_class */
|
||||
|
||||
#define FC_STATE_DVB_INIT 0x01
|
||||
#define FC_STATE_I2C_INIT 0x02
|
||||
#define FC_STATE_FE_INIT 0x04
|
||||
int init_state;
|
||||
|
||||
/* device information */
|
||||
int has_32_hw_pid_filter;
|
||||
flexcop_revision_t rev;
|
||||
flexcop_device_type_t dev_type;
|
||||
flexcop_bus_t bus_type;
|
||||
|
||||
/* dvb stuff */
|
||||
struct dvb_adapter dvb_adapter;
|
||||
struct dvb_frontend *fe;
|
||||
struct dvb_net dvbnet;
|
||||
struct dvb_demux demux;
|
||||
struct dmxdev dmxdev;
|
||||
struct dmx_frontend hw_frontend;
|
||||
struct dmx_frontend mem_frontend;
|
||||
int (*fe_sleep) (struct dvb_frontend *);
|
||||
|
||||
struct i2c_adapter i2c_adap;
|
||||
struct mutex i2c_mutex;
|
||||
struct module *owner;
|
||||
|
||||
/* options and status */
|
||||
int extra_feedcount;
|
||||
int feedcount;
|
||||
int pid_filtering;
|
||||
int fullts_streaming_state;
|
||||
|
||||
/* bus specific callbacks */
|
||||
flexcop_ibi_value (*read_ibi_reg) (struct flexcop_device *, flexcop_ibi_register);
|
||||
int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
|
||||
|
||||
|
||||
int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
|
||||
int (*stream_control) (struct flexcop_device*, int);
|
||||
|
||||
int (*get_mac_addr) (struct flexcop_device *fc, int extended);
|
||||
|
||||
void *bus_specific;
|
||||
};
|
||||
|
||||
/* exported prototypes */
|
||||
|
||||
/* from flexcop.c */
|
||||
void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
|
||||
void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
|
||||
|
||||
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
|
||||
void flexcop_device_kfree(struct flexcop_device*);
|
||||
|
||||
int flexcop_device_initialize(struct flexcop_device*);
|
||||
void flexcop_device_exit(struct flexcop_device *fc);
|
||||
|
||||
void flexcop_reset_block_300(struct flexcop_device *fc);
|
||||
|
||||
/* from flexcop-dma.c */
|
||||
int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
|
||||
void flexcop_dma_free(struct flexcop_dma *dma);
|
||||
|
||||
int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
|
||||
int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
|
||||
int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
|
||||
int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
|
||||
int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
|
||||
|
||||
/* from flexcop-eeprom.c */
|
||||
/* the PCI part uses this call to get the MAC address, the USB part has its own */
|
||||
int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
|
||||
|
||||
/* from flexcop-i2c.c */
|
||||
/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
|
||||
* one. We have it in flexcop-i2c.c, because it is going via the actual
|
||||
* I2C-channel of the flexcop.
|
||||
*/
|
||||
int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t,
|
||||
flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
|
||||
|
||||
/* from flexcop-sram.c */
|
||||
int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
|
||||
void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
|
||||
void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill);
|
||||
|
||||
/* global prototypes for the flexcop-chip */
|
||||
/* from flexcop-fe-tuner.c */
|
||||
int flexcop_frontend_init(struct flexcop_device *card);
|
||||
void flexcop_frontend_exit(struct flexcop_device *fc);
|
||||
|
||||
/* from flexcop-i2c.c */
|
||||
int flexcop_i2c_init(struct flexcop_device *fc);
|
||||
void flexcop_i2c_exit(struct flexcop_device *fc);
|
||||
|
||||
/* from flexcop-sram.c */
|
||||
int flexcop_sram_init(struct flexcop_device *fc);
|
||||
|
||||
/* from flexcop-misc.c */
|
||||
void flexcop_determine_revision(struct flexcop_device *fc);
|
||||
void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
|
||||
void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);
|
||||
|
||||
/* from flexcop-hw-filter.c */
|
||||
int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
|
||||
void flexcop_hw_filter_init(struct flexcop_device *fc);
|
||||
|
||||
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
|
||||
|
||||
void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
|
||||
void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
|
||||
|
||||
#endif
|
||||
171
drivers/media/dvb/b2c2/flexcop-dma.c
Normal file
171
drivers/media/dvb/b2c2/flexcop-dma.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
|
||||
{
|
||||
u8 *tcpu;
|
||||
dma_addr_t tdma;
|
||||
|
||||
if (size % 2) {
|
||||
err("dma buffersize has to be even.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
|
||||
dma->pdev = pdev;
|
||||
dma->cpu_addr0 = tcpu;
|
||||
dma->dma_addr0 = tdma;
|
||||
dma->cpu_addr1 = tcpu + size/2;
|
||||
dma->dma_addr1 = tdma + size/2;
|
||||
dma->size = size/2;
|
||||
return 0;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_allocate);
|
||||
|
||||
void flexcop_dma_free(struct flexcop_dma *dma)
|
||||
{
|
||||
pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
|
||||
memset(dma,0,sizeof(struct flexcop_dma));
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_free);
|
||||
|
||||
int flexcop_dma_config(struct flexcop_device *fc,
|
||||
struct flexcop_dma *dma,
|
||||
flexcop_dma_index_t dma_idx)
|
||||
{
|
||||
flexcop_ibi_value v0x0,v0x4,v0xc;
|
||||
v0x0.raw = v0x4.raw = v0xc.raw = 0;
|
||||
|
||||
v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
|
||||
v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
|
||||
v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
|
||||
|
||||
if ((dma_idx & FC_DMA_1) == dma_idx) {
|
||||
fc->write_ibi_reg(fc,dma1_000,v0x0);
|
||||
fc->write_ibi_reg(fc,dma1_004,v0x4);
|
||||
fc->write_ibi_reg(fc,dma1_00c,v0xc);
|
||||
} else if ((dma_idx & FC_DMA_2) == dma_idx) {
|
||||
fc->write_ibi_reg(fc,dma2_010,v0x0);
|
||||
fc->write_ibi_reg(fc,dma2_014,v0x4);
|
||||
fc->write_ibi_reg(fc,dma2_01c,v0xc);
|
||||
} else {
|
||||
err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_config);
|
||||
|
||||
/* start the DMA transfers, but not the DMA IRQs */
|
||||
int flexcop_dma_xfer_control(struct flexcop_device *fc,
|
||||
flexcop_dma_index_t dma_idx,
|
||||
flexcop_dma_addr_index_t index,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_value v0x0,v0xc;
|
||||
flexcop_ibi_register r0x0,r0xc;
|
||||
|
||||
if ((dma_idx & FC_DMA_1) == dma_idx) {
|
||||
r0x0 = dma1_000;
|
||||
r0xc = dma1_00c;
|
||||
} else if ((dma_idx & FC_DMA_2) == dma_idx) {
|
||||
r0x0 = dma2_010;
|
||||
r0xc = dma2_01c;
|
||||
} else {
|
||||
err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v0x0 = fc->read_ibi_reg(fc,r0x0);
|
||||
v0xc = fc->read_ibi_reg(fc,r0xc);
|
||||
|
||||
deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
|
||||
deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
|
||||
|
||||
if (index & FC_DMA_SUBADDR_0)
|
||||
v0x0.dma_0x0.dma_0start = onoff;
|
||||
|
||||
if (index & FC_DMA_SUBADDR_1)
|
||||
v0xc.dma_0xc.dma_1start = onoff;
|
||||
|
||||
fc->write_ibi_reg(fc,r0x0,v0x0);
|
||||
fc->write_ibi_reg(fc,r0xc,v0xc);
|
||||
|
||||
deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
|
||||
deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_xfer_control);
|
||||
|
||||
static int flexcop_dma_remap(struct flexcop_device *fc,
|
||||
flexcop_dma_index_t dma_idx,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
|
||||
deb_info("%s\n",__FUNCTION__);
|
||||
v.dma_0xc.remap_enable = onoff;
|
||||
fc->write_ibi_reg(fc,r,v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexcop_dma_control_size_irq(struct flexcop_device *fc,
|
||||
flexcop_dma_index_t no,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
|
||||
|
||||
if (no & FC_DMA_1)
|
||||
v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
|
||||
|
||||
if (no & FC_DMA_2)
|
||||
v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
|
||||
|
||||
fc->write_ibi_reg(fc,ctrl_208,v);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_control_size_irq);
|
||||
|
||||
int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
|
||||
flexcop_dma_index_t no,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
|
||||
|
||||
if (no & FC_DMA_1)
|
||||
v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
|
||||
|
||||
if (no & FC_DMA_2)
|
||||
v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
|
||||
|
||||
fc->write_ibi_reg(fc,ctrl_208,v);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
|
||||
|
||||
/* 1 cycles = 1.97 msec */
|
||||
int flexcop_dma_config_timer(struct flexcop_device *fc,
|
||||
flexcop_dma_index_t dma_idx,
|
||||
u8 cycles)
|
||||
{
|
||||
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
|
||||
|
||||
flexcop_dma_remap(fc,dma_idx,0);
|
||||
|
||||
deb_info("%s\n",__FUNCTION__);
|
||||
v.dma_0x4_write.dmatimer = cycles;
|
||||
fc->write_ibi_reg(fc,r,v);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_config_timer);
|
||||
|
||||
153
drivers/media/dvb/b2c2/flexcop-eeprom.c
Normal file
153
drivers/media/dvb/b2c2/flexcop-eeprom.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
#if 0
|
||||
/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
|
||||
static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
|
||||
{
|
||||
return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
|
||||
}
|
||||
|
||||
static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < retries; i++) {
|
||||
if (eeprom_write(adapter, addr, wbuf, len) == len) {
|
||||
if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These functions could be used to unlock SkyStar2 cards. */
|
||||
|
||||
static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
|
||||
{
|
||||
u8 rbuf[20];
|
||||
u8 wbuf[20];
|
||||
|
||||
if (len != 16)
|
||||
return 0;
|
||||
|
||||
memcpy(wbuf, key, len);
|
||||
|
||||
wbuf[16] = 0;
|
||||
wbuf[17] = 0;
|
||||
wbuf[18] = 0;
|
||||
wbuf[19] = calc_lrc(wbuf, 19);
|
||||
|
||||
return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
|
||||
}
|
||||
|
||||
static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
|
||||
{
|
||||
u8 buf[20];
|
||||
|
||||
if (len != 16)
|
||||
return 0;
|
||||
|
||||
if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
|
||||
return 0;
|
||||
|
||||
memcpy(key, buf, len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
|
||||
{
|
||||
u8 tmp[8];
|
||||
|
||||
if (type != 0) {
|
||||
tmp[0] = mac[0];
|
||||
tmp[1] = mac[1];
|
||||
tmp[2] = mac[2];
|
||||
tmp[3] = mac[5];
|
||||
tmp[4] = mac[6];
|
||||
tmp[5] = mac[7];
|
||||
|
||||
} else {
|
||||
|
||||
tmp[0] = mac[0];
|
||||
tmp[1] = mac[1];
|
||||
tmp[2] = mac[2];
|
||||
tmp[3] = mac[3];
|
||||
tmp[4] = mac[4];
|
||||
tmp[5] = mac[5];
|
||||
}
|
||||
|
||||
tmp[6] = 0;
|
||||
tmp[7] = calc_lrc(tmp, 7);
|
||||
|
||||
if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
|
||||
{
|
||||
return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static u8 calc_lrc(u8 *buf, int len)
|
||||
{
|
||||
int i;
|
||||
u8 sum = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
sum = sum ^ buf[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
|
||||
{
|
||||
int i,ret = 0;
|
||||
u8 chipaddr = 0x50 | ((addr >> 8) & 3);
|
||||
for (i = 0; i < retries; i++)
|
||||
if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
|
||||
break;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
|
||||
{
|
||||
int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
|
||||
if (ret == 0)
|
||||
if (calc_lrc(buf, len - 1) != buf[len - 1])
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* JJ's comment about extended == 1: it is not presently used anywhere but was
|
||||
* added to the low-level functions for possible support of EUI64
|
||||
*/
|
||||
int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
|
||||
{
|
||||
u8 buf[8];
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
|
||||
if (extended != 0) {
|
||||
err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
|
||||
ret = -EINVAL;
|
||||
/* memcpy(fc->dvb_adapter.proposed_mac,buf,3);
|
||||
mac[3] = 0xfe;
|
||||
mac[4] = 0xff;
|
||||
memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */
|
||||
} else
|
||||
memcpy(fc->dvb_adapter.proposed_mac,buf,6);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
|
||||
565
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
Normal file
565
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
Normal file
@@ -0,0 +1,565 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
#include "stv0299.h"
|
||||
#include "mt352.h"
|
||||
#include "nxt200x.h"
|
||||
#include "bcm3510.h"
|
||||
#include "stv0297.h"
|
||||
#include "mt312.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "dvb-pll.h"
|
||||
|
||||
/* lnb control */
|
||||
|
||||
static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
flexcop_ibi_value v;
|
||||
deb_tuner("polarity/voltage = %u\n", voltage);
|
||||
|
||||
v = fc->read_ibi_reg(fc, misc_204);
|
||||
switch (voltage) {
|
||||
case SEC_VOLTAGE_OFF:
|
||||
v.misc_204.ACPI1_sig = 1;
|
||||
break;
|
||||
case SEC_VOLTAGE_13:
|
||||
v.misc_204.ACPI1_sig = 0;
|
||||
v.misc_204.LNB_L_H_sig = 0;
|
||||
break;
|
||||
case SEC_VOLTAGE_18:
|
||||
v.misc_204.ACPI1_sig = 0;
|
||||
v.misc_204.LNB_L_H_sig = 1;
|
||||
break;
|
||||
default:
|
||||
err("unknown SEC_VOLTAGE value");
|
||||
return -EINVAL;
|
||||
}
|
||||
return fc->write_ibi_reg(fc, misc_204, v);
|
||||
}
|
||||
|
||||
static int flexcop_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
|
||||
|
||||
if (fc->fe_sleep)
|
||||
return fc->fe_sleep(fe);
|
||||
|
||||
/* v.misc_204.ACPI3_sig = 1;
|
||||
fc->write_ibi_reg(fc,misc_204,v);*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
flexcop_ibi_value v;
|
||||
u16 ax;
|
||||
v.raw = 0;
|
||||
|
||||
deb_tuner("tone = %u\n",tone);
|
||||
|
||||
switch (tone) {
|
||||
case SEC_TONE_ON:
|
||||
ax = 0x01ff;
|
||||
break;
|
||||
case SEC_TONE_OFF:
|
||||
ax = 0;
|
||||
break;
|
||||
default:
|
||||
err("unknown SEC_TONE value");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
|
||||
|
||||
v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
|
||||
v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
|
||||
|
||||
return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
|
||||
}
|
||||
|
||||
static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
|
||||
{
|
||||
flexcop_set_tone(fe, SEC_TONE_ON);
|
||||
udelay(data ? 500 : 1000);
|
||||
flexcop_set_tone(fe, SEC_TONE_OFF);
|
||||
udelay(data ? 1000 : 500);
|
||||
}
|
||||
|
||||
static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
|
||||
{
|
||||
int i, par = 1, d;
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
d = (data >> i) & 1;
|
||||
par ^= d;
|
||||
flexcop_diseqc_send_bit(fe, d);
|
||||
}
|
||||
|
||||
flexcop_diseqc_send_bit(fe, par);
|
||||
}
|
||||
|
||||
static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
|
||||
{
|
||||
int i;
|
||||
|
||||
flexcop_set_tone(fe, SEC_TONE_OFF);
|
||||
mdelay(16);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
flexcop_diseqc_send_byte(fe,msg[i]);
|
||||
|
||||
mdelay(16);
|
||||
|
||||
if (burst != -1) {
|
||||
if (burst)
|
||||
flexcop_diseqc_send_byte(fe, 0xff);
|
||||
else {
|
||||
flexcop_set_tone(fe, SEC_TONE_ON);
|
||||
udelay(12500);
|
||||
flexcop_set_tone(fe, SEC_TONE_OFF);
|
||||
}
|
||||
msleep(20);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
|
||||
{
|
||||
return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
|
||||
}
|
||||
|
||||
static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
|
||||
{
|
||||
return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
|
||||
}
|
||||
|
||||
/* dvb-s stv0299 */
|
||||
static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
|
||||
{
|
||||
u8 aclk = 0;
|
||||
u8 bclk = 0;
|
||||
|
||||
if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
|
||||
else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
|
||||
else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
|
||||
else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
|
||||
else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
|
||||
else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
|
||||
|
||||
stv0299_writereg (fe, 0x13, aclk);
|
||||
stv0299_writereg (fe, 0x14, bclk);
|
||||
stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
|
||||
stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
|
||||
stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
|
||||
div = params->frequency / 125;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = div & 0xff;
|
||||
buf[2] = 0x84; /* 0xC4 */
|
||||
buf[3] = 0x08;
|
||||
|
||||
if (params->frequency < 1500000) buf[3] |= 0x10;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 samsung_tbmu24112_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x30,
|
||||
0x03, 0x00,
|
||||
0x04, 0x7D,
|
||||
0x05, 0x35,
|
||||
0x06, 0x02,
|
||||
0x07, 0x00,
|
||||
0x08, 0xC3,
|
||||
0x0C, 0x00,
|
||||
0x0D, 0x81,
|
||||
0x0E, 0x23,
|
||||
0x0F, 0x12,
|
||||
0x10, 0x7E,
|
||||
0x11, 0x84,
|
||||
0x12, 0xB9,
|
||||
0x13, 0x88,
|
||||
0x14, 0x89,
|
||||
0x15, 0xC9,
|
||||
0x16, 0x00,
|
||||
0x17, 0x5C,
|
||||
0x18, 0x00,
|
||||
0x19, 0x00,
|
||||
0x1A, 0x00,
|
||||
0x1C, 0x00,
|
||||
0x1D, 0x00,
|
||||
0x1E, 0x00,
|
||||
0x1F, 0x3A,
|
||||
0x20, 0x2E,
|
||||
0x21, 0x80,
|
||||
0x22, 0xFF,
|
||||
0x23, 0xC1,
|
||||
0x28, 0x00,
|
||||
0x29, 0x1E,
|
||||
0x2A, 0x14,
|
||||
0x2B, 0x0F,
|
||||
0x2C, 0x09,
|
||||
0x2D, 0x05,
|
||||
0x31, 0x1F,
|
||||
0x32, 0x19,
|
||||
0x33, 0xFE,
|
||||
0x34, 0x93,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static struct stv0299_config samsung_tbmu24112_config = {
|
||||
.demod_address = 0x68,
|
||||
.inittab = samsung_tbmu24112_inittab,
|
||||
.mclk = 88000000UL,
|
||||
.invert = 0,
|
||||
.skip_reinit = 0,
|
||||
.lock_output = STV0229_LOCKOUTPUT_LK,
|
||||
.volt13_op0_op1 = STV0299_VOLT13_OP1,
|
||||
.min_delay_ms = 100,
|
||||
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
|
||||
};
|
||||
|
||||
/* dvb-t mt352 */
|
||||
static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
|
||||
{
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
|
||||
if (buf_len < 5)
|
||||
return -EINVAL;
|
||||
|
||||
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
|
||||
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
|
||||
if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
|
||||
if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0x61;
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = 0xcc;
|
||||
pllbuf[4] = bs;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static struct mt352_config samsung_tdtc9251dh0_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = samsung_tdtc9251dh0_demod_init,
|
||||
};
|
||||
|
||||
static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
|
||||
{
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
return request_firmware(fw, name, fc->dev);
|
||||
}
|
||||
|
||||
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
|
||||
.demod_address = 0x59,
|
||||
.demod_chip = LGDT3303,
|
||||
.serial_mpeg = 0x04,
|
||||
.clock_polarity_flip = 1,
|
||||
};
|
||||
|
||||
static struct nxt200x_config samsung_tbmv_config = {
|
||||
.demod_address = 0x0a,
|
||||
};
|
||||
|
||||
static struct bcm3510_config air2pc_atsc_first_gen_config = {
|
||||
.demod_address = 0x0f,
|
||||
.request_firmware = flexcop_fe_request_firmware,
|
||||
};
|
||||
|
||||
static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
|
||||
div = (params->frequency + (125/2)) / 125;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = (div >> 0) & 0xff;
|
||||
buf[2] = 0x84 | ((div >> 10) & 0x60);
|
||||
buf[3] = 0x80;
|
||||
|
||||
if (params->frequency < 1550000)
|
||||
buf[3] |= 0x02;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt312_config skystar23_samsung_tbdu18132_config = {
|
||||
|
||||
.demod_address = 0x0e,
|
||||
};
|
||||
|
||||
static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
u8 buf[4];
|
||||
u16 div;
|
||||
int ret;
|
||||
|
||||
/* 62.5 kHz * 10 */
|
||||
#define REF_FREQ 625
|
||||
#define FREQ_OFFSET 36125
|
||||
|
||||
div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz
|
||||
|
||||
buf[0] = (u8)( div >> 8) & 0x7f;
|
||||
buf[1] = (u8) div & 0xff;
|
||||
|
||||
/* F(osc) = N * Reference Freq. (62.5 kHz)
|
||||
* byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
|
||||
* byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
|
||||
* byte 4 : 1 * * AGD R3 R2 R1 R0
|
||||
* byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
|
||||
* AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
|
||||
buf[2] = 0x95;
|
||||
|
||||
// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
|
||||
// 47 - 153 0 * 0 0 0 0 0 1 0x01
|
||||
// 153 - 430 0 * 0 0 0 0 1 0 0x02
|
||||
// 430 - 822 0 * 0 0 1 0 0 0 0x08
|
||||
// 822 - 862 1 * 0 0 1 0 0 0 0x88
|
||||
|
||||
if (fep->frequency <= 153000000) buf[3] = 0x01;
|
||||
else if (fep->frequency <= 430000000) buf[3] = 0x02;
|
||||
else if (fep->frequency <= 822000000) buf[3] = 0x08;
|
||||
else buf[3] = 0x88;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
|
||||
ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
|
||||
deb_tuner("tuner write returned: %d\n",ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 alps_tdee4_stv0297_inittab[] = {
|
||||
0x80, 0x01,
|
||||
0x80, 0x00,
|
||||
0x81, 0x01,
|
||||
0x81, 0x00,
|
||||
0x00, 0x48,
|
||||
0x01, 0x58,
|
||||
0x03, 0x00,
|
||||
0x04, 0x00,
|
||||
0x07, 0x00,
|
||||
0x08, 0x00,
|
||||
0x30, 0xff,
|
||||
0x31, 0x9d,
|
||||
0x32, 0xff,
|
||||
0x33, 0x00,
|
||||
0x34, 0x29,
|
||||
0x35, 0x55,
|
||||
0x36, 0x80,
|
||||
0x37, 0x6e,
|
||||
0x38, 0x9c,
|
||||
0x40, 0x1a,
|
||||
0x41, 0xfe,
|
||||
0x42, 0x33,
|
||||
0x43, 0x00,
|
||||
0x44, 0xff,
|
||||
0x45, 0x00,
|
||||
0x46, 0x00,
|
||||
0x49, 0x04,
|
||||
0x4a, 0x51,
|
||||
0x4b, 0xf8,
|
||||
0x52, 0x30,
|
||||
0x53, 0x06,
|
||||
0x59, 0x06,
|
||||
0x5a, 0x5e,
|
||||
0x5b, 0x04,
|
||||
0x61, 0x49,
|
||||
0x62, 0x0a,
|
||||
0x70, 0xff,
|
||||
0x71, 0x04,
|
||||
0x72, 0x00,
|
||||
0x73, 0x00,
|
||||
0x74, 0x0c,
|
||||
0x80, 0x20,
|
||||
0x81, 0x00,
|
||||
0x82, 0x30,
|
||||
0x83, 0x00,
|
||||
0x84, 0x04,
|
||||
0x85, 0x22,
|
||||
0x86, 0x08,
|
||||
0x87, 0x1b,
|
||||
0x88, 0x00,
|
||||
0x89, 0x00,
|
||||
0x90, 0x00,
|
||||
0x91, 0x04,
|
||||
0xa0, 0x86,
|
||||
0xa1, 0x00,
|
||||
0xa2, 0x00,
|
||||
0xb0, 0x91,
|
||||
0xb1, 0x0b,
|
||||
0xc0, 0x5b,
|
||||
0xc1, 0x10,
|
||||
0xc2, 0x12,
|
||||
0xd0, 0x02,
|
||||
0xd1, 0x00,
|
||||
0xd2, 0x00,
|
||||
0xd3, 0x00,
|
||||
0xd4, 0x02,
|
||||
0xd5, 0x00,
|
||||
0xde, 0x00,
|
||||
0xdf, 0x01,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static struct stv0297_config alps_tdee4_stv0297_config = {
|
||||
.demod_address = 0x1c,
|
||||
.inittab = alps_tdee4_stv0297_inittab,
|
||||
// .invert = 1,
|
||||
// .pll_set = alps_tdee4_stv0297_pll_set,
|
||||
};
|
||||
|
||||
/* try to figure out the frontend, each card/box can have on of the following list */
|
||||
int flexcop_frontend_init(struct flexcop_device *fc)
|
||||
{
|
||||
struct dvb_frontend_ops *ops;
|
||||
|
||||
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
|
||||
if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
|
||||
ops = &fc->fe->ops;
|
||||
|
||||
ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
|
||||
|
||||
ops->set_voltage = flexcop_set_voltage;
|
||||
|
||||
fc->fe_sleep = ops->sleep;
|
||||
ops->sleep = flexcop_sleep;
|
||||
|
||||
fc->dev_type = FC_SKY;
|
||||
info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
|
||||
} else
|
||||
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
|
||||
if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
|
||||
fc->dev_type = FC_AIR_DVB;
|
||||
fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
|
||||
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
|
||||
} else
|
||||
/* try the air atsc 2nd generation (nxt2002) */
|
||||
if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->dev_type = FC_AIR_ATSC2;
|
||||
dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
|
||||
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
|
||||
} else
|
||||
/* try the air atsc 3nd generation (lgdt3303) */
|
||||
if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->dev_type = FC_AIR_ATSC3;
|
||||
dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap);
|
||||
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
|
||||
} else
|
||||
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
|
||||
if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->dev_type = FC_AIR_ATSC1;
|
||||
info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
|
||||
} else
|
||||
/* try the cable dvb (stv0297) */
|
||||
if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->dev_type = FC_CABLE;
|
||||
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
|
||||
info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
|
||||
} else
|
||||
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
|
||||
if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
|
||||
ops = &fc->fe->ops;
|
||||
|
||||
ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
|
||||
|
||||
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
|
||||
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
|
||||
ops->set_tone = flexcop_set_tone;
|
||||
ops->set_voltage = flexcop_set_voltage;
|
||||
|
||||
fc->fe_sleep = ops->sleep;
|
||||
ops->sleep = flexcop_sleep;
|
||||
|
||||
fc->dev_type = FC_SKY_OLD;
|
||||
info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
|
||||
}
|
||||
|
||||
if (fc->fe == NULL) {
|
||||
err("no frontend driver found for this B2C2/FlexCop adapter");
|
||||
return -ENODEV;
|
||||
} else {
|
||||
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
|
||||
err("frontend registration failed!");
|
||||
dvb_frontend_detach(fc->fe);
|
||||
fc->fe = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
fc->init_state |= FC_STATE_FE_INIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexcop_frontend_exit(struct flexcop_device *fc)
|
||||
{
|
||||
if (fc->init_state & FC_STATE_FE_INIT) {
|
||||
dvb_unregister_frontend(fc->fe);
|
||||
dvb_frontend_detach(fc->fe);
|
||||
}
|
||||
|
||||
fc->init_state &= ~FC_STATE_FE_INIT;
|
||||
}
|
||||
212
drivers/media/dvb/b2c2/flexcop-hw-filter.c
Normal file
212
drivers/media/dvb/b2c2/flexcop-hw-filter.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
|
||||
|
||||
deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
|
||||
}
|
||||
|
||||
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
|
||||
}
|
||||
|
||||
static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff);
|
||||
}
|
||||
|
||||
void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
|
||||
{
|
||||
flexcop_ibi_value v418,v41c;
|
||||
v41c = fc->read_ibi_reg(fc,mac_address_41c);
|
||||
|
||||
v418.mac_address_418.MAC1 = mac[0];
|
||||
v418.mac_address_418.MAC2 = mac[1];
|
||||
v418.mac_address_418.MAC3 = mac[2];
|
||||
v418.mac_address_418.MAC6 = mac[3];
|
||||
v41c.mac_address_41c.MAC7 = mac[4];
|
||||
v41c.mac_address_41c.MAC8 = mac[5];
|
||||
|
||||
fc->write_ibi_reg(fc,mac_address_418,v418);
|
||||
fc->write_ibi_reg(fc,mac_address_41c,v41c);
|
||||
}
|
||||
|
||||
void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff);
|
||||
}
|
||||
|
||||
static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask)
|
||||
{
|
||||
/* index_reg_310.extra_index_reg need to 0 or 7 to work */
|
||||
flexcop_ibi_value v30c;
|
||||
v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
|
||||
v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
|
||||
fc->write_ibi_reg(fc,pid_filter_30c,v30c);
|
||||
}
|
||||
|
||||
static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff);
|
||||
}
|
||||
|
||||
/* this fancy define reduces the code size of the quite similar PID controlling of
|
||||
* the first 6 PIDs
|
||||
*/
|
||||
|
||||
#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
|
||||
flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
|
||||
v208 = fc->read_ibi_reg(fc, ctrl_208); \
|
||||
\
|
||||
vpid.vregname.field = onoff ? pid : 0x1fff; \
|
||||
vpid.vregname.trans_field = transval; \
|
||||
v208.ctrl_208.enablefield = onoff; \
|
||||
\
|
||||
fc->write_ibi_reg(fc,vregname,vpid); \
|
||||
fc->write_ibi_reg(fc,ctrl_208,v208);
|
||||
|
||||
static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
|
||||
{
|
||||
pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0);
|
||||
}
|
||||
|
||||
static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
|
||||
{
|
||||
pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0);
|
||||
}
|
||||
|
||||
static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
|
||||
{
|
||||
pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0);
|
||||
}
|
||||
|
||||
static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
|
||||
{
|
||||
pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0);
|
||||
}
|
||||
|
||||
static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
|
||||
{
|
||||
pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0);
|
||||
}
|
||||
|
||||
static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff)
|
||||
{
|
||||
pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0);
|
||||
}
|
||||
|
||||
static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff)
|
||||
{
|
||||
if (pid == 0x2000)
|
||||
return;
|
||||
|
||||
deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off");
|
||||
|
||||
/* We could use bit magic here to reduce source code size.
|
||||
* I decided against it, but to use the real register names */
|
||||
switch (index) {
|
||||
case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break;
|
||||
case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break;
|
||||
case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break;
|
||||
case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break;
|
||||
case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break;
|
||||
case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break;
|
||||
default:
|
||||
if (fc->has_32_hw_pid_filter && index < 38) {
|
||||
flexcop_ibi_value vpid,vid;
|
||||
|
||||
/* set the index */
|
||||
vid = fc->read_ibi_reg(fc,index_reg_310);
|
||||
vid.index_reg_310.index_reg = index - 6;
|
||||
fc->write_ibi_reg(fc,index_reg_310, vid);
|
||||
|
||||
vpid = fc->read_ibi_reg(fc,pid_n_reg_314);
|
||||
vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
|
||||
vpid.pid_n_reg_314.PID_enable_bit = onoff;
|
||||
fc->write_ibi_reg(fc,pid_n_reg_314, vpid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff)
|
||||
{
|
||||
if (fc->fullts_streaming_state != onoff) {
|
||||
deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
|
||||
flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
|
||||
flexcop_pid_group_filter_ctrl(fc,onoff);
|
||||
fc->fullts_streaming_state = onoff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff)
|
||||
{
|
||||
int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
|
||||
|
||||
fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
|
||||
if (dvbdmxfeed->index >= max_pid_filter)
|
||||
fc->extra_feedcount += onoff ? 1 : -1;
|
||||
|
||||
/* toggle complete-TS-streaming when:
|
||||
* - pid_filtering is not enabled and it is the first or last feed requested
|
||||
* - pid_filtering is enabled,
|
||||
* - but the number of requested feeds is exceeded
|
||||
* - or the requested pid is 0x2000 */
|
||||
|
||||
if (!fc->pid_filtering && fc->feedcount == onoff)
|
||||
flexcop_toggle_fullts_streaming(fc,onoff);
|
||||
|
||||
if (fc->pid_filtering) {
|
||||
flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
|
||||
|
||||
if (fc->extra_feedcount > 0)
|
||||
flexcop_toggle_fullts_streaming(fc,1);
|
||||
else if (dvbdmxfeed->pid == 0x2000)
|
||||
flexcop_toggle_fullts_streaming(fc,onoff);
|
||||
else
|
||||
flexcop_toggle_fullts_streaming(fc,0);
|
||||
}
|
||||
|
||||
/* if it was the first or last feed request change the stream-status */
|
||||
if (fc->feedcount == onoff) {
|
||||
flexcop_rcv_data_ctrl(fc,onoff);
|
||||
if (fc->stream_control) /* device specific stream control */
|
||||
fc->stream_control(fc,onoff);
|
||||
|
||||
/* feeding stopped -> reset the flexcop filter*/
|
||||
if (onoff == 0) {
|
||||
flexcop_reset_block_300(fc);
|
||||
flexcop_hw_filter_init(fc);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexcop_hw_filter_init(struct flexcop_device *fc)
|
||||
{
|
||||
int i;
|
||||
flexcop_ibi_value v;
|
||||
for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
|
||||
flexcop_pid_control(fc,i,0x1fff,0);
|
||||
|
||||
flexcop_pid_group_filter(fc, 0, 0x1fe0);
|
||||
flexcop_pid_group_filter_ctrl(fc,0);
|
||||
|
||||
v = fc->read_ibi_reg(fc,pid_filter_308);
|
||||
v.pid_filter_308.EMM_filter_4 = 1;
|
||||
v.pid_filter_308.EMM_filter_6 = 0;
|
||||
fc->write_ibi_reg(fc,pid_filter_308,v);
|
||||
|
||||
flexcop_null_filter_ctrl(fc, 1);
|
||||
}
|
||||
208
drivers/media/dvb/b2c2/flexcop-i2c.c
Normal file
208
drivers/media/dvb/b2c2/flexcop-i2c.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
#define FC_MAX_I2C_RETRIES 100000
|
||||
|
||||
static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
|
||||
{
|
||||
int i;
|
||||
flexcop_ibi_value r;
|
||||
|
||||
r100->tw_sm_c_100.working_start = 1;
|
||||
deb_i2c("r100 before: %08x\n",r100->raw);
|
||||
|
||||
fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
|
||||
fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
|
||||
|
||||
for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
|
||||
r = fc->read_ibi_reg(fc, tw_sm_c_100);
|
||||
|
||||
if (!r.tw_sm_c_100.no_base_addr_ack_error) {
|
||||
if (r.tw_sm_c_100.st_done) { /* && !r.tw_sm_c_100.working_start */
|
||||
*r100 = r;
|
||||
deb_i2c("i2c success\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
deb_i2c("suffering from an i2c ack_error\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
|
||||
{
|
||||
flexcop_ibi_value r104;
|
||||
int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
|
||||
ret;
|
||||
|
||||
if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
|
||||
/* The Cablestar needs a different kind of i2c-transfer (does not
|
||||
* support "Repeat Start"):
|
||||
* wait for the ACK failure,
|
||||
* and do a subsequent read with the Bit 30 enabled
|
||||
*/
|
||||
r100.tw_sm_c_100.no_base_addr_ack_error = 1;
|
||||
if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
|
||||
deb_i2c("no_base_addr read failed. %d\n",ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
buf[0] = r100.tw_sm_c_100.data1_reg;
|
||||
|
||||
if (len > 0) {
|
||||
r104 = fc->read_ibi_reg(fc,tw_sm_c_104);
|
||||
deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
|
||||
|
||||
/* there is at least one more byte, otherwise we wouldn't be here */
|
||||
buf[1] = r104.tw_sm_c_104.data2_reg;
|
||||
if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
|
||||
if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
|
||||
{
|
||||
flexcop_ibi_value r104;
|
||||
int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
|
||||
r104.raw = 0;
|
||||
|
||||
/* there is at least one byte, otherwise we wouldn't be here */
|
||||
r100.tw_sm_c_100.data1_reg = buf[0];
|
||||
|
||||
r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
|
||||
r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
|
||||
r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
|
||||
|
||||
deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
|
||||
|
||||
/* write the additional i2c data before doing the actual i2c operation */
|
||||
fc->write_ibi_reg(fc,tw_sm_c_104,r104);
|
||||
return flexcop_i2c_operation(fc,&r100);
|
||||
}
|
||||
|
||||
int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
|
||||
flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
int ret;
|
||||
u16 bytes_to_transfer;
|
||||
flexcop_ibi_value r100;
|
||||
|
||||
deb_i2c("op = %d\n",op);
|
||||
r100.raw = 0;
|
||||
r100.tw_sm_c_100.chipaddr = chipaddr;
|
||||
r100.tw_sm_c_100.twoWS_rw = op;
|
||||
r100.tw_sm_c_100.twoWS_port_reg = port;
|
||||
|
||||
while (len != 0) {
|
||||
bytes_to_transfer = len > 4 ? 4 : len;
|
||||
|
||||
r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
|
||||
r100.tw_sm_c_100.baseaddr = addr;
|
||||
|
||||
if (op == FC_READ)
|
||||
ret = flexcop_i2c_read4(fc, r100, buf);
|
||||
else
|
||||
ret = flexcop_i2c_write4(fc,r100, buf);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
buf += bytes_to_transfer;
|
||||
addr += bytes_to_transfer;
|
||||
len -= bytes_to_transfer;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* exported for PCI i2c */
|
||||
EXPORT_SYMBOL(flexcop_i2c_request);
|
||||
|
||||
/* master xfer callback for demodulator */
|
||||
static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
|
||||
int i, ret = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&fc->i2c_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* reading */
|
||||
if (num == 2 &&
|
||||
msgs[0].flags == 0 &&
|
||||
msgs[1].flags == I2C_M_RD &&
|
||||
msgs[0].buf != NULL &&
|
||||
msgs[1].buf != NULL) {
|
||||
|
||||
ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
|
||||
|
||||
} else for (i = 0; i < num; i++) { /* writing command */
|
||||
if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
err("i2c master_xfer failed");
|
||||
else
|
||||
ret = num;
|
||||
|
||||
mutex_unlock(&fc->i2c_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm flexcop_algo = {
|
||||
.master_xfer = flexcop_master_xfer,
|
||||
.functionality = flexcop_i2c_func,
|
||||
};
|
||||
|
||||
int flexcop_i2c_init(struct flexcop_device *fc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_init(&fc->i2c_mutex);
|
||||
|
||||
memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
|
||||
strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
|
||||
|
||||
i2c_set_adapdata(&fc->i2c_adap,fc);
|
||||
|
||||
fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
fc->i2c_adap.algo = &flexcop_algo;
|
||||
fc->i2c_adap.algo_data = NULL;
|
||||
fc->i2c_adap.dev.parent = fc->dev;
|
||||
|
||||
if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
|
||||
return ret;
|
||||
|
||||
fc->init_state |= FC_STATE_I2C_INIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexcop_i2c_exit(struct flexcop_device *fc)
|
||||
{
|
||||
if (fc->init_state & FC_STATE_I2C_INIT)
|
||||
i2c_del_adapter(&fc->i2c_adap);
|
||||
|
||||
fc->init_state &= ~FC_STATE_I2C_INIT;
|
||||
}
|
||||
80
drivers/media/dvb/b2c2/flexcop-misc.c
Normal file
80
drivers/media/dvb/b2c2/flexcop-misc.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-misc.c - miscellaneous functions.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
void flexcop_determine_revision(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
|
||||
|
||||
switch (v.misc_204.Rev_N_sig_revision_hi) {
|
||||
case 0x2:
|
||||
deb_info("found a FlexCopII.\n");
|
||||
fc->rev = FLEXCOP_II;
|
||||
break;
|
||||
case 0x3:
|
||||
deb_info("found a FlexCopIIb.\n");
|
||||
fc->rev = FLEXCOP_IIB;
|
||||
break;
|
||||
case 0x0:
|
||||
deb_info("found a FlexCopIII.\n");
|
||||
fc->rev = FLEXCOP_III;
|
||||
break;
|
||||
default:
|
||||
err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
|
||||
deb_info("this FlexCop has the additional 32 hardware pid filter.\n");
|
||||
else
|
||||
deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n");
|
||||
/* bus parts have to decide if hw pid filtering is used or not. */
|
||||
}
|
||||
|
||||
static const char *flexcop_revision_names[] = {
|
||||
"Unkown chip",
|
||||
"FlexCopII",
|
||||
"FlexCopIIb",
|
||||
"FlexCopIII",
|
||||
};
|
||||
|
||||
static const char *flexcop_device_names[] = {
|
||||
"Unkown device",
|
||||
"Air2PC/AirStar 2 DVB-T",
|
||||
"Air2PC/AirStar 2 ATSC 1st generation",
|
||||
"Air2PC/AirStar 2 ATSC 2nd generation",
|
||||
"Sky2PC/SkyStar 2 DVB-S",
|
||||
"Sky2PC/SkyStar 2 DVB-S (old version)",
|
||||
"Cable2PC/CableStar 2 DVB-C",
|
||||
"Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
|
||||
};
|
||||
|
||||
static const char *flexcop_bus_names[] = {
|
||||
"USB",
|
||||
"PCI",
|
||||
};
|
||||
|
||||
void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
|
||||
char *suffix)
|
||||
{
|
||||
info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix,
|
||||
flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
|
||||
flexcop_revision_names[fc->rev],suffix);
|
||||
}
|
||||
|
||||
void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
|
||||
{
|
||||
flexcop_ibi_value v;
|
||||
int i;
|
||||
for (i = 0; i < num; i++) {
|
||||
v = fc->read_ibi_reg(fc,reg+4*i);
|
||||
deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
|
||||
}
|
||||
deb_rdump("\n");
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dump_reg);
|
||||
431
drivers/media/dvb/b2c2/flexcop-pci.c
Normal file
431
drivers/media/dvb/b2c2/flexcop-pci.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-pci.c - covers the PCI part including DMA transfers.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
|
||||
#define FC_LOG_PREFIX "flexcop-pci"
|
||||
#include "flexcop-common.h"
|
||||
|
||||
static int enable_pid_filtering = 1;
|
||||
module_param(enable_pid_filtering, int, 0444);
|
||||
MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
|
||||
|
||||
static int irq_chk_intv;
|
||||
module_param(irq_chk_intv, int, 0644);
|
||||
MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
|
||||
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define dprintk(level,args...) \
|
||||
do { if ((debug & level)) printk(args); } while (0)
|
||||
#define DEBSTATUS ""
|
||||
#else
|
||||
#define dprintk(level,args...)
|
||||
#define DEBSTATUS " (debugging is not enabled)"
|
||||
#endif
|
||||
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_reg(args...) dprintk(0x02,args)
|
||||
#define deb_ts(args...) dprintk(0x04,args)
|
||||
#define deb_irq(args...) dprintk(0x08,args)
|
||||
#define deb_chk(args...) dprintk(0x10,args)
|
||||
|
||||
static int debug = 0;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
|
||||
|
||||
#define DRIVER_VERSION "0.1"
|
||||
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
|
||||
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
|
||||
|
||||
struct flexcop_pci {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
#define FC_PCI_INIT 0x01
|
||||
#define FC_PCI_DMA_INIT 0x02
|
||||
int init_state;
|
||||
|
||||
void __iomem *io_mem;
|
||||
u32 irq;
|
||||
/* buffersize (at least for DMA1, need to be % 188 == 0,
|
||||
* this logic is required */
|
||||
#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
|
||||
#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
|
||||
struct flexcop_dma dma[2];
|
||||
|
||||
int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
|
||||
u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
|
||||
int count;
|
||||
|
||||
spinlock_t irq_lock;
|
||||
|
||||
unsigned long last_irq;
|
||||
|
||||
struct delayed_work irq_check_work;
|
||||
|
||||
struct flexcop_device *fc_dev;
|
||||
};
|
||||
|
||||
static int lastwreg,lastwval,lastrreg,lastrval;
|
||||
|
||||
static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = fc->bus_specific;
|
||||
flexcop_ibi_value v;
|
||||
v.raw = readl(fc_pci->io_mem + r);
|
||||
|
||||
if (lastrreg != r || lastrval != v.raw) {
|
||||
lastrreg = r; lastrval = v.raw;
|
||||
deb_reg("new rd: %3x: %08x\n",r,v.raw);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = fc->bus_specific;
|
||||
|
||||
if (lastwreg != r || lastwval != v.raw) {
|
||||
lastwreg = r; lastwval = v.raw;
|
||||
deb_reg("new wr: %3x: %08x\n",r,v.raw);
|
||||
}
|
||||
|
||||
writel(v.raw, fc_pci->io_mem + r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flexcop_pci_irq_check_work(struct work_struct *work)
|
||||
{
|
||||
struct flexcop_pci *fc_pci =
|
||||
container_of(work, struct flexcop_pci, irq_check_work.work);
|
||||
struct flexcop_device *fc = fc_pci->fc_dev;
|
||||
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
|
||||
|
||||
flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
|
||||
|
||||
if (v.sram_dest_reg_714.net_ovflow_error)
|
||||
deb_chk("sram net_ovflow_error\n");
|
||||
if (v.sram_dest_reg_714.media_ovflow_error)
|
||||
deb_chk("sram media_ovflow_error\n");
|
||||
if (v.sram_dest_reg_714.cai_ovflow_error)
|
||||
deb_chk("sram cai_ovflow_error\n");
|
||||
if (v.sram_dest_reg_714.cai_ovflow_error)
|
||||
deb_chk("sram cai_ovflow_error\n");
|
||||
|
||||
schedule_delayed_work(&fc_pci->irq_check_work,
|
||||
msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
|
||||
}
|
||||
|
||||
/* When PID filtering is turned on, we use the timer IRQ, because small amounts
|
||||
* of data need to be passed to the user space instantly as well. When PID
|
||||
* filtering is turned off, we use the page-change-IRQ */
|
||||
static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = dev_id;
|
||||
struct flexcop_device *fc = fc_pci->fc_dev;
|
||||
flexcop_ibi_value v;
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
|
||||
spin_lock_irq(&fc_pci->irq_lock);
|
||||
|
||||
v = fc->read_ibi_reg(fc,irq_20c);
|
||||
|
||||
/* errors */
|
||||
if (v.irq_20c.Data_receiver_error)
|
||||
deb_chk("data receiver error\n");
|
||||
if (v.irq_20c.Continuity_error_flag)
|
||||
deb_chk("Contunuity error flag is set\n");
|
||||
if (v.irq_20c.LLC_SNAP_FLAG_set)
|
||||
deb_chk("LLC_SNAP_FLAG_set is set\n");
|
||||
if (v.irq_20c.Transport_Error)
|
||||
deb_chk("Transport error\n");
|
||||
|
||||
if ((fc_pci->count % 1000) == 0)
|
||||
deb_chk("%d valid irq took place so far\n",fc_pci->count);
|
||||
|
||||
if (v.irq_20c.DMA1_IRQ_Status == 1) {
|
||||
if (fc_pci->active_dma1_addr == 0)
|
||||
flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
|
||||
else
|
||||
flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188);
|
||||
|
||||
deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
|
||||
fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
|
||||
} else if (v.irq_20c.DMA1_Timer_Status == 1) {
|
||||
/* for the timer IRQ we only can use buffer dmx feeding, because we don't have
|
||||
* complete TS packets when reading from the DMA memory */
|
||||
dma_addr_t cur_addr =
|
||||
fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
|
||||
u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
|
||||
|
||||
deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, last_cur_pos: %08x ",
|
||||
jiffies_to_usecs(jiffies - fc_pci->last_irq),
|
||||
v.raw, (unsigned long long)cur_addr, cur_pos,
|
||||
fc_pci->last_dma1_cur_pos);
|
||||
fc_pci->last_irq = jiffies;
|
||||
|
||||
/* buffer end was reached, restarted from the beginning
|
||||
* pass the data from last_cur_pos to the buffer end to the demux
|
||||
*/
|
||||
if (cur_pos < fc_pci->last_dma1_cur_pos) {
|
||||
deb_irq(" end was reached: passing %d bytes ",(fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos);
|
||||
flexcop_pass_dmx_data(fc_pci->fc_dev,
|
||||
fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
|
||||
(fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
|
||||
fc_pci->last_dma1_cur_pos = 0;
|
||||
}
|
||||
|
||||
if (cur_pos > fc_pci->last_dma1_cur_pos) {
|
||||
deb_irq(" passing %d bytes ",cur_pos - fc_pci->last_dma1_cur_pos);
|
||||
flexcop_pass_dmx_data(fc_pci->fc_dev,
|
||||
fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
|
||||
cur_pos - fc_pci->last_dma1_cur_pos);
|
||||
}
|
||||
deb_irq("\n");
|
||||
|
||||
fc_pci->last_dma1_cur_pos = cur_pos;
|
||||
fc_pci->count++;
|
||||
} else {
|
||||
deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
|
||||
ret = IRQ_NONE;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&fc_pci->irq_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = fc->bus_specific;
|
||||
if (onoff) {
|
||||
flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
|
||||
flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
|
||||
|
||||
flexcop_dma_config_timer(fc,FC_DMA_1,0);
|
||||
|
||||
flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
|
||||
deb_irq("DMA xfer enabled\n");
|
||||
|
||||
fc_pci->last_dma1_cur_pos = 0;
|
||||
flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
|
||||
deb_irq("IRQ enabled\n");
|
||||
|
||||
// fc_pci->active_dma1_addr = 0;
|
||||
// flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
|
||||
|
||||
if (irq_chk_intv > 0)
|
||||
schedule_delayed_work(&fc_pci->irq_check_work,
|
||||
msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
|
||||
} else {
|
||||
if (irq_chk_intv > 0)
|
||||
cancel_delayed_work(&fc_pci->irq_check_work);
|
||||
|
||||
flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
|
||||
deb_irq("IRQ disabled\n");
|
||||
|
||||
// flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
|
||||
|
||||
flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
|
||||
deb_irq("DMA xfer disabled\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
|
||||
flexcop_dma_free(&fc_pci->dma[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
|
||||
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
|
||||
|
||||
fc_pci->init_state |= FC_PCI_DMA_INIT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
if (fc_pci->init_state & FC_PCI_DMA_INIT) {
|
||||
flexcop_dma_free(&fc_pci->dma[0]);
|
||||
flexcop_dma_free(&fc_pci->dma[1]);
|
||||
}
|
||||
fc_pci->init_state &= ~FC_PCI_DMA_INIT;
|
||||
}
|
||||
|
||||
static int flexcop_pci_init(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
int ret;
|
||||
u8 card_rev;
|
||||
|
||||
pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
|
||||
info("card revision %x", card_rev);
|
||||
|
||||
if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
|
||||
return ret;
|
||||
|
||||
pci_set_master(fc_pci->pdev);
|
||||
|
||||
/* enable interrupts */
|
||||
// pci_write_config_dword(pdev, 0x6c, 0x8000);
|
||||
|
||||
if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
|
||||
goto err_pci_disable_device;
|
||||
|
||||
fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800);
|
||||
|
||||
if (!fc_pci->io_mem) {
|
||||
err("cannot map io memory\n");
|
||||
ret = -EIO;
|
||||
goto err_pci_release_regions;
|
||||
}
|
||||
|
||||
pci_set_drvdata(fc_pci->pdev, fc_pci);
|
||||
|
||||
if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
|
||||
IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
|
||||
goto err_pci_iounmap;
|
||||
|
||||
spin_lock_init(&fc_pci->irq_lock);
|
||||
|
||||
fc_pci->init_state |= FC_PCI_INIT;
|
||||
return ret;
|
||||
|
||||
err_pci_iounmap:
|
||||
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
|
||||
pci_set_drvdata(fc_pci->pdev, NULL);
|
||||
err_pci_release_regions:
|
||||
pci_release_regions(fc_pci->pdev);
|
||||
err_pci_disable_device:
|
||||
pci_disable_device(fc_pci->pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
if (fc_pci->init_state & FC_PCI_INIT) {
|
||||
free_irq(fc_pci->pdev->irq, fc_pci);
|
||||
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
|
||||
pci_set_drvdata(fc_pci->pdev, NULL);
|
||||
pci_release_regions(fc_pci->pdev);
|
||||
pci_disable_device(fc_pci->pdev);
|
||||
}
|
||||
fc_pci->init_state &= ~FC_PCI_INIT;
|
||||
}
|
||||
|
||||
|
||||
static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct flexcop_device *fc;
|
||||
struct flexcop_pci *fc_pci;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) {
|
||||
err("out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* general flexcop init */
|
||||
fc_pci = fc->bus_specific;
|
||||
fc_pci->fc_dev = fc;
|
||||
|
||||
fc->read_ibi_reg = flexcop_pci_read_ibi_reg;
|
||||
fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
|
||||
fc->i2c_request = flexcop_i2c_request;
|
||||
fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
|
||||
|
||||
fc->stream_control = flexcop_pci_stream_control;
|
||||
|
||||
if (enable_pid_filtering)
|
||||
info("will use the HW PID filter.");
|
||||
else
|
||||
info("will pass the complete TS to the demuxer.");
|
||||
|
||||
fc->pid_filtering = enable_pid_filtering;
|
||||
fc->bus_type = FC_PCI;
|
||||
|
||||
fc->dev = &pdev->dev;
|
||||
fc->owner = THIS_MODULE;
|
||||
|
||||
/* bus specific part */
|
||||
fc_pci->pdev = pdev;
|
||||
if ((ret = flexcop_pci_init(fc_pci)) != 0)
|
||||
goto err_kfree;
|
||||
|
||||
/* init flexcop */
|
||||
if ((ret = flexcop_device_initialize(fc)) != 0)
|
||||
goto err_pci_exit;
|
||||
|
||||
/* init dma */
|
||||
if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
|
||||
goto err_fc_exit;
|
||||
|
||||
INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
|
||||
|
||||
return ret;
|
||||
|
||||
err_fc_exit:
|
||||
flexcop_device_exit(fc);
|
||||
err_pci_exit:
|
||||
flexcop_pci_exit(fc_pci);
|
||||
err_kfree:
|
||||
flexcop_device_kfree(fc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* in theory every _exit function should be called exactly two times,
|
||||
* here and in the bail-out-part of the _init-function
|
||||
*/
|
||||
static void flexcop_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
|
||||
|
||||
flexcop_pci_dma_exit(fc_pci);
|
||||
flexcop_device_exit(fc_pci->fc_dev);
|
||||
flexcop_pci_exit(fc_pci);
|
||||
flexcop_device_kfree(fc_pci->fc_dev);
|
||||
}
|
||||
|
||||
static struct pci_device_id flexcop_pci_tbl[] = {
|
||||
{ PCI_DEVICE(0x13d0, 0x2103) },
|
||||
/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
|
||||
|
||||
static struct pci_driver flexcop_pci_driver = {
|
||||
.name = "b2c2_flexcop_pci",
|
||||
.id_table = flexcop_pci_tbl,
|
||||
.probe = flexcop_pci_probe,
|
||||
.remove = flexcop_pci_remove,
|
||||
};
|
||||
|
||||
static int __init flexcop_pci_module_init(void)
|
||||
{
|
||||
return pci_register_driver(&flexcop_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit flexcop_pci_module_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&flexcop_pci_driver);
|
||||
}
|
||||
|
||||
module_init(flexcop_pci_module_init);
|
||||
module_exit(flexcop_pci_module_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_NAME);
|
||||
MODULE_LICENSE("GPL");
|
||||
167
drivers/media/dvb/b2c2/flexcop-reg.h
Normal file
167
drivers/media/dvb/b2c2/flexcop-reg.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#ifndef __FLEXCOP_REG_H__
|
||||
#define __FLEXCOP_REG_H__
|
||||
|
||||
|
||||
typedef enum {
|
||||
FLEXCOP_UNK = 0,
|
||||
FLEXCOP_II,
|
||||
FLEXCOP_IIB,
|
||||
FLEXCOP_III,
|
||||
} flexcop_revision_t;
|
||||
|
||||
typedef enum {
|
||||
FC_UNK = 0,
|
||||
FC_AIR_DVB,
|
||||
FC_AIR_ATSC1,
|
||||
FC_AIR_ATSC2,
|
||||
FC_SKY,
|
||||
FC_SKY_OLD,
|
||||
FC_CABLE,
|
||||
FC_AIR_ATSC3,
|
||||
} flexcop_device_type_t;
|
||||
|
||||
typedef enum {
|
||||
FC_USB = 0,
|
||||
FC_PCI,
|
||||
} flexcop_bus_t;
|
||||
|
||||
/* FlexCop IBI Registers */
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
#include "flexcop_ibi_value_le.h"
|
||||
#else
|
||||
#if defined(__BIG_ENDIAN)
|
||||
#include "flexcop_ibi_value_be.h"
|
||||
#else
|
||||
#error no endian defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define fc_data_Tag_ID_DVB 0x3e
|
||||
#define fc_data_Tag_ID_ATSC 0x3f
|
||||
#define fc_data_Tag_ID_IDSB 0x8b
|
||||
|
||||
#define fc_key_code_default 0x1
|
||||
#define fc_key_code_even 0x2
|
||||
#define fc_key_code_odd 0x3
|
||||
|
||||
extern flexcop_ibi_value ibi_zero;
|
||||
|
||||
typedef enum {
|
||||
FC_I2C_PORT_DEMOD = 1,
|
||||
FC_I2C_PORT_EEPROM = 2,
|
||||
FC_I2C_PORT_TUNER = 3,
|
||||
} flexcop_i2c_port_t;
|
||||
|
||||
typedef enum {
|
||||
FC_WRITE = 0,
|
||||
FC_READ = 1,
|
||||
} flexcop_access_op_t;
|
||||
|
||||
typedef enum {
|
||||
FC_SRAM_DEST_NET = 1,
|
||||
FC_SRAM_DEST_CAI = 2,
|
||||
FC_SRAM_DEST_CAO = 4,
|
||||
FC_SRAM_DEST_MEDIA = 8
|
||||
} flexcop_sram_dest_t;
|
||||
|
||||
typedef enum {
|
||||
FC_SRAM_DEST_TARGET_WAN_USB = 0,
|
||||
FC_SRAM_DEST_TARGET_DMA1 = 1,
|
||||
FC_SRAM_DEST_TARGET_DMA2 = 2,
|
||||
FC_SRAM_DEST_TARGET_FC3_CA = 3
|
||||
} flexcop_sram_dest_target_t;
|
||||
|
||||
typedef enum {
|
||||
FC_SRAM_2_32KB = 0, /* 64KB */
|
||||
FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */
|
||||
FC_SRAM_1_128KB = 2, /* 128KB */
|
||||
FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */
|
||||
} flexcop_sram_type_t;
|
||||
|
||||
typedef enum {
|
||||
FC_WAN_SPEED_4MBITS = 0,
|
||||
FC_WAN_SPEED_8MBITS = 1,
|
||||
FC_WAN_SPEED_12MBITS = 2,
|
||||
FC_WAN_SPEED_16MBITS = 3,
|
||||
} flexcop_wan_speed_t;
|
||||
|
||||
typedef enum {
|
||||
FC_DMA_1 = 1,
|
||||
FC_DMA_2 = 2,
|
||||
} flexcop_dma_index_t;
|
||||
|
||||
typedef enum {
|
||||
FC_DMA_SUBADDR_0 = 1,
|
||||
FC_DMA_SUBADDR_1 = 2,
|
||||
} flexcop_dma_addr_index_t;
|
||||
|
||||
/* names of the particular registers */
|
||||
typedef enum {
|
||||
dma1_000 = 0x000,
|
||||
dma1_004 = 0x004,
|
||||
dma1_008 = 0x008,
|
||||
dma1_00c = 0x00c,
|
||||
dma2_010 = 0x010,
|
||||
dma2_014 = 0x014,
|
||||
dma2_018 = 0x018,
|
||||
dma2_01c = 0x01c,
|
||||
|
||||
tw_sm_c_100 = 0x100,
|
||||
tw_sm_c_104 = 0x104,
|
||||
tw_sm_c_108 = 0x108,
|
||||
tw_sm_c_10c = 0x10c,
|
||||
tw_sm_c_110 = 0x110,
|
||||
|
||||
lnb_switch_freq_200 = 0x200,
|
||||
misc_204 = 0x204,
|
||||
ctrl_208 = 0x208,
|
||||
irq_20c = 0x20c,
|
||||
sw_reset_210 = 0x210,
|
||||
misc_214 = 0x214,
|
||||
mbox_v8_to_host_218 = 0x218,
|
||||
mbox_host_to_v8_21c = 0x21c,
|
||||
|
||||
pid_filter_300 = 0x300,
|
||||
pid_filter_304 = 0x304,
|
||||
pid_filter_308 = 0x308,
|
||||
pid_filter_30c = 0x30c,
|
||||
index_reg_310 = 0x310,
|
||||
pid_n_reg_314 = 0x314,
|
||||
mac_low_reg_318 = 0x318,
|
||||
mac_high_reg_31c = 0x31c,
|
||||
|
||||
data_tag_400 = 0x400,
|
||||
card_id_408 = 0x408,
|
||||
card_id_40c = 0x40c,
|
||||
mac_address_418 = 0x418,
|
||||
mac_address_41c = 0x41c,
|
||||
|
||||
ci_600 = 0x600,
|
||||
pi_604 = 0x604,
|
||||
pi_608 = 0x608,
|
||||
dvb_reg_60c = 0x60c,
|
||||
|
||||
sram_ctrl_reg_700 = 0x700,
|
||||
net_buf_reg_704 = 0x704,
|
||||
cai_buf_reg_708 = 0x708,
|
||||
cao_buf_reg_70c = 0x70c,
|
||||
media_buf_reg_710 = 0x710,
|
||||
sram_dest_reg_714 = 0x714,
|
||||
net_buf_reg_718 = 0x718,
|
||||
wan_ctrl_reg_71c = 0x71c,
|
||||
} flexcop_ibi_register;
|
||||
|
||||
#define flexcop_set_ibi_value(reg,attr,val) { \
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
|
||||
v.reg.attr = val; \
|
||||
fc->write_ibi_reg(fc,reg,v); \
|
||||
}
|
||||
|
||||
#endif
|
||||
403
drivers/media/dvb/b2c2/flexcop-sram.c
Normal file
403
drivers/media/dvb/b2c2/flexcop-sram.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-sram.c - functions for controlling the SRAM.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type)
|
||||
{
|
||||
flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type);
|
||||
}
|
||||
|
||||
int flexcop_sram_init(struct flexcop_device *fc)
|
||||
{
|
||||
switch (fc->rev) {
|
||||
case FLEXCOP_II:
|
||||
case FLEXCOP_IIB:
|
||||
flexcop_sram_set_chip(fc,FC_SRAM_1_32KB);
|
||||
break;
|
||||
case FLEXCOP_III:
|
||||
flexcop_sram_set_chip(fc,FC_SRAM_1_48KB);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target)
|
||||
{
|
||||
flexcop_ibi_value v;
|
||||
|
||||
v = fc->read_ibi_reg(fc,sram_dest_reg_714);
|
||||
|
||||
if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
|
||||
err("SRAM destination target to available on FlexCopII(b)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
deb_sram("sram dest: %x target: %x\n",dest, target);
|
||||
|
||||
if (dest & FC_SRAM_DEST_NET)
|
||||
v.sram_dest_reg_714.NET_Dest = target;
|
||||
if (dest & FC_SRAM_DEST_CAI)
|
||||
v.sram_dest_reg_714.CAI_Dest = target;
|
||||
if (dest & FC_SRAM_DEST_CAO)
|
||||
v.sram_dest_reg_714.CAO_Dest = target;
|
||||
if (dest & FC_SRAM_DEST_MEDIA)
|
||||
v.sram_dest_reg_714.MEDIA_Dest = target;
|
||||
|
||||
fc->write_ibi_reg(fc,sram_dest_reg_714,v);
|
||||
udelay(1000); /* TODO delay really necessary */
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_sram_set_dest);
|
||||
|
||||
void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
|
||||
{
|
||||
flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_wan_set_speed);
|
||||
|
||||
void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
|
||||
v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
|
||||
v.sram_dest_reg_714.ctrl_sramdma = sramdma;
|
||||
v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
|
||||
fc->write_ibi_reg(fc,sram_dest_reg_714,v);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_sram_ctrl);
|
||||
|
||||
#if 0
|
||||
static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
int i, retries;
|
||||
u32 command;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
command = bank | addr | 0x04000000 | (*buf << 0x10);
|
||||
|
||||
retries = 2;
|
||||
|
||||
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
|
||||
mdelay(1);
|
||||
retries--;
|
||||
};
|
||||
|
||||
if (retries == 0)
|
||||
printk("%s: SRAM timeout\n", __FUNCTION__);
|
||||
|
||||
write_reg_dw(adapter, 0x700, command);
|
||||
|
||||
buf++;
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
int i, retries;
|
||||
u32 command, value;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
command = bank | addr | 0x04008000;
|
||||
|
||||
retries = 10000;
|
||||
|
||||
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
|
||||
mdelay(1);
|
||||
retries--;
|
||||
};
|
||||
|
||||
if (retries == 0)
|
||||
printk("%s: SRAM timeout\n", __FUNCTION__);
|
||||
|
||||
write_reg_dw(adapter, 0x700, command);
|
||||
|
||||
retries = 10000;
|
||||
|
||||
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
|
||||
mdelay(1);
|
||||
retries--;
|
||||
};
|
||||
|
||||
if (retries == 0)
|
||||
printk("%s: SRAM timeout\n", __FUNCTION__);
|
||||
|
||||
value = read_reg_dw(adapter, 0x700) >> 0x10;
|
||||
|
||||
*buf = (value & 0xff);
|
||||
|
||||
addr++;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
|
||||
{
|
||||
u32 bank;
|
||||
|
||||
bank = 0;
|
||||
|
||||
if (adapter->dw_sram_type == 0x20000) {
|
||||
bank = (addr & 0x18000) << 0x0d;
|
||||
}
|
||||
|
||||
if (adapter->dw_sram_type == 0x00000) {
|
||||
if ((addr >> 0x0f) == 0)
|
||||
bank = 0x20000000;
|
||||
else
|
||||
bank = 0x10000000;
|
||||
}
|
||||
|
||||
flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
|
||||
}
|
||||
|
||||
static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
|
||||
{
|
||||
u32 bank;
|
||||
|
||||
bank = 0;
|
||||
|
||||
if (adapter->dw_sram_type == 0x20000) {
|
||||
bank = (addr & 0x18000) << 0x0d;
|
||||
}
|
||||
|
||||
if (adapter->dw_sram_type == 0x00000) {
|
||||
if ((addr >> 0x0f) == 0)
|
||||
bank = 0x20000000;
|
||||
else
|
||||
bank = 0x10000000;
|
||||
}
|
||||
|
||||
flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
|
||||
}
|
||||
|
||||
static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 length;
|
||||
|
||||
while (len != 0) {
|
||||
length = len;
|
||||
|
||||
// check if the address range belongs to the same
|
||||
// 32K memory chip. If not, the data is read from
|
||||
// one chip at a time.
|
||||
if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
|
||||
length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
|
||||
}
|
||||
|
||||
sram_read_chunk(adapter, addr, buf, length);
|
||||
|
||||
addr = addr + length;
|
||||
buf = buf + length;
|
||||
len = len - length;
|
||||
}
|
||||
}
|
||||
|
||||
static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 length;
|
||||
|
||||
while (len != 0) {
|
||||
length = len;
|
||||
|
||||
// check if the address range belongs to the same
|
||||
// 32K memory chip. If not, the data is written to
|
||||
// one chip at a time.
|
||||
if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
|
||||
length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
|
||||
}
|
||||
|
||||
sram_write_chunk(adapter, addr, buf, length);
|
||||
|
||||
addr = addr + length;
|
||||
buf = buf + length;
|
||||
len = len - length;
|
||||
}
|
||||
}
|
||||
|
||||
static void sram_set_size(struct adapter *adapter, u32 mask)
|
||||
{
|
||||
write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
|
||||
}
|
||||
|
||||
static void sram_init(struct adapter *adapter)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = read_reg_dw(adapter, 0x71c);
|
||||
|
||||
write_reg_dw(adapter, 0x71c, 1);
|
||||
|
||||
if (read_reg_dw(adapter, 0x71c) != 0) {
|
||||
write_reg_dw(adapter, 0x71c, tmp);
|
||||
|
||||
adapter->dw_sram_type = tmp & 0x30000;
|
||||
|
||||
ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
|
||||
|
||||
} else {
|
||||
|
||||
adapter->dw_sram_type = 0x10000;
|
||||
|
||||
ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
|
||||
}
|
||||
|
||||
/* return value is never used? */
|
||||
/* return adapter->dw_sram_type; */
|
||||
}
|
||||
|
||||
static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
|
||||
{
|
||||
u8 tmp1, tmp2;
|
||||
|
||||
dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
|
||||
|
||||
sram_set_size(adapter, mask);
|
||||
sram_init(adapter);
|
||||
|
||||
tmp2 = 0xa5;
|
||||
tmp1 = 0x4f;
|
||||
|
||||
sram_write(adapter, addr, &tmp2, 1);
|
||||
sram_write(adapter, addr + 4, &tmp1, 1);
|
||||
|
||||
tmp2 = 0;
|
||||
|
||||
mdelay(20);
|
||||
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
|
||||
dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
|
||||
|
||||
if (tmp2 != 0xa5)
|
||||
return 0;
|
||||
|
||||
tmp2 = 0x5a;
|
||||
tmp1 = 0xf4;
|
||||
|
||||
sram_write(adapter, addr, &tmp2, 1);
|
||||
sram_write(adapter, addr + 4, &tmp1, 1);
|
||||
|
||||
tmp2 = 0;
|
||||
|
||||
mdelay(20);
|
||||
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
|
||||
dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
|
||||
|
||||
if (tmp2 != 0x5a)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32 sram_length(struct adapter *adapter)
|
||||
{
|
||||
if (adapter->dw_sram_type == 0x10000)
|
||||
return 32768; // 32K
|
||||
if (adapter->dw_sram_type == 0x00000)
|
||||
return 65536; // 64K
|
||||
if (adapter->dw_sram_type == 0x20000)
|
||||
return 131072; // 128K
|
||||
|
||||
return 32768; // 32K
|
||||
}
|
||||
|
||||
/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
|
||||
- for 128K there are 4x32K chips at bank 0,1,2,3.
|
||||
- for 64K there are 2x32K chips at bank 1,2.
|
||||
- for 32K there is one 32K chip at bank 0.
|
||||
|
||||
FlexCop works only with one bank at a time. The bank is selected
|
||||
by bits 28-29 of the 0x700 register.
|
||||
|
||||
bank 0 covers addresses 0x00000-0x07fff
|
||||
bank 1 covers addresses 0x08000-0x0ffff
|
||||
bank 2 covers addresses 0x10000-0x17fff
|
||||
bank 3 covers addresses 0x18000-0x1ffff
|
||||
*/
|
||||
|
||||
static int flexcop_sram_detect(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_ibi_value r208,r71c_0,vr71c_1;
|
||||
|
||||
r208 = fc->read_ibi_reg(fc, ctrl_208);
|
||||
fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
|
||||
|
||||
r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
|
||||
|
||||
write_reg_dw(adapter, 0x71c, 1);
|
||||
|
||||
tmp3 = read_reg_dw(adapter, 0x71c);
|
||||
|
||||
dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
|
||||
|
||||
write_reg_dw(adapter, 0x71c, tmp2);
|
||||
|
||||
// check for internal SRAM ???
|
||||
tmp3--;
|
||||
if (tmp3 != 0) {
|
||||
sram_set_size(adapter, 0x10000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 32K\n", __FUNCTION__);
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
|
||||
sram_set_size(adapter, 0x20000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 128K\n", __FUNCTION__);
|
||||
|
||||
return 128;
|
||||
}
|
||||
|
||||
if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
|
||||
sram_set_size(adapter, 0x00000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 64K\n", __FUNCTION__);
|
||||
|
||||
return 64;
|
||||
}
|
||||
|
||||
if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
|
||||
sram_set_size(adapter, 0x10000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 32K\n", __FUNCTION__);
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
sram_set_size(adapter, 0x10000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sll_detect_sram_size(struct adapter *adapter)
|
||||
{
|
||||
sram_detect_for_flex2(adapter);
|
||||
}
|
||||
|
||||
#endif
|
||||
575
drivers/media/dvb/b2c2/flexcop-usb.c
Normal file
575
drivers/media/dvb/b2c2/flexcop-usb.c
Normal file
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-usb.c - covers the USB part.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
|
||||
#define FC_LOG_PREFIX "flexcop_usb"
|
||||
#include "flexcop-usb.h"
|
||||
#include "flexcop-common.h"
|
||||
|
||||
/* Version information */
|
||||
#define DRIVER_VERSION "0.1"
|
||||
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
|
||||
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
|
||||
|
||||
/* debug */
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define dprintk(level,args...) \
|
||||
do { if ((debug & level)) { printk(args); } } while (0)
|
||||
#define debug_dump(b,l,method) {\
|
||||
int i; \
|
||||
for (i = 0; i < l; i++) method("%02x ", b[i]); \
|
||||
method("\n");\
|
||||
}
|
||||
|
||||
#define DEBSTATUS ""
|
||||
#else
|
||||
#define dprintk(level,args...)
|
||||
#define debug_dump(b,l,method)
|
||||
#define DEBSTATUS " (debugging is not enabled)"
|
||||
#endif
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
|
||||
#undef DEBSTATUS
|
||||
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_ts(args...) dprintk(0x02,args)
|
||||
#define deb_ctrl(args...) dprintk(0x04,args)
|
||||
#define deb_i2c(args...) dprintk(0x08,args)
|
||||
#define deb_v8(args...) dprintk(0x10,args)
|
||||
|
||||
/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
|
||||
* in the IBI address, to make the V8 code simpler.
|
||||
* PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
|
||||
* in general: 0000 0HHH 000L LL00
|
||||
* IBI ADDRESS FORMAT: RHHH BLLL
|
||||
*
|
||||
* where R is the read(1)/write(0) bit, B is the busy bit
|
||||
* and HHH and LLL are the two sets of three bits from the PCI address.
|
||||
*/
|
||||
#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
|
||||
#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
|
||||
|
||||
/*
|
||||
* DKT 020228
|
||||
* - forget about this VENDOR_BUFFER_SIZE, read and write register
|
||||
* deal with DWORD or 4 bytes, that should be should from now on
|
||||
* - from now on, we don't support anything older than firm 1.00
|
||||
* I eliminated the write register as a 2 trip of writing hi word and lo word
|
||||
* and force this to write only 4 bytes at a time.
|
||||
* NOTE: this should work with all the firmware from 1.00 and newer
|
||||
*/
|
||||
static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
|
||||
{
|
||||
struct flexcop_usb *fc_usb = fc->bus_specific;
|
||||
u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
|
||||
u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
|
||||
u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0);
|
||||
|
||||
int len = usb_control_msg(fc_usb->udev,
|
||||
read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
|
||||
request,
|
||||
request_type, /* 0xc0 read or 0x40 write*/
|
||||
wAddress,
|
||||
0,
|
||||
val,
|
||||
sizeof(u32),
|
||||
B2C2_WAIT_FOR_OPERATION_RDW * HZ);
|
||||
|
||||
if (len != sizeof(u32)) {
|
||||
err("error while %s dword from %d (%d).",read ? "reading" : "writing",
|
||||
wAddress,wRegOffsPCI);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DKT 010817 - add support for V8 memory read/write and flash update
|
||||
*/
|
||||
static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
|
||||
flexcop_usb_request_t req, u8 page, u16 wAddress,
|
||||
u8 *pbBuffer,u32 buflen)
|
||||
{
|
||||
// u8 dwRequestType;
|
||||
u8 request_type = USB_TYPE_VENDOR;
|
||||
u16 wIndex;
|
||||
int nWaitTime,pipe,len;
|
||||
|
||||
wIndex = page << 8;
|
||||
|
||||
switch (req) {
|
||||
case B2C2_USB_READ_V8_MEM:
|
||||
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
|
||||
request_type |= USB_DIR_IN;
|
||||
// dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
|
||||
pipe = B2C2_USB_CTRL_PIPE_IN;
|
||||
break;
|
||||
case B2C2_USB_WRITE_V8_MEM:
|
||||
wIndex |= pbBuffer[0];
|
||||
request_type |= USB_DIR_OUT;
|
||||
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
|
||||
// dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
|
||||
pipe = B2C2_USB_CTRL_PIPE_OUT;
|
||||
break;
|
||||
case B2C2_USB_FLASH_BLOCK:
|
||||
request_type |= USB_DIR_OUT;
|
||||
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
|
||||
// dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
|
||||
pipe = B2C2_USB_CTRL_PIPE_OUT;
|
||||
break;
|
||||
default:
|
||||
deb_info("unsupported request for v8_mem_req %x.\n",req);
|
||||
return -EINVAL;
|
||||
}
|
||||
deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req,
|
||||
wAddress,wIndex,buflen);
|
||||
|
||||
len = usb_control_msg(fc_usb->udev,pipe,
|
||||
req,
|
||||
request_type,
|
||||
wAddress,
|
||||
wIndex,
|
||||
pbBuffer,
|
||||
buflen,
|
||||
nWaitTime * HZ);
|
||||
|
||||
debug_dump(pbBuffer,len,deb_v8);
|
||||
|
||||
return len == buflen ? 0 : -EIO;
|
||||
}
|
||||
|
||||
#define bytes_left_to_read_on_page(paddr,buflen) \
|
||||
((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
|
||||
? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
|
||||
|
||||
static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req,
|
||||
flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len)
|
||||
{
|
||||
int i,ret = 0;
|
||||
u16 wMax;
|
||||
u32 pagechunk = 0;
|
||||
|
||||
switch(req) {
|
||||
case B2C2_USB_READ_V8_MEM: wMax = USB_MEM_READ_MAX; break;
|
||||
case B2C2_USB_WRITE_V8_MEM: wMax = USB_MEM_WRITE_MAX; break;
|
||||
case B2C2_USB_FLASH_BLOCK: wMax = USB_FLASH_MAX; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < len;) {
|
||||
pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len);
|
||||
deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended));
|
||||
if ((ret = flexcop_usb_v8_memory_req(fc_usb,req,
|
||||
page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */
|
||||
(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended),
|
||||
&buf[i],pagechunk)) < 0)
|
||||
return ret;
|
||||
|
||||
addr += pagechunk;
|
||||
len -= pagechunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
|
||||
{
|
||||
return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,
|
||||
V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->dvb_adapter.proposed_mac,6);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
|
||||
flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
|
||||
u16 buflen, u8 *pvBuffer)
|
||||
{
|
||||
u16 wValue;
|
||||
u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
|
||||
// u8 dwRequestType = (u8) RTYPE_GENERIC,
|
||||
int nWaitTime = 2,
|
||||
pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
|
||||
len;
|
||||
|
||||
wValue = (func << 8) | extra;
|
||||
|
||||
len = usb_control_msg(fc_usb->udev,pipe,
|
||||
B2C2_USB_UTILITY,
|
||||
request_type,
|
||||
wValue,
|
||||
wIndex,
|
||||
pvBuffer,
|
||||
buflen,
|
||||
nWaitTime * HZ);
|
||||
return len == buflen ? 0 : -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* usb i2c stuff */
|
||||
static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb,
|
||||
flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
|
||||
flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
|
||||
{
|
||||
u16 wValue, wIndex;
|
||||
int nWaitTime,pipe,len;
|
||||
// u8 dwRequestType;
|
||||
u8 request_type = USB_TYPE_VENDOR;
|
||||
|
||||
switch (func) {
|
||||
case USB_FUNC_I2C_WRITE:
|
||||
case USB_FUNC_I2C_MULTIWRITE:
|
||||
case USB_FUNC_I2C_REPEATWRITE:
|
||||
/* DKT 020208 - add this to support special case of DiSEqC */
|
||||
case USB_FUNC_I2C_CHECKWRITE:
|
||||
pipe = B2C2_USB_CTRL_PIPE_OUT;
|
||||
nWaitTime = 2;
|
||||
// dwRequestType = (u8) RTYPE_GENERIC;
|
||||
request_type |= USB_DIR_OUT;
|
||||
break;
|
||||
case USB_FUNC_I2C_READ:
|
||||
case USB_FUNC_I2C_REPEATREAD:
|
||||
pipe = B2C2_USB_CTRL_PIPE_IN;
|
||||
nWaitTime = 2;
|
||||
// dwRequestType = (u8) RTYPE_GENERIC;
|
||||
request_type |= USB_DIR_IN;
|
||||
break;
|
||||
default:
|
||||
deb_info("unsupported function for i2c_req %x\n",func);
|
||||
return -EINVAL;
|
||||
}
|
||||
wValue = (func << 8 ) | (port << 4);
|
||||
wIndex = (chipaddr << 8 ) | addr;
|
||||
|
||||
deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
|
||||
wValue & 0xff, wValue >> 8, wIndex & 0xff, wIndex >> 8);
|
||||
|
||||
len = usb_control_msg(fc_usb->udev,pipe,
|
||||
req,
|
||||
request_type,
|
||||
wValue,
|
||||
wIndex,
|
||||
buf,
|
||||
buflen,
|
||||
nWaitTime * HZ);
|
||||
|
||||
return len == buflen ? 0 : -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* actual bus specific access functions, make sure prototype are/will be equal to pci */
|
||||
static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg)
|
||||
{
|
||||
flexcop_ibi_value val;
|
||||
val.raw = 0;
|
||||
flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val)
|
||||
{
|
||||
return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
|
||||
}
|
||||
|
||||
static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
|
||||
flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
if (op == FC_READ)
|
||||
return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len);
|
||||
else
|
||||
return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len);
|
||||
}
|
||||
|
||||
static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length)
|
||||
{
|
||||
u8 *b;
|
||||
int l;
|
||||
|
||||
deb_ts("tmp_buffer_length=%d, buffer_length=%d\n", fc_usb->tmp_buffer_length, buffer_length);
|
||||
|
||||
if (fc_usb->tmp_buffer_length > 0) {
|
||||
memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer, buffer_length);
|
||||
fc_usb->tmp_buffer_length += buffer_length;
|
||||
b = fc_usb->tmp_buffer;
|
||||
l = fc_usb->tmp_buffer_length;
|
||||
} else {
|
||||
b=buffer;
|
||||
l=buffer_length;
|
||||
}
|
||||
|
||||
while (l >= 190) {
|
||||
if (*b == 0xff)
|
||||
switch (*(b+1) & 0x03) {
|
||||
case 0x01: /* media packet */
|
||||
if ( *(b+2) == 0x47 )
|
||||
flexcop_pass_dmx_packets(fc_usb->fc_dev, b+2, 1);
|
||||
else
|
||||
deb_ts("not ts packet %02x %02x %02x %02x \n", *(b+2), *(b+3), *(b+4), *(b+5) );
|
||||
|
||||
b += 190;
|
||||
l -= 190;
|
||||
break;
|
||||
default:
|
||||
deb_ts("wrong packet type\n");
|
||||
l = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
deb_ts("wrong header\n");
|
||||
l = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (l>0)
|
||||
memcpy(fc_usb->tmp_buffer, b, l);
|
||||
fc_usb->tmp_buffer_length = l;
|
||||
}
|
||||
|
||||
static void flexcop_usb_urb_complete(struct urb *urb)
|
||||
{
|
||||
struct flexcop_usb *fc_usb = urb->context;
|
||||
int i;
|
||||
|
||||
if (urb->actual_length > 0)
|
||||
deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length);
|
||||
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
if (urb->iso_frame_desc[i].status < 0) {
|
||||
err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status);
|
||||
} else
|
||||
if (urb->iso_frame_desc[i].actual_length > 0) {
|
||||
deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length);
|
||||
|
||||
flexcop_usb_process_frame(fc_usb,
|
||||
urb->transfer_buffer + urb->iso_frame_desc[i].offset,
|
||||
urb->iso_frame_desc[i].actual_length);
|
||||
}
|
||||
urb->iso_frame_desc[i].status = 0;
|
||||
urb->iso_frame_desc[i].actual_length = 0;
|
||||
}
|
||||
|
||||
usb_submit_urb(urb,GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
/* submit/kill iso packets */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
|
||||
if (fc_usb->iso_urb[i] != NULL) {
|
||||
deb_ts("unlinking/killing urb no. %d\n",i);
|
||||
usb_kill_urb(fc_usb->iso_urb[i]);
|
||||
usb_free_urb(fc_usb->iso_urb[i]);
|
||||
}
|
||||
|
||||
if (fc_usb->iso_buffer != NULL)
|
||||
pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr);
|
||||
}
|
||||
|
||||
static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
u16 frame_size = fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize;
|
||||
int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
|
||||
int buffer_offset = 0;
|
||||
|
||||
deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
|
||||
B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
|
||||
|
||||
fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr);
|
||||
if (fc_usb->iso_buffer == NULL)
|
||||
return -ENOMEM;
|
||||
memset(fc_usb->iso_buffer, 0, bufsize);
|
||||
fc_usb->buffer_size = bufsize;
|
||||
|
||||
/* creating iso urbs */
|
||||
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
|
||||
if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
|
||||
ret = -ENOMEM;
|
||||
goto urb_error;
|
||||
}
|
||||
/* initialising and submitting iso urbs */
|
||||
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
|
||||
int frame_offset = 0;
|
||||
struct urb *urb = fc_usb->iso_urb[i];
|
||||
deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
|
||||
|
||||
urb->dev = fc_usb->udev;
|
||||
urb->context = fc_usb;
|
||||
urb->complete = flexcop_usb_urb_complete;
|
||||
urb->pipe = B2C2_USB_DATA_PIPE;
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
urb->interval = 1;
|
||||
urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
|
||||
urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
|
||||
urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
|
||||
|
||||
buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
|
||||
for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
|
||||
deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
|
||||
urb->iso_frame_desc[j].offset = frame_offset;
|
||||
urb->iso_frame_desc[j].length = frame_size;
|
||||
frame_offset += frame_size;
|
||||
}
|
||||
|
||||
if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
|
||||
err("submitting urb %d failed with %d.",i,ret);
|
||||
goto urb_error;
|
||||
}
|
||||
deb_ts("submitted urb no. %d.\n",i);
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
|
||||
flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET |
|
||||
FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB);
|
||||
flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
|
||||
flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
|
||||
|
||||
return 0;
|
||||
|
||||
urb_error:
|
||||
flexcop_usb_transfer_exit(fc_usb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flexcop_usb_init(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
/* use the alternate setting with the larges buffer */
|
||||
usb_set_interface(fc_usb->udev,0,1);
|
||||
switch (fc_usb->udev->speed) {
|
||||
case USB_SPEED_LOW:
|
||||
err("cannot handle USB speed because it is to sLOW.");
|
||||
return -ENODEV;
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
info("running at FULL speed.");
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
info("running at HIGH speed.");
|
||||
break;
|
||||
case USB_SPEED_UNKNOWN: /* fall through */
|
||||
default:
|
||||
err("cannot handle USB speed because it is unkown.");
|
||||
return -ENODEV;
|
||||
}
|
||||
usb_set_intfdata(fc_usb->uintf, fc_usb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
usb_set_intfdata(fc_usb->uintf, NULL);
|
||||
}
|
||||
|
||||
static int flexcop_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct flexcop_usb *fc_usb = NULL;
|
||||
struct flexcop_device *fc = NULL;
|
||||
int ret;
|
||||
|
||||
if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
|
||||
err("out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* general flexcop init */
|
||||
fc_usb = fc->bus_specific;
|
||||
fc_usb->fc_dev = fc;
|
||||
|
||||
fc->read_ibi_reg = flexcop_usb_read_ibi_reg;
|
||||
fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
|
||||
fc->i2c_request = flexcop_usb_i2c_request;
|
||||
fc->get_mac_addr = flexcop_usb_get_mac_addr;
|
||||
|
||||
fc->stream_control = flexcop_usb_stream_control;
|
||||
|
||||
fc->pid_filtering = 1;
|
||||
fc->bus_type = FC_USB;
|
||||
|
||||
fc->dev = &udev->dev;
|
||||
fc->owner = THIS_MODULE;
|
||||
|
||||
/* bus specific part */
|
||||
fc_usb->udev = udev;
|
||||
fc_usb->uintf = intf;
|
||||
if ((ret = flexcop_usb_init(fc_usb)) != 0)
|
||||
goto err_kfree;
|
||||
|
||||
/* init flexcop */
|
||||
if ((ret = flexcop_device_initialize(fc)) != 0)
|
||||
goto err_usb_exit;
|
||||
|
||||
/* xfer init */
|
||||
if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
|
||||
goto err_fc_exit;
|
||||
|
||||
info("%s successfully initialized and connected.",DRIVER_NAME);
|
||||
return 0;
|
||||
|
||||
err_fc_exit:
|
||||
flexcop_device_exit(fc);
|
||||
err_usb_exit:
|
||||
flexcop_usb_exit(fc_usb);
|
||||
err_kfree:
|
||||
flexcop_device_kfree(fc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
|
||||
flexcop_usb_transfer_exit(fc_usb);
|
||||
flexcop_device_exit(fc_usb->fc_dev);
|
||||
flexcop_usb_exit(fc_usb);
|
||||
flexcop_device_kfree(fc_usb->fc_dev);
|
||||
info("%s successfully deinitialized and disconnected.",DRIVER_NAME);
|
||||
}
|
||||
|
||||
static struct usb_device_id flexcop_usb_table [] = {
|
||||
{ USB_DEVICE(0x0af7, 0x0101) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver flexcop_usb_driver = {
|
||||
.name = "b2c2_flexcop_usb",
|
||||
.probe = flexcop_usb_probe,
|
||||
.disconnect = flexcop_usb_disconnect,
|
||||
.id_table = flexcop_usb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init flexcop_usb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&flexcop_usb_driver))) {
|
||||
err("usb_register failed. (%d)",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit flexcop_usb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&flexcop_usb_driver);
|
||||
}
|
||||
|
||||
module_init(flexcop_usb_module_init);
|
||||
module_exit(flexcop_usb_module_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_NAME);
|
||||
MODULE_LICENSE("GPL");
|
||||
119
drivers/media/dvb/b2c2/flexcop-usb.h
Normal file
119
drivers/media/dvb/b2c2/flexcop-usb.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#ifndef __FLEXCOP_USB_H_INCLUDED__
|
||||
#define __FLEXCOP_USB_H_INCLUDED__
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
/* transfer parameters */
|
||||
#define B2C2_USB_FRAMES_PER_ISO 4
|
||||
#define B2C2_USB_NUM_ISO_URB 4
|
||||
|
||||
#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0)
|
||||
#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0)
|
||||
#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81)
|
||||
|
||||
struct flexcop_usb {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *uintf;
|
||||
|
||||
u8 *iso_buffer;
|
||||
int buffer_size;
|
||||
dma_addr_t dma_addr;
|
||||
struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
|
||||
|
||||
struct flexcop_device *fc_dev;
|
||||
|
||||
u8 tmp_buffer[1023+190];
|
||||
int tmp_buffer_length;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* request types TODO What is its use?*/
|
||||
typedef enum {
|
||||
|
||||
/* something is wrong with this part
|
||||
RTYPE_READ_DW = (1 << 6),
|
||||
RTYPE_WRITE_DW_1 = (3 << 6),
|
||||
RTYPE_READ_V8_MEMORY = (6 << 6),
|
||||
RTYPE_WRITE_V8_MEMORY = (7 << 6),
|
||||
RTYPE_WRITE_V8_FLASH = (8 << 6),
|
||||
RTYPE_GENERIC = (9 << 6),
|
||||
*/
|
||||
} flexcop_usb_request_type_t;
|
||||
#endif
|
||||
|
||||
/* request */
|
||||
typedef enum {
|
||||
B2C2_USB_WRITE_V8_MEM = 0x04,
|
||||
B2C2_USB_READ_V8_MEM = 0x05,
|
||||
B2C2_USB_READ_REG = 0x08,
|
||||
B2C2_USB_WRITE_REG = 0x0A,
|
||||
/* B2C2_USB_WRITEREGLO = 0x0A, */
|
||||
B2C2_USB_WRITEREGHI = 0x0B,
|
||||
B2C2_USB_FLASH_BLOCK = 0x10,
|
||||
B2C2_USB_I2C_REQUEST = 0x11,
|
||||
B2C2_USB_UTILITY = 0x12,
|
||||
} flexcop_usb_request_t;
|
||||
|
||||
/* function definition for I2C_REQUEST */
|
||||
typedef enum {
|
||||
USB_FUNC_I2C_WRITE = 0x01,
|
||||
USB_FUNC_I2C_MULTIWRITE = 0x02,
|
||||
USB_FUNC_I2C_READ = 0x03,
|
||||
USB_FUNC_I2C_REPEATWRITE = 0x04,
|
||||
USB_FUNC_GET_DESCRIPTOR = 0x05,
|
||||
USB_FUNC_I2C_REPEATREAD = 0x06,
|
||||
/* DKT 020208 - add this to support special case of DiSEqC */
|
||||
USB_FUNC_I2C_CHECKWRITE = 0x07,
|
||||
USB_FUNC_I2C_CHECKRESULT = 0x08,
|
||||
} flexcop_usb_i2c_function_t;
|
||||
|
||||
/*
|
||||
* function definition for UTILITY request 0x12
|
||||
* DKT 020304 - new utility function
|
||||
*/
|
||||
typedef enum {
|
||||
UTILITY_SET_FILTER = 0x01,
|
||||
UTILITY_DATA_ENABLE = 0x02,
|
||||
UTILITY_FLEX_MULTIWRITE = 0x03,
|
||||
UTILITY_SET_BUFFER_SIZE = 0x04,
|
||||
UTILITY_FLEX_OPERATOR = 0x05,
|
||||
UTILITY_FLEX_RESET300_START = 0x06,
|
||||
UTILITY_FLEX_RESET300_STOP = 0x07,
|
||||
UTILITY_FLEX_RESET300 = 0x08,
|
||||
UTILITY_SET_ISO_SIZE = 0x09,
|
||||
UTILITY_DATA_RESET = 0x0A,
|
||||
UTILITY_GET_DATA_STATUS = 0x10,
|
||||
UTILITY_GET_V8_REG = 0x11,
|
||||
/* DKT 020326 - add function for v1.14 */
|
||||
UTILITY_SRAM_WRITE = 0x12,
|
||||
UTILITY_SRAM_READ = 0x13,
|
||||
UTILITY_SRAM_TESTFILL = 0x14,
|
||||
UTILITY_SRAM_TESTSET = 0x15,
|
||||
UTILITY_SRAM_TESTVERIFY = 0x16,
|
||||
} flexcop_usb_utility_function_t;
|
||||
|
||||
#define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */
|
||||
|
||||
#define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */
|
||||
|
||||
typedef enum {
|
||||
V8_MEMORY_PAGE_DVB_CI = 0x20,
|
||||
V8_MEMORY_PAGE_DVB_DS = 0x40,
|
||||
V8_MEMORY_PAGE_MULTI2 = 0x60,
|
||||
V8_MEMORY_PAGE_FLASH = 0x80
|
||||
} flexcop_usb_mem_page_t;
|
||||
|
||||
#define V8_MEMORY_EXTENDED (1 << 15)
|
||||
|
||||
#define USB_MEM_READ_MAX 32
|
||||
#define USB_MEM_WRITE_MAX 1
|
||||
#define USB_FLASH_MAX 8
|
||||
|
||||
#define V8_MEMORY_PAGE_SIZE 0x8000 // 32K
|
||||
#define V8_MEMORY_PAGE_MASK 0x7FFF
|
||||
|
||||
#endif
|
||||
311
drivers/media/dvb/b2c2/flexcop.c
Normal file
311
drivers/media/dvb/b2c2/flexcop.c
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* based on the skystar2-driver
|
||||
* Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
|
||||
*
|
||||
* Acknowledgements:
|
||||
* John Jurrius from BBTI, Inc. for extensive support with
|
||||
* code examples and data books
|
||||
*
|
||||
* Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
|
||||
*
|
||||
* Contributions to the skystar2-driver have been done by
|
||||
* Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
|
||||
* Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
|
||||
* Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "flexcop.h"
|
||||
|
||||
#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
|
||||
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
|
||||
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define DEBSTATUS ""
|
||||
#else
|
||||
#define DEBSTATUS " (debugging is not enabled)"
|
||||
#endif
|
||||
|
||||
int b2c2_flexcop_debug;
|
||||
module_param_named(debug, b2c2_flexcop_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
|
||||
#undef DEBSTATUS
|
||||
|
||||
/* global zero for ibi values */
|
||||
flexcop_ibi_value ibi_zero;
|
||||
|
||||
static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct flexcop_device *fc = dvbdmxfeed->demux->priv;
|
||||
return flexcop_pid_feed_control(fc,dvbdmxfeed,1);
|
||||
}
|
||||
|
||||
static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct flexcop_device *fc = dvbdmxfeed->demux->priv;
|
||||
return flexcop_pid_feed_control(fc,dvbdmxfeed,0);
|
||||
}
|
||||
|
||||
static int flexcop_dvb_init(struct flexcop_device *fc)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
|
||||
err("error registering DVB adapter");
|
||||
return ret;
|
||||
}
|
||||
fc->dvb_adapter.priv = fc;
|
||||
|
||||
fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
|
||||
fc->demux.priv = fc;
|
||||
|
||||
fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
|
||||
|
||||
fc->demux.start_feed = flexcop_dvb_start_feed;
|
||||
fc->demux.stop_feed = flexcop_dvb_stop_feed;
|
||||
fc->demux.write_to_decoder = NULL;
|
||||
|
||||
if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
|
||||
err("dvb_dmx failed: error %d",ret);
|
||||
goto err_dmx;
|
||||
}
|
||||
|
||||
fc->hw_frontend.source = DMX_FRONTEND_0;
|
||||
|
||||
fc->dmxdev.filternum = fc->demux.feednum;
|
||||
fc->dmxdev.demux = &fc->demux.dmx;
|
||||
fc->dmxdev.capabilities = 0;
|
||||
if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
|
||||
err("dvb_dmxdev_init failed: error %d",ret);
|
||||
goto err_dmx_dev;
|
||||
}
|
||||
|
||||
if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
|
||||
err("adding hw_frontend to dmx failed: error %d",ret);
|
||||
goto err_dmx_add_hw_frontend;
|
||||
}
|
||||
|
||||
fc->mem_frontend.source = DMX_MEMORY_FE;
|
||||
if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
|
||||
err("adding mem_frontend to dmx failed: error %d",ret);
|
||||
goto err_dmx_add_mem_frontend;
|
||||
}
|
||||
|
||||
if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
|
||||
err("connect frontend failed: error %d",ret);
|
||||
goto err_connect_frontend;
|
||||
}
|
||||
|
||||
dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
|
||||
|
||||
fc->init_state |= FC_STATE_DVB_INIT;
|
||||
return 0;
|
||||
|
||||
err_connect_frontend:
|
||||
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
|
||||
err_dmx_add_mem_frontend:
|
||||
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
|
||||
err_dmx_add_hw_frontend:
|
||||
dvb_dmxdev_release(&fc->dmxdev);
|
||||
err_dmx_dev:
|
||||
dvb_dmx_release(&fc->demux);
|
||||
err_dmx:
|
||||
dvb_unregister_adapter(&fc->dvb_adapter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_dvb_exit(struct flexcop_device *fc)
|
||||
{
|
||||
if (fc->init_state & FC_STATE_DVB_INIT) {
|
||||
dvb_net_release(&fc->dvbnet);
|
||||
|
||||
fc->demux.dmx.close(&fc->demux.dmx);
|
||||
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
|
||||
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend);
|
||||
dvb_dmxdev_release(&fc->dmxdev);
|
||||
dvb_dmx_release(&fc->demux);
|
||||
dvb_unregister_adapter(&fc->dvb_adapter);
|
||||
|
||||
deb_info("deinitialized dvb stuff\n");
|
||||
}
|
||||
fc->init_state &= ~FC_STATE_DVB_INIT;
|
||||
}
|
||||
|
||||
/* these methods are necessary to achieve the long-term-goal of hiding the
|
||||
* struct flexcop_device from the bus-parts */
|
||||
void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
|
||||
{
|
||||
dvb_dmx_swfilter(&fc->demux, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_pass_dmx_data);
|
||||
|
||||
void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
|
||||
{
|
||||
dvb_dmx_swfilter_packets(&fc->demux, buf, no);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_pass_dmx_packets);
|
||||
|
||||
static void flexcop_reset(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_ibi_value v210,v204;
|
||||
|
||||
/* reset the flexcop itself */
|
||||
fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
|
||||
|
||||
v210.raw = 0;
|
||||
v210.sw_reset_210.reset_block_000 = 1;
|
||||
v210.sw_reset_210.reset_block_100 = 1;
|
||||
v210.sw_reset_210.reset_block_200 = 1;
|
||||
v210.sw_reset_210.reset_block_300 = 1;
|
||||
v210.sw_reset_210.reset_block_400 = 1;
|
||||
v210.sw_reset_210.reset_block_500 = 1;
|
||||
v210.sw_reset_210.reset_block_600 = 1;
|
||||
v210.sw_reset_210.reset_block_700 = 1;
|
||||
v210.sw_reset_210.Block_reset_enable = 0xb2;
|
||||
|
||||
v210.sw_reset_210.Special_controls = 0xc259;
|
||||
|
||||
fc->write_ibi_reg(fc,sw_reset_210,v210);
|
||||
msleep(1);
|
||||
|
||||
/* reset the periphical devices */
|
||||
|
||||
v204 = fc->read_ibi_reg(fc,misc_204);
|
||||
v204.misc_204.Per_reset_sig = 0;
|
||||
fc->write_ibi_reg(fc,misc_204,v204);
|
||||
msleep(1);
|
||||
v204.misc_204.Per_reset_sig = 1;
|
||||
fc->write_ibi_reg(fc,misc_204,v204);
|
||||
}
|
||||
|
||||
void flexcop_reset_block_300(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208),
|
||||
v210 = fc->read_ibi_reg(fc,sw_reset_210);
|
||||
|
||||
deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw);
|
||||
|
||||
fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
|
||||
|
||||
v210.sw_reset_210.reset_block_300 = 1;
|
||||
v210.sw_reset_210.Block_reset_enable = 0xb2;
|
||||
|
||||
fc->write_ibi_reg(fc,sw_reset_210,v210);
|
||||
msleep(1);
|
||||
|
||||
fc->write_ibi_reg(fc,ctrl_208,v208_save);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_reset_block_300);
|
||||
|
||||
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
|
||||
{
|
||||
void *bus;
|
||||
struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), GFP_KERNEL);
|
||||
if (!fc) {
|
||||
err("no memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bus = kzalloc(bus_specific_len, GFP_KERNEL);
|
||||
if (!bus) {
|
||||
err("no memory");
|
||||
kfree(fc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fc->bus_specific = bus;
|
||||
|
||||
return fc;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_device_kmalloc);
|
||||
|
||||
void flexcop_device_kfree(struct flexcop_device *fc)
|
||||
{
|
||||
kfree(fc->bus_specific);
|
||||
kfree(fc);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_device_kfree);
|
||||
|
||||
int flexcop_device_initialize(struct flexcop_device *fc)
|
||||
{
|
||||
int ret;
|
||||
ibi_zero.raw = 0;
|
||||
|
||||
flexcop_reset(fc);
|
||||
flexcop_determine_revision(fc);
|
||||
flexcop_sram_init(fc);
|
||||
flexcop_hw_filter_init(fc);
|
||||
|
||||
flexcop_smc_ctrl(fc, 0);
|
||||
|
||||
if ((ret = flexcop_dvb_init(fc)))
|
||||
goto error;
|
||||
|
||||
/* do the MAC address reading after initializing the dvb_adapter */
|
||||
if (fc->get_mac_addr(fc, 0) == 0) {
|
||||
u8 *b = fc->dvb_adapter.proposed_mac;
|
||||
info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]);
|
||||
flexcop_set_mac_filter(fc,b);
|
||||
flexcop_mac_filter_ctrl(fc,1);
|
||||
} else
|
||||
warn("reading of MAC address failed.\n");
|
||||
|
||||
|
||||
if ((ret = flexcop_i2c_init(fc)))
|
||||
goto error;
|
||||
|
||||
if ((ret = flexcop_frontend_init(fc)))
|
||||
goto error;
|
||||
|
||||
flexcop_device_name(fc,"initialization of","complete");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
flexcop_device_exit(fc);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_device_initialize);
|
||||
|
||||
void flexcop_device_exit(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_frontend_exit(fc);
|
||||
flexcop_i2c_exit(fc);
|
||||
flexcop_dvb_exit(fc);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_device_exit);
|
||||
|
||||
static int flexcop_module_init(void)
|
||||
{
|
||||
info(DRIVER_NAME " loaded successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flexcop_module_cleanup(void)
|
||||
{
|
||||
info(DRIVER_NAME " unloaded successfully");
|
||||
}
|
||||
|
||||
module_init(flexcop_module_init);
|
||||
module_exit(flexcop_module_cleanup);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_NAME);
|
||||
MODULE_LICENSE("GPL");
|
||||
31
drivers/media/dvb/b2c2/flexcop.h
Normal file
31
drivers/media/dvb/b2c2/flexcop.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop.h - private header file for all flexcop-chip-source files.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#ifndef __FLEXCOP_H__
|
||||
#define __FLEXCOP_H___
|
||||
|
||||
#define FC_LOG_PREFIX "b2c2-flexcop"
|
||||
#include "flexcop-common.h"
|
||||
|
||||
extern int b2c2_flexcop_debug;
|
||||
|
||||
/* debug */
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define dprintk(level,args...) \
|
||||
do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
|
||||
#else
|
||||
#define dprintk(level,args...)
|
||||
#endif
|
||||
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_tuner(args...) dprintk(0x02,args)
|
||||
#define deb_i2c(args...) dprintk(0x04,args)
|
||||
#define deb_ts(args...) dprintk(0x08,args)
|
||||
#define deb_sram(args...) dprintk(0x10,args)
|
||||
#define deb_rdump(args...) dprintk(0x20,args)
|
||||
|
||||
#endif
|
||||
458
drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
Normal file
458
drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
Normal file
@@ -0,0 +1,458 @@
|
||||
/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* register descriptions
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
|
||||
/* This file is automatically generated, do not edit things here. */
|
||||
#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
|
||||
#define __FLEXCOP_IBI_VALUE_INCLUDED__
|
||||
|
||||
typedef union {
|
||||
u32 raw;
|
||||
|
||||
struct {
|
||||
u32 dma_address0 :30;
|
||||
u32 dma_0No_update : 1;
|
||||
u32 dma_0start : 1;
|
||||
} dma_0x0;
|
||||
|
||||
struct {
|
||||
u32 dma_addr_size :24;
|
||||
u32 DMA_maxpackets : 8;
|
||||
} dma_0x4_remap;
|
||||
|
||||
struct {
|
||||
u32 dma_addr_size :24;
|
||||
u32 unused : 1;
|
||||
u32 dma1timer : 7;
|
||||
} dma_0x4_read;
|
||||
|
||||
struct {
|
||||
u32 dma_addr_size :24;
|
||||
u32 dmatimer : 7;
|
||||
u32 unused : 1;
|
||||
} dma_0x4_write;
|
||||
|
||||
struct {
|
||||
u32 dma_cur_addr :30;
|
||||
u32 unused : 2;
|
||||
} dma_0x8;
|
||||
|
||||
struct {
|
||||
u32 dma_address1 :30;
|
||||
u32 remap_enable : 1;
|
||||
u32 dma_1start : 1;
|
||||
} dma_0xc;
|
||||
|
||||
struct {
|
||||
u32 st_done : 1;
|
||||
u32 no_base_addr_ack_error : 1;
|
||||
u32 twoWS_port_reg : 2;
|
||||
u32 total_bytes : 2;
|
||||
u32 twoWS_rw : 1;
|
||||
u32 working_start : 1;
|
||||
u32 data1_reg : 8;
|
||||
u32 baseaddr : 8;
|
||||
u32 reserved1 : 1;
|
||||
u32 chipaddr : 7;
|
||||
} tw_sm_c_100;
|
||||
|
||||
struct {
|
||||
u32 unused : 6;
|
||||
u32 force_stop : 1;
|
||||
u32 exlicit_stops : 1;
|
||||
u32 data4_reg : 8;
|
||||
u32 data3_reg : 8;
|
||||
u32 data2_reg : 8;
|
||||
} tw_sm_c_104;
|
||||
|
||||
struct {
|
||||
u32 reserved2 :19;
|
||||
u32 tlo1 : 5;
|
||||
u32 reserved1 : 2;
|
||||
u32 thi1 : 6;
|
||||
} tw_sm_c_108;
|
||||
|
||||
struct {
|
||||
u32 reserved2 :19;
|
||||
u32 tlo1 : 5;
|
||||
u32 reserved1 : 2;
|
||||
u32 thi1 : 6;
|
||||
} tw_sm_c_10c;
|
||||
|
||||
struct {
|
||||
u32 reserved2 :19;
|
||||
u32 tlo1 : 5;
|
||||
u32 reserved1 : 2;
|
||||
u32 thi1 : 6;
|
||||
} tw_sm_c_110;
|
||||
|
||||
struct {
|
||||
u32 LNB_CTLPrescaler_sig : 2;
|
||||
u32 LNB_CTLLowCount_sig :15;
|
||||
u32 LNB_CTLHighCount_sig :15;
|
||||
} lnb_switch_freq_200;
|
||||
|
||||
struct {
|
||||
u32 Rev_N_sig_reserved2 : 1;
|
||||
u32 Rev_N_sig_caps : 1;
|
||||
u32 Rev_N_sig_reserved1 : 2;
|
||||
u32 Rev_N_sig_revision_hi : 4;
|
||||
u32 reserved :20;
|
||||
u32 Per_reset_sig : 1;
|
||||
u32 LNB_L_H_sig : 1;
|
||||
u32 ACPI3_sig : 1;
|
||||
u32 ACPI1_sig : 1;
|
||||
} misc_204;
|
||||
|
||||
struct {
|
||||
u32 unused : 9;
|
||||
u32 Mailbox_from_V8_Enable_sig : 1;
|
||||
u32 DMA2_Size_IRQ_Enable_sig : 1;
|
||||
u32 DMA1_Size_IRQ_Enable_sig : 1;
|
||||
u32 DMA2_Timer_Enable_sig : 1;
|
||||
u32 DMA2_IRQ_Enable_sig : 1;
|
||||
u32 DMA1_Timer_Enable_sig : 1;
|
||||
u32 DMA1_IRQ_Enable_sig : 1;
|
||||
u32 Rcv_Data_sig : 1;
|
||||
u32 MAC_filter_Mode_sig : 1;
|
||||
u32 Multi2_Enable_sig : 1;
|
||||
u32 Per_CA_Enable_sig : 1;
|
||||
u32 SMC_Enable_sig : 1;
|
||||
u32 CA_Enable_sig : 1;
|
||||
u32 WAN_CA_Enable_sig : 1;
|
||||
u32 WAN_Enable_sig : 1;
|
||||
u32 Mask_filter_sig : 1;
|
||||
u32 Null_filter_sig : 1;
|
||||
u32 ECM_filter_sig : 1;
|
||||
u32 EMM_filter_sig : 1;
|
||||
u32 PMT_filter_sig : 1;
|
||||
u32 PCR_filter_sig : 1;
|
||||
u32 Stream2_filter_sig : 1;
|
||||
u32 Stream1_filter_sig : 1;
|
||||
} ctrl_208;
|
||||
|
||||
struct {
|
||||
u32 reserved :21;
|
||||
u32 Transport_Error : 1;
|
||||
u32 LLC_SNAP_FLAG_set : 1;
|
||||
u32 Continuity_error_flag : 1;
|
||||
u32 Data_receiver_error : 1;
|
||||
u32 Mailbox_from_V8_Status_sig : 1;
|
||||
u32 DMA2_Size_IRQ_Status : 1;
|
||||
u32 DMA1_Size_IRQ_Status : 1;
|
||||
u32 DMA2_Timer_Status : 1;
|
||||
u32 DMA2_IRQ_Status : 1;
|
||||
u32 DMA1_Timer_Status : 1;
|
||||
u32 DMA1_IRQ_Status : 1;
|
||||
} irq_20c;
|
||||
|
||||
struct {
|
||||
u32 Special_controls :16;
|
||||
u32 Block_reset_enable : 8;
|
||||
u32 reset_block_700 : 1;
|
||||
u32 reset_block_600 : 1;
|
||||
u32 reset_block_500 : 1;
|
||||
u32 reset_block_400 : 1;
|
||||
u32 reset_block_300 : 1;
|
||||
u32 reset_block_200 : 1;
|
||||
u32 reset_block_100 : 1;
|
||||
u32 reset_block_000 : 1;
|
||||
} sw_reset_210;
|
||||
|
||||
struct {
|
||||
u32 unused2 :20;
|
||||
u32 polarity_PS_ERR_sig : 1;
|
||||
u32 polarity_PS_SYNC_sig : 1;
|
||||
u32 polarity_PS_VALID_sig : 1;
|
||||
u32 polarity_PS_CLK_sig : 1;
|
||||
u32 unused1 : 3;
|
||||
u32 s2p_sel_sig : 1;
|
||||
u32 section_pkg_enable_sig : 1;
|
||||
u32 halt_V8_sig : 1;
|
||||
u32 v2WS_oe_sig : 1;
|
||||
u32 vuart_oe_sig : 1;
|
||||
} misc_214;
|
||||
|
||||
struct {
|
||||
u32 Mailbox_from_V8 :32;
|
||||
} mbox_v8_to_host_218;
|
||||
|
||||
struct {
|
||||
u32 sysramaccess_busmuster : 1;
|
||||
u32 sysramaccess_write : 1;
|
||||
u32 unused : 7;
|
||||
u32 sysramaccess_addr :15;
|
||||
u32 sysramaccess_data : 8;
|
||||
} mbox_host_to_v8_21c;
|
||||
|
||||
struct {
|
||||
u32 debug_fifo_problem : 1;
|
||||
u32 debug_flag_write_status00 : 1;
|
||||
u32 Stream2_trans : 1;
|
||||
u32 Stream2_PID :13;
|
||||
u32 debug_flag_pid_saved : 1;
|
||||
u32 MAC_Multicast_filter : 1;
|
||||
u32 Stream1_trans : 1;
|
||||
u32 Stream1_PID :13;
|
||||
} pid_filter_300;
|
||||
|
||||
struct {
|
||||
u32 reserved : 2;
|
||||
u32 PMT_trans : 1;
|
||||
u32 PMT_PID :13;
|
||||
u32 debug_overrun2 : 1;
|
||||
u32 debug_overrun3 : 1;
|
||||
u32 PCR_trans : 1;
|
||||
u32 PCR_PID :13;
|
||||
} pid_filter_304;
|
||||
|
||||
struct {
|
||||
u32 reserved : 2;
|
||||
u32 ECM_trans : 1;
|
||||
u32 ECM_PID :13;
|
||||
u32 EMM_filter_6 : 1;
|
||||
u32 EMM_filter_4 : 1;
|
||||
u32 EMM_trans : 1;
|
||||
u32 EMM_PID :13;
|
||||
} pid_filter_308;
|
||||
|
||||
struct {
|
||||
u32 unused2 : 3;
|
||||
u32 Group_mask :13;
|
||||
u32 unused1 : 2;
|
||||
u32 Group_trans : 1;
|
||||
u32 Group_PID :13;
|
||||
} pid_filter_30c_ext_ind_0_7;
|
||||
|
||||
struct {
|
||||
u32 unused :15;
|
||||
u32 net_master_read :17;
|
||||
} pid_filter_30c_ext_ind_1;
|
||||
|
||||
struct {
|
||||
u32 unused :15;
|
||||
u32 net_master_write :17;
|
||||
} pid_filter_30c_ext_ind_2;
|
||||
|
||||
struct {
|
||||
u32 unused :15;
|
||||
u32 next_net_master_write :17;
|
||||
} pid_filter_30c_ext_ind_3;
|
||||
|
||||
struct {
|
||||
u32 reserved2 : 5;
|
||||
u32 stack_read :10;
|
||||
u32 reserved1 : 6;
|
||||
u32 state_write :10;
|
||||
u32 unused1 : 1;
|
||||
} pid_filter_30c_ext_ind_4;
|
||||
|
||||
struct {
|
||||
u32 unused :22;
|
||||
u32 stack_cnt :10;
|
||||
} pid_filter_30c_ext_ind_5;
|
||||
|
||||
struct {
|
||||
u32 unused : 4;
|
||||
u32 data_size_reg :12;
|
||||
u32 write_status4 : 2;
|
||||
u32 write_status1 : 2;
|
||||
u32 pid_fsm_save_reg300 : 2;
|
||||
u32 pid_fsm_save_reg4 : 2;
|
||||
u32 pid_fsm_save_reg3 : 2;
|
||||
u32 pid_fsm_save_reg2 : 2;
|
||||
u32 pid_fsm_save_reg1 : 2;
|
||||
u32 pid_fsm_save_reg0 : 2;
|
||||
} pid_filter_30c_ext_ind_6;
|
||||
|
||||
struct {
|
||||
u32 unused :22;
|
||||
u32 pass_alltables : 1;
|
||||
u32 AB_select : 1;
|
||||
u32 extra_index_reg : 3;
|
||||
u32 index_reg : 5;
|
||||
} index_reg_310;
|
||||
|
||||
struct {
|
||||
u32 reserved :17;
|
||||
u32 PID_enable_bit : 1;
|
||||
u32 PID_trans : 1;
|
||||
u32 PID :13;
|
||||
} pid_n_reg_314;
|
||||
|
||||
struct {
|
||||
u32 reserved : 6;
|
||||
u32 HighAB_bit : 1;
|
||||
u32 Enable_bit : 1;
|
||||
u32 A6_byte : 8;
|
||||
u32 A5_byte : 8;
|
||||
u32 A4_byte : 8;
|
||||
} mac_low_reg_318;
|
||||
|
||||
struct {
|
||||
u32 reserved : 8;
|
||||
u32 A3_byte : 8;
|
||||
u32 A2_byte : 8;
|
||||
u32 A1_byte : 8;
|
||||
} mac_high_reg_31c;
|
||||
|
||||
struct {
|
||||
u32 data_Tag_ID :16;
|
||||
u32 reserved :16;
|
||||
} data_tag_400;
|
||||
|
||||
struct {
|
||||
u32 Card_IDbyte3 : 8;
|
||||
u32 Card_IDbyte4 : 8;
|
||||
u32 Card_IDbyte5 : 8;
|
||||
u32 Card_IDbyte6 : 8;
|
||||
} card_id_408;
|
||||
|
||||
struct {
|
||||
u32 Card_IDbyte1 : 8;
|
||||
u32 Card_IDbyte2 : 8;
|
||||
} card_id_40c;
|
||||
|
||||
struct {
|
||||
u32 MAC6 : 8;
|
||||
u32 MAC3 : 8;
|
||||
u32 MAC2 : 8;
|
||||
u32 MAC1 : 8;
|
||||
} mac_address_418;
|
||||
|
||||
struct {
|
||||
u32 reserved :16;
|
||||
u32 MAC8 : 8;
|
||||
u32 MAC7 : 8;
|
||||
} mac_address_41c;
|
||||
|
||||
struct {
|
||||
u32 reserved :21;
|
||||
u32 txbuffempty : 1;
|
||||
u32 ReceiveByteFrameError : 1;
|
||||
u32 ReceiveDataReady : 1;
|
||||
u32 transmitter_data_byte : 8;
|
||||
} ci_600;
|
||||
|
||||
struct {
|
||||
u32 pi_component_reg : 3;
|
||||
u32 pi_rw : 1;
|
||||
u32 pi_ha :20;
|
||||
u32 pi_d : 8;
|
||||
} pi_604;
|
||||
|
||||
struct {
|
||||
u32 pi_busy_n : 1;
|
||||
u32 pi_wait_n : 1;
|
||||
u32 pi_timeout_status : 1;
|
||||
u32 pi_CiMax_IRQ_n : 1;
|
||||
u32 config_cclk : 1;
|
||||
u32 config_cs_n : 1;
|
||||
u32 config_wr_n : 1;
|
||||
u32 config_Prog_n : 1;
|
||||
u32 config_Init_stat : 1;
|
||||
u32 config_Done_stat : 1;
|
||||
u32 pcmcia_b_mod_pwr_n : 1;
|
||||
u32 pcmcia_a_mod_pwr_n : 1;
|
||||
u32 reserved : 3;
|
||||
u32 Timer_addr : 5;
|
||||
u32 unused : 1;
|
||||
u32 timer_data : 7;
|
||||
u32 Timer_Load_req : 1;
|
||||
u32 Timer_Read_req : 1;
|
||||
u32 oncecycle_read : 1;
|
||||
u32 serialReset : 1;
|
||||
} pi_608;
|
||||
|
||||
struct {
|
||||
u32 reserved : 6;
|
||||
u32 rw_flag : 1;
|
||||
u32 dvb_en : 1;
|
||||
u32 key_array_row : 5;
|
||||
u32 key_array_col : 3;
|
||||
u32 key_code : 2;
|
||||
u32 key_enable : 1;
|
||||
u32 PID :13;
|
||||
} dvb_reg_60c;
|
||||
|
||||
struct {
|
||||
u32 start_sram_ibi : 1;
|
||||
u32 reserved2 : 1;
|
||||
u32 ce_pin_reg : 1;
|
||||
u32 oe_pin_reg : 1;
|
||||
u32 reserved1 : 3;
|
||||
u32 sc_xfer_bit : 1;
|
||||
u32 sram_data : 8;
|
||||
u32 sram_rw : 1;
|
||||
u32 sram_addr :15;
|
||||
} sram_ctrl_reg_700;
|
||||
|
||||
struct {
|
||||
u32 net_addr_write :16;
|
||||
u32 net_addr_read :16;
|
||||
} net_buf_reg_704;
|
||||
|
||||
struct {
|
||||
u32 cai_cnt : 4;
|
||||
u32 reserved2 : 6;
|
||||
u32 cai_write :11;
|
||||
u32 reserved1 : 5;
|
||||
u32 cai_read :11;
|
||||
} cai_buf_reg_708;
|
||||
|
||||
struct {
|
||||
u32 cao_cnt : 4;
|
||||
u32 reserved2 : 6;
|
||||
u32 cap_write :11;
|
||||
u32 reserved1 : 5;
|
||||
u32 cao_read :11;
|
||||
} cao_buf_reg_70c;
|
||||
|
||||
struct {
|
||||
u32 media_cnt : 4;
|
||||
u32 reserved2 : 6;
|
||||
u32 media_write :11;
|
||||
u32 reserved1 : 5;
|
||||
u32 media_read :11;
|
||||
} media_buf_reg_710;
|
||||
|
||||
struct {
|
||||
u32 reserved :17;
|
||||
u32 ctrl_maximumfill : 1;
|
||||
u32 ctrl_sramdma : 1;
|
||||
u32 ctrl_usb_wan : 1;
|
||||
u32 cao_ovflow_error : 1;
|
||||
u32 cai_ovflow_error : 1;
|
||||
u32 media_ovflow_error : 1;
|
||||
u32 net_ovflow_error : 1;
|
||||
u32 MEDIA_Dest : 2;
|
||||
u32 CAO_Dest : 2;
|
||||
u32 CAI_Dest : 2;
|
||||
u32 NET_Dest : 2;
|
||||
} sram_dest_reg_714;
|
||||
|
||||
struct {
|
||||
u32 reserved3 :11;
|
||||
u32 net_addr_write : 1;
|
||||
u32 reserved2 : 3;
|
||||
u32 net_addr_read : 1;
|
||||
u32 reserved1 : 4;
|
||||
u32 net_cnt :12;
|
||||
} net_buf_reg_718;
|
||||
|
||||
struct {
|
||||
u32 reserved3 : 4;
|
||||
u32 wan_pkt_frame : 4;
|
||||
u32 reserved2 : 4;
|
||||
u32 sram_memmap : 2;
|
||||
u32 sram_chip : 2;
|
||||
u32 wan_wait_state : 8;
|
||||
u32 reserved1 : 6;
|
||||
u32 wan_speed_sig : 2;
|
||||
} wan_ctrl_reg_71c;
|
||||
} flexcop_ibi_value;
|
||||
|
||||
#endif
|
||||
458
drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
Normal file
458
drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
Normal file
@@ -0,0 +1,458 @@
|
||||
/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* register descriptions
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
|
||||
/* This file is automatically generated, do not edit things here. */
|
||||
#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
|
||||
#define __FLEXCOP_IBI_VALUE_INCLUDED__
|
||||
|
||||
typedef union {
|
||||
u32 raw;
|
||||
|
||||
struct {
|
||||
u32 dma_0start : 1;
|
||||
u32 dma_0No_update : 1;
|
||||
u32 dma_address0 :30;
|
||||
} dma_0x0;
|
||||
|
||||
struct {
|
||||
u32 DMA_maxpackets : 8;
|
||||
u32 dma_addr_size :24;
|
||||
} dma_0x4_remap;
|
||||
|
||||
struct {
|
||||
u32 dma1timer : 7;
|
||||
u32 unused : 1;
|
||||
u32 dma_addr_size :24;
|
||||
} dma_0x4_read;
|
||||
|
||||
struct {
|
||||
u32 unused : 1;
|
||||
u32 dmatimer : 7;
|
||||
u32 dma_addr_size :24;
|
||||
} dma_0x4_write;
|
||||
|
||||
struct {
|
||||
u32 unused : 2;
|
||||
u32 dma_cur_addr :30;
|
||||
} dma_0x8;
|
||||
|
||||
struct {
|
||||
u32 dma_1start : 1;
|
||||
u32 remap_enable : 1;
|
||||
u32 dma_address1 :30;
|
||||
} dma_0xc;
|
||||
|
||||
struct {
|
||||
u32 chipaddr : 7;
|
||||
u32 reserved1 : 1;
|
||||
u32 baseaddr : 8;
|
||||
u32 data1_reg : 8;
|
||||
u32 working_start : 1;
|
||||
u32 twoWS_rw : 1;
|
||||
u32 total_bytes : 2;
|
||||
u32 twoWS_port_reg : 2;
|
||||
u32 no_base_addr_ack_error : 1;
|
||||
u32 st_done : 1;
|
||||
} tw_sm_c_100;
|
||||
|
||||
struct {
|
||||
u32 data2_reg : 8;
|
||||
u32 data3_reg : 8;
|
||||
u32 data4_reg : 8;
|
||||
u32 exlicit_stops : 1;
|
||||
u32 force_stop : 1;
|
||||
u32 unused : 6;
|
||||
} tw_sm_c_104;
|
||||
|
||||
struct {
|
||||
u32 thi1 : 6;
|
||||
u32 reserved1 : 2;
|
||||
u32 tlo1 : 5;
|
||||
u32 reserved2 :19;
|
||||
} tw_sm_c_108;
|
||||
|
||||
struct {
|
||||
u32 thi1 : 6;
|
||||
u32 reserved1 : 2;
|
||||
u32 tlo1 : 5;
|
||||
u32 reserved2 :19;
|
||||
} tw_sm_c_10c;
|
||||
|
||||
struct {
|
||||
u32 thi1 : 6;
|
||||
u32 reserved1 : 2;
|
||||
u32 tlo1 : 5;
|
||||
u32 reserved2 :19;
|
||||
} tw_sm_c_110;
|
||||
|
||||
struct {
|
||||
u32 LNB_CTLHighCount_sig :15;
|
||||
u32 LNB_CTLLowCount_sig :15;
|
||||
u32 LNB_CTLPrescaler_sig : 2;
|
||||
} lnb_switch_freq_200;
|
||||
|
||||
struct {
|
||||
u32 ACPI1_sig : 1;
|
||||
u32 ACPI3_sig : 1;
|
||||
u32 LNB_L_H_sig : 1;
|
||||
u32 Per_reset_sig : 1;
|
||||
u32 reserved :20;
|
||||
u32 Rev_N_sig_revision_hi : 4;
|
||||
u32 Rev_N_sig_reserved1 : 2;
|
||||
u32 Rev_N_sig_caps : 1;
|
||||
u32 Rev_N_sig_reserved2 : 1;
|
||||
} misc_204;
|
||||
|
||||
struct {
|
||||
u32 Stream1_filter_sig : 1;
|
||||
u32 Stream2_filter_sig : 1;
|
||||
u32 PCR_filter_sig : 1;
|
||||
u32 PMT_filter_sig : 1;
|
||||
u32 EMM_filter_sig : 1;
|
||||
u32 ECM_filter_sig : 1;
|
||||
u32 Null_filter_sig : 1;
|
||||
u32 Mask_filter_sig : 1;
|
||||
u32 WAN_Enable_sig : 1;
|
||||
u32 WAN_CA_Enable_sig : 1;
|
||||
u32 CA_Enable_sig : 1;
|
||||
u32 SMC_Enable_sig : 1;
|
||||
u32 Per_CA_Enable_sig : 1;
|
||||
u32 Multi2_Enable_sig : 1;
|
||||
u32 MAC_filter_Mode_sig : 1;
|
||||
u32 Rcv_Data_sig : 1;
|
||||
u32 DMA1_IRQ_Enable_sig : 1;
|
||||
u32 DMA1_Timer_Enable_sig : 1;
|
||||
u32 DMA2_IRQ_Enable_sig : 1;
|
||||
u32 DMA2_Timer_Enable_sig : 1;
|
||||
u32 DMA1_Size_IRQ_Enable_sig : 1;
|
||||
u32 DMA2_Size_IRQ_Enable_sig : 1;
|
||||
u32 Mailbox_from_V8_Enable_sig : 1;
|
||||
u32 unused : 9;
|
||||
} ctrl_208;
|
||||
|
||||
struct {
|
||||
u32 DMA1_IRQ_Status : 1;
|
||||
u32 DMA1_Timer_Status : 1;
|
||||
u32 DMA2_IRQ_Status : 1;
|
||||
u32 DMA2_Timer_Status : 1;
|
||||
u32 DMA1_Size_IRQ_Status : 1;
|
||||
u32 DMA2_Size_IRQ_Status : 1;
|
||||
u32 Mailbox_from_V8_Status_sig : 1;
|
||||
u32 Data_receiver_error : 1;
|
||||
u32 Continuity_error_flag : 1;
|
||||
u32 LLC_SNAP_FLAG_set : 1;
|
||||
u32 Transport_Error : 1;
|
||||
u32 reserved :21;
|
||||
} irq_20c;
|
||||
|
||||
struct {
|
||||
u32 reset_block_000 : 1;
|
||||
u32 reset_block_100 : 1;
|
||||
u32 reset_block_200 : 1;
|
||||
u32 reset_block_300 : 1;
|
||||
u32 reset_block_400 : 1;
|
||||
u32 reset_block_500 : 1;
|
||||
u32 reset_block_600 : 1;
|
||||
u32 reset_block_700 : 1;
|
||||
u32 Block_reset_enable : 8;
|
||||
u32 Special_controls :16;
|
||||
} sw_reset_210;
|
||||
|
||||
struct {
|
||||
u32 vuart_oe_sig : 1;
|
||||
u32 v2WS_oe_sig : 1;
|
||||
u32 halt_V8_sig : 1;
|
||||
u32 section_pkg_enable_sig : 1;
|
||||
u32 s2p_sel_sig : 1;
|
||||
u32 unused1 : 3;
|
||||
u32 polarity_PS_CLK_sig : 1;
|
||||
u32 polarity_PS_VALID_sig : 1;
|
||||
u32 polarity_PS_SYNC_sig : 1;
|
||||
u32 polarity_PS_ERR_sig : 1;
|
||||
u32 unused2 :20;
|
||||
} misc_214;
|
||||
|
||||
struct {
|
||||
u32 Mailbox_from_V8 :32;
|
||||
} mbox_v8_to_host_218;
|
||||
|
||||
struct {
|
||||
u32 sysramaccess_data : 8;
|
||||
u32 sysramaccess_addr :15;
|
||||
u32 unused : 7;
|
||||
u32 sysramaccess_write : 1;
|
||||
u32 sysramaccess_busmuster : 1;
|
||||
} mbox_host_to_v8_21c;
|
||||
|
||||
struct {
|
||||
u32 Stream1_PID :13;
|
||||
u32 Stream1_trans : 1;
|
||||
u32 MAC_Multicast_filter : 1;
|
||||
u32 debug_flag_pid_saved : 1;
|
||||
u32 Stream2_PID :13;
|
||||
u32 Stream2_trans : 1;
|
||||
u32 debug_flag_write_status00 : 1;
|
||||
u32 debug_fifo_problem : 1;
|
||||
} pid_filter_300;
|
||||
|
||||
struct {
|
||||
u32 PCR_PID :13;
|
||||
u32 PCR_trans : 1;
|
||||
u32 debug_overrun3 : 1;
|
||||
u32 debug_overrun2 : 1;
|
||||
u32 PMT_PID :13;
|
||||
u32 PMT_trans : 1;
|
||||
u32 reserved : 2;
|
||||
} pid_filter_304;
|
||||
|
||||
struct {
|
||||
u32 EMM_PID :13;
|
||||
u32 EMM_trans : 1;
|
||||
u32 EMM_filter_4 : 1;
|
||||
u32 EMM_filter_6 : 1;
|
||||
u32 ECM_PID :13;
|
||||
u32 ECM_trans : 1;
|
||||
u32 reserved : 2;
|
||||
} pid_filter_308;
|
||||
|
||||
struct {
|
||||
u32 Group_PID :13;
|
||||
u32 Group_trans : 1;
|
||||
u32 unused1 : 2;
|
||||
u32 Group_mask :13;
|
||||
u32 unused2 : 3;
|
||||
} pid_filter_30c_ext_ind_0_7;
|
||||
|
||||
struct {
|
||||
u32 net_master_read :17;
|
||||
u32 unused :15;
|
||||
} pid_filter_30c_ext_ind_1;
|
||||
|
||||
struct {
|
||||
u32 net_master_write :17;
|
||||
u32 unused :15;
|
||||
} pid_filter_30c_ext_ind_2;
|
||||
|
||||
struct {
|
||||
u32 next_net_master_write :17;
|
||||
u32 unused :15;
|
||||
} pid_filter_30c_ext_ind_3;
|
||||
|
||||
struct {
|
||||
u32 unused1 : 1;
|
||||
u32 state_write :10;
|
||||
u32 reserved1 : 6;
|
||||
u32 stack_read :10;
|
||||
u32 reserved2 : 5;
|
||||
} pid_filter_30c_ext_ind_4;
|
||||
|
||||
struct {
|
||||
u32 stack_cnt :10;
|
||||
u32 unused :22;
|
||||
} pid_filter_30c_ext_ind_5;
|
||||
|
||||
struct {
|
||||
u32 pid_fsm_save_reg0 : 2;
|
||||
u32 pid_fsm_save_reg1 : 2;
|
||||
u32 pid_fsm_save_reg2 : 2;
|
||||
u32 pid_fsm_save_reg3 : 2;
|
||||
u32 pid_fsm_save_reg4 : 2;
|
||||
u32 pid_fsm_save_reg300 : 2;
|
||||
u32 write_status1 : 2;
|
||||
u32 write_status4 : 2;
|
||||
u32 data_size_reg :12;
|
||||
u32 unused : 4;
|
||||
} pid_filter_30c_ext_ind_6;
|
||||
|
||||
struct {
|
||||
u32 index_reg : 5;
|
||||
u32 extra_index_reg : 3;
|
||||
u32 AB_select : 1;
|
||||
u32 pass_alltables : 1;
|
||||
u32 unused :22;
|
||||
} index_reg_310;
|
||||
|
||||
struct {
|
||||
u32 PID :13;
|
||||
u32 PID_trans : 1;
|
||||
u32 PID_enable_bit : 1;
|
||||
u32 reserved :17;
|
||||
} pid_n_reg_314;
|
||||
|
||||
struct {
|
||||
u32 A4_byte : 8;
|
||||
u32 A5_byte : 8;
|
||||
u32 A6_byte : 8;
|
||||
u32 Enable_bit : 1;
|
||||
u32 HighAB_bit : 1;
|
||||
u32 reserved : 6;
|
||||
} mac_low_reg_318;
|
||||
|
||||
struct {
|
||||
u32 A1_byte : 8;
|
||||
u32 A2_byte : 8;
|
||||
u32 A3_byte : 8;
|
||||
u32 reserved : 8;
|
||||
} mac_high_reg_31c;
|
||||
|
||||
struct {
|
||||
u32 reserved :16;
|
||||
u32 data_Tag_ID :16;
|
||||
} data_tag_400;
|
||||
|
||||
struct {
|
||||
u32 Card_IDbyte6 : 8;
|
||||
u32 Card_IDbyte5 : 8;
|
||||
u32 Card_IDbyte4 : 8;
|
||||
u32 Card_IDbyte3 : 8;
|
||||
} card_id_408;
|
||||
|
||||
struct {
|
||||
u32 Card_IDbyte2 : 8;
|
||||
u32 Card_IDbyte1 : 8;
|
||||
} card_id_40c;
|
||||
|
||||
struct {
|
||||
u32 MAC1 : 8;
|
||||
u32 MAC2 : 8;
|
||||
u32 MAC3 : 8;
|
||||
u32 MAC6 : 8;
|
||||
} mac_address_418;
|
||||
|
||||
struct {
|
||||
u32 MAC7 : 8;
|
||||
u32 MAC8 : 8;
|
||||
u32 reserved :16;
|
||||
} mac_address_41c;
|
||||
|
||||
struct {
|
||||
u32 transmitter_data_byte : 8;
|
||||
u32 ReceiveDataReady : 1;
|
||||
u32 ReceiveByteFrameError : 1;
|
||||
u32 txbuffempty : 1;
|
||||
u32 reserved :21;
|
||||
} ci_600;
|
||||
|
||||
struct {
|
||||
u32 pi_d : 8;
|
||||
u32 pi_ha :20;
|
||||
u32 pi_rw : 1;
|
||||
u32 pi_component_reg : 3;
|
||||
} pi_604;
|
||||
|
||||
struct {
|
||||
u32 serialReset : 1;
|
||||
u32 oncecycle_read : 1;
|
||||
u32 Timer_Read_req : 1;
|
||||
u32 Timer_Load_req : 1;
|
||||
u32 timer_data : 7;
|
||||
u32 unused : 1;
|
||||
u32 Timer_addr : 5;
|
||||
u32 reserved : 3;
|
||||
u32 pcmcia_a_mod_pwr_n : 1;
|
||||
u32 pcmcia_b_mod_pwr_n : 1;
|
||||
u32 config_Done_stat : 1;
|
||||
u32 config_Init_stat : 1;
|
||||
u32 config_Prog_n : 1;
|
||||
u32 config_wr_n : 1;
|
||||
u32 config_cs_n : 1;
|
||||
u32 config_cclk : 1;
|
||||
u32 pi_CiMax_IRQ_n : 1;
|
||||
u32 pi_timeout_status : 1;
|
||||
u32 pi_wait_n : 1;
|
||||
u32 pi_busy_n : 1;
|
||||
} pi_608;
|
||||
|
||||
struct {
|
||||
u32 PID :13;
|
||||
u32 key_enable : 1;
|
||||
u32 key_code : 2;
|
||||
u32 key_array_col : 3;
|
||||
u32 key_array_row : 5;
|
||||
u32 dvb_en : 1;
|
||||
u32 rw_flag : 1;
|
||||
u32 reserved : 6;
|
||||
} dvb_reg_60c;
|
||||
|
||||
struct {
|
||||
u32 sram_addr :15;
|
||||
u32 sram_rw : 1;
|
||||
u32 sram_data : 8;
|
||||
u32 sc_xfer_bit : 1;
|
||||
u32 reserved1 : 3;
|
||||
u32 oe_pin_reg : 1;
|
||||
u32 ce_pin_reg : 1;
|
||||
u32 reserved2 : 1;
|
||||
u32 start_sram_ibi : 1;
|
||||
} sram_ctrl_reg_700;
|
||||
|
||||
struct {
|
||||
u32 net_addr_read :16;
|
||||
u32 net_addr_write :16;
|
||||
} net_buf_reg_704;
|
||||
|
||||
struct {
|
||||
u32 cai_read :11;
|
||||
u32 reserved1 : 5;
|
||||
u32 cai_write :11;
|
||||
u32 reserved2 : 6;
|
||||
u32 cai_cnt : 4;
|
||||
} cai_buf_reg_708;
|
||||
|
||||
struct {
|
||||
u32 cao_read :11;
|
||||
u32 reserved1 : 5;
|
||||
u32 cap_write :11;
|
||||
u32 reserved2 : 6;
|
||||
u32 cao_cnt : 4;
|
||||
} cao_buf_reg_70c;
|
||||
|
||||
struct {
|
||||
u32 media_read :11;
|
||||
u32 reserved1 : 5;
|
||||
u32 media_write :11;
|
||||
u32 reserved2 : 6;
|
||||
u32 media_cnt : 4;
|
||||
} media_buf_reg_710;
|
||||
|
||||
struct {
|
||||
u32 NET_Dest : 2;
|
||||
u32 CAI_Dest : 2;
|
||||
u32 CAO_Dest : 2;
|
||||
u32 MEDIA_Dest : 2;
|
||||
u32 net_ovflow_error : 1;
|
||||
u32 media_ovflow_error : 1;
|
||||
u32 cai_ovflow_error : 1;
|
||||
u32 cao_ovflow_error : 1;
|
||||
u32 ctrl_usb_wan : 1;
|
||||
u32 ctrl_sramdma : 1;
|
||||
u32 ctrl_maximumfill : 1;
|
||||
u32 reserved :17;
|
||||
} sram_dest_reg_714;
|
||||
|
||||
struct {
|
||||
u32 net_cnt :12;
|
||||
u32 reserved1 : 4;
|
||||
u32 net_addr_read : 1;
|
||||
u32 reserved2 : 3;
|
||||
u32 net_addr_write : 1;
|
||||
u32 reserved3 :11;
|
||||
} net_buf_reg_718;
|
||||
|
||||
struct {
|
||||
u32 wan_speed_sig : 2;
|
||||
u32 reserved1 : 6;
|
||||
u32 wan_wait_state : 8;
|
||||
u32 sram_chip : 2;
|
||||
u32 sram_memmap : 2;
|
||||
u32 reserved2 : 4;
|
||||
u32 wan_pkt_frame : 4;
|
||||
u32 reserved3 : 4;
|
||||
} wan_ctrl_reg_71c;
|
||||
} flexcop_ibi_value;
|
||||
|
||||
#endif
|
||||
23
drivers/media/dvb/bt8xx/Kconfig
Normal file
23
drivers/media/dvb/bt8xx/Kconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
config DVB_BT8XX
|
||||
tristate "BT8xx based PCI cards"
|
||||
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_SP887X if !DVB_FE_CUSTOMISE
|
||||
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_CX24110 if !DVB_FE_CUSTOMISE
|
||||
select DVB_OR51211 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select FW_LOADER
|
||||
help
|
||||
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
|
||||
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
|
||||
the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
|
||||
some AVerMedia cards.
|
||||
|
||||
Since these cards have no MPEG decoder onboard, they transmit
|
||||
only compressed MPEG data over the PCI bus, so you need
|
||||
an external software decoder to watch TV on your computer.
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
3
drivers/media/dvb/bt8xx/Makefile
Normal file
3
drivers/media/dvb/bt8xx/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
|
||||
|
||||
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
|
||||
636
drivers/media/dvb/bt8xx/bt878.c
Normal file
636
drivers/media/dvb/bt8xx/bt878.c
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
* bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card
|
||||
*
|
||||
* Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
|
||||
*
|
||||
* large parts based on the bttv driver
|
||||
* Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de)
|
||||
* & Marcus Metzler (mocm@metzlerbros.de)
|
||||
* (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "bt878.h"
|
||||
#include "dst_priv.h"
|
||||
|
||||
|
||||
/**************************************/
|
||||
/* Miscellaneous utility definitions */
|
||||
/**************************************/
|
||||
|
||||
static unsigned int bt878_verbose = 1;
|
||||
static unsigned int bt878_debug;
|
||||
|
||||
module_param_named(verbose, bt878_verbose, int, 0444);
|
||||
MODULE_PARM_DESC(verbose,
|
||||
"verbose startup messages, default is 1 (yes)");
|
||||
module_param_named(debug, bt878_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
|
||||
|
||||
int bt878_num;
|
||||
struct bt878 bt878[BT878_MAX];
|
||||
|
||||
EXPORT_SYMBOL(bt878_num);
|
||||
EXPORT_SYMBOL(bt878);
|
||||
|
||||
#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr)))
|
||||
#define btread(adr) bmtread(bt->bt878_mem+(adr))
|
||||
|
||||
#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
|
||||
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
|
||||
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
|
||||
|
||||
#if defined(dprintk)
|
||||
#undef dprintk
|
||||
#endif
|
||||
#define dprintk if(bt878_debug) printk
|
||||
|
||||
static void bt878_mem_free(struct bt878 *bt)
|
||||
{
|
||||
if (bt->buf_cpu) {
|
||||
pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu,
|
||||
bt->buf_dma);
|
||||
bt->buf_cpu = NULL;
|
||||
}
|
||||
|
||||
if (bt->risc_cpu) {
|
||||
pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu,
|
||||
bt->risc_dma);
|
||||
bt->risc_cpu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int bt878_mem_alloc(struct bt878 *bt)
|
||||
{
|
||||
if (!bt->buf_cpu) {
|
||||
bt->buf_size = 128 * 1024;
|
||||
|
||||
bt->buf_cpu =
|
||||
pci_alloc_consistent(bt->dev, bt->buf_size,
|
||||
&bt->buf_dma);
|
||||
|
||||
if (!bt->buf_cpu)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(bt->buf_cpu, 0, bt->buf_size);
|
||||
}
|
||||
|
||||
if (!bt->risc_cpu) {
|
||||
bt->risc_size = PAGE_SIZE;
|
||||
bt->risc_cpu =
|
||||
pci_alloc_consistent(bt->dev, bt->risc_size,
|
||||
&bt->risc_dma);
|
||||
|
||||
if (!bt->risc_cpu) {
|
||||
bt878_mem_free(bt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(bt->risc_cpu, 0, bt->risc_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RISC instructions */
|
||||
#define RISC_WRITE (0x01 << 28)
|
||||
#define RISC_JUMP (0x07 << 28)
|
||||
#define RISC_SYNC (0x08 << 28)
|
||||
|
||||
/* RISC bits */
|
||||
#define RISC_WR_SOL (1 << 27)
|
||||
#define RISC_WR_EOL (1 << 26)
|
||||
#define RISC_IRQ (1 << 24)
|
||||
#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))
|
||||
#define RISC_SYNC_RESYNC (1 << 15)
|
||||
#define RISC_SYNC_FM1 0x06
|
||||
#define RISC_SYNC_VRO 0x0C
|
||||
|
||||
#define RISC_FLUSH() bt->risc_pos = 0
|
||||
#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
|
||||
|
||||
static int bt878_make_risc(struct bt878 *bt)
|
||||
{
|
||||
bt->block_bytes = bt->buf_size >> 4;
|
||||
bt->block_count = 1 << 4;
|
||||
bt->line_bytes = bt->block_bytes;
|
||||
bt->line_count = bt->block_count;
|
||||
|
||||
while (bt->line_bytes > 4095) {
|
||||
bt->line_bytes >>= 1;
|
||||
bt->line_count <<= 1;
|
||||
}
|
||||
|
||||
if (bt->line_count > 255) {
|
||||
printk("bt878: buffer size error!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin)
|
||||
{
|
||||
u32 buf_pos = 0;
|
||||
u32 line;
|
||||
|
||||
RISC_FLUSH();
|
||||
RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin);
|
||||
RISC_INSTR(0);
|
||||
|
||||
dprintk("bt878: risc len lines %u, bytes per line %u\n",
|
||||
bt->line_count, bt->line_bytes);
|
||||
for (line = 0; line < bt->line_count; line++) {
|
||||
// At the beginning of every block we issue an IRQ with previous (finished) block number set
|
||||
if (!(buf_pos % bt->block_bytes))
|
||||
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
|
||||
RISC_IRQ |
|
||||
RISC_STATUS(((buf_pos /
|
||||
bt->block_bytes) +
|
||||
(bt->block_count -
|
||||
1)) %
|
||||
bt->block_count) | bt->
|
||||
line_bytes);
|
||||
else
|
||||
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
|
||||
bt->line_bytes);
|
||||
RISC_INSTR(bt->buf_dma + buf_pos);
|
||||
buf_pos += bt->line_bytes;
|
||||
}
|
||||
|
||||
RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO);
|
||||
RISC_INSTR(0);
|
||||
|
||||
RISC_INSTR(RISC_JUMP);
|
||||
RISC_INSTR(bt->risc_dma);
|
||||
|
||||
btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
/* Start/Stop grabbing funcs */
|
||||
/*****************************/
|
||||
|
||||
void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
|
||||
u32 irq_err_ignore)
|
||||
{
|
||||
u32 int_mask;
|
||||
|
||||
dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg);
|
||||
/* complete the writing of the risc dma program now we have
|
||||
* the card specifics
|
||||
*/
|
||||
bt878_risc_program(bt, op_sync_orin);
|
||||
controlreg &= ~0x1f;
|
||||
controlreg |= 0x1b;
|
||||
|
||||
btwrite(bt->risc_dma, BT878_ARISC_START);
|
||||
|
||||
/* original int mask had :
|
||||
* 6 2 8 4 0
|
||||
* 1111 1111 1000 0000 0000
|
||||
* SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI
|
||||
* Hacked for DST to:
|
||||
* SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI
|
||||
*/
|
||||
int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT |
|
||||
BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT |
|
||||
BT878_AFBUS | BT878_ARISCI;
|
||||
|
||||
|
||||
/* ignore pesky bits */
|
||||
int_mask &= ~irq_err_ignore;
|
||||
|
||||
btwrite(int_mask, BT878_AINT_MASK);
|
||||
btwrite(controlreg, BT878_AGPIO_DMA_CTL);
|
||||
}
|
||||
|
||||
void bt878_stop(struct bt878 *bt)
|
||||
{
|
||||
u32 stat;
|
||||
int i = 0;
|
||||
|
||||
dprintk("bt878 debug: bt878_stop\n");
|
||||
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
btand(~0x13, BT878_AGPIO_DMA_CTL);
|
||||
|
||||
do {
|
||||
stat = btread(BT878_AINT_STAT);
|
||||
if (!(stat & BT878_ARISC_EN))
|
||||
break;
|
||||
i++;
|
||||
} while (i < 500);
|
||||
|
||||
dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",
|
||||
bt->nr, i, stat);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(bt878_start);
|
||||
EXPORT_SYMBOL(bt878_stop);
|
||||
|
||||
/*****************************/
|
||||
/* Interrupt service routine */
|
||||
/*****************************/
|
||||
|
||||
static irqreturn_t bt878_irq(int irq, void *dev_id)
|
||||
{
|
||||
u32 stat, astat, mask;
|
||||
int count;
|
||||
struct bt878 *bt;
|
||||
|
||||
bt = (struct bt878 *) dev_id;
|
||||
|
||||
count = 0;
|
||||
while (1) {
|
||||
stat = btread(BT878_AINT_STAT);
|
||||
mask = btread(BT878_AINT_MASK);
|
||||
if (!(astat = (stat & mask)))
|
||||
return IRQ_NONE; /* this interrupt is not for me */
|
||||
/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */
|
||||
btwrite(astat, BT878_AINT_STAT); /* try to clear interupt condition */
|
||||
|
||||
|
||||
if (astat & (BT878_ASCERR | BT878_AOCERR)) {
|
||||
if (bt878_verbose) {
|
||||
printk("bt878(%d): irq%s%s risc_pc=%08x\n",
|
||||
bt->nr,
|
||||
(astat & BT878_ASCERR) ? " SCERR" :
|
||||
"",
|
||||
(astat & BT878_AOCERR) ? " OCERR" :
|
||||
"", btread(BT878_ARISC_PC));
|
||||
}
|
||||
}
|
||||
if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) {
|
||||
if (bt878_verbose) {
|
||||
printk
|
||||
("bt878(%d): irq%s%s%s risc_pc=%08x\n",
|
||||
bt->nr,
|
||||
(astat & BT878_APABORT) ? " PABORT" :
|
||||
"",
|
||||
(astat & BT878_ARIPERR) ? " RIPERR" :
|
||||
"",
|
||||
(astat & BT878_APPERR) ? " PPERR" :
|
||||
"", btread(BT878_ARISC_PC));
|
||||
}
|
||||
}
|
||||
if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) {
|
||||
if (bt878_verbose) {
|
||||
printk
|
||||
("bt878(%d): irq%s%s%s risc_pc=%08x\n",
|
||||
bt->nr,
|
||||
(astat & BT878_AFDSR) ? " FDSR" : "",
|
||||
(astat & BT878_AFTRGT) ? " FTRGT" :
|
||||
"",
|
||||
(astat & BT878_AFBUS) ? " FBUS" : "",
|
||||
btread(BT878_ARISC_PC));
|
||||
}
|
||||
}
|
||||
if (astat & BT878_ARISCI) {
|
||||
bt->finished_block = (stat & BT878_ARISCS) >> 28;
|
||||
tasklet_schedule(&bt->tasklet);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
if (count > 20) {
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
printk(KERN_ERR
|
||||
"bt878(%d): IRQ lockup, cleared int mask\n",
|
||||
bt->nr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int
|
||||
bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = 0;
|
||||
if (mutex_lock_interruptible(&bt->gpio_lock))
|
||||
return -ERESTARTSYS;
|
||||
/* special gpio signal */
|
||||
switch (cmd) {
|
||||
case DST_IG_ENABLE:
|
||||
// dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable);
|
||||
retval = bttv_gpio_enable(bt->bttv_nr,
|
||||
mp->enb.mask,
|
||||
mp->enb.enable);
|
||||
break;
|
||||
case DST_IG_WRITE:
|
||||
// dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals);
|
||||
retval = bttv_write_gpio(bt->bttv_nr,
|
||||
mp->outp.mask,
|
||||
mp->outp.highvals);
|
||||
|
||||
break;
|
||||
case DST_IG_READ:
|
||||
/* read */
|
||||
retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value);
|
||||
// dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value);
|
||||
break;
|
||||
case DST_IG_TS:
|
||||
/* Set packet size */
|
||||
bt->TS_Size = mp->psize;
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&bt->gpio_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(bt878_device_control);
|
||||
|
||||
|
||||
static struct cards card_list[] __devinitdata = {
|
||||
|
||||
{ 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
|
||||
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
|
||||
{ 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" },
|
||||
{ 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" },
|
||||
{ 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" },
|
||||
{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
|
||||
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
|
||||
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
|
||||
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
|
||||
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
|
||||
{ 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
|
||||
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
|
||||
|
||||
{ 0, -1, NULL }
|
||||
};
|
||||
|
||||
|
||||
/***********************/
|
||||
/* PCI device handling */
|
||||
/***********************/
|
||||
|
||||
static int __devinit bt878_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
int result = 0, has_dvb = 0, i;
|
||||
unsigned char lat;
|
||||
struct bt878 *bt;
|
||||
#if defined(__powerpc__)
|
||||
unsigned int cmd;
|
||||
#endif
|
||||
unsigned int cardid;
|
||||
unsigned short id;
|
||||
struct cards *dvb_cards;
|
||||
|
||||
printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
|
||||
bt878_num);
|
||||
if (bt878_num >= BT878_MAX) {
|
||||
printk(KERN_ERR "bt878: Too many devices inserted\n");
|
||||
result = -ENOMEM;
|
||||
goto fail0;
|
||||
}
|
||||
if (pci_enable_device(dev))
|
||||
return -EIO;
|
||||
|
||||
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id);
|
||||
cardid = id << 16;
|
||||
pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id);
|
||||
cardid |= id;
|
||||
|
||||
for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) {
|
||||
if (cardid == dvb_cards->pci_id) {
|
||||
printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n",
|
||||
__func__, cardid, dvb_cards->name);
|
||||
has_dvb = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_dvb) {
|
||||
printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid);
|
||||
result = -EINVAL;
|
||||
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
bt = &bt878[bt878_num];
|
||||
bt->dev = dev;
|
||||
bt->nr = bt878_num;
|
||||
bt->shutdown = 0;
|
||||
|
||||
bt->id = dev->device;
|
||||
bt->irq = dev->irq;
|
||||
bt->bt878_adr = pci_resource_start(dev, 0);
|
||||
if (!request_mem_region(pci_resource_start(dev, 0),
|
||||
pci_resource_len(dev, 0), "bt878")) {
|
||||
result = -EBUSY;
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision);
|
||||
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
|
||||
|
||||
|
||||
printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ",
|
||||
bt878_num, bt->id, bt->revision, dev->bus->number,
|
||||
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
||||
printk("irq: %d, latency: %d, memory: 0x%lx\n",
|
||||
bt->irq, lat, bt->bt878_adr);
|
||||
|
||||
|
||||
#if defined(__powerpc__)
|
||||
/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
|
||||
/* response on cards with no firmware is not enabled by OF */
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &cmd);
|
||||
cmd = (cmd | PCI_COMMAND_MEMORY);
|
||||
pci_write_config_dword(dev, PCI_COMMAND, cmd);
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
bt->bt878_mem = (unsigned char *) bt->bt878_adr;
|
||||
#else
|
||||
bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000);
|
||||
#endif
|
||||
|
||||
/* clear interrupt mask */
|
||||
btwrite(0, BT848_INT_MASK);
|
||||
|
||||
result = request_irq(bt->irq, bt878_irq,
|
||||
IRQF_SHARED | IRQF_DISABLED, "bt878",
|
||||
(void *) bt);
|
||||
if (result == -EINVAL) {
|
||||
printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
|
||||
bt878_num);
|
||||
goto fail1;
|
||||
}
|
||||
if (result == -EBUSY) {
|
||||
printk(KERN_ERR
|
||||
"bt878(%d): IRQ %d busy, change your PnP config in BIOS\n",
|
||||
bt878_num, bt->irq);
|
||||
goto fail1;
|
||||
}
|
||||
if (result < 0)
|
||||
goto fail1;
|
||||
|
||||
pci_set_master(dev);
|
||||
pci_set_drvdata(dev, bt);
|
||||
|
||||
/* if(init_bt878(btv) < 0) {
|
||||
bt878_remove(dev);
|
||||
return -EIO;
|
||||
}
|
||||
*/
|
||||
|
||||
if ((result = bt878_mem_alloc(bt))) {
|
||||
printk("bt878: failed to allocate memory!\n");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
bt878_make_risc(bt);
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
bt878_num++;
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
free_irq(bt->irq, bt);
|
||||
fail1:
|
||||
release_mem_region(pci_resource_start(bt->dev, 0),
|
||||
pci_resource_len(bt->dev, 0));
|
||||
fail0:
|
||||
pci_disable_device(dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __devexit bt878_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
u8 command;
|
||||
struct bt878 *bt = pci_get_drvdata(pci_dev);
|
||||
|
||||
if (bt878_verbose)
|
||||
printk("bt878(%d): unloading\n", bt->nr);
|
||||
|
||||
/* turn off all capturing, DMA and IRQs */
|
||||
btand(~0x13, BT878_AGPIO_DMA_CTL);
|
||||
|
||||
/* first disable interrupts before unmapping the memory! */
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
btwrite(~0U, BT878_AINT_STAT);
|
||||
|
||||
/* disable PCI bus-mastering */
|
||||
pci_read_config_byte(bt->dev, PCI_COMMAND, &command);
|
||||
/* Should this be &=~ ?? */
|
||||
command &= ~PCI_COMMAND_MASTER;
|
||||
pci_write_config_byte(bt->dev, PCI_COMMAND, command);
|
||||
|
||||
free_irq(bt->irq, bt);
|
||||
printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem);
|
||||
if (bt->bt878_mem)
|
||||
iounmap(bt->bt878_mem);
|
||||
|
||||
release_mem_region(pci_resource_start(bt->dev, 0),
|
||||
pci_resource_len(bt->dev, 0));
|
||||
/* wake up any waiting processes
|
||||
because shutdown flag is set, no new processes (in this queue)
|
||||
are expected
|
||||
*/
|
||||
bt->shutdown = 1;
|
||||
bt878_mem_free(bt);
|
||||
|
||||
pci_set_drvdata(pci_dev, NULL);
|
||||
pci_disable_device(pci_dev);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
|
||||
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{0,}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
|
||||
|
||||
static struct pci_driver bt878_pci_driver = {
|
||||
.name = "bt878",
|
||||
.id_table = bt878_pci_tbl,
|
||||
.probe = bt878_probe,
|
||||
.remove = bt878_remove,
|
||||
};
|
||||
|
||||
static int bt878_pci_driver_registered;
|
||||
|
||||
/*******************************/
|
||||
/* Module management functions */
|
||||
/*******************************/
|
||||
|
||||
static int bt878_init_module(void)
|
||||
{
|
||||
bt878_num = 0;
|
||||
bt878_pci_driver_registered = 0;
|
||||
|
||||
printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
|
||||
(BT878_VERSION_CODE >> 16) & 0xff,
|
||||
(BT878_VERSION_CODE >> 8) & 0xff,
|
||||
BT878_VERSION_CODE & 0xff);
|
||||
/*
|
||||
bt878_check_chipset();
|
||||
*/
|
||||
/* later we register inside of bt878_find_audio_dma()
|
||||
* because we may want to ignore certain cards */
|
||||
bt878_pci_driver_registered = 1;
|
||||
return pci_register_driver(&bt878_pci_driver);
|
||||
}
|
||||
|
||||
static void bt878_cleanup_module(void)
|
||||
{
|
||||
if (bt878_pci_driver_registered) {
|
||||
bt878_pci_driver_registered = 0;
|
||||
pci_unregister_driver(&bt878_pci_driver);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(bt878_init_module);
|
||||
module_exit(bt878_cleanup_module);
|
||||
|
||||
//MODULE_AUTHOR("XXX");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
166
drivers/media/dvb/bt8xx/bt878.h
Normal file
166
drivers/media/dvb/bt8xx/bt878.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
bt878.h - Bt878 audio module (register offsets)
|
||||
|
||||
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _BT878_H_
|
||||
#define _BT878_H_
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "bt848.h"
|
||||
#include "bttv.h"
|
||||
|
||||
#define BT878_VERSION_CODE 0x000000
|
||||
|
||||
#define BT878_AINT_STAT 0x100
|
||||
#define BT878_ARISCS (0xf<<28)
|
||||
#define BT878_ARISC_EN (1<<27)
|
||||
#define BT878_ASCERR (1<<19)
|
||||
#define BT878_AOCERR (1<<18)
|
||||
#define BT878_APABORT (1<<17)
|
||||
#define BT878_ARIPERR (1<<16)
|
||||
#define BT878_APPERR (1<<15)
|
||||
#define BT878_AFDSR (1<<14)
|
||||
#define BT878_AFTRGT (1<<13)
|
||||
#define BT878_AFBUS (1<<12)
|
||||
#define BT878_ARISCI (1<<11)
|
||||
#define BT878_AOFLOW (1<<3)
|
||||
|
||||
#define BT878_AINT_MASK 0x104
|
||||
|
||||
#define BT878_AGPIO_DMA_CTL 0x10c
|
||||
#define BT878_A_GAIN (0xf<<28)
|
||||
#define BT878_A_G2X (1<<27)
|
||||
#define BT878_A_PWRDN (1<<26)
|
||||
#define BT878_A_SEL (3<<24)
|
||||
#define BT878_DA_SCE (1<<23)
|
||||
#define BT878_DA_LRI (1<<22)
|
||||
#define BT878_DA_MLB (1<<21)
|
||||
#define BT878_DA_LRD (0x1f<<16)
|
||||
#define BT878_DA_DPM (1<<15)
|
||||
#define BT878_DA_SBR (1<<14)
|
||||
#define BT878_DA_ES2 (1<<13)
|
||||
#define BT878_DA_LMT (1<<12)
|
||||
#define BT878_DA_SDR (0xf<<8)
|
||||
#define BT878_DA_IOM (3<<6)
|
||||
#define BT878_DA_APP (1<<5)
|
||||
#define BT878_ACAP_EN (1<<4)
|
||||
#define BT878_PKTP (3<<2)
|
||||
#define BT878_RISC_EN (1<<1)
|
||||
#define BT878_FIFO_EN 1
|
||||
|
||||
#define BT878_APACK_LEN 0x110
|
||||
#define BT878_AFP_LEN (0xff<<16)
|
||||
#define BT878_ALP_LEN 0xfff
|
||||
|
||||
#define BT878_ARISC_START 0x114
|
||||
|
||||
#define BT878_ARISC_PC 0x120
|
||||
|
||||
/* BT878 FUNCTION 0 REGISTERS */
|
||||
#define BT878_GPIO_DMA_CTL 0x10c
|
||||
|
||||
/* Interrupt register */
|
||||
#define BT878_INT_STAT 0x100
|
||||
#define BT878_INT_MASK 0x104
|
||||
#define BT878_I2CRACK (1<<25)
|
||||
#define BT878_I2CDONE (1<<8)
|
||||
|
||||
#define BT878_MAX 4
|
||||
|
||||
#define BT878_RISC_SYNC_MASK (1 << 15)
|
||||
|
||||
|
||||
#define BTTV_BOARD_UNKNOWN 0x00
|
||||
#define BTTV_BOARD_PINNACLESAT 0x5e
|
||||
#define BTTV_BOARD_NEBULA_DIGITV 0x68
|
||||
#define BTTV_BOARD_PC_HDTV 0x70
|
||||
#define BTTV_BOARD_TWINHAN_DST 0x71
|
||||
#define BTTV_BOARD_AVDVBT_771 0x7b
|
||||
#define BTTV_BOARD_AVDVBT_761 0x7c
|
||||
#define BTTV_BOARD_DVICO_DVBT_LITE 0x80
|
||||
#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
|
||||
|
||||
struct cards {
|
||||
__u32 pci_id;
|
||||
__u16 card_id;
|
||||
char *name;
|
||||
};
|
||||
|
||||
extern int bt878_num;
|
||||
|
||||
struct bt878 {
|
||||
struct mutex gpio_lock;
|
||||
unsigned int nr;
|
||||
unsigned int bttv_nr;
|
||||
struct i2c_adapter *adapter;
|
||||
struct pci_dev *dev;
|
||||
unsigned int id;
|
||||
unsigned int TS_Size;
|
||||
unsigned char revision;
|
||||
unsigned int irq;
|
||||
unsigned long bt878_adr;
|
||||
volatile void __iomem *bt878_mem; /* function 1 */
|
||||
|
||||
volatile u32 finished_block;
|
||||
volatile u32 last_block;
|
||||
u32 block_count;
|
||||
u32 block_bytes;
|
||||
u32 line_bytes;
|
||||
u32 line_count;
|
||||
|
||||
u32 buf_size;
|
||||
u8 *buf_cpu;
|
||||
dma_addr_t buf_dma;
|
||||
|
||||
u32 risc_size;
|
||||
u32 *risc_cpu;
|
||||
dma_addr_t risc_dma;
|
||||
u32 risc_pos;
|
||||
|
||||
struct tasklet_struct tasklet;
|
||||
int shutdown;
|
||||
};
|
||||
|
||||
extern struct bt878 bt878[BT878_MAX];
|
||||
|
||||
void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
|
||||
u32 irq_err_ignore);
|
||||
void bt878_stop(struct bt878 *bt);
|
||||
|
||||
#if defined(__powerpc__) /* big-endian */
|
||||
extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
|
||||
{
|
||||
__asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val),
|
||||
"r"(addr));
|
||||
__asm__ __volatile__("eieio":::"memory");
|
||||
}
|
||||
|
||||
#define bmtwrite(dat,adr) io_st_le32((adr),(dat))
|
||||
#define bmtread(adr) ld_le32((adr))
|
||||
#else
|
||||
#define bmtwrite(dat,adr) writel((dat), (adr))
|
||||
#define bmtread(adr) readl(adr)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1871
drivers/media/dvb/bt8xx/dst.c
Normal file
1871
drivers/media/dvb/bt8xx/dst.c
Normal file
File diff suppressed because it is too large
Load Diff
719
drivers/media/dvb/bt8xx/dst_ca.c
Normal file
719
drivers/media/dvb/bt8xx/dst_ca.c
Normal file
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
CA-driver for TwinHan DST Frontend/Card
|
||||
|
||||
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dst_ca.h"
|
||||
#include "dst_common.h"
|
||||
|
||||
#define DST_CA_ERROR 0
|
||||
#define DST_CA_NOTICE 1
|
||||
#define DST_CA_INFO 2
|
||||
#define DST_CA_DEBUG 3
|
||||
|
||||
#define dprintk(x, y, z, format, arg...) do { \
|
||||
if (z) { \
|
||||
if ((x > DST_CA_ERROR) && (x > y)) \
|
||||
printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \
|
||||
else if ((x > DST_CA_NOTICE) && (x > y)) \
|
||||
printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \
|
||||
else if ((x > DST_CA_INFO) && (x > y)) \
|
||||
printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \
|
||||
else if ((x > DST_CA_DEBUG) && (x > y)) \
|
||||
printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \
|
||||
} else { \
|
||||
if (x > y) \
|
||||
printk(format, ## arg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
static unsigned int verbose = 5;
|
||||
module_param(verbose, int, 0644);
|
||||
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
|
||||
|
||||
/* Need some more work */
|
||||
static int ca_set_slot_descr(void)
|
||||
{
|
||||
/* We could make this more graceful ? */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Need some more work */
|
||||
static int ca_set_pid(void)
|
||||
{
|
||||
/* We could make this more graceful ? */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void put_command_and_length(u8 *data, int command, int length)
|
||||
{
|
||||
data[0] = (command >> 16) & 0xff;
|
||||
data[1] = (command >> 8) & 0xff;
|
||||
data[2] = command & 0xff;
|
||||
data[3] = length;
|
||||
}
|
||||
|
||||
static void put_checksum(u8 *check_string, int length)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length);
|
||||
check_string[length] = dst_check_sum (check_string, length);
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]);
|
||||
}
|
||||
|
||||
static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
|
||||
{
|
||||
u8 reply;
|
||||
|
||||
mutex_lock(&state->dst_mutex);
|
||||
dst_comm_init(state);
|
||||
msleep(65);
|
||||
|
||||
if (write_dst(state, data, len)) {
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
|
||||
dst_error_recovery(state);
|
||||
goto error;
|
||||
}
|
||||
if ((dst_pio_disable(state)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
|
||||
goto error;
|
||||
}
|
||||
if (read_dst(state, &reply, GET_ACK) < 0) {
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
|
||||
dst_error_recovery(state);
|
||||
goto error;
|
||||
}
|
||||
if (read) {
|
||||
if (! dst_wait_dst_ready(state, LONG_DELAY)) {
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
|
||||
goto error;
|
||||
}
|
||||
if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
|
||||
dst_error_recovery(state);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&state->dst_mutex);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
mutex_unlock(&state->dst_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
|
||||
{
|
||||
u8 dst_ca_comm_err = 0;
|
||||
|
||||
while (dst_ca_comm_err < RETRIES) {
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
|
||||
if (dst_ci_command(state, data, ca_string, len, read)) { // If error
|
||||
dst_error_recovery(state);
|
||||
dst_ca_comm_err++; // work required here.
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dst_ca_comm_err == RETRIES)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ca_get_app_info(struct dst_state *state)
|
||||
{
|
||||
int length, str_length;
|
||||
static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
|
||||
|
||||
put_checksum(&command[0], command[0]);
|
||||
if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
|
||||
dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
|
||||
state->messages[7], (state->messages[8] << 8) | state->messages[9],
|
||||
(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
|
||||
dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
|
||||
|
||||
// Transform dst message to correct application_info message
|
||||
length = state->messages[5];
|
||||
str_length = length - 6;
|
||||
if (str_length < 0) {
|
||||
str_length = 0;
|
||||
dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
|
||||
}
|
||||
|
||||
// First, the command and length fields
|
||||
put_command_and_length(&state->messages[0], CA_APP_INFO, length);
|
||||
|
||||
// Copy application_type, application_manufacturer and manufacturer_code
|
||||
memcpy(&state->messages[4], &state->messages[7], 5);
|
||||
|
||||
// Set string length and copy string
|
||||
state->messages[9] = str_length;
|
||||
memcpy(&state->messages[10], &state->messages[12], str_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ca_get_ca_info(struct dst_state *state)
|
||||
{
|
||||
int srcPtr, dstPtr, i, num_ids;
|
||||
static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
|
||||
const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
|
||||
|
||||
put_checksum(&slot_command[0], slot_command[0]);
|
||||
if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
|
||||
|
||||
// Print raw data
|
||||
dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
|
||||
for (i = 0; i < state->messages[0] + 1; i++) {
|
||||
dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 0, "]\n");
|
||||
|
||||
// Set the command and length of the output
|
||||
num_ids = state->messages[in_num_ids_pos];
|
||||
if (num_ids >= 100) {
|
||||
num_ids = 100;
|
||||
dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
|
||||
}
|
||||
put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
|
||||
|
||||
dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
|
||||
srcPtr = in_system_id_pos;
|
||||
dstPtr = out_system_id_pos;
|
||||
for(i = 0; i < num_ids; i++) {
|
||||
dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
|
||||
// Append to output
|
||||
state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
|
||||
state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
|
||||
srcPtr += 2;
|
||||
dstPtr += 2;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 0, "]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
|
||||
{
|
||||
int i;
|
||||
u8 slot_cap[256];
|
||||
static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
|
||||
|
||||
put_checksum(&slot_command[0], slot_command[0]);
|
||||
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
|
||||
|
||||
/* Will implement the rest soon */
|
||||
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
|
||||
for (i = 0; i < slot_cap[0] + 1; i++)
|
||||
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "\n");
|
||||
|
||||
p_ca_caps->slot_num = 1;
|
||||
p_ca_caps->slot_type = 1;
|
||||
p_ca_caps->descr_num = slot_cap[7];
|
||||
p_ca_caps->descr_type = 1;
|
||||
|
||||
if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Need some more work */
|
||||
static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
|
||||
{
|
||||
int i;
|
||||
static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
|
||||
|
||||
u8 *slot_info = state->messages;
|
||||
|
||||
put_checksum(&slot_command[0], 7);
|
||||
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
|
||||
|
||||
/* Will implement the rest soon */
|
||||
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
|
||||
for (i = 0; i < 8; i++)
|
||||
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "\n");
|
||||
|
||||
if (slot_info[4] & 0x80) {
|
||||
p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
|
||||
p_ca_slot_info->num = 1;
|
||||
p_ca_slot_info->type = CA_CI;
|
||||
} else if (slot_info[4] & 0x40) {
|
||||
p_ca_slot_info->flags = CA_CI_MODULE_READY;
|
||||
p_ca_slot_info->num = 1;
|
||||
p_ca_slot_info->type = CA_CI;
|
||||
} else
|
||||
p_ca_slot_info->flags = 0;
|
||||
|
||||
if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
|
||||
{
|
||||
u8 i = 0;
|
||||
u32 command = 0;
|
||||
|
||||
if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
|
||||
return -EFAULT;
|
||||
|
||||
if (p_ca_message->msg) {
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
command = command | p_ca_message->msg[i];
|
||||
if (i < 2)
|
||||
command = command << 8;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
|
||||
|
||||
switch (command) {
|
||||
case CA_APP_INFO:
|
||||
memcpy(p_ca_message->msg, state->messages, 128);
|
||||
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
|
||||
return -EFAULT;
|
||||
break;
|
||||
case CA_INFO:
|
||||
memcpy(p_ca_message->msg, state->messages, 128);
|
||||
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
|
||||
{
|
||||
if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
|
||||
hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
|
||||
hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
|
||||
} else {
|
||||
if (length > 247) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
|
||||
return -1;
|
||||
}
|
||||
hw_buffer->msg[0] = (length & 0xff) + 7;
|
||||
hw_buffer->msg[1] = 0x40;
|
||||
hw_buffer->msg[2] = 0x03;
|
||||
hw_buffer->msg[3] = 0x00;
|
||||
hw_buffer->msg[4] = 0x03;
|
||||
hw_buffer->msg[5] = length & 0xff;
|
||||
hw_buffer->msg[6] = 0x00;
|
||||
|
||||
/*
|
||||
* Need to compute length for EN50221 section 8.3.2, for the time being
|
||||
* assuming 8.3.2 is not applicable
|
||||
*/
|
||||
memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
|
||||
{
|
||||
if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
|
||||
rdc_reset_state(state);
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 asn_1_decode(u8 *asn_1_array)
|
||||
{
|
||||
u8 length_field = 0, word_count = 0, count = 0;
|
||||
u32 length = 0;
|
||||
|
||||
length_field = asn_1_array[0];
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
|
||||
if (length_field < 0x80) {
|
||||
length = length_field & 0x7f;
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
|
||||
} else {
|
||||
word_count = length_field & 0x7f;
|
||||
for (count = 0; count < word_count; count++) {
|
||||
length = length << 8;
|
||||
length += asn_1_array[count + 1];
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static int debug_string(u8 *msg, u32 length, u32 offset)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
|
||||
for (i = offset; i < length; i++)
|
||||
dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
|
||||
dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
|
||||
{
|
||||
u32 length = 0;
|
||||
u8 tag_length = 8;
|
||||
|
||||
length = asn_1_decode(&p_ca_message->msg[3]);
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
|
||||
debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */
|
||||
|
||||
memset(hw_buffer->msg, '\0', length);
|
||||
handle_dst_tag(state, p_ca_message, hw_buffer, length);
|
||||
put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
|
||||
|
||||
debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */
|
||||
write_to_8820(state, hw_buffer, (length + tag_length), reply);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Board supports CA PMT reply ? */
|
||||
static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
|
||||
{
|
||||
int ca_pmt_reply_test = 0;
|
||||
|
||||
/* Do test board */
|
||||
/* Not there yet but soon */
|
||||
|
||||
/* CA PMT Reply capable */
|
||||
if (ca_pmt_reply_test) {
|
||||
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Process CA PMT Reply */
|
||||
/* will implement soon */
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
|
||||
}
|
||||
/* CA PMT Reply not capable */
|
||||
if (!ca_pmt_reply_test) {
|
||||
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
|
||||
/* put a dummy message */
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int ca_message_header_len;
|
||||
|
||||
u32 command = 0;
|
||||
struct ca_msg *hw_buffer;
|
||||
int result = 0;
|
||||
|
||||
if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
|
||||
return -ENOMEM;
|
||||
}
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " ");
|
||||
|
||||
if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
|
||||
result = -EFAULT;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
|
||||
|
||||
if (p_ca_message->msg) {
|
||||
ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */
|
||||
/* EN50221 tag */
|
||||
command = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
command = command | p_ca_message->msg[i];
|
||||
if (i < 2)
|
||||
command = command << 8;
|
||||
}
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
|
||||
|
||||
switch (command) {
|
||||
case CA_PMT:
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
|
||||
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
|
||||
break;
|
||||
case CA_PMT_REPLY:
|
||||
dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
|
||||
/* Have to handle the 2 basic types of cards here */
|
||||
if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
|
||||
break;
|
||||
case CA_APP_INFO_ENQUIRY: // only for debugging
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
|
||||
|
||||
if ((ca_get_app_info(state)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
|
||||
break;
|
||||
case CA_INFO_ENQUIRY:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
|
||||
|
||||
if ((ca_get_ca_info(state)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_mem_and_exit:
|
||||
kfree (hw_buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg)
|
||||
{
|
||||
struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
|
||||
struct dst_state* state = (struct dst_state*) dvbdev->priv;
|
||||
struct ca_slot_info *p_ca_slot_info;
|
||||
struct ca_caps *p_ca_caps;
|
||||
struct ca_msg *p_ca_message;
|
||||
void __user *arg = (void __user *)ioctl_arg;
|
||||
int result = 0;
|
||||
|
||||
p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
|
||||
p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
|
||||
p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
|
||||
if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
|
||||
result = -ENOMEM;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
|
||||
/* We have now only the standard ioctl's, the driver is upposed to handle internals. */
|
||||
switch (cmd) {
|
||||
case CA_SEND_MSG:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Sending message");
|
||||
if ((ca_send_message(state, p_ca_message, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
break;
|
||||
case CA_GET_MSG:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting message");
|
||||
if ((ca_get_message(state, p_ca_message, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
|
||||
break;
|
||||
case CA_RESET:
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
|
||||
dst_error_bailout(state);
|
||||
msleep(4000);
|
||||
break;
|
||||
case CA_GET_SLOT_INFO:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
|
||||
if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
|
||||
break;
|
||||
case CA_GET_CAP:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
|
||||
if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
|
||||
break;
|
||||
case CA_GET_DESCR_INFO:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
|
||||
if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
|
||||
break;
|
||||
case CA_SET_DESCR:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
|
||||
if ((ca_set_slot_descr()) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
|
||||
break;
|
||||
case CA_SET_PID:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
|
||||
if ((ca_set_pid()) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
|
||||
default:
|
||||
result = -EOPNOTSUPP;
|
||||
};
|
||||
free_mem_and_exit:
|
||||
kfree (p_ca_message);
|
||||
kfree (p_ca_slot_info);
|
||||
kfree (p_ca_caps);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dst_ca_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dst_ca_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
|
||||
{
|
||||
ssize_t bytes_read = 0;
|
||||
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dst_ca_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = dst_ca_ioctl,
|
||||
.open = dst_ca_open,
|
||||
.release = dst_ca_release,
|
||||
.read = dst_ca_read,
|
||||
.write = dst_ca_write
|
||||
};
|
||||
|
||||
static struct dvb_device dvbdev_ca = {
|
||||
.priv = NULL,
|
||||
.users = 1,
|
||||
.readers = 1,
|
||||
.writers = 1,
|
||||
.fops = &dst_ca_fops
|
||||
};
|
||||
|
||||
struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
|
||||
dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
|
||||
if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
|
||||
dst->dst_ca = dvbdev;
|
||||
return dst->dst_ca;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dst_ca_attach);
|
||||
|
||||
MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
|
||||
MODULE_AUTHOR("Manu Abraham");
|
||||
MODULE_LICENSE("GPL");
|
||||
58
drivers/media/dvb/bt8xx/dst_ca.h
Normal file
58
drivers/media/dvb/bt8xx/dst_ca.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
CA-driver for TwinHan DST Frontend/Card
|
||||
|
||||
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DST_CA_H_
|
||||
#define _DST_CA_H_
|
||||
|
||||
#define RETRIES 5
|
||||
|
||||
|
||||
#define CA_APP_INFO_ENQUIRY 0x9f8020
|
||||
#define CA_APP_INFO 0x9f8021
|
||||
#define CA_ENTER_MENU 0x9f8022
|
||||
#define CA_INFO_ENQUIRY 0x9f8030
|
||||
#define CA_INFO 0x9f8031
|
||||
#define CA_PMT 0x9f8032
|
||||
#define CA_PMT_REPLY 0x9f8033
|
||||
|
||||
#define CA_CLOSE_MMI 0x9f8800
|
||||
#define CA_DISPLAY_CONTROL 0x9f8801
|
||||
#define CA_DISPLAY_REPLY 0x9f8802
|
||||
#define CA_TEXT_LAST 0x9f8803
|
||||
#define CA_TEXT_MORE 0x9f8804
|
||||
#define CA_KEYPAD_CONTROL 0x9f8805
|
||||
#define CA_KEYPRESS 0x9f8806
|
||||
|
||||
#define CA_ENQUIRY 0x9f8807
|
||||
#define CA_ANSWER 0x9f8808
|
||||
#define CA_MENU_LAST 0x9f8809
|
||||
#define CA_MENU_MORE 0x9f880a
|
||||
#define CA_MENU_ANSWER 0x9f880b
|
||||
#define CA_LIST_LAST 0x9f880c
|
||||
#define CA_LIST_MORE 0x9f880d
|
||||
|
||||
|
||||
struct dst_ca_private {
|
||||
struct dst_state *dst;
|
||||
struct dvb_device *dvbdev;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
188
drivers/media/dvb/bt8xx/dst_common.h
Normal file
188
drivers/media/dvb/bt8xx/dst_common.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
Frontend-driver for TwinHan DST Frontend
|
||||
|
||||
Copyright (C) 2003 Jamie Honan
|
||||
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef DST_COMMON_H
|
||||
#define DST_COMMON_H
|
||||
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "bt878.h"
|
||||
|
||||
#include "dst_ca.h"
|
||||
|
||||
|
||||
#define NO_DELAY 0
|
||||
#define LONG_DELAY 1
|
||||
#define DEVICE_INIT 2
|
||||
|
||||
#define DELAY 1
|
||||
|
||||
#define DST_TYPE_IS_SAT 0
|
||||
#define DST_TYPE_IS_TERR 1
|
||||
#define DST_TYPE_IS_CABLE 2
|
||||
#define DST_TYPE_IS_ATSC 3
|
||||
|
||||
#define DST_TYPE_HAS_TS188 1
|
||||
#define DST_TYPE_HAS_TS204 2
|
||||
#define DST_TYPE_HAS_SYMDIV 4
|
||||
#define DST_TYPE_HAS_FW_1 8
|
||||
#define DST_TYPE_HAS_FW_2 16
|
||||
#define DST_TYPE_HAS_FW_3 32
|
||||
#define DST_TYPE_HAS_FW_BUILD 64
|
||||
#define DST_TYPE_HAS_OBS_REGS 128
|
||||
#define DST_TYPE_HAS_INC_COUNT 256
|
||||
#define DST_TYPE_HAS_MULTI_FE 512
|
||||
#define DST_TYPE_HAS_NEWTUNE_2 1024
|
||||
#define DST_TYPE_HAS_DBOARD 2048
|
||||
#define DST_TYPE_HAS_VLF 4096
|
||||
|
||||
/* Card capability list */
|
||||
|
||||
#define DST_TYPE_HAS_MAC 1
|
||||
#define DST_TYPE_HAS_DISEQC3 2
|
||||
#define DST_TYPE_HAS_DISEQC4 4
|
||||
#define DST_TYPE_HAS_DISEQC5 8
|
||||
#define DST_TYPE_HAS_MOTO 16
|
||||
#define DST_TYPE_HAS_CA 32
|
||||
#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */
|
||||
#define DST_TYPE_HAS_SESSION 128
|
||||
|
||||
#define TUNER_TYPE_MULTI 1
|
||||
#define TUNER_TYPE_UNKNOWN 2
|
||||
/* DVB-S */
|
||||
#define TUNER_TYPE_L64724 4
|
||||
#define TUNER_TYPE_STV0299 8
|
||||
#define TUNER_TYPE_MB86A15 16
|
||||
|
||||
/* DVB-T */
|
||||
#define TUNER_TYPE_TDA10046 32
|
||||
|
||||
/* ATSC */
|
||||
#define TUNER_TYPE_NXT200x 64
|
||||
|
||||
|
||||
#define RDC_8820_PIO_0_DISABLE 0
|
||||
#define RDC_8820_PIO_0_ENABLE 1
|
||||
#define RDC_8820_INT 2
|
||||
#define RDC_8820_RESET 4
|
||||
|
||||
/* DST Communication */
|
||||
#define GET_REPLY 1
|
||||
#define NO_REPLY 0
|
||||
|
||||
#define GET_ACK 1
|
||||
#define FIXED_COMM 8
|
||||
|
||||
#define ACK 0xff
|
||||
|
||||
struct dst_state {
|
||||
|
||||
struct i2c_adapter* i2c;
|
||||
|
||||
struct bt878* bt;
|
||||
|
||||
/* configuration settings */
|
||||
const struct dst_config* config;
|
||||
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
/* private ASIC data */
|
||||
u8 tx_tuna[10];
|
||||
u8 rx_tuna[10];
|
||||
u8 rxbuffer[10];
|
||||
u8 diseq_flags;
|
||||
u8 dst_type;
|
||||
u32 type_flags;
|
||||
u32 frequency; /* intermediate frequency in kHz for QPSK */
|
||||
fe_spectral_inversion_t inversion;
|
||||
u32 symbol_rate; /* symbol rate in Symbols per second */
|
||||
fe_code_rate_t fec;
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t tone;
|
||||
u32 decode_freq;
|
||||
u8 decode_lock;
|
||||
u16 decode_strength;
|
||||
u16 decode_snr;
|
||||
unsigned long cur_jiff;
|
||||
u8 k22;
|
||||
fe_bandwidth_t bandwidth;
|
||||
u32 dst_hw_cap;
|
||||
u8 dst_fw_version;
|
||||
fe_sec_mini_cmd_t minicmd;
|
||||
fe_modulation_t modulation;
|
||||
u8 messages[256];
|
||||
u8 mac_address[8];
|
||||
u8 fw_version[8];
|
||||
u8 card_info[8];
|
||||
u8 vendor[8];
|
||||
u8 board_info[8];
|
||||
u32 tuner_type;
|
||||
char *tuner_name;
|
||||
struct mutex dst_mutex;
|
||||
u8 fw_name[8];
|
||||
struct dvb_device *dst_ca;
|
||||
};
|
||||
|
||||
struct tuner_types {
|
||||
u32 tuner_type;
|
||||
char *tuner_name;
|
||||
char *board_name;
|
||||
char *fw_name;
|
||||
};
|
||||
|
||||
struct dst_types {
|
||||
char *device_id;
|
||||
int offset;
|
||||
u8 dst_type;
|
||||
u32 type_flags;
|
||||
u32 dst_feature;
|
||||
u32 tuner_type;
|
||||
};
|
||||
|
||||
struct dst_config
|
||||
{
|
||||
/* the ASIC i2c address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
int rdc_reset_state(struct dst_state *state);
|
||||
int rdc_8820_reset(struct dst_state *state);
|
||||
|
||||
int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
|
||||
int dst_pio_enable(struct dst_state *state);
|
||||
int dst_pio_disable(struct dst_state *state);
|
||||
int dst_error_recovery(struct dst_state* state);
|
||||
int dst_error_bailout(struct dst_state *state);
|
||||
int dst_comm_init(struct dst_state* state);
|
||||
|
||||
int write_dst(struct dst_state *state, u8 * data, u8 len);
|
||||
int read_dst(struct dst_state *state, u8 * ret, u8 len);
|
||||
u8 dst_check_sum(u8 * buf, u32 len);
|
||||
struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
|
||||
struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
|
||||
int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
|
||||
|
||||
int dst_command(struct dst_state* state, u8 * data, u8 len);
|
||||
|
||||
|
||||
#endif // DST_COMMON_H
|
||||
35
drivers/media/dvb/bt8xx/dst_priv.h
Normal file
35
drivers/media/dvb/bt8xx/dst_priv.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
|
||||
*
|
||||
* Copyright (C) 2003 Jamie Honan
|
||||
*/
|
||||
|
||||
struct dst_gpio_enable {
|
||||
u32 mask;
|
||||
u32 enable;
|
||||
};
|
||||
|
||||
struct dst_gpio_output {
|
||||
u32 mask;
|
||||
u32 highvals;
|
||||
};
|
||||
|
||||
struct dst_gpio_read {
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
union dst_gpio_packet {
|
||||
struct dst_gpio_enable enb;
|
||||
struct dst_gpio_output outp;
|
||||
struct dst_gpio_read rd;
|
||||
int psize;
|
||||
};
|
||||
|
||||
#define DST_IG_ENABLE 0
|
||||
#define DST_IG_WRITE 1
|
||||
#define DST_IG_READ 2
|
||||
#define DST_IG_TS 3
|
||||
|
||||
struct bt878;
|
||||
|
||||
int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
|
||||
960
drivers/media/dvb/bt8xx/dvb-bt8xx.c
Normal file
960
drivers/media/dvb/bt8xx/dvb-bt8xx.c
Normal file
@@ -0,0 +1,960 @@
|
||||
/*
|
||||
* Bt8xx based DVB adapter driver
|
||||
*
|
||||
* Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb-bt8xx.h"
|
||||
#include "bt878.h"
|
||||
|
||||
static int debug;
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
#define dprintk( args... ) \
|
||||
do \
|
||||
if (debug) printk(KERN_DEBUG args); \
|
||||
while (0)
|
||||
|
||||
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
|
||||
|
||||
static void dvb_bt8xx_task(unsigned long data)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
|
||||
|
||||
//printk("%d ", card->bt->finished_block);
|
||||
|
||||
while (card->bt->last_block != card->bt->finished_block) {
|
||||
(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
|
||||
(&card->demux,
|
||||
&card->bt->buf_cpu[card->bt->last_block *
|
||||
card->bt->block_bytes],
|
||||
card->bt->block_bytes);
|
||||
card->bt->last_block = (card->bt->last_block + 1) %
|
||||
card->bt->block_count;
|
||||
}
|
||||
}
|
||||
|
||||
static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
|
||||
struct dvb_bt8xx_card *card = dvbdmx->priv;
|
||||
int rc;
|
||||
|
||||
dprintk("dvb_bt8xx: start_feed\n");
|
||||
|
||||
if (!dvbdmx->dmx.frontend)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&card->lock);
|
||||
card->nfeeds++;
|
||||
rc = card->nfeeds;
|
||||
if (card->nfeeds == 1)
|
||||
bt878_start(card->bt, card->gpio_mode,
|
||||
card->op_sync_orin, card->irq_err_ignore);
|
||||
mutex_unlock(&card->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
|
||||
struct dvb_bt8xx_card *card = dvbdmx->priv;
|
||||
|
||||
dprintk("dvb_bt8xx: stop_feed\n");
|
||||
|
||||
if (!dvbdmx->dmx.frontend)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&card->lock);
|
||||
card->nfeeds--;
|
||||
if (card->nfeeds == 0)
|
||||
bt878_stop(card->bt);
|
||||
mutex_unlock(&card->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
|
||||
{
|
||||
if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
|
||||
(adev->subsystem_device == bdev->subsystem_device) &&
|
||||
(adev->bus->number == bdev->bus->number) &&
|
||||
(PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
|
||||
{
|
||||
unsigned int card_nr;
|
||||
|
||||
/* Hmm, n squared. Hope n is small */
|
||||
for (card_nr = 0; card_nr < bt878_num; card_nr++)
|
||||
if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
|
||||
return &bt878[card_nr];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
|
||||
static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
|
||||
mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
|
||||
{
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
unsigned char cp = 0;
|
||||
|
||||
if (buf_len < 5)
|
||||
return -EINVAL;
|
||||
|
||||
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
if (params->frequency < 542000000)
|
||||
cp = 0xb4;
|
||||
else if (params->frequency < 771000000)
|
||||
cp = 0xbc;
|
||||
else
|
||||
cp = 0xf4;
|
||||
|
||||
if (params->frequency == 0)
|
||||
bs = 0x03;
|
||||
else if (params->frequency < 443250000)
|
||||
bs = 0x02;
|
||||
else
|
||||
bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0x60;
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = cp;
|
||||
pllbuf[4] = bs;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static struct mt352_config thomson_dtt7579_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = thomson_dtt7579_demod_init,
|
||||
};
|
||||
|
||||
static struct zl10353_config thomson_dtt7579_zl10353_config = {
|
||||
.demod_address = 0x0f,
|
||||
};
|
||||
|
||||
static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
|
||||
{
|
||||
u32 freq = params->frequency;
|
||||
|
||||
int i, a, n, pump;
|
||||
u32 band, pll;
|
||||
|
||||
u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
|
||||
1576000,1718000,1856000,2036000,2150000};
|
||||
u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
|
||||
0x00102000,0x00104000,0x00108000,0x00110000,
|
||||
0x00120000,0x00140000};
|
||||
|
||||
#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
|
||||
printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
|
||||
|
||||
/* This is really the bit driving the tuner chip cx24108 */
|
||||
|
||||
if (freq<950000)
|
||||
freq = 950000; /* kHz */
|
||||
else if (freq>2150000)
|
||||
freq = 2150000; /* satellite IF is 950..2150MHz */
|
||||
|
||||
/* decide which VCO to use for the input frequency */
|
||||
for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
|
||||
printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
|
||||
band=bandsel[i];
|
||||
/* the gain values must be set by SetSymbolrate */
|
||||
/* compute the pll divider needed, from Conexant data sheet,
|
||||
resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
|
||||
depending on the divider bit. It is set to /4 on the 2 lowest
|
||||
bands */
|
||||
n=((i<=2?2:1)*freq*10L)/(XTAL/100);
|
||||
a=n%32; n/=32; if(a==0) n--;
|
||||
pump=(freq<(osci[i-1]+osci[i])/2);
|
||||
pll=0xf8000000|
|
||||
((pump?1:2)<<(14+11))|
|
||||
((n&0x1ff)<<(5+11))|
|
||||
((a&0x1f)<<11);
|
||||
/* everything is shifted left 11 bits to left-align the bits in the
|
||||
32bit word. Output to the tuner goes MSB-aligned, after all */
|
||||
printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
|
||||
cx24110_pll_write(fe,band);
|
||||
/* set vga and vca to their widest-band settings, as a precaution.
|
||||
SetSymbolrate might not be called to set this up */
|
||||
cx24110_pll_write(fe,0x500c0000);
|
||||
cx24110_pll_write(fe,0x83f1f800);
|
||||
cx24110_pll_write(fe,pll);
|
||||
//writereg(client,0x56,0x7f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pinnsat_tuner_init(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = fe->dvb->priv;
|
||||
|
||||
bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */
|
||||
bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = fe->dvb->priv;
|
||||
|
||||
bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cx24110_config pctvsat_config = {
|
||||
.demod_address = 0x55,
|
||||
};
|
||||
|
||||
static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
|
||||
u8 cfg, cpump, band_select;
|
||||
u8 data[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
|
||||
|
||||
div = (36000000 + params->frequency + 83333) / 166666;
|
||||
cfg = 0x88;
|
||||
|
||||
if (params->frequency < 175000000)
|
||||
cpump = 2;
|
||||
else if (params->frequency < 390000000)
|
||||
cpump = 1;
|
||||
else if (params->frequency < 470000000)
|
||||
cpump = 2;
|
||||
else if (params->frequency < 750000000)
|
||||
cpump = 2;
|
||||
else
|
||||
cpump = 3;
|
||||
|
||||
if (params->frequency < 175000000)
|
||||
band_select = 0x0e;
|
||||
else if (params->frequency < 470000000)
|
||||
band_select = 0x05;
|
||||
else
|
||||
band_select = 0x03;
|
||||
|
||||
data[0] = (div >> 8) & 0x7f;
|
||||
data[1] = div & 0xff;
|
||||
data[2] = ((div >> 10) & 0x60) | cfg;
|
||||
data[3] = (cpump << 6) | band_select;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(card->i2c_adapter, &msg, 1);
|
||||
return (div * 166666 - 36000000);
|
||||
}
|
||||
|
||||
static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
|
||||
{
|
||||
struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
|
||||
|
||||
return request_firmware(fw, name, &bt->bt->dev->dev);
|
||||
}
|
||||
|
||||
static struct sp887x_config microtune_mt7202dtf_config = {
|
||||
.demod_address = 0x70,
|
||||
.request_firmware = microtune_mt7202dtf_request_firmware,
|
||||
};
|
||||
|
||||
static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0x40, 0x40 };
|
||||
static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
|
||||
{
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
unsigned char cp = 0;
|
||||
|
||||
if (buf_len < 5) return -EINVAL;
|
||||
|
||||
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
if (params->frequency < 150000000)
|
||||
cp = 0xB4;
|
||||
else if (params->frequency < 173000000)
|
||||
cp = 0xBC;
|
||||
else if (params->frequency < 250000000)
|
||||
cp = 0xB4;
|
||||
else if (params->frequency < 400000000)
|
||||
cp = 0xBC;
|
||||
else if (params->frequency < 420000000)
|
||||
cp = 0xF4;
|
||||
else if (params->frequency < 470000000)
|
||||
cp = 0xFC;
|
||||
else if (params->frequency < 600000000)
|
||||
cp = 0xBC;
|
||||
else if (params->frequency < 730000000)
|
||||
cp = 0xF4;
|
||||
else
|
||||
cp = 0xFC;
|
||||
|
||||
if (params->frequency < 150000000)
|
||||
bs = 0x01;
|
||||
else if (params->frequency < 173000000)
|
||||
bs = 0x01;
|
||||
else if (params->frequency < 250000000)
|
||||
bs = 0x02;
|
||||
else if (params->frequency < 400000000)
|
||||
bs = 0x02;
|
||||
else if (params->frequency < 420000000)
|
||||
bs = 0x02;
|
||||
else if (params->frequency < 470000000)
|
||||
bs = 0x02;
|
||||
else if (params->frequency < 600000000)
|
||||
bs = 0x08;
|
||||
else if (params->frequency < 730000000)
|
||||
bs = 0x08;
|
||||
else
|
||||
bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0x61;
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = cp;
|
||||
pllbuf[4] = bs;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
|
||||
};
|
||||
|
||||
static struct dst_config dst_config = {
|
||||
.demod_address = 0x55,
|
||||
};
|
||||
|
||||
static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
|
||||
{
|
||||
struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
|
||||
|
||||
return request_firmware(fw, name, &bt->bt->dev->dev);
|
||||
}
|
||||
|
||||
static void or51211_setmode(struct dvb_frontend * fe, int mode)
|
||||
{
|
||||
struct dvb_bt8xx_card *bt = fe->dvb->priv;
|
||||
bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void or51211_reset(struct dvb_frontend * fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *bt = fe->dvb->priv;
|
||||
|
||||
/* RESET DEVICE
|
||||
* reset is controled by GPIO-0
|
||||
* when set to 0 causes reset and when to 1 for normal op
|
||||
* must remain reset for 128 clock cycles on a 50Mhz clock
|
||||
* also PRM1 PRM2 & PRM4 are controled by GPIO-1,GPIO-2 & GPIO-4
|
||||
* We assume that the reset has be held low long enough or we
|
||||
* have been reset by a power on. When the driver is unloaded
|
||||
* reset set to 0 so if reloaded we have been reset.
|
||||
*/
|
||||
/* reset & PRM1,2&4 are outputs */
|
||||
int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret);
|
||||
bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */
|
||||
msleep(20);
|
||||
/* Now set for normal operation */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
|
||||
/* wait for operation to begin */
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
static void or51211_sleep(struct dvb_frontend * fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *bt = fe->dvb->priv;
|
||||
bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
|
||||
}
|
||||
|
||||
static struct or51211_config or51211_config = {
|
||||
.demod_address = 0x15,
|
||||
.request_firmware = or51211_request_firmware,
|
||||
.setmode = or51211_setmode,
|
||||
.reset = or51211_reset,
|
||||
.sleep = or51211_sleep,
|
||||
};
|
||||
|
||||
static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
|
||||
div = (params->frequency + 36166667) / 166667;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7F;
|
||||
buf[1] = div & 0xFF;
|
||||
buf[2] = 0x85;
|
||||
if ((params->frequency >= 47000000) && (params->frequency < 153000000))
|
||||
buf[3] = 0x01;
|
||||
else if ((params->frequency >= 153000000) && (params->frequency < 430000000))
|
||||
buf[3] = 0x02;
|
||||
else if ((params->frequency >= 430000000) && (params->frequency < 824000000))
|
||||
buf[3] = 0x0C;
|
||||
else if ((params->frequency >= 824000000) && (params->frequency < 863000000))
|
||||
buf[3] = 0x8C;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(card->i2c_adapter, &msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nxt6000_config vp3021_alps_tded4_config = {
|
||||
.demod_address = 0x0a,
|
||||
.clock_inversion = 1,
|
||||
};
|
||||
|
||||
static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
|
||||
{
|
||||
u32 div;
|
||||
struct dvb_ofdm_parameters *op = ¶ms->u.ofdm;
|
||||
|
||||
if (buf_len < 5)
|
||||
return -EINVAL;
|
||||
|
||||
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
pllbuf[0] = 0x61;
|
||||
pllbuf[1] = (div >> 8) & 0x7F;
|
||||
pllbuf[2] = div & 0xFF;
|
||||
pllbuf[3] = 0x85;
|
||||
|
||||
dprintk("frequency %u, div %u\n", params->frequency, div);
|
||||
|
||||
if (params->frequency < 470000000)
|
||||
pllbuf[4] = 0x02;
|
||||
else if (params->frequency > 823000000)
|
||||
pllbuf[4] = 0x88;
|
||||
else
|
||||
pllbuf[4] = 0x08;
|
||||
|
||||
if (op->bandwidth == 8)
|
||||
pllbuf[4] |= 0x04;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
|
||||
{
|
||||
/*
|
||||
* Reset the frontend, must be called before trying
|
||||
* to initialise the MT352 or mt352_attach
|
||||
* will fail. Same goes for the nxt6000 frontend.
|
||||
*
|
||||
*/
|
||||
|
||||
int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret);
|
||||
|
||||
/* Pulse the reset line */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */
|
||||
msleep(100);
|
||||
|
||||
bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
|
||||
}
|
||||
|
||||
static struct mt352_config digitv_alps_tded4_config = {
|
||||
.demod_address = 0x0a,
|
||||
.demod_init = digitv_alps_tded4_demod_init,
|
||||
};
|
||||
|
||||
static struct lgdt330x_config tdvs_tua6034_config = {
|
||||
.demod_address = 0x0e,
|
||||
.demod_chip = LGDT3303,
|
||||
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
|
||||
};
|
||||
|
||||
static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
|
||||
{
|
||||
/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
|
||||
|
||||
/* Pulse the reset line */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */
|
||||
msleep(100);
|
||||
|
||||
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
|
||||
{
|
||||
struct dst_state* state = NULL;
|
||||
|
||||
switch(type) {
|
||||
case BTTV_BOARD_DVICO_DVBT_LITE:
|
||||
card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
|
||||
|
||||
if (card->fe == NULL)
|
||||
card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
|
||||
card->i2c_adapter);
|
||||
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
|
||||
card->fe->ops.info.frequency_min = 174000000;
|
||||
card->fe->ops.info.frequency_max = 862000000;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
|
||||
lgdt330x_reset(card);
|
||||
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter);
|
||||
dprintk ("dvb_bt8xx: lgdt330x detected\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_NEBULA_DIGITV:
|
||||
/*
|
||||
* It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
|
||||
* this would be a cleaner solution than trying each frontend in turn.
|
||||
*/
|
||||
|
||||
/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
|
||||
digitv_alps_tded4_reset(card);
|
||||
card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
|
||||
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
|
||||
digitv_alps_tded4_reset(card);
|
||||
card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
|
||||
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
|
||||
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_AVDVBT_761:
|
||||
card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter);
|
||||
if (card->fe) {
|
||||
card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_AVDVBT_771:
|
||||
card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
|
||||
card->fe->ops.info.frequency_min = 174000000;
|
||||
card->fe->ops.info.frequency_max = 862000000;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_TWINHAN_DST:
|
||||
/* DST is not a frontend driver !!! */
|
||||
state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
|
||||
if (!state) {
|
||||
printk("dvb_bt8xx: No memory\n");
|
||||
break;
|
||||
}
|
||||
/* Setup the Card */
|
||||
state->config = &dst_config;
|
||||
state->i2c = card->i2c_adapter;
|
||||
state->bt = card->bt;
|
||||
state->dst_ca = NULL;
|
||||
/* DST is not a frontend, attaching the ASIC */
|
||||
if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
|
||||
printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
/* Attach other DST peripherals if any */
|
||||
/* Conditional Access device */
|
||||
card->fe = &state->frontend;
|
||||
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
|
||||
dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PINNACLESAT:
|
||||
card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
|
||||
if (card->fe) {
|
||||
card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
|
||||
card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
|
||||
card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PC_HDTV:
|
||||
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
|
||||
break;
|
||||
}
|
||||
|
||||
if (card->fe == NULL)
|
||||
printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
|
||||
card->bt->dev->vendor,
|
||||
card->bt->dev->device,
|
||||
card->bt->dev->subsystem_vendor,
|
||||
card->bt->dev->subsystem_device);
|
||||
else
|
||||
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
|
||||
printk("dvb-bt8xx: Frontend registration failed!\n");
|
||||
dvb_frontend_detach(card->fe);
|
||||
card->fe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
|
||||
printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
|
||||
return result;
|
||||
}
|
||||
card->dvb_adapter.priv = card;
|
||||
|
||||
card->bt->adapter = card->i2c_adapter;
|
||||
|
||||
memset(&card->demux, 0, sizeof(struct dvb_demux));
|
||||
|
||||
card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
|
||||
|
||||
card->demux.priv = card;
|
||||
card->demux.filternum = 256;
|
||||
card->demux.feednum = 256;
|
||||
card->demux.start_feed = dvb_bt8xx_start_feed;
|
||||
card->demux.stop_feed = dvb_bt8xx_stop_feed;
|
||||
card->demux.write_to_decoder = NULL;
|
||||
|
||||
if ((result = dvb_dmx_init(&card->demux)) < 0) {
|
||||
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
|
||||
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
return result;
|
||||
}
|
||||
|
||||
card->dmxdev.filternum = 256;
|
||||
card->dmxdev.demux = &card->demux.dmx;
|
||||
card->dmxdev.capabilities = 0;
|
||||
|
||||
if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) {
|
||||
printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result);
|
||||
|
||||
dvb_dmx_release(&card->demux);
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
return result;
|
||||
}
|
||||
|
||||
card->fe_hw.source = DMX_FRONTEND_0;
|
||||
|
||||
if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
|
||||
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
|
||||
|
||||
dvb_dmxdev_release(&card->dmxdev);
|
||||
dvb_dmx_release(&card->demux);
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
return result;
|
||||
}
|
||||
|
||||
card->fe_mem.source = DMX_MEMORY_FE;
|
||||
|
||||
if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) {
|
||||
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
|
||||
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
dvb_dmxdev_release(&card->dmxdev);
|
||||
dvb_dmx_release(&card->demux);
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
|
||||
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
|
||||
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
dvb_dmxdev_release(&card->dmxdev);
|
||||
dvb_dmx_release(&card->demux);
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
return result;
|
||||
}
|
||||
|
||||
dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
|
||||
|
||||
tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
|
||||
|
||||
frontend_init(card, type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
|
||||
{
|
||||
struct dvb_bt8xx_card *card;
|
||||
struct pci_dev* bttv_pci_dev;
|
||||
int ret;
|
||||
|
||||
if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&card->lock);
|
||||
card->bttv_nr = sub->core->nr;
|
||||
strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
|
||||
card->i2c_adapter = &sub->core->i2c_adap;
|
||||
|
||||
switch(sub->core->type) {
|
||||
case BTTV_BOARD_PINNACLESAT:
|
||||
card->gpio_mode = 0x0400c060;
|
||||
/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
|
||||
BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_DVICO_DVBT_LITE:
|
||||
card->gpio_mode = 0x0400C060;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
/* 26, 15, 14, 6, 5
|
||||
* A_PWRDN DA_DPM DA_SBR DA_IOM_DA
|
||||
* DA_APP(parallel) */
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
|
||||
card->gpio_mode = 0x0400c060;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_NEBULA_DIGITV:
|
||||
case BTTV_BOARD_AVDVBT_761:
|
||||
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
/* A_PWRDN DA_SBR DA_APP (high speed serial) */
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
|
||||
card->gpio_mode = 0x0400402B;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
/* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_TWINHAN_DST:
|
||||
card->gpio_mode = 0x2204f2c;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
|
||||
BT878_APPERR | BT878_AFBUS;
|
||||
/* 25,21,14,11,10,9,8,3,2 then
|
||||
* 0x33 = 5,4,1,0
|
||||
* A_SEL=SML, DA_MLB, DA_SBR,
|
||||
* DA_SDR=f, fifo trigger = 32 DWORDS
|
||||
* IOM = 0 == audio A/D
|
||||
* DPM = 0 == digital audio mode
|
||||
* == async data parallel port
|
||||
* then 0x33 (13 is set by start_capture)
|
||||
* DA_APP = async data parallel port,
|
||||
* ACAP_EN = 1,
|
||||
* RISC+FIFO ENABLE */
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PC_HDTV:
|
||||
card->gpio_mode = 0x0100EC7B;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
|
||||
sub->core->type);
|
||||
kfree(card);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
|
||||
|
||||
if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
|
||||
printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
|
||||
kfree(card);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
|
||||
printk("dvb_bt8xx: unable to determine DMA core of card %d,\n",
|
||||
card->bttv_nr);
|
||||
printk("dvb_bt8xx: if you have the ALSA bt87x audio driver "
|
||||
"installed, try removing it.\n");
|
||||
|
||||
kfree(card);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
mutex_init(&card->bt->gpio_lock);
|
||||
card->bt->bttv_nr = sub->core->nr;
|
||||
|
||||
if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
|
||||
kfree(card);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&sub->dev, card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
|
||||
|
||||
dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
|
||||
|
||||
bt878_stop(card->bt);
|
||||
tasklet_kill(&card->bt->tasklet);
|
||||
dvb_net_release(&card->dvbnet);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
dvb_dmxdev_release(&card->dmxdev);
|
||||
dvb_dmx_release(&card->demux);
|
||||
if (card->fe) {
|
||||
dvb_unregister_frontend(card->fe);
|
||||
dvb_frontend_detach(card->fe);
|
||||
}
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
static struct bttv_sub_driver driver = {
|
||||
.drv = {
|
||||
.name = "dvb-bt8xx",
|
||||
},
|
||||
.probe = dvb_bt8xx_probe,
|
||||
.remove = dvb_bt8xx_remove,
|
||||
/* FIXME:
|
||||
* .shutdown = dvb_bt8xx_shutdown,
|
||||
* .suspend = dvb_bt8xx_suspend,
|
||||
* .resume = dvb_bt8xx_resume,
|
||||
*/
|
||||
};
|
||||
|
||||
static int __init dvb_bt8xx_init(void)
|
||||
{
|
||||
return bttv_sub_register(&driver, "dvb");
|
||||
}
|
||||
|
||||
static void __exit dvb_bt8xx_exit(void)
|
||||
{
|
||||
bttv_sub_unregister(&driver);
|
||||
}
|
||||
|
||||
module_init(dvb_bt8xx_init);
|
||||
module_exit(dvb_bt8xx_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
|
||||
MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
63
drivers/media/dvb/bt8xx/dvb-bt8xx.h
Normal file
63
drivers/media/dvb/bt8xx/dvb-bt8xx.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Bt8xx based DVB adapter driver
|
||||
*
|
||||
* Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
|
||||
* Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
|
||||
* Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH
|
||||
* Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DVB_BT8XX_H
|
||||
#define DVB_BT8XX_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_net.h"
|
||||
#include "bttv.h"
|
||||
#include "mt352.h"
|
||||
#include "sp887x.h"
|
||||
#include "dst_common.h"
|
||||
#include "nxt6000.h"
|
||||
#include "cx24110.h"
|
||||
#include "or51211.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "zl10353.h"
|
||||
|
||||
struct dvb_bt8xx_card {
|
||||
struct mutex lock;
|
||||
int nfeeds;
|
||||
char card_name[32];
|
||||
struct dvb_adapter dvb_adapter;
|
||||
struct bt878 *bt;
|
||||
unsigned int bttv_nr;
|
||||
struct dvb_demux demux;
|
||||
struct dmxdev dmxdev;
|
||||
struct dmx_frontend fe_hw;
|
||||
struct dmx_frontend fe_mem;
|
||||
u32 gpio_mode;
|
||||
u32 op_sync_orin;
|
||||
u32 irq_err_ignore;
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
struct dvb_net dvbnet;
|
||||
|
||||
struct dvb_frontend* fe;
|
||||
};
|
||||
|
||||
#endif /* DVB_BT8XX_H */
|
||||
85
drivers/media/dvb/cinergyT2/Kconfig
Normal file
85
drivers/media/dvb/cinergyT2/Kconfig
Normal file
@@ -0,0 +1,85 @@
|
||||
config DVB_CINERGYT2
|
||||
tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
|
||||
depends on DVB_CORE && USB
|
||||
help
|
||||
Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_TUNING
|
||||
bool "sophisticated fine-tuning for CinergyT2 cards"
|
||||
depends on DVB_CINERGYT2
|
||||
help
|
||||
Here you can fine-tune some parameters of the CinergyT2 driver.
|
||||
|
||||
Normally you don't need to touch this, but in exotic setups you
|
||||
may fine-tune your setup and adjust e.g. DMA buffer sizes for
|
||||
a particular application.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_STREAM_URB_COUNT
|
||||
int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default "32"
|
||||
help
|
||||
USB Request Blocks for Highspeed Stream transfers are scheduled in
|
||||
a queue for the Host Controller.
|
||||
|
||||
Usually the default value is a safe choice.
|
||||
|
||||
You may increase this number if you are using this device in a
|
||||
Server Environment with many high-traffic USB Highspeed devices
|
||||
sharing the same USB bus.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_STREAM_BUF_SIZE
|
||||
int "Size of URB Stream Buffers for Highspeed Transfers"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default "512"
|
||||
help
|
||||
Should be a multiple of native buffer size of 512 bytes.
|
||||
Default value is a safe choice.
|
||||
|
||||
You may increase this number if you are using this device in a
|
||||
Server Environment with many high-traffic USB Highspeed devices
|
||||
sharing the same USB bus.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_QUERY_INTERVAL
|
||||
int "Status update interval [milliseconds]"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default "250"
|
||||
help
|
||||
This is the interval for status readouts from the demodulator.
|
||||
You may try lower values if you need more responsive signal quality
|
||||
measurements.
|
||||
|
||||
Please keep in mind that these updates cause traffic on the tuner
|
||||
control bus and thus may or may not affect reception sensitivity.
|
||||
|
||||
The default value should be a safe choice for common applications.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
|
||||
bool "Register the onboard IR Remote Control Receiver as Input Device"
|
||||
depends on DVB_CINERGYT2_TUNING
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the onboard Infrared Remote
|
||||
Control Receiver as Linux-Input device.
|
||||
|
||||
Right now only the keycode table for the default Remote Control
|
||||
delivered with the device is supported, please see the driver
|
||||
source code to find out how to add support for other controls.
|
||||
|
||||
|
||||
config DVB_CINERGYT2_RC_QUERY_INTERVAL
|
||||
int "Infrared Remote Controller update interval [milliseconds]"
|
||||
depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
|
||||
default "50"
|
||||
help
|
||||
If you have a very fast-repeating remote control you can try lower
|
||||
values, for normal consumer receivers the default value should be
|
||||
a safe choice.
|
||||
|
||||
3
drivers/media/dvb/cinergyT2/Makefile
Normal file
3
drivers/media/dvb/cinergyT2/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
|
||||
|
||||
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
|
||||
1071
drivers/media/dvb/cinergyT2/cinergyT2.c
Normal file
1071
drivers/media/dvb/cinergyT2/cinergyT2.c
Normal file
File diff suppressed because it is too large
Load Diff
24
drivers/media/dvb/dvb-core/Kconfig
Normal file
24
drivers/media/dvb/dvb-core/Kconfig
Normal file
@@ -0,0 +1,24 @@
|
||||
config DVB_CORE
|
||||
tristate "DVB Core Support"
|
||||
depends on DVB
|
||||
select CRC32
|
||||
help
|
||||
DVB core utility functions for device handling, software fallbacks etc.
|
||||
Say Y when you have a DVB card and want to use it. Say Y if your want
|
||||
to build your drivers outside the kernel, but need the DVB core. All
|
||||
in-kernel drivers will select this automatically if needed.
|
||||
If unsure say N.
|
||||
|
||||
config DVB_CORE_ATTACH
|
||||
bool "Load and attach frontend modules as needed"
|
||||
depends on DVB_CORE
|
||||
depends on MODULES
|
||||
help
|
||||
Remove the static dependency of DVB card drivers on all
|
||||
frontend modules for all possible card variants. Instead,
|
||||
allow the card drivers to only load the frontend modules
|
||||
they require. This saves several KBytes of memory.
|
||||
|
||||
Note: You will need module-init-tools v3.2 or later for this feature.
|
||||
|
||||
If unsure say Y.
|
||||
9
drivers/media/dvb/dvb-core/Makefile
Normal file
9
drivers/media/dvb/dvb-core/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for the kernel DVB device drivers.
|
||||
#
|
||||
|
||||
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
|
||||
dvb_ca_en50221.o dvb_frontend.o \
|
||||
dvb_net.o dvb_ringbuffer.o dvb_math.o
|
||||
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core.o
|
||||
278
drivers/media/dvb/dvb-core/demux.h
Normal file
278
drivers/media/dvb/dvb-core/demux.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* demux.h
|
||||
*
|
||||
* Copyright (c) 2002 Convergence GmbH
|
||||
*
|
||||
* based on code:
|
||||
* Copyright (c) 2000 Nokia Research Center
|
||||
* Tampere, FINLAND
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEMUX_H
|
||||
#define __DEMUX_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Common definitions */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
|
||||
*/
|
||||
|
||||
#ifndef DMX_MAX_FILTER_SIZE
|
||||
#define DMX_MAX_FILTER_SIZE 18
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
|
||||
*/
|
||||
|
||||
#ifndef DMX_MAX_SECTION_SIZE
|
||||
#define DMX_MAX_SECTION_SIZE 4096
|
||||
#endif
|
||||
#ifndef DMX_MAX_SECFEED_SIZE
|
||||
#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* enum dmx_success: Success codes for the Demux Callback API.
|
||||
*/
|
||||
|
||||
enum dmx_success {
|
||||
DMX_OK = 0, /* Received Ok */
|
||||
DMX_LENGTH_ERROR, /* Incorrect length */
|
||||
DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
|
||||
DMX_CRC_ERROR, /* Incorrect CRC */
|
||||
DMX_FRAME_ERROR, /* Frame alignment error */
|
||||
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
|
||||
DMX_MISSED_ERROR /* Receiver missed packet */
|
||||
} ;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* TS packet reception */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/* TS filter type for set() */
|
||||
|
||||
#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */
|
||||
#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS
|
||||
payload (<=184 bytes per packet) to callback */
|
||||
#define TS_DECODER 4 /* send stream to built-in decoder (if present) */
|
||||
|
||||
/* PES type for filters which write to built-in decoder */
|
||||
/* these should be kept identical to the types in dmx.h */
|
||||
|
||||
enum dmx_ts_pes
|
||||
{ /* also send packets to decoder (if it exists) */
|
||||
DMX_TS_PES_AUDIO0,
|
||||
DMX_TS_PES_VIDEO0,
|
||||
DMX_TS_PES_TELETEXT0,
|
||||
DMX_TS_PES_SUBTITLE0,
|
||||
DMX_TS_PES_PCR0,
|
||||
|
||||
DMX_TS_PES_AUDIO1,
|
||||
DMX_TS_PES_VIDEO1,
|
||||
DMX_TS_PES_TELETEXT1,
|
||||
DMX_TS_PES_SUBTITLE1,
|
||||
DMX_TS_PES_PCR1,
|
||||
|
||||
DMX_TS_PES_AUDIO2,
|
||||
DMX_TS_PES_VIDEO2,
|
||||
DMX_TS_PES_TELETEXT2,
|
||||
DMX_TS_PES_SUBTITLE2,
|
||||
DMX_TS_PES_PCR2,
|
||||
|
||||
DMX_TS_PES_AUDIO3,
|
||||
DMX_TS_PES_VIDEO3,
|
||||
DMX_TS_PES_TELETEXT3,
|
||||
DMX_TS_PES_SUBTITLE3,
|
||||
DMX_TS_PES_PCR3,
|
||||
|
||||
DMX_TS_PES_OTHER
|
||||
};
|
||||
|
||||
#define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0
|
||||
#define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0
|
||||
#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0
|
||||
#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
|
||||
#define DMX_TS_PES_PCR DMX_TS_PES_PCR0
|
||||
|
||||
|
||||
struct dmx_ts_feed {
|
||||
int is_filtering; /* Set to non-zero when filtering in progress */
|
||||
struct dmx_demux *parent; /* Back-pointer */
|
||||
void *priv; /* Pointer to private data of the API client */
|
||||
int (*set) (struct dmx_ts_feed *feed,
|
||||
u16 pid,
|
||||
int type,
|
||||
enum dmx_ts_pes pes_type,
|
||||
size_t circular_buffer_size,
|
||||
struct timespec timeout);
|
||||
int (*start_filtering) (struct dmx_ts_feed* feed);
|
||||
int (*stop_filtering) (struct dmx_ts_feed* feed);
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Section reception */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
struct dmx_section_filter {
|
||||
u8 filter_value [DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mask [DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mode [DMX_MAX_FILTER_SIZE];
|
||||
struct dmx_section_feed* parent; /* Back-pointer */
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
};
|
||||
|
||||
struct dmx_section_feed {
|
||||
int is_filtering; /* Set to non-zero when filtering in progress */
|
||||
struct dmx_demux* parent; /* Back-pointer */
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
|
||||
int check_crc;
|
||||
u32 crc_val;
|
||||
|
||||
u8 *secbuf;
|
||||
u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
|
||||
u16 secbufp, seclen, tsfeedp;
|
||||
|
||||
int (*set) (struct dmx_section_feed* feed,
|
||||
u16 pid,
|
||||
size_t circular_buffer_size,
|
||||
int check_crc);
|
||||
int (*allocate_filter) (struct dmx_section_feed* feed,
|
||||
struct dmx_section_filter** filter);
|
||||
int (*release_filter) (struct dmx_section_feed* feed,
|
||||
struct dmx_section_filter* filter);
|
||||
int (*start_filtering) (struct dmx_section_feed* feed);
|
||||
int (*stop_filtering) (struct dmx_section_feed* feed);
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Callback functions */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
typedef int (*dmx_ts_cb) ( const u8 * buffer1,
|
||||
size_t buffer1_length,
|
||||
const u8 * buffer2,
|
||||
size_t buffer2_length,
|
||||
struct dmx_ts_feed* source,
|
||||
enum dmx_success success);
|
||||
|
||||
typedef int (*dmx_section_cb) ( const u8 * buffer1,
|
||||
size_t buffer1_len,
|
||||
const u8 * buffer2,
|
||||
size_t buffer2_len,
|
||||
struct dmx_section_filter * source,
|
||||
enum dmx_success success);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* DVB Front-End */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
enum dmx_frontend_source {
|
||||
DMX_MEMORY_FE,
|
||||
DMX_FRONTEND_0,
|
||||
DMX_FRONTEND_1,
|
||||
DMX_FRONTEND_2,
|
||||
DMX_FRONTEND_3,
|
||||
DMX_STREAM_0, /* external stream input, e.g. LVDS */
|
||||
DMX_STREAM_1,
|
||||
DMX_STREAM_2,
|
||||
DMX_STREAM_3
|
||||
};
|
||||
|
||||
struct dmx_frontend {
|
||||
struct list_head connectivity_list; /* List of front-ends that can
|
||||
be connected to a particular
|
||||
demux */
|
||||
enum dmx_frontend_source source;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* MPEG-2 TS Demux */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Flags OR'ed in the capabilities field of struct dmx_demux.
|
||||
*/
|
||||
|
||||
#define DMX_TS_FILTERING 1
|
||||
#define DMX_PES_FILTERING 2
|
||||
#define DMX_SECTION_FILTERING 4
|
||||
#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */
|
||||
#define DMX_CRC_CHECKING 16
|
||||
#define DMX_TS_DESCRAMBLING 32
|
||||
|
||||
/*
|
||||
* Demux resource type identifier.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DMX_FE_ENTRY(): Casts elements in the list of registered
|
||||
* front-ends from the generic type struct list_head
|
||||
* to the type * struct dmx_frontend
|
||||
*.
|
||||
*/
|
||||
|
||||
#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
|
||||
|
||||
struct dmx_demux {
|
||||
u32 capabilities; /* Bitfield of capability flags */
|
||||
struct dmx_frontend* frontend; /* Front-end connected to the demux */
|
||||
void* priv; /* Pointer to private data of the API client */
|
||||
int (*open) (struct dmx_demux* demux);
|
||||
int (*close) (struct dmx_demux* demux);
|
||||
int (*write) (struct dmx_demux* demux, const char* buf, size_t count);
|
||||
int (*allocate_ts_feed) (struct dmx_demux* demux,
|
||||
struct dmx_ts_feed** feed,
|
||||
dmx_ts_cb callback);
|
||||
int (*release_ts_feed) (struct dmx_demux* demux,
|
||||
struct dmx_ts_feed* feed);
|
||||
int (*allocate_section_feed) (struct dmx_demux* demux,
|
||||
struct dmx_section_feed** feed,
|
||||
dmx_section_cb callback);
|
||||
int (*release_section_feed) (struct dmx_demux* demux,
|
||||
struct dmx_section_feed* feed);
|
||||
int (*add_frontend) (struct dmx_demux* demux,
|
||||
struct dmx_frontend* frontend);
|
||||
int (*remove_frontend) (struct dmx_demux* demux,
|
||||
struct dmx_frontend* frontend);
|
||||
struct list_head* (*get_frontends) (struct dmx_demux* demux);
|
||||
int (*connect_frontend) (struct dmx_demux* demux,
|
||||
struct dmx_frontend* frontend);
|
||||
int (*disconnect_frontend) (struct dmx_demux* demux);
|
||||
|
||||
int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
|
||||
|
||||
int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
|
||||
|
||||
int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
|
||||
|
||||
int (*get_stc) (struct dmx_demux* demux, unsigned int num,
|
||||
u64 *stc, unsigned int *base);
|
||||
};
|
||||
|
||||
#endif /* #ifndef __DEMUX_H */
|
||||
1075
drivers/media/dvb/dvb-core/dmxdev.c
Normal file
1075
drivers/media/dvb/dvb-core/dmxdev.c
Normal file
File diff suppressed because it is too large
Load Diff
108
drivers/media/dvb/dvb-core/dmxdev.h
Normal file
108
drivers/media/dvb/dvb-core/dmxdev.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* dmxdev.h
|
||||
*
|
||||
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DMXDEV_H_
|
||||
#define _DMXDEV_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
#include "demux.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
|
||||
enum dmxdev_type {
|
||||
DMXDEV_TYPE_NONE,
|
||||
DMXDEV_TYPE_SEC,
|
||||
DMXDEV_TYPE_PES,
|
||||
};
|
||||
|
||||
enum dmxdev_state {
|
||||
DMXDEV_STATE_FREE,
|
||||
DMXDEV_STATE_ALLOCATED,
|
||||
DMXDEV_STATE_SET,
|
||||
DMXDEV_STATE_GO,
|
||||
DMXDEV_STATE_DONE,
|
||||
DMXDEV_STATE_TIMEDOUT
|
||||
};
|
||||
|
||||
struct dmxdev_filter {
|
||||
union {
|
||||
struct dmx_section_filter *sec;
|
||||
} filter;
|
||||
|
||||
union {
|
||||
struct dmx_ts_feed *ts;
|
||||
struct dmx_section_feed *sec;
|
||||
} feed;
|
||||
|
||||
union {
|
||||
struct dmx_sct_filter_params sec;
|
||||
struct dmx_pes_filter_params pes;
|
||||
} params;
|
||||
|
||||
enum dmxdev_type type;
|
||||
enum dmxdev_state state;
|
||||
struct dmxdev *dev;
|
||||
struct dvb_ringbuffer buffer;
|
||||
|
||||
struct mutex mutex;
|
||||
|
||||
/* only for sections */
|
||||
struct timer_list timer;
|
||||
int todo;
|
||||
u8 secheader[3];
|
||||
};
|
||||
|
||||
|
||||
struct dmxdev {
|
||||
struct dvb_device *dvbdev;
|
||||
struct dvb_device *dvr_dvbdev;
|
||||
|
||||
struct dmxdev_filter *filter;
|
||||
struct dmx_demux *demux;
|
||||
|
||||
int filternum;
|
||||
int capabilities;
|
||||
#define DMXDEV_CAP_DUPLEX 1
|
||||
struct dmx_frontend *dvr_orig_fe;
|
||||
|
||||
struct dvb_ringbuffer dvr_buffer;
|
||||
#define DVR_BUFFER_SIZE (10*188*1024)
|
||||
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
|
||||
void dvb_dmxdev_release(struct dmxdev *dmxdev);
|
||||
|
||||
#endif /* _DMXDEV_H_ */
|
||||
1771
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
Normal file
1771
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
Normal file
File diff suppressed because it is too large
Load Diff
134
drivers/media/dvb/dvb-core/dvb_ca_en50221.h
Normal file
134
drivers/media/dvb/dvb-core/dvb_ca_en50221.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* dvb_ca.h: generic DVB functions for EN50221 CA interfaces
|
||||
*
|
||||
* Copyright (C) 2004 Andrew de Quincey
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_CA_EN50221_H_
|
||||
#define _DVB_CA_EN50221_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
#define DVB_CA_EN50221_POLL_CAM_PRESENT 1
|
||||
#define DVB_CA_EN50221_POLL_CAM_CHANGED 2
|
||||
#define DVB_CA_EN50221_POLL_CAM_READY 4
|
||||
|
||||
#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1
|
||||
#define DVB_CA_EN50221_FLAG_IRQ_FR 2
|
||||
#define DVB_CA_EN50221_FLAG_IRQ_DA 4
|
||||
|
||||
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
|
||||
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
|
||||
|
||||
|
||||
|
||||
/* Structure describing a CA interface */
|
||||
struct dvb_ca_en50221 {
|
||||
|
||||
/* the module owning this structure */
|
||||
struct module* owner;
|
||||
|
||||
/* NOTE: the read_*, write_* and poll_slot_status functions must use locks as
|
||||
* they may be called from several threads at once */
|
||||
|
||||
/* functions for accessing attribute memory on the CAM */
|
||||
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
|
||||
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
|
||||
|
||||
/* functions for accessing the control interface on the CAM */
|
||||
int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
|
||||
int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
|
||||
|
||||
/* Functions for controlling slots */
|
||||
int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
|
||||
int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
|
||||
int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
|
||||
|
||||
/*
|
||||
* Poll slot status.
|
||||
* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
|
||||
*/
|
||||
int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
|
||||
|
||||
/* private data, used by caller */
|
||||
void* data;
|
||||
|
||||
/* Opaque data used by the dvb_ca core. Do not modify! */
|
||||
void* private;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* ******************************************************************************** */
|
||||
/* Functions for reporting IRQ events */
|
||||
|
||||
/**
|
||||
* A CAMCHANGE IRQ has occurred.
|
||||
*
|
||||
* @param ca CA instance.
|
||||
* @param slot Slot concerned.
|
||||
* @param change_type One of the DVB_CA_CAMCHANGE_* values
|
||||
*/
|
||||
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
|
||||
|
||||
/**
|
||||
* A CAMREADY IRQ has occurred.
|
||||
*
|
||||
* @param ca CA instance.
|
||||
* @param slot Slot concerned.
|
||||
*/
|
||||
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
|
||||
|
||||
/**
|
||||
* An FR or a DA IRQ has occurred.
|
||||
*
|
||||
* @param ca CA instance.
|
||||
* @param slot Slot concerned.
|
||||
*/
|
||||
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
|
||||
|
||||
|
||||
|
||||
/* ******************************************************************************** */
|
||||
/* Initialisation/shutdown functions */
|
||||
|
||||
/**
|
||||
* Initialise a new DVB CA device.
|
||||
*
|
||||
* @param dvb_adapter DVB adapter to attach the new CA device to.
|
||||
* @param ca The dvb_ca instance.
|
||||
* @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
|
||||
* @param slot_count Number of slots supported.
|
||||
*
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
|
||||
|
||||
/**
|
||||
* Release a DVB CA device.
|
||||
*
|
||||
* @param ca The associated dvb_ca instance.
|
||||
*/
|
||||
extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
1225
drivers/media/dvb/dvb-core/dvb_demux.c
Normal file
1225
drivers/media/dvb/dvb-core/dvb_demux.c
Normal file
File diff suppressed because it is too large
Load Diff
140
drivers/media/dvb/dvb-core/dvb_demux.h
Normal file
140
drivers/media/dvb/dvb-core/dvb_demux.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* dvb_demux.h: DVB kernel demux API
|
||||
*
|
||||
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_DEMUX_H_
|
||||
#define _DVB_DEMUX_H_
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "demux.h"
|
||||
|
||||
#define DMX_TYPE_TS 0
|
||||
#define DMX_TYPE_SEC 1
|
||||
#define DMX_TYPE_PES 2
|
||||
|
||||
#define DMX_STATE_FREE 0
|
||||
#define DMX_STATE_ALLOCATED 1
|
||||
#define DMX_STATE_SET 2
|
||||
#define DMX_STATE_READY 3
|
||||
#define DMX_STATE_GO 4
|
||||
|
||||
#define DVB_DEMUX_MASK_MAX 18
|
||||
|
||||
struct dvb_demux_filter {
|
||||
struct dmx_section_filter filter;
|
||||
u8 maskandmode[DMX_MAX_FILTER_SIZE];
|
||||
u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
|
||||
int doneq;
|
||||
|
||||
struct dvb_demux_filter *next;
|
||||
struct dvb_demux_feed *feed;
|
||||
int index;
|
||||
int state;
|
||||
int type;
|
||||
|
||||
u16 hw_handle;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
|
||||
|
||||
struct dvb_demux_feed {
|
||||
union {
|
||||
struct dmx_ts_feed ts;
|
||||
struct dmx_section_feed sec;
|
||||
} feed;
|
||||
|
||||
union {
|
||||
dmx_ts_cb ts;
|
||||
dmx_section_cb sec;
|
||||
} cb;
|
||||
|
||||
struct dvb_demux *demux;
|
||||
void *priv;
|
||||
int type;
|
||||
int state;
|
||||
u16 pid;
|
||||
u8 *buffer;
|
||||
int buffer_size;
|
||||
|
||||
struct timespec timeout;
|
||||
struct dvb_demux_filter *filter;
|
||||
|
||||
int ts_type;
|
||||
enum dmx_ts_pes pes_type;
|
||||
|
||||
int cc;
|
||||
int pusi_seen; /* prevents feeding of garbage from previous section */
|
||||
|
||||
u16 peslen;
|
||||
|
||||
struct list_head list_head;
|
||||
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
|
||||
};
|
||||
|
||||
struct dvb_demux {
|
||||
struct dmx_demux dmx;
|
||||
void *priv;
|
||||
int filternum;
|
||||
int feednum;
|
||||
int (*start_feed)(struct dvb_demux_feed *feed);
|
||||
int (*stop_feed)(struct dvb_demux_feed *feed);
|
||||
int (*write_to_decoder)(struct dvb_demux_feed *feed,
|
||||
const u8 *buf, size_t len);
|
||||
u32 (*check_crc32)(struct dvb_demux_feed *feed,
|
||||
const u8 *buf, size_t len);
|
||||
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
|
||||
const u8 *src, size_t len);
|
||||
|
||||
int users;
|
||||
#define MAX_DVB_DEMUX_USERS 10
|
||||
struct dvb_demux_filter *filter;
|
||||
struct dvb_demux_feed *feed;
|
||||
|
||||
struct list_head frontend_list;
|
||||
|
||||
struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
|
||||
u16 pids[DMX_TS_PES_OTHER];
|
||||
int playing;
|
||||
int recording;
|
||||
|
||||
#define DMX_MAX_PID 0x2000
|
||||
struct list_head feed_list;
|
||||
u8 tsbuf[204];
|
||||
int tsbufp;
|
||||
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
int dvb_dmx_init(struct dvb_demux *dvbdemux);
|
||||
void dvb_dmx_release(struct dvb_demux *dvbdemux);
|
||||
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
|
||||
size_t count);
|
||||
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
|
||||
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
|
||||
size_t count);
|
||||
|
||||
#endif /* _DVB_DEMUX_H_ */
|
||||
603
drivers/media/dvb/dvb-core/dvb_filter.c
Normal file
603
drivers/media/dvb/dvb-core/dvb_filter.c
Normal file
@@ -0,0 +1,603 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include "dvb_filter.h"
|
||||
|
||||
#if 0
|
||||
static unsigned int bitrates[3][16] =
|
||||
{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
|
||||
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
|
||||
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
|
||||
#endif
|
||||
|
||||
static u32 freq[4] = {480, 441, 320, 0};
|
||||
|
||||
static unsigned int ac3_bitrates[32] =
|
||||
{32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
static u32 ac3_frames[3][32] =
|
||||
{{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
|
||||
1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
|
||||
1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
|
||||
1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
|
||||
void (*pes_write)(u8 *buf, int count, void *data),
|
||||
void *priv)
|
||||
{
|
||||
dvb_filter_ipack_init(pa, IPACKS, pes_write);
|
||||
dvb_filter_ipack_init(pv, IPACKS, pes_write);
|
||||
pa->pid = pida;
|
||||
pv->pid = pidv;
|
||||
pa->data = priv;
|
||||
pv->data = priv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
|
||||
{
|
||||
u8 off = 0;
|
||||
|
||||
if (!buf || !p ){
|
||||
printk("NULL POINTER IDIOT\n");
|
||||
return;
|
||||
}
|
||||
if (buf[1]&PAY_START) {
|
||||
if (p->plength == MMAX_PLENGTH-6 && p->found>6){
|
||||
p->plength = p->found-6;
|
||||
p->found = 0;
|
||||
send_ipack(p);
|
||||
dvb_filter_ipack_reset(p);
|
||||
}
|
||||
}
|
||||
if (buf[3] & ADAPT_FIELD) { // adaptation field?
|
||||
off = buf[4] + 1;
|
||||
if (off+4 > 187) return;
|
||||
}
|
||||
dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* needs 5 byte input, returns picture coding type*/
|
||||
static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
|
||||
{
|
||||
u8 pct;
|
||||
|
||||
if (pr) printk( "Pic header: ");
|
||||
pic->temporal_reference[field] = (( headr[0] << 2 ) |
|
||||
(headr[1] & 0x03) )& 0x03ff;
|
||||
if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
|
||||
|
||||
pct = ( headr[1] >> 2 ) & 0x07;
|
||||
pic->picture_coding_type[field] = pct;
|
||||
if (pr) {
|
||||
switch(pct){
|
||||
case I_FRAME:
|
||||
printk( " I-FRAME");
|
||||
break;
|
||||
case B_FRAME:
|
||||
printk( " B-FRAME");
|
||||
break;
|
||||
case P_FRAME:
|
||||
printk( " P-FRAME");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) |
|
||||
( (headr[3] & 0x1F) << 11) ) & 0xffff;
|
||||
|
||||
if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
|
||||
|
||||
pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
|
||||
((headr[4] & 0x80) >> 3);
|
||||
|
||||
if ( pct == B_FRAME ){
|
||||
pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
|
||||
}
|
||||
if (pr) printk( " pic head param: 0x%x",
|
||||
pic->picture_header_parameter);
|
||||
|
||||
return pct;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* needs 4 byte input */
|
||||
static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
|
||||
{
|
||||
if (pr) printk("GOP header: ");
|
||||
|
||||
pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) |
|
||||
( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
|
||||
|
||||
if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
|
||||
((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
|
||||
((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
|
||||
|
||||
if ( ( headr[3] & 0x40 ) != 0 ){
|
||||
pic->closed_gop = 1;
|
||||
} else {
|
||||
pic->closed_gop = 0;
|
||||
}
|
||||
if (pr) printk("closed: %d", pic->closed_gop);
|
||||
|
||||
if ( ( headr[3] & 0x20 ) != 0 ){
|
||||
pic->broken_link = 1;
|
||||
} else {
|
||||
pic->broken_link = 0;
|
||||
}
|
||||
if (pr) printk(" broken: %d\n", pic->broken_link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* needs 8 byte input */
|
||||
static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
|
||||
{
|
||||
int sw;
|
||||
int form = -1;
|
||||
|
||||
if (pr) printk("Reading sequence header\n");
|
||||
|
||||
vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
|
||||
vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]);
|
||||
|
||||
sw = (int)((headr[3]&0xF0) >> 4) ;
|
||||
|
||||
switch( sw ){
|
||||
case 1:
|
||||
if (pr)
|
||||
printk("Videostream: ASPECT: 1:1");
|
||||
vi->aspect_ratio = 100;
|
||||
break;
|
||||
case 2:
|
||||
if (pr)
|
||||
printk("Videostream: ASPECT: 4:3");
|
||||
vi->aspect_ratio = 133;
|
||||
break;
|
||||
case 3:
|
||||
if (pr)
|
||||
printk("Videostream: ASPECT: 16:9");
|
||||
vi->aspect_ratio = 177;
|
||||
break;
|
||||
case 4:
|
||||
if (pr)
|
||||
printk("Videostream: ASPECT: 2.21:1");
|
||||
vi->aspect_ratio = 221;
|
||||
break;
|
||||
|
||||
case 5 ... 15:
|
||||
if (pr)
|
||||
printk("Videostream: ASPECT: reserved");
|
||||
vi->aspect_ratio = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
vi->aspect_ratio = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pr)
|
||||
printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size);
|
||||
|
||||
sw = (int)(headr[3]&0x0F);
|
||||
|
||||
switch ( sw ) {
|
||||
case 1:
|
||||
if (pr)
|
||||
printk(" FRate: 23.976 fps");
|
||||
vi->framerate = 23976;
|
||||
form = -1;
|
||||
break;
|
||||
case 2:
|
||||
if (pr)
|
||||
printk(" FRate: 24 fps");
|
||||
vi->framerate = 24000;
|
||||
form = -1;
|
||||
break;
|
||||
case 3:
|
||||
if (pr)
|
||||
printk(" FRate: 25 fps");
|
||||
vi->framerate = 25000;
|
||||
form = VIDEO_MODE_PAL;
|
||||
break;
|
||||
case 4:
|
||||
if (pr)
|
||||
printk(" FRate: 29.97 fps");
|
||||
vi->framerate = 29970;
|
||||
form = VIDEO_MODE_NTSC;
|
||||
break;
|
||||
case 5:
|
||||
if (pr)
|
||||
printk(" FRate: 30 fps");
|
||||
vi->framerate = 30000;
|
||||
form = VIDEO_MODE_NTSC;
|
||||
break;
|
||||
case 6:
|
||||
if (pr)
|
||||
printk(" FRate: 50 fps");
|
||||
vi->framerate = 50000;
|
||||
form = VIDEO_MODE_PAL;
|
||||
break;
|
||||
case 7:
|
||||
if (pr)
|
||||
printk(" FRate: 60 fps");
|
||||
vi->framerate = 60000;
|
||||
form = VIDEO_MODE_NTSC;
|
||||
break;
|
||||
}
|
||||
|
||||
vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
|
||||
|
||||
vi->vbv_buffer_size
|
||||
= (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
|
||||
|
||||
if (pr){
|
||||
printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
|
||||
printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
vi->video_format = form;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
|
||||
{
|
||||
u8 *headr;
|
||||
int found = 0;
|
||||
int c = 0;
|
||||
|
||||
while (found < 4 && c+4 < count){
|
||||
u8 *b;
|
||||
|
||||
b = mbuf+c;
|
||||
if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
|
||||
&& b[3] == 0xb3) found = 4;
|
||||
else {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) return -1;
|
||||
c += 4;
|
||||
if (c+12 >= count) return -1;
|
||||
headr = mbuf+c;
|
||||
if (read_sequence_header(headr, vi, pr) < 0) return -1;
|
||||
vi->off = c-4;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
|
||||
{
|
||||
u8 *headr;
|
||||
int found = 0;
|
||||
int c = 0;
|
||||
int fr = 0;
|
||||
|
||||
while (found < 2 && c < count){
|
||||
u8 b[2];
|
||||
memcpy( b, mbuf+c, 2);
|
||||
|
||||
if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
|
||||
found = 2;
|
||||
else {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) return -1;
|
||||
|
||||
if (c+3 >= count) return -1;
|
||||
headr = mbuf+c;
|
||||
|
||||
ai->layer = (headr[1] & 0x06) >> 1;
|
||||
|
||||
if (pr)
|
||||
printk("Audiostream: Layer: %d", 4-ai->layer);
|
||||
|
||||
|
||||
ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
|
||||
|
||||
if (pr){
|
||||
if (ai->bit_rate == 0)
|
||||
printk(" Bit rate: free");
|
||||
else if (ai->bit_rate == 0xf)
|
||||
printk(" BRate: reserved");
|
||||
else
|
||||
printk(" BRate: %d kb/s", ai->bit_rate/1000);
|
||||
}
|
||||
|
||||
fr = (headr[2] & 0x0c ) >> 2;
|
||||
ai->frequency = freq[fr]*100;
|
||||
if (pr){
|
||||
if (ai->frequency == 3)
|
||||
printk(" Freq: reserved\n");
|
||||
else
|
||||
printk(" Freq: %d kHz\n",ai->frequency);
|
||||
|
||||
}
|
||||
ai->off = c;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
|
||||
{
|
||||
u8 *headr;
|
||||
int found = 0;
|
||||
int c = 0;
|
||||
u8 frame = 0;
|
||||
int fr = 0;
|
||||
|
||||
while ( !found && c < count){
|
||||
u8 *b = mbuf+c;
|
||||
|
||||
if ( b[0] == 0x0b && b[1] == 0x77 )
|
||||
found = 1;
|
||||
else {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) return -1;
|
||||
if (pr)
|
||||
printk("Audiostream: AC3");
|
||||
|
||||
ai->off = c;
|
||||
if (c+5 >= count) return -1;
|
||||
|
||||
ai->layer = 0; // 0 for AC3
|
||||
headr = mbuf+c+2;
|
||||
|
||||
frame = (headr[2]&0x3f);
|
||||
ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
|
||||
|
||||
if (pr)
|
||||
printk(" BRate: %d kb/s", (int) ai->bit_rate/1000);
|
||||
|
||||
ai->frequency = (headr[2] & 0xc0 ) >> 6;
|
||||
fr = (headr[2] & 0xc0 ) >> 6;
|
||||
ai->frequency = freq[fr]*100;
|
||||
if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency);
|
||||
|
||||
|
||||
ai->framesize = ac3_frames[fr][frame >> 1];
|
||||
if ((frame & 1) && (fr == 1)) ai->framesize++;
|
||||
ai->framesize = ai->framesize << 1;
|
||||
if (pr) printk (" Framesize %d\n",(int) ai->framesize);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_filter_get_ac3info);
|
||||
|
||||
|
||||
#if 0
|
||||
static u8 *skip_pes_header(u8 **bufp)
|
||||
{
|
||||
u8 *inbuf = *bufp;
|
||||
u8 *buf = inbuf;
|
||||
u8 *pts = NULL;
|
||||
int skip = 0;
|
||||
|
||||
static const int mpeg1_skip_table[16] = {
|
||||
1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
|
||||
};
|
||||
|
||||
|
||||
if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
|
||||
if (buf[7] & PTS_ONLY)
|
||||
pts = buf+9;
|
||||
else pts = NULL;
|
||||
buf = inbuf + 9 + inbuf[8];
|
||||
} else { /* mpeg1 */
|
||||
for (buf = inbuf + 6; *buf == 0xff; buf++)
|
||||
if (buf == inbuf + 6 + 16) {
|
||||
break;
|
||||
}
|
||||
if ((*buf & 0xc0) == 0x40)
|
||||
buf += 2;
|
||||
skip = mpeg1_skip_table [*buf >> 4];
|
||||
if (skip == 5 || skip == 10) pts = buf;
|
||||
else pts = NULL;
|
||||
|
||||
buf += mpeg1_skip_table [*buf >> 4];
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return pts;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void initialize_quant_matrix( u32 *matrix )
|
||||
{
|
||||
int i;
|
||||
|
||||
matrix[0] = 0x08101013;
|
||||
matrix[1] = 0x10131616;
|
||||
matrix[2] = 0x16161616;
|
||||
matrix[3] = 0x1a181a1b;
|
||||
matrix[4] = 0x1b1b1a1a;
|
||||
matrix[5] = 0x1a1a1b1b;
|
||||
matrix[6] = 0x1b1d1d1d;
|
||||
matrix[7] = 0x2222221d;
|
||||
matrix[8] = 0x1d1d1b1b;
|
||||
matrix[9] = 0x1d1d2020;
|
||||
matrix[10] = 0x22222526;
|
||||
matrix[11] = 0x25232322;
|
||||
matrix[12] = 0x23262628;
|
||||
matrix[13] = 0x28283030;
|
||||
matrix[14] = 0x2e2e3838;
|
||||
matrix[15] = 0x3a454553;
|
||||
|
||||
for ( i = 16 ; i < 32 ; i++ )
|
||||
matrix[i] = 0x10101010;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void initialize_mpg_picture(struct mpg_picture *pic)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set MPEG1 */
|
||||
pic->mpeg1_flag = 1;
|
||||
pic->profile_and_level = 0x4A ; /* MP@LL */
|
||||
pic->progressive_sequence = 1;
|
||||
pic->low_delay = 0;
|
||||
|
||||
pic->sequence_display_extension_flag = 0;
|
||||
for ( i = 0 ; i < 4 ; i++ ){
|
||||
pic->frame_centre_horizontal_offset[i] = 0;
|
||||
pic->frame_centre_vertical_offset[i] = 0;
|
||||
}
|
||||
pic->last_frame_centre_horizontal_offset = 0;
|
||||
pic->last_frame_centre_vertical_offset = 0;
|
||||
|
||||
pic->picture_display_extension_flag[0] = 0;
|
||||
pic->picture_display_extension_flag[1] = 0;
|
||||
pic->sequence_header_flag = 0;
|
||||
pic->gop_flag = 0;
|
||||
pic->sequence_end_flag = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
|
||||
{
|
||||
int16_t last_h_offset;
|
||||
int16_t last_v_offset;
|
||||
|
||||
int16_t *p_h_offset;
|
||||
int16_t *p_v_offset;
|
||||
|
||||
if ( pic->mpeg1_flag ){
|
||||
pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
|
||||
pic->top_field_first = 0;
|
||||
pic->repeat_first_field = 0;
|
||||
pic->progressive_frame = 1;
|
||||
pic->picture_coding_parameter = 0x000010;
|
||||
}
|
||||
|
||||
/* Reset flag */
|
||||
pic->picture_display_extension_flag[field_type] = 0;
|
||||
|
||||
last_h_offset = pic->last_frame_centre_horizontal_offset;
|
||||
last_v_offset = pic->last_frame_centre_vertical_offset;
|
||||
if ( field_type == FIRST_FIELD ){
|
||||
p_h_offset = pic->frame_centre_horizontal_offset;
|
||||
p_v_offset = pic->frame_centre_vertical_offset;
|
||||
*p_h_offset = last_h_offset;
|
||||
*(p_h_offset + 1) = last_h_offset;
|
||||
*(p_h_offset + 2) = last_h_offset;
|
||||
*p_v_offset = last_v_offset;
|
||||
*(p_v_offset + 1) = last_v_offset;
|
||||
*(p_v_offset + 2) = last_v_offset;
|
||||
} else {
|
||||
pic->frame_centre_horizontal_offset[3] = last_h_offset;
|
||||
pic->frame_centre_vertical_offset[3] = last_v_offset;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
|
||||
{
|
||||
pic->picture_header = 0;
|
||||
pic->sequence_header_data
|
||||
= ( INIT_HORIZONTAL_SIZE << 20 )
|
||||
| ( INIT_VERTICAL_SIZE << 8 )
|
||||
| ( INIT_ASPECT_RATIO << 4 )
|
||||
| ( INIT_FRAME_RATE );
|
||||
pic->mpeg1_flag = 0;
|
||||
pic->vinfo.horizontal_size
|
||||
= INIT_DISP_HORIZONTAL_SIZE;
|
||||
pic->vinfo.vertical_size
|
||||
= INIT_DISP_VERTICAL_SIZE;
|
||||
pic->picture_display_extension_flag[field_type]
|
||||
= 0;
|
||||
pic->pts_flag[field_type] = 0;
|
||||
|
||||
pic->sequence_gop_header = 0;
|
||||
pic->picture_header = 0;
|
||||
pic->sequence_header_flag = 0;
|
||||
pic->gop_flag = 0;
|
||||
pic->sequence_end_flag = 0;
|
||||
pic->sequence_display_extension_flag = 0;
|
||||
pic->last_frame_centre_horizontal_offset = 0;
|
||||
pic->last_frame_centre_vertical_offset = 0;
|
||||
pic->channel = chan;
|
||||
}
|
||||
#endif
|
||||
|
||||
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
|
||||
dvb_filter_pes2ts_cb_t *cb, void *priv)
|
||||
{
|
||||
unsigned char *buf=p2ts->buf;
|
||||
|
||||
buf[0]=0x47;
|
||||
buf[1]=(pid>>8);
|
||||
buf[2]=pid&0xff;
|
||||
p2ts->cc=0;
|
||||
p2ts->cb=cb;
|
||||
p2ts->priv=priv;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_filter_pes2ts_init);
|
||||
|
||||
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
|
||||
int len, int payload_start)
|
||||
{
|
||||
unsigned char *buf=p2ts->buf;
|
||||
int ret=0, rest;
|
||||
|
||||
//len=6+((pes[4]<<8)|pes[5]);
|
||||
|
||||
if (payload_start)
|
||||
buf[1]|=0x40;
|
||||
else
|
||||
buf[1]&=~0x40;
|
||||
while (len>=184) {
|
||||
buf[3]=0x10|((p2ts->cc++)&0x0f);
|
||||
memcpy(buf+4, pes, 184);
|
||||
if ((ret=p2ts->cb(p2ts->priv, buf)))
|
||||
return ret;
|
||||
len-=184; pes+=184;
|
||||
buf[1]&=~0x40;
|
||||
}
|
||||
if (!len)
|
||||
return 0;
|
||||
buf[3]=0x30|((p2ts->cc++)&0x0f);
|
||||
rest=183-len;
|
||||
if (rest) {
|
||||
buf[5]=0x00;
|
||||
if (rest-1)
|
||||
memset(buf+6, 0xff, rest-1);
|
||||
}
|
||||
buf[4]=rest;
|
||||
memcpy(buf+5+rest, pes, len);
|
||||
return p2ts->cb(p2ts->priv, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_filter_pes2ts);
|
||||
246
drivers/media/dvb/dvb-core/dvb_filter.h
Normal file
246
drivers/media/dvb/dvb-core/dvb_filter.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* dvb_filter.h
|
||||
*
|
||||
* Copyright (C) 2003 Convergence GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_FILTER_H_
|
||||
#define _DVB_FILTER_H_
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "demux.h"
|
||||
|
||||
typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
|
||||
|
||||
struct dvb_filter_pes2ts {
|
||||
unsigned char buf[188];
|
||||
unsigned char cc;
|
||||
dvb_filter_pes2ts_cb_t *cb;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
|
||||
dvb_filter_pes2ts_cb_t *cb, void *priv);
|
||||
|
||||
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
|
||||
int len, int payload_start);
|
||||
|
||||
|
||||
#define PROG_STREAM_MAP 0xBC
|
||||
#define PRIVATE_STREAM1 0xBD
|
||||
#define PADDING_STREAM 0xBE
|
||||
#define PRIVATE_STREAM2 0xBF
|
||||
#define AUDIO_STREAM_S 0xC0
|
||||
#define AUDIO_STREAM_E 0xDF
|
||||
#define VIDEO_STREAM_S 0xE0
|
||||
#define VIDEO_STREAM_E 0xEF
|
||||
#define ECM_STREAM 0xF0
|
||||
#define EMM_STREAM 0xF1
|
||||
#define DSM_CC_STREAM 0xF2
|
||||
#define ISO13522_STREAM 0xF3
|
||||
#define PROG_STREAM_DIR 0xFF
|
||||
|
||||
#define DVB_PICTURE_START 0x00
|
||||
#define DVB_USER_START 0xb2
|
||||
#define DVB_SEQUENCE_HEADER 0xb3
|
||||
#define DVB_SEQUENCE_ERROR 0xb4
|
||||
#define DVB_EXTENSION_START 0xb5
|
||||
#define DVB_SEQUENCE_END 0xb7
|
||||
#define DVB_GOP_START 0xb8
|
||||
#define DVB_EXCEPT_SLICE 0xb0
|
||||
|
||||
#define SEQUENCE_EXTENSION 0x01
|
||||
#define SEQUENCE_DISPLAY_EXTENSION 0x02
|
||||
#define PICTURE_CODING_EXTENSION 0x08
|
||||
#define QUANT_MATRIX_EXTENSION 0x03
|
||||
#define PICTURE_DISPLAY_EXTENSION 0x07
|
||||
|
||||
#define I_FRAME 0x01
|
||||
#define B_FRAME 0x02
|
||||
#define P_FRAME 0x03
|
||||
|
||||
/* Initialize sequence_data */
|
||||
#define INIT_HORIZONTAL_SIZE 720
|
||||
#define INIT_VERTICAL_SIZE 576
|
||||
#define INIT_ASPECT_RATIO 0x02
|
||||
#define INIT_FRAME_RATE 0x03
|
||||
#define INIT_DISP_HORIZONTAL_SIZE 540
|
||||
#define INIT_DISP_VERTICAL_SIZE 576
|
||||
|
||||
|
||||
//flags2
|
||||
#define PTS_DTS_FLAGS 0xC0
|
||||
#define ESCR_FLAG 0x20
|
||||
#define ES_RATE_FLAG 0x10
|
||||
#define DSM_TRICK_FLAG 0x08
|
||||
#define ADD_CPY_FLAG 0x04
|
||||
#define PES_CRC_FLAG 0x02
|
||||
#define PES_EXT_FLAG 0x01
|
||||
|
||||
//pts_dts flags
|
||||
#define PTS_ONLY 0x80
|
||||
#define PTS_DTS 0xC0
|
||||
|
||||
#define TS_SIZE 188
|
||||
#define TRANS_ERROR 0x80
|
||||
#define PAY_START 0x40
|
||||
#define TRANS_PRIO 0x20
|
||||
#define PID_MASK_HI 0x1F
|
||||
//flags
|
||||
#define TRANS_SCRMBL1 0x80
|
||||
#define TRANS_SCRMBL2 0x40
|
||||
#define ADAPT_FIELD 0x20
|
||||
#define PAYLOAD 0x10
|
||||
#define COUNT_MASK 0x0F
|
||||
|
||||
// adaptation flags
|
||||
#define DISCON_IND 0x80
|
||||
#define RAND_ACC_IND 0x40
|
||||
#define ES_PRI_IND 0x20
|
||||
#define PCR_FLAG 0x10
|
||||
#define OPCR_FLAG 0x08
|
||||
#define SPLICE_FLAG 0x04
|
||||
#define TRANS_PRIV 0x02
|
||||
#define ADAP_EXT_FLAG 0x01
|
||||
|
||||
// adaptation extension flags
|
||||
#define LTW_FLAG 0x80
|
||||
#define PIECE_RATE 0x40
|
||||
#define SEAM_SPLICE 0x20
|
||||
|
||||
|
||||
#define MAX_PLENGTH 0xFFFF
|
||||
#define MMAX_PLENGTH (256*MAX_PLENGTH)
|
||||
|
||||
#ifndef IPACKS
|
||||
#define IPACKS 2048
|
||||
#endif
|
||||
|
||||
struct ipack {
|
||||
int size;
|
||||
int found;
|
||||
u8 *buf;
|
||||
u8 cid;
|
||||
u32 plength;
|
||||
u8 plen[2];
|
||||
u8 flag1;
|
||||
u8 flag2;
|
||||
u8 hlength;
|
||||
u8 pts[5];
|
||||
u16 *pid;
|
||||
int mpeg;
|
||||
u8 check;
|
||||
int which;
|
||||
int done;
|
||||
void *data;
|
||||
void (*func)(u8 *buf, int size, void *priv);
|
||||
int count;
|
||||
int repack_subids;
|
||||
};
|
||||
|
||||
struct dvb_video_info {
|
||||
u32 horizontal_size;
|
||||
u32 vertical_size;
|
||||
u32 aspect_ratio;
|
||||
u32 framerate;
|
||||
u32 video_format;
|
||||
u32 bit_rate;
|
||||
u32 comp_bit_rate;
|
||||
u32 vbv_buffer_size;
|
||||
s16 vbv_delay;
|
||||
u32 CSPF;
|
||||
u32 off;
|
||||
};
|
||||
|
||||
#define OFF_SIZE 4
|
||||
#define FIRST_FIELD 0
|
||||
#define SECOND_FIELD 1
|
||||
#define VIDEO_FRAME_PICTURE 0x03
|
||||
|
||||
struct mpg_picture {
|
||||
int channel;
|
||||
struct dvb_video_info vinfo;
|
||||
u32 *sequence_gop_header;
|
||||
u32 *picture_header;
|
||||
s32 time_code;
|
||||
int low_delay;
|
||||
int closed_gop;
|
||||
int broken_link;
|
||||
int sequence_header_flag;
|
||||
int gop_flag;
|
||||
int sequence_end_flag;
|
||||
|
||||
u8 profile_and_level;
|
||||
s32 picture_coding_parameter;
|
||||
u32 matrix[32];
|
||||
s8 matrix_change_flag;
|
||||
|
||||
u8 picture_header_parameter;
|
||||
/* bit 0 - 2: bwd f code
|
||||
bit 3 : fpb vector
|
||||
bit 4 - 6: fwd f code
|
||||
bit 7 : fpf vector */
|
||||
|
||||
int mpeg1_flag;
|
||||
int progressive_sequence;
|
||||
int sequence_display_extension_flag;
|
||||
u32 sequence_header_data;
|
||||
s16 last_frame_centre_horizontal_offset;
|
||||
s16 last_frame_centre_vertical_offset;
|
||||
|
||||
u32 pts[2]; /* [0] 1st field, [1] 2nd field */
|
||||
int top_field_first;
|
||||
int repeat_first_field;
|
||||
int progressive_frame;
|
||||
int bank;
|
||||
int forward_bank;
|
||||
int backward_bank;
|
||||
int compress;
|
||||
s16 frame_centre_horizontal_offset[OFF_SIZE];
|
||||
/* [0-2] 1st field, [3] 2nd field */
|
||||
s16 frame_centre_vertical_offset[OFF_SIZE];
|
||||
/* [0-2] 1st field, [3] 2nd field */
|
||||
s16 temporal_reference[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
|
||||
s8 picture_coding_type[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
s8 picture_structure[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
s8 picture_display_extension_flag[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
/* picture_display_extenion() 0:no 1:exit*/
|
||||
s8 pts_flag[2];
|
||||
/* [0] 1st field, [1] 2nd field */
|
||||
};
|
||||
|
||||
struct dvb_audio_info {
|
||||
int layer;
|
||||
u32 bit_rate;
|
||||
u32 frequency;
|
||||
u32 mode;
|
||||
u32 mode_extension ;
|
||||
u32 emphasis;
|
||||
u32 framesize;
|
||||
u32 off;
|
||||
};
|
||||
|
||||
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
|
||||
|
||||
|
||||
#endif
|
||||
1135
drivers/media/dvb/dvb-core/dvb_frontend.c
Normal file
1135
drivers/media/dvb/dvb-core/dvb_frontend.c
Normal file
File diff suppressed because it is too large
Load Diff
169
drivers/media/dvb/dvb-core/dvb_frontend.h
Normal file
169
drivers/media/dvb/dvb-core/dvb_frontend.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* dvb_frontend.h
|
||||
*
|
||||
* Copyright (C) 2001 convergence integrated media GmbH
|
||||
* Copyright (C) 2004 convergence GmbH
|
||||
*
|
||||
* Written by Ralph Metzler
|
||||
* Overhauled by Holger Waechtler
|
||||
* Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_FRONTEND_H_
|
||||
#define _DVB_FRONTEND_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
struct dvb_frontend_tune_settings {
|
||||
int min_delay_ms;
|
||||
int step_size;
|
||||
int max_drift;
|
||||
struct dvb_frontend_parameters parameters;
|
||||
};
|
||||
|
||||
struct dvb_frontend;
|
||||
|
||||
struct dvb_tuner_info {
|
||||
char name[128];
|
||||
|
||||
u32 frequency_min;
|
||||
u32 frequency_max;
|
||||
u32 frequency_step;
|
||||
|
||||
u32 bandwidth_min;
|
||||
u32 bandwidth_max;
|
||||
u32 bandwidth_step;
|
||||
};
|
||||
|
||||
struct dvb_tuner_ops {
|
||||
|
||||
struct dvb_tuner_info info;
|
||||
|
||||
int (*release)(struct dvb_frontend *fe);
|
||||
int (*init)(struct dvb_frontend *fe);
|
||||
int (*sleep)(struct dvb_frontend *fe);
|
||||
|
||||
/** This is for simple PLLs - set all parameters in one go. */
|
||||
int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
|
||||
|
||||
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
|
||||
int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
|
||||
|
||||
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
|
||||
|
||||
#define TUNER_STATUS_LOCKED 1
|
||||
int (*get_status)(struct dvb_frontend *fe, u32 *status);
|
||||
|
||||
/** These are provided seperately from set_params in order to facilitate silicon
|
||||
* tuners which require sophisticated tuning loops, controlling each parameter seperately. */
|
||||
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
|
||||
};
|
||||
|
||||
struct dvb_frontend_ops {
|
||||
|
||||
struct dvb_frontend_info info;
|
||||
|
||||
void (*release)(struct dvb_frontend* fe);
|
||||
void (*release_sec)(struct dvb_frontend* fe);
|
||||
|
||||
int (*init)(struct dvb_frontend* fe);
|
||||
int (*sleep)(struct dvb_frontend* fe);
|
||||
|
||||
int (*write)(struct dvb_frontend* fe, u8* buf, int len);
|
||||
|
||||
/* if this is set, it overrides the default swzigzag */
|
||||
int (*tune)(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters* params,
|
||||
unsigned int mode_flags,
|
||||
int *delay,
|
||||
fe_status_t *status);
|
||||
/* get frontend tuning algorithm from the module */
|
||||
int (*get_frontend_algo)(struct dvb_frontend *fe);
|
||||
|
||||
/* these two are only used for the swzigzag code */
|
||||
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
|
||||
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
|
||||
|
||||
int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
|
||||
|
||||
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
|
||||
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
|
||||
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
|
||||
int (*read_snr)(struct dvb_frontend* fe, u16* snr);
|
||||
int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
|
||||
|
||||
int (*diseqc_reset_overload)(struct dvb_frontend* fe);
|
||||
int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
|
||||
int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
|
||||
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
|
||||
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
|
||||
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
|
||||
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
|
||||
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
|
||||
int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
|
||||
|
||||
struct dvb_tuner_ops tuner_ops;
|
||||
};
|
||||
|
||||
#define MAX_EVENT 8
|
||||
|
||||
struct dvb_fe_events {
|
||||
struct dvb_frontend_event events[MAX_EVENT];
|
||||
int eventw;
|
||||
int eventr;
|
||||
int overflow;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct semaphore sem;
|
||||
};
|
||||
|
||||
struct dvb_frontend {
|
||||
struct dvb_frontend_ops ops;
|
||||
struct dvb_adapter *dvb;
|
||||
void* demodulator_priv;
|
||||
void* tuner_priv;
|
||||
void* frontend_priv;
|
||||
void* sec_priv;
|
||||
};
|
||||
|
||||
extern int dvb_register_frontend(struct dvb_adapter* dvb,
|
||||
struct dvb_frontend* fe);
|
||||
|
||||
extern int dvb_unregister_frontend(struct dvb_frontend* fe);
|
||||
|
||||
extern void dvb_frontend_detach(struct dvb_frontend* fe);
|
||||
|
||||
extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
|
||||
|
||||
extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
|
||||
extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
|
||||
|
||||
#endif
|
||||
145
drivers/media/dvb/dvb-core/dvb_math.c
Normal file
145
drivers/media/dvb/dvb-core/dvb_math.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* dvb-math provides some complex fixed-point math
|
||||
* operations shared between the dvb related stuff
|
||||
*
|
||||
* Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/bug.h>
|
||||
#include "dvb_math.h"
|
||||
|
||||
static const unsigned short logtable[256] = {
|
||||
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
|
||||
0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
|
||||
0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
|
||||
0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
|
||||
0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
|
||||
0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
|
||||
0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
|
||||
0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
|
||||
0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
|
||||
0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
|
||||
0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
|
||||
0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
|
||||
0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
|
||||
0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
|
||||
0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
|
||||
0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
|
||||
0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
|
||||
0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
|
||||
0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
|
||||
0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
|
||||
0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
|
||||
0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
|
||||
0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
|
||||
0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
|
||||
0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
|
||||
0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
|
||||
0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
|
||||
0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
|
||||
0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
|
||||
0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
|
||||
0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
|
||||
0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
|
||||
};
|
||||
|
||||
unsigned int intlog2(u32 value)
|
||||
{
|
||||
/**
|
||||
* returns: log2(value) * 2^24
|
||||
* wrong result if value = 0 (log2(0) is undefined)
|
||||
*/
|
||||
unsigned int msb;
|
||||
unsigned int logentry;
|
||||
unsigned int significand;
|
||||
unsigned int interpolation;
|
||||
|
||||
if (unlikely(value == 0)) {
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* first detect the msb (count begins at 0) */
|
||||
msb = fls(value) - 1;
|
||||
|
||||
/**
|
||||
* now we use a logtable after the following method:
|
||||
*
|
||||
* log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
|
||||
* where x = msb and therefore 1 <= y < 2
|
||||
* first y is determined by shifting the value left
|
||||
* so that msb is bit 31
|
||||
* 0x00231f56 -> 0x8C7D5800
|
||||
* the result is y * 2^31 -> "significand"
|
||||
* then the highest 9 bits are used for a table lookup
|
||||
* the highest bit is discarded because it's always set
|
||||
* the highest nine bits in our example are 100011000
|
||||
* so we would use the entry 0x18
|
||||
*/
|
||||
significand = value << (31 - msb);
|
||||
logentry = (significand >> 23) & 0xff;
|
||||
|
||||
/**
|
||||
* last step we do is interpolation because of the
|
||||
* limitations of the log table the error is that part of
|
||||
* the significand which isn't used for lookup then we
|
||||
* compute the ratio between the error and the next table entry
|
||||
* and interpolate it between the log table entry used and the
|
||||
* next one the biggest error possible is 0x7fffff
|
||||
* (in our example it's 0x7D5800)
|
||||
* needed value for next table entry is 0x800000
|
||||
* so the interpolation is
|
||||
* (error / 0x800000) * (logtable_next - logtable_current)
|
||||
* in the implementation the division is moved to the end for
|
||||
* better accuracy there is also an overflow correction if
|
||||
* logtable_next is 256
|
||||
*/
|
||||
interpolation = ((significand & 0x7fffff) *
|
||||
((logtable[(logentry + 1) & 0xff] -
|
||||
logtable[logentry]) & 0xffff)) >> 15;
|
||||
|
||||
/* now we return the result */
|
||||
return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
|
||||
}
|
||||
EXPORT_SYMBOL(intlog2);
|
||||
|
||||
unsigned int intlog10(u32 value)
|
||||
{
|
||||
/**
|
||||
* returns: log10(value) * 2^24
|
||||
* wrong result if value = 0 (log10(0) is undefined)
|
||||
*/
|
||||
u64 log;
|
||||
|
||||
if (unlikely(value == 0)) {
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log = intlog2(value);
|
||||
|
||||
/**
|
||||
* we use the following method:
|
||||
* log10(x) = log2(x) * log10(2)
|
||||
*/
|
||||
|
||||
return (log * 646456993) >> 31;
|
||||
}
|
||||
EXPORT_SYMBOL(intlog10);
|
||||
58
drivers/media/dvb/dvb-core/dvb_math.h
Normal file
58
drivers/media/dvb/dvb-core/dvb_math.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* dvb-math provides some complex fixed-point math
|
||||
* operations shared between the dvb related stuff
|
||||
*
|
||||
* Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __DVB_MATH_H
|
||||
#define __DVB_MATH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* computes log2 of a value; the result is shifted left by 24 bits
|
||||
*
|
||||
* to use rational values you can use the following method:
|
||||
* intlog2(value) = intlog2(value * 2^x) - x * 2^24
|
||||
*
|
||||
* example: intlog2(8) will give 3 << 24 = 3 * 2^24
|
||||
* example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
|
||||
* example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
|
||||
*
|
||||
* @param value The value (must be != 0)
|
||||
* @return log2(value) * 2^24
|
||||
*/
|
||||
extern unsigned int intlog2(u32 value);
|
||||
|
||||
/**
|
||||
* computes log10 of a value; the result is shifted left by 24 bits
|
||||
*
|
||||
* to use rational values you can use the following method:
|
||||
* intlog10(value) = intlog10(value * 10^x) - x * 2^24
|
||||
*
|
||||
* example: intlog10(1000) will give 3 << 24 = 3 * 2^24
|
||||
* due to the implementation intlog10(1000) might be not exactly 3 * 2^24
|
||||
*
|
||||
* look at intlog2 for similar examples
|
||||
*
|
||||
* @param value The value (must be != 0)
|
||||
* @return log10(value) * 2^24
|
||||
*/
|
||||
extern unsigned int intlog10(u32 value);
|
||||
|
||||
#endif
|
||||
1483
drivers/media/dvb/dvb-core/dvb_net.c
Normal file
1483
drivers/media/dvb/dvb-core/dvb_net.c
Normal file
File diff suppressed because it is too large
Load Diff
46
drivers/media/dvb/dvb-core/dvb_net.h
Normal file
46
drivers/media/dvb/dvb-core/dvb_net.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* dvb_net.h
|
||||
*
|
||||
* Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVB_NET_H_
|
||||
#define _DVB_NET_H_
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
#define DVB_NET_DEVICES_MAX 10
|
||||
|
||||
struct dvb_net {
|
||||
struct dvb_device *dvbdev;
|
||||
struct net_device *device[DVB_NET_DEVICES_MAX];
|
||||
int state[DVB_NET_DEVICES_MAX];
|
||||
struct dmx_demux *demux;
|
||||
};
|
||||
|
||||
|
||||
void dvb_net_release(struct dvb_net *);
|
||||
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
|
||||
|
||||
#endif
|
||||
271
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
Normal file
271
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
*
|
||||
* dvb_ringbuffer.c: ring buffer implementation for the dvb driver
|
||||
*
|
||||
* Copyright (C) 2003 Oliver Endriss
|
||||
* Copyright (C) 2004 Andrew de Quincey
|
||||
*
|
||||
* based on code originally found in av7110.c & dvb_ci.c:
|
||||
* Copyright (C) 1999-2003 Ralph Metzler
|
||||
* & Marcus Metzler for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "dvb_ringbuffer.h"
|
||||
|
||||
#define PKT_READY 0
|
||||
#define PKT_DISPOSED 1
|
||||
|
||||
|
||||
void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
|
||||
{
|
||||
rbuf->pread=rbuf->pwrite=0;
|
||||
rbuf->data=data;
|
||||
rbuf->size=len;
|
||||
rbuf->error=0;
|
||||
|
||||
init_waitqueue_head(&rbuf->queue);
|
||||
|
||||
spin_lock_init(&(rbuf->lock));
|
||||
}
|
||||
|
||||
|
||||
|
||||
int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
return (rbuf->pread==rbuf->pwrite);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
ssize_t free;
|
||||
|
||||
free = rbuf->pread - rbuf->pwrite;
|
||||
if (free <= 0)
|
||||
free += rbuf->size;
|
||||
return free-1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
ssize_t avail;
|
||||
|
||||
avail = rbuf->pwrite - rbuf->pread;
|
||||
if (avail < 0)
|
||||
avail += rbuf->size;
|
||||
return avail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
rbuf->pread = rbuf->pwrite;
|
||||
rbuf->error = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rbuf->lock, flags);
|
||||
dvb_ringbuffer_flush(rbuf);
|
||||
spin_unlock_irqrestore(&rbuf->lock, flags);
|
||||
|
||||
wake_up(&rbuf->queue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem)
|
||||
{
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
|
||||
if (split > 0) {
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+rbuf->pread, split);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pread = 0;
|
||||
}
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+rbuf->pread, todo);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
|
||||
return -EFAULT;
|
||||
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
|
||||
{
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
|
||||
|
||||
if (split > 0) {
|
||||
memcpy(rbuf->data+rbuf->pwrite, buf, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pwrite = 0;
|
||||
}
|
||||
memcpy(rbuf->data+rbuf->pwrite, buf, todo);
|
||||
rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
|
||||
{
|
||||
int status;
|
||||
ssize_t oldpwrite = rbuf->pwrite;
|
||||
|
||||
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
|
||||
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
|
||||
DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
|
||||
status = dvb_ringbuffer_write(rbuf, buf, len);
|
||||
|
||||
if (status < 0) rbuf->pwrite = oldpwrite;
|
||||
return status;
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8* buf, size_t len, int usermem)
|
||||
{
|
||||
size_t todo;
|
||||
size_t split;
|
||||
size_t pktlen;
|
||||
|
||||
pktlen = rbuf->data[idx] << 8;
|
||||
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
|
||||
if (offset > pktlen) return -EINVAL;
|
||||
if ((offset + len) > pktlen) len = pktlen - offset;
|
||||
|
||||
idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
|
||||
todo = len;
|
||||
split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
|
||||
if (split > 0) {
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+idx, split);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+idx, split))
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
idx = 0;
|
||||
}
|
||||
if (!usermem)
|
||||
memcpy(buf, rbuf->data+idx, todo);
|
||||
else
|
||||
if (copy_to_user(buf, rbuf->data+idx, todo))
|
||||
return -EFAULT;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
|
||||
{
|
||||
size_t pktlen;
|
||||
|
||||
rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
|
||||
|
||||
// clean up disposed packets
|
||||
while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
|
||||
if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
|
||||
pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
|
||||
pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
|
||||
DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
|
||||
} else {
|
||||
// first packet is not disposed, so we stop cleaning now
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
|
||||
{
|
||||
int consumed;
|
||||
int curpktlen;
|
||||
int curpktstatus;
|
||||
|
||||
if (idx == -1) {
|
||||
idx = rbuf->pread;
|
||||
} else {
|
||||
curpktlen = rbuf->data[idx] << 8;
|
||||
curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
|
||||
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
|
||||
}
|
||||
|
||||
consumed = (idx - rbuf->pread) % rbuf->size;
|
||||
|
||||
while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
|
||||
|
||||
curpktlen = rbuf->data[idx] << 8;
|
||||
curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
|
||||
curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
|
||||
|
||||
if (curpktstatus == PKT_READY) {
|
||||
*pktlen = curpktlen;
|
||||
return idx;
|
||||
}
|
||||
|
||||
consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
|
||||
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
|
||||
}
|
||||
|
||||
// no packets available
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_init);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_empty);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_free);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_avail);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_flush);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_write);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
|
||||
174
drivers/media/dvb/dvb-core/dvb_ringbuffer.h
Normal file
174
drivers/media/dvb/dvb-core/dvb_ringbuffer.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
*
|
||||
* dvb_ringbuffer.h: ring buffer implementation for the dvb driver
|
||||
*
|
||||
* Copyright (C) 2003 Oliver Endriss
|
||||
* Copyright (C) 2004 Andrew de Quincey
|
||||
*
|
||||
* based on code originally found in av7110.c & dvb_ci.c:
|
||||
* Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _DVB_RINGBUFFER_H_
|
||||
#define _DVB_RINGBUFFER_H_
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
struct dvb_ringbuffer {
|
||||
u8 *data;
|
||||
ssize_t size;
|
||||
ssize_t pread;
|
||||
ssize_t pwrite;
|
||||
int error;
|
||||
|
||||
wait_queue_head_t queue;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define DVB_RINGBUFFER_PKTHDRSIZE 3
|
||||
|
||||
|
||||
/*
|
||||
** Notes:
|
||||
** ------
|
||||
** (1) For performance reasons read and write routines don't check buffer sizes
|
||||
** and/or number of bytes free/available. This has to be done before these
|
||||
** routines are called. For example:
|
||||
**
|
||||
** *** write <buflen> bytes ***
|
||||
** free = dvb_ringbuffer_free(rbuf);
|
||||
** if (free >= buflen)
|
||||
** count = dvb_ringbuffer_write(rbuf, buffer, buflen);
|
||||
** else
|
||||
** ...
|
||||
**
|
||||
** *** read min. 1000, max. <bufsize> bytes ***
|
||||
** avail = dvb_ringbuffer_avail(rbuf);
|
||||
** if (avail >= 1000)
|
||||
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
|
||||
** else
|
||||
** ...
|
||||
**
|
||||
** (2) If there is exactly one reader and one writer, there is no need
|
||||
** to lock read or write operations.
|
||||
** Two or more readers must be locked against each other.
|
||||
** Flushing the buffer counts as a read operation.
|
||||
** Two or more writers must be locked against each other.
|
||||
*/
|
||||
|
||||
/* initialize ring buffer, lock and queue */
|
||||
extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
|
||||
|
||||
/* test whether buffer is empty */
|
||||
extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* return the number of free bytes in the buffer */
|
||||
extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* return the number of bytes waiting in the buffer */
|
||||
extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
|
||||
/* read routines & macros */
|
||||
/* ---------------------- */
|
||||
/* flush buffer */
|
||||
extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* flush buffer protected by spinlock and wake-up waiting task(s) */
|
||||
extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
|
||||
|
||||
/* peek at byte <offs> in the buffer */
|
||||
#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
|
||||
(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
|
||||
|
||||
/* advance read ptr by <num> bytes */
|
||||
#define DVB_RINGBUFFER_SKIP(rbuf,num) \
|
||||
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
|
||||
|
||||
/*
|
||||
** read <len> bytes from ring buffer into <buf>
|
||||
** <usermem> specifies whether <buf> resides in user space
|
||||
** returns number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
|
||||
size_t len, int usermem);
|
||||
|
||||
|
||||
/* write routines & macros */
|
||||
/* ----------------------- */
|
||||
/* write single byte to ring buffer */
|
||||
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \
|
||||
{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
|
||||
(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
|
||||
/*
|
||||
** write <len> bytes to ring buffer
|
||||
** <usermem> specifies whether <buf> resides in user space
|
||||
** returns number of bytes transferred or -EFAULT
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
|
||||
size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Write a packet into the ringbuffer.
|
||||
*
|
||||
* <rbuf> Ringbuffer to write to.
|
||||
* <buf> Buffer to write.
|
||||
* <len> Length of buffer (currently limited to 65535 bytes max).
|
||||
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
|
||||
* does NOT update the read pointer in the ringbuffer. You must use
|
||||
* dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
|
||||
*
|
||||
* <rbuf> Ringbuffer concerned.
|
||||
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
* <offset> Offset into packet to read from.
|
||||
* <buf> Destination buffer for data.
|
||||
* <len> Size of destination buffer.
|
||||
* <usermem> Set to 1 if <buf> is in userspace.
|
||||
* returns Number of bytes read, or -EFAULT.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8* buf, size_t len, int usermem);
|
||||
|
||||
/**
|
||||
* Dispose of a packet in the ring buffer.
|
||||
*
|
||||
* <rbuf> Ring buffer concerned.
|
||||
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
|
||||
*/
|
||||
extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
|
||||
|
||||
/**
|
||||
* Get the index of the next packet in a ringbuffer.
|
||||
*
|
||||
* <rbuf> Ringbuffer concerned.
|
||||
* <idx> Previous packet index, or -1 to return the first packet index.
|
||||
* <pktlen> On success, will be updated to contain the length of the packet in bytes.
|
||||
* returns Packet index (if >=0), or -1 if no packets available.
|
||||
*/
|
||||
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
|
||||
|
||||
|
||||
#endif /* _DVB_RINGBUFFER_H_ */
|
||||
438
drivers/media/dvb/dvb-core/dvbdev.c
Normal file
438
drivers/media/dvb/dvb-core/dvbdev.c
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* dvbdev.c
|
||||
*
|
||||
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
|
||||
* & Marcus Metzler <marcus@convergence.de>
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "dvbdev.h"
|
||||
|
||||
static int dvbdev_debug;
|
||||
|
||||
module_param(dvbdev_debug, int, 0644);
|
||||
MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
|
||||
|
||||
#define dprintk if (dvbdev_debug) printk
|
||||
|
||||
static LIST_HEAD(dvb_adapter_list);
|
||||
static DEFINE_MUTEX(dvbdev_register_lock);
|
||||
|
||||
static const char * const dnames[] = {
|
||||
"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
|
||||
"net", "osd"
|
||||
};
|
||||
|
||||
#define DVB_MAX_ADAPTERS 8
|
||||
#define DVB_MAX_IDS 4
|
||||
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
|
||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
||||
|
||||
static struct class *dvb_class;
|
||||
|
||||
static struct dvb_device* dvbdev_find_device (int minor)
|
||||
{
|
||||
struct list_head *entry;
|
||||
|
||||
list_for_each (entry, &dvb_adapter_list) {
|
||||
struct list_head *entry0;
|
||||
struct dvb_adapter *adap;
|
||||
adap = list_entry (entry, struct dvb_adapter, list_head);
|
||||
list_for_each (entry0, &adap->device_list) {
|
||||
struct dvb_device *dev;
|
||||
dev = list_entry (entry0, struct dvb_device, list_head);
|
||||
if (nums2minor(adap->num, dev->type, dev->id) == minor)
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int dvb_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
|
||||
dvbdev = dvbdev_find_device (iminor(inode));
|
||||
|
||||
if (dvbdev && dvbdev->fops) {
|
||||
int err = 0;
|
||||
const struct file_operations *old_fops;
|
||||
|
||||
file->private_data = dvbdev;
|
||||
old_fops = file->f_op;
|
||||
file->f_op = fops_get(dvbdev->fops);
|
||||
if(file->f_op->open)
|
||||
err = file->f_op->open(inode,file);
|
||||
if (err) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
return err;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
static struct file_operations dvb_device_fops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.open = dvb_device_open,
|
||||
};
|
||||
|
||||
static struct cdev dvb_device_cdev = {
|
||||
.kobj = {.name = "dvb", },
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
int dvb_generic_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
|
||||
if (!dvbdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!dvbdev->users)
|
||||
return -EBUSY;
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
if (!dvbdev->readers)
|
||||
return -EBUSY;
|
||||
dvbdev->readers--;
|
||||
} else {
|
||||
if (!dvbdev->writers)
|
||||
return -EBUSY;
|
||||
dvbdev->writers--;
|
||||
}
|
||||
|
||||
dvbdev->users--;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_generic_open);
|
||||
|
||||
|
||||
int dvb_generic_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
|
||||
if (!dvbdev)
|
||||
return -ENODEV;
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
dvbdev->readers++;
|
||||
} else {
|
||||
dvbdev->writers++;
|
||||
}
|
||||
|
||||
dvbdev->users++;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_generic_release);
|
||||
|
||||
|
||||
int dvb_generic_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
|
||||
if (!dvbdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!dvbdev->kernel_ioctl)
|
||||
return -EINVAL;
|
||||
|
||||
return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_generic_ioctl);
|
||||
|
||||
|
||||
static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
|
||||
{
|
||||
u32 id = 0;
|
||||
|
||||
while (id < DVB_MAX_IDS) {
|
||||
struct list_head *entry;
|
||||
list_for_each (entry, &adap->device_list) {
|
||||
struct dvb_device *dev;
|
||||
dev = list_entry (entry, struct dvb_device, list_head);
|
||||
if (dev->type == type && dev->id == id)
|
||||
goto skip;
|
||||
}
|
||||
return id;
|
||||
skip:
|
||||
id++;
|
||||
}
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
|
||||
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template, void *priv, int type)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
|
||||
int id;
|
||||
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
|
||||
if ((id = dvbdev_get_free_id (adap, type)) < 0){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
*pdvbdev = NULL;
|
||||
printk ("%s: could get find free device id...\n", __FUNCTION__);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
|
||||
|
||||
if (!dvbdev){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
|
||||
|
||||
if (!dvbdevfops){
|
||||
kfree (dvbdev);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(dvbdev, template, sizeof(struct dvb_device));
|
||||
dvbdev->type = type;
|
||||
dvbdev->id = id;
|
||||
dvbdev->adapter = adap;
|
||||
dvbdev->priv = priv;
|
||||
dvbdev->fops = dvbdevfops;
|
||||
|
||||
memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
|
||||
dvbdev->fops->owner = adap->module;
|
||||
|
||||
list_add_tail (&dvbdev->list_head, &adap->device_list);
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
|
||||
class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
|
||||
adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
|
||||
|
||||
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
||||
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
|
||||
nums2minor(adap->num, type, id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_register_device);
|
||||
|
||||
|
||||
void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||
{
|
||||
if (!dvbdev)
|
||||
return;
|
||||
|
||||
class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
|
||||
dvbdev->type, dvbdev->id)));
|
||||
|
||||
list_del (&dvbdev->list_head);
|
||||
kfree (dvbdev->fops);
|
||||
kfree (dvbdev);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_unregister_device);
|
||||
|
||||
|
||||
static int dvbdev_get_free_adapter_num (void)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
while (num < DVB_MAX_ADAPTERS) {
|
||||
struct list_head *entry;
|
||||
list_for_each (entry, &dvb_adapter_list) {
|
||||
struct dvb_adapter *adap;
|
||||
adap = list_entry (entry, struct dvb_adapter, list_head);
|
||||
if (adap->num == num)
|
||||
goto skip;
|
||||
}
|
||||
return num;
|
||||
skip:
|
||||
num++;
|
||||
}
|
||||
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
|
||||
int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
|
||||
{
|
||||
int num;
|
||||
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
|
||||
if ((num = dvbdev_get_free_adapter_num ()) < 0) {
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
memset (adap, 0, sizeof(struct dvb_adapter));
|
||||
INIT_LIST_HEAD (&adap->device_list);
|
||||
|
||||
printk ("DVB: registering new adapter (%s).\n", name);
|
||||
|
||||
adap->num = num;
|
||||
adap->name = name;
|
||||
adap->module = module;
|
||||
adap->device = device;
|
||||
|
||||
list_add_tail (&adap->list_head, &dvb_adapter_list);
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
|
||||
return num;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_register_adapter);
|
||||
|
||||
|
||||
int dvb_unregister_adapter(struct dvb_adapter *adap)
|
||||
{
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
list_del (&adap->list_head);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_unregister_adapter);
|
||||
|
||||
/* if the miracle happens and "generic_usercopy()" is included into
|
||||
the kernel, then this can vanish. please don't make the mistake and
|
||||
define this as video_usercopy(). this will introduce a dependecy
|
||||
to the v4l "videodev.o" module, which is unnecessary for some
|
||||
cards (ie. the budget dvb-cards don't need the v4l module...) */
|
||||
int dvb_usercopy(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg))
|
||||
{
|
||||
char sbuf[128];
|
||||
void *mbuf = NULL;
|
||||
void *parg = NULL;
|
||||
int err = -EINVAL;
|
||||
|
||||
/* Copy arguments into temp kernel buffer */
|
||||
switch (_IOC_DIR(cmd)) {
|
||||
case _IOC_NONE:
|
||||
/*
|
||||
* For this command, the pointer is actually an integer
|
||||
* argument.
|
||||
*/
|
||||
parg = (void *) arg;
|
||||
break;
|
||||
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
|
||||
case _IOC_WRITE:
|
||||
case (_IOC_WRITE | _IOC_READ):
|
||||
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
|
||||
parg = sbuf;
|
||||
} else {
|
||||
/* too big to allocate from stack */
|
||||
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
|
||||
if (NULL == mbuf)
|
||||
return -ENOMEM;
|
||||
parg = mbuf;
|
||||
}
|
||||
|
||||
err = -EFAULT;
|
||||
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
/* call driver */
|
||||
if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
|
||||
err = -EINVAL;
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
/* Copy results into user buffer */
|
||||
switch (_IOC_DIR(cmd))
|
||||
{
|
||||
case _IOC_READ:
|
||||
case (_IOC_WRITE | _IOC_READ):
|
||||
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(mbuf);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init init_dvbdev(void)
|
||||
{
|
||||
int retval;
|
||||
dev_t dev = MKDEV(DVB_MAJOR, 0);
|
||||
|
||||
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
|
||||
printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
|
||||
return retval;
|
||||
}
|
||||
|
||||
cdev_init(&dvb_device_cdev, &dvb_device_fops);
|
||||
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
|
||||
printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dvb_class = class_create(THIS_MODULE, "dvb");
|
||||
if (IS_ERR(dvb_class)) {
|
||||
retval = PTR_ERR(dvb_class);
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
cdev_del(&dvb_device_cdev);
|
||||
unregister_chrdev_region(dev, MAX_DVB_MINORS);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static void __exit exit_dvbdev(void)
|
||||
{
|
||||
class_destroy(dvb_class);
|
||||
cdev_del(&dvb_device_cdev);
|
||||
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
|
||||
}
|
||||
|
||||
module_init(init_dvbdev);
|
||||
module_exit(exit_dvbdev);
|
||||
|
||||
MODULE_DESCRIPTION("DVB Core Driver");
|
||||
MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
|
||||
MODULE_LICENSE("GPL");
|
||||
127
drivers/media/dvb/dvb-core/dvbdev.h
Normal file
127
drivers/media/dvb/dvb-core/dvbdev.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* dvbdev.h
|
||||
*
|
||||
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
|
||||
* for convergence integrated media GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Lesser Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DVBDEV_H_
|
||||
#define _DVBDEV_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/smp_lock.h>
|
||||
|
||||
#define DVB_MAJOR 212
|
||||
|
||||
#define DVB_DEVICE_VIDEO 0
|
||||
#define DVB_DEVICE_AUDIO 1
|
||||
#define DVB_DEVICE_SEC 2
|
||||
#define DVB_DEVICE_FRONTEND 3
|
||||
#define DVB_DEVICE_DEMUX 4
|
||||
#define DVB_DEVICE_DVR 5
|
||||
#define DVB_DEVICE_CA 6
|
||||
#define DVB_DEVICE_NET 7
|
||||
#define DVB_DEVICE_OSD 8
|
||||
|
||||
|
||||
struct dvb_adapter {
|
||||
int num;
|
||||
struct list_head list_head;
|
||||
struct list_head device_list;
|
||||
const char *name;
|
||||
u8 proposed_mac [6];
|
||||
void* priv;
|
||||
|
||||
struct device *device;
|
||||
|
||||
struct module *module;
|
||||
};
|
||||
|
||||
|
||||
struct dvb_device {
|
||||
struct list_head list_head;
|
||||
struct file_operations *fops;
|
||||
struct dvb_adapter *adapter;
|
||||
int type;
|
||||
u32 id;
|
||||
|
||||
/* in theory, 'users' can vanish now,
|
||||
but I don't want to change too much now... */
|
||||
int readers;
|
||||
int writers;
|
||||
int users;
|
||||
|
||||
/* don't really need those !? -- FIXME: use video_usercopy */
|
||||
int (*kernel_ioctl)(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
|
||||
extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
|
||||
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
|
||||
|
||||
extern int dvb_register_device (struct dvb_adapter *adap,
|
||||
struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template,
|
||||
void *priv,
|
||||
int type);
|
||||
|
||||
extern void dvb_unregister_device (struct dvb_device *dvbdev);
|
||||
|
||||
extern int dvb_generic_open (struct inode *inode, struct file *file);
|
||||
extern int dvb_generic_release (struct inode *inode, struct file *file);
|
||||
extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/* we don't mess with video_usercopy() any more,
|
||||
we simply define out own dvb_usercopy(), which will hopefully become
|
||||
generic_usercopy() someday... */
|
||||
|
||||
extern int dvb_usercopy(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg));
|
||||
|
||||
/** generic DVB attach function. */
|
||||
#ifdef CONFIG_DVB_CORE_ATTACH
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
void *__r = NULL; \
|
||||
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
|
||||
if (__a) { \
|
||||
__r = (void *) __a(ARGS); \
|
||||
if (__r == NULL) \
|
||||
symbol_put(FUNCTION); \
|
||||
} else { \
|
||||
printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#else
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
FUNCTION(ARGS); \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _DVBDEV_H_ */
|
||||
210
drivers/media/dvb/dvb-usb/Kconfig
Normal file
210
drivers/media/dvb/dvb-usb/Kconfig
Normal file
@@ -0,0 +1,210 @@
|
||||
config DVB_USB
|
||||
tristate "Support for various USB DVB devices"
|
||||
depends on DVB_CORE && USB && I2C
|
||||
select FW_LOADER
|
||||
select DVB_PLL
|
||||
help
|
||||
By enabling this you will be able to choose the various supported
|
||||
USB1.1 and USB2.0 DVB devices.
|
||||
|
||||
Almost every USB device needs a firmware, please look into
|
||||
<file:Documentation/dvb/README.dvb-usb>.
|
||||
|
||||
For a complete list of supported USB devices see the LinuxTV DVB Wiki:
|
||||
<http://www.linuxtv.org/wiki/index.php/DVB_USB>
|
||||
|
||||
Say Y if you own a USB DVB device.
|
||||
|
||||
config DVB_USB_DEBUG
|
||||
bool "Enable extended debug support for all DVB-USB devices"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y if you want to enable debugging. See modinfo dvb-usb (and the
|
||||
appropriate drivers) for debug levels.
|
||||
|
||||
config DVB_USB_A800
|
||||
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB3000MC
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
|
||||
|
||||
config DVB_USB_DIBUSB_MB
|
||||
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB3000MB
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
|
||||
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the Linux-DVB Wiki at www.linuxtv.org.
|
||||
|
||||
Say Y if you own such a device and want to use it. You should build it as
|
||||
a module.
|
||||
|
||||
config DVB_USB_DIBUSB_MB_FAULTY
|
||||
bool "Support faulty USB IDs"
|
||||
depends on DVB_USB_DIBUSB_MB
|
||||
help
|
||||
Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
|
||||
|
||||
config DVB_USB_DIBUSB_MC
|
||||
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB3000MC
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for USB2.0 DVB-T receivers based on reference designs made by
|
||||
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the Linux-DVB Wiki at www.linuxtv.org.
|
||||
|
||||
Say Y if you own such a device and want to use it. You should build it as
|
||||
a module.
|
||||
|
||||
config DVB_USB_DIB0700
|
||||
tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB7000P
|
||||
select DVB_DIB7000M
|
||||
select DVB_DIB3000MC
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
|
||||
USB bridge is also present in devices having the DiB7700 DVB-T-USB
|
||||
silicon. This chip can be found in devices offered by Hauppauge,
|
||||
Avermedia and other big and small companies.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the Linux-DVB Wiki at www.linuxtv.org.
|
||||
|
||||
Say Y if you own such a device and want to use it. You should build it as
|
||||
a module.
|
||||
|
||||
config DVB_USB_UMT_010
|
||||
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB3000MC
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
|
||||
|
||||
config DVB_USB_CXUSB
|
||||
tristate "Conexant USB2.0 hybrid reference design support"
|
||||
depends on DVB_USB
|
||||
select DVB_CX22702 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Conexant USB2.0 hybrid reference design.
|
||||
Currently, only DVB and ATSC modes are supported, analog mode
|
||||
shall be added in the future. Devices that require this module:
|
||||
|
||||
Medion MD95700 hybrid USB2.0 device.
|
||||
DViCO FusionHDTV (Bluebird) USB2.0 devices
|
||||
|
||||
config DVB_USB_M920X
|
||||
tristate "Uli m920x DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
|
||||
Currently, only devices with a product id of
|
||||
"DTV USB MINI" (in cold state) are supported.
|
||||
Firmware required.
|
||||
|
||||
config DVB_USB_GL861
|
||||
tristate "Genesys Logic GL861 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
|
||||
receiver with USB ID 0db0:5581.
|
||||
|
||||
config DVB_USB_AU6610
|
||||
tristate "Alcor Micro AU6610 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_DIGITV
|
||||
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
|
||||
|
||||
config DVB_USB_VP7045
|
||||
tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the
|
||||
|
||||
TwinhanDTV Alpha (stick) (VP-7045),
|
||||
TwinhanDTV MagicBox II (VP-7046),
|
||||
DigitalNow TinyUSB 2 DVB-t,
|
||||
DigitalRise USB 2.0 Ter (Beetle) and
|
||||
TYPHOON DVB-T USB DRIVE
|
||||
|
||||
DVB-T USB2.0 receivers.
|
||||
|
||||
config DVB_USB_VP702X
|
||||
tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the
|
||||
|
||||
TwinhanDTV StarBox,
|
||||
DigitalRise USB Starbox and
|
||||
TYPHOON DVB-S USB 2.0 BOX
|
||||
|
||||
DVB-S USB2.0 receivers.
|
||||
|
||||
config DVB_USB_GP8PSK
|
||||
tristate "GENPIX 8PSK->USB module support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the
|
||||
GENPIX 8psk module
|
||||
|
||||
DVB-S USB2.0 receivers.
|
||||
|
||||
config DVB_USB_NOVA_T_USB2
|
||||
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB3000MC
|
||||
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_TTUSB2
|
||||
tristate "Pinnacle 400e DVB-S USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
|
||||
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA826X if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
|
||||
firmware protocol used by this module is similar to the one used by the
|
||||
old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko.
|
||||
|
||||
config DVB_USB_DTT200U
|
||||
tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
|
||||
|
||||
The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
|
||||
|
||||
The WT-220U and its clones are pen-sized.
|
||||
54
drivers/media/dvb/dvb-usb/Makefile
Normal file
54
drivers/media/dvb/dvb-usb/Makefile
Normal file
@@ -0,0 +1,54 @@
|
||||
dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o
|
||||
obj-$(CONFIG_DVB_USB) += dvb-usb.o
|
||||
|
||||
dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
|
||||
obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
|
||||
|
||||
dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
|
||||
obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
|
||||
|
||||
dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
|
||||
obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
|
||||
|
||||
dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
|
||||
obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
|
||||
|
||||
dvb-usb-dibusb-common-objs = dibusb-common.o
|
||||
|
||||
dvb-usb-a800-objs = a800.o
|
||||
obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
|
||||
|
||||
dvb-usb-dibusb-mb-objs = dibusb-mb.o
|
||||
obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
|
||||
|
||||
dvb-usb-dibusb-mc-objs = dibusb-mc.o
|
||||
obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
|
||||
|
||||
dvb-usb-nova-t-usb2-objs = nova-t-usb2.o
|
||||
obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
|
||||
|
||||
dvb-usb-umt-010-objs = umt-010.o
|
||||
obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
|
||||
|
||||
dvb-usb-m920x-objs = m920x.o
|
||||
obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
|
||||
|
||||
dvb-usb-gl861-objs = gl861.o
|
||||
obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
|
||||
|
||||
dvb-usb-au6610-objs = au6610.o
|
||||
obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
|
||||
|
||||
dvb-usb-digitv-objs = digitv.o
|
||||
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
|
||||
|
||||
dvb-usb-cxusb-objs = cxusb.o
|
||||
obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
|
||||
|
||||
dvb-usb-ttusb2-objs = ttusb2.o
|
||||
obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
|
||||
|
||||
dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
|
||||
obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
|
||||
|
||||
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
193
drivers/media/dvb/dvb-usb/a800.c
Normal file
193
drivers/media/dvb/dvb-usb/a800.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
|
||||
* USB2.0 (A800) DVB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* Thanks to
|
||||
* - AVerMedia who kindly provided information and
|
||||
* - Glen Harris who suffered from my mistakes during development.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dibusb.h"
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
#define deb_rc(args...) dprintk(debug,0x01,args)
|
||||
|
||||
static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
/* do nothing for the AVerMedia */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* assure to put cold to 0 for iManufacturer == 1 */
|
||||
static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold)
|
||||
{
|
||||
*cold = udev->descriptor.iManufacturer != 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key a800_rc_keys[] = {
|
||||
{ 0x02, 0x01, KEY_PROG1 }, /* SOURCE */
|
||||
{ 0x02, 0x00, KEY_POWER }, /* POWER */
|
||||
{ 0x02, 0x05, KEY_1 }, /* 1 */
|
||||
{ 0x02, 0x06, KEY_2 }, /* 2 */
|
||||
{ 0x02, 0x07, KEY_3 }, /* 3 */
|
||||
{ 0x02, 0x09, KEY_4 }, /* 4 */
|
||||
{ 0x02, 0x0a, KEY_5 }, /* 5 */
|
||||
{ 0x02, 0x0b, KEY_6 }, /* 6 */
|
||||
{ 0x02, 0x0d, KEY_7 }, /* 7 */
|
||||
{ 0x02, 0x0e, KEY_8 }, /* 8 */
|
||||
{ 0x02, 0x0f, KEY_9 }, /* 9 */
|
||||
{ 0x02, 0x12, KEY_LEFT }, /* L / DISPLAY */
|
||||
{ 0x02, 0x11, KEY_0 }, /* 0 */
|
||||
{ 0x02, 0x13, KEY_RIGHT }, /* R / CH RTN */
|
||||
{ 0x02, 0x17, KEY_PROG2 }, /* SNAP SHOT */
|
||||
{ 0x02, 0x10, KEY_PROG3 }, /* 16-CH PREV */
|
||||
{ 0x02, 0x1e, KEY_VOLUMEDOWN }, /* VOL DOWN */
|
||||
{ 0x02, 0x0c, KEY_ZOOM }, /* FULL SCREEN */
|
||||
{ 0x02, 0x1f, KEY_VOLUMEUP }, /* VOL UP */
|
||||
{ 0x02, 0x14, KEY_MUTE }, /* MUTE */
|
||||
{ 0x02, 0x08, KEY_AUDIO }, /* AUDIO */
|
||||
{ 0x02, 0x19, KEY_RECORD }, /* RECORD */
|
||||
{ 0x02, 0x18, KEY_PLAY }, /* PLAY */
|
||||
{ 0x02, 0x1b, KEY_STOP }, /* STOP */
|
||||
{ 0x02, 0x1a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
|
||||
{ 0x02, 0x1d, KEY_BACK }, /* << / RED */
|
||||
{ 0x02, 0x1c, KEY_FORWARD }, /* >> / YELLOW */
|
||||
{ 0x02, 0x03, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x02, 0x04, KEY_EPG }, /* EPG */
|
||||
{ 0x02, 0x15, KEY_MENU }, /* MENU */
|
||||
|
||||
{ 0x03, 0x03, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x03, 0x01, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x03, 0x00, KEY_LAST }, /* >>| / BLUE */
|
||||
|
||||
};
|
||||
|
||||
static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 key[5];
|
||||
if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
|
||||
0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
|
||||
2000) != 5)
|
||||
return -ENODEV;
|
||||
|
||||
/* call the universal NEC remote processor, to find out the key's state and event */
|
||||
dvb_usb_nec_rc_key_to_event(d,key,event,state);
|
||||
if (key[0] != 0)
|
||||
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties a800_properties;
|
||||
|
||||
static int a800_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE,NULL);
|
||||
}
|
||||
|
||||
/* do not change the order of the ID table */
|
||||
static struct usb_device_id a800_table [] = {
|
||||
/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) },
|
||||
/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, a800_table);
|
||||
|
||||
static struct dvb_usb_device_properties a800_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-avertv-a800-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
|
||||
.frontend_attach = dibusb_dib3000mc_frontend_attach,
|
||||
.tuner_attach = dibusb_dib3000mc_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = a800_power_ctrl,
|
||||
.identify_state = a800_identify_state,
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = a800_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(a800_rc_keys),
|
||||
.rc_query = a800_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "AVerMedia AverTV DVB-T USB 2.0 (A800)",
|
||||
{ &a800_table[0], NULL },
|
||||
{ &a800_table[1], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver a800_driver = {
|
||||
.name = "dvb_usb_a800",
|
||||
.probe = a800_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = a800_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init a800_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&a800_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit a800_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&a800_driver);
|
||||
}
|
||||
|
||||
module_init (a800_module_init);
|
||||
module_exit (a800_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
255
drivers/media/dvb/dvb-usb/au6610.c
Normal file
255
drivers/media/dvb/dvb-usb/au6610.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
|
||||
#include "au6610.h"
|
||||
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_au6610_debug;
|
||||
module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
int ret;
|
||||
u16 index;
|
||||
u8 usb_buf[6]; /* enough for all known requests,
|
||||
read returns 5 and write 6 bytes */
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0] << 8;
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0] << 8;
|
||||
index += wbuf[1];
|
||||
break;
|
||||
default:
|
||||
warn("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
|
||||
USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
|
||||
sizeof(usb_buf), AU6610_USB_TIMEOUT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (operation) {
|
||||
case AU6610_REQ_I2C_READ:
|
||||
case AU6610_REQ_USB_READ:
|
||||
/* requested value is always 5th byte in buffer */
|
||||
rbuf[0] = usb_buf[4];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u8 request;
|
||||
u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
|
||||
if (wo) {
|
||||
request = AU6610_REQ_I2C_WRITE;
|
||||
} else { /* rw */
|
||||
request = AU6610_REQ_I2C_READ;
|
||||
}
|
||||
|
||||
return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
|
||||
}
|
||||
|
||||
|
||||
/* I2C */
|
||||
static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf,
|
||||
msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static u32 au6610_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm au6610_i2c_algo = {
|
||||
.master_xfer = au6610_i2c_xfer,
|
||||
.functionality = au6610_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int au6610_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zl10353_config au6610_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
|
||||
&adap->dev->i2c_adap)) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct qt1010_config au6610_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
};
|
||||
|
||||
static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe, &adap->dev->i2c_adap,
|
||||
&au6610_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties au6610_properties;
|
||||
|
||||
static int au6610_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
|
||||
return -ENODEV;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
|
||||
alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
|
||||
|
||||
if (alt == NULL) {
|
||||
deb_rc("no alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct usb_device_id au6610_table [] = {
|
||||
{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, au6610_table);
|
||||
|
||||
static struct dvb_usb_device_properties au6610_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.size_of_priv = 0,
|
||||
.identify_state = au6610_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = au6610_zl10353_frontend_attach,
|
||||
.tuner_attach = au6610_qt1010_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 40,
|
||||
.framesize = 942, /* maximum packet size */
|
||||
.interval = 1.25, /* 125 us */
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.i2c_algo = &au6610_i2c_algo,
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
"Sigmatek DVB-110 DVB-T USB2.0",
|
||||
{ &au6610_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver au6610_driver = {
|
||||
.name = "dvb_usb_au6610",
|
||||
.probe = au6610_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = au6610_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init au6610_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&au6610_driver))) {
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit au6610_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&au6610_driver);
|
||||
}
|
||||
|
||||
module_init (au6610_module_init);
|
||||
module_exit (au6610_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
19
drivers/media/dvb/dvb-usb/au6610.h
Normal file
19
drivers/media/dvb/dvb-usb/au6610.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _DVB_USB_AU6610_H_
|
||||
#define _DVB_USB_AU6610_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "au6610"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args)
|
||||
|
||||
#define AU6610_REQ_I2C_WRITE 0x14
|
||||
#define AU6610_REQ_I2C_READ 0x13
|
||||
#define AU6610_REQ_USB_WRITE 0x16
|
||||
#define AU6610_REQ_USB_READ 0x15
|
||||
|
||||
#define AU6610_USB_TIMEOUT 1000
|
||||
|
||||
#define AU6610_ALTSETTING_COUNT 6
|
||||
#define AU6610_ALTSETTING 5
|
||||
|
||||
#endif
|
||||
808
drivers/media/dvb/dvb-usb/cxusb.c
Normal file
808
drivers/media/dvb/dvb-usb/cxusb.c
Normal file
@@ -0,0 +1,808 @@
|
||||
/* DVB USB compliant linux driver for Conexant USB reference design.
|
||||
*
|
||||
* The Conexant reference design I saw on their website was only for analogue
|
||||
* capturing (using the cx25842). The box I took to write this driver (reverse
|
||||
* engineered) is the one labeled Medion MD95700. In addition to the cx25842
|
||||
* for analogue capturing it also has a cx22702 DVB-T demodulator on the main
|
||||
* board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
|
||||
*
|
||||
* Maybe it is a little bit premature to call this driver cxusb, but I assume
|
||||
* the USB protocol is identical or at least inherited from the reference
|
||||
* design, so it can be reused for the "analogue-only" device (if it will
|
||||
* appear at all).
|
||||
*
|
||||
* TODO: Use the cx25840-driver for the analogue part
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
|
||||
* Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "cxusb.h"
|
||||
|
||||
#include "cx22702.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "lgh06xf.h"
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#include "zl10353.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_cxusb_debug;
|
||||
module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int cxusb_ctrl_msg(struct dvb_usb_device *d,
|
||||
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
|
||||
{
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 sndbuf[1+wlen];
|
||||
memset(sndbuf, 0, 1+wlen);
|
||||
|
||||
sndbuf[0] = cmd;
|
||||
memcpy(&sndbuf[1], wbuf, wlen);
|
||||
if (wo)
|
||||
dvb_usb_generic_write(d, sndbuf, 1+wlen);
|
||||
else
|
||||
dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GPIO */
|
||||
static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
struct cxusb_state *st = d->priv;
|
||||
u8 o[2], i;
|
||||
|
||||
if (st->gpio_write_state[GPIO_TUNER] == onoff)
|
||||
return;
|
||||
|
||||
o[0] = GPIO_TUNER;
|
||||
o[1] = onoff;
|
||||
cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
|
||||
|
||||
if (i != 0x01)
|
||||
deb_info("gpio_write failed.\n");
|
||||
|
||||
st->gpio_write_state[GPIO_TUNER] = onoff;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
warn("more than two i2c messages at a time is not handled yet. TODO.");
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
|
||||
if (d->udev->descriptor.idVendor == USB_VID_MEDION)
|
||||
switch (msg[i].addr) {
|
||||
case 0x63:
|
||||
cxusb_gpio_tuner(d, 0);
|
||||
break;
|
||||
default:
|
||||
cxusb_gpio_tuner(d, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
|
||||
obuf[0] = msg[i].len;
|
||||
obuf[1] = msg[i+1].len;
|
||||
obuf[2] = msg[i].addr;
|
||||
memcpy(&obuf[3], msg[i].buf, msg[i].len);
|
||||
|
||||
if (cxusb_ctrl_msg(d, CMD_I2C_READ,
|
||||
obuf, 3+msg[i].len,
|
||||
ibuf, 1+msg[i+1].len) < 0)
|
||||
break;
|
||||
|
||||
if (ibuf[0] != 0x08)
|
||||
deb_i2c("i2c read may have failed\n");
|
||||
|
||||
memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
|
||||
|
||||
i++;
|
||||
} else { /* write */
|
||||
u8 obuf[2+msg[i].len], ibuf;
|
||||
obuf[0] = msg[i].addr;
|
||||
obuf[1] = msg[i].len;
|
||||
memcpy(&obuf[2], msg[i].buf, msg[i].len);
|
||||
|
||||
if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
|
||||
2+msg[i].len, &ibuf,1) < 0)
|
||||
break;
|
||||
if (ibuf != 0x08)
|
||||
deb_i2c("i2c write may have failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm cxusb_i2c_algo = {
|
||||
.master_xfer = cxusb_i2c_xfer,
|
||||
.functionality = cxusb_i2c_func,
|
||||
};
|
||||
|
||||
static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b = 0;
|
||||
if (onoff)
|
||||
return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
|
||||
else
|
||||
return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
|
||||
}
|
||||
|
||||
static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b = 0;
|
||||
if (onoff)
|
||||
return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
u8 buf[2] = { 0x03, 0x00 };
|
||||
if (onoff)
|
||||
cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0);
|
||||
else
|
||||
cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
u8 ircode[4];
|
||||
int i;
|
||||
|
||||
cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
|
||||
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[2] &&
|
||||
keymap[i].data == ircode[3]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
|
||||
{ 0xfe, 0x02, KEY_TV },
|
||||
{ 0xfe, 0x0e, KEY_MP3 },
|
||||
{ 0xfe, 0x1a, KEY_DVD },
|
||||
{ 0xfe, 0x1e, KEY_FAVORITES },
|
||||
{ 0xfe, 0x16, KEY_SETUP },
|
||||
{ 0xfe, 0x46, KEY_POWER2 },
|
||||
{ 0xfe, 0x0a, KEY_EPG },
|
||||
{ 0xfe, 0x49, KEY_BACK },
|
||||
{ 0xfe, 0x4d, KEY_MENU },
|
||||
{ 0xfe, 0x51, KEY_UP },
|
||||
{ 0xfe, 0x5b, KEY_LEFT },
|
||||
{ 0xfe, 0x5f, KEY_RIGHT },
|
||||
{ 0xfe, 0x53, KEY_DOWN },
|
||||
{ 0xfe, 0x5e, KEY_OK },
|
||||
{ 0xfe, 0x59, KEY_INFO },
|
||||
{ 0xfe, 0x55, KEY_TAB },
|
||||
{ 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
|
||||
{ 0xfe, 0x12, KEY_NEXTSONG }, /* Skip */
|
||||
{ 0xfe, 0x42, KEY_ENTER }, /* Windows/Start */
|
||||
{ 0xfe, 0x15, KEY_VOLUMEUP },
|
||||
{ 0xfe, 0x05, KEY_VOLUMEDOWN },
|
||||
{ 0xfe, 0x11, KEY_CHANNELUP },
|
||||
{ 0xfe, 0x09, KEY_CHANNELDOWN },
|
||||
{ 0xfe, 0x52, KEY_CAMERA },
|
||||
{ 0xfe, 0x5a, KEY_TUNER }, /* Live */
|
||||
{ 0xfe, 0x19, KEY_OPEN },
|
||||
{ 0xfe, 0x0b, KEY_1 },
|
||||
{ 0xfe, 0x17, KEY_2 },
|
||||
{ 0xfe, 0x1b, KEY_3 },
|
||||
{ 0xfe, 0x07, KEY_4 },
|
||||
{ 0xfe, 0x50, KEY_5 },
|
||||
{ 0xfe, 0x54, KEY_6 },
|
||||
{ 0xfe, 0x48, KEY_7 },
|
||||
{ 0xfe, 0x4c, KEY_8 },
|
||||
{ 0xfe, 0x58, KEY_9 },
|
||||
{ 0xfe, 0x13, KEY_ANGLE }, /* Aspect */
|
||||
{ 0xfe, 0x03, KEY_0 },
|
||||
{ 0xfe, 0x1f, KEY_ZOOM },
|
||||
{ 0xfe, 0x43, KEY_REWIND },
|
||||
{ 0xfe, 0x47, KEY_PLAYPAUSE },
|
||||
{ 0xfe, 0x4f, KEY_FASTFORWARD },
|
||||
{ 0xfe, 0x57, KEY_MUTE },
|
||||
{ 0xfe, 0x0d, KEY_STOP },
|
||||
{ 0xfe, 0x01, KEY_RECORD },
|
||||
{ 0xfe, 0x4e, KEY_POWER },
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key dvico_portable_rc_keys[] = {
|
||||
{ 0xfc, 0x02, KEY_SETUP }, /* Profile */
|
||||
{ 0xfc, 0x43, KEY_POWER2 },
|
||||
{ 0xfc, 0x06, KEY_EPG },
|
||||
{ 0xfc, 0x5a, KEY_BACK },
|
||||
{ 0xfc, 0x05, KEY_MENU },
|
||||
{ 0xfc, 0x47, KEY_INFO },
|
||||
{ 0xfc, 0x01, KEY_TAB },
|
||||
{ 0xfc, 0x42, KEY_PREVIOUSSONG },/* Replay */
|
||||
{ 0xfc, 0x49, KEY_VOLUMEUP },
|
||||
{ 0xfc, 0x09, KEY_VOLUMEDOWN },
|
||||
{ 0xfc, 0x54, KEY_CHANNELUP },
|
||||
{ 0xfc, 0x0b, KEY_CHANNELDOWN },
|
||||
{ 0xfc, 0x16, KEY_CAMERA },
|
||||
{ 0xfc, 0x40, KEY_TUNER }, /* ATV/DTV */
|
||||
{ 0xfc, 0x45, KEY_OPEN },
|
||||
{ 0xfc, 0x19, KEY_1 },
|
||||
{ 0xfc, 0x18, KEY_2 },
|
||||
{ 0xfc, 0x1b, KEY_3 },
|
||||
{ 0xfc, 0x1a, KEY_4 },
|
||||
{ 0xfc, 0x58, KEY_5 },
|
||||
{ 0xfc, 0x59, KEY_6 },
|
||||
{ 0xfc, 0x15, KEY_7 },
|
||||
{ 0xfc, 0x14, KEY_8 },
|
||||
{ 0xfc, 0x17, KEY_9 },
|
||||
{ 0xfc, 0x44, KEY_ANGLE }, /* Aspect */
|
||||
{ 0xfc, 0x55, KEY_0 },
|
||||
{ 0xfc, 0x07, KEY_ZOOM },
|
||||
{ 0xfc, 0x0a, KEY_REWIND },
|
||||
{ 0xfc, 0x08, KEY_PLAYPAUSE },
|
||||
{ 0xfc, 0x4b, KEY_FASTFORWARD },
|
||||
{ 0xfc, 0x5b, KEY_MUTE },
|
||||
{ 0xfc, 0x04, KEY_STOP },
|
||||
{ 0xfc, 0x56, KEY_RECORD },
|
||||
{ 0xfc, 0x57, KEY_POWER },
|
||||
{ 0xfc, 0x41, KEY_UNKNOWN }, /* INPUT */
|
||||
{ 0xfc, 0x00, KEY_UNKNOWN }, /* HD */
|
||||
};
|
||||
|
||||
static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
|
||||
static u8 reset [] = { RESET, 0x80 };
|
||||
static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
|
||||
static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
|
||||
static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
|
||||
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
|
||||
|
||||
mt352_write(fe, clock_config, sizeof(clock_config));
|
||||
udelay(200);
|
||||
mt352_write(fe, reset, sizeof(reset));
|
||||
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
|
||||
mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
|
||||
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
|
||||
{ /* used in both lgz201 and th7579 */
|
||||
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 };
|
||||
static u8 reset [] = { RESET, 0x80 };
|
||||
static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
|
||||
static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
|
||||
static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
|
||||
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
|
||||
|
||||
mt352_write(fe, clock_config, sizeof(clock_config));
|
||||
udelay(200);
|
||||
mt352_write(fe, reset, sizeof(reset));
|
||||
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
|
||||
mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
|
||||
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cx22702_config cxusb_cx22702_config = {
|
||||
.demod_address = 0x63,
|
||||
.output_mode = CX22702_PARALLEL_OUTPUT,
|
||||
};
|
||||
|
||||
static struct lgdt330x_config cxusb_lgdt3303_config = {
|
||||
.demod_address = 0x0e,
|
||||
.demod_chip = LGDT3303,
|
||||
};
|
||||
|
||||
static struct mt352_config cxusb_dee1601_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = cxusb_dee1601_demod_init,
|
||||
};
|
||||
|
||||
static struct zl10353_config cxusb_zl10353_dee1601_config = {
|
||||
.demod_address = 0x0f,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static struct mt352_config cxusb_mt352_config = {
|
||||
/* used in both lgz201 and th7579 */
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = cxusb_mt352_demod_init,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
|
||||
adap->pll_addr = 0x61;
|
||||
memcpy(adap->pll_init, bpll, 4);
|
||||
adap->pll_desc = &dvb_pll_fmd1216me;
|
||||
|
||||
adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
|
||||
adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
|
||||
NULL, &dvb_pll_thomson_dtt7579);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
|
||||
NULL, &dvb_pll_thomson_dtt7579);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 b;
|
||||
if (usb_set_interface(adap->dev->udev, 0, 6) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
|
||||
|
||||
if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
|
||||
&adap->dev->i2c_adap)) != NULL)
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev, 0, 7) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
|
||||
|
||||
if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config,
|
||||
&adap->dev->i2c_adap)) != NULL)
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
/* used in both lgz201 and th7579 */
|
||||
if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
|
||||
|
||||
if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
|
||||
&adap->dev->i2c_adap)) != NULL)
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
|
||||
|
||||
if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
|
||||
&adap->dev->i2c_adap)) != NULL) ||
|
||||
((adap->fe = dvb_attach(zl10353_attach,
|
||||
&cxusb_zl10353_dee1601_config,
|
||||
&adap->dev->i2c_adap)) != NULL))
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* DViCO bluebird firmware needs the "warm" product ID to be patched into the
|
||||
* firmware file before download.
|
||||
*/
|
||||
|
||||
#define BLUEBIRD_01_ID_OFFSET 6638
|
||||
static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
|
||||
return -EINVAL;
|
||||
|
||||
if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
|
||||
fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
|
||||
|
||||
fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
|
||||
le16_to_cpu(udev->descriptor.idProduct) + 1;
|
||||
fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
|
||||
le16_to_cpu(udev->descriptor.idProduct) >> 8;
|
||||
|
||||
return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties cxusb_medion_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
|
||||
|
||||
static int cxusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct usb_device_id cxusb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, cxusb_table);
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_medion_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_cx22702_frontend_attach,
|
||||
.tuner_attach = cxusb_fmd1216me_tuner_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
},
|
||||
.power_ctrl = cxusb_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Medion MD95700 (MDUSBTV-HYBRID)",
|
||||
{ NULL },
|
||||
{ &cxusb_table[0], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-bluebird-01.fw",
|
||||
.download_firmware = bluebird_patch_dvico_firmware_download,
|
||||
/* use usb alt setting 0 for EP4 transfer (dvb-t),
|
||||
use usb alt setting 7 for EP2 transfer (atsc) */
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_lgdt3303_frontend_attach,
|
||||
.tuner_attach = cxusb_lgh064f_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = cxusb_bluebird_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = dvico_portable_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
|
||||
.rc_query = cxusb_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "DViCO FusionHDTV5 USB Gold",
|
||||
{ &cxusb_table[1], NULL },
|
||||
{ &cxusb_table[2], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-bluebird-01.fw",
|
||||
.download_firmware = bluebird_patch_dvico_firmware_download,
|
||||
/* use usb alt setting 0 for EP4 transfer (dvb-t),
|
||||
use usb alt setting 7 for EP2 transfer (atsc) */
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_dee1601_frontend_attach,
|
||||
.tuner_attach = cxusb_dee1601_tuner_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x04,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = cxusb_bluebird_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.rc_interval = 150,
|
||||
.rc_key_map = dvico_mce_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
|
||||
.rc_query = cxusb_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 3,
|
||||
.devices = {
|
||||
{ "DViCO FusionHDTV DVB-T Dual USB",
|
||||
{ &cxusb_table[3], NULL },
|
||||
{ &cxusb_table[4], NULL },
|
||||
},
|
||||
{ "DigitalNow DVB-T Dual USB",
|
||||
{ &cxusb_table[9], NULL },
|
||||
{ &cxusb_table[10], NULL },
|
||||
},
|
||||
{ "DViCO FusionHDTV DVB-T Dual Digital 2",
|
||||
{ &cxusb_table[11], NULL },
|
||||
{ &cxusb_table[12], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-bluebird-01.fw",
|
||||
.download_firmware = bluebird_patch_dvico_firmware_download,
|
||||
/* use usb alt setting 0 for EP4 transfer (dvb-t),
|
||||
use usb alt setting 7 for EP2 transfer (atsc) */
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_mt352_frontend_attach,
|
||||
.tuner_attach = cxusb_lgz201_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x04,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
.power_ctrl = cxusb_bluebird_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = dvico_portable_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
|
||||
.rc_query = cxusb_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "DViCO FusionHDTV DVB-T USB (LGZ201)",
|
||||
{ &cxusb_table[5], NULL },
|
||||
{ &cxusb_table[6], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-bluebird-01.fw",
|
||||
.download_firmware = bluebird_patch_dvico_firmware_download,
|
||||
/* use usb alt setting 0 for EP4 transfer (dvb-t),
|
||||
use usb alt setting 7 for EP2 transfer (atsc) */
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_mt352_frontend_attach,
|
||||
.tuner_attach = cxusb_dtt7579_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x04,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
.power_ctrl = cxusb_bluebird_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = dvico_portable_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
|
||||
.rc_query = cxusb_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "DViCO FusionHDTV DVB-T USB (TH7579)",
|
||||
{ &cxusb_table[7], NULL },
|
||||
{ &cxusb_table[8], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver cxusb_driver = {
|
||||
.name = "dvb_usb_cxusb",
|
||||
.probe = cxusb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = cxusb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init cxusb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&cxusb_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cxusb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&cxusb_driver);
|
||||
}
|
||||
|
||||
module_init (cxusb_module_init);
|
||||
module_exit (cxusb_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
|
||||
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
|
||||
MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
|
||||
MODULE_VERSION("1.0-alpha");
|
||||
MODULE_LICENSE("GPL");
|
||||
35
drivers/media/dvb/dvb-usb/cxusb.h
Normal file
35
drivers/media/dvb/dvb-usb/cxusb.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _DVB_USB_CXUSB_H_
|
||||
#define _DVB_USB_CXUSB_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "cxusb"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_cxusb_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args)
|
||||
#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
|
||||
dprintk(dvb_usb_cxusb_debug,0x01,args)
|
||||
|
||||
/* usb commands - some of it are guesses, don't have a reference yet */
|
||||
#define CMD_I2C_WRITE 0x08
|
||||
#define CMD_I2C_READ 0x09
|
||||
|
||||
#define CMD_GPIO_READ 0x0d
|
||||
#define CMD_GPIO_WRITE 0x0e
|
||||
#define GPIO_TUNER 0x02
|
||||
|
||||
#define CMD_POWER_OFF 0xdc
|
||||
#define CMD_POWER_ON 0xde
|
||||
|
||||
#define CMD_STREAMING_ON 0x36
|
||||
#define CMD_STREAMING_OFF 0x37
|
||||
|
||||
#define CMD_GET_IR_CODE 0x47
|
||||
|
||||
#define CMD_ANALOG 0x50
|
||||
#define CMD_DIGITAL 0x51
|
||||
|
||||
struct cxusb_state {
|
||||
u8 gpio_write_state[3];
|
||||
};
|
||||
|
||||
#endif
|
||||
54
drivers/media/dvb/dvb-usb/dib0700.h
Normal file
54
drivers/media/dvb/dvb-usb/dib0700.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* Copyright (C) 2005-6 DiBcom, SA
|
||||
*/
|
||||
#ifndef _DIB0700_H_
|
||||
#define _DIB0700_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dib0700"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "dib07x0.h"
|
||||
|
||||
extern int dvb_usb_dib0700_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args)
|
||||
#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
|
||||
#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args)
|
||||
|
||||
#define REQUEST_I2C_READ 0x2
|
||||
#define REQUEST_I2C_WRITE 0x3
|
||||
#define REQUEST_POLL_RC 0x4
|
||||
#define REQUEST_JUMPRAM 0x8
|
||||
#define REQUEST_SET_CLOCK 0xB
|
||||
#define REQUEST_SET_GPIO 0xC
|
||||
#define REQUEST_ENABLE_VIDEO 0xF
|
||||
// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
|
||||
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
|
||||
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
|
||||
#define REQUEST_GET_VERSION 0x15
|
||||
|
||||
struct dib0700_state {
|
||||
u8 channel_state;
|
||||
u16 mt2060_if1[2];
|
||||
|
||||
u8 is_dib7000pc;
|
||||
};
|
||||
|
||||
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
|
||||
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
|
||||
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
|
||||
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
|
||||
extern struct i2c_algorithm dib0700_i2c_algo;
|
||||
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold);
|
||||
|
||||
extern int dib0700_device_count;
|
||||
extern struct dvb_usb_device_properties dib0700_devices[];
|
||||
extern struct usb_device_id dib0700_usb_id_table[];
|
||||
|
||||
#endif
|
||||
311
drivers/media/dvb/dvb-usb/dib0700_core.c
Normal file
311
drivers/media/dvb/dvb-usb/dib0700_core.c
Normal file
@@ -0,0 +1,311 @@
|
||||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* Copyright (C) 2005-6 DiBcom, SA
|
||||
*/
|
||||
#include "dib0700.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_dib0700_debug;
|
||||
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
/* expecting rx buffer: request data[0] data[1] ... data[2] */
|
||||
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
|
||||
{
|
||||
int status;
|
||||
|
||||
deb_data(">>> ");
|
||||
debug_dump(tx,txlen,deb_data);
|
||||
|
||||
status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
|
||||
tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
|
||||
if (status != txlen)
|
||||
deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
|
||||
|
||||
return status < 0 ? status : 0;
|
||||
}
|
||||
|
||||
/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
|
||||
static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
|
||||
{
|
||||
u16 index, value;
|
||||
int status;
|
||||
|
||||
if (txlen < 2) {
|
||||
err("tx buffer length is smaller than 2. Makes no sense.");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (txlen > 4) {
|
||||
err("tx buffer length is larger than 4. Not supported.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
deb_data(">>> ");
|
||||
debug_dump(tx,txlen,deb_data);
|
||||
|
||||
value = ((txlen - 2) << 8) | tx[1];
|
||||
index = 0;
|
||||
if (txlen > 2)
|
||||
index |= (tx[2] << 8);
|
||||
if (txlen > 3)
|
||||
index |= tx[3];
|
||||
|
||||
/* think about swapping here */
|
||||
value = le16_to_cpu(value);
|
||||
index = le16_to_cpu(index);
|
||||
|
||||
status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
|
||||
USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
|
||||
if (status < 0)
|
||||
deb_info("ep 0 read error (status = %d)\n",status);
|
||||
|
||||
deb_data("<<< ");
|
||||
debug_dump(rx,rxlen,deb_data);
|
||||
|
||||
return status; /* length in case of success */
|
||||
}
|
||||
|
||||
int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
|
||||
{
|
||||
u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
|
||||
return dib0700_ctrl_wr(d,buf,3);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C master xfer function
|
||||
*/
|
||||
static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i,len;
|
||||
u8 buf[255];
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* fill in the address */
|
||||
buf[1] = (msg[i].addr << 1);
|
||||
/* fill the buffer */
|
||||
memcpy(&buf[2], msg[i].buf, msg[i].len);
|
||||
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
buf[0] = REQUEST_I2C_READ;
|
||||
buf[1] |= 1;
|
||||
|
||||
/* special thing in the current firmware: when length is zero the read-failed */
|
||||
if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
|
||||
deb_info("I2C read failed on address %x\n", msg[i].addr);
|
||||
break;
|
||||
}
|
||||
|
||||
msg[i+1].len = len;
|
||||
|
||||
i++;
|
||||
} else {
|
||||
buf[0] = REQUEST_I2C_WRITE;
|
||||
if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
struct i2c_algorithm dib0700_i2c_algo = {
|
||||
.master_xfer = dib0700_i2c_xfer,
|
||||
.functionality = dib0700_i2c_func,
|
||||
};
|
||||
|
||||
int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold)
|
||||
{
|
||||
u8 b[16];
|
||||
s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
|
||||
REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
|
||||
|
||||
deb_info("FW GET_VERSION length: %d\n",ret);
|
||||
|
||||
*cold = ret <= 0;
|
||||
|
||||
deb_info("cold: %d\n", *cold);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
|
||||
u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
|
||||
u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
|
||||
{
|
||||
u8 b[10];
|
||||
b[0] = REQUEST_SET_CLOCK;
|
||||
b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
|
||||
b[2] = (pll_prediv >> 8) & 0xff; // MSB
|
||||
b[3] = pll_prediv & 0xff; // LSB
|
||||
b[4] = (pll_loopdiv >> 8) & 0xff; // MSB
|
||||
b[5] = pll_loopdiv & 0xff; // LSB
|
||||
b[6] = (free_div >> 8) & 0xff; // MSB
|
||||
b[7] = free_div & 0xff; // LSB
|
||||
b[8] = (dsuScaler >> 8) & 0xff; // MSB
|
||||
b[9] = dsuScaler & 0xff; // LSB
|
||||
|
||||
return dib0700_ctrl_wr(d, b, 10);
|
||||
}
|
||||
|
||||
int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
|
||||
{
|
||||
switch (clk_MHz) {
|
||||
case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib0700_jumpram(struct usb_device *udev, u32 address)
|
||||
{
|
||||
int ret, actlen;
|
||||
u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
|
||||
(address >> 24) & 0xff,
|
||||
(address >> 16) & 0xff,
|
||||
(address >> 8) & 0xff,
|
||||
address & 0xff };
|
||||
|
||||
if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
|
||||
deb_fw("jumpram to 0x%x failed\n",address);
|
||||
return ret;
|
||||
}
|
||||
if (actlen != 8) {
|
||||
deb_fw("jumpram to 0x%x failed\n",address);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
|
||||
{
|
||||
struct hexline hx;
|
||||
int pos = 0, ret, act_len;
|
||||
|
||||
u8 buf[260];
|
||||
|
||||
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
|
||||
deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
|
||||
|
||||
buf[0] = hx.len;
|
||||
buf[1] = (hx.addr >> 8) & 0xff;
|
||||
buf[2] = hx.addr & 0xff;
|
||||
buf[3] = hx.type;
|
||||
memcpy(&buf[4],hx.data,hx.len);
|
||||
buf[4+hx.len] = hx.chk;
|
||||
|
||||
ret = usb_bulk_msg(udev,
|
||||
usb_sndbulkpipe(udev, 0x01),
|
||||
buf,
|
||||
hx.len + 5,
|
||||
&act_len,
|
||||
1000);
|
||||
|
||||
if (ret < 0) {
|
||||
err("firmware download failed at %d with %d",pos,ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* start the firmware */
|
||||
if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
|
||||
info("firmware started successfully.");
|
||||
msleep(500);
|
||||
}
|
||||
} else
|
||||
ret = -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
u8 b[4];
|
||||
|
||||
b[0] = REQUEST_ENABLE_VIDEO;
|
||||
b[1] = 0x00;
|
||||
b[2] = (0x01 << 4); /* Master mode */
|
||||
b[3] = 0x00;
|
||||
|
||||
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
|
||||
|
||||
if (onoff)
|
||||
st->channel_state |= 1 << adap->id;
|
||||
else
|
||||
st->channel_state &= ~(1 << adap->id);
|
||||
|
||||
b[2] |= st->channel_state;
|
||||
|
||||
if (st->channel_state) /* if at least one channel is active */
|
||||
b[1] = (0x01 << 4) | 0x00;
|
||||
|
||||
deb_info("data for streaming: %x %x\n",b[1],b[2]);
|
||||
|
||||
return dib0700_ctrl_wr(adap->dev, b, 4);
|
||||
}
|
||||
|
||||
static int dib0700_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dib0700_device_count; i++)
|
||||
if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_driver dib0700_driver = {
|
||||
.name = "dvb_usb_dib0700",
|
||||
.probe = dib0700_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dib0700_usb_id_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init dib0700_module_init(void)
|
||||
{
|
||||
int result;
|
||||
info("loaded with support for %d different device-types", dib0700_device_count);
|
||||
if ((result = usb_register(&dib0700_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dib0700_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&dib0700_driver);
|
||||
}
|
||||
|
||||
module_init (dib0700_module_init);
|
||||
module_exit (dib0700_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
|
||||
MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
378
drivers/media/dvb/dvb-usb/dib0700_devices.c
Normal file
378
drivers/media/dvb/dvb-usb/dib0700_devices.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* Copyright (C) 2005-6 DiBcom, SA
|
||||
*/
|
||||
#include "dib0700.h"
|
||||
|
||||
#include "dib3000mc.h"
|
||||
#include "dib7000m.h"
|
||||
#include "dib7000p.h"
|
||||
#include "mt2060.h"
|
||||
|
||||
static int force_lna_activation;
|
||||
module_param(force_lna_activation, int, 0644);
|
||||
MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
|
||||
"if applicable for the device (default: 0=automatic/off).");
|
||||
|
||||
/* Hauppauge Nova-T 500
|
||||
* has a LNA on GPIO0 which is enabled by setting 1 */
|
||||
static struct mt2060_config bristol_mt2060_config[2] = {
|
||||
{
|
||||
.i2c_address = 0x60,
|
||||
.clock_out = 3,
|
||||
}, {
|
||||
.i2c_address = 0x61,
|
||||
}
|
||||
};
|
||||
|
||||
static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
|
||||
.band_caps = BAND_VHF | BAND_UHF,
|
||||
.setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
|
||||
|
||||
.agc1_max = 42598,
|
||||
.agc1_min = 17694,
|
||||
.agc2_max = 45875,
|
||||
.agc2_min = 0,
|
||||
|
||||
.agc1_pt1 = 0,
|
||||
.agc1_pt2 = 59,
|
||||
|
||||
.agc1_slope1 = 0,
|
||||
.agc1_slope2 = 69,
|
||||
|
||||
.agc2_pt1 = 0,
|
||||
.agc2_pt2 = 59,
|
||||
|
||||
.agc2_slope1 = 111,
|
||||
.agc2_slope2 = 28,
|
||||
};
|
||||
|
||||
static struct dib3000mc_config bristol_dib3000mc_config[2] = {
|
||||
{ .agc = &bristol_dib3000p_mt2060_agc_config,
|
||||
.max_time = 0x196,
|
||||
.ln_adc_level = 0x1cc7,
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
},
|
||||
{ .agc = &bristol_dib3000p_mt2060_agc_config,
|
||||
.max_time = 0x196,
|
||||
.ln_adc_level = 0x1cc7,
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
if (adap->id == 0) {
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
|
||||
|
||||
if (force_lna_activation)
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
|
||||
else
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
|
||||
|
||||
if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
st->mt2060_if1[adap->id] = 1220;
|
||||
return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
|
||||
(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
|
||||
return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
|
||||
st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
|
||||
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
|
||||
BAND_UHF | BAND_VHF, // band_caps
|
||||
|
||||
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
|
||||
* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
|
||||
(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
|
||||
|
||||
712, // inv_gain
|
||||
41, // time_stabiliz
|
||||
|
||||
0, // alpha_level
|
||||
118, // thlock
|
||||
|
||||
0, // wbd_inv
|
||||
4095, // wbd_ref
|
||||
0, // wbd_sel
|
||||
0, // wbd_alpha
|
||||
|
||||
42598, // agc1_max
|
||||
17694, // agc1_min
|
||||
45875, // agc2_max
|
||||
2621, // agc2_min
|
||||
0, // agc1_pt1
|
||||
76, // agc1_pt2
|
||||
139, // agc1_pt3
|
||||
52, // agc1_slope1
|
||||
59, // agc1_slope2
|
||||
107, // agc2_pt1
|
||||
172, // agc2_pt2
|
||||
57, // agc2_slope1
|
||||
70, // agc2_slope2
|
||||
|
||||
21, // alpha_mant
|
||||
25, // alpha_exp
|
||||
28, // beta_mant
|
||||
48, // beta_exp
|
||||
|
||||
1, // perform_agc_softsplit
|
||||
{ 0, // split_min
|
||||
107, // split_max
|
||||
51800, // global_split_min
|
||||
24700 // global_split_max
|
||||
},
|
||||
};
|
||||
|
||||
static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
|
||||
BAND_UHF | BAND_VHF,
|
||||
|
||||
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
|
||||
* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
|
||||
(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
|
||||
|
||||
712, // inv_gain
|
||||
41, // time_stabiliz
|
||||
|
||||
0, // alpha_level
|
||||
118, // thlock
|
||||
|
||||
0, // wbd_inv
|
||||
4095, // wbd_ref
|
||||
0, // wbd_sel
|
||||
0, // wbd_alpha
|
||||
|
||||
42598, // agc1_max
|
||||
16384, // agc1_min
|
||||
42598, // agc2_max
|
||||
0, // agc2_min
|
||||
|
||||
0, // agc1_pt1
|
||||
137, // agc1_pt2
|
||||
255, // agc1_pt3
|
||||
|
||||
0, // agc1_slope1
|
||||
255, // agc1_slope2
|
||||
|
||||
0, // agc2_pt1
|
||||
0, // agc2_pt2
|
||||
|
||||
0, // agc2_slope1
|
||||
41, // agc2_slope2
|
||||
|
||||
15, // alpha_mant
|
||||
25, // alpha_exp
|
||||
|
||||
28, // beta_mant
|
||||
48, // beta_exp
|
||||
|
||||
0, // perform_agc_softsplit
|
||||
};
|
||||
|
||||
static struct dibx000_bandwidth_config stk7700p_pll_config = {
|
||||
60000, 30000, // internal, sampling
|
||||
1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
|
||||
0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
|
||||
(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
|
||||
60258167, // ifreq
|
||||
20452225, // timf
|
||||
};
|
||||
|
||||
static struct dib7000m_config stk7700p_dib7000m_config = {
|
||||
.dvbt_mode = 1,
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
.quartz_direct = 1,
|
||||
|
||||
.agc_config_count = 1,
|
||||
.agc = &stk7700p_7000m_mt2060_agc_config,
|
||||
.bw = &stk7700p_pll_config,
|
||||
|
||||
.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
|
||||
.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
|
||||
.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
|
||||
};
|
||||
|
||||
static struct dib7000p_config stk7700p_dib7000p_config = {
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc = &stk7700p_7000p_mt2060_agc_config,
|
||||
.bw = &stk7700p_pll_config,
|
||||
|
||||
.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
|
||||
.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
|
||||
.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
|
||||
};
|
||||
|
||||
static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
/* unless there is no real power management in DVB - we leave the device on GPIO6 */
|
||||
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50);
|
||||
|
||||
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
|
||||
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
|
||||
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
|
||||
dib0700_ctrl_clock(adap->dev, 72, 1);
|
||||
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);
|
||||
|
||||
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
|
||||
|
||||
st->mt2060_if1[0] = 1220;
|
||||
|
||||
if (dib7000pc_detection(&adap->dev->i2c_adap)) {
|
||||
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
|
||||
st->is_dib7000pc = 1;
|
||||
} else
|
||||
adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
|
||||
|
||||
return adap->fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static struct mt2060_config stk7700p_mt2060_config = {
|
||||
0x60
|
||||
};
|
||||
|
||||
static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
struct i2c_adapter *tun_i2c;
|
||||
|
||||
if (st->is_dib7000pc)
|
||||
tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
else
|
||||
tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
|
||||
return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
|
||||
st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
struct usb_device_id dib0700_usb_id_table[] = {
|
||||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
|
||||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
|
||||
|
||||
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
|
||||
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
|
||||
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
|
||||
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
|
||||
{ USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
|
||||
{ USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
|
||||
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
|
||||
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
|
||||
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
|
||||
#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER, \
|
||||
.usb_ctrl = DEVICE_SPECIFIC, \
|
||||
.firmware = "dvb-usb-dib0700-01.fw", \
|
||||
.download_firmware = dib0700_download_firmware, \
|
||||
.no_reconnect = 1, \
|
||||
.size_of_priv = sizeof(struct dib0700_state), \
|
||||
.i2c_algo = &dib0700_i2c_algo, \
|
||||
.identify_state = dib0700_identify_state
|
||||
|
||||
#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \
|
||||
.streaming_ctrl = dib0700_streaming_ctrl, \
|
||||
.stream = { \
|
||||
.type = USB_BULK, \
|
||||
.count = 4, \
|
||||
.endpoint = ep, \
|
||||
.u = { \
|
||||
.bulk = { \
|
||||
.buffersize = 39480, \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
struct dvb_usb_device_properties dib0700_devices[] = {
|
||||
{
|
||||
DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = stk7700p_frontend_attach,
|
||||
.tuner_attach = stk7700p_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 6,
|
||||
.devices = {
|
||||
{ "DiBcom STK7700P reference design",
|
||||
{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Hauppauge Nova-T Stick",
|
||||
{ &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "AVerMedia AVerTV DVB-T Volar",
|
||||
{ &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Compro Videomate U500",
|
||||
{ &dib0700_usb_id_table[6], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Uniwill STK7700P based (Hama and others)",
|
||||
{ &dib0700_usb_id_table[7], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Leadtek Winfast DTV Dongle (STK7700P based)",
|
||||
{ &dib0700_usb_id_table[8], NULL },
|
||||
{ NULL },
|
||||
}
|
||||
}
|
||||
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
|
||||
|
||||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = bristol_frontend_attach,
|
||||
.tuner_attach = bristol_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
}, {
|
||||
.frontend_attach = bristol_frontend_attach,
|
||||
.tuner_attach = bristol_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
|
||||
}
|
||||
},
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Hauppauge Nova-T 500 Dual DVB-T",
|
||||
{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
|
||||
21
drivers/media/dvb/dvb-usb/dib07x0.h
Normal file
21
drivers/media/dvb/dvb-usb/dib07x0.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef _DIB07X0_H_
|
||||
#define _DIB07X0_H_
|
||||
|
||||
enum dib07x0_gpios {
|
||||
GPIO0 = 0,
|
||||
GPIO1 = 2,
|
||||
GPIO2 = 3,
|
||||
GPIO3 = 4,
|
||||
GPIO4 = 5,
|
||||
GPIO5 = 6,
|
||||
GPIO6 = 8,
|
||||
GPIO7 = 10,
|
||||
GPIO8 = 11,
|
||||
GPIO9 = 14,
|
||||
GPIO10 = 15,
|
||||
};
|
||||
|
||||
#define GPIO_IN 0
|
||||
#define GPIO_OUT 1
|
||||
|
||||
#endif
|
||||
452
drivers/media/dvb/dvb-usb/dibusb-common.c
Normal file
452
drivers/media/dvb/dvb-usb/dibusb-common.c
Normal file
@@ -0,0 +1,452 @@
|
||||
/* Common methods for dibusb-based-receivers.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dibusb.h"
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define deb_info(args...) dprintk(debug,0x01,args)
|
||||
|
||||
/* common stuff used by the different dibusb modules */
|
||||
int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
if (st->ops.fifo_ctrl != NULL)
|
||||
if (st->ops.fifo_ctrl(adap->fe,onoff)) {
|
||||
err("error while controlling the fifo of the demod.");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_streaming_ctrl);
|
||||
|
||||
int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
|
||||
{
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
if (st->ops.pid_ctrl != NULL)
|
||||
st->ops.pid_ctrl(adap->fe,index,pid,onoff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_pid_filter);
|
||||
|
||||
int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
if (st->ops.pid_parse != NULL)
|
||||
if (st->ops.pid_parse(adap->fe,onoff) < 0)
|
||||
err("could not handle pid_parser");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
|
||||
|
||||
int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b[3];
|
||||
int ret;
|
||||
b[0] = DIBUSB_REQ_SET_IOCTL;
|
||||
b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
|
||||
b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
|
||||
ret = dvb_usb_generic_write(d,b,3);
|
||||
msleep(10);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_power_ctrl);
|
||||
|
||||
int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
u8 b[3] = { 0 };
|
||||
int ret;
|
||||
|
||||
if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
|
||||
return ret;
|
||||
|
||||
if (onoff) {
|
||||
b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
|
||||
b[1] = 0x00;
|
||||
if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
b[0] = DIBUSB_REQ_SET_IOCTL;
|
||||
b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
|
||||
return dvb_usb_generic_write(adap->dev,b,3);
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
|
||||
|
||||
int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
if (onoff) {
|
||||
u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
|
||||
return dvb_usb_generic_write(d,b,3);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb2_0_power_ctrl);
|
||||
|
||||
static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
|
||||
/* write only ? */
|
||||
int wo = (rbuf == NULL || rlen == 0),
|
||||
len = 2 + wlen + (wo ? 0 : 2);
|
||||
|
||||
sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
|
||||
sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
|
||||
|
||||
memcpy(&sndbuf[2],wbuf,wlen);
|
||||
|
||||
if (!wo) {
|
||||
sndbuf[wlen+2] = (rlen >> 8) & 0xff;
|
||||
sndbuf[wlen+3] = rlen & 0xff;
|
||||
}
|
||||
|
||||
return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C master xfer function
|
||||
*/
|
||||
static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
|
||||
msg[i+1].buf,msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
struct i2c_algorithm dibusb_i2c_algo = {
|
||||
.master_xfer = dibusb_i2c_xfer,
|
||||
.functionality = dibusb_i2c_func,
|
||||
};
|
||||
EXPORT_SYMBOL(dibusb_i2c_algo);
|
||||
|
||||
int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
|
||||
{
|
||||
u8 wbuf[1] = { offs };
|
||||
return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_read_eeprom_byte);
|
||||
|
||||
/* 3000MC/P stuff */
|
||||
// Config Adjacent channels Perf -cal22
|
||||
static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
|
||||
.band_caps = BAND_VHF | BAND_UHF,
|
||||
.setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
|
||||
|
||||
.agc1_max = 48497,
|
||||
.agc1_min = 23593,
|
||||
.agc2_max = 46531,
|
||||
.agc2_min = 24904,
|
||||
|
||||
.agc1_pt1 = 0x65,
|
||||
.agc1_pt2 = 0x69,
|
||||
|
||||
.agc1_slope1 = 0x51,
|
||||
.agc1_slope2 = 0x27,
|
||||
|
||||
.agc2_pt1 = 0,
|
||||
.agc2_pt2 = 0x33,
|
||||
|
||||
.agc2_slope1 = 0x35,
|
||||
.agc2_slope2 = 0x37,
|
||||
};
|
||||
|
||||
static struct dib3000mc_config stk3000p_dib3000p_config = {
|
||||
&dib3000p_mt2060_agc_config,
|
||||
|
||||
.max_time = 0x196,
|
||||
.ln_adc_level = 0x1cc7,
|
||||
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_command1 = 1,
|
||||
.agc_command2 = 1,
|
||||
};
|
||||
|
||||
static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
|
||||
.band_caps = BAND_VHF | BAND_UHF,
|
||||
.setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
|
||||
|
||||
.agc1_max = 56361,
|
||||
.agc1_min = 22282,
|
||||
.agc2_max = 47841,
|
||||
.agc2_min = 36045,
|
||||
|
||||
.agc1_pt1 = 0x3b,
|
||||
.agc1_pt2 = 0x6b,
|
||||
|
||||
.agc1_slope1 = 0x55,
|
||||
.agc1_slope2 = 0x1d,
|
||||
|
||||
.agc2_pt1 = 0,
|
||||
.agc2_pt2 = 0x0a,
|
||||
|
||||
.agc2_slope1 = 0x95,
|
||||
.agc2_slope2 = 0x1e,
|
||||
};
|
||||
|
||||
static struct dib3000mc_config mod3000p_dib3000p_config = {
|
||||
&dib3000p_panasonic_agc_config,
|
||||
|
||||
.max_time = 0x51,
|
||||
.ln_adc_level = 0x1cc7,
|
||||
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_command1 = 1,
|
||||
.agc_command2 = 1,
|
||||
};
|
||||
|
||||
int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL ||
|
||||
(adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) {
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
st->ops.pid_parse = dib3000mc_pid_parse;
|
||||
st->ops.pid_ctrl = dib3000mc_pid_control;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
|
||||
|
||||
static struct mt2060_config stk3000p_mt2060_config = {
|
||||
0x60
|
||||
};
|
||||
|
||||
int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dibusb_state *st = adap->priv;
|
||||
u8 a,b;
|
||||
u16 if1 = 1220;
|
||||
struct i2c_adapter *tun_i2c;
|
||||
|
||||
// First IF calibration for Liteon Sticks
|
||||
if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON &&
|
||||
adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
|
||||
|
||||
dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
|
||||
dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
|
||||
|
||||
if (a == 0x00)
|
||||
if1 += b;
|
||||
else if (a == 0x80)
|
||||
if1 -= b;
|
||||
else
|
||||
warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
|
||||
|
||||
} else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM &&
|
||||
adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
|
||||
u8 desc;
|
||||
dibusb_read_eeprom_byte(adap->dev, 7, &desc);
|
||||
if (desc == 2) {
|
||||
a = 127;
|
||||
do {
|
||||
dibusb_read_eeprom_byte(adap->dev, a, &desc);
|
||||
a--;
|
||||
} while (a > 7 && (desc == 0xff || desc == 0x00));
|
||||
if (desc & 0x80)
|
||||
if1 -= (0xff - desc);
|
||||
else
|
||||
if1 += desc;
|
||||
}
|
||||
}
|
||||
|
||||
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
|
||||
if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
|
||||
/* not found - use panasonic pll parameters */
|
||||
if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
st->mt2060_present = 1;
|
||||
/* set the correct parameters for the dib3000p */
|
||||
dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
|
||||
|
||||
/*
|
||||
* common remote control stuff
|
||||
*/
|
||||
struct dvb_usb_rc_key dibusb_rc_keys[] = {
|
||||
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
|
||||
{ 0x00, 0x16, KEY_POWER },
|
||||
{ 0x00, 0x10, KEY_MUTE },
|
||||
{ 0x00, 0x03, KEY_1 },
|
||||
{ 0x00, 0x01, KEY_2 },
|
||||
{ 0x00, 0x06, KEY_3 },
|
||||
{ 0x00, 0x09, KEY_4 },
|
||||
{ 0x00, 0x1d, KEY_5 },
|
||||
{ 0x00, 0x1f, KEY_6 },
|
||||
{ 0x00, 0x0d, KEY_7 },
|
||||
{ 0x00, 0x19, KEY_8 },
|
||||
{ 0x00, 0x1b, KEY_9 },
|
||||
{ 0x00, 0x15, KEY_0 },
|
||||
{ 0x00, 0x05, KEY_CHANNELUP },
|
||||
{ 0x00, 0x02, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x0a, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x11, KEY_RECORD },
|
||||
{ 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
|
||||
{ 0x00, 0x14, KEY_PLAY },
|
||||
{ 0x00, 0x1a, KEY_STOP },
|
||||
{ 0x00, 0x40, KEY_REWIND },
|
||||
{ 0x00, 0x12, KEY_FASTFORWARD },
|
||||
{ 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
|
||||
{ 0x00, 0x4c, KEY_PAUSE },
|
||||
{ 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
|
||||
{ 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
|
||||
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
|
||||
{ 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x00, 0x1c, KEY_EPG }, /* EPG */
|
||||
{ 0x00, 0x00, KEY_TAB }, /* Tab */
|
||||
{ 0x00, 0x48, KEY_INFO }, /* Preview */
|
||||
{ 0x00, 0x04, KEY_LIST }, /* RecordList */
|
||||
{ 0x00, 0x0f, KEY_TEXT }, /* Teletext */
|
||||
/* Key codes for the KWorld/ADSTech/JetWay remote. */
|
||||
{ 0x86, 0x12, KEY_POWER },
|
||||
{ 0x86, 0x0f, KEY_SELECT }, /* source */
|
||||
{ 0x86, 0x0c, KEY_UNKNOWN }, /* scan */
|
||||
{ 0x86, 0x0b, KEY_EPG },
|
||||
{ 0x86, 0x10, KEY_MUTE },
|
||||
{ 0x86, 0x01, KEY_1 },
|
||||
{ 0x86, 0x02, KEY_2 },
|
||||
{ 0x86, 0x03, KEY_3 },
|
||||
{ 0x86, 0x04, KEY_4 },
|
||||
{ 0x86, 0x05, KEY_5 },
|
||||
{ 0x86, 0x06, KEY_6 },
|
||||
{ 0x86, 0x07, KEY_7 },
|
||||
{ 0x86, 0x08, KEY_8 },
|
||||
{ 0x86, 0x09, KEY_9 },
|
||||
{ 0x86, 0x0a, KEY_0 },
|
||||
{ 0x86, 0x18, KEY_ZOOM },
|
||||
{ 0x86, 0x1c, KEY_UNKNOWN }, /* preview */
|
||||
{ 0x86, 0x13, KEY_UNKNOWN }, /* snap */
|
||||
{ 0x86, 0x00, KEY_UNDO },
|
||||
{ 0x86, 0x1d, KEY_RECORD },
|
||||
{ 0x86, 0x0d, KEY_STOP },
|
||||
{ 0x86, 0x0e, KEY_PAUSE },
|
||||
{ 0x86, 0x16, KEY_PLAY },
|
||||
{ 0x86, 0x11, KEY_BACK },
|
||||
{ 0x86, 0x19, KEY_FORWARD },
|
||||
{ 0x86, 0x14, KEY_UNKNOWN }, /* pip */
|
||||
{ 0x86, 0x15, KEY_ESC },
|
||||
{ 0x86, 0x1a, KEY_UP },
|
||||
{ 0x86, 0x1e, KEY_DOWN },
|
||||
{ 0x86, 0x1f, KEY_LEFT },
|
||||
{ 0x86, 0x1b, KEY_RIGHT },
|
||||
|
||||
/* Key codes for the DiBcom MOD3000 remote. */
|
||||
{ 0x80, 0x00, KEY_MUTE },
|
||||
{ 0x80, 0x01, KEY_TEXT },
|
||||
{ 0x80, 0x02, KEY_HOME },
|
||||
{ 0x80, 0x03, KEY_POWER },
|
||||
|
||||
{ 0x80, 0x04, KEY_RED },
|
||||
{ 0x80, 0x05, KEY_GREEN },
|
||||
{ 0x80, 0x06, KEY_YELLOW },
|
||||
{ 0x80, 0x07, KEY_BLUE },
|
||||
|
||||
{ 0x80, 0x08, KEY_DVD },
|
||||
{ 0x80, 0x09, KEY_AUDIO },
|
||||
{ 0x80, 0x0a, KEY_MEDIA }, /* Pictures */
|
||||
{ 0x80, 0x0b, KEY_VIDEO },
|
||||
|
||||
{ 0x80, 0x0c, KEY_BACK },
|
||||
{ 0x80, 0x0d, KEY_UP },
|
||||
{ 0x80, 0x0e, KEY_RADIO },
|
||||
{ 0x80, 0x0f, KEY_EPG },
|
||||
|
||||
{ 0x80, 0x10, KEY_LEFT },
|
||||
{ 0x80, 0x11, KEY_OK },
|
||||
{ 0x80, 0x12, KEY_RIGHT },
|
||||
{ 0x80, 0x13, KEY_UNKNOWN }, /* SAP */
|
||||
|
||||
{ 0x80, 0x14, KEY_TV },
|
||||
{ 0x80, 0x15, KEY_DOWN },
|
||||
{ 0x80, 0x16, KEY_MENU }, /* DVD Menu */
|
||||
{ 0x80, 0x17, KEY_LAST },
|
||||
|
||||
{ 0x80, 0x18, KEY_RECORD },
|
||||
{ 0x80, 0x19, KEY_STOP },
|
||||
{ 0x80, 0x1a, KEY_PAUSE },
|
||||
{ 0x80, 0x1b, KEY_PLAY },
|
||||
|
||||
{ 0x80, 0x1c, KEY_PREVIOUS },
|
||||
{ 0x80, 0x1d, KEY_REWIND },
|
||||
{ 0x80, 0x1e, KEY_FASTFORWARD },
|
||||
{ 0x80, 0x1f, KEY_NEXT},
|
||||
|
||||
{ 0x80, 0x40, KEY_1 },
|
||||
{ 0x80, 0x41, KEY_2 },
|
||||
{ 0x80, 0x42, KEY_3 },
|
||||
{ 0x80, 0x43, KEY_CHANNELUP },
|
||||
|
||||
{ 0x80, 0x44, KEY_4 },
|
||||
{ 0x80, 0x45, KEY_5 },
|
||||
{ 0x80, 0x46, KEY_6 },
|
||||
{ 0x80, 0x47, KEY_CHANNELDOWN },
|
||||
|
||||
{ 0x80, 0x48, KEY_7 },
|
||||
{ 0x80, 0x49, KEY_8 },
|
||||
{ 0x80, 0x4a, KEY_9 },
|
||||
{ 0x80, 0x4b, KEY_VOLUMEUP },
|
||||
|
||||
{ 0x80, 0x4c, KEY_CLEAR },
|
||||
{ 0x80, 0x4d, KEY_0 },
|
||||
{ 0x80, 0x4e, KEY_ENTER },
|
||||
{ 0x80, 0x4f, KEY_VOLUMEDOWN },
|
||||
};
|
||||
EXPORT_SYMBOL(dibusb_rc_keys);
|
||||
|
||||
int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
|
||||
dvb_usb_generic_rw(d,&cmd,1,key,5,0);
|
||||
dvb_usb_nec_rc_key_to_event(d,key,event,state);
|
||||
if (key[0] != 0)
|
||||
deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_rc_query);
|
||||
444
drivers/media/dvb/dvb-usb/dibusb-mb.c
Normal file
444
drivers/media/dvb/dvb-usb/dibusb-mb.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
|
||||
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* based on GPL code from DiBcom, which has
|
||||
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dibusb.h"
|
||||
|
||||
static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib3000_config demod_cfg;
|
||||
struct dibusb_state *st = adap->priv;
|
||||
|
||||
demod_cfg.demod_address = 0x8;
|
||||
|
||||
if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
|
||||
adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
|
||||
|
||||
adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->pll_addr = 0x61;
|
||||
adap->pll_desc = &dvb_pll_tua6010xs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Some of the Artec 1.1 device aren't equipped with the default tuner
|
||||
* (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures
|
||||
* this out. */
|
||||
static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 b[2] = { 0,0 }, b2[1];
|
||||
int ret = 0;
|
||||
struct i2c_msg msg[2] = {
|
||||
{ .flags = 0, .buf = b, .len = 2 },
|
||||
{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
|
||||
};
|
||||
|
||||
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
|
||||
msg[0].addr = msg[1].addr = 0x60;
|
||||
|
||||
if (adap->tuner_pass_ctrl)
|
||||
adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
|
||||
|
||||
if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
|
||||
err("tuner i2c write failed.");
|
||||
ret = -EREMOTEIO;
|
||||
}
|
||||
|
||||
if (adap->tuner_pass_ctrl)
|
||||
adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
|
||||
|
||||
if (b2[0] == 0xfe) {
|
||||
info("This device has the Thomson Cable onboard. Which is default.");
|
||||
dibusb_thomson_tuner_attach(adap);
|
||||
} else {
|
||||
u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
|
||||
info("This device has the Panasonic ENV77H11D5 onboard.");
|
||||
adap->pll_addr = 0x60;
|
||||
memcpy(adap->pll_init,bpll,4);
|
||||
adap->pll_desc = &dvb_pll_tda665x;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties dibusb1_1_properties;
|
||||
static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
|
||||
static struct dvb_usb_device_properties dibusb2_0b_properties;
|
||||
static struct dvb_usb_device_properties artec_t1_usb2_properties;
|
||||
|
||||
static int dibusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&artec_t1_usb2_properties,THIS_MODULE,NULL) == 0)
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* do not change the order of the ID table */
|
||||
static struct usb_device_id dibusb_dib3000mb_table [] = {
|
||||
/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) },
|
||||
/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) },
|
||||
/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
|
||||
/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
|
||||
/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) },
|
||||
/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
|
||||
/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
|
||||
/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
|
||||
/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
|
||||
/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
|
||||
/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
|
||||
/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
|
||||
/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) },
|
||||
/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) },
|
||||
/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) },
|
||||
/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) },
|
||||
/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) },
|
||||
/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
|
||||
/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
|
||||
/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
|
||||
/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
|
||||
/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
|
||||
/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
|
||||
/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
|
||||
|
||||
/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
|
||||
/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
|
||||
/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) },
|
||||
/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) },
|
||||
|
||||
/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) },
|
||||
|
||||
/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
|
||||
/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
|
||||
|
||||
/*
|
||||
* XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
|
||||
* we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
|
||||
* have been left on the device. If you don't have such a device but an Artec
|
||||
* device that's supposed to work with this driver but is not detected by it,
|
||||
* free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
|
||||
/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
|
||||
#endif
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
|
||||
|
||||
static struct dvb_usb_device_properties dibusb1_1_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_AN2135,
|
||||
|
||||
.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_tuner_probe_and_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = dibusb_power_ctrl,
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dibusb_rc_keys,
|
||||
.rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
|
||||
.rc_query = dibusb_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 9,
|
||||
.devices = {
|
||||
{ "AVerMedia AverTV DVBT USB1.1",
|
||||
{ &dibusb_dib3000mb_table[0], NULL },
|
||||
{ &dibusb_dib3000mb_table[1], NULL },
|
||||
},
|
||||
{ "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
|
||||
{ &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
|
||||
{ &dibusb_dib3000mb_table[3], NULL },
|
||||
},
|
||||
{ "DiBcom USB1.1 DVB-T reference design (MOD3000)",
|
||||
{ &dibusb_dib3000mb_table[5], NULL },
|
||||
{ &dibusb_dib3000mb_table[6], NULL },
|
||||
},
|
||||
{ "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
|
||||
{ &dibusb_dib3000mb_table[7], NULL },
|
||||
{ &dibusb_dib3000mb_table[8], NULL },
|
||||
},
|
||||
{ "Grandtec USB1.1 DVB-T",
|
||||
{ &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL },
|
||||
{ &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
|
||||
},
|
||||
{ "Unkown USB1.1 DVB-T device ???? please report the name to the author",
|
||||
{ &dibusb_dib3000mb_table[13], NULL },
|
||||
{ &dibusb_dib3000mb_table[14], NULL },
|
||||
},
|
||||
{ "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
|
||||
{ &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
|
||||
{ &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
|
||||
},
|
||||
{ "Artec T1 USB1.1 TVBOX with AN2135",
|
||||
{ &dibusb_dib3000mb_table[19], NULL },
|
||||
{ &dibusb_dib3000mb_table[20], NULL },
|
||||
},
|
||||
{ "VideoWalker DVB-T USB",
|
||||
{ &dibusb_dib3000mb_table[25], NULL },
|
||||
{ &dibusb_dib3000mb_table[26], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = CYPRESS_AN2235,
|
||||
|
||||
.firmware = "dvb-usb-dibusb-an2235-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_tuner_probe_and_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
},
|
||||
},
|
||||
.power_ctrl = dibusb_power_ctrl,
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dibusb_rc_keys,
|
||||
.rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
|
||||
.rc_query = dibusb_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
|
||||
.num_device_descs = 2,
|
||||
#else
|
||||
.num_device_descs = 1,
|
||||
#endif
|
||||
.devices = {
|
||||
{ "Artec T1 USB1.1 TVBOX with AN2235",
|
||||
{ &dibusb_dib3000mb_table[21], NULL },
|
||||
{ &dibusb_dib3000mb_table[22], NULL },
|
||||
},
|
||||
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
|
||||
{ "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
|
||||
{ &dibusb_dib3000mb_table[30], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ NULL },
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties dibusb2_0b_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.firmware = "dvb-usb-adstech-usb2-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_thomson_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dibusb_rc_keys,
|
||||
.rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
|
||||
.rc_query = dibusb_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "KWorld/ADSTech Instant DVB-T USB2.0",
|
||||
{ &dibusb_dib3000mb_table[23], NULL },
|
||||
{ &dibusb_dib3000mb_table[24], NULL },
|
||||
},
|
||||
{ "KWorld Xpert DVB-T USB2.0",
|
||||
{ &dibusb_dib3000mb_table[27], NULL },
|
||||
{ NULL }
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties artec_t1_usb2_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_tuner_probe_and_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dibusb_rc_keys,
|
||||
.rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
|
||||
.rc_query = dibusb_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Artec T1 USB2.0",
|
||||
{ &dibusb_dib3000mb_table[28], NULL },
|
||||
{ &dibusb_dib3000mb_table[29], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver dibusb_driver = {
|
||||
.name = "dvb_usb_dibusb_mb",
|
||||
.probe = dibusb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dibusb_dib3000mb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init dibusb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&dibusb_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dibusb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&dibusb_driver);
|
||||
}
|
||||
|
||||
module_init (dibusb_module_init);
|
||||
module_exit (dibusb_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
154
drivers/media/dvb/dvb-usb/dibusb-mc.c
Normal file
154
drivers/media/dvb/dvb-usb/dibusb-mc.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
|
||||
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* based on GPL code from DiBcom, which has
|
||||
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dibusb.h"
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties dibusb_mc_properties;
|
||||
|
||||
static int dibusb_mc_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE,NULL);
|
||||
}
|
||||
|
||||
/* do not change the order of the ID table */
|
||||
static struct usb_device_id dibusb_dib3000mc_table [] = {
|
||||
/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
|
||||
/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
|
||||
/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
|
||||
/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
|
||||
/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) },
|
||||
/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) },
|
||||
/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) },
|
||||
/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) },
|
||||
/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) },
|
||||
/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) },
|
||||
/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) },
|
||||
/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) },
|
||||
/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) },
|
||||
/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
|
||||
|
||||
static struct dvb_usb_device_properties dibusb_mc_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mc_frontend_attach,
|
||||
.tuner_attach = dibusb_dib3000mc_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dibusb_rc_keys,
|
||||
.rc_key_map_size = 111, /* FIXME */
|
||||
.rc_query = dibusb_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 7,
|
||||
.devices = {
|
||||
{ "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
|
||||
{ &dibusb_dib3000mc_table[0], NULL },
|
||||
{ &dibusb_dib3000mc_table[1], NULL },
|
||||
},
|
||||
{ "Artec T1 USB2.0 TVBOX (please check the warm ID)",
|
||||
{ &dibusb_dib3000mc_table[2], NULL },
|
||||
{ &dibusb_dib3000mc_table[3], NULL },
|
||||
},
|
||||
{ "LITE-ON USB2.0 DVB-T Tuner",
|
||||
/* Also rebranded as Intuix S800, Toshiba */
|
||||
{ &dibusb_dib3000mc_table[4], NULL },
|
||||
{ &dibusb_dib3000mc_table[5], NULL },
|
||||
},
|
||||
{ "MSI Digivox Mini SL",
|
||||
{ &dibusb_dib3000mc_table[6], NULL },
|
||||
{ &dibusb_dib3000mc_table[7], NULL },
|
||||
},
|
||||
{ "GRAND - USB2.0 DVB-T adapter",
|
||||
{ &dibusb_dib3000mc_table[8], NULL },
|
||||
{ &dibusb_dib3000mc_table[9], NULL },
|
||||
},
|
||||
{ "Artec T14 - USB2.0 DVB-T",
|
||||
{ &dibusb_dib3000mc_table[10], NULL },
|
||||
{ &dibusb_dib3000mc_table[11], NULL },
|
||||
},
|
||||
{ "Leadtek - USB2.0 Winfast DTV dongle",
|
||||
{ &dibusb_dib3000mc_table[12], NULL },
|
||||
{ &dibusb_dib3000mc_table[13], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver dibusb_mc_driver = {
|
||||
.name = "dvb_usb_dibusb_mc",
|
||||
.probe = dibusb_mc_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dibusb_dib3000mc_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init dibusb_mc_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&dibusb_mc_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dibusb_mc_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&dibusb_mc_driver);
|
||||
}
|
||||
|
||||
module_init (dibusb_mc_module_init);
|
||||
module_exit (dibusb_mc_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
130
drivers/media/dvb/dvb-usb/dibusb.h
Normal file
130
drivers/media/dvb/dvb-usb/dibusb.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/* Header file for all dibusb-based-receivers.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#ifndef _DVB_USB_DIBUSB_H_
|
||||
#define _DVB_USB_DIBUSB_H_
|
||||
|
||||
#ifndef DVB_USB_LOG_PREFIX
|
||||
#define DVB_USB_LOG_PREFIX "dibusb"
|
||||
#endif
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "dib3000.h"
|
||||
#include "dib3000mc.h"
|
||||
#include "mt2060.h"
|
||||
|
||||
/*
|
||||
* protocol of all dibusb related devices
|
||||
*/
|
||||
|
||||
/*
|
||||
* bulk msg to/from endpoint 0x01
|
||||
*
|
||||
* general structure:
|
||||
* request_byte parameter_bytes
|
||||
*/
|
||||
|
||||
#define DIBUSB_REQ_START_READ 0x00
|
||||
#define DIBUSB_REQ_START_DEMOD 0x01
|
||||
|
||||
/*
|
||||
* i2c read
|
||||
* bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
|
||||
* bulk read: byte_buffer (length_word bytes)
|
||||
*/
|
||||
#define DIBUSB_REQ_I2C_READ 0x02
|
||||
|
||||
/*
|
||||
* i2c write
|
||||
* bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
|
||||
*/
|
||||
#define DIBUSB_REQ_I2C_WRITE 0x03
|
||||
|
||||
/*
|
||||
* polling the value of the remote control
|
||||
* bulk write: 0x04
|
||||
* bulk read: byte_buffer (5 bytes)
|
||||
*/
|
||||
#define DIBUSB_REQ_POLL_REMOTE 0x04
|
||||
|
||||
/* additional status values for Hauppauge Remote Control Protocol */
|
||||
#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01
|
||||
#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03
|
||||
|
||||
/* streaming mode:
|
||||
* bulk write: 0x05 mode_byte
|
||||
*
|
||||
* mode_byte is mostly 0x00
|
||||
*/
|
||||
#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
|
||||
|
||||
/* interrupt the internal read loop, when blocking */
|
||||
#define DIBUSB_REQ_INTR_READ 0x06
|
||||
|
||||
/* io control
|
||||
* 0x07 cmd_byte param_bytes
|
||||
*
|
||||
* param_bytes can be up to 32 bytes
|
||||
*
|
||||
* cmd_byte function parameter name
|
||||
* 0x00 power mode
|
||||
* 0x00 sleep
|
||||
* 0x01 wakeup
|
||||
*
|
||||
* 0x01 enable streaming
|
||||
* 0x02 disable streaming
|
||||
*
|
||||
*
|
||||
*/
|
||||
#define DIBUSB_REQ_SET_IOCTL 0x07
|
||||
|
||||
/* IOCTL commands */
|
||||
|
||||
/* change the power mode in firmware */
|
||||
#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00
|
||||
#define DIBUSB_IOCTL_POWER_SLEEP 0x00
|
||||
#define DIBUSB_IOCTL_POWER_WAKEUP 0x01
|
||||
|
||||
/* modify streaming of the FX2 */
|
||||
#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
|
||||
#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02
|
||||
|
||||
struct dibusb_state {
|
||||
struct dib_fe_xfer_ops ops;
|
||||
int mt2060_present;
|
||||
};
|
||||
|
||||
struct dibusb_device_state {
|
||||
/* for RC5 remote control */
|
||||
int old_toggle;
|
||||
int last_repeat_count;
|
||||
};
|
||||
|
||||
extern struct i2c_algorithm dibusb_i2c_algo;
|
||||
|
||||
extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *);
|
||||
extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *);
|
||||
|
||||
extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int);
|
||||
extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int);
|
||||
extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int);
|
||||
extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int);
|
||||
|
||||
extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
|
||||
extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
|
||||
|
||||
#define DEFAULT_RC_INTERVAL 150
|
||||
//#define DEFAULT_RC_INTERVAL 100000
|
||||
|
||||
extern struct dvb_usb_rc_key dibusb_rc_keys[];
|
||||
extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
|
||||
extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
|
||||
|
||||
#endif
|
||||
347
drivers/media/dvb/dvb-usb/digitv.c
Normal file
347
drivers/media/dvb/dvb-usb/digitv.c
Normal file
@@ -0,0 +1,347 @@
|
||||
/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
|
||||
* receiver
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* partly based on the SDK published by Nebula Electronics
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "digitv.h"
|
||||
|
||||
#include "mt352.h"
|
||||
#include "nxt6000.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_digitv_debug;
|
||||
module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int digitv_ctrl_msg(struct dvb_usb_device *d,
|
||||
u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
|
||||
{
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 sndbuf[7],rcvbuf[7];
|
||||
memset(sndbuf,0,7); memset(rcvbuf,0,7);
|
||||
|
||||
sndbuf[0] = cmd;
|
||||
sndbuf[1] = vv;
|
||||
sndbuf[2] = wo ? wlen : rlen;
|
||||
|
||||
if (wo) {
|
||||
memcpy(&sndbuf[3],wbuf,wlen);
|
||||
dvb_usb_generic_write(d,sndbuf,7);
|
||||
} else {
|
||||
dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
|
||||
memcpy(rbuf,&rcvbuf[3],rlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
|
||||
msg[i+1].buf,msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
|
||||
&msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 digitv_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm digitv_i2c_algo = {
|
||||
.master_xfer = digitv_i2c_xfer,
|
||||
.functionality = digitv_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int digitv_identify_state (struct usb_device *udev, struct
|
||||
dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digitv_mt352_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 };
|
||||
static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50,
|
||||
0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00,
|
||||
0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f,
|
||||
0x75, 0x32 };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
|
||||
mt352_write(fe, &reset_buf[i], 2);
|
||||
|
||||
msleep(1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
|
||||
mt352_write(fe, &init_buf[i], 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt352_config digitv_mt352_config = {
|
||||
.demod_init = digitv_mt352_demod_init,
|
||||
};
|
||||
|
||||
static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
u8 b[5];
|
||||
dvb_usb_tuner_calc_regs(fe,fep,b, 5);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
|
||||
}
|
||||
|
||||
static struct nxt6000_config digitv_nxt6000_config = {
|
||||
.clock_inversion = 1,
|
||||
};
|
||||
|
||||
static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
|
||||
adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
|
||||
return 0;
|
||||
}
|
||||
if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
|
||||
adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->pll_addr = 0x60;
|
||||
adap->pll_desc = &dvb_pll_tded4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key digitv_rc_keys[] = {
|
||||
{ 0x5f, 0x55, KEY_0 },
|
||||
{ 0x6f, 0x55, KEY_1 },
|
||||
{ 0x9f, 0x55, KEY_2 },
|
||||
{ 0xaf, 0x55, KEY_3 },
|
||||
{ 0x5f, 0x56, KEY_4 },
|
||||
{ 0x6f, 0x56, KEY_5 },
|
||||
{ 0x9f, 0x56, KEY_6 },
|
||||
{ 0xaf, 0x56, KEY_7 },
|
||||
{ 0x5f, 0x59, KEY_8 },
|
||||
{ 0x6f, 0x59, KEY_9 },
|
||||
{ 0x9f, 0x59, KEY_TV },
|
||||
{ 0xaf, 0x59, KEY_AUX },
|
||||
{ 0x5f, 0x5a, KEY_DVD },
|
||||
{ 0x6f, 0x5a, KEY_POWER },
|
||||
{ 0x9f, 0x5a, KEY_MHP }, /* labelled 'Picture' */
|
||||
{ 0xaf, 0x5a, KEY_AUDIO },
|
||||
{ 0x5f, 0x65, KEY_INFO },
|
||||
{ 0x6f, 0x65, KEY_F13 }, /* 16:9 */
|
||||
{ 0x9f, 0x65, KEY_F14 }, /* 14:9 */
|
||||
{ 0xaf, 0x65, KEY_EPG },
|
||||
{ 0x5f, 0x66, KEY_EXIT },
|
||||
{ 0x6f, 0x66, KEY_MENU },
|
||||
{ 0x9f, 0x66, KEY_UP },
|
||||
{ 0xaf, 0x66, KEY_DOWN },
|
||||
{ 0x5f, 0x69, KEY_LEFT },
|
||||
{ 0x6f, 0x69, KEY_RIGHT },
|
||||
{ 0x9f, 0x69, KEY_ENTER },
|
||||
{ 0xaf, 0x69, KEY_CHANNELUP },
|
||||
{ 0x5f, 0x6a, KEY_CHANNELDOWN },
|
||||
{ 0x6f, 0x6a, KEY_VOLUMEUP },
|
||||
{ 0x9f, 0x6a, KEY_VOLUMEDOWN },
|
||||
{ 0xaf, 0x6a, KEY_RED },
|
||||
{ 0x5f, 0x95, KEY_GREEN },
|
||||
{ 0x6f, 0x95, KEY_YELLOW },
|
||||
{ 0x9f, 0x95, KEY_BLUE },
|
||||
{ 0xaf, 0x95, KEY_SUBTITLE },
|
||||
{ 0x5f, 0x96, KEY_F15 }, /* AD */
|
||||
{ 0x6f, 0x96, KEY_TEXT },
|
||||
{ 0x9f, 0x96, KEY_MUTE },
|
||||
{ 0xaf, 0x96, KEY_REWIND },
|
||||
{ 0x5f, 0x99, KEY_STOP },
|
||||
{ 0x6f, 0x99, KEY_PLAY },
|
||||
{ 0x9f, 0x99, KEY_FASTFORWARD },
|
||||
{ 0xaf, 0x99, KEY_F16 }, /* chapter */
|
||||
{ 0x5f, 0x9a, KEY_PAUSE },
|
||||
{ 0x6f, 0x9a, KEY_PLAY },
|
||||
{ 0x9f, 0x9a, KEY_RECORD },
|
||||
{ 0xaf, 0x9a, KEY_F17 }, /* picture in picture */
|
||||
{ 0x5f, 0xa5, KEY_KPPLUS }, /* zoom in */
|
||||
{ 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
|
||||
{ 0x9f, 0xa5, KEY_F18 }, /* capture */
|
||||
{ 0xaf, 0xa5, KEY_F19 }, /* web */
|
||||
{ 0x5f, 0xa6, KEY_EMAIL },
|
||||
{ 0x6f, 0xa6, KEY_PHONE },
|
||||
{ 0x9f, 0xa6, KEY_PC },
|
||||
};
|
||||
|
||||
static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
int i;
|
||||
u8 key[5];
|
||||
u8 b[4] = { 0 };
|
||||
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
|
||||
|
||||
/* Tell the device we've read the remote. Not sure how necessary
|
||||
this is, but the Nebula SDK does it. */
|
||||
digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
|
||||
|
||||
/* if something is inside the buffer, simulate key press */
|
||||
if (key[1] != 0)
|
||||
{
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (d->props.rc_key_map[i].custom == key[1] &&
|
||||
d->props.rc_key_map[i].data == key[2]) {
|
||||
*event = d->props.rc_key_map[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key[0] != 0)
|
||||
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties digitv_properties;
|
||||
|
||||
static int digitv_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
int ret;
|
||||
if ((ret = dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,&d)) == 0) {
|
||||
u8 b[4] = { 0 };
|
||||
|
||||
if (d != NULL) { /* do that only when the firmware is loaded */
|
||||
b[0] = 1;
|
||||
digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0);
|
||||
|
||||
b[0] = 0;
|
||||
digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id digitv_table [] = {
|
||||
{ USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, digitv_table);
|
||||
|
||||
static struct dvb_usb_device_properties digitv_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-digitv-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = digitv_frontend_attach,
|
||||
.tuner_attach = digitv_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.identify_state = digitv_identify_state,
|
||||
|
||||
.rc_interval = 1000,
|
||||
.rc_key_map = digitv_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(digitv_rc_keys),
|
||||
.rc_query = digitv_rc_query,
|
||||
|
||||
.i2c_algo = &digitv_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Nebula Electronics uDigiTV DVB-T USB2.0)",
|
||||
{ &digitv_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver digitv_driver = {
|
||||
.name = "dvb_usb_digitv",
|
||||
.probe = digitv_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = digitv_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init digitv_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&digitv_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit digitv_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&digitv_driver);
|
||||
}
|
||||
|
||||
module_init (digitv_module_init);
|
||||
module_exit (digitv_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
|
||||
MODULE_VERSION("1.0-alpha");
|
||||
MODULE_LICENSE("GPL");
|
||||
65
drivers/media/dvb/dvb-usb/digitv.h
Normal file
65
drivers/media/dvb/dvb-usb/digitv.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef _DVB_USB_DIGITV_H_
|
||||
#define _DVB_USB_DIGITV_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "digitv"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_digitv_debug;
|
||||
#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
|
||||
|
||||
/* protocol (from usblogging and the SDK:
|
||||
*
|
||||
* Always 7 bytes bulk message(s) for controlling
|
||||
*
|
||||
* First byte describes the command. Reads are 2 consecutive transfer (as always).
|
||||
*
|
||||
* General structure:
|
||||
*
|
||||
* write or first message of a read:
|
||||
* <cmdbyte> VV <len> B0 B1 B2 B3
|
||||
*
|
||||
* second message of a read
|
||||
* <cmdbyte> VV <len> R0 R1 R2 R3
|
||||
*
|
||||
* whereas 0 < len <= 4
|
||||
*
|
||||
* I2C address is stored somewhere inside the device.
|
||||
*
|
||||
* 0x01 read from EEPROM
|
||||
* VV = offset; B* = 0; R* = value(s)
|
||||
*
|
||||
* 0x02 read register of the COFDM
|
||||
* VV = register; B* = 0; R* = value(s)
|
||||
*
|
||||
* 0x05 write register of the COFDM
|
||||
* VV = register; B* = value(s);
|
||||
*
|
||||
* 0x06 write to the tuner (only for NXT6000)
|
||||
* VV = 0; B* = PLL data; len = 4;
|
||||
*
|
||||
* 0x03 read remote control
|
||||
* VV = 0; B* = 0; len = 4; R* = key
|
||||
*
|
||||
* 0x07 write to the remote (don't know why one should this, resetting ?)
|
||||
* VV = 0; B* = key; len = 4;
|
||||
*
|
||||
* 0x08 write remote type
|
||||
* VV = 0; B[0] = 0x01, len = 4
|
||||
*
|
||||
* 0x09 write device init
|
||||
* TODO
|
||||
*/
|
||||
#define USB_READ_EEPROM 1
|
||||
|
||||
#define USB_READ_COFDM 2
|
||||
#define USB_WRITE_COFDM 5
|
||||
|
||||
#define USB_WRITE_TUNER 6
|
||||
|
||||
#define USB_READ_REMOTE 3
|
||||
#define USB_WRITE_REMOTE 7
|
||||
#define USB_WRITE_REMOTE_TYPE 8
|
||||
|
||||
#define USB_DEV_INIT 9
|
||||
|
||||
#endif
|
||||
205
drivers/media/dvb/dvb-usb/dtt200u-fe.c
Normal file
205
drivers/media/dvb/dvb-usb/dtt200u-fe.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
|
||||
* Typhoon/ Yuan DVB-T USB2.0 receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dtt200u.h"
|
||||
|
||||
struct dtt200u_fe_state {
|
||||
struct dvb_usb_device *d;
|
||||
|
||||
fe_status_t stat;
|
||||
|
||||
struct dvb_frontend_parameters fep;
|
||||
struct dvb_frontend frontend;
|
||||
};
|
||||
|
||||
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 st = GET_TUNE_STATUS, b[3];
|
||||
|
||||
dvb_usb_generic_rw(state->d,&st,1,b,3,0);
|
||||
|
||||
switch (b[0]) {
|
||||
case 0x01:
|
||||
*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
break;
|
||||
case 0x00: /* pending */
|
||||
*stat = FE_TIMEDOUT; /* during set_frontend */
|
||||
break;
|
||||
default:
|
||||
case 0x02: /* failed */
|
||||
*stat = 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 bw = GET_VIT_ERR_CNT,b[3];
|
||||
dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
|
||||
*ber = (b[0] << 16) | (b[1] << 8) | b[2];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
|
||||
|
||||
dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
|
||||
*unc = (b[0] << 8) | b[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 bw = GET_AGC, b;
|
||||
dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
|
||||
*strength = (b << 8) | b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 bw = GET_SNR,br;
|
||||
dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
|
||||
*snr = ~((br << 8) | br);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_init(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 b = SET_INIT;
|
||||
return dvb_usb_generic_write(state->d,&b,1);
|
||||
}
|
||||
|
||||
static int dtt200u_fe_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
return dtt200u_fe_init(fe);
|
||||
}
|
||||
|
||||
static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 1500;
|
||||
tune->step_size = 0;
|
||||
tune->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
int i;
|
||||
fe_status_t st;
|
||||
u16 freq = fep->frequency / 250000;
|
||||
u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
|
||||
|
||||
switch (fep->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break;
|
||||
case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break;
|
||||
case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break;
|
||||
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dvb_usb_generic_write(state->d,bwbuf,2);
|
||||
|
||||
freqbuf[1] = freq & 0xff;
|
||||
freqbuf[2] = (freq >> 8) & 0xff;
|
||||
dvb_usb_generic_write(state->d,freqbuf,3);
|
||||
|
||||
for (i = 0; i < 30; i++) {
|
||||
msleep(20);
|
||||
dtt200u_fe_read_status(fe, &st);
|
||||
if (st & FE_TIMEDOUT)
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dtt200u_fe_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops dtt200u_fe_ops;
|
||||
|
||||
struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct dtt200u_fe_state* state = NULL;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
deb_info("attaching frontend dtt200u\n");
|
||||
|
||||
state->d = d;
|
||||
|
||||
memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
return &state->frontend;
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops dtt200u_fe_ops = {
|
||||
.info = {
|
||||
.name = "WideView USB DVB-T",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 44250000,
|
||||
.frequency_max = 867250000,
|
||||
.frequency_stepsize = 250000,
|
||||
.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 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_RECOVER |
|
||||
FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.release = dtt200u_fe_release,
|
||||
|
||||
.init = dtt200u_fe_init,
|
||||
.sleep = dtt200u_fe_sleep,
|
||||
|
||||
.set_frontend = dtt200u_fe_set_frontend,
|
||||
.get_frontend = dtt200u_fe_get_frontend,
|
||||
.get_tune_settings = dtt200u_fe_get_tune_settings,
|
||||
|
||||
.read_status = dtt200u_fe_read_status,
|
||||
.read_ber = dtt200u_fe_read_ber,
|
||||
.read_signal_strength = dtt200u_fe_read_signal_strength,
|
||||
.read_snr = dtt200u_fe_read_snr,
|
||||
.read_ucblocks = dtt200u_fe_read_unc_blocks,
|
||||
};
|
||||
338
drivers/media/dvb/dvb-usb/dtt200u.c
Normal file
338
drivers/media/dvb/dvb-usb/dtt200u.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
|
||||
* Typhoon/ Yuan DVB-T USB2.0 receiver.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* Thanks to Steve Chang from WideView for providing support for the WT-220U.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dtt200u.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_dtt200u_debug;
|
||||
module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b = SET_INIT;
|
||||
|
||||
if (onoff)
|
||||
dvb_usb_generic_write(d,&b,2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
u8 b_streaming[2] = { SET_STREAMING, onoff };
|
||||
u8 b_rst_pid = RESET_PID_FILTER;
|
||||
|
||||
dvb_usb_generic_write(adap->dev, b_streaming, 2);
|
||||
|
||||
if (onoff == 0)
|
||||
dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
|
||||
{
|
||||
u8 b_pid[4];
|
||||
pid = onoff ? pid : 0;
|
||||
|
||||
b_pid[0] = SET_PID_FILTER;
|
||||
b_pid[1] = index;
|
||||
b_pid[2] = pid & 0xff;
|
||||
b_pid[3] = (pid >> 8) & 0x1f;
|
||||
|
||||
return dvb_usb_generic_write(adap->dev, b_pid, 4);
|
||||
}
|
||||
|
||||
/* remote control */
|
||||
/* key list for the tiny remote control (Yakumo, don't know about the others) */
|
||||
static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
|
||||
{ 0x80, 0x01, KEY_MUTE },
|
||||
{ 0x80, 0x02, KEY_CHANNELDOWN },
|
||||
{ 0x80, 0x03, KEY_VOLUMEDOWN },
|
||||
{ 0x80, 0x04, KEY_1 },
|
||||
{ 0x80, 0x05, KEY_2 },
|
||||
{ 0x80, 0x06, KEY_3 },
|
||||
{ 0x80, 0x07, KEY_4 },
|
||||
{ 0x80, 0x08, KEY_5 },
|
||||
{ 0x80, 0x09, KEY_6 },
|
||||
{ 0x80, 0x0a, KEY_7 },
|
||||
{ 0x80, 0x0c, KEY_ZOOM },
|
||||
{ 0x80, 0x0d, KEY_0 },
|
||||
{ 0x80, 0x0e, KEY_SELECT },
|
||||
{ 0x80, 0x12, KEY_POWER },
|
||||
{ 0x80, 0x1a, KEY_CHANNELUP },
|
||||
{ 0x80, 0x1b, KEY_8 },
|
||||
{ 0x80, 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x80, 0x1f, KEY_9 },
|
||||
};
|
||||
|
||||
static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 key[5],cmd = GET_RC_CODE;
|
||||
dvb_usb_generic_rw(d,&cmd,1,key,5,0);
|
||||
dvb_usb_nec_rc_key_to_event(d,key,event,state);
|
||||
if (key[0] != 0)
|
||||
deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe = dtt200u_fe_attach(adap->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties dtt200u_properties;
|
||||
static struct dvb_usb_device_properties wt220u_fc_properties;
|
||||
static struct dvb_usb_device_properties wt220u_properties;
|
||||
static struct dvb_usb_device_properties wt220u_zl0353_properties;
|
||||
|
||||
static int dtt200u_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
|
||||
dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_device_id dtt200u_usb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties dtt200u_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-dtt200u-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc_interval = 300,
|
||||
.rc_key_map = dtt200u_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
|
||||
.cold_ids = { &dtt200u_usb_table[0], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[1], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc_interval = 300,
|
||||
.rc_key_map = dtt200u_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
|
||||
.cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[3], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_fc_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-fc03.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc_interval = 300,
|
||||
.rc_key_map = dtt200u_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
|
||||
.cold_ids = { &dtt200u_usb_table[6], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[7], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_zl0353_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-zl0353-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc_interval = 300,
|
||||
.rc_key_map = dtt200u_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (based on ZL353)",
|
||||
.cold_ids = { &dtt200u_usb_table[4], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[5], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver dtt200u_usb_driver = {
|
||||
.name = "dvb_usb_dtt200u",
|
||||
.probe = dtt200u_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dtt200u_usb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init dtt200u_usb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&dtt200u_usb_driver))) {
|
||||
err("usb_register failed. (%d)",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dtt200u_usb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&dtt200u_usb_driver);
|
||||
}
|
||||
|
||||
module_init(dtt200u_usb_module_init);
|
||||
module_exit(dtt200u_usb_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
57
drivers/media/dvb/dvb-usb/dtt200u.h
Normal file
57
drivers/media/dvb/dvb-usb/dtt200u.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
|
||||
* Typhoon/ Yuan DVB-T USB2.0 receiver.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#ifndef _DVB_USB_DTT200U_H_
|
||||
#define _DVB_USB_DTT200U_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dtt200u"
|
||||
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_dtt200u_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args)
|
||||
|
||||
/* guessed protocol description (reverse engineered):
|
||||
* read
|
||||
* 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
|
||||
* 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
|
||||
*/
|
||||
|
||||
#define GET_SPEED 0x00
|
||||
#define GET_TUNE_STATUS 0x81
|
||||
#define GET_RC_CODE 0x84
|
||||
#define GET_CONFIGURATION 0x88
|
||||
#define GET_AGC 0x89
|
||||
#define GET_SNR 0x8a
|
||||
#define GET_VIT_ERR_CNT 0x8c
|
||||
#define GET_RS_ERR_CNT 0x8d
|
||||
#define GET_RS_UNCOR_BLK_CNT 0x8e
|
||||
|
||||
/* write
|
||||
* 01 - init
|
||||
* 02 - frequency (divided by 250000)
|
||||
* 03 - bandwidth
|
||||
* 04 - pid table (index pid(7:0) pid(12:8))
|
||||
* 05 - reset the pid table
|
||||
* 08 - transfer switch
|
||||
*/
|
||||
|
||||
#define SET_INIT 0x01
|
||||
#define SET_RF_FREQ 0x02
|
||||
#define SET_BANDWIDTH 0x03
|
||||
#define SET_PID_FILTER 0x04
|
||||
#define RESET_PID_FILTER 0x05
|
||||
#define SET_STREAMING 0x08
|
||||
|
||||
extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
|
||||
|
||||
#endif
|
||||
51
drivers/media/dvb/dvb-usb/dvb-usb-common.h
Normal file
51
drivers/media/dvb/dvb-usb/dvb-usb-common.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* dvb-usb-common.h is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* a header file containing prototypes and types for internal use of the dvb-usb-lib
|
||||
*/
|
||||
#ifndef _DVB_USB_COMMON_H_
|
||||
#define _DVB_USB_COMMON_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dvb-usb"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_debug;
|
||||
extern int dvb_usb_disable_rc_polling;
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args)
|
||||
#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args)
|
||||
#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args)
|
||||
#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args)
|
||||
#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args)
|
||||
#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
|
||||
|
||||
/* commonly used methods */
|
||||
extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
|
||||
|
||||
extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff);
|
||||
|
||||
extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
|
||||
extern int usb_urb_exit(struct usb_data_stream *stream);
|
||||
extern int usb_urb_submit(struct usb_data_stream *stream);
|
||||
extern int usb_urb_kill(struct usb_data_stream *stream);
|
||||
|
||||
extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
|
||||
|
||||
extern int dvb_usb_i2c_init(struct dvb_usb_device *);
|
||||
extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
|
||||
|
||||
extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
|
||||
|
||||
extern int dvb_usb_remote_init(struct dvb_usb_device *);
|
||||
extern int dvb_usb_remote_exit(struct dvb_usb_device *);
|
||||
|
||||
#endif
|
||||
206
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
Normal file
206
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/* dvb-usb-dvb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file contains functions for initializing and handling the
|
||||
* linux-dvb API.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
/* does the complete input transfer handling */
|
||||
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
|
||||
int newfeedcount,ret;
|
||||
|
||||
if (adap == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
newfeedcount = adap->feedcount + (onoff ? 1 : -1);
|
||||
|
||||
/* stop feed before setting a new pid if there will be no pid anymore */
|
||||
if (newfeedcount == 0) {
|
||||
deb_ts("stop feeding\n");
|
||||
usb_urb_kill(&adap->stream);
|
||||
|
||||
if (adap->props.streaming_ctrl != NULL)
|
||||
if ((ret = adap->props.streaming_ctrl(adap,0)))
|
||||
err("error while stopping stream.");
|
||||
}
|
||||
|
||||
adap->feedcount = newfeedcount;
|
||||
|
||||
/* activate the pid on the device specific pid_filter */
|
||||
deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ?
|
||||
"yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ?
|
||||
"on" : "off");
|
||||
if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
|
||||
adap->pid_filtering &&
|
||||
adap->props.pid_filter != NULL)
|
||||
adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff);
|
||||
|
||||
/* start the feed if this was the first feed and there is still a feed
|
||||
* for reception.
|
||||
*/
|
||||
if (adap->feedcount == onoff && adap->feedcount > 0) {
|
||||
deb_ts("submitting all URBs\n");
|
||||
usb_urb_submit(&adap->stream);
|
||||
|
||||
deb_ts("controlling pid parser\n");
|
||||
if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
|
||||
adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
|
||||
adap->props.pid_filter_ctrl != NULL)
|
||||
if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0)
|
||||
err("could not handle pid_parser");
|
||||
|
||||
deb_ts("start feeding\n");
|
||||
if (adap->props.streaming_ctrl != NULL)
|
||||
if (adap->props.streaming_ctrl(adap,1)) {
|
||||
err("error while enabling fifo.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
|
||||
return dvb_usb_ctrl_feed(dvbdmxfeed,1);
|
||||
}
|
||||
|
||||
static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
|
||||
return dvb_usb_ctrl_feed(dvbdmxfeed,0);
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
|
||||
adap->dev->owner, &adap->dev->udev->dev)) < 0) {
|
||||
deb_info("dvb_register_adapter failed: error %d", ret);
|
||||
goto err;
|
||||
}
|
||||
adap->dvb_adap.priv = adap;
|
||||
|
||||
if (adap->dev->props.read_mac_address) {
|
||||
if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
|
||||
info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0],
|
||||
adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2],
|
||||
adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4],
|
||||
adap->dvb_adap.proposed_mac[5]);
|
||||
else
|
||||
err("MAC address reading failed.");
|
||||
}
|
||||
|
||||
|
||||
adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
|
||||
adap->demux.priv = adap;
|
||||
|
||||
adap->demux.feednum = adap->demux.filternum = adap->max_feed_count;
|
||||
adap->demux.start_feed = dvb_usb_start_feed;
|
||||
adap->demux.stop_feed = dvb_usb_stop_feed;
|
||||
adap->demux.write_to_decoder = NULL;
|
||||
if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
|
||||
err("dvb_dmx_init failed: error %d",ret);
|
||||
goto err_dmx;
|
||||
}
|
||||
|
||||
adap->dmxdev.filternum = adap->demux.filternum;
|
||||
adap->dmxdev.demux = &adap->demux.dmx;
|
||||
adap->dmxdev.capabilities = 0;
|
||||
if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
|
||||
err("dvb_dmxdev_init failed: error %d",ret);
|
||||
goto err_dmx_dev;
|
||||
}
|
||||
|
||||
dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
|
||||
|
||||
adap->state |= DVB_USB_ADAP_STATE_DVB;
|
||||
return 0;
|
||||
|
||||
err_dmx_dev:
|
||||
dvb_dmx_release(&adap->demux);
|
||||
err_dmx:
|
||||
dvb_unregister_adapter(&adap->dvb_adap);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (adap->state & DVB_USB_ADAP_STATE_DVB) {
|
||||
deb_info("unregistering DVB part\n");
|
||||
dvb_net_release(&adap->dvb_net);
|
||||
adap->demux.dmx.close(&adap->demux.dmx);
|
||||
dvb_dmxdev_release(&adap->dmxdev);
|
||||
dvb_dmx_release(&adap->demux);
|
||||
dvb_unregister_adapter(&adap->dvb_adap);
|
||||
adap->state &= ~DVB_USB_ADAP_STATE_DVB;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
dvb_usb_device_power_ctrl(adap->dev, 1);
|
||||
|
||||
if (adap->fe_init)
|
||||
adap->fe_init(fe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
if (adap->fe_sleep)
|
||||
adap->fe_sleep(fe);
|
||||
|
||||
return dvb_usb_device_power_ctrl(adap->dev, 0);
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (adap->props.frontend_attach == NULL) {
|
||||
err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* re-assign sleep and wakeup functions */
|
||||
if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) {
|
||||
adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup;
|
||||
adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep;
|
||||
|
||||
if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
|
||||
err("Frontend registration failed.");
|
||||
dvb_frontend_detach(adap->fe);
|
||||
adap->fe = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* only attach the tuner if the demod is there */
|
||||
if (adap->props.tuner_attach != NULL)
|
||||
adap->props.tuner_attach(adap);
|
||||
} else
|
||||
err("no frontend was attached by '%s'",adap->dev->desc->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (adap->fe != NULL) {
|
||||
dvb_unregister_frontend(adap->fe);
|
||||
dvb_frontend_detach(adap->fe);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
146
drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
Normal file
146
drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* dvb-usb-firmware.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
|
||||
*
|
||||
* FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
struct usb_cypress_controller {
|
||||
int id;
|
||||
const char *name; /* name of the usb controller */
|
||||
u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */
|
||||
};
|
||||
|
||||
static struct usb_cypress_controller cypress[] = {
|
||||
{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
|
||||
{ .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
|
||||
{ .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
|
||||
{ .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
|
||||
};
|
||||
|
||||
/*
|
||||
* load a firmware packet to the device
|
||||
*/
|
||||
static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
|
||||
{
|
||||
return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
|
||||
0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
|
||||
}
|
||||
|
||||
int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
|
||||
{
|
||||
struct hexline hx;
|
||||
u8 reset;
|
||||
int ret,pos=0;
|
||||
|
||||
/* stop the CPU */
|
||||
reset = 1;
|
||||
if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
|
||||
err("could not stop the USB controller CPU.");
|
||||
|
||||
while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
|
||||
deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
|
||||
ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
|
||||
|
||||
if (ret != hx.len) {
|
||||
err("error while transferring firmware "
|
||||
"(transferred size: %d, block size: %d)",
|
||||
ret,hx.len);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
err("firmware download failed at %d with %d",pos,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* restart the CPU */
|
||||
reset = 0;
|
||||
if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
|
||||
err("could not restart the USB controller CPU.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
} else
|
||||
ret = -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_cypress_load_firmware);
|
||||
|
||||
int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
|
||||
{
|
||||
int ret;
|
||||
const struct firmware *fw = NULL;
|
||||
|
||||
if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
|
||||
err("did not find the firmware file. (%s) "
|
||||
"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
|
||||
props->firmware,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
info("downloading firmware from file '%s'",props->firmware);
|
||||
|
||||
switch (props->usb_ctrl) {
|
||||
case CYPRESS_AN2135:
|
||||
case CYPRESS_AN2235:
|
||||
case CYPRESS_FX2:
|
||||
ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
|
||||
break;
|
||||
case DEVICE_SPECIFIC:
|
||||
if (props->download_firmware)
|
||||
ret = props->download_firmware(udev,fw);
|
||||
else {
|
||||
err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
|
||||
int *pos)
|
||||
{
|
||||
u8 *b = (u8 *) &fw->data[*pos];
|
||||
int data_offs = 4;
|
||||
if (*pos >= fw->size)
|
||||
return 0;
|
||||
|
||||
memset(hx,0,sizeof(struct hexline));
|
||||
|
||||
hx->len = b[0];
|
||||
|
||||
if ((*pos + hx->len + 4) >= fw->size)
|
||||
return -EINVAL;
|
||||
|
||||
hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
|
||||
hx->type = b[3];
|
||||
|
||||
if (hx->type == 0x04) {
|
||||
/* b[4] and b[5] are the Extended linear address record data field */
|
||||
hx->addr |= (b[4] << 24) | (b[5] << 16);
|
||||
/* hx->len -= 2;
|
||||
data_offs += 2; */
|
||||
}
|
||||
memcpy(hx->data,&b[data_offs],hx->len);
|
||||
hx->chk = b[hx->len + data_offs];
|
||||
|
||||
*pos += hx->len + 5;
|
||||
|
||||
return *pos;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_get_hexline);
|
||||
127
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
Normal file
127
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/* dvb-usb-i2c.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file contains functions for (de-)initializing an I2C adapter.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
int dvb_usb_i2c_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
|
||||
return 0;
|
||||
|
||||
if (d->props.i2c_algo == NULL) {
|
||||
err("no i2c algorithm specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE);
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
|
||||
#else
|
||||
d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
|
||||
#endif
|
||||
d->i2c_adap.algo = d->props.i2c_algo;
|
||||
d->i2c_adap.algo_data = NULL;
|
||||
d->i2c_adap.dev.parent = &d->udev->dev;
|
||||
|
||||
i2c_set_adapdata(&d->i2c_adap, d);
|
||||
|
||||
if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
|
||||
err("could not add i2c adapter");
|
||||
|
||||
d->state |= DVB_USB_STATE_I2C;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usb_i2c_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
if (d->state & DVB_USB_STATE_I2C)
|
||||
i2c_del_adapter(&d->i2c_adap);
|
||||
d->state &= ~DVB_USB_STATE_I2C;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
|
||||
int ret = 0;
|
||||
|
||||
/* if pll_desc is not used */
|
||||
if (adap->pll_desc == NULL)
|
||||
return 0;
|
||||
|
||||
if (adap->tuner_pass_ctrl)
|
||||
adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
|
||||
|
||||
deb_pll("pll init: %x\n",adap->pll_addr);
|
||||
deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
|
||||
adap->pll_init[2], adap->pll_init[3]);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
|
||||
err("tuner i2c write failed for pll_init.");
|
||||
ret = -EREMOTEIO;
|
||||
}
|
||||
msleep(1);
|
||||
|
||||
if (adap->tuner_pass_ctrl)
|
||||
adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
|
||||
|
||||
int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
if (buf_len != 5)
|
||||
return -EINVAL;
|
||||
if (adap->pll_desc == NULL)
|
||||
return 0;
|
||||
|
||||
deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
|
||||
|
||||
b[0] = adap->pll_addr;
|
||||
dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
|
||||
|
||||
deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
|
||||
|
||||
return 5;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
|
||||
|
||||
int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
int ret = 0;
|
||||
u8 b[5];
|
||||
struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
|
||||
|
||||
dvb_usb_tuner_calc_regs(fe,fep,b,5);
|
||||
|
||||
if (adap->tuner_pass_ctrl)
|
||||
adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
|
||||
err("tuner i2c write failed for pll_set.");
|
||||
ret = -EREMOTEIO;
|
||||
}
|
||||
msleep(1);
|
||||
|
||||
if (adap->tuner_pass_ctrl)
|
||||
adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
|
||||
144
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
Normal file
144
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/* dvb-usb-ids.h is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
|
||||
* dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* a header file containing define's for the USB device supported by the
|
||||
* various drivers.
|
||||
*/
|
||||
#ifndef _DVB_USB_IDS_H_
|
||||
#define _DVB_USB_IDS_H_
|
||||
|
||||
/* Vendor IDs */
|
||||
#define USB_VID_ADSTECH 0x06e1
|
||||
#define USB_VID_ALCOR_MICRO 0x058f
|
||||
#define USB_VID_ANCHOR 0x0547
|
||||
#define USB_VID_AVERMEDIA 0x07ca
|
||||
#define USB_VID_COMPRO 0x185b
|
||||
#define USB_VID_COMPRO_UNK 0x145f
|
||||
#define USB_VID_CYPRESS 0x04b4
|
||||
#define USB_VID_DIBCOM 0x10b8
|
||||
#define USB_VID_DVICO 0x0fe9
|
||||
#define USB_VID_EMPIA 0xeb1a
|
||||
#define USB_VID_GENPIX 0x09c0
|
||||
#define USB_VID_GRANDTEC 0x5032
|
||||
#define USB_VID_HANFTEK 0x15f4
|
||||
#define USB_VID_HAUPPAUGE 0x2040
|
||||
#define USB_VID_HYPER_PALTEK 0x1025
|
||||
#define USB_VID_KWORLD 0xeb2a
|
||||
#define USB_VID_KYE 0x0458
|
||||
#define USB_VID_LEADTEK 0x0413
|
||||
#define USB_VID_LITEON 0x04ca
|
||||
#define USB_VID_MEDION 0x1660
|
||||
#define USB_VID_MSI 0x0db0
|
||||
#define USB_VID_PINNACLE 0x2304
|
||||
#define USB_VID_VISIONPLUS 0x13d3
|
||||
#define USB_VID_TWINHAN 0x1822
|
||||
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
|
||||
#define USB_VID_UNIWILL 0x1584
|
||||
#define USB_VID_WIDEVIEW 0x14aa
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
#define USB_PID_ADSTECH_USB2_WARM 0xa334
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
|
||||
#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801
|
||||
#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
|
||||
#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
|
||||
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
|
||||
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
|
||||
#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78
|
||||
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
|
||||
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
|
||||
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
|
||||
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
|
||||
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
|
||||
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
|
||||
#define USB_PID_DIBCOM_STK7700P 0x1e14
|
||||
#define USB_PID_DIBCOM_STK7700P_PC 0x1e78
|
||||
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
|
||||
#define USB_PID_UNIWILL_STK7700P 0x6003
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
|
||||
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
|
||||
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
|
||||
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
|
||||
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
|
||||
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
|
||||
#define USB_PID_TWINHAN_VP7020_WARM 0x3204
|
||||
#define USB_PID_TWINHAN_VP7045_COLD 0x3205
|
||||
#define USB_PID_TWINHAN_VP7045_WARM 0x3206
|
||||
#define USB_PID_TWINHAN_VP7021_COLD 0x3207
|
||||
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
|
||||
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
|
||||
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
|
||||
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
|
||||
#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
|
||||
#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
|
||||
#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
|
||||
#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
|
||||
#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
|
||||
#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a
|
||||
#define USB_PID_ARTEC_T14_COLD 0x810b
|
||||
#define USB_PID_ARTEC_T14_WARM 0x810c
|
||||
#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
|
||||
#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
|
||||
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
|
||||
#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
|
||||
#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
|
||||
#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
|
||||
#define USB_PID_DTT200U_COLD 0x0201
|
||||
#define USB_PID_DTT200U_WARM 0x0301
|
||||
#define USB_PID_WT220U_ZAP250_COLD 0x0220
|
||||
#define USB_PID_WT220U_COLD 0x0222
|
||||
#define USB_PID_WT220U_WARM 0x0221
|
||||
#define USB_PID_WT220U_FC_COLD 0x0225
|
||||
#define USB_PID_WT220U_FC_WARM 0x0226
|
||||
#define USB_PID_WT220U_ZL0353_COLD 0x022a
|
||||
#define USB_PID_WT220U_ZL0353_WARM 0x022b
|
||||
#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
|
||||
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
|
||||
#define USB_PID_AVERMEDIA_VOLAR 0xa807
|
||||
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
|
||||
#define USB_PID_NEBULA_DIGITV 0x0201
|
||||
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
|
||||
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
|
||||
#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501
|
||||
#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD 0xdb00
|
||||
#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01
|
||||
#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10
|
||||
#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD 0xdb50
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59
|
||||
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
|
||||
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55
|
||||
#define USB_PID_MEDION_MD95700 0x0932
|
||||
#define USB_PID_MSI_MEGASKY580 0x5580
|
||||
#define USB_PID_MSI_MEGASKY580_55801 0x5581
|
||||
#define USB_PID_KYE_DVB_T_COLD 0x701e
|
||||
#define USB_PID_KYE_DVB_T_WARM 0x701f
|
||||
#define USB_PID_PCTV_200E 0x020e
|
||||
#define USB_PID_PCTV_400E 0x020f
|
||||
#define USB_PID_LITEON_DVB_T_COLD 0xf000
|
||||
#define USB_PID_LITEON_DVB_T_WARM 0xf001
|
||||
#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
|
||||
#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361
|
||||
#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6
|
||||
#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
|
||||
#define USB_PID_GENPIX_8PSK_COLD 0x0200
|
||||
#define USB_PID_GENPIX_8PSK_WARM 0x0201
|
||||
#define USB_PID_SIGMATEK_DVB_110 0x6610
|
||||
|
||||
|
||||
#endif
|
||||
285
drivers/media/dvb/dvb-usb/dvb-usb-init.c
Normal file
285
drivers/media/dvb/dvb-usb/dvb-usb-init.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* DVB USB library - provides a generic interface for a DVB USB device driver.
|
||||
*
|
||||
* dvb-usb-init.c
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_debug;
|
||||
module_param_named(debug,dvb_usb_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
int dvb_usb_disable_rc_polling;
|
||||
module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
|
||||
MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
|
||||
|
||||
static int dvb_usb_force_pid_filter_usage;
|
||||
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
|
||||
MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
|
||||
|
||||
static int dvb_usb_adapter_init(struct dvb_usb_device *d)
|
||||
{
|
||||
struct dvb_usb_adapter *adap;
|
||||
int ret,n;
|
||||
|
||||
for (n = 0; n < d->props.num_adapters; n++) {
|
||||
adap = &d->adapter[n];
|
||||
adap->dev = d;
|
||||
adap->id = n;
|
||||
|
||||
memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
|
||||
|
||||
/* speed - when running at FULL speed we need a HW PID filter */
|
||||
if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
|
||||
err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
|
||||
(adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
|
||||
info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
|
||||
adap->pid_filtering = 1;
|
||||
adap->max_feed_count = adap->props.pid_filter_count;
|
||||
} else {
|
||||
info("will pass the complete MPEG2 transport stream to the software demuxer.");
|
||||
adap->pid_filtering = 0;
|
||||
adap->max_feed_count = 255;
|
||||
}
|
||||
|
||||
if (!adap->pid_filtering &&
|
||||
dvb_usb_force_pid_filter_usage &&
|
||||
adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) {
|
||||
info("pid filter enabled by module option.");
|
||||
adap->pid_filtering = 1;
|
||||
adap->max_feed_count = adap->props.pid_filter_count;
|
||||
}
|
||||
|
||||
if (adap->props.size_of_priv > 0) {
|
||||
adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
|
||||
if (adap->priv == NULL) {
|
||||
err("no memory for priv for adapter %d.",n);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = dvb_usb_adapter_stream_init(adap)) ||
|
||||
(ret = dvb_usb_adapter_dvb_init(adap)) ||
|
||||
(ret = dvb_usb_adapter_frontend_init(adap))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
d->num_adapters_initialized++;
|
||||
d->state |= DVB_USB_STATE_DVB;
|
||||
}
|
||||
|
||||
/*
|
||||
* when reloading the driver w/o replugging the device
|
||||
* sometimes a timeout occures, this helps
|
||||
*/
|
||||
if (d->props.generic_bulk_ctrl_endpoint != 0) {
|
||||
usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
|
||||
usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < d->num_adapters_initialized; n++) {
|
||||
dvb_usb_adapter_frontend_exit(&d->adapter[n]);
|
||||
dvb_usb_adapter_dvb_exit(&d->adapter[n]);
|
||||
dvb_usb_adapter_stream_exit(&d->adapter[n]);
|
||||
kfree(d->adapter[n].priv);
|
||||
}
|
||||
d->num_adapters_initialized = 0;
|
||||
d->state &= ~DVB_USB_STATE_DVB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* general initialization functions */
|
||||
static int dvb_usb_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
deb_info("state before exiting everything: %x\n",d->state);
|
||||
dvb_usb_remote_exit(d);
|
||||
dvb_usb_adapter_exit(d);
|
||||
dvb_usb_i2c_exit(d);
|
||||
deb_info("state should be zero now: %x\n",d->state);
|
||||
d->state = DVB_USB_STATE_INIT;
|
||||
kfree(d->priv);
|
||||
kfree(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_init(&d->usb_mutex);
|
||||
mutex_init(&d->i2c_mutex);
|
||||
|
||||
d->state = DVB_USB_STATE_INIT;
|
||||
|
||||
if (d->props.size_of_priv > 0) {
|
||||
d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
|
||||
if (d->priv == NULL) {
|
||||
err("no memory for priv in 'struct dvb_usb_device'");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* check the capabilities and set appropriate variables */
|
||||
dvb_usb_device_power_ctrl(d, 1);
|
||||
|
||||
if ((ret = dvb_usb_i2c_init(d)) ||
|
||||
(ret = dvb_usb_adapter_init(d))) {
|
||||
dvb_usb_exit(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dvb_usb_remote_init(d)))
|
||||
err("could not initialize remote control.");
|
||||
|
||||
dvb_usb_device_power_ctrl(d, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* determine the name and the state of the just found USB device */
|
||||
static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
|
||||
{
|
||||
int i,j;
|
||||
struct dvb_usb_device_description *desc = NULL;
|
||||
*cold = -1;
|
||||
|
||||
for (i = 0; i < props->num_device_descs; i++) {
|
||||
|
||||
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
|
||||
deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
|
||||
if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
|
||||
props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
|
||||
*cold = 1;
|
||||
desc = &props->devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc != NULL)
|
||||
break;
|
||||
|
||||
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
|
||||
deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
|
||||
if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
|
||||
props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
|
||||
*cold = 0;
|
||||
desc = &props->devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (desc != NULL && props->identify_state != NULL)
|
||||
props->identify_state(udev,props,&desc,cold);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
if (onoff)
|
||||
d->powered++;
|
||||
else
|
||||
d->powered--;
|
||||
|
||||
if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
|
||||
deb_info("power control: %d\n", onoff);
|
||||
if (d->props.power_ctrl)
|
||||
return d->props.power_ctrl(d, onoff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* USB
|
||||
*/
|
||||
int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_device_properties
|
||||
*props, struct module *owner,struct dvb_usb_device **du)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct dvb_usb_device *d = NULL;
|
||||
struct dvb_usb_device_description *desc = NULL;
|
||||
|
||||
int ret = -ENOMEM,cold=0;
|
||||
|
||||
if (du != NULL)
|
||||
*du = NULL;
|
||||
|
||||
if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
|
||||
deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (cold) {
|
||||
info("found a '%s' in cold state, will try to load a firmware",desc->name);
|
||||
ret = dvb_usb_download_firmware(udev,props);
|
||||
if (!props->no_reconnect || ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
info("found a '%s' in warm state.",desc->name);
|
||||
d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
|
||||
if (d == NULL) {
|
||||
err("no memory for 'struct dvb_usb_device'");
|
||||
return ret;
|
||||
}
|
||||
|
||||
d->udev = udev;
|
||||
memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
|
||||
d->desc = desc;
|
||||
d->owner = owner;
|
||||
|
||||
usb_set_intfdata(intf, d);
|
||||
|
||||
if (du != NULL)
|
||||
*du = d;
|
||||
|
||||
ret = dvb_usb_init(d);
|
||||
|
||||
if (ret == 0)
|
||||
info("%s successfully initialized and connected.",desc->name);
|
||||
else
|
||||
info("%s error while loading driver (%d)",desc->name,ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_device_init);
|
||||
|
||||
void dvb_usb_device_exit(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
const char *name = "generic DVB-USB module";
|
||||
|
||||
usb_set_intfdata(intf,NULL);
|
||||
if (d != NULL && d->desc != NULL) {
|
||||
name = d->desc->name;
|
||||
dvb_usb_exit(d);
|
||||
}
|
||||
info("%s successfully deinitialized and disconnected.",name);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_device_exit);
|
||||
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
|
||||
MODULE_LICENSE("GPL");
|
||||
198
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
Normal file
198
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/* dvb-usb-remote.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file contains functions for initializing the the input-device and for handling remote-control-queries.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
/* Remote-control poll function - called every dib->rc_query_interval ms to see
|
||||
* whether the remote control has received anything.
|
||||
*
|
||||
* TODO: Fix the repeat rate of the input device.
|
||||
*/
|
||||
static void dvb_usb_read_remote_control(struct work_struct *work)
|
||||
{
|
||||
struct dvb_usb_device *d =
|
||||
container_of(work, struct dvb_usb_device, rc_query_work.work);
|
||||
u32 event;
|
||||
int state;
|
||||
|
||||
/* TODO: need a lock here. We can simply skip checking for the remote control
|
||||
if we're busy. */
|
||||
|
||||
/* when the parameter has been set to 1 via sysfs while the driver was running */
|
||||
if (dvb_usb_disable_rc_polling)
|
||||
return;
|
||||
|
||||
if (d->props.rc_query(d,&event,&state)) {
|
||||
err("error while querying for an remote control event.");
|
||||
goto schedule;
|
||||
}
|
||||
|
||||
|
||||
switch (state) {
|
||||
case REMOTE_NO_KEY_PRESSED:
|
||||
break;
|
||||
case REMOTE_KEY_PRESSED:
|
||||
deb_rc("key pressed\n");
|
||||
d->last_event = event;
|
||||
case REMOTE_KEY_REPEAT:
|
||||
deb_rc("key repeated\n");
|
||||
input_event(d->rc_input_dev, EV_KEY, event, 1);
|
||||
input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
|
||||
input_sync(d->rc_input_dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* improved repeat handling ???
|
||||
switch (state) {
|
||||
case REMOTE_NO_KEY_PRESSED:
|
||||
deb_rc("NO KEY PRESSED\n");
|
||||
if (d->last_state != REMOTE_NO_KEY_PRESSED) {
|
||||
deb_rc("releasing event %d\n",d->last_event);
|
||||
input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
|
||||
input_sync(d->rc_input_dev);
|
||||
}
|
||||
d->last_state = REMOTE_NO_KEY_PRESSED;
|
||||
d->last_event = 0;
|
||||
break;
|
||||
case REMOTE_KEY_PRESSED:
|
||||
deb_rc("KEY PRESSED\n");
|
||||
deb_rc("pressing event %d\n",event);
|
||||
|
||||
input_event(d->rc_input_dev, EV_KEY, event, 1);
|
||||
input_sync(d->rc_input_dev);
|
||||
|
||||
d->last_event = event;
|
||||
d->last_state = REMOTE_KEY_PRESSED;
|
||||
break;
|
||||
case REMOTE_KEY_REPEAT:
|
||||
deb_rc("KEY_REPEAT\n");
|
||||
if (d->last_state != REMOTE_NO_KEY_PRESSED) {
|
||||
deb_rc("repeating event %d\n",d->last_event);
|
||||
input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);
|
||||
input_sync(d->rc_input_dev);
|
||||
d->last_state = REMOTE_KEY_REPEAT;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
schedule:
|
||||
schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
|
||||
}
|
||||
|
||||
int dvb_usb_remote_init(struct dvb_usb_device *d)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
if (d->props.rc_key_map == NULL ||
|
||||
d->props.rc_query == NULL ||
|
||||
dvb_usb_disable_rc_polling)
|
||||
return 0;
|
||||
|
||||
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
|
||||
strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY);
|
||||
input_dev->name = "IR-receiver inside an USB DVB receiver";
|
||||
input_dev->phys = d->rc_phys;
|
||||
usb_to_input_id(d->udev, &input_dev->id);
|
||||
input_dev->cdev.dev = &d->udev->dev;
|
||||
|
||||
/* set the bits for the keys */
|
||||
deb_rc("key map size: %d\n", d->props.rc_key_map_size);
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
deb_rc("setting bit for event %d item %d\n",
|
||||
d->props.rc_key_map[i].event, i);
|
||||
set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
|
||||
}
|
||||
|
||||
/* Start the remote-control polling. */
|
||||
if (d->props.rc_interval < 40)
|
||||
d->props.rc_interval = 100; /* default */
|
||||
|
||||
/* setting these two values to non-zero, we have to manage key repeats */
|
||||
input_dev->rep[REP_PERIOD] = d->props.rc_interval;
|
||||
input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
d->rc_input_dev = input_dev;
|
||||
|
||||
INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
|
||||
|
||||
info("schedule remote query interval to %d msecs.", d->props.rc_interval);
|
||||
schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
|
||||
|
||||
d->state |= DVB_USB_STATE_REMOTE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_usb_remote_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
if (d->state & DVB_USB_STATE_REMOTE) {
|
||||
cancel_rearming_delayed_work(&d->rc_query_work);
|
||||
flush_scheduled_work();
|
||||
input_unregister_device(d->rc_input_dev);
|
||||
}
|
||||
d->state &= ~DVB_USB_STATE_REMOTE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DVB_USB_RC_NEC_EMPTY 0x00
|
||||
#define DVB_USB_RC_NEC_KEY_PRESSED 0x01
|
||||
#define DVB_USB_RC_NEC_KEY_REPEATED 0x02
|
||||
int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
|
||||
u8 keybuf[5], u32 *event, int *state)
|
||||
{
|
||||
int i;
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
switch (keybuf[0]) {
|
||||
case DVB_USB_RC_NEC_EMPTY:
|
||||
break;
|
||||
case DVB_USB_RC_NEC_KEY_PRESSED:
|
||||
if ((u8) ~keybuf[1] != keybuf[2] ||
|
||||
(u8) ~keybuf[3] != keybuf[4]) {
|
||||
deb_err("remote control checksum failed.\n");
|
||||
break;
|
||||
}
|
||||
/* See if we can match the raw key code. */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (keymap[i].custom == keybuf[1] &&
|
||||
keymap[i].data == keybuf[3]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
deb_err("key mapping failed - no appropriate key found in keymapping\n");
|
||||
break;
|
||||
case DVB_USB_RC_NEC_KEY_REPEATED:
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
break;
|
||||
default:
|
||||
deb_err("unkown type of remote status: %d\n",keybuf[0]);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
|
||||
95
drivers/media/dvb/dvb-usb/dvb-usb-urb.c
Normal file
95
drivers/media/dvb/dvb-usb/dvb-usb-urb.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/* dvb-usb-urb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file keeps functions for initializing and handling the
|
||||
* USB and URB stuff.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
|
||||
u16 rlen, int delay_ms)
|
||||
{
|
||||
int actlen,ret = -ENOMEM;
|
||||
|
||||
if (d->props.generic_bulk_ctrl_endpoint == 0) {
|
||||
err("endpoint for generic control not specified.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wbuf == NULL || wlen == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
deb_xfer(">>> ");
|
||||
debug_dump(wbuf,wlen,deb_xfer);
|
||||
|
||||
ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
|
||||
d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
|
||||
2000);
|
||||
|
||||
if (ret)
|
||||
err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
|
||||
else
|
||||
ret = actlen != wlen ? -1 : 0;
|
||||
|
||||
/* an answer is expected, and no error before */
|
||||
if (!ret && rbuf && rlen) {
|
||||
if (delay_ms)
|
||||
msleep(delay_ms);
|
||||
|
||||
ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
|
||||
d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
|
||||
2000);
|
||||
|
||||
if (ret)
|
||||
err("recv bulk message failed: %d",ret);
|
||||
else {
|
||||
deb_xfer("<<< ");
|
||||
debug_dump(rbuf,actlen,deb_xfer);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_generic_rw);
|
||||
|
||||
int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
|
||||
{
|
||||
return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_generic_write);
|
||||
|
||||
static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = stream->user_priv;
|
||||
if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
|
||||
dvb_dmx_swfilter(&adap->demux, buffer, length);
|
||||
}
|
||||
|
||||
static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = stream->user_priv;
|
||||
if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
|
||||
dvb_dmx_swfilter_204(&adap->demux, buffer, length);
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->stream.udev = adap->dev->udev;
|
||||
if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
|
||||
adap->stream.complete = dvb_usb_data_complete_204;
|
||||
else
|
||||
adap->stream.complete = dvb_usb_data_complete;
|
||||
adap->stream.user_priv = adap;
|
||||
return usb_urb_init(&adap->stream, &adap->props.stream);
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return usb_urb_exit(&adap->stream);
|
||||
}
|
||||
408
drivers/media/dvb/dvb-usb/dvb-usb.h
Normal file
408
drivers/media/dvb/dvb-usb/dvb-usb.h
Normal file
@@ -0,0 +1,408 @@
|
||||
/* dvb-usb.h is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* the headerfile, all dvb-usb-drivers have to include.
|
||||
*
|
||||
* TODO: clean-up the structures for unused fields and update the comments
|
||||
*/
|
||||
#ifndef __DVB_USB_H__
|
||||
#define __DVB_USB_H__
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_net.h"
|
||||
#include "dmxdev.h"
|
||||
|
||||
#include "dvb-pll.h"
|
||||
|
||||
#include "dvb-usb-ids.h"
|
||||
|
||||
/* debug */
|
||||
#ifdef CONFIG_DVB_USB_DEBUG
|
||||
#define dprintk(var,level,args...) \
|
||||
do { if ((var & level)) { printk(args); } } while (0)
|
||||
|
||||
#define debug_dump(b,l,func) {\
|
||||
int loop_; \
|
||||
for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
|
||||
func("\n");\
|
||||
}
|
||||
#define DVB_USB_DEBUG_STATUS
|
||||
#else
|
||||
#define dprintk(args...)
|
||||
#define debug_dump(b,l,func)
|
||||
|
||||
#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
|
||||
|
||||
#endif
|
||||
|
||||
/* generic log methods - taken from usb.h */
|
||||
#ifndef DVB_USB_LOG_PREFIX
|
||||
#define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
|
||||
#endif
|
||||
|
||||
#undef err
|
||||
#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
#undef info
|
||||
#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
#undef warn
|
||||
#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
|
||||
/**
|
||||
* struct dvb_usb_device_description - name and its according USB IDs
|
||||
* @name: real name of the box, regardless which DVB USB device class is in use
|
||||
* @cold_ids: array of struct usb_device_id which describe the device in
|
||||
* pre-firmware state
|
||||
* @warm_ids: array of struct usb_device_id which describe the device in
|
||||
* post-firmware state
|
||||
*
|
||||
* Each DVB USB device class can have one or more actual devices, this struct
|
||||
* assigns a name to it.
|
||||
*/
|
||||
struct dvb_usb_device_description {
|
||||
const char *name;
|
||||
|
||||
#define DVB_USB_ID_MAX_NUM 15
|
||||
struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
|
||||
struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_rc_key - a remote control key and its input-event
|
||||
* @custom: the vendor/custom part of the key
|
||||
* @data: the actual key part
|
||||
* @event: the input event assigned to key identified by custom and data
|
||||
*/
|
||||
struct dvb_usb_rc_key {
|
||||
u8 custom,data;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
struct dvb_usb_device;
|
||||
struct dvb_usb_adapter;
|
||||
struct usb_data_stream;
|
||||
|
||||
/**
|
||||
* Properties of USB streaming - TODO this structure should be somewhere else
|
||||
* describes the kind of USB transfer used for data-streaming.
|
||||
* (BULK or ISOC)
|
||||
*/
|
||||
struct usb_data_stream_properties {
|
||||
#define USB_BULK 1
|
||||
#define USB_ISOC 2
|
||||
int type;
|
||||
int count;
|
||||
int endpoint;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int buffersize; /* per URB */
|
||||
} bulk;
|
||||
struct {
|
||||
int framesperurb;
|
||||
int framesize;
|
||||
int interval;
|
||||
} isoc;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
|
||||
* A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
|
||||
* @caps: capabilities of the DVB USB device.
|
||||
* @pid_filter_count: number of PID filter position in the optional hardware
|
||||
* PID-filter.
|
||||
* @streaming_crtl: called to start and stop the MPEG2-TS streaming of the
|
||||
* device (not URB submitting/killing).
|
||||
* @pid_filter_ctrl: called to en/disable the PID filter, if any.
|
||||
* @pid_filter: called to set/unset a PID for filtering.
|
||||
* @frontend_attach: called to attach the possible frontends (fill fe-field
|
||||
* of struct dvb_usb_device).
|
||||
* @tuner_attach: called to attach the correct tuner and to fill pll_addr,
|
||||
* pll_desc and pll_init_buf of struct dvb_usb_device).
|
||||
* @stream: configuration of the USB streaming
|
||||
*/
|
||||
struct dvb_usb_adapter_properties {
|
||||
#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
|
||||
#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
|
||||
#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
|
||||
#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
|
||||
int caps;
|
||||
int pid_filter_count;
|
||||
|
||||
int (*streaming_ctrl) (struct dvb_usb_adapter *, int);
|
||||
int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
|
||||
int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
|
||||
|
||||
int (*frontend_attach) (struct dvb_usb_adapter *);
|
||||
int (*tuner_attach) (struct dvb_usb_adapter *);
|
||||
|
||||
struct usb_data_stream_properties stream;
|
||||
|
||||
int size_of_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_device_properties - properties of a dvb-usb-device
|
||||
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
|
||||
* download.
|
||||
* @firmware: name of the firmware file.
|
||||
* @download_firmware: called to download the firmware when the usb_ctrl is
|
||||
* DEVICE_SPECIFIC.
|
||||
* @no_reconnect: device doesn't do a reconnect after downloading the firmware,
|
||||
* so do the warm initialization right after it
|
||||
*
|
||||
* @size_of_priv: how many bytes shall be allocated for the private field
|
||||
* of struct dvb_usb_device.
|
||||
*
|
||||
* @power_ctrl: called to enable/disable power of the device.
|
||||
* @read_mac_address: called to read the MAC address of the device.
|
||||
* @identify_state: called to determine the state (cold or warm), when it
|
||||
* is not distinguishable by the USB IDs.
|
||||
*
|
||||
* @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
|
||||
* remote control handling).
|
||||
* @rc_key_map_size: number of items in @rc_key_map.
|
||||
* @rc_query: called to query an event event.
|
||||
* @rc_interval: time in ms between two queries.
|
||||
*
|
||||
* @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
|
||||
*
|
||||
* @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
|
||||
* endpoint which received control messages with bulk transfers. When this
|
||||
* is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
|
||||
* helper functions.
|
||||
*
|
||||
* @num_device_descs: number of struct dvb_usb_device_description in @devices
|
||||
* @devices: array of struct dvb_usb_device_description compatibles with these
|
||||
* properties.
|
||||
*/
|
||||
#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
|
||||
struct dvb_usb_device_properties {
|
||||
|
||||
#define DVB_USB_IS_AN_I2C_ADAPTER 0x01
|
||||
int caps;
|
||||
|
||||
#define DEVICE_SPECIFIC 0
|
||||
#define CYPRESS_AN2135 1
|
||||
#define CYPRESS_AN2235 2
|
||||
#define CYPRESS_FX2 3
|
||||
int usb_ctrl;
|
||||
int (*download_firmware) (struct usb_device *, const struct firmware *);
|
||||
const char firmware[FIRMWARE_NAME_MAX];
|
||||
int no_reconnect;
|
||||
|
||||
int size_of_priv;
|
||||
|
||||
int num_adapters;
|
||||
struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
|
||||
|
||||
int (*power_ctrl) (struct dvb_usb_device *, int);
|
||||
int (*read_mac_address) (struct dvb_usb_device *, u8 []);
|
||||
int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
|
||||
struct dvb_usb_device_description **, int *);
|
||||
|
||||
/* remote control properties */
|
||||
#define REMOTE_NO_KEY_PRESSED 0x00
|
||||
#define REMOTE_KEY_PRESSED 0x01
|
||||
#define REMOTE_KEY_REPEAT 0x02
|
||||
struct dvb_usb_rc_key *rc_key_map;
|
||||
int rc_key_map_size;
|
||||
int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
|
||||
int rc_interval;
|
||||
|
||||
struct i2c_algorithm *i2c_algo;
|
||||
|
||||
int generic_bulk_ctrl_endpoint;
|
||||
|
||||
int num_device_descs;
|
||||
struct dvb_usb_device_description devices[9];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct usb_data_stream - generic object of an USB stream
|
||||
* @buf_num: number of buffer allocated.
|
||||
* @buf_size: size of each buffer in buf_list.
|
||||
* @buf_list: array containing all allocate buffers for streaming.
|
||||
* @dma_addr: list of dma_addr_t for each buffer in buf_list.
|
||||
*
|
||||
* @urbs_initialized: number of URBs initialized.
|
||||
* @urbs_submitted: number of URBs submitted.
|
||||
*/
|
||||
#define MAX_NO_URBS_FOR_DATA_STREAM 10
|
||||
struct usb_data_stream {
|
||||
struct usb_device *udev;
|
||||
struct usb_data_stream_properties props;
|
||||
|
||||
#define USB_STATE_INIT 0x00
|
||||
#define USB_STATE_URB_BUF 0x01
|
||||
int state;
|
||||
|
||||
void (*complete) (struct usb_data_stream *, u8 *, size_t);
|
||||
|
||||
struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
int buf_num;
|
||||
unsigned long buf_size;
|
||||
u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
|
||||
int urbs_initialized;
|
||||
int urbs_submitted;
|
||||
|
||||
void *user_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_adapter - a DVB adapter on a USB device
|
||||
* @id: index of this adapter (starting with 0).
|
||||
*
|
||||
* @feedcount: number of reqested feeds (used for streaming-activation)
|
||||
* @pid_filtering: is hardware pid_filtering used or not.
|
||||
*
|
||||
* @pll_addr: I2C address of the tuner for programming
|
||||
* @pll_init: array containing the initialization buffer
|
||||
* @pll_desc: pointer to the appropriate struct dvb_pll_desc
|
||||
* @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
|
||||
*
|
||||
* @dvb_adap: device's dvb_adapter.
|
||||
* @dmxdev: device's dmxdev.
|
||||
* @demux: device's software demuxer.
|
||||
* @dvb_net: device's dvb_net interfaces.
|
||||
* @dvb_frontend: device's frontend.
|
||||
* @max_feed_count: how many feeds can be handled simultaneously by this
|
||||
* device
|
||||
*
|
||||
* @fe_init: rerouted frontend-init (wakeup) function.
|
||||
* @fe_sleep: rerouted frontend-sleep function.
|
||||
*
|
||||
* @stream: the usb data stream.
|
||||
*/
|
||||
struct dvb_usb_adapter {
|
||||
struct dvb_usb_device *dev;
|
||||
struct dvb_usb_adapter_properties props;
|
||||
|
||||
#define DVB_USB_ADAP_STATE_INIT 0x000
|
||||
#define DVB_USB_ADAP_STATE_DVB 0x001
|
||||
int state;
|
||||
|
||||
u8 id;
|
||||
|
||||
int feedcount;
|
||||
int pid_filtering;
|
||||
|
||||
/* tuner programming information */
|
||||
u8 pll_addr;
|
||||
u8 pll_init[4];
|
||||
struct dvb_pll_desc *pll_desc;
|
||||
int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
|
||||
|
||||
/* dvb */
|
||||
struct dvb_adapter dvb_adap;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_demux demux;
|
||||
struct dvb_net dvb_net;
|
||||
struct dvb_frontend *fe;
|
||||
int max_feed_count;
|
||||
|
||||
int (*fe_init) (struct dvb_frontend *);
|
||||
int (*fe_sleep) (struct dvb_frontend *);
|
||||
|
||||
struct usb_data_stream stream;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_device - object of a DVB USB device
|
||||
* @props: copy of the struct dvb_usb_properties this device belongs to.
|
||||
* @desc: pointer to the device's struct dvb_usb_device_description.
|
||||
* @state: initialization and runtime state of the device.
|
||||
*
|
||||
* @powered: indicated whether the device is power or not.
|
||||
* Powered is in/decremented for each call to modify the state.
|
||||
* @udev: pointer to the device's struct usb_device.
|
||||
*
|
||||
* @usb_mutex: semaphore of USB control messages (reading needs two messages)
|
||||
* @i2c_mutex: semaphore for i2c-transfers
|
||||
*
|
||||
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
|
||||
*
|
||||
* @rc_input_dev: input device for the remote control.
|
||||
* @rc_query_work: struct work_struct frequent rc queries
|
||||
* @last_event: last triggered event
|
||||
* @last_state: last state (no, pressed, repeat)
|
||||
* @owner: owner of the dvb_adapter
|
||||
* @priv: private data of the actual driver (allocate by dvb-usb, size defined
|
||||
* in size_of_priv of dvb_usb_properties).
|
||||
*/
|
||||
struct dvb_usb_device {
|
||||
struct dvb_usb_device_properties props;
|
||||
struct dvb_usb_device_description *desc;
|
||||
|
||||
struct usb_device *udev;
|
||||
|
||||
#define DVB_USB_STATE_INIT 0x000
|
||||
#define DVB_USB_STATE_I2C 0x001
|
||||
#define DVB_USB_STATE_DVB 0x002
|
||||
#define DVB_USB_STATE_REMOTE 0x004
|
||||
int state;
|
||||
|
||||
int powered;
|
||||
|
||||
/* locking */
|
||||
struct mutex usb_mutex;
|
||||
|
||||
/* i2c */
|
||||
struct mutex i2c_mutex;
|
||||
struct i2c_adapter i2c_adap;
|
||||
|
||||
int num_adapters_initialized;
|
||||
struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
|
||||
|
||||
/* remote control */
|
||||
struct input_dev *rc_input_dev;
|
||||
char rc_phys[64];
|
||||
struct delayed_work rc_query_work;
|
||||
u32 last_event;
|
||||
int last_state;
|
||||
|
||||
struct module *owner;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_device_properties *, struct module *, struct dvb_usb_device **);
|
||||
extern void dvb_usb_device_exit(struct usb_interface *);
|
||||
|
||||
/* the generic read/write method for device control */
|
||||
extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
|
||||
extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
|
||||
|
||||
/* commonly used remote control parsing */
|
||||
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
|
||||
|
||||
/* commonly used pll init and set functions */
|
||||
extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
|
||||
extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
|
||||
extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
|
||||
|
||||
/* commonly used firmware download types and function */
|
||||
struct hexline {
|
||||
u8 len;
|
||||
u32 addr;
|
||||
u8 type;
|
||||
u8 data[255];
|
||||
u8 chk;
|
||||
};
|
||||
extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
|
||||
extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
|
||||
|
||||
|
||||
#endif
|
||||
231
drivers/media/dvb/dvb-usb/gl861.c
Normal file
231
drivers/media/dvb/dvb-usb/gl861.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/* DVB USB compliant linux driver for GL861 USB2.0 devices.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "gl861.h"
|
||||
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_gl861_debug;
|
||||
module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index;
|
||||
u16 value = addr << 8;
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 req, type;
|
||||
|
||||
if (wo) {
|
||||
req = GL861_REQ_I2C_WRITE;
|
||||
type = GL861_WRITE;
|
||||
} else { /* rw */
|
||||
req = GL861_REQ_I2C_READ;
|
||||
type = GL861_READ;
|
||||
}
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0];
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
default:
|
||||
warn("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
|
||||
value, index, rbuf, rlen, 2000);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 gl861_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm gl861_i2c_algo = {
|
||||
.master_xfer = gl861_i2c_xfer,
|
||||
.functionality = gl861_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int gl861_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zl10353_config gl861_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
|
||||
&adap->dev->i2c_adap)) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct qt1010_config gl861_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
};
|
||||
|
||||
static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe, &adap->dev->i2c_adap,
|
||||
&gl861_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties gl861_properties;
|
||||
|
||||
static int gl861_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if (intf->num_altsetting < 2)
|
||||
return -ENODEV;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d)) == 0) {
|
||||
alt = usb_altnum_to_altsetting(intf, 0);
|
||||
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id gl861_table [] = {
|
||||
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, gl861_table);
|
||||
|
||||
static struct dvb_usb_device_properties gl861_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.identify_state = gl861_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
|
||||
.frontend_attach = gl861_frontend_attach,
|
||||
.tuner_attach = gl861_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x81,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.i2c_algo = &gl861_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "MSI Mega Sky 55801 DVB-T USB2.0",
|
||||
{ &gl861_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver gl861_driver = {
|
||||
.name = "dvb_usb_gl861",
|
||||
.probe = gl861_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = gl861_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init gl861_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&gl861_driver))) {
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit gl861_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&gl861_driver);
|
||||
}
|
||||
|
||||
module_init (gl861_module_init);
|
||||
module_exit (gl861_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
15
drivers/media/dvb/dvb-usb/gl861.h
Normal file
15
drivers/media/dvb/dvb-usb/gl861.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _DVB_USB_GL861_H_
|
||||
#define _DVB_USB_GL861_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "gl861"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args)
|
||||
|
||||
#define GL861_WRITE 0x40
|
||||
#define GL861_READ 0xc0
|
||||
|
||||
#define GL861_REQ_I2C_WRITE 0x01
|
||||
#define GL861_REQ_I2C_READ 0x02
|
||||
|
||||
#endif
|
||||
272
drivers/media/dvb/dvb-usb/gp8psk-fe.c
Normal file
272
drivers/media/dvb/dvb-usb/gp8psk-fe.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/* DVB USB compliant Linux driver for the
|
||||
* - GENPIX 8pks/qpsk USB2.0 DVB-S module
|
||||
*
|
||||
* Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
|
||||
*
|
||||
* Thanks to GENPIX for the sample code used to implement this module.
|
||||
*
|
||||
* This module is based off the vp7045 and vp702x modules
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "gp8psk.h"
|
||||
|
||||
struct gp8psk_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
|
||||
struct dvb_usb_device *d;
|
||||
|
||||
u16 snr;
|
||||
|
||||
unsigned long next_snr_check;
|
||||
};
|
||||
|
||||
static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
u8 lock;
|
||||
|
||||
if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
|
||||
return -EINVAL;
|
||||
|
||||
if (lock)
|
||||
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
else
|
||||
*status = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
|
||||
{
|
||||
(void) fe;
|
||||
*ber = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
|
||||
{
|
||||
(void) fe;
|
||||
*unc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
u8 buf[2];
|
||||
|
||||
if (time_after(jiffies,st->next_snr_check)) {
|
||||
gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
|
||||
*snr = (int)(buf[1]) << 8 | buf[0];
|
||||
/* snr is reported in dBu*256 */
|
||||
/* snr / 38.4 ~= 100% strength */
|
||||
/* snr * 17 returns 100% strength as 65535 */
|
||||
if (*snr <= 3855)
|
||||
*snr = (*snr<<4) + *snr; // snr * 17
|
||||
else
|
||||
*snr = 65535;
|
||||
st->next_snr_check = jiffies + (10*HZ)/1000;
|
||||
} else {
|
||||
*snr = st->snr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
|
||||
{
|
||||
return gp8psk_fe_read_snr(fe, strength);
|
||||
}
|
||||
|
||||
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 800;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
u8 cmd[10];
|
||||
u32 freq = fep->frequency * 1000;
|
||||
|
||||
cmd[4] = freq & 0xff;
|
||||
cmd[5] = (freq >> 8) & 0xff;
|
||||
cmd[6] = (freq >> 16) & 0xff;
|
||||
cmd[7] = (freq >> 24) & 0xff;
|
||||
|
||||
switch(fe->ops.info.type) {
|
||||
case FE_QPSK:
|
||||
cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
|
||||
cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
|
||||
cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
|
||||
cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
|
||||
cmd[8] = ADV_MOD_DVB_QPSK;
|
||||
cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
|
||||
break;
|
||||
default:
|
||||
// other modes are unsuported right now
|
||||
cmd[0] = 0;
|
||||
cmd[1] = 0;
|
||||
cmd[2] = 0;
|
||||
cmd[3] = 0;
|
||||
cmd[8] = 0;
|
||||
cmd[9] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
|
||||
|
||||
state->next_snr_check = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
|
||||
if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
|
||||
m->msg, m->msg_len)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
|
||||
fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
u8 cmd;
|
||||
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
|
||||
/* These commands are certainly wrong */
|
||||
cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
|
||||
|
||||
if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
|
||||
&cmd, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
|
||||
if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
|
||||
(tone == SEC_TONE_ON), 0, NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
|
||||
if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
|
||||
voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
u8 cmd = sw_cmd & 0x7f;
|
||||
|
||||
if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
|
||||
NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
|
||||
0, NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gp8psk_fe_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops gp8psk_fe_ops;
|
||||
|
||||
struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
s->d = d;
|
||||
memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
|
||||
goto success;
|
||||
error:
|
||||
return NULL;
|
||||
success:
|
||||
return &s->fe;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops gp8psk_fe_ops = {
|
||||
.info = {
|
||||
.name = "Genpix 8psk-USB DVB-S",
|
||||
.type = FE_QPSK,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 100,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.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
|
||||
},
|
||||
|
||||
.release = gp8psk_fe_release,
|
||||
|
||||
.init = NULL,
|
||||
.sleep = NULL,
|
||||
|
||||
.set_frontend = gp8psk_fe_set_frontend,
|
||||
.get_frontend = gp8psk_fe_get_frontend,
|
||||
.get_tune_settings = gp8psk_fe_get_tune_settings,
|
||||
|
||||
.read_status = gp8psk_fe_read_status,
|
||||
.read_ber = gp8psk_fe_read_ber,
|
||||
.read_signal_strength = gp8psk_fe_read_signal_strength,
|
||||
.read_snr = gp8psk_fe_read_snr,
|
||||
.read_ucblocks = gp8psk_fe_read_unc_blocks,
|
||||
|
||||
.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
|
||||
.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
|
||||
.set_tone = gp8psk_fe_set_tone,
|
||||
.set_voltage = gp8psk_fe_set_voltage,
|
||||
.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
|
||||
};
|
||||
258
drivers/media/dvb/dvb-usb/gp8psk.c
Normal file
258
drivers/media/dvb/dvb-usb/gp8psk.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/* DVB USB compliant Linux driver for the
|
||||
* - GENPIX 8pks/qpsk USB2.0 DVB-S module
|
||||
*
|
||||
* Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
|
||||
*
|
||||
* Thanks to GENPIX for the sample code used to implement this module.
|
||||
*
|
||||
* This module is based off the vp7045 and vp702x modules
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "gp8psk.h"
|
||||
|
||||
/* debug */
|
||||
static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
|
||||
int dvb_usb_gp8psk_debug;
|
||||
module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret = 0,try = 0;
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
while (ret >= 0 && ret != blen && try < 3) {
|
||||
ret = usb_control_msg(d->udev,
|
||||
usb_rcvctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value,index,b,blen,
|
||||
2000);
|
||||
deb_info("reading number %d (ret: %d)\n",try,ret);
|
||||
try++;
|
||||
}
|
||||
|
||||
if (ret < 0 || ret != blen) {
|
||||
warn("usb in operation failed.");
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
if (usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value,index,b,blen,
|
||||
2000) != blen) {
|
||||
warn("usb out operation failed.");
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret;
|
||||
const struct firmware *fw = NULL;
|
||||
u8 *ptr, *buf;
|
||||
if ((ret = request_firmware(&fw, bcm4500_firmware,
|
||||
&d->udev->dev)) != 0) {
|
||||
err("did not find the bcm4500 firmware file. (%s) "
|
||||
"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
|
||||
bcm4500_firmware,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
|
||||
goto out_rel_fw;
|
||||
|
||||
info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
|
||||
|
||||
ptr = fw->data;
|
||||
buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
|
||||
|
||||
while (ptr[0] != 0xff) {
|
||||
u16 buflen = ptr[0] + 4;
|
||||
if (ptr + buflen >= fw->data + fw->size) {
|
||||
err("failed to load bcm4500 firmware.");
|
||||
goto out_free;
|
||||
}
|
||||
memcpy(buf, ptr, buflen);
|
||||
if (dvb_usb_generic_write(d, buf, buflen)) {
|
||||
err("failed to load bcm4500 firmware.");
|
||||
goto out_free;
|
||||
}
|
||||
ptr += buflen;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out_free:
|
||||
kfree(buf);
|
||||
out_rel_fw:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 status, buf;
|
||||
if (onoff) {
|
||||
gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
|
||||
if (! (status & 0x01)) /* started */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (! (status & 0x02)) /* BCM4500 firmware loaded */
|
||||
if(gp8psk_load_bcm4500fw(d))
|
||||
return EINVAL;
|
||||
|
||||
if (! (status & 0x04)) /* LNB Power */
|
||||
if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
|
||||
&buf, 1))
|
||||
return EINVAL;
|
||||
|
||||
/* Set DVB mode */
|
||||
if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
|
||||
return -EINVAL;
|
||||
gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
|
||||
} else {
|
||||
/* Turn off LNB power */
|
||||
if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
|
||||
return EINVAL;
|
||||
/* Turn off 8psk power */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
|
||||
}
|
||||
|
||||
static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe = gp8psk_fe_attach(adap->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties gp8psk_properties;
|
||||
|
||||
static int gp8psk_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
|
||||
}
|
||||
|
||||
static struct usb_device_id gp8psk_usb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties gp8psk_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-gp8psk-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = gp8psk_streaming_ctrl,
|
||||
.frontend_attach = gp8psk_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.power_ctrl = gp8psk_power_ctrl,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
|
||||
.cold_ids = { &gp8psk_usb_table[0], NULL },
|
||||
.warm_ids = { &gp8psk_usb_table[1], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver gp8psk_usb_driver = {
|
||||
.name = "dvb_usb_gp8psk",
|
||||
.probe = gp8psk_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = gp8psk_usb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init gp8psk_usb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&gp8psk_usb_driver))) {
|
||||
err("usb_register failed. (%d)",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit gp8psk_usb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&gp8psk_usb_driver);
|
||||
}
|
||||
|
||||
module_init(gp8psk_usb_module_init);
|
||||
module_exit(gp8psk_usb_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
|
||||
MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
79
drivers/media/dvb/dvb-usb/gp8psk.h
Normal file
79
drivers/media/dvb/dvb-usb/gp8psk.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* DVB USB compliant Linux driver for the
|
||||
* - GENPIX 8pks/qpsk USB2.0 DVB-S module
|
||||
*
|
||||
* Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
|
||||
*
|
||||
* Thanks to GENPIX for the sample code used to implement this module.
|
||||
*
|
||||
* This module is based off the vp7045 and vp702x modules
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#ifndef _DVB_USB_GP8PSK_H_
|
||||
#define _DVB_USB_GP8PSK_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "gp8psk"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_gp8psk_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
|
||||
/* gp8psk commands */
|
||||
|
||||
/* Twinhan Vendor requests */
|
||||
#define TH_COMMAND_IN 0xC0
|
||||
#define TH_COMMAND_OUT 0xC1
|
||||
|
||||
/* command bytes */
|
||||
#define GET_8PSK_CONFIG 0x80
|
||||
#define SET_8PSK_CONFIG 0x81
|
||||
#define ARM_TRANSFER 0x85
|
||||
#define TUNE_8PSK 0x86
|
||||
#define GET_SIGNAL_STRENGTH 0x87
|
||||
#define LOAD_BCM4500 0x88
|
||||
#define BOOT_8PSK 0x89
|
||||
#define START_INTERSIL 0x8A
|
||||
#define SET_LNB_VOLTAGE 0x8B
|
||||
#define SET_22KHZ_TONE 0x8C
|
||||
#define SEND_DISEQC_COMMAND 0x8D
|
||||
#define SET_DVB_MODE 0x8E
|
||||
#define SET_DN_SWITCH 0x8F
|
||||
#define GET_SIGNAL_LOCK 0x90
|
||||
|
||||
/* Satellite modulation modes */
|
||||
#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
|
||||
#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */
|
||||
#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */
|
||||
#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */
|
||||
|
||||
#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */
|
||||
#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */
|
||||
#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */
|
||||
#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
|
||||
#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */
|
||||
#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */
|
||||
|
||||
#define GET_USB_SPEED 0x07
|
||||
#define USB_SPEED_LOW 0
|
||||
#define USB_SPEED_FULL 1
|
||||
#define USB_SPEED_HIGH 2
|
||||
|
||||
#define RESET_FX2 0x13
|
||||
|
||||
#define FW_VERSION_READ 0x0B
|
||||
#define VENDOR_STRING_READ 0x0C
|
||||
#define PRODUCT_STRING_READ 0x0D
|
||||
#define FW_BCD_VERSION_READ 0x14
|
||||
|
||||
extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
|
||||
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
|
||||
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen);
|
||||
|
||||
#endif
|
||||
541
drivers/media/dvb/dvb-usb/m920x.c
Normal file
541
drivers/media/dvb/dvb-usb/m920x.c
Normal file
@@ -0,0 +1,541 @@
|
||||
/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
|
||||
#include "m920x.h"
|
||||
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_m920x_debug;
|
||||
module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static struct dvb_usb_rc_key megasky_rc_keys [] = {
|
||||
{ 0x0, 0x12, KEY_POWER },
|
||||
{ 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
|
||||
{ 0x0, 0x02, KEY_CHANNELUP },
|
||||
{ 0x0, 0x05, KEY_CHANNELDOWN },
|
||||
{ 0x0, 0x03, KEY_VOLUMEUP },
|
||||
{ 0x0, 0x06, KEY_VOLUMEDOWN },
|
||||
{ 0x0, 0x04, KEY_MUTE },
|
||||
{ 0x0, 0x07, KEY_OK }, /* TS */
|
||||
{ 0x0, 0x08, KEY_STOP },
|
||||
{ 0x0, 0x09, KEY_MENU }, /* swap */
|
||||
{ 0x0, 0x0a, KEY_REWIND },
|
||||
{ 0x0, 0x1b, KEY_PAUSE },
|
||||
{ 0x0, 0x1f, KEY_FASTFORWARD },
|
||||
{ 0x0, 0x0c, KEY_RECORD },
|
||||
{ 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
|
||||
};
|
||||
|
||||
static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
|
||||
u16 index, void *data, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
request, USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, data, size, 2000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != size)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int m9206_write(struct usb_device *udev, u8 request,
|
||||
u16 value, u16 index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
request, USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value, index, NULL, 0, 2000);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_rc_init(struct usb_device *udev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Remote controller init. */
|
||||
if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct m9206_state *m = d->priv;
|
||||
int i, ret = 0;
|
||||
u8 rc_state[2];
|
||||
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
|
||||
goto unlock;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
|
||||
if (megasky_rc_keys[i].data == rc_state[1]) {
|
||||
*event = megasky_rc_keys[i].event;
|
||||
|
||||
switch(rc_state[0]) {
|
||||
case 0x80:
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
goto unlock;
|
||||
|
||||
case 0x93:
|
||||
case 0x92:
|
||||
m->rep_count = 0;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
goto unlock;
|
||||
|
||||
case 0x91:
|
||||
/* For comfort. */
|
||||
if (++m->rep_count > 2)
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
goto unlock;
|
||||
|
||||
default:
|
||||
deb_rc("Unexpected rc response %x\n", rc_state[0]);
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_state[1] != 0)
|
||||
deb_rc("Unknown rc key %x\n", rc_state[1]);
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
unlock:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct m9206_state *m = d->priv;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
|
||||
int i2c_i;
|
||||
|
||||
for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
|
||||
if (msg[i].addr == m->i2c_r[i2c_i].addr)
|
||||
break;
|
||||
|
||||
if (i2c_i >= M9206_I2C_MAX) {
|
||||
deb_rc("No magic for i2c addr!\n");
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
|
||||
goto unlock;
|
||||
|
||||
i++;
|
||||
} else {
|
||||
if (msg[i].len != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
ret = i;
|
||||
unlock:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 m9206_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm m9206_i2c_algo = {
|
||||
.master_xfer = m9206_i2c_xfer,
|
||||
.functionality = m9206_i2c_func,
|
||||
};
|
||||
|
||||
|
||||
static int m9206_set_filter(struct dvb_usb_adapter *adap, int type, int idx,
|
||||
int pid)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (pid >= 0x8000)
|
||||
return -EINVAL;
|
||||
|
||||
pid |= 0x8000;
|
||||
|
||||
if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_update_filters(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
int enabled = m->filtering_enabled;
|
||||
int i, ret = 0, filter = 0;
|
||||
|
||||
for (i = 0; i < M9206_MAX_FILTERS; i++)
|
||||
if (m->filters[i] == 8192)
|
||||
enabled = 0;
|
||||
|
||||
/* Disable all filters */
|
||||
if ((ret = m9206_set_filter(adap, 0x81, 1, enabled)) != 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < M9206_MAX_FILTERS; i++)
|
||||
if ((ret = m9206_set_filter(adap, 0x81, i + 2, 0)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_set_filter(adap, 0x82, 0, 0x0)) != 0)
|
||||
return ret;
|
||||
|
||||
/* Set */
|
||||
if (enabled) {
|
||||
for (i = 0; i < M9206_MAX_FILTERS; i++) {
|
||||
if (m->filters[i] == 0)
|
||||
continue;
|
||||
|
||||
if ((ret = m9206_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
|
||||
return ret;
|
||||
|
||||
filter++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = m9206_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->filtering_enabled = onoff ? 1 : 0;
|
||||
|
||||
return m9206_update_filters(adap);
|
||||
}
|
||||
|
||||
static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
||||
int onoff)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->filters[index] = onoff ? pid : 0;
|
||||
|
||||
return m9206_update_filters(adap);
|
||||
}
|
||||
|
||||
static int m9206_firmware_download(struct usb_device *udev,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u16 value, index, size;
|
||||
u8 read[4], *buff;
|
||||
int i, pass, ret = 0;
|
||||
|
||||
buff = kmalloc(65536, GFP_KERNEL);
|
||||
|
||||
if ((ret = m9206_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
|
||||
goto done;
|
||||
deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
|
||||
|
||||
if ((ret = m9206_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
|
||||
goto done;
|
||||
deb_rc("%x\n", read[0]);
|
||||
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
|
||||
value = le16_to_cpu(*(u16 *)(fw->data + i));
|
||||
i += sizeof(u16);
|
||||
|
||||
index = le16_to_cpu(*(u16 *)(fw->data + i));
|
||||
i += sizeof(u16);
|
||||
|
||||
size = le16_to_cpu(*(u16 *)(fw->data + i));
|
||||
i += sizeof(u16);
|
||||
|
||||
if (pass == 1) {
|
||||
/* Will stall if using fw->data ... */
|
||||
memcpy(buff, fw->data + i, size);
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
|
||||
M9206_FW,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value, index, buff, size, 20);
|
||||
if (ret != size) {
|
||||
deb_rc("error while uploading fw!\n");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
msleep(3);
|
||||
}
|
||||
i += size;
|
||||
}
|
||||
if (i != fw->size) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
msleep(36);
|
||||
|
||||
/* m9206 will disconnect itself from the bus after this. */
|
||||
(void) m9206_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
|
||||
deb_rc("firmware uploaded!\n");
|
||||
|
||||
done:
|
||||
kfree(buff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int megasky_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
struct usb_host_interface *alt;
|
||||
|
||||
alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
|
||||
*cold = (alt == NULL) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int megasky_mt352_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
u8 config[] = { CONFIG, 0x3d };
|
||||
u8 clock[] = { CLOCK_CTL, 0x30 };
|
||||
u8 reset[] = { RESET, 0x80 };
|
||||
u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
|
||||
u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
|
||||
u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
|
||||
u8 unk1[] = { 0x93, 0x1a };
|
||||
u8 unk2[] = { 0xb5, 0x7a };
|
||||
|
||||
mt352_write(fe, config, ARRAY_SIZE(config));
|
||||
mt352_write(fe, clock, ARRAY_SIZE(clock));
|
||||
mt352_write(fe, reset, ARRAY_SIZE(reset));
|
||||
mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
|
||||
mt352_write(fe, agc, ARRAY_SIZE(agc));
|
||||
mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
|
||||
mt352_write(fe, unk1, ARRAY_SIZE(unk1));
|
||||
mt352_write(fe, unk2, ARRAY_SIZE(unk2));
|
||||
|
||||
deb_rc("Demod init!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt352_config megasky_mt352_config = {
|
||||
.demod_address = 0x1e,
|
||||
.no_tuner = 1,
|
||||
.demod_init = megasky_mt352_demod_init,
|
||||
};
|
||||
|
||||
static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
deb_rc("megasky_frontend_attach!\n");
|
||||
|
||||
m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
|
||||
m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
|
||||
|
||||
if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config megasky_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
};
|
||||
|
||||
static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
|
||||
m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
|
||||
|
||||
if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
|
||||
&megasky_qt1010_config) == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties megasky_properties;
|
||||
|
||||
static int m920x_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
|
||||
deb_rc("probed!\n");
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 1);
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
deb_rc("Changed to alternate setting!\n");
|
||||
|
||||
if ((ret = m9206_rc_init(d->udev)) != 0)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id m920x_table [] = {
|
||||
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, m920x_table);
|
||||
|
||||
static struct dvb_usb_device_properties megasky_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-megasky-02.fw",
|
||||
.download_firmware = m9206_firmware_download,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = megasky_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(megasky_rc_keys),
|
||||
.rc_query = m9206_rc_query,
|
||||
|
||||
.size_of_priv = sizeof(struct m9206_state),
|
||||
|
||||
.identify_state = megasky_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
|
||||
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
|
||||
.pid_filter_count = 8,
|
||||
.pid_filter = m9206_pid_filter,
|
||||
.pid_filter_ctrl = m9206_pid_filter_ctrl,
|
||||
|
||||
.frontend_attach = megasky_mt352_frontend_attach,
|
||||
.tuner_attach = megasky_qt1010_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x81,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.i2c_algo = &m9206_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "MSI Mega Sky 580 DVB-T USB2.0",
|
||||
{ &m920x_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver m920x_driver = {
|
||||
.name = "dvb_usb_m920x",
|
||||
.probe = m920x_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = m920x_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init m920x_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&m920x_driver))) {
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit m920x_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&m920x_driver);
|
||||
}
|
||||
|
||||
module_init (m920x_module_init);
|
||||
module_exit (m920x_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
|
||||
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
35
drivers/media/dvb/dvb-usb/m920x.h
Normal file
35
drivers/media/dvb/dvb-usb/m920x.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _DVB_USB_M920X_H_
|
||||
#define _DVB_USB_M920X_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "m920x"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_m920x_debug,0x01,args)
|
||||
|
||||
#define M9206_CORE 0x22
|
||||
#define M9206_RC_STATE 0xff51
|
||||
#define M9206_RC_KEY 0xff52
|
||||
#define M9206_RC_INIT1 0xff54
|
||||
#define M9206_RC_INIT2 0xff55
|
||||
#define M9206_FW_GO 0xff69
|
||||
|
||||
#define M9206_I2C 0x23
|
||||
#define M9206_FILTER 0x25
|
||||
#define M9206_FW 0x30
|
||||
|
||||
#define M9206_MAX_FILTERS 8
|
||||
|
||||
#define M9206_I2C_TUNER 0
|
||||
#define M9206_I2C_DEMOD 1
|
||||
#define M9206_I2C_MAX 2
|
||||
|
||||
struct m9206_state {
|
||||
u16 filters[M9206_MAX_FILTERS];
|
||||
int filtering_enabled;
|
||||
int rep_count;
|
||||
struct {
|
||||
unsigned char addr;
|
||||
unsigned char magic;
|
||||
}i2c_r[M9206_I2C_MAX];
|
||||
};
|
||||
#endif
|
||||
244
drivers/media/dvb/dvb-usb/nova-t-usb2.c
Normal file
244
drivers/media/dvb/dvb-usb/nova-t-usb2.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
|
||||
* DVB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dibusb.h"
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
#define deb_rc(args...) dprintk(debug,0x01,args)
|
||||
#define deb_ee(args...) dprintk(debug,0x02,args)
|
||||
|
||||
/* Hauppauge NOVA-T USB2 keys */
|
||||
static struct dvb_usb_rc_key haupp_rc_keys [] = {
|
||||
{ 0x1e, 0x00, KEY_0 },
|
||||
{ 0x1e, 0x01, KEY_1 },
|
||||
{ 0x1e, 0x02, KEY_2 },
|
||||
{ 0x1e, 0x03, KEY_3 },
|
||||
{ 0x1e, 0x04, KEY_4 },
|
||||
{ 0x1e, 0x05, KEY_5 },
|
||||
{ 0x1e, 0x06, KEY_6 },
|
||||
{ 0x1e, 0x07, KEY_7 },
|
||||
{ 0x1e, 0x08, KEY_8 },
|
||||
{ 0x1e, 0x09, KEY_9 },
|
||||
{ 0x1e, 0x0a, KEY_KPASTERISK },
|
||||
{ 0x1e, 0x0b, KEY_RED },
|
||||
{ 0x1e, 0x0c, KEY_RADIO },
|
||||
{ 0x1e, 0x0d, KEY_MENU },
|
||||
{ 0x1e, 0x0e, KEY_GRAVE }, /* # */
|
||||
{ 0x1e, 0x0f, KEY_MUTE },
|
||||
{ 0x1e, 0x10, KEY_VOLUMEUP },
|
||||
{ 0x1e, 0x11, KEY_VOLUMEDOWN },
|
||||
{ 0x1e, 0x12, KEY_CHANNEL },
|
||||
{ 0x1e, 0x14, KEY_UP },
|
||||
{ 0x1e, 0x15, KEY_DOWN },
|
||||
{ 0x1e, 0x16, KEY_LEFT },
|
||||
{ 0x1e, 0x17, KEY_RIGHT },
|
||||
{ 0x1e, 0x18, KEY_VIDEO },
|
||||
{ 0x1e, 0x19, KEY_AUDIO },
|
||||
{ 0x1e, 0x1a, KEY_MEDIA },
|
||||
{ 0x1e, 0x1b, KEY_EPG },
|
||||
{ 0x1e, 0x1c, KEY_TV },
|
||||
{ 0x1e, 0x1e, KEY_NEXT },
|
||||
{ 0x1e, 0x1f, KEY_BACK },
|
||||
{ 0x1e, 0x20, KEY_CHANNELUP },
|
||||
{ 0x1e, 0x21, KEY_CHANNELDOWN },
|
||||
{ 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
|
||||
{ 0x1e, 0x25, KEY_OK },
|
||||
{ 0x1e, 0x29, KEY_BLUE},
|
||||
{ 0x1e, 0x2e, KEY_GREEN },
|
||||
{ 0x1e, 0x30, KEY_PAUSE },
|
||||
{ 0x1e, 0x32, KEY_REWIND },
|
||||
{ 0x1e, 0x34, KEY_FASTFORWARD },
|
||||
{ 0x1e, 0x35, KEY_PLAY },
|
||||
{ 0x1e, 0x36, KEY_STOP },
|
||||
{ 0x1e, 0x37, KEY_RECORD },
|
||||
{ 0x1e, 0x38, KEY_YELLOW },
|
||||
{ 0x1e, 0x3b, KEY_GOTO },
|
||||
{ 0x1e, 0x3d, KEY_POWER },
|
||||
};
|
||||
|
||||
/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
|
||||
* is delivered. No workaround yet, maybe a new firmware.
|
||||
*/
|
||||
static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
|
||||
u16 raw;
|
||||
int i;
|
||||
struct dibusb_device_state *st = d->priv;
|
||||
|
||||
dvb_usb_generic_rw(d,cmd,2,key,5,0);
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
switch (key[0]) {
|
||||
case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
|
||||
raw = ((key[1] << 8) | key[2]) >> 3;
|
||||
toggle = !!(raw & 0x800);
|
||||
data = raw & 0x3f;
|
||||
custom = (raw >> 6) & 0x1f;
|
||||
|
||||
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
|
||||
if (haupp_rc_keys[i].data == data &&
|
||||
haupp_rc_keys[i].custom == custom) {
|
||||
|
||||
deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
|
||||
|
||||
*event = haupp_rc_keys[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
if (st->old_toggle == toggle) {
|
||||
if (st->last_repeat_count++ < 2)
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
} else {
|
||||
st->last_repeat_count = 0;
|
||||
st->old_toggle = toggle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
int i;
|
||||
u8 b;
|
||||
|
||||
mac[0] = 0x00;
|
||||
mac[1] = 0x0d;
|
||||
mac[2] = 0xfe;
|
||||
|
||||
/* this is a complete guess, but works for my box */
|
||||
for (i = 136; i < 139; i++) {
|
||||
dibusb_read_eeprom_byte(d,i, &b);
|
||||
|
||||
mac[5 - (i - 136)] = b;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties nova_t_properties;
|
||||
|
||||
static int nova_t_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE,NULL);
|
||||
}
|
||||
|
||||
/* do not change the order of the ID table */
|
||||
static struct usb_device_id nova_t_table [] = {
|
||||
/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) },
|
||||
/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, nova_t_table);
|
||||
|
||||
static struct dvb_usb_device_properties nova_t_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-nova-t-usb2-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mc_frontend_attach,
|
||||
.tuner_attach = dibusb_dib3000mc_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_device_state),
|
||||
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
.read_mac_address = nova_t_read_mac_address,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = haupp_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(haupp_rc_keys),
|
||||
.rc_query = nova_t_rc_query,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Hauppauge WinTV-NOVA-T usb2",
|
||||
{ &nova_t_table[0], NULL },
|
||||
{ &nova_t_table[1], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver nova_t_driver = {
|
||||
.name = "dvb_usb_nova_t_usb2",
|
||||
.probe = nova_t_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = nova_t_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init nova_t_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&nova_t_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nova_t_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&nova_t_driver);
|
||||
}
|
||||
|
||||
module_init (nova_t_module_init);
|
||||
module_exit (nova_t_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
270
drivers/media/dvb/dvb-usb/ttusb2.c
Normal file
270
drivers/media/dvb/dvb-usb/ttusb2.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
|
||||
* (e.g. Pinnacle 400e DVB-S USB2.0).
|
||||
*
|
||||
* The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
|
||||
*
|
||||
* TDA8263 + TDA10086
|
||||
*
|
||||
* I2C addresses:
|
||||
* 0x08 - LNBP21PD - LNB power supply
|
||||
* 0x0e - TDA10086 - Demodulator
|
||||
* 0x50 - FX2 eeprom
|
||||
* 0x60 - TDA8263 - Tuner
|
||||
* 0x78 ???
|
||||
*
|
||||
* Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
|
||||
* Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
|
||||
* Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org>
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#define DVB_USB_LOG_PREFIX "ttusb2"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "ttusb2.h"
|
||||
|
||||
#include "tda826x.h"
|
||||
#include "tda10086.h"
|
||||
#include "lnbp21.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_ttusb2_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args)
|
||||
module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
struct ttusb2_state {
|
||||
u8 id;
|
||||
};
|
||||
|
||||
static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
|
||||
u8 *wbuf, int wlen, u8 *rbuf, int rlen)
|
||||
{
|
||||
struct ttusb2_state *st = d->priv;
|
||||
u8 s[wlen+4],r[64] = { 0 };
|
||||
int ret = 0;
|
||||
|
||||
memset(s,0,wlen+4);
|
||||
|
||||
s[0] = 0xaa;
|
||||
s[1] = ++st->id;
|
||||
s[2] = cmd;
|
||||
s[3] = wlen;
|
||||
memcpy(&s[4],wbuf,wlen);
|
||||
|
||||
ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
|
||||
|
||||
if (ret != 0 ||
|
||||
r[0] != 0x55 ||
|
||||
r[1] != s[1] ||
|
||||
r[2] != cmd ||
|
||||
(rlen > 0 && r[3] != rlen)) {
|
||||
warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rlen > 0)
|
||||
memcpy(rbuf, &r[4], rlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
static u8 obuf[60], ibuf[60];
|
||||
int i,read;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
|
||||
|
||||
obuf[0] = (msg[i].addr << 1) | read;
|
||||
obuf[1] = msg[i].len;
|
||||
|
||||
/* read request */
|
||||
if (read)
|
||||
obuf[2] = msg[i+1].len;
|
||||
else
|
||||
obuf[2] = 0;
|
||||
|
||||
memcpy(&obuf[3],msg[i].buf,msg[i].len);
|
||||
|
||||
if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
|
||||
err("i2c transfer failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (read) {
|
||||
memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ttusb2_i2c_algo = {
|
||||
.master_xfer = ttusb2_i2c_xfer,
|
||||
.functionality = ttusb2_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int ttusb2_identify_state (struct usb_device *udev, struct
|
||||
dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b = onoff;
|
||||
ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
|
||||
return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static struct tda10086_config tda10086_config = {
|
||||
.demod_address = 0x0e,
|
||||
.invert = 0,
|
||||
};
|
||||
|
||||
static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev,0,3) < 0)
|
||||
err("set interface to alts=3 failed");
|
||||
|
||||
if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
|
||||
deb_info("TDA10086 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
|
||||
deb_info("TDA8263 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
|
||||
deb_info("LNBP21 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties ttusb2_properties;
|
||||
|
||||
static int ttusb2_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL);
|
||||
}
|
||||
|
||||
static struct usb_device_id ttusb2_table [] = {
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, ttusb2_table);
|
||||
|
||||
static struct dvb_usb_device_properties ttusb2_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-pctv-400e-01.fw",
|
||||
|
||||
.size_of_priv = sizeof(struct ttusb2_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = NULL, // ttusb2_streaming_ctrl,
|
||||
|
||||
.frontend_attach = ttusb2_frontend_attach,
|
||||
.tuner_attach = ttusb2_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 4,
|
||||
.framesize = 940,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = ttusb2_power_ctrl,
|
||||
.identify_state = ttusb2_identify_state,
|
||||
|
||||
.i2c_algo = &ttusb2_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Pinnacle 400e DVB-S USB2.0",
|
||||
{ &ttusb2_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver ttusb2_driver = {
|
||||
.name = "dvb_usb_ttusb2",
|
||||
.probe = ttusb2_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = ttusb2_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init ttusb2_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&ttusb2_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ttusb2_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&ttusb2_driver);
|
||||
}
|
||||
|
||||
module_init (ttusb2_module_init);
|
||||
module_exit (ttusb2_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
70
drivers/media/dvb/dvb-usb/ttusb2.h
Normal file
70
drivers/media/dvb/dvb-usb/ttusb2.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
|
||||
* (e.g. Pinnacle 400e DVB-S USB2.0).
|
||||
*
|
||||
* Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
|
||||
* Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
|
||||
* Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.de>
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#ifndef _DVB_USB_TTUSB2_H_
|
||||
#define _DVB_USB_TTUSB2_H_
|
||||
|
||||
/* TTUSB protocol
|
||||
*
|
||||
* always to messages (out/in)
|
||||
* out message:
|
||||
* 0xaa <id> <cmdbyte> <datalen> <data...>
|
||||
*
|
||||
* in message (complete block is always 0x40 bytes long)
|
||||
* 0x55 <id> <cmdbyte> <datalen> <data...>
|
||||
*
|
||||
* id is incremented for each transaction
|
||||
*/
|
||||
|
||||
#define CMD_DSP_DOWNLOAD 0x13
|
||||
/* out data: <byte>[28]
|
||||
* last block must be empty */
|
||||
|
||||
#define CMD_DSP_BOOT 0x14
|
||||
/* out data: nothing */
|
||||
|
||||
#define CMD_POWER 0x15
|
||||
/* out data: <on=1/off=0> */
|
||||
|
||||
#define CMD_LNB 0x16
|
||||
/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */
|
||||
|
||||
#define CMD_GET_VERSION 0x17
|
||||
/* in data: <version_byte>[5] */
|
||||
|
||||
#define CMD_DISEQC 0x18
|
||||
/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
|
||||
|
||||
#define CMD_PID_ENABLE 0x22
|
||||
/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
|
||||
|
||||
#define CMD_PID_DISABLE 0x23
|
||||
/* out data: <index> */
|
||||
|
||||
#define CMD_FILTER_ENABLE 0x24
|
||||
/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */
|
||||
|
||||
#define CMD_FILTER_DISABLE 0x25
|
||||
/* out data: <index> */
|
||||
|
||||
#define CMD_GET_DSP_VERSION 0x26
|
||||
/* in data: <version_byte>[28] */
|
||||
|
||||
#define CMD_I2C_XFER 0x31
|
||||
/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen]
|
||||
* in data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */
|
||||
|
||||
#define CMD_I2C_BITRATE 0x32
|
||||
/* out data: <default=0> */
|
||||
|
||||
#endif
|
||||
167
drivers/media/dvb/dvb-usb/umt-010.c
Normal file
167
drivers/media/dvb/dvb-usb/umt-010.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
|
||||
* DVB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dibusb.h"
|
||||
|
||||
#include "mt352.h"
|
||||
|
||||
static int umt_mt352_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
|
||||
static u8 mt352_reset[] = { 0x50, 0x80 };
|
||||
static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
|
||||
static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
|
||||
|
||||
static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
|
||||
static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
|
||||
static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
|
||||
static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
|
||||
static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
|
||||
|
||||
static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
|
||||
static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
|
||||
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
|
||||
|
||||
mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
|
||||
mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
|
||||
mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
|
||||
mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
|
||||
mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
|
||||
|
||||
mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
|
||||
mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct mt352_config umt_config;
|
||||
|
||||
memset(&umt_config,0,sizeof(struct mt352_config));
|
||||
umt_config.demod_init = umt_mt352_demod_init;
|
||||
umt_config.demod_address = 0xf;
|
||||
|
||||
adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int umt_tuner_attach (struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->pll_addr = 0x61;
|
||||
adap->pll_desc = &dvb_pll_tua6034;
|
||||
adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties umt_properties;
|
||||
|
||||
static int umt_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE,NULL) == 0)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* do not change the order of the ID table */
|
||||
static struct usb_device_id umt_table [] = {
|
||||
/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
|
||||
/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, umt_table);
|
||||
|
||||
static struct dvb_usb_device_properties umt_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-umt-010-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.frontend_attach = umt_mt352_frontend_attach,
|
||||
.tuner_attach = umt_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 20,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb_power_ctrl,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Hanftek UMT-010 DVB-T USB2.0",
|
||||
{ &umt_table[0], NULL },
|
||||
{ &umt_table[1], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver umt_driver = {
|
||||
.name = "dvb_usb_umt_010",
|
||||
.probe = umt_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = umt_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init umt_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&umt_driver))) {
|
||||
err("usb_register failed. Error number %d",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit umt_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&umt_driver);
|
||||
}
|
||||
|
||||
module_init (umt_module_init);
|
||||
module_exit (umt_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
243
drivers/media/dvb/dvb-usb/usb-urb.c
Normal file
243
drivers/media/dvb/dvb-usb/usb-urb.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/* usb-urb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file keeps functions for initializing and handling the
|
||||
* BULK and ISOC USB data transfers in a generic way.
|
||||
* Can be used for DVB-only and also, that's the plan, for
|
||||
* Hybrid USB devices (analog and DVB).
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
/* URB stuff for streaming */
|
||||
static void usb_urb_complete(struct urb *urb)
|
||||
{
|
||||
struct usb_data_stream *stream = urb->context;
|
||||
int ptype = usb_pipetype(urb->pipe);
|
||||
int i;
|
||||
u8 *b;
|
||||
|
||||
deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
|
||||
ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
|
||||
urb->status,urb->actual_length,urb->transfer_buffer_length,
|
||||
urb->number_of_packets,urb->error_count);
|
||||
|
||||
switch (urb->status) {
|
||||
case 0: /* success */
|
||||
case -ETIMEDOUT: /* NAK */
|
||||
break;
|
||||
case -ECONNRESET: /* kill */
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
default: /* error */
|
||||
deb_ts("urb completition error %d.\n", urb->status);
|
||||
break;
|
||||
}
|
||||
|
||||
b = (u8 *) urb->transfer_buffer;
|
||||
switch (ptype) {
|
||||
case PIPE_ISOCHRONOUS:
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
|
||||
if (urb->iso_frame_desc[i].status != 0)
|
||||
deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
|
||||
else if (urb->iso_frame_desc[i].actual_length > 0)
|
||||
stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length);
|
||||
|
||||
urb->iso_frame_desc[i].status = 0;
|
||||
urb->iso_frame_desc[i].actual_length = 0;
|
||||
}
|
||||
debug_dump(b,20,deb_uxfer);
|
||||
break;
|
||||
case PIPE_BULK:
|
||||
if (urb->actual_length > 0)
|
||||
stream->complete(stream, b, urb->actual_length);
|
||||
break;
|
||||
default:
|
||||
err("unkown endpoint type in completition handler.");
|
||||
return;
|
||||
}
|
||||
usb_submit_urb(urb,GFP_ATOMIC);
|
||||
}
|
||||
|
||||
int usb_urb_kill(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < stream->urbs_submitted; i++) {
|
||||
deb_ts("killing URB no. %d.\n",i);
|
||||
|
||||
/* stop the URB */
|
||||
usb_kill_urb(stream->urb_list[i]);
|
||||
}
|
||||
stream->urbs_submitted = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_submit(struct usb_data_stream *stream)
|
||||
{
|
||||
int i,ret;
|
||||
for (i = 0; i < stream->urbs_initialized; i++) {
|
||||
deb_ts("submitting URB no. %d\n",i);
|
||||
if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
|
||||
err("could not submit URB no. %d - get them all back",i);
|
||||
usb_urb_kill(stream);
|
||||
return ret;
|
||||
}
|
||||
stream->urbs_submitted++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_free_stream_buffers(struct usb_data_stream *stream)
|
||||
{
|
||||
if (stream->state & USB_STATE_URB_BUF) {
|
||||
while (stream->buf_num) {
|
||||
stream->buf_num--;
|
||||
deb_mem("freeing buffer %d\n",stream->buf_num);
|
||||
usb_buffer_free(stream->udev, stream->buf_size,
|
||||
stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]);
|
||||
}
|
||||
}
|
||||
|
||||
stream->state &= ~USB_STATE_URB_BUF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
|
||||
{
|
||||
stream->buf_num = 0;
|
||||
stream->buf_size = size;
|
||||
|
||||
deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
|
||||
|
||||
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
|
||||
deb_mem("allocating buffer %d\n",stream->buf_num);
|
||||
if (( stream->buf_list[stream->buf_num] =
|
||||
usb_buffer_alloc(stream->udev, size, GFP_ATOMIC,
|
||||
&stream->dma_addr[stream->buf_num]) ) == NULL) {
|
||||
deb_mem("not enough memory for urb-buffer allocation.\n");
|
||||
usb_free_stream_buffers(stream);
|
||||
return -ENOMEM;
|
||||
}
|
||||
deb_mem("buffer %d: %p (dma: %Lu)\n",
|
||||
stream->buf_num,
|
||||
stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
|
||||
memset(stream->buf_list[stream->buf_num],0,size);
|
||||
stream->state |= USB_STATE_URB_BUF;
|
||||
}
|
||||
deb_mem("allocation successful\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_bulk_urb_init(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
|
||||
stream->props.u.bulk.buffersize)) < 0)
|
||||
return i;
|
||||
|
||||
/* allocate the URBs */
|
||||
for (i = 0; i < stream->props.count; i++) {
|
||||
if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
|
||||
usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
|
||||
stream->buf_list[i],
|
||||
stream->props.u.bulk.buffersize,
|
||||
usb_urb_complete, stream);
|
||||
|
||||
stream->urb_list[i]->transfer_flags = 0;
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_isoc_urb_init(struct usb_data_stream *stream)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
|
||||
stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
|
||||
return i;
|
||||
|
||||
/* allocate the URBs */
|
||||
for (i = 0; i < stream->props.count; i++) {
|
||||
struct urb *urb;
|
||||
int frame_offset = 0;
|
||||
if ((stream->urb_list[i] =
|
||||
usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
urb = stream->urb_list[i];
|
||||
|
||||
urb->dev = stream->udev;
|
||||
urb->context = stream;
|
||||
urb->complete = usb_urb_complete;
|
||||
urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
|
||||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
||||
urb->interval = stream->props.u.isoc.interval;
|
||||
urb->number_of_packets = stream->props.u.isoc.framesperurb;
|
||||
urb->transfer_buffer_length = stream->buf_size;
|
||||
urb->transfer_buffer = stream->buf_list[i];
|
||||
urb->transfer_dma = stream->dma_addr[i];
|
||||
|
||||
for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
|
||||
urb->iso_frame_desc[j].offset = frame_offset;
|
||||
urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
|
||||
frame_offset += stream->props.u.isoc.framesize;
|
||||
}
|
||||
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
|
||||
{
|
||||
if (stream == NULL || props == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&stream->props, props, sizeof(*props));
|
||||
|
||||
usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
|
||||
|
||||
if (stream->complete == NULL) {
|
||||
err("there is no data callback - this doesn't make sense.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (stream->props.type) {
|
||||
case USB_BULK:
|
||||
return usb_bulk_urb_init(stream);
|
||||
case USB_ISOC:
|
||||
return usb_isoc_urb_init(stream);
|
||||
default:
|
||||
err("unkown URB-type for data transfer.");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_urb_exit(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
|
||||
usb_urb_kill(stream);
|
||||
|
||||
for (i = 0; i < stream->urbs_initialized; i++) {
|
||||
if (stream->urb_list[i] != NULL) {
|
||||
deb_mem("freeing URB no. %d.\n",i);
|
||||
/* free the URBs */
|
||||
usb_free_urb(stream->urb_list[i]);
|
||||
}
|
||||
}
|
||||
stream->urbs_initialized = 0;
|
||||
|
||||
usb_free_stream_buffers(stream);
|
||||
return 0;
|
||||
}
|
||||
349
drivers/media/dvb/dvb-usb/vp702x-fe.c
Normal file
349
drivers/media/dvb/dvb-usb/vp702x-fe.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
|
||||
* DVB-S receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Metzler Brothers Systementwicklung GbR
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* Thanks to Twinhan who kindly provided hardware and information.
|
||||
*
|
||||
* This file can be removed soon, after the DST-driver is rewritten to provice
|
||||
* the frontend-controlling separately.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*
|
||||
*/
|
||||
#include "vp702x.h"
|
||||
|
||||
struct vp702x_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
struct dvb_usb_device *d;
|
||||
|
||||
struct dvb_frontend_ops ops;
|
||||
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t tone_mode;
|
||||
|
||||
u8 lnb_buf[8];
|
||||
|
||||
u8 lock;
|
||||
u8 sig;
|
||||
u8 snr;
|
||||
|
||||
unsigned long next_status_check;
|
||||
unsigned long status_check_interval;
|
||||
};
|
||||
|
||||
static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
|
||||
{
|
||||
u8 buf[10];
|
||||
if (time_after(jiffies,st->next_status_check)) {
|
||||
vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10);
|
||||
|
||||
st->lock = buf[4];
|
||||
vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1);
|
||||
vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1);
|
||||
|
||||
st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 vp702x_chksum(u8 *buf,int f, int count)
|
||||
{
|
||||
u8 s = 0;
|
||||
int i;
|
||||
for (i = f; i < f+count; i++)
|
||||
s += buf[i];
|
||||
return ~s+1;
|
||||
}
|
||||
|
||||
static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
|
||||
if (st->lock == 0)
|
||||
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
else
|
||||
*status = 0;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
st->status_check_interval = 1000;
|
||||
else
|
||||
st->status_check_interval = 250;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
*ber = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
*unc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
|
||||
*strength = (st->sig << 8) | st->sig;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
u8 _snr;
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
|
||||
_snr = (st->snr & 0x1f) * 0xff / 0x1f;
|
||||
*snr = (_snr << 8) | _snr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
tune->min_delay_ms = 2000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
u32 freq = fep->frequency/1000;
|
||||
/*CalFrequency*/
|
||||
/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
|
||||
u64 sr;
|
||||
u8 cmd[8] = { 0 },ibuf[10];
|
||||
|
||||
cmd[0] = (freq >> 8) & 0x7f;
|
||||
cmd[1] = freq & 0xff;
|
||||
cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
|
||||
|
||||
sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20;
|
||||
do_div(sr,88000);
|
||||
cmd[3] = (sr >> 12) & 0xff;
|
||||
cmd[4] = (sr >> 4) & 0xff;
|
||||
cmd[5] = (sr << 4) & 0xf0;
|
||||
|
||||
deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
|
||||
fep->frequency,freq,freq, fep->u.qpsk.symbol_rate,
|
||||
(unsigned long) sr, (unsigned long) sr);
|
||||
|
||||
/* if (fep->inversion == INVERSION_ON)
|
||||
cmd[6] |= 0x80; */
|
||||
|
||||
if (st->voltage == SEC_VOLTAGE_18)
|
||||
cmd[6] |= 0x40;
|
||||
|
||||
/* if (fep->u.qpsk.symbol_rate > 8000000)
|
||||
cmd[6] |= 0x20;
|
||||
|
||||
if (fep->frequency < 1531000)
|
||||
cmd[6] |= 0x04;
|
||||
|
||||
if (st->tone_mode == SEC_TONE_ON)
|
||||
cmd[6] |= 0x01;*/
|
||||
|
||||
cmd[7] = vp702x_chksum(cmd,0,7);
|
||||
|
||||
st->status_check_interval = 250;
|
||||
st->next_status_check = jiffies;
|
||||
|
||||
vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
|
||||
|
||||
if (ibuf[2] == 0 && ibuf[3] == 0)
|
||||
deb_fe("tuning failed.\n");
|
||||
else
|
||||
deb_fe("tuning succeeded.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
//struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
u8 cmd[8];//,ibuf[10];
|
||||
memset(cmd,0,8);
|
||||
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
|
||||
if (m->msg_len > 4)
|
||||
return -EINVAL;
|
||||
|
||||
cmd[1] = SET_DISEQC_CMD;
|
||||
cmd[2] = m->msg_len;
|
||||
memcpy(&cmd[3], m->msg, m->msg_len);
|
||||
cmd[7] = vp702x_chksum(cmd,0,7);
|
||||
|
||||
// vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
|
||||
|
||||
// if (ibuf[2] == 0 && ibuf[3] == 0)
|
||||
// deb_fe("diseqc cmd failed.\n");
|
||||
// else
|
||||
// deb_fe("diseqc cmd succeeded.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
u8 ibuf[10];
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
|
||||
st->tone_mode = tone;
|
||||
|
||||
if (tone == SEC_TONE_ON)
|
||||
st->lnb_buf[2] = 0x02;
|
||||
else
|
||||
st->lnb_buf[2] = 0x00;
|
||||
|
||||
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
|
||||
|
||||
vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
|
||||
if (ibuf[2] == 0 && ibuf[3] == 0)
|
||||
deb_fe("set_tone cmd failed.\n");
|
||||
else
|
||||
deb_fe("set_tone cmd succeeded.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
|
||||
voltage)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
u8 ibuf[10];
|
||||
deb_fe("%s\n",__FUNCTION__);
|
||||
|
||||
st->voltage = voltage;
|
||||
|
||||
if (voltage != SEC_VOLTAGE_OFF)
|
||||
st->lnb_buf[4] = 0x01;
|
||||
else
|
||||
st->lnb_buf[4] = 0x00;
|
||||
|
||||
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
|
||||
|
||||
vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
|
||||
if (ibuf[2] == 0 && ibuf[3] == 0)
|
||||
deb_fe("set_voltage cmd failed.\n");
|
||||
else
|
||||
deb_fe("set_voltage cmd succeeded.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vp702x_fe_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
kfree(st);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops vp702x_fe_ops;
|
||||
|
||||
struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
s->d = d;
|
||||
|
||||
memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
|
||||
s->lnb_buf[1] = SET_LNB_POWER;
|
||||
s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
|
||||
|
||||
return &s->fe;
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops vp702x_fe_ops = {
|
||||
.info = {
|
||||
.name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
|
||||
.type = FE_QPSK,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
|
||||
.frequency_tolerance = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.caps = 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_QPSK |
|
||||
FE_CAN_FEC_AUTO
|
||||
},
|
||||
.release = vp702x_fe_release,
|
||||
|
||||
.init = vp702x_fe_init,
|
||||
.sleep = vp702x_fe_sleep,
|
||||
|
||||
.set_frontend = vp702x_fe_set_frontend,
|
||||
.get_frontend = vp702x_fe_get_frontend,
|
||||
.get_tune_settings = vp702x_fe_get_tune_settings,
|
||||
|
||||
.read_status = vp702x_fe_read_status,
|
||||
.read_ber = vp702x_fe_read_ber,
|
||||
.read_signal_strength = vp702x_fe_read_signal_strength,
|
||||
.read_snr = vp702x_fe_read_snr,
|
||||
.read_ucblocks = vp702x_fe_read_unc_blocks,
|
||||
|
||||
.diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg,
|
||||
.diseqc_send_burst = vp702x_fe_send_diseqc_burst,
|
||||
.set_tone = vp702x_fe_set_tone,
|
||||
.set_voltage = vp702x_fe_set_voltage,
|
||||
};
|
||||
347
drivers/media/dvb/dvb-usb/vp702x.c
Normal file
347
drivers/media/dvb/dvb-usb/vp702x.c
Normal file
@@ -0,0 +1,347 @@
|
||||
/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
|
||||
* receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Metzler Brothers Systementwicklung GbR
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* Thanks to Twinhan who kindly provided hardware and information.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "vp702x.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_vp702x_debug;
|
||||
module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
struct vp702x_state {
|
||||
int pid_filter_count;
|
||||
int pid_filter_can_bypass;
|
||||
u8 pid_filter_state;
|
||||
};
|
||||
|
||||
struct vp702x_device_state {
|
||||
u8 power_state;
|
||||
};
|
||||
|
||||
/* check for mutex FIXME */
|
||||
int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
ret = usb_control_msg(d->udev,
|
||||
usb_rcvctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value,index,b,blen,
|
||||
2000);
|
||||
|
||||
if (ret < 0) {
|
||||
warn("usb in operation failed. (%d)", ret);
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
|
||||
deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
if ((ret = usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value,index,b,blen,
|
||||
2000)) != blen) {
|
||||
warn("usb out operation failed. (%d)",ret);
|
||||
return -EIO;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
|
||||
msleep(msec);
|
||||
ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
|
||||
int olen, u8 *i, int ilen, int msec)
|
||||
{
|
||||
u8 bout[olen+2];
|
||||
u8 bin[ilen+1];
|
||||
int ret = 0;
|
||||
|
||||
bout[0] = 0x00;
|
||||
bout[1] = cmd;
|
||||
memcpy(&bout[2],o,olen);
|
||||
|
||||
ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec);
|
||||
|
||||
if (ret == 0)
|
||||
memcpy(i,&bin[1],ilen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
|
||||
{
|
||||
u8 buf[16] = { 0 };
|
||||
return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
|
||||
}
|
||||
|
||||
static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
|
||||
{
|
||||
u8 buf[16] = { 0 };
|
||||
return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
|
||||
}
|
||||
|
||||
static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
|
||||
{
|
||||
struct vp702x_state *st = adap->priv;
|
||||
u8 buf[16] = { 0 };
|
||||
|
||||
if (onoff)
|
||||
st->pid_filter_state |= (1 << id);
|
||||
else {
|
||||
st->pid_filter_state &= ~(1 << id);
|
||||
pid = 0xffff;
|
||||
}
|
||||
|
||||
id = 0x10 + id*2;
|
||||
|
||||
vp702x_set_pld_state(adap, st->pid_filter_state);
|
||||
vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
|
||||
vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct vp702x_state *st = adap->priv;
|
||||
int i;
|
||||
u8 b[10] = { 0 };
|
||||
|
||||
st->pid_filter_count = 8;
|
||||
st->pid_filter_can_bypass = 1;
|
||||
st->pid_filter_state = 0x00;
|
||||
|
||||
vp702x_set_pld_mode(adap, 1); // bypass
|
||||
|
||||
for (i = 0; i < st->pid_filter_count; i++)
|
||||
vp702x_set_pid(adap, 0xffff, i, 1);
|
||||
|
||||
vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
|
||||
vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
|
||||
vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
|
||||
|
||||
//vp702x_set_pld_mode(d, 0); // filter
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keys for the enclosed remote control */
|
||||
static struct dvb_usb_rc_key vp702x_rc_keys[] = {
|
||||
{ 0x00, 0x01, KEY_1 },
|
||||
{ 0x00, 0x02, KEY_2 },
|
||||
};
|
||||
|
||||
/* remote control stuff (does not work with my box) */
|
||||
static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 key[10];
|
||||
int i;
|
||||
|
||||
/* remove the following return to enabled remote querying */
|
||||
return 0;
|
||||
|
||||
vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
|
||||
|
||||
deb_rc("remote query key: %x %d\n",key[1],key[1]);
|
||||
|
||||
if (key[1] == 0x44) {
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++)
|
||||
if (vp702x_rc_keys[i].custom == key[1]) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = vp702x_rc_keys[i].event;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
struct vp702x_device_state *st = d->priv;
|
||||
|
||||
if (st->power_state == 0 && onoff)
|
||||
vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
|
||||
else if (st->power_state == 1 && onoff == 0)
|
||||
vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
|
||||
|
||||
st->power_state = onoff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
|
||||
{
|
||||
u8 i;
|
||||
for (i = 6; i < 12; i++)
|
||||
vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 buf[10] = { 0 };
|
||||
|
||||
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
|
||||
|
||||
if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
|
||||
return -EIO;
|
||||
|
||||
buf[9] = '\0';
|
||||
info("system string: %s",&buf[1]);
|
||||
|
||||
vp702x_init_pid_filter(adap);
|
||||
|
||||
adap->fe = vp702x_fe_attach(adap->dev);
|
||||
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties vp702x_properties;
|
||||
|
||||
static int vp702x_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL);
|
||||
}
|
||||
|
||||
static struct usb_device_id vp702x_usb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
|
||||
// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
|
||||
// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties vp702x_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-vp702x-02.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.size_of_priv = sizeof(struct vp702x_device_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
|
||||
|
||||
.streaming_ctrl = vp702x_streaming_ctrl,
|
||||
.frontend_attach = vp702x_frontend_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 10,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct vp702x_state),
|
||||
}
|
||||
},
|
||||
.read_mac_address = vp702x_read_mac_addr,
|
||||
|
||||
.rc_key_map = vp702x_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
|
||||
.rc_interval = 400,
|
||||
.rc_query = vp702x_rc_query,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
|
||||
.cold_ids = { &vp702x_usb_table[0], NULL },
|
||||
.warm_ids = { NULL },
|
||||
},
|
||||
/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
|
||||
.cold_ids = { &vp702x_usb_table[2], NULL },
|
||||
.warm_ids = { &vp702x_usb_table[3], NULL },
|
||||
},
|
||||
*/ { NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver vp702x_usb_driver = {
|
||||
.name = "dvb_usb_vp702x",
|
||||
.probe = vp702x_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = vp702x_usb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init vp702x_usb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&vp702x_usb_driver))) {
|
||||
err("usb_register failed. (%d)",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit vp702x_usb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&vp702x_usb_driver);
|
||||
}
|
||||
|
||||
module_init(vp702x_usb_module_init);
|
||||
module_exit(vp702x_usb_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
108
drivers/media/dvb/dvb-usb/vp702x.h
Normal file
108
drivers/media/dvb/dvb-usb/vp702x.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef _DVB_USB_VP7021_H_
|
||||
#define _DVB_USB_VP7021_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "vp702x"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_vp702x_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args)
|
||||
|
||||
/* commands are read and written with USB control messages */
|
||||
|
||||
/* consecutive read/write operation */
|
||||
#define REQUEST_OUT 0xB2
|
||||
#define REQUEST_IN 0xB3
|
||||
|
||||
/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
|
||||
* request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
|
||||
* the returning buffer looks as follows
|
||||
* request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
|
||||
|
||||
#define GET_TUNER_STATUS 0x05
|
||||
/* additional in buffer:
|
||||
* 0 1 2 3 4 5 6 7 8
|
||||
* N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
|
||||
|
||||
#define GET_SYSTEM_STRING 0x06
|
||||
/* additional in buffer:
|
||||
* 0 1 2 3 4 5 6 7 8
|
||||
* N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
|
||||
|
||||
#define SET_DISEQC_CMD 0x08
|
||||
/* additional out buffer:
|
||||
* 0 1 2 3 4
|
||||
* len X1 X2 X3 X4
|
||||
* additional in buffer:
|
||||
* 0 1 2
|
||||
* N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */
|
||||
|
||||
#define SET_LNB_POWER 0x09
|
||||
/* additional out buffer:
|
||||
* 0 1 2
|
||||
* 0x00 0xff 1 = on, 0 = off
|
||||
* additional in buffer:
|
||||
* 0 1 2
|
||||
* N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */
|
||||
|
||||
#define GET_MAC_ADDRESS 0x0A
|
||||
/* #define GET_MAC_ADDRESS 0x0B */
|
||||
/* additional in buffer:
|
||||
* 0 1 2 3 4 5 6 7 8
|
||||
* N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
|
||||
|
||||
#define SET_PID_FILTER 0x11
|
||||
/* additional in buffer:
|
||||
* 0 1 ... 14 15 16
|
||||
* PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
|
||||
|
||||
/* request: 0xB2; i: 0; v: 0;
|
||||
* b[0] != 0 -> tune and lock a channel
|
||||
* 0 1 2 3 4 5 6 7
|
||||
* freq0 freq1 divstep srate0 srate1 srate2 flag chksum
|
||||
*/
|
||||
|
||||
/* one direction requests */
|
||||
#define READ_REMOTE_REQ 0xB4
|
||||
/* IN i: 0; v: 0; b[0] == request, b[1] == key */
|
||||
|
||||
#define READ_PID_NUMBER_REQ 0xB5
|
||||
/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
|
||||
|
||||
#define WRITE_EEPROM_REQ 0xB6
|
||||
/* OUT i: offset; v: value to write; no extra buffer */
|
||||
|
||||
#define READ_EEPROM_REQ 0xB7
|
||||
/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */
|
||||
|
||||
#define READ_STATUS 0xB8
|
||||
/* IN i: 0; v: 0; bufferlen 10 */
|
||||
|
||||
#define READ_TUNER_REG_REQ 0xB9
|
||||
/* IN i: 0; v: register; b[0] = value */
|
||||
|
||||
#define READ_FX2_REG_REQ 0xBA
|
||||
/* IN i: offset; v: 0; b[0] = value */
|
||||
|
||||
#define WRITE_FX2_REG_REQ 0xBB
|
||||
/* OUT i: offset; v: value to write; 1 byte extra buffer */
|
||||
|
||||
#define SET_TUNER_POWER_REQ 0xBC
|
||||
/* IN i: 0 = power off, 1 = power on */
|
||||
|
||||
#define WRITE_TUNER_REG_REQ 0xBD
|
||||
/* IN i: register, v: value to write, no extra buffer */
|
||||
|
||||
#define RESET_TUNER 0xBE
|
||||
/* IN i: 0, v: 0, no extra buffer */
|
||||
|
||||
extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
|
||||
|
||||
extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
|
||||
extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
|
||||
extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
|
||||
extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
|
||||
|
||||
#endif
|
||||
192
drivers/media/dvb/dvb-usb/vp7045-fe.c
Normal file
192
drivers/media/dvb/dvb-usb/vp7045-fe.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
|
||||
* DVB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* Thanks to Twinhan who kindly provided hardware and information.
|
||||
*
|
||||
* 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, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*
|
||||
*/
|
||||
#include "vp7045.h"
|
||||
|
||||
/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
|
||||
*
|
||||
* Programming is hidden inside the firmware, so set_frontend is very easy.
|
||||
* Even though there is a Firmware command that one can use to access the demod
|
||||
* via its registers. This is used for status information.
|
||||
*/
|
||||
|
||||
struct vp7045_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
struct dvb_usb_device *d;
|
||||
};
|
||||
|
||||
static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
u8 s0 = vp7045_read_reg(state->d,0x00),
|
||||
s1 = vp7045_read_reg(state->d,0x01),
|
||||
s3 = vp7045_read_reg(state->d,0x03);
|
||||
|
||||
*status = 0;
|
||||
if (s0 & (1 << 4))
|
||||
*status |= FE_HAS_CARRIER;
|
||||
if (s0 & (1 << 1))
|
||||
*status |= FE_HAS_VITERBI;
|
||||
if (s0 & (1 << 5))
|
||||
*status |= FE_HAS_LOCK;
|
||||
if (s1 & (1 << 1))
|
||||
*status |= FE_HAS_SYNC;
|
||||
if (s3 & (1 << 6))
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
|
||||
if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
|
||||
(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
|
||||
*status &= ~FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
*ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
|
||||
(vp7045_read_reg(state->d, 0x0E) << 8) |
|
||||
vp7045_read_reg(state->d, 0x0F);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
*unc = (vp7045_read_reg(state->d, 0x10) << 8) |
|
||||
vp7045_read_reg(state->d, 0x11);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
|
||||
vp7045_read_reg(state->d, 0x15);
|
||||
|
||||
*strength = ~signal;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
u8 _snr = vp7045_read_reg(state->d, 0x09);
|
||||
*snr = (_snr << 8) | _snr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_init(struct dvb_frontend* fe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 800;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
u8 buf[5];
|
||||
u32 freq = fep->frequency / 1000;
|
||||
|
||||
buf[0] = (freq >> 16) & 0xff;
|
||||
buf[1] = (freq >> 8) & 0xff;
|
||||
buf[2] = freq & 0xff;
|
||||
buf[3] = 0;
|
||||
|
||||
switch (fep->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_8_MHZ: buf[4] = 8; break;
|
||||
case BANDWIDTH_7_MHZ: buf[4] = 7; break;
|
||||
case BANDWIDTH_6_MHZ: buf[4] = 6; break;
|
||||
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp7045_fe_get_frontend(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vp7045_fe_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct vp7045_fe_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops vp7045_fe_ops;
|
||||
|
||||
struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
s->d = d;
|
||||
memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
|
||||
return &s->fe;
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops vp7045_fe_ops = {
|
||||
.info = {
|
||||
.name = "Twinhan VP7045/46 USB DVB-T",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 44250000,
|
||||
.frequency_max = 867250000,
|
||||
.frequency_stepsize = 1000,
|
||||
.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 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_RECOVER |
|
||||
FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.release = vp7045_fe_release,
|
||||
|
||||
.init = vp7045_fe_init,
|
||||
.sleep = vp7045_fe_sleep,
|
||||
|
||||
.set_frontend = vp7045_fe_set_frontend,
|
||||
.get_frontend = vp7045_fe_get_frontend,
|
||||
.get_tune_settings = vp7045_fe_get_tune_settings,
|
||||
|
||||
.read_status = vp7045_fe_read_status,
|
||||
.read_ber = vp7045_fe_read_ber,
|
||||
.read_signal_strength = vp7045_fe_read_signal_strength,
|
||||
.read_snr = vp7045_fe_read_snr,
|
||||
.read_ucblocks = vp7045_fe_read_unc_blocks,
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user