mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 07:18:51 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
222
drivers/media/Kconfig
Normal file
222
drivers/media/Kconfig
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
#
|
||||
# Multimedia device configuration
|
||||
#
|
||||
|
||||
menuconfig MEDIA_SUPPORT
|
||||
tristate "Multimedia support"
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
If you want to use Webcams, Video grabber devices and/or TV devices
|
||||
enable this option and other options below.
|
||||
Additional info and docs are available on the web at
|
||||
<http://linuxtv.org>
|
||||
|
||||
if MEDIA_SUPPORT
|
||||
|
||||
comment "Multimedia core support"
|
||||
|
||||
#
|
||||
# Multimedia support - automatically enable V4L2 and DVB core
|
||||
#
|
||||
config MEDIA_CAMERA_SUPPORT
|
||||
bool "Cameras/video grabbers support"
|
||||
---help---
|
||||
Enable support for webcams and video grabbers.
|
||||
|
||||
Say Y when you have a webcam or a video capture grabber board.
|
||||
|
||||
config MEDIA_ANALOG_TV_SUPPORT
|
||||
bool "Analog TV support"
|
||||
---help---
|
||||
Enable analog TV support.
|
||||
|
||||
Say Y when you have a TV board with analog support or with a
|
||||
hybrid analog/digital TV chipset.
|
||||
|
||||
Note: There are several DVB cards that are based on chips that
|
||||
support both analog and digital TV. Disabling this option
|
||||
will disable support for them.
|
||||
|
||||
config MEDIA_DIGITAL_TV_SUPPORT
|
||||
bool "Digital TV support"
|
||||
---help---
|
||||
Enable digital TV support.
|
||||
|
||||
Say Y when you have a board with digital support or a board with
|
||||
hybrid digital TV and analog TV.
|
||||
|
||||
config MEDIA_RADIO_SUPPORT
|
||||
bool "AM/FM radio receivers/transmitters support"
|
||||
---help---
|
||||
Enable AM/FM radio support.
|
||||
|
||||
Additional info and docs are available on the web at
|
||||
<http://linuxtv.org>
|
||||
|
||||
Say Y when you have a board with radio support.
|
||||
|
||||
Note: There are several TV cards that are based on chips that
|
||||
support radio reception. Disabling this option will
|
||||
disable support for them.
|
||||
|
||||
config MEDIA_SDR_SUPPORT
|
||||
bool "Software defined radio support"
|
||||
---help---
|
||||
Enable software defined radio support.
|
||||
|
||||
Say Y when you have a software defined radio device.
|
||||
|
||||
config MEDIA_RC_SUPPORT
|
||||
bool "Remote Controller support"
|
||||
depends on INPUT
|
||||
---help---
|
||||
Enable support for Remote Controllers on Linux. This is
|
||||
needed in order to support several video capture adapters,
|
||||
standalone IR receivers/transmitters, and RF receivers.
|
||||
|
||||
Enable this option if you have a video capture board even
|
||||
if you don't need IR, as otherwise, you may not be able to
|
||||
compile the driver for your adapter.
|
||||
|
||||
Say Y when you have a TV or an IR device.
|
||||
|
||||
config MEDIA_M2M1SHOT
|
||||
bool "Non-streaming m2m media processing (m2m1shot) API"
|
||||
---help---
|
||||
Enables support for non-steaming m2m media processing API for some
|
||||
device drivers like JPEG codec.
|
||||
|
||||
config MEDIA_M2M1SHOT_TESTDEV
|
||||
depends on MEDIA_M2M1SHOT
|
||||
bool "Test driver for non-streaming m2m media processing (m2m1shot) API"
|
||||
|
||||
#
|
||||
# Media controller
|
||||
# Selectable only for webcam/grabbers, as other drivers don't use it
|
||||
#
|
||||
|
||||
config MEDIA_CONTROLLER
|
||||
bool "Media Controller API"
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
---help---
|
||||
Enable the media controller API used to query media devices internal
|
||||
topology and configure it dynamically.
|
||||
|
||||
This API is mostly used by camera interfaces in embedded platforms.
|
||||
|
||||
#
|
||||
# Video4Linux support
|
||||
# Only enables if one of the V4L2 types (ATV, webcam, radio) is selected
|
||||
#
|
||||
|
||||
config VIDEO_DEV
|
||||
tristate
|
||||
depends on MEDIA_SUPPORT
|
||||
depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT
|
||||
default y
|
||||
|
||||
config VIDEO_V4L2_SUBDEV_API
|
||||
bool "V4L2 sub-device userspace API"
|
||||
depends on VIDEO_DEV && MEDIA_CONTROLLER
|
||||
---help---
|
||||
Enables the V4L2 sub-device pad-level userspace API used to configure
|
||||
video format, size and frame rate between hardware blocks.
|
||||
|
||||
This API is mostly used by camera interfaces in embedded platforms.
|
||||
|
||||
source "drivers/media/v4l2-core/Kconfig"
|
||||
|
||||
#
|
||||
# DVB Core
|
||||
# Only enables if one of DTV is selected
|
||||
#
|
||||
|
||||
config DVB_CORE
|
||||
tristate
|
||||
depends on MEDIA_SUPPORT
|
||||
depends on MEDIA_DIGITAL_TV_SUPPORT
|
||||
default y
|
||||
select CRC32
|
||||
|
||||
config DVB_NET
|
||||
bool "DVB Network Support"
|
||||
default (NET && INET)
|
||||
depends on NET && INET && DVB_CORE
|
||||
help
|
||||
This option enables DVB Network Support which is a part of the DVB
|
||||
standard. It is used, for example, by automatic firmware updates used
|
||||
on Set-Top-Boxes. It can also be used to access the Internet via the
|
||||
DVB card, if the network provider supports it.
|
||||
|
||||
You may want to disable the network support on embedded devices. If
|
||||
unsure say Y.
|
||||
|
||||
# This Kconfig option is used by both PCI and USB drivers
|
||||
config TTPCI_EEPROM
|
||||
tristate
|
||||
depends on I2C
|
||||
default n
|
||||
|
||||
source "drivers/media/dvb-core/Kconfig"
|
||||
|
||||
comment "Media drivers"
|
||||
source "drivers/media/rc/Kconfig"
|
||||
|
||||
#
|
||||
# V4L platform/mem2mem drivers
|
||||
#
|
||||
|
||||
source "drivers/media/usb/Kconfig"
|
||||
source "drivers/media/pci/Kconfig"
|
||||
source "drivers/media/platform/Kconfig"
|
||||
source "drivers/media/mmc/Kconfig"
|
||||
source "drivers/media/parport/Kconfig"
|
||||
source "drivers/media/radio/Kconfig"
|
||||
|
||||
comment "Supported FireWire (IEEE 1394) Adapters"
|
||||
depends on DVB_CORE && FIREWIRE
|
||||
source "drivers/media/firewire/Kconfig"
|
||||
|
||||
# Common driver options
|
||||
source "drivers/media/common/Kconfig"
|
||||
|
||||
comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
|
||||
|
||||
#
|
||||
# Ancillary drivers (tuners, i2c, frontends)
|
||||
#
|
||||
|
||||
config MEDIA_SUBDRV_AUTOSELECT
|
||||
bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
|
||||
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT
|
||||
depends on HAS_IOMEM
|
||||
select I2C
|
||||
select I2C_MUX
|
||||
default y
|
||||
help
|
||||
By default, a media driver auto-selects all possible ancillary
|
||||
devices such as tuners, sensors, video encoders/decoders and
|
||||
frontends, that are used by any of the supported devices.
|
||||
|
||||
This is generally the right thing to do, except when there
|
||||
are strict constraints with regards to the kernel size,
|
||||
like on embedded systems.
|
||||
|
||||
Use this option with care, as deselecting ancillary drivers which
|
||||
are, in fact, necessary will result in the lack of the needed
|
||||
functionality for your device (it may not tune or may not have
|
||||
the needed demodulators).
|
||||
|
||||
If unsure say Y.
|
||||
|
||||
config MEDIA_ATTACH
|
||||
bool
|
||||
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
|
||||
depends on MODULES
|
||||
default MODULES
|
||||
|
||||
source "drivers/media/i2c/Kconfig"
|
||||
source "drivers/media/tuners/Kconfig"
|
||||
source "drivers/media/dvb-frontends/Kconfig"
|
||||
|
||||
endif # MEDIA_SUPPORT
|
||||
36
drivers/media/Makefile
Normal file
36
drivers/media/Makefile
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
# Makefile for the kernel multimedia device drivers.
|
||||
#
|
||||
|
||||
media-objs := media-device.o media-devnode.o media-entity.o
|
||||
|
||||
#
|
||||
# I2C drivers should come before other drivers, otherwise they'll fail
|
||||
# when compiled as builtin drivers
|
||||
#
|
||||
obj-y += i2c/ tuners/
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-frontends/
|
||||
|
||||
#
|
||||
# Now, let's link-in the media core
|
||||
#
|
||||
ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
|
||||
obj-$(CONFIG_MEDIA_SUPPORT) += media.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_VIDEO_DEV) += v4l2-core/
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core/
|
||||
|
||||
obj-$(CONFIG_MEDIA_M2M1SHOT) += m2m1shot.o m2m1shot-helper.o
|
||||
obj-$(CONFIG_MEDIA_M2M1SHOT_TESTDEV) += m2m1shot-testdev.o
|
||||
|
||||
# There are both core and drivers at RC subtree - merge before drivers
|
||||
obj-y += rc/
|
||||
|
||||
#
|
||||
# Finally, merge the drivers that require the core
|
||||
#
|
||||
|
||||
obj-y += common/ platform/ pci/ usb/ mmc/ firewire/ parport/
|
||||
obj-$(CONFIG_VIDEO_DEV) += radio/
|
||||
|
||||
25
drivers/media/common/Kconfig
Normal file
25
drivers/media/common/Kconfig
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Used by common drivers, when they need to ask questions
|
||||
config MEDIA_COMMON_OPTIONS
|
||||
bool
|
||||
|
||||
comment "common driver options"
|
||||
depends on MEDIA_COMMON_OPTIONS
|
||||
|
||||
config VIDEO_CX2341X
|
||||
tristate
|
||||
|
||||
config VIDEO_BTCX
|
||||
depends on PCI
|
||||
tristate
|
||||
|
||||
config VIDEO_TVEEPROM
|
||||
tristate
|
||||
depends on I2C
|
||||
|
||||
config CYPRESS_FIRMWARE
|
||||
tristate "Cypress firmware helper routines"
|
||||
depends on USB
|
||||
|
||||
source "drivers/media/common/b2c2/Kconfig"
|
||||
source "drivers/media/common/saa7146/Kconfig"
|
||||
source "drivers/media/common/siano/Kconfig"
|
||||
5
drivers/media/common/Makefile
Normal file
5
drivers/media/common/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
obj-y += b2c2/ saa7146/ siano/
|
||||
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
|
||||
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
|
||||
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
|
||||
obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
|
||||
23
drivers/media/common/b2c2/Kconfig
Normal file
23
drivers/media/common/b2c2/Kconfig
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
config DVB_B2C2_FLEXCOP
|
||||
tristate
|
||||
depends on DVB_CORE && I2C
|
||||
depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB
|
||||
default y
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_BCM3510 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
# Selected via the PCI or USB flexcop drivers
|
||||
config DVB_B2C2_FLEXCOP_DEBUG
|
||||
bool
|
||||
8
drivers/media/common/b2c2/Makefile
Normal file
8
drivers/media/common/b2c2/Makefile
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
b2c2-flexcop-objs += flexcop.o flexcop-fe-tuner.o flexcop-i2c.o
|
||||
b2c2-flexcop-objs += flexcop-sram.o flexcop-eeprom.o flexcop-misc.o
|
||||
b2c2-flexcop-objs += flexcop-hw-filter.o
|
||||
obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core/
|
||||
ccflags-y += -Idrivers/media/dvb-frontends/
|
||||
ccflags-y += -Idrivers/media/tuners/
|
||||
185
drivers/media/common/b2c2/flexcop-common.h
Normal file
185
drivers/media/common/b2c2/flexcop-common.h
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
* flexcop-common.h - common header file for device-specific source files
|
||||
* see flexcop.c for copyright information
|
||||
*/
|
||||
#ifndef __FLEXCOP_COMMON_H__
|
||||
#define __FLEXCOP_COMMON_H__
|
||||
|
||||
#include <linux/interrupt.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 */
|
||||
};
|
||||
|
||||
struct flexcop_i2c_adapter {
|
||||
struct flexcop_device *fc;
|
||||
struct i2c_adapter i2c_adap;
|
||||
|
||||
u8 no_base_addr;
|
||||
flexcop_i2c_port_t port;
|
||||
};
|
||||
|
||||
/* 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 flexcop_i2c_adapter fc_i2c_adap[3];
|
||||
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_i2c_adapter *,
|
||||
flexcop_access_op_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_i2c_adapter*, flexcop_access_op_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 *fc);
|
||||
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
|
||||
147
drivers/media/common/b2c2/flexcop-eeprom.c
Normal file
147
drivers/media/common/b2c2/flexcop-eeprom.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
* flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
|
||||
* 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++) {
|
||||
ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
|
||||
addr & 0xff, buf, len);
|
||||
if (ret == 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;
|
||||
} else
|
||||
memcpy(fc->dvb_adapter.proposed_mac,buf,6);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
|
||||
678
drivers/media/common/b2c2/flexcop-fe-tuner.c
Normal file
678
drivers/media/common/b2c2/flexcop-fe-tuner.c
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
/*
|
||||
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
* flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
|
||||
* see flexcop.c for copyright information
|
||||
*/
|
||||
#include <media/tuner.h>
|
||||
#include "flexcop.h"
|
||||
#include "mt312.h"
|
||||
#include "stv0299.h"
|
||||
#include "s5h1420.h"
|
||||
#include "itd1000.h"
|
||||
#include "cx24113.h"
|
||||
#include "cx24123.h"
|
||||
#include "isl6421.h"
|
||||
#include "mt352.h"
|
||||
#include "bcm3510.h"
|
||||
#include "nxt200x.h"
|
||||
#include "dvb-pll.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "tuner-simple.h"
|
||||
#include "stv0297.h"
|
||||
|
||||
|
||||
/* Can we use the specified front-end? Remember that if we are compiled
|
||||
* into the kernel we can't call code that's in modules. */
|
||||
#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
|
||||
(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
|
||||
|
||||
/* lnb control */
|
||||
#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
|
||||
static int flexcop_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
if (fc->fe_sleep)
|
||||
return fc->fe_sleep(fe);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* SkyStar2 DVB-S rev 2.3 */
|
||||
#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
|
||||
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);
|
||||
mdelay(12);
|
||||
udelay(500);
|
||||
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);
|
||||
}
|
||||
|
||||
static struct mt312_config skystar23_samsung_tbdu18132_config = {
|
||||
.demod_address = 0x0e,
|
||||
};
|
||||
|
||||
static int skystar2_rev23_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct dvb_frontend_ops *ops;
|
||||
|
||||
fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
|
||||
DVB_PLL_SAMSUNG_TBDU18132))
|
||||
return 0;
|
||||
|
||||
ops = &fc->fe->ops;
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#define skystar2_rev23_attach NULL
|
||||
#endif
|
||||
|
||||
/* SkyStar2 DVB-S rev 2.6 */
|
||||
#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
|
||||
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 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 = STV0299_LOCKOUTPUT_LK,
|
||||
.volt13_op0_op1 = STV0299_VOLT13_OP1,
|
||||
.min_delay_ms = 100,
|
||||
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
|
||||
};
|
||||
|
||||
static int skystar2_rev26_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
|
||||
DVB_PLL_SAMSUNG_TBMU24112))
|
||||
return 0;
|
||||
|
||||
fc->fe->ops.set_voltage = flexcop_set_voltage;
|
||||
fc->fe_sleep = fc->fe->ops.sleep;
|
||||
fc->fe->ops.sleep = flexcop_sleep;
|
||||
return 1;
|
||||
|
||||
}
|
||||
#else
|
||||
#define skystar2_rev26_attach NULL
|
||||
#endif
|
||||
|
||||
/* SkyStar2 DVB-S rev 2.7 */
|
||||
#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
|
||||
static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
|
||||
.demod_address = 0x53,
|
||||
.invert = 1,
|
||||
.repeated_start_workaround = 1,
|
||||
.serial_mpeg = 1,
|
||||
};
|
||||
|
||||
static struct itd1000_config skystar2_rev2_7_itd1000_config = {
|
||||
.i2c_address = 0x61,
|
||||
};
|
||||
|
||||
static int skystar2_rev27_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
flexcop_ibi_value r108;
|
||||
struct i2c_adapter *i2c_tuner;
|
||||
|
||||
/* enable no_base_addr - no repeated start when reading */
|
||||
fc->fc_i2c_adap[0].no_base_addr = 1;
|
||||
fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
|
||||
i2c);
|
||||
if (!fc->fe)
|
||||
goto fail;
|
||||
|
||||
i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
|
||||
if (!i2c_tuner)
|
||||
goto fail;
|
||||
|
||||
fc->fe_sleep = fc->fe->ops.sleep;
|
||||
fc->fe->ops.sleep = flexcop_sleep;
|
||||
|
||||
/* enable no_base_addr - no repeated start when reading */
|
||||
fc->fc_i2c_adap[2].no_base_addr = 1;
|
||||
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
|
||||
0x08, 1, 1, false)) {
|
||||
err("ISL6421 could NOT be attached");
|
||||
goto fail_isl;
|
||||
}
|
||||
info("ISL6421 successfully attached");
|
||||
|
||||
/* the ITD1000 requires a lower i2c clock - is it a problem ? */
|
||||
r108.raw = 0x00000506;
|
||||
fc->write_ibi_reg(fc, tw_sm_c_108, r108);
|
||||
if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
|
||||
&skystar2_rev2_7_itd1000_config)) {
|
||||
err("ITD1000 could NOT be attached");
|
||||
/* Should i2c clock be restored? */
|
||||
goto fail_isl;
|
||||
}
|
||||
info("ITD1000 successfully attached");
|
||||
|
||||
return 1;
|
||||
|
||||
fail_isl:
|
||||
fc->fc_i2c_adap[2].no_base_addr = 0;
|
||||
fail:
|
||||
/* for the next devices we need it again */
|
||||
fc->fc_i2c_adap[0].no_base_addr = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define skystar2_rev27_attach NULL
|
||||
#endif
|
||||
|
||||
/* SkyStar2 rev 2.8 */
|
||||
#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
|
||||
static struct cx24123_config skystar2_rev2_8_cx24123_config = {
|
||||
.demod_address = 0x55,
|
||||
.dont_use_pll = 1,
|
||||
.agc_callback = cx24113_agc_callback,
|
||||
};
|
||||
|
||||
static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
|
||||
.i2c_addr = 0x54,
|
||||
.xtal_khz = 10111,
|
||||
};
|
||||
|
||||
static int skystar2_rev28_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct i2c_adapter *i2c_tuner;
|
||||
|
||||
fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
|
||||
i2c);
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
|
||||
if (!i2c_tuner)
|
||||
return 0;
|
||||
|
||||
if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
|
||||
i2c_tuner)) {
|
||||
err("CX24113 could NOT be attached");
|
||||
return 0;
|
||||
}
|
||||
info("CX24113 successfully attached");
|
||||
|
||||
fc->fc_i2c_adap[2].no_base_addr = 1;
|
||||
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
|
||||
0x08, 0, 0, false)) {
|
||||
err("ISL6421 could NOT be attached");
|
||||
fc->fc_i2c_adap[2].no_base_addr = 0;
|
||||
return 0;
|
||||
}
|
||||
info("ISL6421 successfully attached");
|
||||
/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
|
||||
* IR-receiver (PIC16F818) - but the card has no input for that ??? */
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#define skystar2_rev28_attach NULL
|
||||
#endif
|
||||
|
||||
/* AirStar DVB-T */
|
||||
#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
|
||||
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 struct mt352_config samsung_tdtc9251dh0_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = samsung_tdtc9251dh0_demod_init,
|
||||
};
|
||||
|
||||
static int airstar_dvbt_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
|
||||
DVB_PLL_SAMSUNG_TDTC9251DH0);
|
||||
}
|
||||
#else
|
||||
#define airstar_dvbt_attach NULL
|
||||
#endif
|
||||
|
||||
/* AirStar ATSC 1st generation */
|
||||
#if FE_SUPPORTED(BCM3510)
|
||||
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 bcm3510_config air2pc_atsc_first_gen_config = {
|
||||
.demod_address = 0x0f,
|
||||
.request_firmware = flexcop_fe_request_firmware,
|
||||
};
|
||||
|
||||
static int airstar_atsc1_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
|
||||
return fc->fe != NULL;
|
||||
}
|
||||
#else
|
||||
#define airstar_atsc1_attach NULL
|
||||
#endif
|
||||
|
||||
/* AirStar ATSC 2nd generation */
|
||||
#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
|
||||
static struct nxt200x_config samsung_tbmv_config = {
|
||||
.demod_address = 0x0a,
|
||||
};
|
||||
|
||||
static int airstar_atsc2_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
|
||||
DVB_PLL_SAMSUNG_TBMV);
|
||||
}
|
||||
#else
|
||||
#define airstar_atsc2_attach NULL
|
||||
#endif
|
||||
|
||||
/* AirStar ATSC 3rd generation */
|
||||
#if FE_SUPPORTED(LGDT330X)
|
||||
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
|
||||
.demod_address = 0x59,
|
||||
.demod_chip = LGDT3303,
|
||||
.serial_mpeg = 0x04,
|
||||
.clock_polarity_flip = 1,
|
||||
};
|
||||
|
||||
static int airstar_atsc3_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
|
||||
TUNER_LG_TDVS_H06XF);
|
||||
}
|
||||
#else
|
||||
#define airstar_atsc3_attach NULL
|
||||
#endif
|
||||
|
||||
/* CableStar2 DVB-C */
|
||||
#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
|
||||
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,
|
||||
};
|
||||
|
||||
static int cablestar2_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fc_i2c_adap[0].no_base_addr = 1;
|
||||
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
|
||||
if (!fc->fe)
|
||||
goto fail;
|
||||
|
||||
/* This tuner doesn't use the stv0297's I2C gate, but instead the
|
||||
* tuner is connected to a different flexcop I2C adapter. */
|
||||
if (fc->fe->ops.i2c_gate_ctrl)
|
||||
fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
|
||||
fc->fe->ops.i2c_gate_ctrl = NULL;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
|
||||
&fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
/* Reset for next frontend to try */
|
||||
fc->fc_i2c_adap[0].no_base_addr = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define cablestar2_attach NULL
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
flexcop_device_type_t type;
|
||||
int (*attach)(struct flexcop_device *, struct i2c_adapter *);
|
||||
} flexcop_frontends[] = {
|
||||
{ FC_SKY_REV27, skystar2_rev27_attach },
|
||||
{ FC_SKY_REV28, skystar2_rev28_attach },
|
||||
{ FC_SKY_REV26, skystar2_rev26_attach },
|
||||
{ FC_AIR_DVBT, airstar_dvbt_attach },
|
||||
{ FC_AIR_ATSC2, airstar_atsc2_attach },
|
||||
{ FC_AIR_ATSC3, airstar_atsc3_attach },
|
||||
{ FC_AIR_ATSC1, airstar_atsc1_attach },
|
||||
{ FC_CABLE, cablestar2_attach },
|
||||
{ FC_SKY_REV23, skystar2_rev23_attach },
|
||||
};
|
||||
|
||||
/* try to figure out the frontend */
|
||||
int flexcop_frontend_init(struct flexcop_device *fc)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
|
||||
if (!flexcop_frontends[i].attach)
|
||||
continue;
|
||||
/* type needs to be set before, because of some workarounds
|
||||
* done based on the probed card type */
|
||||
fc->dev_type = flexcop_frontends[i].type;
|
||||
if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
|
||||
goto fe_found;
|
||||
/* Clean up partially attached frontend */
|
||||
if (fc->fe) {
|
||||
dvb_frontend_detach(fc->fe);
|
||||
fc->fe = NULL;
|
||||
}
|
||||
}
|
||||
fc->dev_type = FC_UNK;
|
||||
err("no frontend driver found for this B2C2/FlexCop adapter");
|
||||
return -ENODEV;
|
||||
|
||||
fe_found:
|
||||
info("found '%s' .", fc->fe->ops.info.name);
|
||||
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;
|
||||
}
|
||||
232
drivers/media/common/b2c2/flexcop-hw-filter.c
Normal file
232
drivers/media/common/b2c2/flexcop-hw-filter.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
* flexcop-hw-filter.c - pid and mac address filtering and 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;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_pid_feed_control);
|
||||
|
||||
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);
|
||||
}
|
||||
288
drivers/media/common/b2c2/flexcop-i2c.c
Normal file
288
drivers/media/common/b2c2/flexcop-i2c.c
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Linux driver for 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) {
|
||||
*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_i2c_adapter *i2c,
|
||||
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;
|
||||
|
||||
/* work-around to have CableStar2 and SkyStar2 rev 2.7 work
|
||||
* correctly:
|
||||
*
|
||||
* the ITD1000 is behind an i2c-gate which closes automatically
|
||||
* after an i2c-transaction the STV0297 needs 2 consecutive reads
|
||||
* one with no_base_addr = 0 and one with 1
|
||||
*
|
||||
* those two work-arounds are conflictin: we check for the card
|
||||
* type, it is set when probing the ITD1000 */
|
||||
if (i2c->fc->dev_type == FC_SKY_REV27)
|
||||
r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
|
||||
|
||||
ret = flexcop_i2c_operation(i2c->fc, &r100);
|
||||
if (ret != 0) {
|
||||
deb_i2c("Retrying operation\n");
|
||||
r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
|
||||
ret = flexcop_i2c_operation(i2c->fc, &r100);
|
||||
}
|
||||
if (ret != 0) {
|
||||
deb_i2c("read failed. %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf[0] = r100.tw_sm_c_100.data1_reg;
|
||||
|
||||
if (len > 0) {
|
||||
r104 = i2c->fc->read_ibi_reg(i2c->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_i2c_adapter *i2c,
|
||||
flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef DUMP_I2C_MESSAGES
|
||||
int i;
|
||||
#endif
|
||||
|
||||
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 = i2c->port;
|
||||
|
||||
#ifdef DUMP_I2C_MESSAGES
|
||||
printk(KERN_DEBUG "%d ", i2c->port);
|
||||
if (op == FC_READ)
|
||||
printk("rd(");
|
||||
else
|
||||
printk("wr(");
|
||||
printk("%02x): %02x ", chipaddr, addr);
|
||||
#endif
|
||||
|
||||
/* in that case addr is the only value ->
|
||||
* we write it twice as baseaddr and val0
|
||||
* BBTI is doing it like that for ISL6421 at least */
|
||||
if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
|
||||
buf = &addr;
|
||||
len = 1;
|
||||
}
|
||||
|
||||
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(i2c, r100, buf);
|
||||
else
|
||||
ret = flexcop_i2c_write4(i2c->fc, r100, buf);
|
||||
|
||||
#ifdef DUMP_I2C_MESSAGES
|
||||
for (i = 0; i < bytes_to_transfer; i++)
|
||||
printk("%02x ", buf[i]);
|
||||
#endif
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
buf += bytes_to_transfer;
|
||||
addr += bytes_to_transfer;
|
||||
len -= bytes_to_transfer;
|
||||
}
|
||||
|
||||
#ifdef DUMP_I2C_MESSAGES
|
||||
printk("\n");
|
||||
#endif
|
||||
|
||||
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_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
|
||||
int i, ret = 0;
|
||||
|
||||
/* Some drivers use 1 byte or 0 byte reads as probes, which this
|
||||
* driver doesn't support. These probes will always fail, so this
|
||||
* hack makes them always succeed. If one knew how, it would of
|
||||
* course be better to actually do the read. */
|
||||
if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
|
||||
return 1;
|
||||
|
||||
if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* reading */
|
||||
if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
|
||||
ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
|
||||
msgs[i].buf[0], msgs[i+1].buf,
|
||||
msgs[i+1].len);
|
||||
i++; /* skip the following message */
|
||||
} else /* writing */
|
||||
ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
|
||||
msgs[i].buf[0], &msgs[i].buf[1],
|
||||
msgs[i].len - 1);
|
||||
if (ret < 0) {
|
||||
deb_i2c("i2c master_xfer failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&i2c->fc->i2c_mutex);
|
||||
|
||||
if (ret == 0)
|
||||
ret = num;
|
||||
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);
|
||||
|
||||
fc->fc_i2c_adap[0].fc = fc;
|
||||
fc->fc_i2c_adap[1].fc = fc;
|
||||
fc->fc_i2c_adap[2].fc = fc;
|
||||
fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
|
||||
fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
|
||||
fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
|
||||
|
||||
strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
|
||||
sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
|
||||
strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
|
||||
sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
|
||||
strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
|
||||
sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
|
||||
|
||||
i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
|
||||
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
|
||||
i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
|
||||
|
||||
fc->fc_i2c_adap[0].i2c_adap.algo =
|
||||
fc->fc_i2c_adap[1].i2c_adap.algo =
|
||||
fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
|
||||
fc->fc_i2c_adap[0].i2c_adap.algo_data =
|
||||
fc->fc_i2c_adap[1].i2c_adap.algo_data =
|
||||
fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
|
||||
fc->fc_i2c_adap[0].i2c_adap.dev.parent =
|
||||
fc->fc_i2c_adap[1].i2c_adap.dev.parent =
|
||||
fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
|
||||
|
||||
ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
|
||||
if (ret < 0)
|
||||
goto adap_1_failed;
|
||||
|
||||
ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
|
||||
if (ret < 0)
|
||||
goto adap_2_failed;
|
||||
|
||||
fc->init_state |= FC_STATE_I2C_INIT;
|
||||
return 0;
|
||||
|
||||
adap_2_failed:
|
||||
i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
|
||||
adap_1_failed:
|
||||
i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void flexcop_i2c_exit(struct flexcop_device *fc)
|
||||
{
|
||||
if (fc->init_state & FC_STATE_I2C_INIT) {
|
||||
i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
|
||||
i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
|
||||
i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
|
||||
}
|
||||
fc->init_state &= ~FC_STATE_I2C_INIT;
|
||||
}
|
||||
86
drivers/media/common/b2c2/flexcop-misc.c
Normal file
86
drivers/media/common/b2c2/flexcop-misc.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Linux driver for 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("unknown FlexCop Revision: %x. Please report this to "
|
||||
"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 "
|
||||
"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[] = {
|
||||
"Unknown chip",
|
||||
"FlexCopII",
|
||||
"FlexCopIIb",
|
||||
"FlexCopIII",
|
||||
};
|
||||
|
||||
static const char *flexcop_device_names[] = {
|
||||
[FC_UNK] = "Unknown device",
|
||||
[FC_CABLE] = "Cable2PC/CableStar 2 DVB-C",
|
||||
[FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T",
|
||||
[FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation",
|
||||
[FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation",
|
||||
[FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
|
||||
[FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
|
||||
[FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
|
||||
[FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
|
||||
[FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
|
||||
};
|
||||
|
||||
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);
|
||||
166
drivers/media/common/b2c2/flexcop-reg.h
Normal file
166
drivers/media/common/b2c2/flexcop-reg.h
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Linux driver for 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_CABLE,
|
||||
FC_AIR_DVBT,
|
||||
FC_AIR_ATSC1,
|
||||
FC_AIR_ATSC2,
|
||||
FC_AIR_ATSC3,
|
||||
FC_SKY_REV23,
|
||||
FC_SKY_REV26,
|
||||
FC_SKY_REV27,
|
||||
FC_SKY_REV28,
|
||||
} 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
|
||||
363
drivers/media/common/b2c2/flexcop-sram.c
Normal file
363
drivers/media/common/b2c2/flexcop-sram.c
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Linux driver for 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", __func__);
|
||||
|
||||
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", __func__);
|
||||
|
||||
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", __func__);
|
||||
|
||||
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", __func__, adapter->dw_sram_type);
|
||||
} else {
|
||||
adapter->dw_sram_type = 0x10000;
|
||||
ddprintk("%s: dw_sram_type = %x\n", __func__, 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", __func__, 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", __func__, 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", __func__, 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", __func__, 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", __func__);
|
||||
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", __func__);
|
||||
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", __func__);
|
||||
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", __func__);
|
||||
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", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sll_detect_sram_size(struct adapter *adapter)
|
||||
{
|
||||
sram_detect_for_flex2(adapter);
|
||||
}
|
||||
|
||||
#endif
|
||||
325
drivers/media/common/b2c2/flexcop.c
Normal file
325
drivers/media/common/b2c2/flexcop.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
* flexcop.c - main module part
|
||||
* Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
* based on 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)
|
||||
* Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
|
||||
* 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;
|
||||
EXPORT_SYMBOL_GPL(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
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/* 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 = dvb_register_adapter(&fc->dvb_adapter,
|
||||
"FlexCop Digital TV device", fc->owner,
|
||||
fc->dev, adapter_nr);
|
||||
if (ret < 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;
|
||||
|
||||
ret = dvb_dmx_init(&fc->demux);
|
||||
if (ret < 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;
|
||||
ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
|
||||
if (ret < 0) {
|
||||
err("dvb_dmxdev_init failed: error %d", ret);
|
||||
goto err_dmx_dev;
|
||||
}
|
||||
|
||||
ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
|
||||
if (ret < 0) {
|
||||
err("adding hw_frontend to dmx failed: error %d", ret);
|
||||
goto err_dmx_add_hw_frontend;
|
||||
}
|
||||
|
||||
fc->mem_frontend.source = DMX_MEMORY_FE;
|
||||
ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
|
||||
if (ret < 0) {
|
||||
err("adding mem_frontend to dmx failed: error %d", ret);
|
||||
goto err_dmx_add_mem_frontend;
|
||||
}
|
||||
|
||||
ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
|
||||
if (ret < 0) {
|
||||
err("connect frontend failed: error %d", ret);
|
||||
goto err_connect_frontend;
|
||||
}
|
||||
|
||||
ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
|
||||
if (ret < 0) {
|
||||
err("dvb_net_init failed: error %d", ret);
|
||||
goto err_net;
|
||||
}
|
||||
|
||||
fc->init_state |= FC_STATE_DVB_INIT;
|
||||
return 0;
|
||||
|
||||
err_net:
|
||||
fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
|
||||
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);
|
||||
fc->write_ibi_reg(fc,ctrl_208,v208_save);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ret = flexcop_dvb_init(fc);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* i2c has to be done before doing EEProm stuff -
|
||||
* because the EEProm is accessed via i2c */
|
||||
ret = flexcop_i2c_init(fc);
|
||||
if (ret)
|
||||
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 = %pM", b);
|
||||
flexcop_set_mac_filter(fc,b);
|
||||
flexcop_mac_filter_ctrl(fc,1);
|
||||
} else
|
||||
warn("reading of MAC address failed.\n");
|
||||
|
||||
ret = flexcop_frontend_init(fc);
|
||||
if (ret)
|
||||
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");
|
||||
29
drivers/media/common/b2c2/flexcop.h
Normal file
29
drivers/media/common/b2c2/flexcop.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Linux driver for 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
|
||||
455
drivers/media/common/b2c2/flexcop_ibi_value_be.h
Normal file
455
drivers/media/common/b2c2/flexcop_ibi_value_be.h
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
/* 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
|
||||
455
drivers/media/common/b2c2/flexcop_ibi_value_le.h
Normal file
455
drivers/media/common/b2c2/flexcop_ibi_value_le.h
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
/* 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
|
||||
260
drivers/media/common/btcx-risc.c
Normal file
260
drivers/media/common/btcx-risc.c
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
|
||||
btcx-risc.c
|
||||
|
||||
bt848/bt878/cx2388x risc code generator.
|
||||
|
||||
(c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
|
||||
|
||||
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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#include "btcx-risc.h"
|
||||
|
||||
MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers");
|
||||
MODULE_AUTHOR("Gerd Knorr");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* allocate/free risc memory */
|
||||
|
||||
static int memcnt;
|
||||
|
||||
void btcx_riscmem_free(struct pci_dev *pci,
|
||||
struct btcx_riscmem *risc)
|
||||
{
|
||||
if (NULL == risc->cpu)
|
||||
return;
|
||||
if (debug) {
|
||||
memcnt--;
|
||||
printk("btcx: riscmem free [%d] dma=%lx\n",
|
||||
memcnt, (unsigned long)risc->dma);
|
||||
}
|
||||
pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
|
||||
memset(risc,0,sizeof(*risc));
|
||||
}
|
||||
|
||||
int btcx_riscmem_alloc(struct pci_dev *pci,
|
||||
struct btcx_riscmem *risc,
|
||||
unsigned int size)
|
||||
{
|
||||
__le32 *cpu;
|
||||
dma_addr_t dma = 0;
|
||||
|
||||
if (NULL != risc->cpu && risc->size < size)
|
||||
btcx_riscmem_free(pci,risc);
|
||||
if (NULL == risc->cpu) {
|
||||
cpu = pci_alloc_consistent(pci, size, &dma);
|
||||
if (NULL == cpu)
|
||||
return -ENOMEM;
|
||||
risc->cpu = cpu;
|
||||
risc->dma = dma;
|
||||
risc->size = size;
|
||||
if (debug) {
|
||||
memcnt++;
|
||||
printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
|
||||
memcnt, (unsigned long)dma, cpu, size);
|
||||
}
|
||||
}
|
||||
memset(risc->cpu,0,risc->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* screen overlay helpers */
|
||||
|
||||
int
|
||||
btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
|
||||
struct v4l2_clip *clips, unsigned int n)
|
||||
{
|
||||
if (win->left < 0) {
|
||||
/* left */
|
||||
clips[n].c.left = 0;
|
||||
clips[n].c.top = 0;
|
||||
clips[n].c.width = -win->left;
|
||||
clips[n].c.height = win->height;
|
||||
n++;
|
||||
}
|
||||
if (win->left + win->width > swidth) {
|
||||
/* right */
|
||||
clips[n].c.left = swidth - win->left;
|
||||
clips[n].c.top = 0;
|
||||
clips[n].c.width = win->width - clips[n].c.left;
|
||||
clips[n].c.height = win->height;
|
||||
n++;
|
||||
}
|
||||
if (win->top < 0) {
|
||||
/* top */
|
||||
clips[n].c.left = 0;
|
||||
clips[n].c.top = 0;
|
||||
clips[n].c.width = win->width;
|
||||
clips[n].c.height = -win->top;
|
||||
n++;
|
||||
}
|
||||
if (win->top + win->height > sheight) {
|
||||
/* bottom */
|
||||
clips[n].c.left = 0;
|
||||
clips[n].c.top = sheight - win->top;
|
||||
clips[n].c.width = win->width;
|
||||
clips[n].c.height = win->height - clips[n].c.top;
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
|
||||
{
|
||||
s32 nx,nw,dx;
|
||||
unsigned int i;
|
||||
|
||||
/* fixup window */
|
||||
nx = (win->left + mask) & ~mask;
|
||||
nw = (win->width) & ~mask;
|
||||
if (nx + nw > win->left + win->width)
|
||||
nw -= mask+1;
|
||||
dx = nx - win->left;
|
||||
win->left = nx;
|
||||
win->width = nw;
|
||||
if (debug)
|
||||
printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
|
||||
win->width, win->height, win->left, win->top, dx);
|
||||
|
||||
/* fixup clips */
|
||||
for (i = 0; i < n; i++) {
|
||||
nx = (clips[i].c.left-dx) & ~mask;
|
||||
nw = (clips[i].c.width) & ~mask;
|
||||
if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
|
||||
nw += mask+1;
|
||||
clips[i].c.left = nx;
|
||||
clips[i].c.width = nw;
|
||||
if (debug)
|
||||
printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n",
|
||||
clips[i].c.width, clips[i].c.height,
|
||||
clips[i].c.left, clips[i].c.top);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
|
||||
{
|
||||
struct v4l2_clip swap;
|
||||
int i,j,n;
|
||||
|
||||
if (nclips < 2)
|
||||
return;
|
||||
for (i = nclips-2; i >= 0; i--) {
|
||||
for (n = 0, j = 0; j <= i; j++) {
|
||||
if (clips[j].c.left > clips[j+1].c.left) {
|
||||
swap = clips[j];
|
||||
clips[j] = clips[j+1];
|
||||
clips[j+1] = swap;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (0 == n)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
btcx_calc_skips(int line, int width, int *maxy,
|
||||
struct btcx_skiplist *skips, unsigned int *nskips,
|
||||
const struct v4l2_clip *clips, unsigned int nclips)
|
||||
{
|
||||
unsigned int clip,skip;
|
||||
int end, maxline;
|
||||
|
||||
skip=0;
|
||||
maxline = 9999;
|
||||
for (clip = 0; clip < nclips; clip++) {
|
||||
|
||||
/* sanity checks */
|
||||
if (clips[clip].c.left + clips[clip].c.width <= 0)
|
||||
continue;
|
||||
if (clips[clip].c.left > (signed)width)
|
||||
break;
|
||||
|
||||
/* vertical range */
|
||||
if (line > clips[clip].c.top+clips[clip].c.height-1)
|
||||
continue;
|
||||
if (line < clips[clip].c.top) {
|
||||
if (maxline > clips[clip].c.top-1)
|
||||
maxline = clips[clip].c.top-1;
|
||||
continue;
|
||||
}
|
||||
if (maxline > clips[clip].c.top+clips[clip].c.height-1)
|
||||
maxline = clips[clip].c.top+clips[clip].c.height-1;
|
||||
|
||||
/* horizontal range */
|
||||
if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
|
||||
/* new one */
|
||||
skips[skip].start = clips[clip].c.left;
|
||||
if (skips[skip].start < 0)
|
||||
skips[skip].start = 0;
|
||||
skips[skip].end = clips[clip].c.left + clips[clip].c.width;
|
||||
if (skips[skip].end > width)
|
||||
skips[skip].end = width;
|
||||
skip++;
|
||||
} else {
|
||||
/* overlaps -- expand last one */
|
||||
end = clips[clip].c.left + clips[clip].c.width;
|
||||
if (skips[skip-1].end < end)
|
||||
skips[skip-1].end = end;
|
||||
if (skips[skip-1].end > width)
|
||||
skips[skip-1].end = width;
|
||||
}
|
||||
}
|
||||
*nskips = skip;
|
||||
*maxy = maxline;
|
||||
|
||||
if (debug) {
|
||||
printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
|
||||
for (skip = 0; skip < *nskips; skip++) {
|
||||
printk(" %d-%d",skips[skip].start,skips[skip].end);
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
|
||||
EXPORT_SYMBOL(btcx_riscmem_alloc);
|
||||
EXPORT_SYMBOL(btcx_riscmem_free);
|
||||
|
||||
EXPORT_SYMBOL(btcx_screen_clips);
|
||||
EXPORT_SYMBOL(btcx_align);
|
||||
EXPORT_SYMBOL(btcx_sort_clips);
|
||||
EXPORT_SYMBOL(btcx_calc_skips);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
34
drivers/media/common/btcx-risc.h
Normal file
34
drivers/media/common/btcx-risc.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
*/
|
||||
struct btcx_riscmem {
|
||||
unsigned int size;
|
||||
__le32 *cpu;
|
||||
__le32 *jmp;
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
struct btcx_skiplist {
|
||||
int start;
|
||||
int end;
|
||||
};
|
||||
|
||||
int btcx_riscmem_alloc(struct pci_dev *pci,
|
||||
struct btcx_riscmem *risc,
|
||||
unsigned int size);
|
||||
void btcx_riscmem_free(struct pci_dev *pci,
|
||||
struct btcx_riscmem *risc);
|
||||
|
||||
int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
|
||||
struct v4l2_clip *clips, unsigned int n);
|
||||
int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
|
||||
unsigned int n, int mask);
|
||||
void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
|
||||
void btcx_calc_skips(int line, int width, int *maxy,
|
||||
struct btcx_skiplist *skips, unsigned int *nskips,
|
||||
const struct v4l2_clip *clips, unsigned int nclips);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
1727
drivers/media/common/cx2341x.c
Normal file
1727
drivers/media/common/cx2341x.c
Normal file
File diff suppressed because it is too large
Load diff
132
drivers/media/common/cypress_firmware.c
Normal file
132
drivers/media/common/cypress_firmware.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* cypress_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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "cypress_firmware.h"
|
||||
|
||||
struct usb_cypress_controller {
|
||||
u8 id;
|
||||
const char *name; /* name of the usb controller */
|
||||
u16 cs_reg; /* needs to be restarted,
|
||||
* when the firmware has been downloaded */
|
||||
};
|
||||
|
||||
static const struct usb_cypress_controller cypress[] = {
|
||||
{ .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 },
|
||||
{ .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 },
|
||||
{ .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 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);
|
||||
}
|
||||
|
||||
static int cypress_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 = b[1] | (b[2] << 8);
|
||||
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);
|
||||
}
|
||||
|
||||
memcpy(hx->data, &b[data_offs], hx->len);
|
||||
hx->chk = b[hx->len + data_offs];
|
||||
*pos += hx->len + 5;
|
||||
|
||||
return *pos;
|
||||
}
|
||||
|
||||
int cypress_load_firmware(struct usb_device *udev,
|
||||
const struct firmware *fw, int type)
|
||||
{
|
||||
struct hexline *hx;
|
||||
int ret, pos = 0;
|
||||
|
||||
hx = kmalloc(sizeof(struct hexline), GFP_KERNEL);
|
||||
if (!hx) {
|
||||
dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* stop the CPU */
|
||||
hx->data[0] = 1;
|
||||
ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1);
|
||||
if (ret != 1) {
|
||||
dev_err(&udev->dev, "%s: CPU stop failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
ret = -EIO;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
/* write firmware to memory */
|
||||
for (;;) {
|
||||
ret = cypress_get_hexline(fw, hx, &pos);
|
||||
if (ret < 0)
|
||||
goto err_kfree;
|
||||
else if (ret == 0)
|
||||
break;
|
||||
|
||||
ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
|
||||
if (ret < 0) {
|
||||
goto err_kfree;
|
||||
} else if (ret != hx->len) {
|
||||
dev_err(&udev->dev,
|
||||
"%s: error while transferring firmware (transferred size=%d, block size=%d)\n",
|
||||
KBUILD_MODNAME, ret, hx->len);
|
||||
ret = -EIO;
|
||||
goto err_kfree;
|
||||
}
|
||||
}
|
||||
|
||||
/* start the CPU */
|
||||
hx->data[0] = 0;
|
||||
ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1);
|
||||
if (ret != 1) {
|
||||
dev_err(&udev->dev, "%s: CPU start failed=%d\n",
|
||||
KBUILD_MODNAME, ret);
|
||||
ret = -EIO;
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
err_kfree:
|
||||
kfree(hx);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cypress_load_firmware);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Cypress firmware download");
|
||||
MODULE_LICENSE("GPL");
|
||||
28
drivers/media/common/cypress_firmware.h
Normal file
28
drivers/media/common/cypress_firmware.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CYPRESS_FIRMWARE_H
|
||||
#define CYPRESS_FIRMWARE_H
|
||||
|
||||
#define CYPRESS_AN2135 0
|
||||
#define CYPRESS_AN2235 1
|
||||
#define CYPRESS_FX2 2
|
||||
|
||||
/* commonly used firmware download types and function */
|
||||
struct hexline {
|
||||
u8 len;
|
||||
u32 addr;
|
||||
u8 type;
|
||||
u8 data[255];
|
||||
u8 chk;
|
||||
};
|
||||
|
||||
int cypress_load_firmware(struct usb_device *, const struct firmware *, int);
|
||||
|
||||
#endif
|
||||
9
drivers/media/common/saa7146/Kconfig
Normal file
9
drivers/media/common/saa7146/Kconfig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
config VIDEO_SAA7146
|
||||
tristate
|
||||
depends on I2C && PCI
|
||||
|
||||
config VIDEO_SAA7146_VV
|
||||
tristate
|
||||
depends on VIDEO_V4L2
|
||||
select VIDEOBUF_DMA_SG
|
||||
select VIDEO_SAA7146
|
||||
5
drivers/media/common/saa7146/Makefile
Normal file
5
drivers/media/common/saa7146/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
saa7146-objs := saa7146_i2c.o saa7146_core.o
|
||||
saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
|
||||
obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
|
||||
587
drivers/media/common/saa7146/saa7146_core.c
Normal file
587
drivers/media/common/saa7146/saa7146_core.c
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
saa7146.o - driver for generic saa7146-based hardware
|
||||
|
||||
Copyright (C) 1998-2003 Michael Hunold <michael@mihu.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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <media/saa7146.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static int saa7146_num;
|
||||
|
||||
unsigned int saa7146_debug;
|
||||
|
||||
module_param(saa7146_debug, uint, 0644);
|
||||
MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
|
||||
|
||||
#if 0
|
||||
static void dump_registers(struct saa7146_dev* dev)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
pr_info(" @ %li jiffies:\n", jiffies);
|
||||
for (i = 0; i <= 0x148; i += 4)
|
||||
pr_info("0x%03x: 0x%08x\n", i, saa7146_read(dev, i));
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* gpio and debi helper functions
|
||||
****************************************************************************/
|
||||
|
||||
void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
|
||||
{
|
||||
u32 value = 0;
|
||||
|
||||
BUG_ON(port > 3);
|
||||
|
||||
value = saa7146_read(dev, GPIO_CTRL);
|
||||
value &= ~(0xff << (8*port));
|
||||
value |= (data << (8*port));
|
||||
saa7146_write(dev, GPIO_CTRL, value);
|
||||
}
|
||||
|
||||
/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
|
||||
static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
|
||||
unsigned long us1, unsigned long us2)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int err;
|
||||
|
||||
/* wait for registers to be programmed */
|
||||
timeout = jiffies + usecs_to_jiffies(us1);
|
||||
while (1) {
|
||||
err = time_after(jiffies, timeout);
|
||||
if (saa7146_read(dev, MC2) & 2)
|
||||
break;
|
||||
if (err) {
|
||||
pr_err("%s: %s timed out while waiting for registers getting programmed\n",
|
||||
dev->name, __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
/* wait for transfer to complete */
|
||||
timeout = jiffies + usecs_to_jiffies(us2);
|
||||
while (1) {
|
||||
err = time_after(jiffies, timeout);
|
||||
if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
|
||||
break;
|
||||
saa7146_read(dev, MC2);
|
||||
if (err) {
|
||||
DEB_S("%s: %s timed out while waiting for transfer completion\n",
|
||||
dev->name, __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
|
||||
unsigned long us1, unsigned long us2)
|
||||
{
|
||||
unsigned long loops;
|
||||
|
||||
/* wait for registers to be programmed */
|
||||
loops = us1;
|
||||
while (1) {
|
||||
if (saa7146_read(dev, MC2) & 2)
|
||||
break;
|
||||
if (!loops--) {
|
||||
pr_err("%s: %s timed out while waiting for registers getting programmed\n",
|
||||
dev->name, __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* wait for transfer to complete */
|
||||
loops = us2 / 5;
|
||||
while (1) {
|
||||
if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
|
||||
break;
|
||||
saa7146_read(dev, MC2);
|
||||
if (!loops--) {
|
||||
DEB_S("%s: %s timed out while waiting for transfer completion\n",
|
||||
dev->name, __func__);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
|
||||
{
|
||||
if (nobusyloop)
|
||||
return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
|
||||
else
|
||||
return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* general helper functions
|
||||
****************************************************************************/
|
||||
|
||||
/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
|
||||
make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
|
||||
may be triggered on highmem machines */
|
||||
static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
|
||||
{
|
||||
struct scatterlist *sglist;
|
||||
struct page *pg;
|
||||
int i;
|
||||
|
||||
sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
|
||||
if (NULL == sglist)
|
||||
return NULL;
|
||||
sg_init_table(sglist, nr_pages);
|
||||
for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
|
||||
pg = vmalloc_to_page(virt);
|
||||
if (NULL == pg)
|
||||
goto err;
|
||||
BUG_ON(PageHighMem(pg));
|
||||
sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
|
||||
}
|
||||
return sglist;
|
||||
|
||||
err:
|
||||
kfree(sglist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/********************************************************************************/
|
||||
/* common page table functions */
|
||||
|
||||
void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
|
||||
{
|
||||
int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
|
||||
void *mem = vmalloc_32(length);
|
||||
int slen = 0;
|
||||
|
||||
if (NULL == mem)
|
||||
goto err_null;
|
||||
|
||||
if (!(pt->slist = vmalloc_to_sg(mem, pages)))
|
||||
goto err_free_mem;
|
||||
|
||||
if (saa7146_pgtable_alloc(pci, pt))
|
||||
goto err_free_slist;
|
||||
|
||||
pt->nents = pages;
|
||||
slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);
|
||||
if (0 == slen)
|
||||
goto err_free_pgtable;
|
||||
|
||||
if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))
|
||||
goto err_unmap_sg;
|
||||
|
||||
return mem;
|
||||
|
||||
err_unmap_sg:
|
||||
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
|
||||
err_free_pgtable:
|
||||
saa7146_pgtable_free(pci, pt);
|
||||
err_free_slist:
|
||||
kfree(pt->slist);
|
||||
pt->slist = NULL;
|
||||
err_free_mem:
|
||||
vfree(mem);
|
||||
err_null:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
|
||||
{
|
||||
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
|
||||
saa7146_pgtable_free(pci, pt);
|
||||
kfree(pt->slist);
|
||||
pt->slist = NULL;
|
||||
vfree(mem);
|
||||
}
|
||||
|
||||
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
{
|
||||
if (NULL == pt->cpu)
|
||||
return;
|
||||
pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);
|
||||
pt->cpu = NULL;
|
||||
}
|
||||
|
||||
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
|
||||
{
|
||||
__le32 *cpu;
|
||||
dma_addr_t dma_addr = 0;
|
||||
|
||||
cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
|
||||
if (NULL == cpu) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
pt->size = PAGE_SIZE;
|
||||
pt->cpu = cpu;
|
||||
pt->dma = dma_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
|
||||
struct scatterlist *list, int sglen )
|
||||
{
|
||||
__le32 *ptr, fill;
|
||||
int nr_pages = 0;
|
||||
int i,p;
|
||||
|
||||
BUG_ON(0 == sglen);
|
||||
BUG_ON(list->offset > PAGE_SIZE);
|
||||
|
||||
/* if we have a user buffer, the first page may not be
|
||||
aligned to a page boundary. */
|
||||
pt->offset = list->offset;
|
||||
|
||||
ptr = pt->cpu;
|
||||
for (i = 0; i < sglen; i++, list++) {
|
||||
/*
|
||||
pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n",
|
||||
i, sg_dma_address(list), sg_dma_len(list),
|
||||
list->offset);
|
||||
*/
|
||||
for (p = 0; p * 4096 < list->length; p++, ptr++) {
|
||||
*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);
|
||||
nr_pages++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* safety; fill the page table up with the last valid page */
|
||||
fill = *(ptr-1);
|
||||
for(i=nr_pages;i<1024;i++) {
|
||||
*ptr++ = fill;
|
||||
}
|
||||
|
||||
/*
|
||||
ptr = pt->cpu;
|
||||
pr_debug("offset: %d\n", pt->offset);
|
||||
for(i=0;i<5;i++) {
|
||||
pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************************/
|
||||
/* interrupt handler */
|
||||
static irqreturn_t interrupt_hw(int irq, void *dev_id)
|
||||
{
|
||||
struct saa7146_dev *dev = dev_id;
|
||||
u32 isr;
|
||||
u32 ack_isr;
|
||||
|
||||
/* read out the interrupt status register */
|
||||
ack_isr = isr = saa7146_read(dev, ISR);
|
||||
|
||||
/* is this our interrupt? */
|
||||
if ( 0 == isr ) {
|
||||
/* nope, some other device */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (dev->ext) {
|
||||
if (dev->ext->irq_mask & isr) {
|
||||
if (dev->ext->irq_func)
|
||||
dev->ext->irq_func(dev, &isr);
|
||||
isr &= ~dev->ext->irq_mask;
|
||||
}
|
||||
}
|
||||
if (0 != (isr & (MASK_27))) {
|
||||
DEB_INT("irq: RPS0 (0x%08x)\n", isr);
|
||||
if (dev->vv_data && dev->vv_callback)
|
||||
dev->vv_callback(dev,isr);
|
||||
isr &= ~MASK_27;
|
||||
}
|
||||
if (0 != (isr & (MASK_28))) {
|
||||
if (dev->vv_data && dev->vv_callback)
|
||||
dev->vv_callback(dev,isr);
|
||||
isr &= ~MASK_28;
|
||||
}
|
||||
if (0 != (isr & (MASK_16|MASK_17))) {
|
||||
SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
|
||||
/* only wake up if we expect something */
|
||||
if (0 != dev->i2c_op) {
|
||||
dev->i2c_op = 0;
|
||||
wake_up(&dev->i2c_wq);
|
||||
} else {
|
||||
u32 psr = saa7146_read(dev, PSR);
|
||||
u32 ssr = saa7146_read(dev, SSR);
|
||||
pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
|
||||
dev->name, isr, psr, ssr);
|
||||
}
|
||||
isr &= ~(MASK_16|MASK_17);
|
||||
}
|
||||
if( 0 != isr ) {
|
||||
ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n",
|
||||
isr);
|
||||
ERR("disabling interrupt source(s)!\n");
|
||||
SAA7146_IER_DISABLE(dev,isr);
|
||||
}
|
||||
saa7146_write(dev, ISR, ack_isr);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*********************************************************************************/
|
||||
/* configuration-functions */
|
||||
|
||||
static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
|
||||
{
|
||||
struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
|
||||
struct saa7146_extension *ext = pci_ext->ext;
|
||||
struct saa7146_dev *dev;
|
||||
int err = -ENOMEM;
|
||||
|
||||
/* clear out mem for sure */
|
||||
dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
ERR("out of memory\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* create a nice device name */
|
||||
sprintf(dev->name, "saa7146 (%d)", saa7146_num);
|
||||
|
||||
DEB_EE("pci:%p\n", pci);
|
||||
|
||||
err = pci_enable_device(pci);
|
||||
if (err < 0) {
|
||||
ERR("pci_enable_device() failed\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* enable bus-mastering */
|
||||
pci_set_master(pci);
|
||||
|
||||
dev->pci = pci;
|
||||
|
||||
/* get chip-revision; this is needed to enable bug-fixes */
|
||||
dev->revision = pci->revision;
|
||||
|
||||
/* remap the memory from virtual to physical address */
|
||||
|
||||
err = pci_request_region(pci, 0, "saa7146");
|
||||
if (err < 0)
|
||||
goto err_disable;
|
||||
|
||||
dev->mem = ioremap(pci_resource_start(pci, 0),
|
||||
pci_resource_len(pci, 0));
|
||||
if (!dev->mem) {
|
||||
ERR("ioremap() failed\n");
|
||||
err = -ENODEV;
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
/* we don't do a master reset here anymore, it screws up
|
||||
some boards that don't have an i2c-eeprom for configuration
|
||||
values */
|
||||
/*
|
||||
saa7146_write(dev, MC1, MASK_31);
|
||||
*/
|
||||
|
||||
/* disable all irqs */
|
||||
saa7146_write(dev, IER, 0);
|
||||
|
||||
/* shut down all dma transfers and rps tasks */
|
||||
saa7146_write(dev, MC1, 0x30ff0000);
|
||||
|
||||
/* clear out any rps-signals pending */
|
||||
saa7146_write(dev, MC2, 0xf8000000);
|
||||
|
||||
/* request an interrupt for the saa7146 */
|
||||
err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED,
|
||||
dev->name, dev);
|
||||
if (err < 0) {
|
||||
ERR("request_irq() failed\n");
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
/* get memory for various stuff */
|
||||
dev->d_rps0.cpu_addr = pci_zalloc_consistent(pci, SAA7146_RPS_MEM,
|
||||
&dev->d_rps0.dma_handle);
|
||||
if (!dev->d_rps0.cpu_addr)
|
||||
goto err_free_irq;
|
||||
|
||||
dev->d_rps1.cpu_addr = pci_zalloc_consistent(pci, SAA7146_RPS_MEM,
|
||||
&dev->d_rps1.dma_handle);
|
||||
if (!dev->d_rps1.cpu_addr)
|
||||
goto err_free_rps0;
|
||||
|
||||
dev->d_i2c.cpu_addr = pci_zalloc_consistent(pci, SAA7146_RPS_MEM,
|
||||
&dev->d_i2c.dma_handle);
|
||||
if (!dev->d_i2c.cpu_addr)
|
||||
goto err_free_rps1;
|
||||
|
||||
/* the rest + print status message */
|
||||
|
||||
pr_info("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x)\n",
|
||||
dev->mem, dev->revision, pci->irq,
|
||||
pci->subsystem_vendor, pci->subsystem_device);
|
||||
dev->ext = ext;
|
||||
|
||||
mutex_init(&dev->v4l2_lock);
|
||||
spin_lock_init(&dev->int_slock);
|
||||
spin_lock_init(&dev->slock);
|
||||
|
||||
mutex_init(&dev->i2c_lock);
|
||||
|
||||
dev->module = THIS_MODULE;
|
||||
init_waitqueue_head(&dev->i2c_wq);
|
||||
|
||||
/* set some sane pci arbitrition values */
|
||||
saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
|
||||
|
||||
/* TODO: use the status code of the callback */
|
||||
|
||||
err = -ENODEV;
|
||||
|
||||
if (ext->probe && ext->probe(dev)) {
|
||||
DEB_D("ext->probe() failed for %p. skipping device.\n", dev);
|
||||
goto err_free_i2c;
|
||||
}
|
||||
|
||||
if (ext->attach(dev, pci_ext)) {
|
||||
DEB_D("ext->attach() failed for %p. skipping device.\n", dev);
|
||||
goto err_free_i2c;
|
||||
}
|
||||
/* V4L extensions will set the pci drvdata to the v4l2_device in the
|
||||
attach() above. So for those cards that do not use V4L we have to
|
||||
set it explicitly. */
|
||||
pci_set_drvdata(pci, &dev->v4l2_dev);
|
||||
|
||||
saa7146_num++;
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
|
||||
err_free_i2c:
|
||||
pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
|
||||
dev->d_i2c.dma_handle);
|
||||
err_free_rps1:
|
||||
pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
|
||||
dev->d_rps1.dma_handle);
|
||||
err_free_rps0:
|
||||
pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
|
||||
dev->d_rps0.dma_handle);
|
||||
err_free_irq:
|
||||
free_irq(pci->irq, (void *)dev);
|
||||
err_unmap:
|
||||
iounmap(dev->mem);
|
||||
err_release:
|
||||
pci_release_region(pci, 0);
|
||||
err_disable:
|
||||
pci_disable_device(pci);
|
||||
err_free:
|
||||
kfree(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void saa7146_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
|
||||
struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
|
||||
struct {
|
||||
void *addr;
|
||||
dma_addr_t dma;
|
||||
} dev_map[] = {
|
||||
{ dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
|
||||
{ dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
|
||||
{ dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
|
||||
{ NULL, 0 }
|
||||
}, *p;
|
||||
|
||||
DEB_EE("dev:%p\n", dev);
|
||||
|
||||
dev->ext->detach(dev);
|
||||
|
||||
/* shut down all video dma transfers */
|
||||
saa7146_write(dev, MC1, 0x00ff0000);
|
||||
|
||||
/* disable all irqs, release irq-routine */
|
||||
saa7146_write(dev, IER, 0);
|
||||
|
||||
free_irq(pdev->irq, dev);
|
||||
|
||||
for (p = dev_map; p->addr; p++)
|
||||
pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
|
||||
|
||||
iounmap(dev->mem);
|
||||
pci_release_region(pdev, 0);
|
||||
pci_disable_device(pdev);
|
||||
kfree(dev);
|
||||
|
||||
saa7146_num--;
|
||||
}
|
||||
|
||||
/*********************************************************************************/
|
||||
/* extension handling functions */
|
||||
|
||||
int saa7146_register_extension(struct saa7146_extension* ext)
|
||||
{
|
||||
DEB_EE("ext:%p\n", ext);
|
||||
|
||||
ext->driver.name = ext->name;
|
||||
ext->driver.id_table = ext->pci_tbl;
|
||||
ext->driver.probe = saa7146_init_one;
|
||||
ext->driver.remove = saa7146_remove_one;
|
||||
|
||||
pr_info("register extension '%s'\n", ext->name);
|
||||
return pci_register_driver(&ext->driver);
|
||||
}
|
||||
|
||||
int saa7146_unregister_extension(struct saa7146_extension* ext)
|
||||
{
|
||||
DEB_EE("ext:%p\n", ext);
|
||||
pr_info("unregister extension '%s'\n", ext->name);
|
||||
pci_unregister_driver(&ext->driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(saa7146_register_extension);
|
||||
EXPORT_SYMBOL_GPL(saa7146_unregister_extension);
|
||||
|
||||
/* misc functions used by extension modules */
|
||||
EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);
|
||||
EXPORT_SYMBOL_GPL(saa7146_pgtable_free);
|
||||
EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);
|
||||
EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);
|
||||
EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);
|
||||
EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
|
||||
|
||||
EXPORT_SYMBOL_GPL(saa7146_setgpio);
|
||||
|
||||
EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
|
||||
|
||||
EXPORT_SYMBOL_GPL(saa7146_debug);
|
||||
|
||||
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
|
||||
MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
|
||||
MODULE_LICENSE("GPL");
|
||||
659
drivers/media/common/saa7146/saa7146_fops.c
Normal file
659
drivers/media/common/saa7146/saa7146_fops.c
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <media/saa7146_vv.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/****************************************************************************/
|
||||
/* resource management functions, shamelessly stolen from saa7134 driver */
|
||||
|
||||
int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
|
||||
{
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
|
||||
if (fh->resources & bit) {
|
||||
DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
|
||||
bit, vv->resources);
|
||||
/* have it already allocated */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* is it free? */
|
||||
if (vv->resources & bit) {
|
||||
DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
|
||||
vv->resources, bit);
|
||||
/* no, someone else uses it */
|
||||
return 0;
|
||||
}
|
||||
/* it's free, grab it */
|
||||
fh->resources |= bit;
|
||||
vv->resources |= bit;
|
||||
DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
|
||||
{
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
|
||||
BUG_ON((fh->resources & bits) != bits);
|
||||
|
||||
fh->resources &= ~bits;
|
||||
vv->resources &= ~bits;
|
||||
DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/* common dma functions */
|
||||
|
||||
void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
|
||||
struct saa7146_buf *buf)
|
||||
{
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
DEB_EE("dev:%p, buf:%p\n", dev, buf);
|
||||
|
||||
BUG_ON(in_interrupt());
|
||||
|
||||
videobuf_waiton(q, &buf->vb, 0, 0);
|
||||
videobuf_dma_unmap(q->dev, dma);
|
||||
videobuf_dma_free(dma);
|
||||
buf->vb.state = VIDEOBUF_NEEDS_INIT;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/* common buffer functions */
|
||||
|
||||
int saa7146_buffer_queue(struct saa7146_dev *dev,
|
||||
struct saa7146_dmaqueue *q,
|
||||
struct saa7146_buf *buf)
|
||||
{
|
||||
assert_spin_locked(&dev->slock);
|
||||
DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf);
|
||||
|
||||
BUG_ON(!q);
|
||||
|
||||
if (NULL == q->curr) {
|
||||
q->curr = buf;
|
||||
DEB_D("immediately activating buffer %p\n", buf);
|
||||
buf->activate(dev,buf,NULL);
|
||||
} else {
|
||||
list_add_tail(&buf->vb.queue,&q->queue);
|
||||
buf->vb.state = VIDEOBUF_QUEUED;
|
||||
DEB_D("adding buffer %p to queue. (active buffer present)\n",
|
||||
buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void saa7146_buffer_finish(struct saa7146_dev *dev,
|
||||
struct saa7146_dmaqueue *q,
|
||||
int state)
|
||||
{
|
||||
assert_spin_locked(&dev->slock);
|
||||
DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
|
||||
DEB_EE("q->curr:%p\n", q->curr);
|
||||
|
||||
BUG_ON(!q->curr);
|
||||
|
||||
/* finish current buffer */
|
||||
if (NULL == q->curr) {
|
||||
DEB_D("aiii. no current buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
q->curr->vb.state = state;
|
||||
v4l2_get_timestamp(&q->curr->vb.ts);
|
||||
wake_up(&q->curr->vb.done);
|
||||
|
||||
q->curr = NULL;
|
||||
}
|
||||
|
||||
void saa7146_buffer_next(struct saa7146_dev *dev,
|
||||
struct saa7146_dmaqueue *q, int vbi)
|
||||
{
|
||||
struct saa7146_buf *buf,*next = NULL;
|
||||
|
||||
BUG_ON(!q);
|
||||
|
||||
DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
|
||||
|
||||
assert_spin_locked(&dev->slock);
|
||||
if (!list_empty(&q->queue)) {
|
||||
/* activate next one from queue */
|
||||
buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue);
|
||||
list_del(&buf->vb.queue);
|
||||
if (!list_empty(&q->queue))
|
||||
next = list_entry(q->queue.next,struct saa7146_buf, vb.queue);
|
||||
q->curr = buf;
|
||||
DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n",
|
||||
buf, q->queue.prev, q->queue.next);
|
||||
buf->activate(dev,buf,next);
|
||||
} else {
|
||||
DEB_INT("no next buffer. stopping.\n");
|
||||
if( 0 != vbi ) {
|
||||
/* turn off video-dma3 */
|
||||
saa7146_write(dev,MC1, MASK_20);
|
||||
} else {
|
||||
/* nothing to do -- just prevent next video-dma1 transfer
|
||||
by lowering the protection address */
|
||||
|
||||
// fixme: fix this for vflip != 0
|
||||
|
||||
saa7146_write(dev, PROT_ADDR1, 0);
|
||||
saa7146_write(dev, MC2, (MASK_02|MASK_18));
|
||||
|
||||
/* write the address of the rps-program */
|
||||
saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
|
||||
/* turn on rps */
|
||||
saa7146_write(dev, MC1, (MASK_12 | MASK_28));
|
||||
|
||||
/*
|
||||
printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
|
||||
printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
|
||||
printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
|
||||
printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
|
||||
printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1));
|
||||
printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
|
||||
*/
|
||||
}
|
||||
del_timer(&q->timeout);
|
||||
}
|
||||
}
|
||||
|
||||
void saa7146_buffer_timeout(unsigned long data)
|
||||
{
|
||||
struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
|
||||
struct saa7146_dev *dev = q->dev;
|
||||
unsigned long flags;
|
||||
|
||||
DEB_EE("dev:%p, dmaq:%p\n", dev, q);
|
||||
|
||||
spin_lock_irqsave(&dev->slock,flags);
|
||||
if (q->curr) {
|
||||
DEB_D("timeout on %p\n", q->curr);
|
||||
saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
|
||||
}
|
||||
|
||||
/* we don't restart the transfer here like other drivers do. when
|
||||
a streaming capture is disabled, the timeout function will be
|
||||
called for the current buffer. if we activate the next buffer now,
|
||||
we mess up our capture logic. if a timeout occurs on another buffer,
|
||||
then something is seriously broken before, so no need to buffer the
|
||||
next capture IMHO... */
|
||||
/*
|
||||
saa7146_buffer_next(dev,q);
|
||||
*/
|
||||
spin_unlock_irqrestore(&dev->slock,flags);
|
||||
}
|
||||
|
||||
/********************************************************************************/
|
||||
/* file operations */
|
||||
|
||||
static int fops_open(struct file *file)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct saa7146_dev *dev = video_drvdata(file);
|
||||
struct saa7146_fh *fh = NULL;
|
||||
int result = 0;
|
||||
|
||||
DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
|
||||
|
||||
if (mutex_lock_interruptible(vdev->lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
DEB_D("using: %p\n", dev);
|
||||
|
||||
/* check if an extension is registered */
|
||||
if( NULL == dev->ext ) {
|
||||
DEB_S("no extension registered for this device\n");
|
||||
result = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* allocate per open data */
|
||||
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
|
||||
if (NULL == fh) {
|
||||
DEB_S("cannot allocate memory for per open data\n");
|
||||
result = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
v4l2_fh_init(&fh->fh, vdev);
|
||||
|
||||
file->private_data = &fh->fh;
|
||||
fh->dev = dev;
|
||||
|
||||
if (vdev->vfl_type == VFL_TYPE_VBI) {
|
||||
DEB_S("initializing vbi...\n");
|
||||
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
|
||||
result = saa7146_vbi_uops.open(dev,file);
|
||||
if (dev->ext_vv_data->vbi_fops.open)
|
||||
dev->ext_vv_data->vbi_fops.open(file);
|
||||
} else {
|
||||
DEB_S("initializing video...\n");
|
||||
result = saa7146_video_uops.open(dev,file);
|
||||
}
|
||||
|
||||
if (0 != result) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if( 0 == try_module_get(dev->ext->module)) {
|
||||
result = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
v4l2_fh_add(&fh->fh);
|
||||
out:
|
||||
if (fh && result != 0) {
|
||||
kfree(fh);
|
||||
file->private_data = NULL;
|
||||
}
|
||||
mutex_unlock(vdev->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int fops_release(struct file *file)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
|
||||
DEB_EE("file:%p\n", file);
|
||||
|
||||
mutex_lock(vdev->lock);
|
||||
|
||||
if (vdev->vfl_type == VFL_TYPE_VBI) {
|
||||
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
|
||||
saa7146_vbi_uops.release(dev,file);
|
||||
if (dev->ext_vv_data->vbi_fops.release)
|
||||
dev->ext_vv_data->vbi_fops.release(file);
|
||||
} else {
|
||||
saa7146_video_uops.release(dev,file);
|
||||
}
|
||||
|
||||
v4l2_fh_del(&fh->fh);
|
||||
v4l2_fh_exit(&fh->fh);
|
||||
module_put(dev->ext->module);
|
||||
file->private_data = NULL;
|
||||
kfree(fh);
|
||||
|
||||
mutex_unlock(vdev->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fops_mmap(struct file *file, struct vm_area_struct * vma)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct videobuf_queue *q;
|
||||
int res;
|
||||
|
||||
switch (vdev->vfl_type) {
|
||||
case VFL_TYPE_GRABBER: {
|
||||
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
|
||||
file, vma);
|
||||
q = &fh->video_q;
|
||||
break;
|
||||
}
|
||||
case VFL_TYPE_VBI: {
|
||||
DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
|
||||
file, vma);
|
||||
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
|
||||
return -ENODEV;
|
||||
q = &fh->vbi_q;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(vdev->lock))
|
||||
return -ERESTARTSYS;
|
||||
res = videobuf_mmap_mapper(q, vma);
|
||||
mutex_unlock(vdev->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int __fops_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct videobuf_buffer *buf = NULL;
|
||||
struct videobuf_queue *q;
|
||||
unsigned int res = v4l2_ctrl_poll(file, wait);
|
||||
|
||||
DEB_EE("file:%p, poll:%p\n", file, wait);
|
||||
|
||||
if (vdev->vfl_type == VFL_TYPE_VBI) {
|
||||
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
|
||||
return res | POLLOUT | POLLWRNORM;
|
||||
if( 0 == fh->vbi_q.streaming )
|
||||
return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
|
||||
q = &fh->vbi_q;
|
||||
} else {
|
||||
DEB_D("using video queue\n");
|
||||
q = &fh->video_q;
|
||||
}
|
||||
|
||||
if (!list_empty(&q->stream))
|
||||
buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
|
||||
|
||||
if (!buf) {
|
||||
DEB_D("buf == NULL!\n");
|
||||
return res | POLLERR;
|
||||
}
|
||||
|
||||
poll_wait(file, &buf->done, wait);
|
||||
if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
|
||||
DEB_D("poll succeeded!\n");
|
||||
return res | POLLIN | POLLRDNORM;
|
||||
}
|
||||
|
||||
DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
unsigned int res;
|
||||
|
||||
mutex_lock(vdev->lock);
|
||||
res = __fops_poll(file, wait);
|
||||
mutex_unlock(vdev->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
int ret;
|
||||
|
||||
switch (vdev->vfl_type) {
|
||||
case VFL_TYPE_GRABBER:
|
||||
/*
|
||||
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
|
||||
file, data, (unsigned long)count);
|
||||
*/
|
||||
return saa7146_video_uops.read(file,data,count,ppos);
|
||||
case VFL_TYPE_VBI:
|
||||
/*
|
||||
DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
|
||||
file, data, (unsigned long)count);
|
||||
*/
|
||||
if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
|
||||
if (mutex_lock_interruptible(vdev->lock))
|
||||
return -ERESTARTSYS;
|
||||
ret = saa7146_vbi_uops.read(file, data, count, ppos);
|
||||
mutex_unlock(vdev->lock);
|
||||
return ret;
|
||||
}
|
||||
return -EINVAL;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
int ret;
|
||||
|
||||
switch (vdev->vfl_type) {
|
||||
case VFL_TYPE_GRABBER:
|
||||
return -EINVAL;
|
||||
case VFL_TYPE_VBI:
|
||||
if (fh->dev->ext_vv_data->vbi_fops.write) {
|
||||
if (mutex_lock_interruptible(vdev->lock))
|
||||
return -ERESTARTSYS;
|
||||
ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
|
||||
mutex_unlock(vdev->lock);
|
||||
return ret;
|
||||
}
|
||||
return -EINVAL;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static const struct v4l2_file_operations video_fops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.open = fops_open,
|
||||
.release = fops_release,
|
||||
.read = fops_read,
|
||||
.write = fops_write,
|
||||
.poll = fops_poll,
|
||||
.mmap = fops_mmap,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
|
||||
{
|
||||
u32 isr = status;
|
||||
|
||||
DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
|
||||
|
||||
if (0 != (isr & (MASK_27))) {
|
||||
DEB_INT("irq: RPS0 (0x%08x)\n", isr);
|
||||
saa7146_video_uops.irq_done(dev,isr);
|
||||
}
|
||||
|
||||
if (0 != (isr & (MASK_28))) {
|
||||
u32 mc2 = saa7146_read(dev, MC2);
|
||||
if( 0 != (mc2 & MASK_15)) {
|
||||
DEB_INT("irq: RPS1 vbi workaround (0x%08x)\n", isr);
|
||||
wake_up(&dev->vv_data->vbi_wq);
|
||||
saa7146_write(dev,MC2, MASK_31);
|
||||
return;
|
||||
}
|
||||
DEB_INT("irq: RPS1 (0x%08x)\n", isr);
|
||||
saa7146_vbi_uops.irq_done(dev,isr);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
|
||||
.s_ctrl = saa7146_s_ctrl,
|
||||
};
|
||||
|
||||
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
|
||||
{
|
||||
struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
|
||||
struct v4l2_pix_format *fmt;
|
||||
struct v4l2_vbi_format *vbi;
|
||||
struct saa7146_vv *vv;
|
||||
int err;
|
||||
|
||||
err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
v4l2_ctrl_handler_init(hdl, 6);
|
||||
v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
|
||||
v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
|
||||
V4L2_CID_CONTRAST, 0, 127, 1, 64);
|
||||
v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
|
||||
V4L2_CID_SATURATION, 0, 127, 1, 64);
|
||||
v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
|
||||
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
||||
v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
|
||||
V4L2_CID_HFLIP, 0, 1, 1, 0);
|
||||
if (hdl->error) {
|
||||
err = hdl->error;
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
return err;
|
||||
}
|
||||
dev->v4l2_dev.ctrl_handler = hdl;
|
||||
|
||||
vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
|
||||
if (vv == NULL) {
|
||||
ERR("out of memory. aborting.\n");
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ext_vv->vid_ops = saa7146_video_ioctl_ops;
|
||||
ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
|
||||
ext_vv->core_ops = &saa7146_video_ioctl_ops;
|
||||
|
||||
DEB_EE("dev:%p\n", dev);
|
||||
|
||||
/* set default values for video parts of the saa7146 */
|
||||
saa7146_write(dev, BCS_CTRL, 0x80400040);
|
||||
|
||||
/* enable video-port pins */
|
||||
saa7146_write(dev, MC1, (MASK_10 | MASK_26));
|
||||
|
||||
/* save per-device extension data (one extension can
|
||||
handle different devices that might need different
|
||||
configuration data) */
|
||||
dev->ext_vv_data = ext_vv;
|
||||
|
||||
vv->d_clipping.cpu_addr =
|
||||
pci_zalloc_consistent(dev->pci, SAA7146_CLIPPING_MEM,
|
||||
&vv->d_clipping.dma_handle);
|
||||
if( NULL == vv->d_clipping.cpu_addr ) {
|
||||
ERR("out of memory. aborting.\n");
|
||||
kfree(vv);
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
saa7146_video_uops.init(dev,vv);
|
||||
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
|
||||
saa7146_vbi_uops.init(dev,vv);
|
||||
|
||||
vv->ov_fb.fmt.width = vv->standard->h_max_out;
|
||||
vv->ov_fb.fmt.height = vv->standard->v_max_out;
|
||||
vv->ov_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
|
||||
vv->ov_fb.fmt.bytesperline = 2 * vv->ov_fb.fmt.width;
|
||||
vv->ov_fb.fmt.sizeimage = vv->ov_fb.fmt.bytesperline * vv->ov_fb.fmt.height;
|
||||
vv->ov_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
|
||||
fmt = &vv->video_fmt;
|
||||
fmt->width = 384;
|
||||
fmt->height = 288;
|
||||
fmt->pixelformat = V4L2_PIX_FMT_BGR24;
|
||||
fmt->field = V4L2_FIELD_ANY;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
fmt->bytesperline = 3 * fmt->width;
|
||||
fmt->sizeimage = fmt->bytesperline * fmt->height;
|
||||
|
||||
vbi = &vv->vbi_fmt;
|
||||
vbi->sampling_rate = 27000000;
|
||||
vbi->offset = 248; /* todo */
|
||||
vbi->samples_per_line = 720 * 2;
|
||||
vbi->sample_format = V4L2_PIX_FMT_GREY;
|
||||
|
||||
/* fixme: this only works for PAL */
|
||||
vbi->start[0] = 5;
|
||||
vbi->count[0] = 16;
|
||||
vbi->start[1] = 312;
|
||||
vbi->count[1] = 16;
|
||||
|
||||
init_timer(&vv->vbi_read_timeout);
|
||||
|
||||
vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
|
||||
vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
|
||||
dev->vv_data = vv;
|
||||
dev->vv_callback = &vv_callback;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(saa7146_vv_init);
|
||||
|
||||
int saa7146_vv_release(struct saa7146_dev* dev)
|
||||
{
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
|
||||
DEB_EE("dev:%p\n", dev);
|
||||
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
|
||||
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
||||
kfree(vv);
|
||||
dev->vv_data = NULL;
|
||||
dev->vv_callback = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(saa7146_vv_release);
|
||||
|
||||
int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
|
||||
char *name, int type)
|
||||
{
|
||||
struct video_device *vfd;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
|
||||
|
||||
// released by vfd->release
|
||||
vfd = video_device_alloc();
|
||||
if (vfd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
vfd->fops = &video_fops;
|
||||
if (type == VFL_TYPE_GRABBER)
|
||||
vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
|
||||
else
|
||||
vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
|
||||
vfd->release = video_device_release;
|
||||
vfd->lock = &dev->v4l2_lock;
|
||||
vfd->v4l2_dev = &dev->v4l2_dev;
|
||||
vfd->tvnorms = 0;
|
||||
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
|
||||
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
|
||||
strlcpy(vfd->name, name, sizeof(vfd->name));
|
||||
video_set_drvdata(vfd, dev);
|
||||
|
||||
err = video_register_device(vfd, type, -1);
|
||||
if (err < 0) {
|
||||
ERR("cannot register v4l2 device. skipping.\n");
|
||||
video_device_release(vfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
pr_info("%s: registered device %s [v4l2]\n",
|
||||
dev->name, video_device_node_name(vfd));
|
||||
|
||||
*vid = vfd;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(saa7146_register_device);
|
||||
|
||||
int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
|
||||
{
|
||||
DEB_EE("dev:%p\n", dev);
|
||||
|
||||
video_unregister_device(*vid);
|
||||
*vid = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(saa7146_unregister_device);
|
||||
|
||||
static int __init saa7146_vv_init_module(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit saa7146_vv_cleanup_module(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(saa7146_vv_init_module);
|
||||
module_exit(saa7146_vv_cleanup_module);
|
||||
|
||||
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
|
||||
MODULE_DESCRIPTION("video4linux driver for saa7146-based hardware");
|
||||
MODULE_LICENSE("GPL");
|
||||
1048
drivers/media/common/saa7146/saa7146_hlp.c
Normal file
1048
drivers/media/common/saa7146/saa7146_hlp.c
Normal file
File diff suppressed because it is too large
Load diff
423
drivers/media/common/saa7146/saa7146_i2c.c
Normal file
423
drivers/media/common/saa7146/saa7146_i2c.c
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <media/saa7146_vv.h>
|
||||
|
||||
static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
/* DEB_I2C("'%s'\n", adapter->name); */
|
||||
|
||||
return I2C_FUNC_I2C
|
||||
| I2C_FUNC_SMBUS_QUICK
|
||||
| I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE
|
||||
| I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
|
||||
}
|
||||
|
||||
/* this function returns the status-register of our i2c-device */
|
||||
static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
|
||||
{
|
||||
u32 iicsta = saa7146_read(dev, I2C_STATUS);
|
||||
/* DEB_I2C("status: 0x%08x\n", iicsta); */
|
||||
return iicsta;
|
||||
}
|
||||
|
||||
/* this function runs through the i2c-messages and prepares the data to be
|
||||
sent through the saa7146. have a look at the specifications p. 122 ff
|
||||
to understand this. it returns the number of u32s to send, or -1
|
||||
in case of an error. */
|
||||
static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
|
||||
{
|
||||
int h1, h2;
|
||||
int i, j, addr;
|
||||
int mem = 0, op_count = 0;
|
||||
|
||||
/* first determine size of needed memory */
|
||||
for(i = 0; i < num; i++) {
|
||||
mem += m[i].len + 1;
|
||||
}
|
||||
|
||||
/* worst case: we need one u32 for three bytes to be send
|
||||
plus one extra byte to address the device */
|
||||
mem = 1 + ((mem-1) / 3);
|
||||
|
||||
/* we assume that op points to a memory of at least
|
||||
* SAA7146_I2C_MEM bytes size. if we exceed this limit...
|
||||
*/
|
||||
if ((4 * mem) > SAA7146_I2C_MEM) {
|
||||
/* DEB_I2C("cannot prepare i2c-message\n"); */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* be careful: clear out the i2c-mem first */
|
||||
memset(op,0,sizeof(__le32)*mem);
|
||||
|
||||
/* loop through all messages */
|
||||
for(i = 0; i < num; i++) {
|
||||
|
||||
/* insert the address of the i2c-slave.
|
||||
note: we get 7 bit i2c-addresses,
|
||||
so we have to perform a translation */
|
||||
addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0);
|
||||
h1 = op_count/3; h2 = op_count%3;
|
||||
op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8));
|
||||
op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2));
|
||||
op_count++;
|
||||
|
||||
/* loop through all bytes of message i */
|
||||
for(j = 0; j < m[i].len; j++) {
|
||||
/* insert the data bytes */
|
||||
h1 = op_count/3; h2 = op_count%3;
|
||||
op[h1] |= cpu_to_le32( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
|
||||
op[h1] |= cpu_to_le32( SAA7146_I2C_CONT << ((3-h2)*2));
|
||||
op_count++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* have a look at the last byte inserted:
|
||||
if it was: ...CONT change it to ...STOP */
|
||||
h1 = (op_count-1)/3; h2 = (op_count-1)%3;
|
||||
if ( SAA7146_I2C_CONT == (0x3 & (le32_to_cpu(op[h1]) >> ((3-h2)*2))) ) {
|
||||
op[h1] &= ~cpu_to_le32(0x2 << ((3-h2)*2));
|
||||
op[h1] |= cpu_to_le32(SAA7146_I2C_STOP << ((3-h2)*2));
|
||||
}
|
||||
|
||||
/* return the number of u32s to send */
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* this functions loops through all i2c-messages. normally, it should determine
|
||||
which bytes were read through the adapter and write them back to the corresponding
|
||||
i2c-message. but instead, we simply write back all bytes.
|
||||
fixme: this could be improved. */
|
||||
static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
|
||||
{
|
||||
int i, j;
|
||||
int op_count = 0;
|
||||
|
||||
/* loop through all messages */
|
||||
for(i = 0; i < num; i++) {
|
||||
|
||||
op_count++;
|
||||
|
||||
/* loop through all bytes of message i */
|
||||
for(j = 0; j < m[i].len; j++) {
|
||||
/* write back all bytes that could have been read */
|
||||
m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
|
||||
op_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this functions resets the i2c-device and returns 0 if everything was fine, otherwise -1 */
|
||||
static int saa7146_i2c_reset(struct saa7146_dev *dev)
|
||||
{
|
||||
/* get current status */
|
||||
u32 status = saa7146_i2c_status(dev);
|
||||
|
||||
/* clear registers for sure */
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, I2C_TRANSFER, 0);
|
||||
|
||||
/* check if any operation is still in progress */
|
||||
if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
|
||||
|
||||
/* yes, kill ongoing operation */
|
||||
DEB_I2C("busy_state detected\n");
|
||||
|
||||
/* set "ABORT-OPERATION"-bit (bit 7)*/
|
||||
saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
msleep(SAA7146_I2C_DELAY);
|
||||
|
||||
/* clear all error-bits pending; this is needed because p.123, note 1 */
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
msleep(SAA7146_I2C_DELAY);
|
||||
}
|
||||
|
||||
/* check if any error is (still) present. (this can be necessary because p.123, note 1) */
|
||||
status = saa7146_i2c_status(dev);
|
||||
|
||||
if ( dev->i2c_bitrate != status ) {
|
||||
|
||||
DEB_I2C("error_state detected. status:0x%08x\n", status);
|
||||
|
||||
/* Repeat the abort operation. This seems to be necessary
|
||||
after serious protocol errors caused by e.g. the SAA7740 */
|
||||
saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
msleep(SAA7146_I2C_DELAY);
|
||||
|
||||
/* clear all error-bits pending */
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
msleep(SAA7146_I2C_DELAY);
|
||||
|
||||
/* the data sheet says it might be necessary to clear the status
|
||||
twice after an abort */
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
msleep(SAA7146_I2C_DELAY);
|
||||
}
|
||||
|
||||
/* if any error is still present, a fatal error has occurred ... */
|
||||
status = saa7146_i2c_status(dev);
|
||||
if ( dev->i2c_bitrate != status ) {
|
||||
DEB_I2C("fatal error. status:0x%08x\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this functions writes out the data-byte 'dword' to the i2c-device.
|
||||
it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
|
||||
failed badly (e.g. address error) */
|
||||
static int saa7146_i2c_writeout(struct saa7146_dev *dev, __le32 *dword, int short_delay)
|
||||
{
|
||||
u32 status = 0, mc2 = 0;
|
||||
int trial = 0;
|
||||
unsigned long timeout;
|
||||
|
||||
/* write out i2c-command */
|
||||
DEB_I2C("before: 0x%08x (status: 0x%08x), %d\n",
|
||||
*dword, saa7146_read(dev, I2C_STATUS), dev->i2c_op);
|
||||
|
||||
if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
|
||||
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
|
||||
|
||||
dev->i2c_op = 1;
|
||||
SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
|
||||
SAA7146_IER_ENABLE(dev, MASK_16|MASK_17);
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
|
||||
timeout = HZ/100 + 1; /* 10ms */
|
||||
timeout = wait_event_interruptible_timeout(dev->i2c_wq, dev->i2c_op == 0, timeout);
|
||||
if (timeout == -ERESTARTSYS || dev->i2c_op) {
|
||||
SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
|
||||
SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
|
||||
if (timeout == -ERESTARTSYS)
|
||||
/* a signal arrived */
|
||||
return -ERESTARTSYS;
|
||||
|
||||
pr_warn("%s %s [irq]: timed out waiting for end of xfer\n",
|
||||
dev->name, __func__);
|
||||
return -EIO;
|
||||
}
|
||||
status = saa7146_read(dev, I2C_STATUS);
|
||||
} else {
|
||||
saa7146_write(dev, I2C_STATUS, dev->i2c_bitrate);
|
||||
saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
|
||||
saa7146_write(dev, MC2, (MASK_00 | MASK_16));
|
||||
|
||||
/* do not poll for i2c-status before upload is complete */
|
||||
timeout = jiffies + HZ/100 + 1; /* 10ms */
|
||||
while(1) {
|
||||
mc2 = (saa7146_read(dev, MC2) & 0x1);
|
||||
if( 0 != mc2 ) {
|
||||
break;
|
||||
}
|
||||
if (time_after(jiffies,timeout)) {
|
||||
pr_warn("%s %s: timed out waiting for MC2\n",
|
||||
dev->name, __func__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
/* wait until we get a transfer done or error */
|
||||
timeout = jiffies + HZ/100 + 1; /* 10ms */
|
||||
/* first read usually delivers bogus results... */
|
||||
saa7146_i2c_status(dev);
|
||||
while(1) {
|
||||
status = saa7146_i2c_status(dev);
|
||||
if ((status & 0x3) != 1)
|
||||
break;
|
||||
if (time_after(jiffies,timeout)) {
|
||||
/* this is normal when probing the bus
|
||||
* (no answer from nonexisistant device...)
|
||||
*/
|
||||
pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
|
||||
dev->name, __func__);
|
||||
return -EIO;
|
||||
}
|
||||
if (++trial < 50 && short_delay)
|
||||
udelay(10);
|
||||
else
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* give a detailed status report */
|
||||
if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
|
||||
SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
|
||||
SAA7146_I2C_AL | SAA7146_I2C_ERR |
|
||||
SAA7146_I2C_BUSY)) ) {
|
||||
|
||||
if ( 0 == (status & SAA7146_I2C_ERR) ||
|
||||
0 == (status & SAA7146_I2C_BUSY) ) {
|
||||
/* it may take some time until ERR goes high - ignore */
|
||||
DEB_I2C("unexpected i2c status %04x\n", status);
|
||||
}
|
||||
if( 0 != (status & SAA7146_I2C_SPERR) ) {
|
||||
DEB_I2C("error due to invalid start/stop condition\n");
|
||||
}
|
||||
if( 0 != (status & SAA7146_I2C_DTERR) ) {
|
||||
DEB_I2C("error in data transmission\n");
|
||||
}
|
||||
if( 0 != (status & SAA7146_I2C_DRERR) ) {
|
||||
DEB_I2C("error when receiving data\n");
|
||||
}
|
||||
if( 0 != (status & SAA7146_I2C_AL) ) {
|
||||
DEB_I2C("error because arbitration lost\n");
|
||||
}
|
||||
|
||||
/* we handle address-errors here */
|
||||
if( 0 != (status & SAA7146_I2C_APERR) ) {
|
||||
DEB_I2C("error in address phase\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* read back data, just in case we were reading ... */
|
||||
*dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
|
||||
|
||||
DEB_I2C("after: 0x%08x\n", *dword);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
|
||||
{
|
||||
int i = 0, count = 0;
|
||||
__le32 *buffer = dev->d_i2c.cpu_addr;
|
||||
int err = 0;
|
||||
int short_delay = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&dev->i2c_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
for(i=0;i<num;i++) {
|
||||
DEB_I2C("msg:%d/%d\n", i+1, num);
|
||||
}
|
||||
|
||||
/* prepare the message(s), get number of u32s to transfer */
|
||||
count = saa7146_i2c_msg_prepare(msgs, num, buffer);
|
||||
if ( 0 > count ) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( count > 3 || 0 != (SAA7146_I2C_SHORT_DELAY & dev->ext->flags) )
|
||||
short_delay = 1;
|
||||
|
||||
do {
|
||||
/* reset the i2c-device if necessary */
|
||||
err = saa7146_i2c_reset(dev);
|
||||
if ( 0 > err ) {
|
||||
DEB_I2C("could not reset i2c-device\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write out the u32s one after another */
|
||||
for(i = 0; i < count; i++) {
|
||||
err = saa7146_i2c_writeout(dev, &buffer[i], short_delay);
|
||||
if ( 0 != err) {
|
||||
/* this one is unsatisfying: some i2c slaves on some
|
||||
dvb cards don't acknowledge correctly, so the saa7146
|
||||
thinks that an address error occurred. in that case, the
|
||||
transaction should be retrying, even if an address error
|
||||
occurred. analog saa7146 based cards extensively rely on
|
||||
i2c address probing, however, and address errors indicate that a
|
||||
device is really *not* there. retrying in that case
|
||||
increases the time the device needs to probe greatly, so
|
||||
it should be avoided. So we bail out in irq mode after an
|
||||
address error and trust the saa7146 address error detection. */
|
||||
if (-EREMOTEIO == err && 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags))
|
||||
goto out;
|
||||
DEB_I2C("error while sending message(s). starting again\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( 0 == err ) {
|
||||
err = num;
|
||||
break;
|
||||
}
|
||||
|
||||
/* delay a bit before retrying */
|
||||
msleep(10);
|
||||
|
||||
} while (err != num && retries--);
|
||||
|
||||
/* quit if any error occurred */
|
||||
if (err != num)
|
||||
goto out;
|
||||
|
||||
/* if any things had to be read, get the results */
|
||||
if ( 0 != saa7146_i2c_msg_cleanup(msgs, num, buffer)) {
|
||||
DEB_I2C("could not cleanup i2c-message\n");
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* return the number of delivered messages */
|
||||
DEB_I2C("transmission successful. (msg:%d)\n", err);
|
||||
out:
|
||||
/* another bug in revision 0: the i2c-registers get uploaded randomly by other
|
||||
uploads, so we better clear them out before continuing */
|
||||
if( 0 == dev->revision ) {
|
||||
__le32 zero = 0;
|
||||
saa7146_i2c_reset(dev);
|
||||
if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
|
||||
pr_info("revision 0 error. this should never happen\n");
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->i2c_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* utility functions */
|
||||
static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
|
||||
{
|
||||
struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
|
||||
struct saa7146_dev *dev = to_saa7146_dev(v4l2_dev);
|
||||
|
||||
/* use helper function to transfer data */
|
||||
return saa7146_i2c_transfer(dev, msg, num, adapter->retries);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* i2c-adapter helper functions */
|
||||
|
||||
/* exported algorithm data */
|
||||
static struct i2c_algorithm saa7146_algo = {
|
||||
.master_xfer = saa7146_i2c_xfer,
|
||||
.functionality = saa7146_i2c_func,
|
||||
};
|
||||
|
||||
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
|
||||
{
|
||||
DEB_EE("bitrate: 0x%08x\n", bitrate);
|
||||
|
||||
/* enable i2c-port pins */
|
||||
saa7146_write(dev, MC1, (MASK_08 | MASK_24));
|
||||
|
||||
dev->i2c_bitrate = bitrate;
|
||||
saa7146_i2c_reset(dev);
|
||||
|
||||
if (i2c_adapter) {
|
||||
i2c_set_adapdata(i2c_adapter, &dev->v4l2_dev);
|
||||
i2c_adapter->dev.parent = &dev->pci->dev;
|
||||
i2c_adapter->algo = &saa7146_algo;
|
||||
i2c_adapter->algo_data = NULL;
|
||||
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
|
||||
i2c_adapter->retries = SAA7146_I2C_RETRIES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
498
drivers/media/common/saa7146/saa7146_vbi.c
Normal file
498
drivers/media/common/saa7146/saa7146_vbi.c
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
#include <media/saa7146_vv.h>
|
||||
|
||||
static int vbi_pixel_to_capture = 720 * 2;
|
||||
|
||||
static int vbi_workaround(struct saa7146_dev *dev)
|
||||
{
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
|
||||
u32 *cpu;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
DEB_VBI("dev:%p\n", dev);
|
||||
|
||||
/* once again, a bug in the saa7146: the brs acquisition
|
||||
is buggy and especially the BXO-counter does not work
|
||||
as specified. there is this workaround, but please
|
||||
don't let me explain it. ;-) */
|
||||
|
||||
cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr);
|
||||
if (NULL == cpu)
|
||||
return -ENOMEM;
|
||||
|
||||
/* setup some basic programming, just for the workaround */
|
||||
saa7146_write(dev, BASE_EVEN3, dma_addr);
|
||||
saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture);
|
||||
saa7146_write(dev, PROT_ADDR3, dma_addr+4096);
|
||||
saa7146_write(dev, PITCH3, vbi_pixel_to_capture);
|
||||
saa7146_write(dev, BASE_PAGE3, 0x0);
|
||||
saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
|
||||
saa7146_write(dev, MC2, MASK_04|MASK_20);
|
||||
|
||||
/* load brs-control register */
|
||||
WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
|
||||
/* BXO = 1h, BRS to outbound */
|
||||
WRITE_RPS1(0xc000008c);
|
||||
/* wait for vbi_a or vbi_b*/
|
||||
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
|
||||
DEB_D("...using port b\n");
|
||||
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
|
||||
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
|
||||
/*
|
||||
WRITE_RPS1(CMD_PAUSE | MASK_09);
|
||||
*/
|
||||
} else {
|
||||
DEB_D("...using port a\n");
|
||||
WRITE_RPS1(CMD_PAUSE | MASK_10);
|
||||
}
|
||||
/* upload brs */
|
||||
WRITE_RPS1(CMD_UPLOAD | MASK_08);
|
||||
/* load brs-control register */
|
||||
WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
|
||||
/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
|
||||
WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
|
||||
/* wait for brs_done */
|
||||
WRITE_RPS1(CMD_PAUSE | MASK_08);
|
||||
/* upload brs */
|
||||
WRITE_RPS1(CMD_UPLOAD | MASK_08);
|
||||
/* load video-dma3 NumLines3 and NumBytes3 */
|
||||
WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
|
||||
/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
|
||||
WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
|
||||
/* load brs-control register */
|
||||
WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
|
||||
/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
|
||||
WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start
|
||||
/* wait for brs_done */
|
||||
WRITE_RPS1(CMD_PAUSE | MASK_08);
|
||||
/* upload brs and video-dma3*/
|
||||
WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
|
||||
/* load mc2 register: enable dma3 */
|
||||
WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
|
||||
WRITE_RPS1(MASK_20 | MASK_04);
|
||||
/* generate interrupt */
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
/* stop rps1 */
|
||||
WRITE_RPS1(CMD_STOP);
|
||||
|
||||
/* we have to do the workaround twice to be sure that
|
||||
everything is ok */
|
||||
for(i = 0; i < 2; i++) {
|
||||
|
||||
/* indicate to the irq handler that we do the workaround */
|
||||
saa7146_write(dev, MC2, MASK_31|MASK_15);
|
||||
|
||||
saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
|
||||
saa7146_write(dev, MC2, MASK_04|MASK_20);
|
||||
|
||||
/* enable rps1 irqs */
|
||||
SAA7146_IER_ENABLE(dev,MASK_28);
|
||||
|
||||
/* prepare to wait to be woken up by the irq-handler */
|
||||
add_wait_queue(&vv->vbi_wq, &wait);
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
|
||||
/* start rps1 to enable workaround */
|
||||
saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
|
||||
saa7146_write(dev, MC1, (MASK_13 | MASK_29));
|
||||
|
||||
schedule();
|
||||
|
||||
DEB_VBI("brs bug workaround %d/1\n", i);
|
||||
|
||||
remove_wait_queue(&vv->vbi_wq, &wait);
|
||||
current->state = TASK_RUNNING;
|
||||
|
||||
/* disable rps1 irqs */
|
||||
SAA7146_IER_DISABLE(dev,MASK_28);
|
||||
|
||||
/* stop video-dma3 */
|
||||
saa7146_write(dev, MC1, MASK_20);
|
||||
|
||||
if(signal_pending(current)) {
|
||||
|
||||
DEB_VBI("aborted (rps:0x%08x)\n",
|
||||
saa7146_read(dev, RPS_ADDR1));
|
||||
|
||||
/* stop rps1 for sure */
|
||||
saa7146_write(dev, MC1, MASK_29);
|
||||
|
||||
pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
|
||||
pci_free_consistent(dev->pci, 4096, cpu, dma_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
|
||||
{
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
|
||||
struct saa7146_video_dma vdma3;
|
||||
|
||||
int count = 0;
|
||||
unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
|
||||
unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
|
||||
|
||||
/*
|
||||
vdma3.base_even = 0xc8000000+2560*70;
|
||||
vdma3.base_odd = 0xc8000000;
|
||||
vdma3.prot_addr = 0xc8000000+2560*164;
|
||||
vdma3.pitch = 2560;
|
||||
vdma3.base_page = 0;
|
||||
vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
|
||||
*/
|
||||
vdma3.base_even = buf->pt[2].offset;
|
||||
vdma3.base_odd = buf->pt[2].offset + 16 * vbi_pixel_to_capture;
|
||||
vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;
|
||||
vdma3.pitch = vbi_pixel_to_capture;
|
||||
vdma3.base_page = buf->pt[2].dma | ME1;
|
||||
vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;
|
||||
|
||||
saa7146_write_out_dma(dev, 3, &vdma3);
|
||||
|
||||
/* write beginning of rps-program */
|
||||
count = 0;
|
||||
|
||||
/* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */
|
||||
|
||||
/* we don't wait here for the first field anymore. this is different from the video
|
||||
capture and might cause that the first buffer is only half filled (with only
|
||||
one field). but since this is some sort of streaming data, this is not that negative.
|
||||
but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
|
||||
|
||||
/*
|
||||
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
|
||||
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
|
||||
*/
|
||||
/* set bit 1 */
|
||||
WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
|
||||
WRITE_RPS1(MASK_28 | MASK_12);
|
||||
|
||||
/* turn on video-dma3 */
|
||||
WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
|
||||
WRITE_RPS1(MASK_04 | MASK_20); /* => mask */
|
||||
WRITE_RPS1(MASK_04 | MASK_20); /* => values */
|
||||
|
||||
/* wait for o_fid_a/b / e_fid_a/b toggle */
|
||||
WRITE_RPS1(CMD_PAUSE | o_wait);
|
||||
WRITE_RPS1(CMD_PAUSE | e_wait);
|
||||
|
||||
/* generate interrupt */
|
||||
WRITE_RPS1(CMD_INTERRUPT);
|
||||
|
||||
/* stop */
|
||||
WRITE_RPS1(CMD_STOP);
|
||||
|
||||
/* enable rps1 irqs */
|
||||
SAA7146_IER_ENABLE(dev, MASK_28);
|
||||
|
||||
/* write the address of the rps-program */
|
||||
saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
|
||||
|
||||
/* turn on rps */
|
||||
saa7146_write(dev, MC1, (MASK_13 | MASK_29));
|
||||
}
|
||||
|
||||
static int buffer_activate(struct saa7146_dev *dev,
|
||||
struct saa7146_buf *buf,
|
||||
struct saa7146_buf *next)
|
||||
{
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
|
||||
DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
|
||||
saa7146_set_vbi_capture(dev,buf,next);
|
||||
|
||||
mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field)
|
||||
{
|
||||
struct file *file = q->priv_data;
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
|
||||
|
||||
int err = 0;
|
||||
int lines, llength, size;
|
||||
|
||||
lines = 16 * 2 ; /* 2 fields */
|
||||
llength = vbi_pixel_to_capture;
|
||||
size = lines * llength;
|
||||
|
||||
DEB_VBI("vb:%p\n", vb);
|
||||
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < size) {
|
||||
DEB_VBI("size mismatch\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (buf->vb.size != size)
|
||||
saa7146_dma_free(dev,q,buf);
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
|
||||
buf->vb.width = llength;
|
||||
buf->vb.height = lines;
|
||||
buf->vb.size = size;
|
||||
buf->vb.field = field; // FIXME: check this
|
||||
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[2]);
|
||||
saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
|
||||
|
||||
err = videobuf_iolock(q,&buf->vb, NULL);
|
||||
if (err)
|
||||
goto oops;
|
||||
err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
|
||||
dma->sglist, dma->sglen);
|
||||
if (0 != err)
|
||||
return err;
|
||||
}
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
buf->activate = buffer_activate;
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
DEB_VBI("error out\n");
|
||||
saa7146_dma_free(dev,q,buf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
|
||||
{
|
||||
int llength,lines;
|
||||
|
||||
lines = 16 * 2 ; /* 2 fields */
|
||||
llength = vbi_pixel_to_capture;
|
||||
|
||||
*size = lines * llength;
|
||||
*count = 2;
|
||||
|
||||
DEB_VBI("count:%d, size:%d\n", *count, *size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct file *file = q->priv_data;
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
|
||||
|
||||
DEB_VBI("vb:%p\n", vb);
|
||||
saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
|
||||
}
|
||||
|
||||
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct file *file = q->priv_data;
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
|
||||
|
||||
DEB_VBI("vb:%p\n", vb);
|
||||
saa7146_dma_free(dev,q,buf);
|
||||
}
|
||||
|
||||
static struct videobuf_queue_ops vbi_qops = {
|
||||
.buf_setup = buffer_setup,
|
||||
.buf_prepare = buffer_prepare,
|
||||
.buf_queue = buffer_queue,
|
||||
.buf_release = buffer_release,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void vbi_stop(struct saa7146_fh *fh, struct file *file)
|
||||
{
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
unsigned long flags;
|
||||
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
|
||||
|
||||
spin_lock_irqsave(&dev->slock,flags);
|
||||
|
||||
/* disable rps1 */
|
||||
saa7146_write(dev, MC1, MASK_29);
|
||||
|
||||
/* disable rps1 irqs */
|
||||
SAA7146_IER_DISABLE(dev, MASK_28);
|
||||
|
||||
/* shut down dma 3 transfers */
|
||||
saa7146_write(dev, MC1, MASK_20);
|
||||
|
||||
if (vv->vbi_dmaq.curr)
|
||||
saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
|
||||
|
||||
videobuf_queue_cancel(&fh->vbi_q);
|
||||
|
||||
vv->vbi_streaming = NULL;
|
||||
|
||||
del_timer(&vv->vbi_dmaq.timeout);
|
||||
del_timer(&vv->vbi_read_timeout);
|
||||
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
}
|
||||
|
||||
static void vbi_read_timeout(unsigned long data)
|
||||
{
|
||||
struct file *file = (struct file*)data;
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
|
||||
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
|
||||
|
||||
vbi_stop(fh, file);
|
||||
}
|
||||
|
||||
static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
|
||||
{
|
||||
DEB_VBI("dev:%p\n", dev);
|
||||
|
||||
INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
|
||||
|
||||
init_timer(&vv->vbi_dmaq.timeout);
|
||||
vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout;
|
||||
vv->vbi_dmaq.timeout.data = (unsigned long)(&vv->vbi_dmaq);
|
||||
vv->vbi_dmaq.dev = dev;
|
||||
|
||||
init_waitqueue_head(&vv->vbi_wq);
|
||||
}
|
||||
|
||||
static int vbi_open(struct saa7146_dev *dev, struct file *file)
|
||||
{
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_vv *vv = fh->dev->vv_data;
|
||||
|
||||
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
|
||||
int ret = 0;
|
||||
|
||||
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
|
||||
|
||||
ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);
|
||||
if (0 == ret) {
|
||||
DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* adjust arbitrition control for video dma 3 */
|
||||
arbtr_ctrl &= ~0x1f0000;
|
||||
arbtr_ctrl |= 0x1d0000;
|
||||
saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
|
||||
saa7146_write(dev, MC2, (MASK_04|MASK_20));
|
||||
|
||||
videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
|
||||
&dev->pci->dev, &dev->slock,
|
||||
V4L2_BUF_TYPE_VBI_CAPTURE,
|
||||
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
|
||||
sizeof(struct saa7146_buf),
|
||||
file, &dev->v4l2_lock);
|
||||
|
||||
vv->vbi_read_timeout.function = vbi_read_timeout;
|
||||
vv->vbi_read_timeout.data = (unsigned long)file;
|
||||
|
||||
/* initialize the brs */
|
||||
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
|
||||
saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
|
||||
} else {
|
||||
saa7146_write(dev, BRS_CTRL, 0x00000001);
|
||||
|
||||
if (0 != (ret = vbi_workaround(dev))) {
|
||||
DEB_VBI("vbi workaround failed!\n");
|
||||
/* return ret;*/
|
||||
}
|
||||
}
|
||||
|
||||
/* upload brs register */
|
||||
saa7146_write(dev, MC2, (MASK_08|MASK_24));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vbi_close(struct saa7146_dev *dev, struct file *file)
|
||||
{
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
|
||||
|
||||
if( fh == vv->vbi_streaming ) {
|
||||
vbi_stop(fh, file);
|
||||
}
|
||||
saa7146_res_free(fh, RESOURCE_DMA3_BRS);
|
||||
}
|
||||
|
||||
static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
|
||||
{
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
spin_lock(&dev->slock);
|
||||
|
||||
if (vv->vbi_dmaq.curr) {
|
||||
DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
|
||||
/* this must be += 2, one count for each field */
|
||||
vv->vbi_fieldcount+=2;
|
||||
vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
|
||||
saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
|
||||
} else {
|
||||
DEB_VBI("dev:%p\n", dev);
|
||||
}
|
||||
saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
|
||||
|
||||
spin_unlock(&dev->slock);
|
||||
}
|
||||
|
||||
static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
struct saa7146_vv *vv = dev->vv_data;
|
||||
ssize_t ret = 0;
|
||||
|
||||
DEB_VBI("dev:%p, fh:%p\n", dev, fh);
|
||||
|
||||
if( NULL == vv->vbi_streaming ) {
|
||||
// fixme: check if dma3 is available
|
||||
// fixme: activate vbi engine here if necessary. (really?)
|
||||
vv->vbi_streaming = fh;
|
||||
}
|
||||
|
||||
if( fh != vv->vbi_streaming ) {
|
||||
DEB_VBI("open %p is already using vbi capture\n",
|
||||
vv->vbi_streaming);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
|
||||
ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
|
||||
file->f_flags & O_NONBLOCK);
|
||||
/*
|
||||
printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3));
|
||||
printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3));
|
||||
printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3));
|
||||
printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3));
|
||||
printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3));
|
||||
printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));
|
||||
printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL));
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct saa7146_use_ops saa7146_vbi_uops = {
|
||||
.init = vbi_init,
|
||||
.open = vbi_open,
|
||||
.release = vbi_close,
|
||||
.irq_done = vbi_irq_done,
|
||||
.read = vbi_read,
|
||||
};
|
||||
1309
drivers/media/common/saa7146/saa7146_video.c
Normal file
1309
drivers/media/common/saa7146/saa7146_video.c
Normal file
File diff suppressed because it is too large
Load diff
32
drivers/media/common/siano/Kconfig
Normal file
32
drivers/media/common/siano/Kconfig
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
# Siano Mobile Silicon Digital TV device configuration
|
||||
#
|
||||
|
||||
config SMS_SIANO_MDTV
|
||||
tristate
|
||||
depends on DVB_CORE && HAS_DMA
|
||||
depends on !RC_CORE || RC_CORE
|
||||
depends on SMS_USB_DRV || SMS_SDIO_DRV
|
||||
default y
|
||||
|
||||
config SMS_SIANO_RC
|
||||
bool "Enable Remote Controller support for Siano devices"
|
||||
depends on SMS_SIANO_MDTV && RC_CORE
|
||||
depends on SMS_USB_DRV || SMS_SDIO_DRV
|
||||
depends on MEDIA_COMMON_OPTIONS
|
||||
default y
|
||||
---help---
|
||||
Choose Y to select Remote Controller support for Siano driver.
|
||||
|
||||
config SMS_SIANO_DEBUGFS
|
||||
bool "Enable debugfs for smsdvb"
|
||||
depends on SMS_SIANO_MDTV
|
||||
depends on DEBUG_FS
|
||||
depends on SMS_USB_DRV = SMS_SDIO_DRV
|
||||
|
||||
---help---
|
||||
Choose Y to enable visualizing a dump of the frontend
|
||||
statistics response packets via debugfs. Currently, works
|
||||
only with Siano USB devices.
|
||||
|
||||
Useful only for developers. In doubt, say N.
|
||||
16
drivers/media/common/siano/Makefile
Normal file
16
drivers/media/common/siano/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o
|
||||
smsdvb-objs := smsdvb-main.o
|
||||
|
||||
obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
|
||||
|
||||
ifeq ($(CONFIG_SMS_SIANO_RC),y)
|
||||
smsmdtv-objs += smsir.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SMS_SIANO_DEBUGFS),y)
|
||||
smsdvb-objs += smsdvb-debugfs.o
|
||||
endif
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core
|
||||
ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
|
||||
|
||||
364
drivers/media/common/siano/sms-cards.c
Normal file
364
drivers/media/common/siano/sms-cards.c
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Card-specific functions for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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 "sms-cards.h"
|
||||
#include "smsir.h"
|
||||
#include <linux/module.h>
|
||||
|
||||
static int sms_dbg;
|
||||
module_param_named(cards_dbg, sms_dbg, int, 0644);
|
||||
MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
|
||||
|
||||
static struct sms_board sms_boards[] = {
|
||||
[SMS_BOARD_UNKNOWN] = {
|
||||
.name = "Unknown board",
|
||||
.type = SMS_UNKNOWN_TYPE,
|
||||
.default_mode = DEVICE_MODE_NONE,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_STELLAR] = {
|
||||
.name = "Siano Stellar Digital Receiver",
|
||||
.type = SMS_STELLAR,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_NOVA_A] = {
|
||||
.name = "Siano Nova A Digital Receiver",
|
||||
.type = SMS_NOVA_A0,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_NOVA_B] = {
|
||||
.name = "Siano Nova B Digital Receiver",
|
||||
.type = SMS_NOVA_B0,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_VEGA] = {
|
||||
.name = "Siano Vega Digital Receiver",
|
||||
.type = SMS_VEGA,
|
||||
.default_mode = DEVICE_MODE_CMMB,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
|
||||
.name = "Hauppauge Catamount",
|
||||
.type = SMS_STELLAR,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_STELLAR,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
|
||||
.name = "Hauppauge Okemo-A",
|
||||
.type = SMS_NOVA_A0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_A,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
|
||||
.name = "Hauppauge Okemo-B",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_B,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
|
||||
.name = "Hauppauge WinTV MiniStick",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_HCW_55XXX,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
.rc_codes = RC_MAP_HAUPPAUGE,
|
||||
.board_cfg.leds_power = 26,
|
||||
.board_cfg.led0 = 27,
|
||||
.board_cfg.led1 = 28,
|
||||
.board_cfg.ir = 9,
|
||||
.led_power = 26,
|
||||
.led_lo = 27,
|
||||
.led_hi = 28,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
|
||||
.name = "Hauppauge WinTV MiniCard",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
.lna_ctrl = 29,
|
||||
.board_cfg.foreign_lna0_ctrl = 29,
|
||||
.rf_switch = 17,
|
||||
.board_cfg.rf_switch_uhf = 17,
|
||||
},
|
||||
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
|
||||
.name = "Hauppauge WinTV MiniCard",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
.lna_ctrl = -1,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_NICE] = {
|
||||
.name = "Siano Nice Digital Receiver",
|
||||
.type = SMS_NOVA_B0,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_VENICE] = {
|
||||
.name = "Siano Venice Digital Receiver",
|
||||
.type = SMS_VEGA,
|
||||
.default_mode = DEVICE_MODE_CMMB,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_STELLAR_ROM] = {
|
||||
.name = "Siano Stellar Digital Receiver ROM",
|
||||
.type = SMS_STELLAR,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
.intf_num = 1,
|
||||
},
|
||||
[SMS1XXX_BOARD_ZTE_DVB_DATA_CARD] = {
|
||||
.name = "ZTE Data Card Digital Receiver",
|
||||
.type = SMS_NOVA_B0,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
.intf_num = 5,
|
||||
.mtu = 15792,
|
||||
},
|
||||
[SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD] = {
|
||||
.name = "ONDA Data Card Digital Receiver",
|
||||
.type = SMS_NOVA_B0,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
.intf_num = 6,
|
||||
.mtu = 15792,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_MING] = {
|
||||
.name = "Siano Ming Digital Receiver",
|
||||
.type = SMS_MING,
|
||||
.default_mode = DEVICE_MODE_CMMB,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_PELE] = {
|
||||
.name = "Siano Pele Digital Receiver",
|
||||
.type = SMS_PELE,
|
||||
.default_mode = DEVICE_MODE_ISDBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_RIO] = {
|
||||
.name = "Siano Rio Digital Receiver",
|
||||
.type = SMS_RIO,
|
||||
.default_mode = DEVICE_MODE_ISDBT_BDA,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_DENVER_1530] = {
|
||||
.name = "Siano Denver (ATSC-M/H) Digital Receiver",
|
||||
.type = SMS_DENVER_1530,
|
||||
.default_mode = DEVICE_MODE_ATSC,
|
||||
.crystal = 2400,
|
||||
},
|
||||
[SMS1XXX_BOARD_SIANO_DENVER_2160] = {
|
||||
.name = "Siano Denver (TDMB) Digital Receiver",
|
||||
.type = SMS_DENVER_2160,
|
||||
.default_mode = DEVICE_MODE_DAB_TDMB,
|
||||
},
|
||||
[SMS1XXX_BOARD_PCTV_77E] = {
|
||||
.name = "Hauppauge microStick 77e",
|
||||
.type = SMS_NOVA_B0,
|
||||
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
|
||||
.default_mode = DEVICE_MODE_DVBT_BDA,
|
||||
},
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(unsigned id)
|
||||
{
|
||||
BUG_ON(id >= ARRAY_SIZE(sms_boards));
|
||||
|
||||
return &sms_boards[id];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_get_board);
|
||||
static inline void sms_gpio_assign_11xx_default_led_config(
|
||||
struct smscore_config_gpio *p_gpio_config) {
|
||||
p_gpio_config->direction = SMS_GPIO_DIRECTION_OUTPUT;
|
||||
p_gpio_config->inputcharacteristics =
|
||||
SMS_GPIO_INPUTCHARACTERISTICS_NORMAL;
|
||||
p_gpio_config->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA;
|
||||
p_gpio_config->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
|
||||
p_gpio_config->pullupdown = SMS_GPIO_PULLUPDOWN_NONE;
|
||||
}
|
||||
|
||||
int sms_board_event(struct smscore_device_t *coredev,
|
||||
enum SMS_BOARD_EVENTS gevent)
|
||||
{
|
||||
struct smscore_config_gpio my_gpio_config;
|
||||
|
||||
sms_gpio_assign_11xx_default_led_config(&my_gpio_config);
|
||||
|
||||
switch (gevent) {
|
||||
case BOARD_EVENT_POWER_INIT: /* including hotplug */
|
||||
break; /* BOARD_EVENT_BIND */
|
||||
|
||||
case BOARD_EVENT_POWER_SUSPEND:
|
||||
break; /* BOARD_EVENT_POWER_SUSPEND */
|
||||
|
||||
case BOARD_EVENT_POWER_RESUME:
|
||||
break; /* BOARD_EVENT_POWER_RESUME */
|
||||
|
||||
case BOARD_EVENT_BIND:
|
||||
break; /* BOARD_EVENT_BIND */
|
||||
|
||||
case BOARD_EVENT_SCAN_PROG:
|
||||
break; /* BOARD_EVENT_SCAN_PROG */
|
||||
case BOARD_EVENT_SCAN_COMP:
|
||||
break; /* BOARD_EVENT_SCAN_COMP */
|
||||
case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
|
||||
break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
|
||||
case BOARD_EVENT_FE_LOCK:
|
||||
break; /* BOARD_EVENT_FE_LOCK */
|
||||
case BOARD_EVENT_FE_UNLOCK:
|
||||
break; /* BOARD_EVENT_FE_UNLOCK */
|
||||
case BOARD_EVENT_DEMOD_LOCK:
|
||||
break; /* BOARD_EVENT_DEMOD_LOCK */
|
||||
case BOARD_EVENT_DEMOD_UNLOCK:
|
||||
break; /* BOARD_EVENT_DEMOD_UNLOCK */
|
||||
case BOARD_EVENT_RECEPTION_MAX_4:
|
||||
break; /* BOARD_EVENT_RECEPTION_MAX_4 */
|
||||
case BOARD_EVENT_RECEPTION_3:
|
||||
break; /* BOARD_EVENT_RECEPTION_3 */
|
||||
case BOARD_EVENT_RECEPTION_2:
|
||||
break; /* BOARD_EVENT_RECEPTION_2 */
|
||||
case BOARD_EVENT_RECEPTION_1:
|
||||
break; /* BOARD_EVENT_RECEPTION_1 */
|
||||
case BOARD_EVENT_RECEPTION_LOST_0:
|
||||
break; /* BOARD_EVENT_RECEPTION_LOST_0 */
|
||||
case BOARD_EVENT_MULTIPLEX_OK:
|
||||
break; /* BOARD_EVENT_MULTIPLEX_OK */
|
||||
case BOARD_EVENT_MULTIPLEX_ERRORS:
|
||||
break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
|
||||
|
||||
default:
|
||||
sms_err("Unknown SMS board event");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_board_event);
|
||||
|
||||
static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
|
||||
{
|
||||
int lvl, ret;
|
||||
u32 gpio;
|
||||
struct smscore_config_gpio gpioconfig = {
|
||||
.direction = SMS_GPIO_DIRECTION_OUTPUT,
|
||||
.pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
|
||||
.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
|
||||
.outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_FAST,
|
||||
.outputdriving = SMS_GPIO_OUTPUTDRIVING_S_4mA,
|
||||
};
|
||||
|
||||
if (pin == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (pin < 0) {
|
||||
/* inverted gpio */
|
||||
gpio = pin * -1;
|
||||
lvl = enable ? 0 : 1;
|
||||
} else {
|
||||
gpio = pin;
|
||||
lvl = enable ? 1 : 0;
|
||||
}
|
||||
|
||||
ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return smscore_set_gpio(coredev, gpio, lvl);
|
||||
}
|
||||
|
||||
int sms_board_setup(struct smscore_device_t *coredev)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
/* turn off all LEDs */
|
||||
sms_set_gpio(coredev, board->led_power, 0);
|
||||
sms_set_gpio(coredev, board->led_hi, 0);
|
||||
sms_set_gpio(coredev, board->led_lo, 0);
|
||||
break;
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
|
||||
/* turn off LNA */
|
||||
sms_set_gpio(coredev, board->lna_ctrl, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_board_setup);
|
||||
|
||||
int sms_board_power(struct smscore_device_t *coredev, int onoff)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
/* power LED */
|
||||
sms_set_gpio(coredev,
|
||||
board->led_power, onoff ? 1 : 0);
|
||||
break;
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
|
||||
/* LNA */
|
||||
if (!onoff)
|
||||
sms_set_gpio(coredev, board->lna_ctrl, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_board_power);
|
||||
|
||||
int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
/* dont touch GPIO if LEDs are already set */
|
||||
if (smscore_led_state(coredev, -1) == led)
|
||||
return 0;
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
sms_set_gpio(coredev,
|
||||
board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
|
||||
sms_set_gpio(coredev,
|
||||
board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
|
||||
|
||||
smscore_led_state(coredev, led);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_board_led_feedback);
|
||||
|
||||
int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
|
||||
{
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct sms_board *board = sms_get_board(board_id);
|
||||
|
||||
sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
|
||||
|
||||
switch (board_id) {
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
|
||||
sms_set_gpio(coredev,
|
||||
board->rf_switch, onoff ? 1 : 0);
|
||||
return sms_set_gpio(coredev,
|
||||
board->lna_ctrl, onoff ? 1 : 0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_board_lna_control);
|
||||
|
||||
int sms_board_load_modules(int id)
|
||||
{
|
||||
request_module("smsdvb");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sms_board_load_modules);
|
||||
138
drivers/media/common/siano/sms-cards.h
Normal file
138
drivers/media/common/siano/sms-cards.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Card-specific functions for the Siano SMS1xxx USB dongle
|
||||
*
|
||||
* Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
*
|
||||
* 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 __SMS_CARDS_H__
|
||||
#define __SMS_CARDS_H__
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include "smscoreapi.h"
|
||||
#include "smsir.h"
|
||||
|
||||
#define SMS_BOARD_UNKNOWN 0
|
||||
#define SMS1XXX_BOARD_SIANO_STELLAR 1
|
||||
#define SMS1XXX_BOARD_SIANO_NOVA_A 2
|
||||
#define SMS1XXX_BOARD_SIANO_NOVA_B 3
|
||||
#define SMS1XXX_BOARD_SIANO_VEGA 4
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
|
||||
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
|
||||
#define SMS1XXX_BOARD_SIANO_NICE 11
|
||||
#define SMS1XXX_BOARD_SIANO_VENICE 12
|
||||
#define SMS1XXX_BOARD_SIANO_STELLAR_ROM 13
|
||||
#define SMS1XXX_BOARD_ZTE_DVB_DATA_CARD 14
|
||||
#define SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD 15
|
||||
#define SMS1XXX_BOARD_SIANO_MING 16
|
||||
#define SMS1XXX_BOARD_SIANO_PELE 17
|
||||
#define SMS1XXX_BOARD_SIANO_RIO 18
|
||||
#define SMS1XXX_BOARD_SIANO_DENVER_1530 19
|
||||
#define SMS1XXX_BOARD_SIANO_DENVER_2160 20
|
||||
#define SMS1XXX_BOARD_PCTV_77E 21
|
||||
|
||||
struct sms_board_gpio_cfg {
|
||||
int lna_vhf_exist;
|
||||
int lna_vhf_ctrl;
|
||||
int lna_uhf_exist;
|
||||
int lna_uhf_ctrl;
|
||||
int lna_uhf_d_ctrl;
|
||||
int lna_sband_exist;
|
||||
int lna_sband_ctrl;
|
||||
int lna_sband_d_ctrl;
|
||||
int foreign_lna0_ctrl;
|
||||
int foreign_lna1_ctrl;
|
||||
int foreign_lna2_ctrl;
|
||||
int rf_switch_vhf;
|
||||
int rf_switch_uhf;
|
||||
int rf_switch_sband;
|
||||
int leds_power;
|
||||
int led0;
|
||||
int led1;
|
||||
int led2;
|
||||
int led3;
|
||||
int led4;
|
||||
int ir;
|
||||
int eeprom_wp;
|
||||
int mrc_sense;
|
||||
int mrc_pdn_resetn;
|
||||
int mrc_gp0; /* mrcs spi int */
|
||||
int mrc_gp1;
|
||||
int mrc_gp2;
|
||||
int mrc_gp3;
|
||||
int mrc_gp4;
|
||||
int host_spi_gsp_ts_int;
|
||||
};
|
||||
|
||||
struct sms_board {
|
||||
enum sms_device_type_st type;
|
||||
char *name, *fw[DEVICE_MODE_MAX];
|
||||
struct sms_board_gpio_cfg board_cfg;
|
||||
char *rc_codes; /* Name of IR codes table */
|
||||
|
||||
/* gpios */
|
||||
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
|
||||
|
||||
char intf_num;
|
||||
int default_mode;
|
||||
unsigned int mtu;
|
||||
unsigned int crystal;
|
||||
struct sms_antenna_config_ST *antenna_config;
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(unsigned id);
|
||||
|
||||
extern struct smscore_device_t *coredev;
|
||||
|
||||
enum SMS_BOARD_EVENTS {
|
||||
BOARD_EVENT_POWER_INIT,
|
||||
BOARD_EVENT_POWER_SUSPEND,
|
||||
BOARD_EVENT_POWER_RESUME,
|
||||
BOARD_EVENT_BIND,
|
||||
BOARD_EVENT_SCAN_PROG,
|
||||
BOARD_EVENT_SCAN_COMP,
|
||||
BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
|
||||
BOARD_EVENT_FE_LOCK,
|
||||
BOARD_EVENT_FE_UNLOCK,
|
||||
BOARD_EVENT_DEMOD_LOCK,
|
||||
BOARD_EVENT_DEMOD_UNLOCK,
|
||||
BOARD_EVENT_RECEPTION_MAX_4,
|
||||
BOARD_EVENT_RECEPTION_3,
|
||||
BOARD_EVENT_RECEPTION_2,
|
||||
BOARD_EVENT_RECEPTION_1,
|
||||
BOARD_EVENT_RECEPTION_LOST_0,
|
||||
BOARD_EVENT_MULTIPLEX_OK,
|
||||
BOARD_EVENT_MULTIPLEX_ERRORS
|
||||
};
|
||||
|
||||
int sms_board_event(struct smscore_device_t *coredev,
|
||||
enum SMS_BOARD_EVENTS gevent);
|
||||
|
||||
int sms_board_setup(struct smscore_device_t *coredev);
|
||||
|
||||
#define SMS_LED_OFF 0
|
||||
#define SMS_LED_LO 1
|
||||
#define SMS_LED_HI 2
|
||||
int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
|
||||
int sms_board_power(struct smscore_device_t *coredev, int onoff);
|
||||
int sms_board_lna_control(struct smscore_device_t *coredev, int onoff);
|
||||
|
||||
extern int sms_board_load_modules(int id);
|
||||
|
||||
#endif /* __SMS_CARDS_H__ */
|
||||
2198
drivers/media/common/siano/smscoreapi.c
Normal file
2198
drivers/media/common/siano/smscoreapi.c
Normal file
File diff suppressed because it is too large
Load diff
1192
drivers/media/common/siano/smscoreapi.h
Normal file
1192
drivers/media/common/siano/smscoreapi.h
Normal file
File diff suppressed because it is too large
Load diff
551
drivers/media/common/siano/smsdvb-debugfs.c
Normal file
551
drivers/media/common/siano/smsdvb-debugfs.c
Normal file
|
|
@ -0,0 +1,551 @@
|
|||
/***********************************************************************
|
||||
*
|
||||
* Copyright(c) 2013 Mauro Carvalho Chehab
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "smscoreapi.h"
|
||||
|
||||
#include "smsdvb.h"
|
||||
|
||||
static struct dentry *smsdvb_debugfs_usb_root;
|
||||
|
||||
struct smsdvb_debugfs {
|
||||
struct kref refcount;
|
||||
spinlock_t lock;
|
||||
|
||||
char stats_data[PAGE_SIZE];
|
||||
unsigned stats_count;
|
||||
bool stats_was_read;
|
||||
|
||||
wait_queue_head_t stats_queue;
|
||||
};
|
||||
|
||||
static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data,
|
||||
struct sms_stats *p)
|
||||
{
|
||||
int n = 0;
|
||||
char *buf;
|
||||
|
||||
spin_lock(&debug_data->lock);
|
||||
if (debug_data->stats_count) {
|
||||
spin_unlock(&debug_data->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = debug_data->stats_data;
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_rf_locked = %d\n", p->is_rf_locked);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_demod_locked = %d\n", p->is_demod_locked);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"SNR = %d\n", p->SNR);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ber = %d\n", p->ber);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"FIB_CRC = %d\n", p->FIB_CRC);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ts_per = %d\n", p->ts_per);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"MFER = %d\n", p->MFER);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"RSSI = %d\n", p->RSSI);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"in_band_pwr = %d\n", p->in_band_pwr);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"carrier_offset = %d\n", p->carrier_offset);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\n", p->modem_state);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"frequency = %d\n", p->frequency);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"bandwidth = %d\n", p->bandwidth);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"transmission_mode = %d\n", p->transmission_mode);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\n", p->modem_state);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"guard_interval = %d\n", p->guard_interval);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"code_rate = %d\n", p->code_rate);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"lp_code_rate = %d\n", p->lp_code_rate);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"hierarchy = %d\n", p->hierarchy);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"constellation = %d\n", p->constellation);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"burst_size = %d\n", p->burst_size);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"burst_duration = %d\n", p->burst_duration);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"burst_cycle_time = %d\n", p->burst_cycle_time);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"calc_burst_cycle_time = %d\n",
|
||||
p->calc_burst_cycle_time);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_rows = %d\n", p->num_of_rows);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_padd_cols = %d\n", p->num_of_padd_cols);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_punct_cols = %d\n", p->num_of_punct_cols);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"error_ts_packets = %d\n", p->error_ts_packets);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"total_ts_packets = %d\n", p->total_ts_packets);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ber_error_count = %d\n", p->ber_error_count);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"ber_bit_count = %d\n", p->ber_bit_count);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"pre_ber = %d\n", p->pre_ber);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"cell_id = %d\n", p->cell_id);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_mpe_received = %d\n", p->num_mpe_received);
|
||||
|
||||
debug_data->stats_count = n;
|
||||
spin_unlock(&debug_data->lock);
|
||||
wake_up(&debug_data->stats_queue);
|
||||
}
|
||||
|
||||
static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
|
||||
struct sms_isdbt_stats *p)
|
||||
{
|
||||
int i, n = 0;
|
||||
char *buf;
|
||||
|
||||
spin_lock(&debug_data->lock);
|
||||
if (debug_data->stats_count) {
|
||||
spin_unlock(&debug_data->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = debug_data->stats_data;
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"statistics_type = %d\t", p->statistics_type);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"full_size = %d\n", p->full_size);
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_demod_locked = %d\t", p->is_demod_locked);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"SNR = %d dB\t\t", p->SNR);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"RSSI = %d dBm\t\t", p->RSSI);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"carrier_offset = %d\t", p->carrier_offset);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"bandwidth = %d\t\t", p->bandwidth);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"frequency = %d Hz\n", p->frequency);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"transmission_mode = %d\t", p->transmission_mode);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\t\t", p->modem_state);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"guard_interval = %d\n", p->guard_interval);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"system_type = %d\t\t", p->system_type);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"partial_reception = %d\t", p->partial_reception);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_layers = %d\n", p->num_of_layers);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (p->layer_info[i].number_of_segments < 1 ||
|
||||
p->layer_info[i].number_of_segments > 13)
|
||||
continue;
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
|
||||
p->layer_info[i].code_rate);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
|
||||
p->layer_info[i].constellation);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
|
||||
p->layer_info[i].ber);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
|
||||
p->layer_info[i].ber_error_count);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
|
||||
p->layer_info[i].ber_bit_count);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
|
||||
p->layer_info[i].pre_ber);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
|
||||
p->layer_info[i].ts_per);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
|
||||
p->layer_info[i].error_ts_packets);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
|
||||
p->layer_info[i].total_ts_packets);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
|
||||
p->layer_info[i].ti_ldepth_i);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\tnumber_of_segments = %d\t",
|
||||
p->layer_info[i].number_of_segments);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
|
||||
p->layer_info[i].tmcc_errors);
|
||||
}
|
||||
|
||||
debug_data->stats_count = n;
|
||||
spin_unlock(&debug_data->lock);
|
||||
wake_up(&debug_data->stats_queue);
|
||||
}
|
||||
|
||||
static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
|
||||
struct sms_isdbt_stats_ex *p)
|
||||
{
|
||||
int i, n = 0;
|
||||
char *buf;
|
||||
|
||||
spin_lock(&debug_data->lock);
|
||||
if (debug_data->stats_count) {
|
||||
spin_unlock(&debug_data->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = debug_data->stats_data;
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"statistics_type = %d\t", p->statistics_type);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"full_size = %d\n", p->full_size);
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_rf_locked = %d\t\t", p->is_rf_locked);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_demod_locked = %d\t", p->is_demod_locked);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"is_external_lna_on = %d\n", p->is_external_lna_on);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"SNR = %d dB\t\t", p->SNR);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"RSSI = %d dBm\t\t", p->RSSI);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"in_band_pwr = %d dBm\n", p->in_band_pwr);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"carrier_offset = %d\t", p->carrier_offset);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"bandwidth = %d\t\t", p->bandwidth);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"frequency = %d Hz\n", p->frequency);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"transmission_mode = %d\t", p->transmission_mode);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"modem_state = %d\t\t", p->modem_state);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"guard_interval = %d\n", p->guard_interval);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"system_type = %d\t\t", p->system_type);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"partial_reception = %d\t", p->partial_reception);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"num_of_layers = %d\n", p->num_of_layers);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t",
|
||||
p->segment_number);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n",
|
||||
p->tune_bw);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (p->layer_info[i].number_of_segments < 1 ||
|
||||
p->layer_info[i].number_of_segments > 13)
|
||||
continue;
|
||||
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
|
||||
p->layer_info[i].code_rate);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
|
||||
p->layer_info[i].constellation);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
|
||||
p->layer_info[i].ber);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
|
||||
p->layer_info[i].ber_error_count);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
|
||||
p->layer_info[i].ber_bit_count);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
|
||||
p->layer_info[i].pre_ber);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
|
||||
p->layer_info[i].ts_per);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
|
||||
p->layer_info[i].error_ts_packets);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
|
||||
p->layer_info[i].total_ts_packets);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
|
||||
p->layer_info[i].ti_ldepth_i);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n,
|
||||
"\tnumber_of_segments = %d\t",
|
||||
p->layer_info[i].number_of_segments);
|
||||
n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
|
||||
p->layer_info[i].tmcc_errors);
|
||||
}
|
||||
|
||||
|
||||
debug_data->stats_count = n;
|
||||
spin_unlock(&debug_data->lock);
|
||||
|
||||
wake_up(&debug_data->stats_queue);
|
||||
}
|
||||
|
||||
static int smsdvb_stats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct smsdvb_client_t *client = inode->i_private;
|
||||
struct smsdvb_debugfs *debug_data = client->debug_data;
|
||||
|
||||
kref_get(&debug_data->refcount);
|
||||
|
||||
spin_lock(&debug_data->lock);
|
||||
debug_data->stats_count = 0;
|
||||
debug_data->stats_was_read = false;
|
||||
spin_unlock(&debug_data->lock);
|
||||
|
||||
file->private_data = debug_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smsdvb_debugfs_data_release(struct kref *ref)
|
||||
{
|
||||
struct smsdvb_debugfs *debug_data;
|
||||
|
||||
debug_data = container_of(ref, struct smsdvb_debugfs, refcount);
|
||||
kfree(debug_data);
|
||||
}
|
||||
|
||||
static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
spin_lock(&debug_data->lock);
|
||||
|
||||
if (debug_data->stats_was_read)
|
||||
goto exit;
|
||||
|
||||
rc = debug_data->stats_count;
|
||||
|
||||
exit:
|
||||
spin_unlock(&debug_data->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct smsdvb_debugfs *debug_data = file->private_data;
|
||||
int rc;
|
||||
|
||||
kref_get(&debug_data->refcount);
|
||||
|
||||
poll_wait(file, &debug_data->stats_queue, wait);
|
||||
|
||||
rc = smsdvb_stats_wait_read(debug_data);
|
||||
if (rc > 0)
|
||||
rc = POLLIN | POLLRDNORM;
|
||||
|
||||
kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf,
|
||||
size_t nbytes, loff_t *ppos)
|
||||
{
|
||||
int rc = 0, len;
|
||||
struct smsdvb_debugfs *debug_data = file->private_data;
|
||||
|
||||
kref_get(&debug_data->refcount);
|
||||
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
rc = smsdvb_stats_wait_read(debug_data);
|
||||
if (!rc) {
|
||||
rc = -EWOULDBLOCK;
|
||||
goto ret;
|
||||
}
|
||||
} else {
|
||||
rc = wait_event_interruptible(debug_data->stats_queue,
|
||||
smsdvb_stats_wait_read(debug_data));
|
||||
if (rc < 0)
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if (debug_data->stats_was_read) {
|
||||
rc = 0; /* EOF */
|
||||
goto ret;
|
||||
}
|
||||
|
||||
len = debug_data->stats_count - *ppos;
|
||||
if (len >= 0)
|
||||
rc = simple_read_from_buffer(user_buf, nbytes, ppos,
|
||||
debug_data->stats_data, len);
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
if (*ppos >= debug_data->stats_count) {
|
||||
spin_lock(&debug_data->lock);
|
||||
debug_data->stats_was_read = true;
|
||||
spin_unlock(&debug_data->lock);
|
||||
}
|
||||
ret:
|
||||
kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smsdvb_stats_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct smsdvb_debugfs *debug_data = file->private_data;
|
||||
|
||||
spin_lock(&debug_data->lock);
|
||||
debug_data->stats_was_read = true; /* return EOF to read() */
|
||||
spin_unlock(&debug_data->lock);
|
||||
wake_up_interruptible_sync(&debug_data->stats_queue);
|
||||
|
||||
kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
|
||||
file->private_data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations debugfs_stats_ops = {
|
||||
.open = smsdvb_stats_open,
|
||||
.poll = smsdvb_stats_poll,
|
||||
.read = smsdvb_stats_read,
|
||||
.release = smsdvb_stats_release,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions used by smsdvb, in order to create the interfaces
|
||||
*/
|
||||
|
||||
int smsdvb_debugfs_create(struct smsdvb_client_t *client)
|
||||
{
|
||||
struct smscore_device_t *coredev = client->coredev;
|
||||
struct dentry *d;
|
||||
struct smsdvb_debugfs *debug_data;
|
||||
|
||||
if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device)
|
||||
return -ENODEV;
|
||||
|
||||
client->debugfs = debugfs_create_dir(coredev->devpath,
|
||||
smsdvb_debugfs_usb_root);
|
||||
if (IS_ERR_OR_NULL(client->debugfs)) {
|
||||
pr_info("Unable to create debugfs %s directory.\n",
|
||||
coredev->devpath);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs,
|
||||
client, &debugfs_stats_ops);
|
||||
if (!d) {
|
||||
debugfs_remove(client->debugfs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL);
|
||||
if (!debug_data)
|
||||
return -ENOMEM;
|
||||
|
||||
client->debug_data = debug_data;
|
||||
client->prt_dvb_stats = smsdvb_print_dvb_stats;
|
||||
client->prt_isdb_stats = smsdvb_print_isdb_stats;
|
||||
client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex;
|
||||
|
||||
init_waitqueue_head(&debug_data->stats_queue);
|
||||
spin_lock_init(&debug_data->lock);
|
||||
kref_init(&debug_data->refcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void smsdvb_debugfs_release(struct smsdvb_client_t *client)
|
||||
{
|
||||
if (!client->debugfs)
|
||||
return;
|
||||
|
||||
client->prt_dvb_stats = NULL;
|
||||
client->prt_isdb_stats = NULL;
|
||||
client->prt_isdb_stats_ex = NULL;
|
||||
|
||||
debugfs_remove_recursive(client->debugfs);
|
||||
kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release);
|
||||
|
||||
client->debug_data = NULL;
|
||||
client->debugfs = NULL;
|
||||
}
|
||||
|
||||
int smsdvb_debugfs_register(void)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
/*
|
||||
* FIXME: This was written to debug Siano USB devices. So, it creates
|
||||
* the debugfs node under <debugfs>/usb.
|
||||
* A similar logic would be needed for Siano sdio devices, but, in that
|
||||
* case, usb_debug_root is not a good choice.
|
||||
*
|
||||
* Perhaps the right fix here would be to create another sysfs root
|
||||
* node for sdio-based boards, but this may need some logic at sdio
|
||||
* subsystem.
|
||||
*/
|
||||
d = debugfs_create_dir("smsdvb", usb_debug_root);
|
||||
if (IS_ERR_OR_NULL(d)) {
|
||||
sms_err("Couldn't create sysfs node for smsdvb");
|
||||
return PTR_ERR(d);
|
||||
} else {
|
||||
smsdvb_debugfs_usb_root = d;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void smsdvb_debugfs_unregister(void)
|
||||
{
|
||||
debugfs_remove_recursive(smsdvb_debugfs_usb_root);
|
||||
smsdvb_debugfs_usb_root = NULL;
|
||||
}
|
||||
1232
drivers/media/common/siano/smsdvb-main.c
Normal file
1232
drivers/media/common/siano/smsdvb-main.c
Normal file
File diff suppressed because it is too large
Load diff
130
drivers/media/common/siano/smsdvb.h
Normal file
130
drivers/media/common/siano/smsdvb.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/***********************************************************************
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
struct smsdvb_debugfs;
|
||||
struct smsdvb_client_t;
|
||||
|
||||
typedef void (*sms_prt_dvb_stats_t)(struct smsdvb_debugfs *debug_data,
|
||||
struct sms_stats *p);
|
||||
|
||||
typedef void (*sms_prt_isdb_stats_t)(struct smsdvb_debugfs *debug_data,
|
||||
struct sms_isdbt_stats *p);
|
||||
|
||||
typedef void (*sms_prt_isdb_stats_ex_t)
|
||||
(struct smsdvb_debugfs *debug_data,
|
||||
struct sms_isdbt_stats_ex *p);
|
||||
|
||||
|
||||
struct smsdvb_client_t {
|
||||
struct list_head entry;
|
||||
|
||||
struct smscore_device_t *coredev;
|
||||
struct smscore_client_t *smsclient;
|
||||
|
||||
struct dvb_adapter adapter;
|
||||
struct dvb_demux demux;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
fe_status_t fe_status;
|
||||
|
||||
struct completion tune_done;
|
||||
struct completion stats_done;
|
||||
|
||||
int last_per;
|
||||
|
||||
int legacy_ber, legacy_per;
|
||||
|
||||
int event_fe_state;
|
||||
int event_unc_state;
|
||||
|
||||
unsigned long get_stats_jiffies;
|
||||
|
||||
int feed_users;
|
||||
bool has_tuned;
|
||||
|
||||
/* stats debugfs data */
|
||||
struct dentry *debugfs;
|
||||
|
||||
struct smsdvb_debugfs *debug_data;
|
||||
|
||||
sms_prt_dvb_stats_t prt_dvb_stats;
|
||||
sms_prt_isdb_stats_t prt_isdb_stats;
|
||||
sms_prt_isdb_stats_ex_t prt_isdb_stats_ex;
|
||||
};
|
||||
|
||||
/*
|
||||
* This struct is a mix of struct sms_rx_stats_ex and
|
||||
* struct sms_srvm_signal_status.
|
||||
* It was obtained by comparing the way it was filled by the original code
|
||||
*/
|
||||
struct RECEPTION_STATISTICS_PER_SLICES_S {
|
||||
u32 result;
|
||||
u32 snr;
|
||||
s32 in_band_power;
|
||||
u32 ts_packets;
|
||||
u32 ets_packets;
|
||||
u32 constellation;
|
||||
u32 hp_code;
|
||||
u32 tps_srv_ind_lp;
|
||||
u32 tps_srv_ind_hp;
|
||||
u32 cell_id;
|
||||
u32 reason;
|
||||
u32 request_id;
|
||||
u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
|
||||
|
||||
u32 ber; /* Post Viterbi BER [1E-5] */
|
||||
s32 RSSI; /* dBm */
|
||||
s32 carrier_offset; /* Carrier Offset in bin/1024 */
|
||||
|
||||
u32 is_rf_locked; /* 0 - not locked, 1 - locked */
|
||||
u32 is_demod_locked; /* 0 - not locked, 1 - locked */
|
||||
|
||||
u32 ber_bit_count; /* Total number of SYNC bits. */
|
||||
u32 ber_error_count; /* Number of erroneous SYNC bits. */
|
||||
|
||||
s32 MRC_SNR; /* dB */
|
||||
s32 mrc_in_band_pwr; /* In band power in dBM */
|
||||
s32 MRC_RSSI; /* dBm */
|
||||
};
|
||||
|
||||
/* From smsdvb-debugfs.c */
|
||||
#ifdef CONFIG_SMS_SIANO_DEBUGFS
|
||||
|
||||
int smsdvb_debugfs_create(struct smsdvb_client_t *client);
|
||||
void smsdvb_debugfs_release(struct smsdvb_client_t *client);
|
||||
int smsdvb_debugfs_register(void);
|
||||
void smsdvb_debugfs_unregister(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline int smsdvb_debugfs_create(struct smsdvb_client_t *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void smsdvb_debugfs_release(struct smsdvb_client_t *client) {}
|
||||
|
||||
static inline int smsdvb_debugfs_register(void)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
static inline void smsdvb_debugfs_unregister(void) {};
|
||||
|
||||
#endif
|
||||
|
||||
103
drivers/media/common/siano/smsendian.c
Normal file
103
drivers/media/common/siano/smsendian.c
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/****************************************************************
|
||||
|
||||
Siano Mobile Silicon, Inc.
|
||||
MDTV receiver kernel modules.
|
||||
Copyright (C) 2006-2009, Uri Shkolnik
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
****************************************************************/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "smsendian.h"
|
||||
#include "smscoreapi.h"
|
||||
|
||||
void smsendian_handle_tx_message(void *buffer)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
struct sms_msg_data *msg = (struct sms_msg_data *)buffer;
|
||||
int i;
|
||||
int msg_words;
|
||||
|
||||
switch (msg->x_msg_header.msg_type) {
|
||||
case MSG_SMS_DATA_DOWNLOAD_REQ:
|
||||
{
|
||||
msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
msg_words = (msg->x_msg_header.msg_length -
|
||||
sizeof(struct sms_msg_hdr))/4;
|
||||
|
||||
for (i = 0; i < msg_words; i++)
|
||||
msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif /* __BIG_ENDIAN */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
|
||||
|
||||
void smsendian_handle_rx_message(void *buffer)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
struct sms_msg_data *msg = (struct sms_msg_data *)buffer;
|
||||
int i;
|
||||
int msg_words;
|
||||
|
||||
switch (msg->x_msg_header.msg_type) {
|
||||
case MSG_SMS_GET_VERSION_EX_RES:
|
||||
{
|
||||
struct sms_version_res *ver =
|
||||
(struct sms_version_res *) msg;
|
||||
ver->chip_model = le16_to_cpu(ver->chip_model);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_SMS_DVBT_BDA_DATA:
|
||||
case MSG_SMS_DAB_CHANNEL:
|
||||
case MSG_SMS_DATA_MSG:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
msg_words = (msg->x_msg_header.msg_length -
|
||||
sizeof(struct sms_msg_hdr))/4;
|
||||
|
||||
for (i = 0; i < msg_words; i++)
|
||||
msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* __BIG_ENDIAN */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
|
||||
|
||||
void smsendian_handle_message_header(void *msg)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg;
|
||||
|
||||
phdr->msg_type = le16_to_cpu(phdr->msg_type);
|
||||
phdr->msg_length = le16_to_cpu(phdr->msg_length);
|
||||
phdr->msg_flags = le16_to_cpu(phdr->msg_flags);
|
||||
#endif /* __BIG_ENDIAN */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
|
||||
32
drivers/media/common/siano/smsendian.h
Normal file
32
drivers/media/common/siano/smsendian.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/****************************************************************
|
||||
|
||||
Siano Mobile Silicon, Inc.
|
||||
MDTV receiver kernel modules.
|
||||
Copyright (C) 2006-2009, Uri Shkolnik
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
****************************************************************/
|
||||
|
||||
#ifndef __SMS_ENDIAN_H__
|
||||
#define __SMS_ENDIAN_H__
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
extern void smsendian_handle_tx_message(void *buffer);
|
||||
extern void smsendian_handle_rx_message(void *buffer);
|
||||
extern void smsendian_handle_message_header(void *msg);
|
||||
|
||||
#endif /* __SMS_ENDIAN_H__ */
|
||||
|
||||
114
drivers/media/common/siano/smsir.c
Normal file
114
drivers/media/common/siano/smsir.c
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/****************************************************************
|
||||
|
||||
Siano Mobile Silicon, Inc.
|
||||
MDTV receiver kernel modules.
|
||||
Copyright (C) 2006-2009, Uri Shkolnik
|
||||
|
||||
Copyright (c) 2010 - Mauro Carvalho Chehab
|
||||
- Ported the driver to use rc-core
|
||||
- IR raw event decoding is now done at rc-core
|
||||
- Code almost re-written
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
****************************************************************/
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "smscoreapi.h"
|
||||
#include "smsir.h"
|
||||
#include "sms-cards.h"
|
||||
|
||||
#define MODULE_NAME "smsmdtv"
|
||||
|
||||
void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
const s32 *samples = (const void *)buf;
|
||||
|
||||
for (i = 0; i < len >> 2; i++) {
|
||||
DEFINE_IR_RAW_EVENT(ev);
|
||||
|
||||
ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
|
||||
ev.pulse = (samples[i] > 0) ? false : true;
|
||||
|
||||
ir_raw_event_store(coredev->ir.dev, &ev);
|
||||
}
|
||||
ir_raw_event_handle(coredev->ir.dev);
|
||||
}
|
||||
|
||||
int sms_ir_init(struct smscore_device_t *coredev)
|
||||
{
|
||||
int err;
|
||||
int board_id = smscore_get_board_id(coredev);
|
||||
struct rc_dev *dev;
|
||||
|
||||
sms_log("Allocating rc device");
|
||||
dev = rc_allocate_device();
|
||||
if (!dev) {
|
||||
sms_err("Not enough memory");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
|
||||
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
|
||||
sms_log("IR port %d, timeout %d ms",
|
||||
coredev->ir.controller, coredev->ir.timeout);
|
||||
|
||||
snprintf(coredev->ir.name, sizeof(coredev->ir.name),
|
||||
"SMS IR (%s)", sms_get_board(board_id)->name);
|
||||
|
||||
strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
|
||||
strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
|
||||
|
||||
dev->input_name = coredev->ir.name;
|
||||
dev->input_phys = coredev->ir.phys;
|
||||
dev->dev.parent = coredev->device;
|
||||
|
||||
#if 0
|
||||
/* TODO: properly initialize the parameters bellow */
|
||||
dev->input_id.bustype = BUS_USB;
|
||||
dev->input_id.version = 1;
|
||||
dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
|
||||
dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
|
||||
#endif
|
||||
|
||||
dev->priv = coredev;
|
||||
dev->driver_type = RC_DRIVER_IR_RAW;
|
||||
dev->allowed_protocols = RC_BIT_ALL;
|
||||
dev->map_name = sms_get_board(board_id)->rc_codes;
|
||||
dev->driver_name = MODULE_NAME;
|
||||
|
||||
sms_log("Input device (IR) %s is set for key events", dev->input_name);
|
||||
|
||||
err = rc_register_device(dev);
|
||||
if (err < 0) {
|
||||
sms_err("Failed to register device");
|
||||
rc_free_device(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
coredev->ir.dev = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sms_ir_exit(struct smscore_device_t *coredev)
|
||||
{
|
||||
if (coredev->ir.dev)
|
||||
rc_unregister_device(coredev->ir.dev);
|
||||
|
||||
sms_log("");
|
||||
}
|
||||
63
drivers/media/common/siano/smsir.h
Normal file
63
drivers/media/common/siano/smsir.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/****************************************************************
|
||||
|
||||
Siano Mobile Silicon, Inc.
|
||||
MDTV receiver kernel modules.
|
||||
Copyright (C) 2006-2009, Uri Shkolnik
|
||||
|
||||
Copyright (c) 2010 - Mauro Carvalho Chehab
|
||||
- Ported the driver to use rc-core
|
||||
- IR raw event decoding is now done at rc-core
|
||||
- Code almost re-written
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
****************************************************************/
|
||||
|
||||
#ifndef __SMS_IR_H__
|
||||
#define __SMS_IR_H__
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#define IR_DEFAULT_TIMEOUT 100
|
||||
|
||||
struct smscore_device_t;
|
||||
|
||||
struct ir_t {
|
||||
struct rc_dev *dev;
|
||||
char name[40];
|
||||
char phys[32];
|
||||
|
||||
char *rc_codes;
|
||||
|
||||
u32 timeout;
|
||||
u32 controller;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SMS_SIANO_RC
|
||||
int sms_ir_init(struct smscore_device_t *coredev);
|
||||
void sms_ir_exit(struct smscore_device_t *coredev);
|
||||
void sms_ir_event(struct smscore_device_t *coredev,
|
||||
const char *buf, int len);
|
||||
#else
|
||||
inline static int sms_ir_init(struct smscore_device_t *coredev) {
|
||||
return 0;
|
||||
}
|
||||
inline static void sms_ir_exit(struct smscore_device_t *coredev) {};
|
||||
inline static void sms_ir_event(struct smscore_device_t *coredev,
|
||||
const char *buf, int len) {};
|
||||
#endif
|
||||
|
||||
#endif /* __SMS_IR_H__ */
|
||||
|
||||
776
drivers/media/common/tveeprom.c
Normal file
776
drivers/media/common/tveeprom.c
Normal file
|
|
@ -0,0 +1,776 @@
|
|||
/*
|
||||
* tveeprom - eeprom decoder for tvcard configuration eeproms
|
||||
*
|
||||
* Data and decoding routines shamelessly borrowed from bttv-cards.c
|
||||
* eeprom access routine shamelessly borrowed from bttv-if.c
|
||||
* which are:
|
||||
|
||||
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
|
||||
& Marcus Metzler (mocm@thp.uni-koeln.de)
|
||||
(c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
|
||||
|
||||
* Adjustments to fit a more general model and all bugs:
|
||||
|
||||
Copyright (C) 2003 John Klar <linpvr at projectplasma.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/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <media/tuner.h>
|
||||
#include <media/tveeprom.h>
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
|
||||
MODULE_AUTHOR("John Klar");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
#define STRM(array, i) \
|
||||
(i < sizeof(array) / sizeof(char *) ? array[i] : "unknown")
|
||||
|
||||
#define tveeprom_info(fmt, arg...) \
|
||||
v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
|
||||
#define tveeprom_warn(fmt, arg...) \
|
||||
v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
|
||||
#define tveeprom_dbg(fmt, arg...) do { \
|
||||
if (debug) \
|
||||
v4l_printk(KERN_DEBUG, "tveeprom", \
|
||||
c->adapter, c->addr, fmt , ## arg); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* The Hauppauge eeprom uses an 8bit field to determine which
|
||||
* tuner formats the tuner supports.
|
||||
*/
|
||||
static const struct {
|
||||
int id;
|
||||
const char * const name;
|
||||
} hauppauge_tuner_fmt[] = {
|
||||
{ V4L2_STD_UNKNOWN, " UNKNOWN" },
|
||||
{ V4L2_STD_UNKNOWN, " FM" },
|
||||
{ V4L2_STD_B|V4L2_STD_GH, " PAL(B/G)" },
|
||||
{ V4L2_STD_MN, " NTSC(M)" },
|
||||
{ V4L2_STD_PAL_I, " PAL(I)" },
|
||||
{ V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, " SECAM(L/L')" },
|
||||
{ V4L2_STD_DK, " PAL(D/D1/K)" },
|
||||
{ V4L2_STD_ATSC, " ATSC/DVB Digital" },
|
||||
};
|
||||
|
||||
/* This is the full list of possible tuners. Many thanks to Hauppauge for
|
||||
supplying this information. Note that many tuners where only used for
|
||||
testing and never made it to the outside world. So you will only see
|
||||
a subset in actual produced cards. */
|
||||
static const struct {
|
||||
int id;
|
||||
const char * const name;
|
||||
} hauppauge_tuner[] = {
|
||||
/* 0-9 */
|
||||
{ TUNER_ABSENT, "None" },
|
||||
{ TUNER_ABSENT, "External" },
|
||||
{ TUNER_ABSENT, "Unspecified" },
|
||||
{ TUNER_PHILIPS_PAL, "Philips FI1216" },
|
||||
{ TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
|
||||
{ TUNER_PHILIPS_NTSC, "Philips FI1236" },
|
||||
{ TUNER_PHILIPS_PAL_I, "Philips FI1246" },
|
||||
{ TUNER_PHILIPS_PAL_DK, "Philips FI1256" },
|
||||
{ TUNER_PHILIPS_PAL, "Philips FI1216 MK2" },
|
||||
{ TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
|
||||
/* 10-19 */
|
||||
{ TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" },
|
||||
{ TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
|
||||
{ TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" },
|
||||
{ TUNER_TEMIC_NTSC, "Temic 4032FY5" },
|
||||
{ TUNER_TEMIC_PAL, "Temic 4002FH5" },
|
||||
{ TUNER_TEMIC_PAL_I, "Temic 4062FY5" },
|
||||
{ TUNER_PHILIPS_PAL, "Philips FR1216 MK2" },
|
||||
{ TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
|
||||
{ TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" },
|
||||
{ TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
|
||||
/* 20-29 */
|
||||
{ TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" },
|
||||
{ TUNER_PHILIPS_PAL, "Philips FM1216" },
|
||||
{ TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
|
||||
{ TUNER_PHILIPS_NTSC, "Philips FM1236" },
|
||||
{ TUNER_PHILIPS_PAL_I, "Philips FM1246" },
|
||||
{ TUNER_PHILIPS_PAL_DK, "Philips FM1256" },
|
||||
{ TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
|
||||
{ TUNER_ABSENT, "Samsung TCPN9082D" },
|
||||
{ TUNER_ABSENT, "Samsung TCPM9092P" },
|
||||
{ TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
|
||||
/* 30-39 */
|
||||
{ TUNER_ABSENT, "Samsung TCPN9085D" },
|
||||
{ TUNER_ABSENT, "Samsung TCPB9085P" },
|
||||
{ TUNER_ABSENT, "Samsung TCPL9091P" },
|
||||
{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
|
||||
{ TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" },
|
||||
{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
|
||||
{ TUNER_PHILIPS_NTSC, "Philips TD1536" },
|
||||
{ TUNER_PHILIPS_NTSC, "Philips TD1536D" },
|
||||
{ TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */
|
||||
{ TUNER_ABSENT, "Philips FI1256MP" },
|
||||
/* 40-49 */
|
||||
{ TUNER_ABSENT, "Samsung TCPQ9091P" },
|
||||
{ TUNER_TEMIC_4006FN5_MULTI_PAL,"Temic 4006FN5" },
|
||||
{ TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
|
||||
{ TUNER_TEMIC_4046FM5, "Temic 4046FM5" },
|
||||
{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
|
||||
{ TUNER_ABSENT, "Philips TD1536D FH 44"},
|
||||
{ TUNER_LG_NTSC_FM, "LG TP18NSR01F"},
|
||||
{ TUNER_LG_PAL_FM, "LG TP18PSB01D"},
|
||||
{ TUNER_LG_PAL, "LG TP18PSB11D"},
|
||||
{ TUNER_LG_PAL_I_FM, "LG TAPC-I001D"},
|
||||
/* 50-59 */
|
||||
{ TUNER_LG_PAL_I, "LG TAPC-I701D"},
|
||||
{ TUNER_ABSENT, "Temic 4042FI5"},
|
||||
{ TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
|
||||
{ TUNER_ABSENT, "LG TPI8NSR11F"},
|
||||
{ TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"},
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
|
||||
{ TUNER_ABSENT, "Philips FI1236 MK3"},
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
|
||||
{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
|
||||
{ TUNER_ABSENT, "Philips FM1216MP MK3"},
|
||||
/* 60-69 */
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
|
||||
{ TUNER_ABSENT, "LG M001D MK3"},
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
|
||||
{ TUNER_ABSENT, "LG M701D MK3"},
|
||||
{ TUNER_ABSENT, "Temic 4146FM5"},
|
||||
{ TUNER_ABSENT, "Temic 4136FY5"},
|
||||
{ TUNER_ABSENT, "Temic 4106FH5"},
|
||||
{ TUNER_ABSENT, "Philips FQ1216LMP MK3"},
|
||||
{ TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"},
|
||||
{ TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"},
|
||||
/* 70-79 */
|
||||
{ TUNER_ABSENT, "LG TALN H200T"},
|
||||
{ TUNER_ABSENT, "LG TALN H250T"},
|
||||
{ TUNER_ABSENT, "LG TALN M200T"},
|
||||
{ TUNER_ABSENT, "LG TALN Z200T"},
|
||||
{ TUNER_ABSENT, "LG TALN S200T"},
|
||||
{ TUNER_ABSENT, "Thompson DTT7595"},
|
||||
{ TUNER_ABSENT, "Thompson DTT7592"},
|
||||
{ TUNER_ABSENT, "Silicon TDA8275C1 8290"},
|
||||
{ TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
|
||||
{ TUNER_ABSENT, "Thompson DTT757"},
|
||||
/* 80-89 */
|
||||
{ TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"},
|
||||
{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
|
||||
{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
|
||||
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
|
||||
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
|
||||
{ TUNER_TCL_2002N, "TCL 2002N 6A"},
|
||||
{ TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
|
||||
{ TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
|
||||
{ TUNER_ABSENT, "Samsung TCPE 4121P30A"},
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
|
||||
/* 90-99 */
|
||||
{ TUNER_ABSENT, "LG TALN H202T"},
|
||||
{ TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
|
||||
{ TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
|
||||
{ TUNER_ABSENT, "Philips FQ1286A MK4"},
|
||||
{ TUNER_ABSENT, "Philips FQ1216ME MK5"},
|
||||
{ TUNER_ABSENT, "Philips FQ1236 MK5"},
|
||||
{ TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
|
||||
{ TUNER_TCL_2002MB, "TCL 2002MB_3H"},
|
||||
{ TUNER_ABSENT, "TCL 2002MI_3H"},
|
||||
{ TUNER_TCL_2002N, "TCL 2002N 5H"},
|
||||
/* 100-109 */
|
||||
{ TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
|
||||
{ TUNER_TEA5767, "Philips TEA5768HL FM Radio"},
|
||||
{ TUNER_ABSENT, "Panasonic ENV57H12D5"},
|
||||
{ TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
|
||||
{ TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"},
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
|
||||
{ TUNER_ABSENT, "TCL MQNM05-4"},
|
||||
{ TUNER_ABSENT, "LG TAPC-W701D"},
|
||||
{ TUNER_ABSENT, "TCL 9886P-WM"},
|
||||
{ TUNER_ABSENT, "TCL 1676NM-WM"},
|
||||
/* 110-119 */
|
||||
{ TUNER_ABSENT, "Thompson DTT75105"},
|
||||
{ TUNER_ABSENT, "Conexant_CX24109"},
|
||||
{ TUNER_TCL_2002N, "TCL M2523_5N_E"},
|
||||
{ TUNER_TCL_2002MB, "TCL M2523_3DB_E"},
|
||||
{ TUNER_ABSENT, "Philips 8275A"},
|
||||
{ TUNER_ABSENT, "Microtune MT2060"},
|
||||
{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
|
||||
{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
|
||||
{ TUNER_ABSENT, "TCL M2523_3DI_E"},
|
||||
{ TUNER_ABSENT, "Samsung THPD5222FG30A"},
|
||||
/* 120-129 */
|
||||
{ TUNER_XC2028, "Xceive XC3028"},
|
||||
{ TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"},
|
||||
{ TUNER_ABSENT, "Philips FQD1216LME"},
|
||||
{ TUNER_ABSENT, "Conexant CX24118A"},
|
||||
{ TUNER_ABSENT, "TCL DMF11WIP"},
|
||||
{ TUNER_ABSENT, "TCL MFNM05_4H_E"},
|
||||
{ TUNER_ABSENT, "TCL MNM05_4H_E"},
|
||||
{ TUNER_ABSENT, "TCL MPE05_2H_E"},
|
||||
{ TUNER_ABSENT, "TCL MQNM05_4_U"},
|
||||
{ TUNER_ABSENT, "TCL M2523_5NH_E"},
|
||||
/* 130-139 */
|
||||
{ TUNER_ABSENT, "TCL M2523_3DBH_E"},
|
||||
{ TUNER_ABSENT, "TCL M2523_3DIH_E"},
|
||||
{ TUNER_ABSENT, "TCL MFPE05_2_U"},
|
||||
{ TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"},
|
||||
{ TUNER_ABSENT, "Philips FRH2036B"},
|
||||
{ TUNER_ABSENT, "Panasonic ENGF75_01GF"},
|
||||
{ TUNER_ABSENT, "MaxLinear MXL5005"},
|
||||
{ TUNER_ABSENT, "MaxLinear MXL5003"},
|
||||
{ TUNER_ABSENT, "Xceive XC2028"},
|
||||
{ TUNER_ABSENT, "Microtune MT2131"},
|
||||
/* 140-149 */
|
||||
{ TUNER_ABSENT, "Philips 8275A_8295"},
|
||||
{ TUNER_ABSENT, "TCL MF02GIP_5N_E"},
|
||||
{ TUNER_ABSENT, "TCL MF02GIP_3DB_E"},
|
||||
{ TUNER_ABSENT, "TCL MF02GIP_3DI_E"},
|
||||
{ TUNER_ABSENT, "Microtune MT2266"},
|
||||
{ TUNER_ABSENT, "TCL MF10WPP_4N_E"},
|
||||
{ TUNER_ABSENT, "LG TAPQ_H702F"},
|
||||
{ TUNER_ABSENT, "TCL M09WPP_4N_E"},
|
||||
{ TUNER_ABSENT, "MaxLinear MXL5005_v2"},
|
||||
{ TUNER_PHILIPS_TDA8290, "Philips 18271_8295"},
|
||||
/* 150-159 */
|
||||
{ TUNER_XC5000, "Xceive XC5000"},
|
||||
{ TUNER_ABSENT, "Xceive XC3028L"},
|
||||
{ TUNER_ABSENT, "NXP 18271C2_716x"},
|
||||
{ TUNER_ABSENT, "Xceive XC4000"},
|
||||
{ TUNER_ABSENT, "Dibcom 7070"},
|
||||
{ TUNER_PHILIPS_TDA8290, "NXP 18271C2"},
|
||||
{ TUNER_ABSENT, "Siano SMS1010"},
|
||||
{ TUNER_ABSENT, "Siano SMS1150"},
|
||||
{ TUNER_ABSENT, "MaxLinear 5007"},
|
||||
{ TUNER_ABSENT, "TCL M09WPP_2P_E"},
|
||||
/* 160-169 */
|
||||
{ TUNER_ABSENT, "Siano SMS1180"},
|
||||
{ TUNER_ABSENT, "Maxim_MAX2165"},
|
||||
{ TUNER_ABSENT, "Siano SMS1140"},
|
||||
{ TUNER_ABSENT, "Siano SMS1150 B1"},
|
||||
{ TUNER_ABSENT, "MaxLinear 111"},
|
||||
{ TUNER_ABSENT, "Dibcom 7770"},
|
||||
{ TUNER_ABSENT, "Siano SMS1180VNS"},
|
||||
{ TUNER_ABSENT, "Siano SMS1184"},
|
||||
{ TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"},
|
||||
{ TUNER_ABSENT, "TCL_M11WPP_2PN_E"},
|
||||
/* 170-179 */
|
||||
{ TUNER_ABSENT, "MaxLinear 301"},
|
||||
{ TUNER_ABSENT, "Mirics MSi001"},
|
||||
{ TUNER_ABSENT, "MaxLinear MxL241SF"},
|
||||
{ TUNER_XC5000C, "Xceive XC5000C"},
|
||||
{ TUNER_ABSENT, "Montage M68TS2020"},
|
||||
{ TUNER_ABSENT, "Siano SMS1530"},
|
||||
{ TUNER_ABSENT, "Dibcom 7090"},
|
||||
{ TUNER_ABSENT, "Xceive XC5200C"},
|
||||
{ TUNER_ABSENT, "NXP 18273"},
|
||||
{ TUNER_ABSENT, "Montage M88TS2022"},
|
||||
/* 180-189 */
|
||||
{ TUNER_ABSENT, "NXP 18272M"},
|
||||
{ TUNER_ABSENT, "NXP 18272S"},
|
||||
};
|
||||
|
||||
/* Use TVEEPROM_AUDPROC_INTERNAL for those audio 'chips' that are
|
||||
* internal to a video chip, i.e. not a separate audio chip. */
|
||||
static const struct {
|
||||
u32 id;
|
||||
const char * const name;
|
||||
} audio_ic[] = {
|
||||
/* 0-4 */
|
||||
{ TVEEPROM_AUDPROC_NONE, "None" },
|
||||
{ TVEEPROM_AUDPROC_OTHER, "TEA6300" },
|
||||
{ TVEEPROM_AUDPROC_OTHER, "TEA6320" },
|
||||
{ TVEEPROM_AUDPROC_OTHER, "TDA9850" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3400C" },
|
||||
/* 5-9 */
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3410D" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3415" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3430" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3438" },
|
||||
{ TVEEPROM_AUDPROC_OTHER, "CS5331" },
|
||||
/* 10-14 */
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3435" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3440" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3445" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3411" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3416" },
|
||||
/* 15-19 */
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3425" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3451" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP3418" },
|
||||
{ TVEEPROM_AUDPROC_OTHER, "Type 0x12" },
|
||||
{ TVEEPROM_AUDPROC_OTHER, "OKI7716" },
|
||||
/* 20-24 */
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4410" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4420" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4440" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4450" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4408" },
|
||||
/* 25-29 */
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4418" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4428" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4448" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "MSP4458" },
|
||||
{ TVEEPROM_AUDPROC_MSP, "Type 0x1d" },
|
||||
/* 30-34 */
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX880" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX881" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX883" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX882" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX25840" },
|
||||
/* 35-39 */
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX25841" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX25842" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX25843" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX23418" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX23885" },
|
||||
/* 40-44 */
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX23888" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "SAA7131" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "CX23887" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "SAA7164" },
|
||||
{ TVEEPROM_AUDPROC_INTERNAL, "AU8522" },
|
||||
};
|
||||
|
||||
/* This list is supplied by Hauppauge. Thanks! */
|
||||
static const char *decoderIC[] = {
|
||||
/* 0-4 */
|
||||
"None", "BT815", "BT817", "BT819", "BT815A",
|
||||
/* 5-9 */
|
||||
"BT817A", "BT819A", "BT827", "BT829", "BT848",
|
||||
/* 10-14 */
|
||||
"BT848A", "BT849A", "BT829A", "BT827A", "BT878",
|
||||
/* 15-19 */
|
||||
"BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
|
||||
/* 20-24 */
|
||||
"CX880", "CX881", "CX883", "SAA7111", "SAA7113",
|
||||
/* 25-29 */
|
||||
"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
|
||||
/* 30-34 */
|
||||
"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
|
||||
/* 35-39 */
|
||||
"SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A",
|
||||
/* 40-42 */
|
||||
"SAA7164", "CX23885B", "AU8522"
|
||||
};
|
||||
|
||||
static int hasRadioTuner(int tunerType)
|
||||
{
|
||||
switch (tunerType) {
|
||||
case 18: /* PNPEnv_TUNER_FR1236_MK2 */
|
||||
case 23: /* PNPEnv_TUNER_FM1236 */
|
||||
case 38: /* PNPEnv_TUNER_FMR1236 */
|
||||
case 16: /* PNPEnv_TUNER_FR1216_MK2 */
|
||||
case 19: /* PNPEnv_TUNER_FR1246_MK2 */
|
||||
case 21: /* PNPEnv_TUNER_FM1216 */
|
||||
case 24: /* PNPEnv_TUNER_FM1246 */
|
||||
case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */
|
||||
case 22: /* PNPEnv_TUNER_FM1216MF */
|
||||
case 20: /* PNPEnv_TUNER_FR1256_MK2 */
|
||||
case 25: /* PNPEnv_TUNER_FM1256 */
|
||||
case 33: /* PNPEnv_TUNER_4039FR5 */
|
||||
case 42: /* PNPEnv_TUNER_4009FR5 */
|
||||
case 52: /* PNPEnv_TUNER_4049FM5 */
|
||||
case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */
|
||||
case 44: /* PNPEnv_TUNER_4009FN5 */
|
||||
case 31: /* PNPEnv_TUNER_TCPB9085P */
|
||||
case 30: /* PNPEnv_TUNER_TCPN9085D */
|
||||
case 46: /* PNPEnv_TUNER_TP18NSR01F */
|
||||
case 47: /* PNPEnv_TUNER_TP18PSB01D */
|
||||
case 49: /* PNPEnv_TUNER_TAPC_I001D */
|
||||
case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */
|
||||
case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */
|
||||
case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */
|
||||
case 58: /* PNPEnv_TUNER_FM1236_MK3 */
|
||||
case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */
|
||||
case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */
|
||||
case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */
|
||||
case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */
|
||||
case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */
|
||||
case 105:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
|
||||
unsigned char *eeprom_data)
|
||||
{
|
||||
/* ----------------------------------------------
|
||||
** The hauppauge eeprom format is tagged
|
||||
**
|
||||
** if packet[0] == 0x84, then packet[0..1] == length
|
||||
** else length = packet[0] & 3f;
|
||||
** if packet[0] & f8 == f8, then EOD and packet[1] == checksum
|
||||
**
|
||||
** In our (ivtv) case we're interested in the following:
|
||||
** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner)
|
||||
** tuner fmts: tag [00].04 or [0a].00 (bitmask index into
|
||||
** hauppauge_tuner_fmt)
|
||||
** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM)
|
||||
** audio proc: tag [02].01 or [05].00 (mask with 0x7f)
|
||||
** decoder proc: tag [09].01)
|
||||
|
||||
** Fun info:
|
||||
** model: tag [00].07-08 or [06].00-01
|
||||
** revision: tag [00].09-0b or [06].04-06
|
||||
** serial#: tag [01].05-07 or [04].04-06
|
||||
|
||||
** # of inputs/outputs ???
|
||||
*/
|
||||
|
||||
int i, j, len, done, beenhere, tag, start;
|
||||
|
||||
int tuner1 = 0, t_format1 = 0, audioic = -1;
|
||||
const char *t_name1 = NULL;
|
||||
const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
|
||||
|
||||
int tuner2 = 0, t_format2 = 0;
|
||||
const char *t_name2 = NULL;
|
||||
const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
|
||||
|
||||
memset(tvee, 0, sizeof(*tvee));
|
||||
tvee->tuner_type = TUNER_ABSENT;
|
||||
tvee->tuner2_type = TUNER_ABSENT;
|
||||
|
||||
done = len = beenhere = 0;
|
||||
|
||||
/* Different eeprom start offsets for em28xx, cx2388x and cx23418 */
|
||||
if (eeprom_data[0] == 0x1a &&
|
||||
eeprom_data[1] == 0xeb &&
|
||||
eeprom_data[2] == 0x67 &&
|
||||
eeprom_data[3] == 0x95)
|
||||
start = 0xa0; /* Generic em28xx offset */
|
||||
else if ((eeprom_data[0] & 0xe1) == 0x01 &&
|
||||
eeprom_data[1] == 0x00 &&
|
||||
eeprom_data[2] == 0x00 &&
|
||||
eeprom_data[8] == 0x84)
|
||||
start = 8; /* Generic cx2388x offset */
|
||||
else if (eeprom_data[1] == 0x70 &&
|
||||
eeprom_data[2] == 0x00 &&
|
||||
eeprom_data[4] == 0x74 &&
|
||||
eeprom_data[8] == 0x84)
|
||||
start = 8; /* Generic cx23418 offset (models 74xxx) */
|
||||
else
|
||||
start = 0;
|
||||
|
||||
for (i = start; !done && i < 256; i += len) {
|
||||
if (eeprom_data[i] == 0x84) {
|
||||
len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
|
||||
i += 3;
|
||||
} else if ((eeprom_data[i] & 0xf0) == 0x70) {
|
||||
if (eeprom_data[i] & 0x08) {
|
||||
/* verify checksum! */
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
len = eeprom_data[i] & 0x07;
|
||||
++i;
|
||||
} else {
|
||||
tveeprom_warn("Encountered bad packet header [%02x]. "
|
||||
"Corrupt or not a Hauppauge eeprom.\n",
|
||||
eeprom_data[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
tveeprom_info("Tag [%02x] + %d bytes:",
|
||||
eeprom_data[i], len - 1);
|
||||
for (j = 1; j < len; j++)
|
||||
printk(KERN_CONT " %02x", eeprom_data[i + j]);
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
/* process by tag */
|
||||
tag = eeprom_data[i];
|
||||
switch (tag) {
|
||||
case 0x00:
|
||||
/* tag: 'Comprehensive' */
|
||||
tuner1 = eeprom_data[i+6];
|
||||
t_format1 = eeprom_data[i+5];
|
||||
tvee->has_radio = eeprom_data[i+len-1];
|
||||
/* old style tag, don't know how to detect
|
||||
IR presence, mark as unknown. */
|
||||
tvee->has_ir = 0;
|
||||
tvee->model =
|
||||
eeprom_data[i+8] +
|
||||
(eeprom_data[i+9] << 8);
|
||||
tvee->revision = eeprom_data[i+10] +
|
||||
(eeprom_data[i+11] << 8) +
|
||||
(eeprom_data[i+12] << 16);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
/* tag: 'SerialID' */
|
||||
tvee->serial_number =
|
||||
eeprom_data[i+6] +
|
||||
(eeprom_data[i+7] << 8) +
|
||||
(eeprom_data[i+8] << 16);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
/* tag 'AudioInfo'
|
||||
Note mask with 0x7F, high bit used on some older models
|
||||
to indicate 4052 mux was removed in favor of using MSP
|
||||
inputs directly. */
|
||||
audioic = eeprom_data[i+2] & 0x7f;
|
||||
if (audioic < ARRAY_SIZE(audio_ic))
|
||||
tvee->audio_processor = audio_ic[audioic].id;
|
||||
else
|
||||
tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
|
||||
break;
|
||||
|
||||
/* case 0x03: tag 'EEInfo' */
|
||||
|
||||
case 0x04:
|
||||
/* tag 'SerialID2' */
|
||||
tvee->serial_number =
|
||||
eeprom_data[i+5] +
|
||||
(eeprom_data[i+6] << 8) +
|
||||
(eeprom_data[i+7] << 16);
|
||||
|
||||
if ((eeprom_data[i + 8] & 0xf0) &&
|
||||
(tvee->serial_number < 0xffffff)) {
|
||||
tvee->MAC_address[0] = 0x00;
|
||||
tvee->MAC_address[1] = 0x0D;
|
||||
tvee->MAC_address[2] = 0xFE;
|
||||
tvee->MAC_address[3] = eeprom_data[i + 7];
|
||||
tvee->MAC_address[4] = eeprom_data[i + 6];
|
||||
tvee->MAC_address[5] = eeprom_data[i + 5];
|
||||
tvee->has_MAC_address = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
/* tag 'Audio2'
|
||||
Note mask with 0x7F, high bit used on some older models
|
||||
to indicate 4052 mux was removed in favor of using MSP
|
||||
inputs directly. */
|
||||
audioic = eeprom_data[i+1] & 0x7f;
|
||||
if (audioic < ARRAY_SIZE(audio_ic))
|
||||
tvee->audio_processor = audio_ic[audioic].id;
|
||||
else
|
||||
tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
|
||||
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
/* tag 'ModelRev' */
|
||||
tvee->model =
|
||||
eeprom_data[i + 1] +
|
||||
(eeprom_data[i + 2] << 8) +
|
||||
(eeprom_data[i + 3] << 16) +
|
||||
(eeprom_data[i + 4] << 24);
|
||||
tvee->revision =
|
||||
eeprom_data[i + 5] +
|
||||
(eeprom_data[i + 6] << 8) +
|
||||
(eeprom_data[i + 7] << 16);
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
/* tag 'Details': according to Hauppauge not interesting
|
||||
on any PCI-era or later boards. */
|
||||
break;
|
||||
|
||||
/* there is no tag 0x08 defined */
|
||||
|
||||
case 0x09:
|
||||
/* tag 'Video' */
|
||||
tvee->decoder_processor = eeprom_data[i + 1];
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
/* tag 'Tuner' */
|
||||
if (beenhere == 0) {
|
||||
tuner1 = eeprom_data[i + 2];
|
||||
t_format1 = eeprom_data[i + 1];
|
||||
beenhere = 1;
|
||||
} else {
|
||||
/* a second (radio) tuner may be present */
|
||||
tuner2 = eeprom_data[i + 2];
|
||||
t_format2 = eeprom_data[i + 1];
|
||||
/* not a TV tuner? */
|
||||
if (t_format2 == 0)
|
||||
tvee->has_radio = 1; /* must be radio */
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0b:
|
||||
/* tag 'Inputs': according to Hauppauge this is specific
|
||||
to each driver family, so no good assumptions can be
|
||||
made. */
|
||||
break;
|
||||
|
||||
/* case 0x0c: tag 'Balun' */
|
||||
/* case 0x0d: tag 'Teletext' */
|
||||
|
||||
case 0x0e:
|
||||
/* tag: 'Radio' */
|
||||
tvee->has_radio = eeprom_data[i+1];
|
||||
break;
|
||||
|
||||
case 0x0f:
|
||||
/* tag 'IRInfo' */
|
||||
tvee->has_ir = 1 | (eeprom_data[i+1] << 1);
|
||||
break;
|
||||
|
||||
/* case 0x10: tag 'VBIInfo' */
|
||||
/* case 0x11: tag 'QCInfo' */
|
||||
/* case 0x12: tag 'InfoBits' */
|
||||
|
||||
default:
|
||||
tveeprom_dbg("Not sure what to do with tag [%02x]\n",
|
||||
tag);
|
||||
/* dump the rest of the packet? */
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
tveeprom_warn("Ran out of data!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tvee->revision != 0) {
|
||||
tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
|
||||
tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
|
||||
tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f);
|
||||
tvee->rev_str[3] = 32 + (tvee->revision & 0x3f);
|
||||
tvee->rev_str[4] = 0;
|
||||
}
|
||||
|
||||
if (hasRadioTuner(tuner1) && !tvee->has_radio) {
|
||||
tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
|
||||
tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
|
||||
tvee->has_radio = 1;
|
||||
}
|
||||
|
||||
if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) {
|
||||
tvee->tuner_type = hauppauge_tuner[tuner1].id;
|
||||
t_name1 = hauppauge_tuner[tuner1].name;
|
||||
} else {
|
||||
t_name1 = "unknown";
|
||||
}
|
||||
|
||||
if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) {
|
||||
tvee->tuner2_type = hauppauge_tuner[tuner2].id;
|
||||
t_name2 = hauppauge_tuner[tuner2].name;
|
||||
} else {
|
||||
t_name2 = "unknown";
|
||||
}
|
||||
|
||||
tvee->tuner_hauppauge_model = tuner1;
|
||||
tvee->tuner2_hauppauge_model = tuner2;
|
||||
tvee->tuner_formats = 0;
|
||||
tvee->tuner2_formats = 0;
|
||||
for (i = j = 0; i < 8; i++) {
|
||||
if (t_format1 & (1 << i)) {
|
||||
tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
|
||||
t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
|
||||
}
|
||||
}
|
||||
for (i = j = 0; i < 8; i++) {
|
||||
if (t_format2 & (1 << i)) {
|
||||
tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
|
||||
t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
|
||||
tvee->model, tvee->rev_str, tvee->serial_number);
|
||||
if (tvee->has_MAC_address == 1)
|
||||
tveeprom_info("MAC address is %pM\n", tvee->MAC_address);
|
||||
tveeprom_info("tuner model is %s (idx %d, type %d)\n",
|
||||
t_name1, tuner1, tvee->tuner_type);
|
||||
tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
|
||||
t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2],
|
||||
t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5],
|
||||
t_fmt_name1[6], t_fmt_name1[7], t_format1);
|
||||
if (tuner2)
|
||||
tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
|
||||
t_name2, tuner2, tvee->tuner2_type);
|
||||
if (t_format2)
|
||||
tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
|
||||
t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2],
|
||||
t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5],
|
||||
t_fmt_name2[6], t_fmt_name2[7], t_format2);
|
||||
if (audioic < 0) {
|
||||
tveeprom_info("audio processor is unknown (no idx)\n");
|
||||
tvee->audio_processor = TVEEPROM_AUDPROC_OTHER;
|
||||
} else {
|
||||
if (audioic < ARRAY_SIZE(audio_ic))
|
||||
tveeprom_info("audio processor is %s (idx %d)\n",
|
||||
audio_ic[audioic].name, audioic);
|
||||
else
|
||||
tveeprom_info("audio processor is unknown (idx %d)\n",
|
||||
audioic);
|
||||
}
|
||||
if (tvee->decoder_processor)
|
||||
tveeprom_info("decoder processor is %s (idx %d)\n",
|
||||
STRM(decoderIC, tvee->decoder_processor),
|
||||
tvee->decoder_processor);
|
||||
if (tvee->has_ir)
|
||||
tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n",
|
||||
tvee->has_radio ? "" : "no ",
|
||||
(tvee->has_ir & 2) ? "" : "no ",
|
||||
(tvee->has_ir & 4) ? "" : "no ");
|
||||
else
|
||||
tveeprom_info("has %sradio\n",
|
||||
tvee->has_radio ? "" : "no ");
|
||||
}
|
||||
EXPORT_SYMBOL(tveeprom_hauppauge_analog);
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* generic helper functions */
|
||||
|
||||
int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
|
||||
{
|
||||
unsigned char buf;
|
||||
int err;
|
||||
|
||||
buf = 0;
|
||||
err = i2c_master_send(c, &buf, 1);
|
||||
if (err != 1) {
|
||||
tveeprom_info("Huh, no eeprom present (err=%d)?\n", err);
|
||||
return -1;
|
||||
}
|
||||
err = i2c_master_recv(c, eedata, len);
|
||||
if (err != len) {
|
||||
tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
|
||||
return -1;
|
||||
}
|
||||
if (debug) {
|
||||
int i;
|
||||
|
||||
tveeprom_info("full 256-byte eeprom dump:\n");
|
||||
for (i = 0; i < len; i++) {
|
||||
if (0 == (i % 16))
|
||||
tveeprom_info("%02x:", i);
|
||||
printk(KERN_CONT " %02x", eedata[i]);
|
||||
if (15 == (i % 16))
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tveeprom_read);
|
||||
29
drivers/media/dvb-core/Kconfig
Normal file
29
drivers/media/dvb-core/Kconfig
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
# DVB device configuration
|
||||
#
|
||||
|
||||
config DVB_MAX_ADAPTERS
|
||||
int "maximum number of DVB/ATSC adapters"
|
||||
depends on DVB_CORE
|
||||
default 8
|
||||
range 1 255
|
||||
help
|
||||
Maximum number of DVB/ATSC adapters. Increasing this number
|
||||
increases the memory consumption of the DVB subsystem even
|
||||
if a much lower number of DVB/ATSC adapters is present.
|
||||
Only values in the range 4-32 are tested.
|
||||
|
||||
If you are unsure about this, use the default value 8
|
||||
|
||||
config DVB_DYNAMIC_MINORS
|
||||
bool "Dynamic DVB minor allocation"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
help
|
||||
If you say Y here, the DVB subsystem will use dynamic minor
|
||||
allocation for any device that uses the DVB major number.
|
||||
This means that you can have more than 4 of a single type
|
||||
of device (like demuxes and frontends) per adapter, but udev
|
||||
will be required to manage the device nodes.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
11
drivers/media/dvb-core/Makefile
Normal file
11
drivers/media/dvb-core/Makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Makefile for the kernel DVB device drivers.
|
||||
#
|
||||
|
||||
dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
|
||||
|
||||
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
|
||||
dvb_ca_en50221.o dvb_frontend.o \
|
||||
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o
|
||||
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core.o
|
||||
241
drivers/media/dvb-core/demux.h
Normal file
241
drivers/media/dvb-core/demux.h
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* 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) */
|
||||
#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to
|
||||
the demux device, not to the dvr device */
|
||||
|
||||
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 __user *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 */
|
||||
1271
drivers/media/dvb-core/dmxdev.c
Normal file
1271
drivers/media/dvb-core/dmxdev.c
Normal file
File diff suppressed because it is too large
Load diff
119
drivers/media/dvb-core/dmxdev.h
Normal file
119
drivers/media/dvb-core/dmxdev.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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/time.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.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_feed {
|
||||
u16 pid;
|
||||
struct dmx_ts_feed *ts;
|
||||
struct list_head next;
|
||||
};
|
||||
|
||||
struct dmxdev_filter {
|
||||
union {
|
||||
struct dmx_section_filter *sec;
|
||||
} filter;
|
||||
|
||||
union {
|
||||
/* list of TS and PES feeds (struct dmxdev_feed) */
|
||||
struct list_head 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;
|
||||
|
||||
unsigned int exit:1;
|
||||
#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_ */
|
||||
387
drivers/media/dvb-core/dvb-usb-ids.h
Normal file
387
drivers/media/dvb-core/dvb-usb-ids.h
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
/* 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_AFATECH 0x15a4
|
||||
#define USB_VID_ALCOR_MICRO 0x058f
|
||||
#define USB_VID_ALINK 0x05e3
|
||||
#define USB_VID_AMT 0x1c73
|
||||
#define USB_VID_ANCHOR 0x0547
|
||||
#define USB_VID_ANSONIC 0x10b9
|
||||
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
|
||||
#define USB_VID_ASUS 0x0b05
|
||||
#define USB_VID_AVERMEDIA 0x07ca
|
||||
#define USB_VID_COMPRO 0x185b
|
||||
#define USB_VID_COMPRO_UNK 0x145f
|
||||
#define USB_VID_CONEXANT 0x0572
|
||||
#define USB_VID_CYPRESS 0x04b4
|
||||
#define USB_VID_DEXATEK 0x1d19
|
||||
#define USB_VID_DIBCOM 0x10b8
|
||||
#define USB_VID_DPOSH 0x1498
|
||||
#define USB_VID_DVICO 0x0fe9
|
||||
#define USB_VID_E3C 0x18b4
|
||||
#define USB_VID_ELGATO 0x0fd9
|
||||
#define USB_VID_EMPIA 0xeb1a
|
||||
#define USB_VID_GENPIX 0x09c0
|
||||
#define USB_VID_GRANDTEC 0x5032
|
||||
#define USB_VID_GTEK 0x1f4d
|
||||
#define USB_VID_HANFTEK 0x15f4
|
||||
#define USB_VID_HAUPPAUGE 0x2040
|
||||
#define USB_VID_HYPER_PALTEK 0x1025
|
||||
#define USB_VID_INTEL 0x8086
|
||||
#define USB_VID_ITETECH 0x048d
|
||||
#define USB_VID_KWORLD 0xeb2a
|
||||
#define USB_VID_KWORLD_2 0x1b80
|
||||
#define USB_VID_KYE 0x0458
|
||||
#define USB_VID_LEADTEK 0x0413
|
||||
#define USB_VID_LITEON 0x04ca
|
||||
#define USB_VID_MEDION 0x1660
|
||||
#define USB_VID_MIGLIA 0x18f3
|
||||
#define USB_VID_MSI 0x0db0
|
||||
#define USB_VID_MSI_2 0x1462
|
||||
#define USB_VID_OPERA1 0x695c
|
||||
#define USB_VID_PINNACLE 0x2304
|
||||
#define USB_VID_PCTV 0x2013
|
||||
#define USB_VID_PIXELVIEW 0x1554
|
||||
#define USB_VID_REALTEK 0x0bda
|
||||
#define USB_VID_TECHNOTREND 0x0b48
|
||||
#define USB_VID_TERRATEC 0x0ccd
|
||||
#define USB_VID_TELESTAR 0x10b9
|
||||
#define USB_VID_VISIONPLUS 0x13d3
|
||||
#define USB_VID_SONY 0x1415
|
||||
#define USB_VID_TWINHAN 0x1822
|
||||
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
|
||||
#define USB_VID_UNIWILL 0x1584
|
||||
#define USB_VID_WIDEVIEW 0x14aa
|
||||
#define USB_VID_GIGABYTE 0x1044
|
||||
#define USB_VID_YUAN 0x1164
|
||||
#define USB_VID_XTENSIONS 0x1ae7
|
||||
#define USB_VID_HUMAX_COEX 0x10b9
|
||||
#define USB_VID_774 0x7a69
|
||||
#define USB_VID_EVOLUTEPC 0x1e59
|
||||
#define USB_VID_AZUREWAVE 0x13d3
|
||||
#define USB_VID_TECHNISAT 0x14f7
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
#define USB_PID_ADSTECH_USB2_WARM 0xa334
|
||||
#define USB_PID_AFATECH_AF9005 0x9020
|
||||
#define USB_PID_AFATECH_AF9015_9015 0x9015
|
||||
#define USB_PID_AFATECH_AF9015_9016 0x9016
|
||||
#define USB_PID_AFATECH_AF9035_1000 0x1000
|
||||
#define USB_PID_AFATECH_AF9035_1001 0x1001
|
||||
#define USB_PID_AFATECH_AF9035_1002 0x1002
|
||||
#define USB_PID_AFATECH_AF9035_1003 0x1003
|
||||
#define USB_PID_AFATECH_AF9035_9035 0x9035
|
||||
#define USB_PID_TREKSTOR_DVBT 0x901b
|
||||
#define USB_PID_TREKSTOR_TERRES_2_0 0xC803
|
||||
#define USB_VID_ALINK_DTU 0xf170
|
||||
#define USB_PID_ANSONIC_DVBT_USB 0x6000
|
||||
#define USB_PID_ANYSEE 0x861f
|
||||
#define USB_PID_AZUREWAVE_AD_TU700 0x3237
|
||||
#define USB_PID_AZUREWAVE_6007 0x0ccd
|
||||
#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_COMPRO_VIDEOMATE_U500_PC 0x1e80
|
||||
#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397
|
||||
#define USB_PID_CONEXANT_D680_DMB 0x86d6
|
||||
#define USB_PID_CREATIX_CTX1921 0x1921
|
||||
#define USB_PID_DELOCK_USB2_DVBT 0xb803
|
||||
#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_STK7700D 0x1ef0
|
||||
#define USB_PID_DIBCOM_STK7700_U7000 0x7001
|
||||
#define USB_PID_DIBCOM_STK7070P 0x1ebc
|
||||
#define USB_PID_DIBCOM_STK7070PD 0x1ebe
|
||||
#define USB_PID_DIBCOM_STK807XP 0x1f90
|
||||
#define USB_PID_DIBCOM_STK807XPVR 0x1f98
|
||||
#define USB_PID_DIBCOM_STK8096GP 0x1fa0
|
||||
#define USB_PID_DIBCOM_NIM8096MD 0x1fa8
|
||||
#define USB_PID_DIBCOM_TFE8096P 0x1f9C
|
||||
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
|
||||
#define USB_PID_DIBCOM_STK7770P 0x1e80
|
||||
#define USB_PID_DIBCOM_NIM7090 0x1bb2
|
||||
#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4
|
||||
#define USB_PID_DIBCOM_TFE7790P 0x1e6e
|
||||
#define USB_PID_DIBCOM_NIM9090M 0x2383
|
||||
#define USB_PID_DIBCOM_NIM9090MD 0x2384
|
||||
#define USB_PID_DPOSH_M9206_COLD 0x9206
|
||||
#define USB_PID_DPOSH_M9206_WARM 0xa090
|
||||
#define USB_PID_E3C_EC168 0x1689
|
||||
#define USB_PID_E3C_EC168_2 0xfffa
|
||||
#define USB_PID_E3C_EC168_3 0xfffb
|
||||
#define USB_PID_E3C_EC168_4 0x1001
|
||||
#define USB_PID_E3C_EC168_5 0x1002
|
||||
#define USB_PID_FREECOM_DVBT 0x0160
|
||||
#define USB_PID_FREECOM_DVBT_2 0x0161
|
||||
#define USB_PID_UNIWILL_STK7700P 0x6003
|
||||
#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
|
||||
#define USB_PID_INTEL_CE9500 0x9500
|
||||
#define USB_PID_ITETECH_IT9135 0x9135
|
||||
#define USB_PID_ITETECH_IT9135_9005 0x9005
|
||||
#define USB_PID_ITETECH_IT9135_9006 0x9006
|
||||
#define USB_PID_ITETECH_IT9303 0x9306
|
||||
#define USB_PID_KWORLD_399U 0xe399
|
||||
#define USB_PID_KWORLD_399U_2 0xe400
|
||||
#define USB_PID_KWORLD_395U 0xe396
|
||||
#define USB_PID_KWORLD_395U_2 0xe39b
|
||||
#define USB_PID_KWORLD_395U_3 0xe395
|
||||
#define USB_PID_KWORLD_395U_4 0xe39a
|
||||
#define USB_PID_KWORLD_MC810 0xc810
|
||||
#define USB_PID_KWORLD_PC160_2T 0xc160
|
||||
#define USB_PID_KWORLD_PC160_T 0xc161
|
||||
#define USB_PID_KWORLD_UB383_T 0xe383
|
||||
#define USB_PID_KWORLD_UB499_2T_T09 0xe409
|
||||
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
|
||||
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
|
||||
#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093
|
||||
#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
|
||||
#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099
|
||||
#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1 0x00a9
|
||||
#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_TWINHAN_VP7049 0x3219
|
||||
#define USB_PID_TINYTWIN 0x3226
|
||||
#define USB_PID_TINYTWIN_2 0xe402
|
||||
#define USB_PID_TINYTWIN_3 0x9016
|
||||
#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_ARTEC_T14BR 0x810f
|
||||
#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_500_3 0x8400
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
|
||||
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070
|
||||
#define USB_PID_HAUPPAUGE_MYTV_T 0x7080
|
||||
#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580
|
||||
#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200
|
||||
#define USB_PID_HAUPPAUGE_TIGER_ATSC 0xb200
|
||||
#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210 0xb210
|
||||
#define USB_PID_AVERMEDIA_EXPRESS 0xb568
|
||||
#define USB_PID_AVERMEDIA_VOLAR 0xa807
|
||||
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
|
||||
#define USB_PID_AVERMEDIA_VOLAR_A868R 0xa868
|
||||
#define USB_PID_AVERMEDIA_MCE_USB_M038 0x1228
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039
|
||||
#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039
|
||||
#define USB_PID_AVERMEDIA_VOLAR_X 0xa815
|
||||
#define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150
|
||||
#define USB_PID_AVERMEDIA_A309 0xa309
|
||||
#define USB_PID_AVERMEDIA_A310 0xa310
|
||||
#define USB_PID_AVERMEDIA_A850 0x850a
|
||||
#define USB_PID_AVERMEDIA_A850T 0x850b
|
||||
#define USB_PID_AVERMEDIA_A805 0xa805
|
||||
#define USB_PID_AVERMEDIA_A815M 0x815a
|
||||
#define USB_PID_AVERMEDIA_A835 0xa835
|
||||
#define USB_PID_AVERMEDIA_B835 0xb835
|
||||
#define USB_PID_AVERMEDIA_A835B_1835 0x1835
|
||||
#define USB_PID_AVERMEDIA_A835B_2835 0x2835
|
||||
#define USB_PID_AVERMEDIA_A835B_3835 0x3835
|
||||
#define USB_PID_AVERMEDIA_A835B_4835 0x4835
|
||||
#define USB_PID_AVERMEDIA_1867 0x1867
|
||||
#define USB_PID_AVERMEDIA_A867 0xa867
|
||||
#define USB_PID_AVERMEDIA_H335 0x0335
|
||||
#define USB_PID_AVERMEDIA_TWINSTAR 0x0825
|
||||
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
|
||||
#define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009
|
||||
#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
|
||||
#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012
|
||||
#define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014
|
||||
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
|
||||
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
|
||||
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
|
||||
#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060
|
||||
#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062
|
||||
#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
|
||||
#define USB_PID_TERRATEC_CINERGY_T_XXS_2 0x00ab
|
||||
#define USB_PID_TERRATEC_H7 0x10b4
|
||||
#define USB_PID_TERRATEC_H7_2 0x10a3
|
||||
#define USB_PID_TERRATEC_T3 0x10a0
|
||||
#define USB_PID_TERRATEC_T5 0x10a1
|
||||
#define USB_PID_NOXON_DAB_STICK 0x00b3
|
||||
#define USB_PID_NOXON_DAB_STICK_REV2 0x00e0
|
||||
#define USB_PID_NOXON_DAB_STICK_REV3 0x00b4
|
||||
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
|
||||
#define USB_PID_PINNACLE_PCTV2000E 0x022c
|
||||
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
|
||||
#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229
|
||||
#define USB_PID_PINNACLE_PCTV71E 0x022b
|
||||
#define USB_PID_PINNACLE_PCTV72E 0x0236
|
||||
#define USB_PID_PINNACLE_PCTV73E 0x0237
|
||||
#define USB_PID_PINNACLE_PCTV310E 0x3211
|
||||
#define USB_PID_PINNACLE_PCTV801E 0x023a
|
||||
#define USB_PID_PINNACLE_PCTV801E_SE 0x023b
|
||||
#define USB_PID_PINNACLE_PCTV340E 0x023d
|
||||
#define USB_PID_PINNACLE_PCTV340E_SE 0x023e
|
||||
#define USB_PID_PINNACLE_PCTV73A 0x0243
|
||||
#define USB_PID_PINNACLE_PCTV73ESE 0x0245
|
||||
#define USB_PID_PINNACLE_PCTV74E 0x0246
|
||||
#define USB_PID_PINNACLE_PCTV282E 0x0248
|
||||
#define USB_PID_PIXELVIEW_SBTVD 0x5010
|
||||
#define USB_PID_PCTV_200E 0x020e
|
||||
#define USB_PID_PCTV_400E 0x020f
|
||||
#define USB_PID_PCTV_450E 0x0222
|
||||
#define USB_PID_PCTV_452E 0x021f
|
||||
#define USB_PID_PCTV_78E 0x025a
|
||||
#define USB_PID_PCTV_79E 0x0262
|
||||
#define USB_PID_REALTEK_RTL2831U 0x2831
|
||||
#define USB_PID_REALTEK_RTL2832U 0x2832
|
||||
#define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007
|
||||
#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a
|
||||
#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_DVICO_BLUEBIRD_DUAL_4 0xdb78
|
||||
#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98
|
||||
#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70
|
||||
#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71
|
||||
#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_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_DTV2000DS 0x6a04
|
||||
#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_WINFAST_DTV_DONGLE_H 0x60f6
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_MINID 0x6f0f
|
||||
#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
|
||||
#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201
|
||||
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
|
||||
#define USB_PID_GENPIX_SKYWALKER_1 0x0203
|
||||
#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
|
||||
#define USB_PID_GENPIX_SKYWALKER_2 0x0206
|
||||
#define USB_PID_SIGMATEK_DVB_110 0x6610
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
|
||||
#define USB_PID_MSI_DIGIVOX_DUO 0x8801
|
||||
#define USB_PID_OPERA1_COLD 0x2830
|
||||
#define USB_PID_OPERA1_WARM 0x3829
|
||||
#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514
|
||||
#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513
|
||||
#define USB_PID_GIGABYTE_U7000 0x7001
|
||||
#define USB_PID_GIGABYTE_U8000 0x7002
|
||||
#define USB_PID_ASUS_U3000 0x171f
|
||||
#define USB_PID_ASUS_U3000H 0x1736
|
||||
#define USB_PID_ASUS_U3100 0x173f
|
||||
#define USB_PID_ASUS_U3100MINI_PLUS 0x1779
|
||||
#define USB_PID_YUAN_EC372S 0x1edc
|
||||
#define USB_PID_YUAN_STK7700PH 0x1f08
|
||||
#define USB_PID_YUAN_PD378S 0x2edc
|
||||
#define USB_PID_YUAN_MC770 0x0871
|
||||
#define USB_PID_YUAN_STK7700D 0x1efc
|
||||
#define USB_PID_YUAN_STK7700D_2 0x1e8c
|
||||
#define USB_PID_DW2102 0x2102
|
||||
#define USB_PID_XTENSIONS_XD_380 0x0381
|
||||
#define USB_PID_TELESTAR_STARSTICK_2 0x8000
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
|
||||
#define USB_PID_SONY_PLAYTV 0x0003
|
||||
#define USB_PID_MYGICA_D689 0xd811
|
||||
#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011
|
||||
#define USB_PID_ELGATO_EYETV_DTT 0x0021
|
||||
#define USB_PID_ELGATO_EYETV_DTT_2 0x003f
|
||||
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
|
||||
#define USB_PID_ELGATO_EYETV_SAT 0x002a
|
||||
#define USB_PID_ELGATO_EYETV_SAT_V2 0x0025
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
|
||||
#define USB_PID_FRIIO_WHITE 0x0001
|
||||
#define USB_PID_TVWAY_PLUS 0x0002
|
||||
#define USB_PID_SVEON_STV20 0xe39d
|
||||
#define USB_PID_SVEON_STV20_RTL2832U 0xd39d
|
||||
#define USB_PID_SVEON_STV21 0xd3b0
|
||||
#define USB_PID_SVEON_STV22 0xe401
|
||||
#define USB_PID_SVEON_STV22_IT9137 0xe411
|
||||
#define USB_PID_AZUREWAVE_AZ6027 0x3275
|
||||
#define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4
|
||||
#define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac
|
||||
#define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001
|
||||
#define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002
|
||||
#define USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI 0x0003
|
||||
#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004
|
||||
#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500
|
||||
#define USB_PID_CPYTO_REDI_PC50A 0xa803
|
||||
#define USB_PID_CTVDIGDUAL_V2 0xe410
|
||||
#define USB_PID_PCTV_2002E 0x025c
|
||||
#define USB_PID_PCTV_2002E_SE 0x025d
|
||||
#define USB_PID_SVEON_STV27 0xd3af
|
||||
#endif
|
||||
1765
drivers/media/dvb-core/dvb_ca_en50221.c
Normal file
1765
drivers/media/dvb-core/dvb_ca_en50221.c
Normal file
File diff suppressed because it is too large
Load diff
136
drivers/media/dvb-core/dvb_ca_en50221.h
Normal file
136
drivers/media/dvb-core/dvb_ca_en50221.h
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 will be
|
||||
* called for different slots concurrently and need to use locks where
|
||||
* and if appropriate. There will be no concurrent access to one slot.
|
||||
*/
|
||||
|
||||
/* 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
|
||||
1330
drivers/media/dvb-core/dvb_demux.c
Normal file
1330
drivers/media/dvb-core/dvb_demux.c
Normal file
File diff suppressed because it is too large
Load diff
151
drivers/media/dvb-core/dvb_demux.h
Normal file
151
drivers/media/dvb-core/dvb_demux.h
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#define MAX_PID 0x1fff
|
||||
|
||||
#define SPEED_PKTS_INTERVAL 50000
|
||||
|
||||
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_PES_OTHER];
|
||||
u16 pids[DMX_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;
|
||||
|
||||
uint8_t *cnt_storage; /* for TS continuity check */
|
||||
|
||||
struct timespec speed_last_time; /* for TS speed check */
|
||||
uint32_t speed_pkts_cnt; /* for TS speed check */
|
||||
};
|
||||
|
||||
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);
|
||||
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
|
||||
size_t count);
|
||||
|
||||
#endif /* _DVB_DEMUX_H_ */
|
||||
603
drivers/media/dvb-core/dvb_filter.c
Normal file
603
drivers/media/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-core/dvb_filter.h
Normal file
246
drivers/media/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
|
||||
2721
drivers/media/dvb-core/dvb_frontend.c
Normal file
2721
drivers/media/dvb-core/dvb_frontend.c
Normal file
File diff suppressed because it is too large
Load diff
445
drivers/media/dvb-core/dvb_frontend.h
Normal file
445
drivers/media/dvb-core/dvb_frontend.h
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* 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/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
|
||||
/*
|
||||
* Maximum number of Delivery systems per frontend. It
|
||||
* should be smaller or equal to 32
|
||||
*/
|
||||
#define MAX_DELSYS 8
|
||||
|
||||
struct dvb_frontend_tune_settings {
|
||||
int min_delay_ms;
|
||||
int step_size;
|
||||
int max_drift;
|
||||
};
|
||||
|
||||
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 analog_parameters {
|
||||
unsigned int frequency;
|
||||
unsigned int mode;
|
||||
unsigned int audmode;
|
||||
u64 std;
|
||||
};
|
||||
|
||||
enum dvbfe_modcod {
|
||||
DVBFE_MODCOD_DUMMY_PLFRAME = 0,
|
||||
DVBFE_MODCOD_QPSK_1_4,
|
||||
DVBFE_MODCOD_QPSK_1_3,
|
||||
DVBFE_MODCOD_QPSK_2_5,
|
||||
DVBFE_MODCOD_QPSK_1_2,
|
||||
DVBFE_MODCOD_QPSK_3_5,
|
||||
DVBFE_MODCOD_QPSK_2_3,
|
||||
DVBFE_MODCOD_QPSK_3_4,
|
||||
DVBFE_MODCOD_QPSK_4_5,
|
||||
DVBFE_MODCOD_QPSK_5_6,
|
||||
DVBFE_MODCOD_QPSK_8_9,
|
||||
DVBFE_MODCOD_QPSK_9_10,
|
||||
DVBFE_MODCOD_8PSK_3_5,
|
||||
DVBFE_MODCOD_8PSK_2_3,
|
||||
DVBFE_MODCOD_8PSK_3_4,
|
||||
DVBFE_MODCOD_8PSK_5_6,
|
||||
DVBFE_MODCOD_8PSK_8_9,
|
||||
DVBFE_MODCOD_8PSK_9_10,
|
||||
DVBFE_MODCOD_16APSK_2_3,
|
||||
DVBFE_MODCOD_16APSK_3_4,
|
||||
DVBFE_MODCOD_16APSK_4_5,
|
||||
DVBFE_MODCOD_16APSK_5_6,
|
||||
DVBFE_MODCOD_16APSK_8_9,
|
||||
DVBFE_MODCOD_16APSK_9_10,
|
||||
DVBFE_MODCOD_32APSK_3_4,
|
||||
DVBFE_MODCOD_32APSK_4_5,
|
||||
DVBFE_MODCOD_32APSK_5_6,
|
||||
DVBFE_MODCOD_32APSK_8_9,
|
||||
DVBFE_MODCOD_32APSK_9_10,
|
||||
DVBFE_MODCOD_RESERVED_1,
|
||||
DVBFE_MODCOD_BPSK_1_3,
|
||||
DVBFE_MODCOD_BPSK_1_4,
|
||||
DVBFE_MODCOD_RESERVED_2
|
||||
};
|
||||
|
||||
enum tuner_param {
|
||||
DVBFE_TUNER_FREQUENCY = (1 << 0),
|
||||
DVBFE_TUNER_TUNERSTEP = (1 << 1),
|
||||
DVBFE_TUNER_IFFREQ = (1 << 2),
|
||||
DVBFE_TUNER_BANDWIDTH = (1 << 3),
|
||||
DVBFE_TUNER_REFCLOCK = (1 << 4),
|
||||
DVBFE_TUNER_IQSENSE = (1 << 5),
|
||||
DVBFE_TUNER_DUMMY = (1 << 31)
|
||||
};
|
||||
|
||||
/*
|
||||
* ALGO_HW: (Hardware Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* Devices that support this algorithm do everything in hardware
|
||||
* and no software support is needed to handle them.
|
||||
* Requesting these devices to LOCK is the only thing required,
|
||||
* device is supposed to do everything in the hardware.
|
||||
*
|
||||
* ALGO_SW: (Software Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* These are dumb devices, that require software to do everything
|
||||
*
|
||||
* ALGO_CUSTOM: (Customizable Agorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* Devices having this algorithm can be customized to have specific
|
||||
* algorithms in the frontend driver, rather than simply doing a
|
||||
* software zig-zag. In this case the zigzag maybe hardware assisted
|
||||
* or it maybe completely done in hardware. In all cases, usage of
|
||||
* this algorithm, in conjunction with the search and track
|
||||
* callbacks, utilizes the driver specific algorithm.
|
||||
*
|
||||
* ALGO_RECOVERY: (Recovery Algorithm)
|
||||
* ----------------------------------------------------------------
|
||||
* These devices have AUTO recovery capabilities from LOCK failure
|
||||
*/
|
||||
enum dvbfe_algo {
|
||||
DVBFE_ALGO_HW = (1 << 0),
|
||||
DVBFE_ALGO_SW = (1 << 1),
|
||||
DVBFE_ALGO_CUSTOM = (1 << 2),
|
||||
DVBFE_ALGO_RECOVERY = (1 << 31)
|
||||
};
|
||||
|
||||
struct tuner_state {
|
||||
u32 frequency;
|
||||
u32 tunerstep;
|
||||
u32 ifreq;
|
||||
u32 bandwidth;
|
||||
u32 iqsense;
|
||||
u32 refclock;
|
||||
};
|
||||
|
||||
/*
|
||||
* search callback possible return status
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_SUCCESS
|
||||
* The frontend search algorithm completed and returned successfully
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_ASLEEP
|
||||
* The frontend search algorithm is sleeping
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_FAILED
|
||||
* The frontend search for a signal failed
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_INVALID
|
||||
* The frontend search algorith was probably supplied with invalid
|
||||
* parameters and the search is an invalid one
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_ERROR
|
||||
* The frontend search algorithm failed due to some error
|
||||
*
|
||||
* DVBFE_ALGO_SEARCH_AGAIN
|
||||
* The frontend search algorithm was requested to search again
|
||||
*/
|
||||
enum dvbfe_search {
|
||||
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
|
||||
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
|
||||
DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
|
||||
DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
|
||||
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
|
||||
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
int (*suspend)(struct dvb_frontend *fe);
|
||||
int (*resume)(struct dvb_frontend *fe);
|
||||
|
||||
/** This is for simple PLLs - set all parameters in one go. */
|
||||
int (*set_params)(struct dvb_frontend *fe);
|
||||
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_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, u8 *buf, int buf_len);
|
||||
|
||||
/** This is to allow setting tuner-specific configs */
|
||||
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
|
||||
|
||||
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
|
||||
int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
|
||||
|
||||
#define TUNER_STATUS_LOCKED 1
|
||||
#define TUNER_STATUS_STEREO 2
|
||||
int (*get_status)(struct dvb_frontend *fe, u32 *status);
|
||||
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
|
||||
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
|
||||
|
||||
/** These are provided separately from set_params in order to facilitate silicon
|
||||
* tuners which require sophisticated tuning loops, controlling each parameter separately. */
|
||||
int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
|
||||
int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
|
||||
|
||||
/*
|
||||
* These are provided separately from set_params in order to facilitate silicon
|
||||
* tuners which require sophisticated tuning loops, controlling each parameter separately.
|
||||
*/
|
||||
int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
|
||||
int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
|
||||
};
|
||||
|
||||
struct analog_demod_info {
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct analog_demod_ops {
|
||||
|
||||
struct analog_demod_info info;
|
||||
|
||||
void (*set_params)(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params);
|
||||
int (*has_signal)(struct dvb_frontend *fe, u16 *signal);
|
||||
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
|
||||
void (*tuner_status)(struct dvb_frontend *fe);
|
||||
void (*standby)(struct dvb_frontend *fe);
|
||||
void (*release)(struct dvb_frontend *fe);
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
|
||||
|
||||
/** This is to allow setting tuner-specific configuration */
|
||||
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
|
||||
};
|
||||
|
||||
struct dtv_frontend_properties;
|
||||
|
||||
struct dvb_frontend_ops {
|
||||
|
||||
struct dvb_frontend_info info;
|
||||
|
||||
u8 delsys[MAX_DELSYS];
|
||||
|
||||
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, const u8 buf[], int len);
|
||||
|
||||
/* if this is set, it overrides the default swzigzag */
|
||||
int (*tune)(struct dvb_frontend* fe,
|
||||
bool re_tune,
|
||||
unsigned int mode_flags,
|
||||
unsigned int *delay,
|
||||
fe_status_t *status);
|
||||
/* get frontend tuning algorithm from the module */
|
||||
enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
|
||||
|
||||
/* these two are only used for the swzigzag code */
|
||||
int (*set_frontend)(struct dvb_frontend *fe);
|
||||
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
|
||||
|
||||
int (*get_frontend)(struct dvb_frontend *fe);
|
||||
|
||||
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);
|
||||
int (*set_lna)(struct dvb_frontend *);
|
||||
|
||||
/* These callbacks are for devices that implement their own
|
||||
* tuning algorithms, rather than a simple swzigzag
|
||||
*/
|
||||
enum dvbfe_search (*search)(struct dvb_frontend *fe);
|
||||
|
||||
struct dvb_tuner_ops tuner_ops;
|
||||
struct analog_demod_ops analog_ops;
|
||||
|
||||
int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
};
|
||||
|
||||
#ifdef __DVB_CORE__
|
||||
#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 mutex mtx;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct dtv_frontend_properties {
|
||||
|
||||
/* Cache State */
|
||||
u32 state;
|
||||
|
||||
u32 frequency;
|
||||
fe_modulation_t modulation;
|
||||
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t sectone;
|
||||
fe_spectral_inversion_t inversion;
|
||||
fe_code_rate_t fec_inner;
|
||||
fe_transmit_mode_t transmission_mode;
|
||||
u32 bandwidth_hz; /* 0 = AUTO */
|
||||
fe_guard_interval_t guard_interval;
|
||||
fe_hierarchy_t hierarchy;
|
||||
u32 symbol_rate;
|
||||
fe_code_rate_t code_rate_HP;
|
||||
fe_code_rate_t code_rate_LP;
|
||||
|
||||
fe_pilot_t pilot;
|
||||
fe_rolloff_t rolloff;
|
||||
|
||||
fe_delivery_system_t delivery_system;
|
||||
|
||||
enum fe_interleaving interleaving;
|
||||
|
||||
/* ISDB-T specifics */
|
||||
u8 isdbt_partial_reception;
|
||||
u8 isdbt_sb_mode;
|
||||
u8 isdbt_sb_subchannel;
|
||||
u32 isdbt_sb_segment_idx;
|
||||
u32 isdbt_sb_segment_count;
|
||||
u8 isdbt_layer_enabled;
|
||||
struct {
|
||||
u8 segment_count;
|
||||
fe_code_rate_t fec;
|
||||
fe_modulation_t modulation;
|
||||
u8 interleaving;
|
||||
} layer[3];
|
||||
|
||||
/* Multistream specifics */
|
||||
u32 stream_id;
|
||||
|
||||
/* ATSC-MH specifics */
|
||||
u8 atscmh_fic_ver;
|
||||
u8 atscmh_parade_id;
|
||||
u8 atscmh_nog;
|
||||
u8 atscmh_tnog;
|
||||
u8 atscmh_sgn;
|
||||
u8 atscmh_prc;
|
||||
|
||||
u8 atscmh_rs_frame_mode;
|
||||
u8 atscmh_rs_frame_ensemble;
|
||||
u8 atscmh_rs_code_mode_pri;
|
||||
u8 atscmh_rs_code_mode_sec;
|
||||
u8 atscmh_sccc_block_mode;
|
||||
u8 atscmh_sccc_code_mode_a;
|
||||
u8 atscmh_sccc_code_mode_b;
|
||||
u8 atscmh_sccc_code_mode_c;
|
||||
u8 atscmh_sccc_code_mode_d;
|
||||
|
||||
u32 lna;
|
||||
|
||||
/* statistics data */
|
||||
struct dtv_fe_stats strength;
|
||||
struct dtv_fe_stats cnr;
|
||||
struct dtv_fe_stats pre_bit_error;
|
||||
struct dtv_fe_stats pre_bit_count;
|
||||
struct dtv_fe_stats post_bit_error;
|
||||
struct dtv_fe_stats post_bit_count;
|
||||
struct dtv_fe_stats block_error;
|
||||
struct dtv_fe_stats block_count;
|
||||
};
|
||||
|
||||
#define DVB_FE_NO_EXIT 0
|
||||
#define DVB_FE_NORMAL_EXIT 1
|
||||
#define DVB_FE_DEVICE_REMOVED 2
|
||||
#define DVB_FE_DEVICE_RESUME 3
|
||||
|
||||
struct dvb_frontend {
|
||||
struct dvb_frontend_ops ops;
|
||||
struct dvb_adapter *dvb;
|
||||
void *demodulator_priv;
|
||||
void *tuner_priv;
|
||||
void *frontend_priv;
|
||||
void *sec_priv;
|
||||
void *analog_demod_priv;
|
||||
struct dtv_frontend_properties dtv_property_cache;
|
||||
#define DVB_FRONTEND_COMPONENT_TUNER 0
|
||||
#define DVB_FRONTEND_COMPONENT_DEMOD 1
|
||||
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
|
||||
int id;
|
||||
unsigned int exit;
|
||||
};
|
||||
|
||||
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 int dvb_frontend_suspend(struct dvb_frontend *fe);
|
||||
extern int dvb_frontend_resume(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-core/dvb_math.c
Normal file
145
drivers/media/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-core/dvb_math.h
Normal file
58
drivers/media/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
|
||||
1541
drivers/media/dvb-core/dvb_net.c
Normal file
1541
drivers/media/dvb-core/dvb_net.c
Normal file
File diff suppressed because it is too large
Load diff
67
drivers/media/dvb-core/dvb_net.h
Normal file
67
drivers/media/dvb-core/dvb_net.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#ifdef CONFIG_DVB_NET
|
||||
|
||||
struct dvb_net {
|
||||
struct dvb_device *dvbdev;
|
||||
struct net_device *device[DVB_NET_DEVICES_MAX];
|
||||
int state[DVB_NET_DEVICES_MAX];
|
||||
unsigned int exit:1;
|
||||
struct dmx_demux *demux;
|
||||
struct mutex ioctl_mutex;
|
||||
};
|
||||
|
||||
void dvb_net_release(struct dvb_net *);
|
||||
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
|
||||
|
||||
#else
|
||||
|
||||
struct dvb_net {
|
||||
struct dvb_device *dvbdev;
|
||||
};
|
||||
|
||||
static inline void dvb_net_release(struct dvb_net *dvbnet)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dvb_net_init(struct dvb_adapter *adap,
|
||||
struct dvb_net *dvbnet, struct dmx_demux *dmx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ifdef CONFIG_DVB_NET */
|
||||
|
||||
#endif
|
||||
325
drivers/media/dvb-core/dvb_ringbuffer.c
Normal file
325
drivers/media/dvb-core/dvb_ringbuffer.c
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_flush);
|
||||
|
||||
void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
|
||||
{
|
||||
rbuf->pread = rbuf->pwrite = 0;
|
||||
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_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
|
||||
{
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
|
||||
if (split > 0) {
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pread = 0;
|
||||
}
|
||||
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
|
||||
return -EFAULT;
|
||||
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
|
||||
{
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
|
||||
if (split > 0) {
|
||||
memcpy(buf, rbuf->data+rbuf->pread, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pread = 0;
|
||||
}
|
||||
memcpy(buf, rbuf->data+rbuf->pread, todo);
|
||||
|
||||
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
|
||||
}
|
||||
|
||||
|
||||
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_write_user(struct dvb_ringbuffer *rbuf,
|
||||
const u8 __user *buf, size_t len)
|
||||
{
|
||||
int status;
|
||||
size_t todo = len;
|
||||
size_t split;
|
||||
|
||||
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
|
||||
|
||||
if (split > 0) {
|
||||
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
|
||||
if (status)
|
||||
return len - todo;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
rbuf->pwrite = 0;
|
||||
}
|
||||
status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
|
||||
if (status)
|
||||
return len - 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_user(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 __user *buf, size_t len)
|
||||
{
|
||||
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 (copy_to_user(buf, rbuf->data+idx, split))
|
||||
return -EFAULT;
|
||||
buf += split;
|
||||
todo -= split;
|
||||
idx = 0;
|
||||
}
|
||||
if (copy_to_user(buf, rbuf->data+idx, todo))
|
||||
return -EFAULT;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8* buf, size_t len)
|
||||
{
|
||||
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) {
|
||||
memcpy(buf, rbuf->data+idx, split);
|
||||
buf += split;
|
||||
todo -= split;
|
||||
idx = 0;
|
||||
}
|
||||
memcpy(buf, rbuf->data+idx, todo);
|
||||
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_spinlock_wakeup);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read_user);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_read);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_write);
|
||||
EXPORT_SYMBOL(dvb_ringbuffer_write_user);
|
||||
188
drivers/media/dvb-core/dvb_ringbuffer.h
Normal file
188
drivers/media/dvb-core/dvb_ringbuffer.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
*
|
||||
* 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));
|
||||
** 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.
|
||||
** Resetting the buffer counts as a read and write 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);
|
||||
|
||||
|
||||
/*
|
||||
** Reset the read and write pointers to zero and flush the buffer
|
||||
** This counts as a read and write operation
|
||||
*/
|
||||
extern void dvb_ringbuffer_reset(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_user(struct dvb_ringbuffer *rbuf,
|
||||
u8 __user *buf, size_t len);
|
||||
extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
|
||||
u8 *buf, size_t len);
|
||||
|
||||
|
||||
/* 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);
|
||||
extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
|
||||
const u8 __user *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_user(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 __user *buf, size_t len);
|
||||
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
|
||||
int offset, u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* 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_ */
|
||||
498
drivers/media/dvb-core/dvbdev.c
Normal file
498
drivers/media/dvb-core/dvbdev.c
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* 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/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 DEFINE_MUTEX(dvbdev_mutex);
|
||||
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"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
#define MAX_DVB_MINORS 256
|
||||
#define DVB_MAX_IDS MAX_DVB_MINORS
|
||||
#else
|
||||
#define DVB_MAX_IDS 4
|
||||
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
|
||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
||||
#endif
|
||||
|
||||
static struct class *dvb_class;
|
||||
|
||||
static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
|
||||
static DECLARE_RWSEM(minor_rwsem);
|
||||
|
||||
static int dvb_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
|
||||
mutex_lock(&dvbdev_mutex);
|
||||
down_read(&minor_rwsem);
|
||||
dvbdev = dvb_minors[iminor(inode)];
|
||||
|
||||
if (dvbdev && dvbdev->fops) {
|
||||
int err = 0;
|
||||
const struct file_operations *new_fops;
|
||||
|
||||
new_fops = fops_get(dvbdev->fops);
|
||||
if (!new_fops)
|
||||
goto fail;
|
||||
file->private_data = dvbdev;
|
||||
replace_fops(file, new_fops);
|
||||
if (file->f_op->open)
|
||||
err = file->f_op->open(inode,file);
|
||||
up_read(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_mutex);
|
||||
return err;
|
||||
}
|
||||
fail:
|
||||
up_read(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
static const struct file_operations dvb_device_fops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.open = dvb_device_open,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct cdev dvb_device_cdev;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
long dvb_generic_ioctl(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(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 dvb_device *dev;
|
||||
list_for_each_entry(dev, &adap->device_list, 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;
|
||||
struct device *clsdev;
|
||||
int minor;
|
||||
int id;
|
||||
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
|
||||
if ((id = dvbdev_get_free_id (adap, type)) < 0){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
*pdvbdev = NULL;
|
||||
printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
|
||||
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;
|
||||
init_waitqueue_head (&dvbdev->wait_queue);
|
||||
|
||||
memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
|
||||
dvbdevfops->owner = adap->module;
|
||||
|
||||
list_add_tail (&dvbdev->list_head, &adap->device_list);
|
||||
|
||||
down_write(&minor_rwsem);
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
|
||||
if (dvb_minors[minor] == NULL)
|
||||
break;
|
||||
|
||||
if (minor == MAX_DVB_MINORS) {
|
||||
kfree(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
up_write(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
#else
|
||||
minor = nums2minor(adap->num, type, id);
|
||||
#endif
|
||||
|
||||
dvbdev->minor = minor;
|
||||
dvb_minors[minor] = dvbdev;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
|
||||
clsdev = device_create(dvb_class, adap->device,
|
||||
MKDEV(DVB_MAJOR, minor),
|
||||
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
|
||||
if (IS_ERR(clsdev)) {
|
||||
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
|
||||
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
|
||||
return PTR_ERR(clsdev);
|
||||
}
|
||||
|
||||
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
|
||||
adap->num, dnames[type], id, minor, minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_register_device);
|
||||
|
||||
|
||||
void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||
{
|
||||
if (!dvbdev)
|
||||
return;
|
||||
|
||||
down_write(&minor_rwsem);
|
||||
dvb_minors[dvbdev->minor] = NULL;
|
||||
up_write(&minor_rwsem);
|
||||
|
||||
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
|
||||
|
||||
list_del (&dvbdev->list_head);
|
||||
kfree (dvbdev->fops);
|
||||
kfree (dvbdev);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_unregister_device);
|
||||
|
||||
static int dvbdev_check_free_adapter_num(int num)
|
||||
{
|
||||
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)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dvbdev_get_free_adapter_num (void)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
while (num < DVB_MAX_ADAPTERS) {
|
||||
if (dvbdev_check_free_adapter_num(num))
|
||||
return num;
|
||||
num++;
|
||||
}
|
||||
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
|
||||
int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
struct module *module, struct device *device,
|
||||
short *adapter_nums)
|
||||
{
|
||||
int i, num;
|
||||
|
||||
mutex_lock(&dvbdev_register_lock);
|
||||
|
||||
for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
|
||||
num = adapter_nums[i];
|
||||
if (num >= 0 && num < DVB_MAX_ADAPTERS) {
|
||||
/* use the one the driver asked for */
|
||||
if (dvbdev_check_free_adapter_num(num))
|
||||
break;
|
||||
} else {
|
||||
num = dvbdev_get_free_adapter_num();
|
||||
break;
|
||||
}
|
||||
num = -1;
|
||||
}
|
||||
|
||||
if (num < 0) {
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
memset (adap, 0, sizeof(struct dvb_adapter));
|
||||
INIT_LIST_HEAD (&adap->device_list);
|
||||
|
||||
printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
|
||||
|
||||
adap->num = num;
|
||||
adap->name = name;
|
||||
adap->module = module;
|
||||
adap->device = device;
|
||||
adap->mfe_shared = 0;
|
||||
adap->mfe_dvbdev = NULL;
|
||||
mutex_init (&adap->mfe_lock);
|
||||
|
||||
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 file *file,
|
||||
unsigned int cmd, unsigned long arg,
|
||||
int (*func)(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(file, cmd, parg)) == -ENOIOCTLCMD)
|
||||
err = -ENOTTY;
|
||||
|
||||
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 dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
||||
add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
|
||||
add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
|
||||
add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *dvb_devnode(struct device *dev, umode_t *mode)
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
||||
return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
|
||||
dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
|
||||
}
|
||||
|
||||
|
||||
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(KERN_ERR "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(KERN_ERR "dvb-core: unable register character device\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
dvb_class = class_create(THIS_MODULE, "dvb");
|
||||
if (IS_ERR(dvb_class)) {
|
||||
retval = PTR_ERR(dvb_class);
|
||||
goto error;
|
||||
}
|
||||
dvb_class->dev_uevent = dvb_uevent;
|
||||
dvb_class->devnode = dvb_devnode;
|
||||
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);
|
||||
}
|
||||
|
||||
subsys_initcall(init_dvbdev);
|
||||
module_exit(exit_dvbdev);
|
||||
|
||||
MODULE_DESCRIPTION("DVB Core Driver");
|
||||
MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
|
||||
MODULE_LICENSE("GPL");
|
||||
150
drivers/media/dvb-core/dvbdev.h
Normal file
150
drivers/media/dvb-core/dvbdev.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#define DVB_MAJOR 212
|
||||
|
||||
#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
|
||||
#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
|
||||
#else
|
||||
#define DVB_MAX_ADAPTERS 8
|
||||
#endif
|
||||
|
||||
#define DVB_UNSET (-1)
|
||||
|
||||
#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
|
||||
|
||||
#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
|
||||
static short adapter_nr[] = \
|
||||
{[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
|
||||
module_param_array(adapter_nr, short, NULL, 0444); \
|
||||
MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
|
||||
|
||||
struct dvb_frontend;
|
||||
|
||||
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;
|
||||
|
||||
int mfe_shared; /* indicates mutually exclusive frontends */
|
||||
struct dvb_device *mfe_dvbdev; /* frontend device in use */
|
||||
struct mutex mfe_lock; /* access lock for thread creation */
|
||||
};
|
||||
|
||||
|
||||
struct dvb_device {
|
||||
struct list_head list_head;
|
||||
const struct file_operations *fops;
|
||||
struct dvb_adapter *adapter;
|
||||
int type;
|
||||
int minor;
|
||||
u32 id;
|
||||
|
||||
/* in theory, 'users' can vanish now,
|
||||
but I don't want to change too much now... */
|
||||
int readers;
|
||||
int writers;
|
||||
int users;
|
||||
|
||||
wait_queue_head_t wait_queue;
|
||||
/* don't really need those !? -- FIXME: use video_usercopy */
|
||||
int (*kernel_ioctl)(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,
|
||||
short *adapter_nums);
|
||||
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 long dvb_generic_ioctl (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 file *file, unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct file *file, unsigned int cmd, void *arg));
|
||||
|
||||
/** generic DVB attach function. */
|
||||
#ifdef CONFIG_MEDIA_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; \
|
||||
})
|
||||
|
||||
#define dvb_detach(FUNC) symbol_put_addr(FUNC)
|
||||
|
||||
#else
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
FUNCTION(ARGS); \
|
||||
})
|
||||
|
||||
#define dvb_detach(FUNC) {}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _DVBDEV_H_ */
|
||||
801
drivers/media/dvb-frontends/Kconfig
Normal file
801
drivers/media/dvb-frontends/Kconfig
Normal file
|
|
@ -0,0 +1,801 @@
|
|||
menu "Customise DVB Frontends"
|
||||
visible if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
comment "Multistandard (satellite) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_STB0899
|
||||
tristate "STB0899 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
|
||||
to support this demodulator based frontends
|
||||
|
||||
config DVB_STB6100
|
||||
tristate "STB6100 based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Silicon tuner from ST used in conjunction with the STB0899
|
||||
demodulator. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV090x
|
||||
tristate "STV0900/STV0903(A/B) based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
|
||||
Say Y when you want to support these frontends.
|
||||
|
||||
config DVB_STV6110x
|
||||
tristate "STV6110/(A) based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Silicon tuner that supports DVB-S and DVB-S2 modes
|
||||
|
||||
config DVB_M88DS3103
|
||||
tristate "Montage M88DS3103"
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Multistandard (cable + terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_DRXK
|
||||
tristate "Micronas DRXK based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Micronas DRX-K DVB-C/T demodulator.
|
||||
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA18271C2DD
|
||||
tristate "NXP TDA18271C2 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
NXP TDA18271 silicon tuner.
|
||||
|
||||
Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_SI2165
|
||||
tristate "Silicon Labs si2165 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C/T demodulator.
|
||||
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-S (satellite) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_CX24110
|
||||
tristate "Conexant CX24110 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CX24123
|
||||
tristate "Conexant CX24123 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MT312
|
||||
tristate "Zarlink VP310/MT312/ZL10313 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10036
|
||||
tristate "Zarlink ZL10036 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10039
|
||||
tristate "Zarlink ZL10039 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_S5H1420
|
||||
tristate "Samsung S5H1420 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0288
|
||||
tristate "ST STV0288 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STB6000
|
||||
tristate "ST STB6000 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0299
|
||||
tristate "ST STV0299 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV6110
|
||||
tristate "ST STV6110 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0900
|
||||
tristate "ST STV0900 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 demodulator. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA8083
|
||||
tristate "Philips TDA8083 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10086
|
||||
tristate "Philips TDA10086 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA8261
|
||||
tristate "Philips TDA8261 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_VES1X93
|
||||
tristate "VLSI VES1893 or VES1993 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TUNER_ITD1000
|
||||
tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TUNER_CX24113
|
||||
tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
|
||||
config DVB_TDA826X
|
||||
tristate "Philips TDA826X silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_TUA6100
|
||||
tristate "Infineon TUA6100 PLL"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S PLL chip.
|
||||
|
||||
config DVB_CX24116
|
||||
tristate "Conexant CX24116 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CX24117
|
||||
tristate "Conexant CX24117 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Dual DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_SI21XX
|
||||
tristate "Silicon Labs SI21XX based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TS2020
|
||||
tristate "Montage Tehnology TS2020 based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_DS3000
|
||||
tristate "Montage Tehnology DS3000 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MB86A16
|
||||
tristate "Fujitsu MB86A16 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S/DSS Direct Conversion reveiver.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10071
|
||||
tristate "NXP TDA10071"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_SP8870
|
||||
tristate "Spase sp8870 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the command
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
|
||||
download/extract it, and then copy it to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_SP887X
|
||||
tristate "Spase sp887x based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the command
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
|
||||
download/extract it, and then copy it to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_CX22700
|
||||
tristate "Conexant CX22700 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CX22702
|
||||
tristate "Conexant cx22702 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_S5H1432
|
||||
tristate "Samsung s5h1432 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DRXD
|
||||
tristate "Micronas DRXD driver"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
Note: this driver was based on vendor driver reference code (released
|
||||
under the GPL) as opposed to the existing drx397xd driver, which
|
||||
was written via reverse engineering.
|
||||
|
||||
config DVB_L64781
|
||||
tristate "LSI L64781"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA1004X
|
||||
tristate "Philips TDA10045H/TDA10046H based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the commands
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
|
||||
download/extract them, and then copy them to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_NXT6000
|
||||
tristate "NxtWave Communications NXT6000 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MT352
|
||||
tristate "Zarlink MT352 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10353
|
||||
tristate "Zarlink ZL10353 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DIB3000MB
|
||||
tristate "DiBcom 3000M-B"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB3000MC
|
||||
tristate "DiBcom 3000P/M-C"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB7000M
|
||||
tristate "DiBcom 7000MA/MB/PA/PB/MC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB7000P
|
||||
tristate "DiBcom 7000PC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_DIB9000
|
||||
tristate "DiBcom 9000"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_TDA10048
|
||||
tristate "Philips TDA10048HN based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_AF9013
|
||||
tristate "Afatech AF9013 demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_EC100
|
||||
tristate "E3C EC100"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_HD29L2
|
||||
tristate "HDIC HD29L2"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0367
|
||||
tristate "ST STV0367 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-T/C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_CXD2820R
|
||||
tristate "Sony CXD2820R"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_RTL2830
|
||||
tristate "Realtek RTL2830 DVB-T"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_RTL2832
|
||||
tristate "Realtek RTL2832 DVB-T"
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_RTL2832_SDR
|
||||
tristate "Realtek RTL2832 SDR"
|
||||
depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB
|
||||
select DVB_RTL2832
|
||||
select VIDEOBUF2_VMALLOC
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this SDR module.
|
||||
|
||||
config DVB_SI2168
|
||||
tristate "Silicon Labs Si2168"
|
||||
depends on DVB_CORE && I2C && I2C_MUX
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_AS102_FE
|
||||
tristate
|
||||
depends on DVB_CORE
|
||||
default DVB_AS102
|
||||
|
||||
comment "DVB-C (cable) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_VES1820
|
||||
tristate "VLSI VES1820 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10021
|
||||
tristate "Philips TDA10021 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA10023
|
||||
tristate "Philips TDA10023 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_STV0297
|
||||
tristate "ST STV0297 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-C tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_NXT200X
|
||||
tristate "NxtWave Communications NXT2002/NXT2004 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the commands
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
|
||||
download/extract them, and then copy them to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_OR51211
|
||||
tristate "Oren OR51211 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the command
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
|
||||
download it, and then copy it to /usr/lib/hotplug/firmware
|
||||
or /lib/firmware (depending on configuration of firmware hotplug).
|
||||
|
||||
config DVB_OR51132
|
||||
tristate "Oren OR51132 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
This driver needs external firmware. Please use the commands
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
|
||||
"<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
|
||||
download firmwares for 8VSB and QAM64/256, respectively. Copy them to
|
||||
/usr/lib/hotplug/firmware or /lib/firmware (depending on
|
||||
configuration of firmware hotplug).
|
||||
|
||||
config DVB_BCM3510
|
||||
tristate "Broadcom BCM3510"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
|
||||
support this frontend.
|
||||
|
||||
config DVB_LGDT330X
|
||||
tristate "LG Electronics LGDT3302/LGDT3303 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_LGDT3305
|
||||
tristate "LG Electronics LGDT3304 and LGDT3305 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_LG2160
|
||||
tristate "LG Electronics LG216x based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC/MH demodulator module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_S5H1409
|
||||
tristate "Samsung S5H1409 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
config DVB_AU8522
|
||||
depends on I2C
|
||||
tristate
|
||||
|
||||
config DVB_AU8522_DTV
|
||||
tristate "Auvitek AU8522 based DTV demod"
|
||||
depends on DVB_CORE && I2C
|
||||
select DVB_AU8522
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
|
||||
you want to enable DTV demodulation support for this frontend.
|
||||
|
||||
config DVB_AU8522_V4L
|
||||
tristate "Auvitek AU8522 based ATV demod"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
select DVB_AU8522
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
|
||||
you want to enable ATV demodulation support for this frontend.
|
||||
|
||||
config DVB_S5H1411
|
||||
tristate "Samsung S5H1411 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
|
||||
to support this frontend.
|
||||
|
||||
comment "ISDB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_S921
|
||||
tristate "Sharp S921 frontend"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DIB8000
|
||||
tristate "DiBcom 8000MB/MC"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_MB86A20S
|
||||
tristate "Fujitsu mb86a20s"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TC90522
|
||||
tristate "Toshiba TC90522"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Digital terrestrial only tuners/PLL"
|
||||
depends on DVB_CORE
|
||||
|
||||
config DVB_PLL
|
||||
tristate "Generic I2C PLL based tuners"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
This module drives a number of tuners based on PLL chips with a
|
||||
common I2C interface. Say Y when you want to support these tuners.
|
||||
|
||||
config DVB_TUNER_DIB0070
|
||||
tristate "DiBcom DiB0070 silicon base-band tuner"
|
||||
depends on I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for the silicon baseband tuner DiB0070 from DiBcom.
|
||||
This device is only used inside a SiP called together with a
|
||||
demodulator for now.
|
||||
|
||||
config DVB_TUNER_DIB0090
|
||||
tristate "DiBcom DiB0090 silicon base-band tuner"
|
||||
depends on I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A driver for the silicon baseband tuner DiB0090 from DiBcom.
|
||||
This device is only used inside a SiP called together with a
|
||||
demodulator for now.
|
||||
|
||||
comment "SEC control devices for DVB-S"
|
||||
depends on DVB_CORE
|
||||
|
||||
source "drivers/media/dvb-frontends/drx39xyj/Kconfig"
|
||||
|
||||
config DVB_LNBP21
|
||||
tristate "LNBP21/LNBH24 SEC controllers"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chips.
|
||||
|
||||
config DVB_LNBP22
|
||||
tristate "LNBP22 SEC controllers"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
LNB power supply and control voltage
|
||||
regulator chip with step-up converter
|
||||
and I2C interface.
|
||||
Say Y when you want to support this chip.
|
||||
|
||||
config DVB_ISL6405
|
||||
tristate "ISL6405 SEC controller"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chip.
|
||||
|
||||
config DVB_ISL6421
|
||||
tristate "ISL6421 SEC controller"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
An SEC control chip.
|
||||
|
||||
config DVB_ISL6423
|
||||
tristate "ISL6423 SEC controller"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A SEC controller chip from Intersil
|
||||
|
||||
config DVB_A8293
|
||||
tristate "Allegro A8293"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
config DVB_SP2
|
||||
tristate "CIMaX SP2"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
CIMaX SP2/SP2HF Common Interface module.
|
||||
|
||||
config DVB_LGS8GL5
|
||||
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_LGS8GXX
|
||||
tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
select FW_LOADER
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ATBM8830
|
||||
tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_TDA665x
|
||||
tristate "TDA665x tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for tuner modules based on Philips TDA6650/TDA6651 chips.
|
||||
Say Y when you want to support this chip.
|
||||
|
||||
Currently supported tuners:
|
||||
* Panasonic ENV57H12D5 (ET-50DT)
|
||||
|
||||
config DVB_IX2505V
|
||||
tristate "Sharp IX2505V silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_M88RS2000
|
||||
tristate "M88RS2000 DVB-S demodulator and tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
A DVB-S tuner module.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_AF9033
|
||||
tristate "Afatech AF9033 DVB-T demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
|
||||
comment "Tools to develop new frontends"
|
||||
|
||||
config DVB_DUMMY_FE
|
||||
tristate "Dummy frontend driver"
|
||||
default n
|
||||
endmenu
|
||||
118
drivers/media/dvb-frontends/Makefile
Normal file
118
drivers/media/dvb-frontends/Makefile
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#
|
||||
# Makefile for the kernel DVB frontend device drivers.
|
||||
#
|
||||
|
||||
ccflags-y += -I$(srctree)/drivers/media/dvb-core/
|
||||
ccflags-y += -I$(srctree)/drivers/media/tuners/
|
||||
|
||||
# FIXME: RTL2832 SDR driver uses power management directly from USB IF driver
|
||||
ifdef CONFIG_DVB_RTL2832_SDR
|
||||
ccflags-y += -I$(srctree)/drivers/media/usb/dvb-usb-v2
|
||||
endif
|
||||
|
||||
stb0899-objs := stb0899_drv.o stb0899_algo.o
|
||||
stv0900-objs := stv0900_core.o stv0900_sw.o
|
||||
drxd-objs := drxd_firm.o drxd_hard.o
|
||||
cxd2820r-objs := cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
|
||||
drxk-objs := drxk_hard.o
|
||||
|
||||
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
|
||||
obj-$(CONFIG_DVB_STV0299) += stv0299.o
|
||||
obj-$(CONFIG_DVB_STB0899) += stb0899.o
|
||||
obj-$(CONFIG_DVB_STB6100) += stb6100.o
|
||||
obj-$(CONFIG_DVB_SP8870) += sp8870.o
|
||||
obj-$(CONFIG_DVB_CX22700) += cx22700.o
|
||||
obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
|
||||
obj-$(CONFIG_DVB_CX24110) += cx24110.o
|
||||
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
|
||||
obj-$(CONFIG_DVB_L64781) += l64781.o
|
||||
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
|
||||
obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
|
||||
obj-$(CONFIG_DVB_MT312) += mt312.o
|
||||
obj-$(CONFIG_DVB_VES1820) += ves1820.o
|
||||
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
|
||||
obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
|
||||
obj-$(CONFIG_DVB_SP887X) += sp887x.o
|
||||
obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
|
||||
obj-$(CONFIG_DVB_MT352) += mt352.o
|
||||
obj-$(CONFIG_DVB_ZL10036) += zl10036.o
|
||||
obj-$(CONFIG_DVB_ZL10039) += zl10039.o
|
||||
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
|
||||
obj-$(CONFIG_DVB_CX22702) += cx22702.o
|
||||
obj-$(CONFIG_DVB_DRXD) += drxd.o
|
||||
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
|
||||
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
|
||||
obj-$(CONFIG_DVB_STV0297) += stv0297.o
|
||||
obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
|
||||
obj-$(CONFIG_DVB_OR51211) += or51211.o
|
||||
obj-$(CONFIG_DVB_OR51132) += or51132.o
|
||||
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
|
||||
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
|
||||
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
|
||||
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
|
||||
obj-$(CONFIG_DVB_LG2160) += lg2160.o
|
||||
obj-$(CONFIG_DVB_CX24123) += cx24123.o
|
||||
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
|
||||
obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
|
||||
obj-$(CONFIG_DVB_ISL6405) += isl6405.o
|
||||
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
|
||||
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
|
||||
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
|
||||
obj-$(CONFIG_DVB_TDA8261) += tda8261.o
|
||||
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
|
||||
obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
|
||||
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
|
||||
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
|
||||
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
|
||||
obj-$(CONFIG_DVB_AU8522) += au8522_common.o
|
||||
obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
|
||||
obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
|
||||
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
|
||||
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
|
||||
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
|
||||
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
|
||||
obj-$(CONFIG_DVB_TDA665x) += tda665x.o
|
||||
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
|
||||
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
|
||||
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
|
||||
obj-$(CONFIG_DVB_AF9013) += af9013.o
|
||||
obj-$(CONFIG_DVB_CX24116) += cx24116.o
|
||||
obj-$(CONFIG_DVB_CX24117) += cx24117.o
|
||||
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
|
||||
obj-$(CONFIG_DVB_SI2168) += si2168.o
|
||||
obj-$(CONFIG_DVB_STV0288) += stv0288.o
|
||||
obj-$(CONFIG_DVB_STB6000) += stb6000.o
|
||||
obj-$(CONFIG_DVB_S921) += s921.o
|
||||
obj-$(CONFIG_DVB_STV6110) += stv6110.o
|
||||
obj-$(CONFIG_DVB_STV0900) += stv0900.o
|
||||
obj-$(CONFIG_DVB_STV090x) += stv090x.o
|
||||
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
|
||||
obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
|
||||
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
|
||||
obj-$(CONFIG_DVB_EC100) += ec100.o
|
||||
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
|
||||
obj-$(CONFIG_DVB_DS3000) += ds3000.o
|
||||
obj-$(CONFIG_DVB_TS2020) += ts2020.o
|
||||
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
|
||||
obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj/
|
||||
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
|
||||
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
|
||||
obj-$(CONFIG_DVB_STV0367) += stv0367.o
|
||||
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
|
||||
obj-$(CONFIG_DVB_DRXK) += drxk.o
|
||||
obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
|
||||
obj-$(CONFIG_DVB_SI2165) += si2165.o
|
||||
obj-$(CONFIG_DVB_A8293) += a8293.o
|
||||
obj-$(CONFIG_DVB_SP2) += sp2.o
|
||||
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
|
||||
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
|
||||
obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
|
||||
obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
|
||||
obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
|
||||
obj-$(CONFIG_DVB_AF9033) += af9033.o
|
||||
obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o
|
||||
obj-$(CONFIG_DVB_TC90522) += tc90522.o
|
||||
169
drivers/media/dvb-frontends/a8293.c
Normal file
169
drivers/media/dvb-frontends/a8293.c
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Allegro A8293 SEC driver
|
||||
*
|
||||
* Copyright (C) 2011 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; 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "a8293.h"
|
||||
|
||||
struct a8293_priv {
|
||||
struct i2c_adapter *i2c;
|
||||
const struct a8293_config *cfg;
|
||||
u8 reg[2];
|
||||
};
|
||||
|
||||
static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_msg msg[1] = {
|
||||
{
|
||||
.addr = priv->cfg->i2c_addr,
|
||||
.len = len,
|
||||
.buf = val,
|
||||
}
|
||||
};
|
||||
|
||||
if (rd)
|
||||
msg[0].flags = I2C_M_RD;
|
||||
else
|
||||
msg[0].flags = 0;
|
||||
|
||||
ret = i2c_transfer(priv->i2c, msg, 1);
|
||||
if (ret == 1) {
|
||||
ret = 0;
|
||||
} else {
|
||||
dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n",
|
||||
KBUILD_MODNAME, ret, rd);
|
||||
ret = -EREMOTEIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int a8293_wr(struct a8293_priv *priv, u8 *val, int len)
|
||||
{
|
||||
return a8293_i2c(priv, val, len, 0);
|
||||
}
|
||||
|
||||
static int a8293_rd(struct a8293_priv *priv, u8 *val, int len)
|
||||
{
|
||||
return a8293_i2c(priv, val, len, 1);
|
||||
}
|
||||
|
||||
static int a8293_set_voltage(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t fe_sec_voltage)
|
||||
{
|
||||
struct a8293_priv *priv = fe->sec_priv;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
|
||||
fe_sec_voltage);
|
||||
|
||||
switch (fe_sec_voltage) {
|
||||
case SEC_VOLTAGE_OFF:
|
||||
/* ENB=0 */
|
||||
priv->reg[0] = 0x10;
|
||||
break;
|
||||
case SEC_VOLTAGE_13:
|
||||
/* VSEL0=1, VSEL1=0, VSEL2=0, VSEL3=0, ENB=1*/
|
||||
priv->reg[0] = 0x31;
|
||||
break;
|
||||
case SEC_VOLTAGE_18:
|
||||
/* VSEL0=0, VSEL1=0, VSEL2=0, VSEL3=1, ENB=1*/
|
||||
priv->reg[0] = 0x38;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = a8293_wr(priv, &priv->reg[0], 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
usleep_range(1500, 50000);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void a8293_release_sec(struct dvb_frontend *fe)
|
||||
{
|
||||
a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
|
||||
|
||||
kfree(fe->sec_priv);
|
||||
fe->sec_priv = NULL;
|
||||
}
|
||||
|
||||
struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c, const struct a8293_config *cfg)
|
||||
{
|
||||
int ret;
|
||||
struct a8293_priv *priv = NULL;
|
||||
u8 buf[2];
|
||||
|
||||
/* allocate memory for the internal priv */
|
||||
priv = kzalloc(sizeof(struct a8293_priv), GFP_KERNEL);
|
||||
if (priv == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* setup the priv */
|
||||
priv->i2c = i2c;
|
||||
priv->cfg = cfg;
|
||||
fe->sec_priv = priv;
|
||||
|
||||
/* check if the SEC is there */
|
||||
ret = a8293_rd(priv, buf, 2);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* ENB=0 */
|
||||
priv->reg[0] = 0x10;
|
||||
ret = a8293_wr(priv, &priv->reg[0], 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* TMODE=0, TGATE=1 */
|
||||
priv->reg[1] = 0x82;
|
||||
ret = a8293_wr(priv, &priv->reg[1], 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
fe->ops.release_sec = a8293_release_sec;
|
||||
|
||||
/* override frontend ops */
|
||||
fe->ops.set_voltage = a8293_set_voltage;
|
||||
|
||||
dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n",
|
||||
KBUILD_MODNAME);
|
||||
|
||||
return fe;
|
||||
err:
|
||||
dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(a8293_attach);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Allegro A8293 SEC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
42
drivers/media/dvb-frontends/a8293.h
Normal file
42
drivers/media/dvb-frontends/a8293.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Allegro A8293 SEC driver
|
||||
*
|
||||
* Copyright (C) 2011 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; 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef A8293_H
|
||||
#define A8293_H
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
|
||||
struct a8293_config {
|
||||
u8 i2c_addr;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_A8293)
|
||||
extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c, const struct a8293_config *cfg);
|
||||
#else
|
||||
static inline struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c, const struct a8293_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* A8293_H */
|
||||
1557
drivers/media/dvb-frontends/af9013.c
Normal file
1557
drivers/media/dvb-frontends/af9013.c
Normal file
File diff suppressed because it is too large
Load diff
118
drivers/media/dvb-frontends/af9013.h
Normal file
118
drivers/media/dvb-frontends/af9013.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Afatech AF9013 demodulator driver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* Thanks to Afatech who kindly provided 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; 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 AF9013_H
|
||||
#define AF9013_H
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
/* AF9013/5 GPIOs (mostly guessed)
|
||||
demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
|
||||
demod#1-gpio#1 - xtal setting (?)
|
||||
demod#1-gpio#3 - tuner#1
|
||||
demod#2-gpio#0 - tuner#2
|
||||
demod#2-gpio#1 - xtal setting (?)
|
||||
*/
|
||||
|
||||
struct af9013_config {
|
||||
/*
|
||||
* I2C address
|
||||
*/
|
||||
u8 i2c_addr;
|
||||
|
||||
/*
|
||||
* clock
|
||||
* 20480000, 25000000, 28000000, 28800000
|
||||
*/
|
||||
u32 clock;
|
||||
|
||||
/*
|
||||
* tuner
|
||||
*/
|
||||
#define AF9013_TUNER_MXL5003D 3 /* MaxLinear */
|
||||
#define AF9013_TUNER_MXL5005D 13 /* MaxLinear */
|
||||
#define AF9013_TUNER_MXL5005R 30 /* MaxLinear */
|
||||
#define AF9013_TUNER_ENV77H11D5 129 /* Panasonic */
|
||||
#define AF9013_TUNER_MT2060 130 /* Microtune */
|
||||
#define AF9013_TUNER_MC44S803 133 /* Freescale */
|
||||
#define AF9013_TUNER_QT1010 134 /* Quantek */
|
||||
#define AF9013_TUNER_UNKNOWN 140 /* for can tuners ? */
|
||||
#define AF9013_TUNER_MT2060_2 147 /* Microtune */
|
||||
#define AF9013_TUNER_TDA18271 156 /* NXP */
|
||||
#define AF9013_TUNER_QT1010A 162 /* Quantek */
|
||||
#define AF9013_TUNER_MXL5007T 177 /* MaxLinear */
|
||||
#define AF9013_TUNER_TDA18218 179 /* NXP */
|
||||
u8 tuner;
|
||||
|
||||
/*
|
||||
* IF frequency
|
||||
*/
|
||||
u32 if_frequency;
|
||||
|
||||
/*
|
||||
* TS settings
|
||||
*/
|
||||
#define AF9013_TS_USB 0
|
||||
#define AF9013_TS_PARALLEL 1
|
||||
#define AF9013_TS_SERIAL 2
|
||||
u8 ts_mode:2;
|
||||
|
||||
/*
|
||||
* input spectrum inversion
|
||||
*/
|
||||
bool spec_inv;
|
||||
|
||||
/*
|
||||
* firmware API version
|
||||
*/
|
||||
u8 api_version[4];
|
||||
|
||||
/*
|
||||
* GPIOs
|
||||
*/
|
||||
#define AF9013_GPIO_ON (1 << 0)
|
||||
#define AF9013_GPIO_EN (1 << 1)
|
||||
#define AF9013_GPIO_O (1 << 2)
|
||||
#define AF9013_GPIO_I (1 << 3)
|
||||
#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
|
||||
#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
|
||||
#define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN)
|
||||
#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
|
||||
u8 gpio[4];
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_AF9013)
|
||||
extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *af9013_attach(
|
||||
const struct af9013_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
pr_warn("%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_AF9013 */
|
||||
|
||||
#endif /* AF9013_H */
|
||||
909
drivers/media/dvb-frontends/af9013_priv.h
Normal file
909
drivers/media/dvb-frontends/af9013_priv.h
Normal file
|
|
@ -0,0 +1,909 @@
|
|||
/*
|
||||
* Afatech AF9013 demodulator driver
|
||||
*
|
||||
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
|
||||
* Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* Thanks to Afatech who kindly provided 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; 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 AF9013_PRIV_H
|
||||
#define AF9013_PRIV_H
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "af9013.h"
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#define AF9013_FIRMWARE "dvb-fe-af9013.fw"
|
||||
|
||||
struct af9013_reg_bit {
|
||||
u16 addr;
|
||||
u8 pos:4;
|
||||
u8 len:4;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct af9013_snr {
|
||||
u32 val;
|
||||
u8 snr;
|
||||
};
|
||||
|
||||
struct af9013_coeff {
|
||||
u32 clock;
|
||||
u32 bandwidth_hz;
|
||||
u8 val[24];
|
||||
};
|
||||
|
||||
/* pre-calculated coeff lookup table */
|
||||
static const struct af9013_coeff coeff_lut[] = {
|
||||
/* 28.800 MHz */
|
||||
{ 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
|
||||
0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
|
||||
0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
|
||||
{ 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
|
||||
0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
|
||||
0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
|
||||
{ 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
|
||||
0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
|
||||
0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
|
||||
/* 20.480 MHz */
|
||||
{ 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
|
||||
0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
|
||||
0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
|
||||
{ 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
|
||||
0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
|
||||
0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
|
||||
{ 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
|
||||
0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
|
||||
0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
|
||||
/* 28.000 MHz */
|
||||
{ 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
|
||||
0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
|
||||
0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
|
||||
{ 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
|
||||
0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
|
||||
0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
|
||||
{ 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
|
||||
0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
|
||||
0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
|
||||
/* 25.000 MHz */
|
||||
{ 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
|
||||
0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
|
||||
0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
|
||||
{ 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
|
||||
0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
|
||||
0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
|
||||
{ 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
|
||||
0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
|
||||
0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
|
||||
};
|
||||
|
||||
/* QPSK SNR lookup table */
|
||||
static const struct af9013_snr qpsk_snr_lut[] = {
|
||||
{ 0x000000, 0 },
|
||||
{ 0x0b4771, 0 },
|
||||
{ 0x0c1aed, 1 },
|
||||
{ 0x0d0d27, 2 },
|
||||
{ 0x0e4d19, 3 },
|
||||
{ 0x0e5da8, 4 },
|
||||
{ 0x107097, 5 },
|
||||
{ 0x116975, 6 },
|
||||
{ 0x1252d9, 7 },
|
||||
{ 0x131fa4, 8 },
|
||||
{ 0x13d5e1, 9 },
|
||||
{ 0x148e53, 10 },
|
||||
{ 0x15358b, 11 },
|
||||
{ 0x15dd29, 12 },
|
||||
{ 0x168112, 13 },
|
||||
{ 0x170b61, 14 },
|
||||
{ 0xffffff, 15 },
|
||||
};
|
||||
|
||||
/* QAM16 SNR lookup table */
|
||||
static const struct af9013_snr qam16_snr_lut[] = {
|
||||
{ 0x000000, 0 },
|
||||
{ 0x05eb62, 5 },
|
||||
{ 0x05fecf, 6 },
|
||||
{ 0x060b80, 7 },
|
||||
{ 0x062501, 8 },
|
||||
{ 0x064865, 9 },
|
||||
{ 0x069604, 10 },
|
||||
{ 0x06f356, 11 },
|
||||
{ 0x07706a, 12 },
|
||||
{ 0x0804d3, 13 },
|
||||
{ 0x089d1a, 14 },
|
||||
{ 0x093e3d, 15 },
|
||||
{ 0x09e35d, 16 },
|
||||
{ 0x0a7c3c, 17 },
|
||||
{ 0x0afaf8, 18 },
|
||||
{ 0x0b719d, 19 },
|
||||
{ 0xffffff, 20 },
|
||||
};
|
||||
|
||||
/* QAM64 SNR lookup table */
|
||||
static const struct af9013_snr qam64_snr_lut[] = {
|
||||
{ 0x000000, 0 },
|
||||
{ 0x03109b, 12 },
|
||||
{ 0x0310d4, 13 },
|
||||
{ 0x031920, 14 },
|
||||
{ 0x0322d0, 15 },
|
||||
{ 0x0339fc, 16 },
|
||||
{ 0x0364a1, 17 },
|
||||
{ 0x038bcc, 18 },
|
||||
{ 0x03c7d3, 19 },
|
||||
{ 0x0408cc, 20 },
|
||||
{ 0x043bed, 21 },
|
||||
{ 0x048061, 22 },
|
||||
{ 0x04be95, 23 },
|
||||
{ 0x04fa7d, 24 },
|
||||
{ 0x052405, 25 },
|
||||
{ 0x05570d, 26 },
|
||||
{ 0xffffff, 27 },
|
||||
};
|
||||
|
||||
static const struct af9013_reg_bit ofsm_init[] = {
|
||||
{ 0xd73a, 0, 8, 0xa1 },
|
||||
{ 0xd73b, 0, 8, 0x1f },
|
||||
{ 0xd73c, 4, 4, 0x0a },
|
||||
{ 0xd732, 3, 1, 0x00 },
|
||||
{ 0xd731, 4, 2, 0x03 },
|
||||
{ 0xd73d, 7, 1, 0x01 },
|
||||
{ 0xd740, 0, 1, 0x00 },
|
||||
{ 0xd740, 1, 1, 0x00 },
|
||||
{ 0xd740, 2, 1, 0x00 },
|
||||
{ 0xd740, 3, 1, 0x01 },
|
||||
{ 0xd3c1, 4, 1, 0x01 },
|
||||
{ 0x9124, 0, 8, 0x58 },
|
||||
{ 0x9125, 0, 2, 0x02 },
|
||||
{ 0xd3a2, 0, 8, 0x00 },
|
||||
{ 0xd3a3, 0, 8, 0x04 },
|
||||
{ 0xd305, 0, 8, 0x32 },
|
||||
{ 0xd306, 0, 8, 0x10 },
|
||||
{ 0xd304, 0, 8, 0x04 },
|
||||
{ 0x9112, 0, 1, 0x01 },
|
||||
{ 0x911d, 0, 1, 0x01 },
|
||||
{ 0x911a, 0, 1, 0x01 },
|
||||
{ 0x911b, 0, 1, 0x01 },
|
||||
{ 0x9bce, 0, 4, 0x02 },
|
||||
{ 0x9116, 0, 1, 0x01 },
|
||||
{ 0x9122, 0, 8, 0xd0 },
|
||||
{ 0xd2e0, 0, 8, 0xd0 },
|
||||
{ 0xd2e9, 0, 4, 0x0d },
|
||||
{ 0xd38c, 0, 8, 0xfc },
|
||||
{ 0xd38d, 0, 8, 0x00 },
|
||||
{ 0xd38e, 0, 8, 0x7e },
|
||||
{ 0xd38f, 0, 8, 0x00 },
|
||||
{ 0xd390, 0, 8, 0x2f },
|
||||
{ 0xd145, 4, 1, 0x01 },
|
||||
{ 0xd1a9, 4, 1, 0x01 },
|
||||
{ 0xd158, 5, 3, 0x01 },
|
||||
{ 0xd159, 0, 6, 0x06 },
|
||||
{ 0xd167, 0, 8, 0x00 },
|
||||
{ 0xd168, 0, 4, 0x07 },
|
||||
{ 0xd1c3, 5, 3, 0x00 },
|
||||
{ 0xd1c4, 0, 6, 0x00 },
|
||||
{ 0xd1c5, 0, 7, 0x10 },
|
||||
{ 0xd1c6, 0, 3, 0x02 },
|
||||
{ 0xd080, 2, 5, 0x03 },
|
||||
{ 0xd081, 4, 4, 0x09 },
|
||||
{ 0xd098, 4, 4, 0x0f },
|
||||
{ 0xd098, 0, 4, 0x03 },
|
||||
{ 0xdbc0, 4, 1, 0x01 },
|
||||
{ 0xdbc7, 0, 8, 0x08 },
|
||||
{ 0xdbc8, 4, 4, 0x00 },
|
||||
{ 0xdbc9, 0, 5, 0x01 },
|
||||
{ 0xd280, 0, 8, 0xe0 },
|
||||
{ 0xd281, 0, 8, 0xff },
|
||||
{ 0xd282, 0, 8, 0xff },
|
||||
{ 0xd283, 0, 8, 0xc3 },
|
||||
{ 0xd284, 0, 8, 0xff },
|
||||
{ 0xd285, 0, 4, 0x01 },
|
||||
{ 0xd0f0, 0, 7, 0x1a },
|
||||
{ 0xd0f1, 4, 1, 0x01 },
|
||||
{ 0xd0f2, 0, 8, 0x0c },
|
||||
{ 0xd101, 5, 3, 0x06 },
|
||||
{ 0xd103, 0, 4, 0x08 },
|
||||
{ 0xd0f8, 0, 7, 0x20 },
|
||||
{ 0xd111, 5, 1, 0x00 },
|
||||
{ 0xd111, 6, 1, 0x00 },
|
||||
{ 0x910b, 0, 8, 0x0a },
|
||||
{ 0x9115, 0, 8, 0x02 },
|
||||
{ 0x910c, 0, 8, 0x02 },
|
||||
{ 0x910d, 0, 8, 0x08 },
|
||||
{ 0x910e, 0, 8, 0x0a },
|
||||
{ 0x9bf6, 0, 8, 0x06 },
|
||||
{ 0x9bf8, 0, 8, 0x02 },
|
||||
{ 0x9bf7, 0, 8, 0x05 },
|
||||
{ 0x9bf9, 0, 8, 0x0f },
|
||||
{ 0x9bfc, 0, 8, 0x13 },
|
||||
{ 0x9bd3, 0, 8, 0xff },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Panasonic ENV77H11D5 tuner init
|
||||
AF9013_TUNER_ENV77H11D5 = 129 */
|
||||
static const struct af9013_reg_bit tuner_init_env77h11d5[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x03 },
|
||||
{ 0x9bbe, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0xd015, 0, 8, 0x50 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0xdf },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x44 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0xeb },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xf4 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xf9 },
|
||||
{ 0x9bc3, 0, 8, 0xdf },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0xeb },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bc9, 0, 8, 0x52 },
|
||||
{ 0xd011, 0, 8, 0x3c },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xf7 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x0b },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x4d },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* Microtune MT2060 tuner init
|
||||
AF9013_TUNER_MT2060 = 130 */
|
||||
static const struct af9013_reg_bit tuner_init_mt2060[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x07 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x00 },
|
||||
{ 0x9bcc, 0, 1, 0x00 },
|
||||
{ 0x9bb9, 0, 8, 0x75 },
|
||||
{ 0x9bcd, 0, 8, 0x24 },
|
||||
{ 0x9bff, 0, 8, 0x30 },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x32 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x36 },
|
||||
{ 0xd00d, 0, 2, 0x03 },
|
||||
{ 0xd00a, 0, 8, 0x35 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x07 },
|
||||
{ 0x9bc8, 0, 8, 0x90 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x36 },
|
||||
{ 0x9bc6, 0, 8, 0x03 },
|
||||
{ 0x9bba, 0, 8, 0xc9 },
|
||||
{ 0x9bc9, 0, 8, 0x79 },
|
||||
{ 0xd011, 0, 8, 0x10 },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0x45 },
|
||||
{ 0xd014, 0, 2, 0x03 },
|
||||
{ 0xd040, 0, 8, 0x98 },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0xcf },
|
||||
{ 0xd043, 0, 2, 0x03 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0xcc },
|
||||
{ 0x9be4, 0, 8, 0xa0 },
|
||||
{ 0x9bbd, 0, 8, 0x8e },
|
||||
{ 0x9be2, 0, 8, 0x4d },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Microtune MT2060 tuner init
|
||||
AF9013_TUNER_MT2060_2 = 147 */
|
||||
static const struct af9013_reg_bit tuner_init_mt2060_2[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x06 },
|
||||
{ 0x9bbe, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x32 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x36 },
|
||||
{ 0xd00d, 0, 2, 0x03 },
|
||||
{ 0xd00a, 0, 8, 0x35 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x07 },
|
||||
{ 0x9bc8, 0, 8, 0x90 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x36 },
|
||||
{ 0x9bc6, 0, 8, 0x03 },
|
||||
{ 0x9bba, 0, 8, 0xc9 },
|
||||
{ 0x9bc9, 0, 8, 0x79 },
|
||||
{ 0xd011, 0, 8, 0x10 },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0x45 },
|
||||
{ 0xd014, 0, 2, 0x03 },
|
||||
{ 0xd040, 0, 8, 0x98 },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0xcf },
|
||||
{ 0xd043, 0, 2, 0x03 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 8, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x96 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0xd045, 7, 1, 0x00 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* MaxLinear MXL5003 tuner init
|
||||
AF9013_TUNER_MXL5003D = 3 */
|
||||
static const struct af9013_reg_bit tuner_init_mxl5003d[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x09 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0x9bfc, 0, 8, 0x0f },
|
||||
{ 0x9bf6, 0, 8, 0x01 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0xd015, 0, 8, 0x33 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x40 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x6c },
|
||||
{ 0xd007, 0, 2, 0x00 },
|
||||
{ 0xd00c, 0, 8, 0x3d },
|
||||
{ 0xd00d, 0, 2, 0x00 },
|
||||
{ 0xd00a, 0, 8, 0x45 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x07 },
|
||||
{ 0x9bc8, 0, 8, 0x52 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x3d },
|
||||
{ 0x9bc6, 0, 8, 0x00 },
|
||||
{ 0x9bba, 0, 8, 0xa2 },
|
||||
{ 0x9bc9, 0, 8, 0xa0 },
|
||||
{ 0xd011, 0, 8, 0x56 },
|
||||
{ 0xd012, 0, 2, 0x00 },
|
||||
{ 0xd013, 0, 8, 0x50 },
|
||||
{ 0xd014, 0, 2, 0x00 },
|
||||
{ 0xd040, 0, 8, 0x56 },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0x50 },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 8, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* MaxLinear MXL5005S & MXL5007T tuner init
|
||||
AF9013_TUNER_MXL5005D = 13
|
||||
AF9013_TUNER_MXL5005R = 30
|
||||
AF9013_TUNER_MXL5007T = 177 */
|
||||
static const struct af9013_reg_bit tuner_init_mxl5005[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x07 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x28 },
|
||||
{ 0x9bff, 0, 8, 0x24 },
|
||||
{ 0xd015, 0, 8, 0x40 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x40 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x73 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0xfa },
|
||||
{ 0xd00d, 0, 2, 0x01 },
|
||||
{ 0xd00a, 0, 8, 0xff },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x23 },
|
||||
{ 0x9bc8, 0, 8, 0x55 },
|
||||
{ 0x9bc3, 0, 8, 0x01 },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0xfa },
|
||||
{ 0x9bc6, 0, 8, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xff },
|
||||
{ 0x9bc9, 0, 8, 0xff },
|
||||
{ 0x9bd3, 0, 8, 0x95 },
|
||||
{ 0xd011, 0, 8, 0x70 },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xfb },
|
||||
{ 0xd014, 0, 2, 0x01 },
|
||||
{ 0xd040, 0, 8, 0x70 },
|
||||
{ 0xd041, 0, 2, 0x01 },
|
||||
{ 0xd042, 0, 8, 0xfb },
|
||||
{ 0xd043, 0, 2, 0x01 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0x93 },
|
||||
{ 0x9be4, 0, 8, 0xfe },
|
||||
{ 0x9bbd, 0, 8, 0x63 },
|
||||
{ 0x9be2, 0, 8, 0xfe },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Quantek QT1010 tuner init
|
||||
AF9013_TUNER_QT1010 = 134
|
||||
AF9013_TUNER_QT1010A = 162 */
|
||||
static const struct af9013_reg_bit tuner_init_qt1010[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x09 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x28 },
|
||||
{ 0x9bff, 0, 8, 0x20 },
|
||||
{ 0xd008, 0, 8, 0x0f },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x99 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x0f },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0x50 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x00 },
|
||||
{ 0x9bc8, 0, 8, 0x00 },
|
||||
{ 0x9bc3, 0, 8, 0x0f },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x0f },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bba, 0, 8, 0xc5 },
|
||||
{ 0x9bc9, 0, 8, 0xff },
|
||||
{ 0xd011, 0, 8, 0x58 },
|
||||
{ 0xd012, 0, 2, 0x02 },
|
||||
{ 0xd013, 0, 8, 0x89 },
|
||||
{ 0xd014, 0, 2, 0x01 },
|
||||
{ 0xd040, 0, 8, 0x58 },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x89 },
|
||||
{ 0xd043, 0, 2, 0x01 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0xcd },
|
||||
{ 0x9be4, 0, 8, 0xbb },
|
||||
{ 0x9bbd, 0, 8, 0x93 },
|
||||
{ 0x9be2, 0, 8, 0x80 },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
/* Freescale MC44S803 tuner init
|
||||
AF9013_TUNER_MC44S803 = 133 */
|
||||
static const struct af9013_reg_bit tuner_init_mc44s803[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x06 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x00 },
|
||||
{ 0x9be3, 0, 8, 0x00 },
|
||||
{ 0x9bf6, 0, 8, 0x01 },
|
||||
{ 0x9bf8, 0, 8, 0x02 },
|
||||
{ 0x9bf9, 0, 8, 0x02 },
|
||||
{ 0x9bfc, 0, 8, 0x1f },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x24 },
|
||||
{ 0x9bff, 0, 8, 0x24 },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0x01 },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x7b },
|
||||
{ 0xd007, 0, 2, 0x00 },
|
||||
{ 0xd00c, 0, 8, 0x7c },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xfe },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bc7, 0, 8, 0x08 },
|
||||
{ 0x9bc8, 0, 8, 0x9a },
|
||||
{ 0x9bc3, 0, 8, 0x01 },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x7c },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bba, 0, 8, 0xfc },
|
||||
{ 0x9bc9, 0, 8, 0xaa },
|
||||
{ 0xd011, 0, 8, 0x6b },
|
||||
{ 0xd012, 0, 2, 0x00 },
|
||||
{ 0xd013, 0, 8, 0x88 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x6b },
|
||||
{ 0xd041, 0, 2, 0x00 },
|
||||
{ 0xd042, 0, 8, 0x7c },
|
||||
{ 0xd043, 0, 2, 0x02 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0x9e },
|
||||
{ 0x9be4, 0, 8, 0xff },
|
||||
{ 0x9bbd, 0, 8, 0x9e },
|
||||
{ 0x9be2, 0, 8, 0x25 },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
{ 0xd73b, 3, 1, 0x00 },
|
||||
};
|
||||
|
||||
/* unknown, probably for tin can tuner, tuner init
|
||||
AF9013_TUNER_UNKNOWN = 140 */
|
||||
static const struct af9013_reg_bit tuner_init_unknown[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x02 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x18 },
|
||||
{ 0x9bff, 0, 8, 0x2c },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0xdf },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x44 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x00 },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xf6 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xf9 },
|
||||
{ 0x9bc8, 0, 8, 0xaa },
|
||||
{ 0x9bc3, 0, 8, 0xdf },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x00 },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bc9, 0, 8, 0xf0 },
|
||||
{ 0xd011, 0, 8, 0x3c },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xf7 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x0b },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x4d },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
};
|
||||
|
||||
/* NXP TDA18271 & TDA18218 tuner init
|
||||
AF9013_TUNER_TDA18271 = 156
|
||||
AF9013_TUNER_TDA18218 = 179 */
|
||||
static const struct af9013_reg_bit tuner_init_tda18271[] = {
|
||||
{ 0x9bd5, 0, 8, 0x01 },
|
||||
{ 0x9bd6, 0, 8, 0x04 },
|
||||
{ 0xd1a0, 1, 1, 0x01 },
|
||||
{ 0xd000, 0, 1, 0x01 },
|
||||
{ 0xd000, 1, 1, 0x00 },
|
||||
{ 0xd001, 1, 1, 0x01 },
|
||||
{ 0xd001, 0, 1, 0x00 },
|
||||
{ 0xd001, 5, 1, 0x00 },
|
||||
{ 0xd002, 0, 5, 0x19 },
|
||||
{ 0xd003, 0, 5, 0x1a },
|
||||
{ 0xd004, 0, 5, 0x19 },
|
||||
{ 0xd005, 0, 5, 0x1a },
|
||||
{ 0xd00e, 0, 5, 0x10 },
|
||||
{ 0xd00f, 0, 3, 0x04 },
|
||||
{ 0xd00f, 3, 3, 0x05 },
|
||||
{ 0xd010, 0, 3, 0x04 },
|
||||
{ 0xd010, 3, 3, 0x05 },
|
||||
{ 0xd016, 4, 4, 0x03 },
|
||||
{ 0xd01f, 0, 6, 0x0a },
|
||||
{ 0xd020, 0, 6, 0x0a },
|
||||
{ 0x9bda, 0, 8, 0x01 },
|
||||
{ 0x9be3, 0, 8, 0x01 },
|
||||
{ 0xd1a0, 1, 1, 0x00 },
|
||||
{ 0x9bbe, 0, 1, 0x01 },
|
||||
{ 0x9bcc, 0, 1, 0x01 },
|
||||
{ 0x9bb9, 0, 8, 0x00 },
|
||||
{ 0x9bcd, 0, 8, 0x18 },
|
||||
{ 0x9bff, 0, 8, 0x2c },
|
||||
{ 0xd015, 0, 8, 0x46 },
|
||||
{ 0xd016, 0, 1, 0x00 },
|
||||
{ 0xd044, 0, 8, 0x46 },
|
||||
{ 0xd045, 0, 1, 0x00 },
|
||||
{ 0xd008, 0, 8, 0xdf },
|
||||
{ 0xd009, 0, 2, 0x02 },
|
||||
{ 0xd006, 0, 8, 0x44 },
|
||||
{ 0xd007, 0, 2, 0x01 },
|
||||
{ 0xd00c, 0, 8, 0x00 },
|
||||
{ 0xd00d, 0, 2, 0x02 },
|
||||
{ 0xd00a, 0, 8, 0xf6 },
|
||||
{ 0xd00b, 0, 2, 0x01 },
|
||||
{ 0x9bba, 0, 8, 0xf9 },
|
||||
{ 0x9bc8, 0, 8, 0xaa },
|
||||
{ 0x9bc3, 0, 8, 0xdf },
|
||||
{ 0x9bc4, 0, 8, 0x02 },
|
||||
{ 0x9bc5, 0, 8, 0x00 },
|
||||
{ 0x9bc6, 0, 8, 0x02 },
|
||||
{ 0x9bc9, 0, 8, 0xf0 },
|
||||
{ 0xd011, 0, 8, 0x3c },
|
||||
{ 0xd012, 0, 2, 0x01 },
|
||||
{ 0xd013, 0, 8, 0xf7 },
|
||||
{ 0xd014, 0, 2, 0x02 },
|
||||
{ 0xd040, 0, 8, 0x0b },
|
||||
{ 0xd041, 0, 2, 0x02 },
|
||||
{ 0xd042, 0, 8, 0x4d },
|
||||
{ 0xd043, 0, 2, 0x00 },
|
||||
{ 0xd045, 1, 1, 0x00 },
|
||||
{ 0x9bcf, 0, 1, 0x01 },
|
||||
{ 0xd045, 2, 1, 0x01 },
|
||||
{ 0xd04f, 0, 8, 0x9a },
|
||||
{ 0xd050, 0, 1, 0x01 },
|
||||
{ 0xd051, 0, 8, 0x5a },
|
||||
{ 0xd052, 0, 1, 0x01 },
|
||||
{ 0xd053, 0, 8, 0x50 },
|
||||
{ 0xd054, 0, 8, 0x46 },
|
||||
{ 0x9bd7, 0, 8, 0x0a },
|
||||
{ 0x9bd8, 0, 8, 0x14 },
|
||||
{ 0x9bd9, 0, 8, 0x08 },
|
||||
{ 0x9bd0, 0, 8, 0xa8 },
|
||||
{ 0x9be4, 0, 8, 0x7f },
|
||||
{ 0x9bbd, 0, 8, 0xa8 },
|
||||
{ 0x9be2, 0, 8, 0x20 },
|
||||
{ 0x9bee, 0, 1, 0x01 },
|
||||
};
|
||||
|
||||
#endif /* AF9013_PRIV_H */
|
||||
1286
drivers/media/dvb-frontends/af9033.c
Normal file
1286
drivers/media/dvb-frontends/af9033.c
Normal file
File diff suppressed because it is too large
Load diff
101
drivers/media/dvb-frontends/af9033.h
Normal file
101
drivers/media/dvb-frontends/af9033.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Afatech AF9033 demodulator driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
* Copyright (C) 2012 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; 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef AF9033_H
|
||||
#define AF9033_H
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
|
||||
/*
|
||||
* I2C address (TODO: are these in 8-bit format?)
|
||||
* 0x38, 0x3a, 0x3c, 0x3e
|
||||
*/
|
||||
struct af9033_config {
|
||||
/*
|
||||
* clock Hz
|
||||
* 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
|
||||
* 30000000, 36000000, 20480000, 16384000
|
||||
*/
|
||||
u32 clock;
|
||||
|
||||
/*
|
||||
* ADC multiplier
|
||||
*/
|
||||
#define AF9033_ADC_MULTIPLIER_1X 0
|
||||
#define AF9033_ADC_MULTIPLIER_2X 1
|
||||
u8 adc_multiplier;
|
||||
|
||||
/*
|
||||
* tuner
|
||||
*/
|
||||
#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */
|
||||
#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */
|
||||
#define AF9033_TUNER_FC0012 0x2e /* Fitipower FC0012 */
|
||||
#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */
|
||||
#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */
|
||||
#define AF9033_TUNER_FC2580 0x32 /* FCI FC2580 */
|
||||
/* 50-5f Omega */
|
||||
#define AF9033_TUNER_IT9135_38 0x38 /* Omega */
|
||||
#define AF9033_TUNER_IT9135_51 0x51 /* Omega LNA config 1 */
|
||||
#define AF9033_TUNER_IT9135_52 0x52 /* Omega LNA config 2 */
|
||||
/* 60-6f Omega v2 */
|
||||
#define AF9033_TUNER_IT9135_60 0x60 /* Omega v2 */
|
||||
#define AF9033_TUNER_IT9135_61 0x61 /* Omega v2 LNA config 1 */
|
||||
#define AF9033_TUNER_IT9135_62 0x62 /* Omega v2 LNA config 2 */
|
||||
u8 tuner;
|
||||
|
||||
/*
|
||||
* TS settings
|
||||
*/
|
||||
#define AF9033_TS_MODE_USB 0
|
||||
#define AF9033_TS_MODE_PARALLEL 1
|
||||
#define AF9033_TS_MODE_SERIAL 2
|
||||
u8 ts_mode:2;
|
||||
|
||||
/*
|
||||
* input spectrum inversion
|
||||
*/
|
||||
bool spec_inv;
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
bool dyn0_clk;
|
||||
|
||||
/*
|
||||
* PID filter ops
|
||||
*/
|
||||
struct af9033_ops *ops;
|
||||
|
||||
/*
|
||||
* frontend
|
||||
* returned by that driver
|
||||
*/
|
||||
struct dvb_frontend **fe;
|
||||
};
|
||||
|
||||
struct af9033_ops {
|
||||
int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff);
|
||||
int (*pid_filter)(struct dvb_frontend *fe, int index, u16 pid,
|
||||
int onoff);
|
||||
};
|
||||
|
||||
#endif /* AF9033_H */
|
||||
2054
drivers/media/dvb-frontends/af9033_priv.h
Normal file
2054
drivers/media/dvb-frontends/af9033_priv.h
Normal file
File diff suppressed because it is too large
Load diff
480
drivers/media/dvb-frontends/as102_fe.c
Normal file
480
drivers/media/dvb-frontends/as102_fe.c
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
* Abilis Systems Single DVB-T Receiver
|
||||
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
|
||||
* Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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.
|
||||
*/
|
||||
|
||||
#include <dvb_frontend.h>
|
||||
|
||||
#include "as102_fe.h"
|
||||
|
||||
struct as102_state {
|
||||
struct dvb_frontend frontend;
|
||||
struct as10x_demod_stats demod_stats;
|
||||
|
||||
const struct as102_fe_ops *ops;
|
||||
void *priv;
|
||||
uint8_t elna_cfg;
|
||||
|
||||
/* signal strength */
|
||||
uint16_t signal_strength;
|
||||
/* bit error rate */
|
||||
uint32_t ber;
|
||||
};
|
||||
|
||||
static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
|
||||
{
|
||||
uint8_t c;
|
||||
|
||||
switch (arg) {
|
||||
case FEC_1_2:
|
||||
c = CODE_RATE_1_2;
|
||||
break;
|
||||
case FEC_2_3:
|
||||
c = CODE_RATE_2_3;
|
||||
break;
|
||||
case FEC_3_4:
|
||||
c = CODE_RATE_3_4;
|
||||
break;
|
||||
case FEC_5_6:
|
||||
c = CODE_RATE_5_6;
|
||||
break;
|
||||
case FEC_7_8:
|
||||
c = CODE_RATE_7_8;
|
||||
break;
|
||||
default:
|
||||
c = CODE_RATE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int as102_fe_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct as10x_tune_args tune_args = { 0 };
|
||||
|
||||
/* set frequency */
|
||||
tune_args.freq = c->frequency / 1000;
|
||||
|
||||
/* fix interleaving_mode */
|
||||
tune_args.interleaving_mode = INTLV_NATIVE;
|
||||
|
||||
switch (c->bandwidth_hz) {
|
||||
case 8000000:
|
||||
tune_args.bandwidth = BW_8_MHZ;
|
||||
break;
|
||||
case 7000000:
|
||||
tune_args.bandwidth = BW_7_MHZ;
|
||||
break;
|
||||
case 6000000:
|
||||
tune_args.bandwidth = BW_6_MHZ;
|
||||
break;
|
||||
default:
|
||||
tune_args.bandwidth = BW_8_MHZ;
|
||||
}
|
||||
|
||||
switch (c->guard_interval) {
|
||||
case GUARD_INTERVAL_1_32:
|
||||
tune_args.guard_interval = GUARD_INT_1_32;
|
||||
break;
|
||||
case GUARD_INTERVAL_1_16:
|
||||
tune_args.guard_interval = GUARD_INT_1_16;
|
||||
break;
|
||||
case GUARD_INTERVAL_1_8:
|
||||
tune_args.guard_interval = GUARD_INT_1_8;
|
||||
break;
|
||||
case GUARD_INTERVAL_1_4:
|
||||
tune_args.guard_interval = GUARD_INT_1_4;
|
||||
break;
|
||||
case GUARD_INTERVAL_AUTO:
|
||||
default:
|
||||
tune_args.guard_interval = GUARD_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c->modulation) {
|
||||
case QPSK:
|
||||
tune_args.modulation = CONST_QPSK;
|
||||
break;
|
||||
case QAM_16:
|
||||
tune_args.modulation = CONST_QAM16;
|
||||
break;
|
||||
case QAM_64:
|
||||
tune_args.modulation = CONST_QAM64;
|
||||
break;
|
||||
default:
|
||||
tune_args.modulation = CONST_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c->transmission_mode) {
|
||||
case TRANSMISSION_MODE_2K:
|
||||
tune_args.transmission_mode = TRANS_MODE_2K;
|
||||
break;
|
||||
case TRANSMISSION_MODE_8K:
|
||||
tune_args.transmission_mode = TRANS_MODE_8K;
|
||||
break;
|
||||
default:
|
||||
tune_args.transmission_mode = TRANS_MODE_UNKNOWN;
|
||||
}
|
||||
|
||||
switch (c->hierarchy) {
|
||||
case HIERARCHY_NONE:
|
||||
tune_args.hierarchy = HIER_NONE;
|
||||
break;
|
||||
case HIERARCHY_1:
|
||||
tune_args.hierarchy = HIER_ALPHA_1;
|
||||
break;
|
||||
case HIERARCHY_2:
|
||||
tune_args.hierarchy = HIER_ALPHA_2;
|
||||
break;
|
||||
case HIERARCHY_4:
|
||||
tune_args.hierarchy = HIER_ALPHA_4;
|
||||
break;
|
||||
case HIERARCHY_AUTO:
|
||||
tune_args.hierarchy = HIER_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n",
|
||||
c->frequency,
|
||||
tune_args.bandwidth,
|
||||
tune_args.guard_interval);
|
||||
|
||||
/*
|
||||
* Detect a hierarchy selection
|
||||
* if HP/LP are both set to FEC_NONE, HP will be selected.
|
||||
*/
|
||||
if ((tune_args.hierarchy != HIER_NONE) &&
|
||||
((c->code_rate_LP == FEC_NONE) ||
|
||||
(c->code_rate_HP == FEC_NONE))) {
|
||||
|
||||
if (c->code_rate_LP == FEC_NONE) {
|
||||
tune_args.hier_select = HIER_HIGH_PRIORITY;
|
||||
tune_args.code_rate =
|
||||
as102_fe_get_code_rate(c->code_rate_HP);
|
||||
}
|
||||
|
||||
if (c->code_rate_HP == FEC_NONE) {
|
||||
tune_args.hier_select = HIER_LOW_PRIORITY;
|
||||
tune_args.code_rate =
|
||||
as102_fe_get_code_rate(c->code_rate_LP);
|
||||
}
|
||||
|
||||
pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n",
|
||||
tune_args.hierarchy,
|
||||
tune_args.hier_select == HIER_HIGH_PRIORITY ?
|
||||
"HP" : "LP",
|
||||
tune_args.hier_select == HIER_HIGH_PRIORITY ?
|
||||
"HP" : "LP",
|
||||
tune_args.code_rate);
|
||||
} else {
|
||||
tune_args.code_rate =
|
||||
as102_fe_get_code_rate(c->code_rate_HP);
|
||||
}
|
||||
|
||||
/* Set frontend arguments */
|
||||
return state->ops->set_tune(state->priv, &tune_args);
|
||||
}
|
||||
|
||||
static int as102_fe_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int ret = 0;
|
||||
struct as10x_tps tps = { 0 };
|
||||
|
||||
/* send abilis command: GET_TPS */
|
||||
ret = state->ops->get_tps(state->priv, &tps);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* extract constellation */
|
||||
switch (tps.modulation) {
|
||||
case CONST_QPSK:
|
||||
c->modulation = QPSK;
|
||||
break;
|
||||
case CONST_QAM16:
|
||||
c->modulation = QAM_16;
|
||||
break;
|
||||
case CONST_QAM64:
|
||||
c->modulation = QAM_64;
|
||||
break;
|
||||
}
|
||||
|
||||
/* extract hierarchy */
|
||||
switch (tps.hierarchy) {
|
||||
case HIER_NONE:
|
||||
c->hierarchy = HIERARCHY_NONE;
|
||||
break;
|
||||
case HIER_ALPHA_1:
|
||||
c->hierarchy = HIERARCHY_1;
|
||||
break;
|
||||
case HIER_ALPHA_2:
|
||||
c->hierarchy = HIERARCHY_2;
|
||||
break;
|
||||
case HIER_ALPHA_4:
|
||||
c->hierarchy = HIERARCHY_4;
|
||||
break;
|
||||
}
|
||||
|
||||
/* extract code rate HP */
|
||||
switch (tps.code_rate_HP) {
|
||||
case CODE_RATE_1_2:
|
||||
c->code_rate_HP = FEC_1_2;
|
||||
break;
|
||||
case CODE_RATE_2_3:
|
||||
c->code_rate_HP = FEC_2_3;
|
||||
break;
|
||||
case CODE_RATE_3_4:
|
||||
c->code_rate_HP = FEC_3_4;
|
||||
break;
|
||||
case CODE_RATE_5_6:
|
||||
c->code_rate_HP = FEC_5_6;
|
||||
break;
|
||||
case CODE_RATE_7_8:
|
||||
c->code_rate_HP = FEC_7_8;
|
||||
break;
|
||||
}
|
||||
|
||||
/* extract code rate LP */
|
||||
switch (tps.code_rate_LP) {
|
||||
case CODE_RATE_1_2:
|
||||
c->code_rate_LP = FEC_1_2;
|
||||
break;
|
||||
case CODE_RATE_2_3:
|
||||
c->code_rate_LP = FEC_2_3;
|
||||
break;
|
||||
case CODE_RATE_3_4:
|
||||
c->code_rate_LP = FEC_3_4;
|
||||
break;
|
||||
case CODE_RATE_5_6:
|
||||
c->code_rate_LP = FEC_5_6;
|
||||
break;
|
||||
case CODE_RATE_7_8:
|
||||
c->code_rate_LP = FEC_7_8;
|
||||
break;
|
||||
}
|
||||
|
||||
/* extract guard interval */
|
||||
switch (tps.guard_interval) {
|
||||
case GUARD_INT_1_32:
|
||||
c->guard_interval = GUARD_INTERVAL_1_32;
|
||||
break;
|
||||
case GUARD_INT_1_16:
|
||||
c->guard_interval = GUARD_INTERVAL_1_16;
|
||||
break;
|
||||
case GUARD_INT_1_8:
|
||||
c->guard_interval = GUARD_INTERVAL_1_8;
|
||||
break;
|
||||
case GUARD_INT_1_4:
|
||||
c->guard_interval = GUARD_INTERVAL_1_4;
|
||||
break;
|
||||
}
|
||||
|
||||
/* extract transmission mode */
|
||||
switch (tps.transmission_mode) {
|
||||
case TRANS_MODE_2K:
|
||||
c->transmission_mode = TRANSMISSION_MODE_2K;
|
||||
break;
|
||||
case TRANS_MODE_8K:
|
||||
c->transmission_mode = TRANSMISSION_MODE_8K;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *settings) {
|
||||
|
||||
settings->min_delay_ms = 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
int ret = 0;
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
struct as10x_tune_status tstate = { 0 };
|
||||
|
||||
/* send abilis command: GET_TUNE_STATUS */
|
||||
ret = state->ops->get_status(state->priv, &tstate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->signal_strength = tstate.signal_strength;
|
||||
state->ber = tstate.BER;
|
||||
|
||||
switch (tstate.tune_state) {
|
||||
case TUNE_STATUS_SIGNAL_DVB_OK:
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
break;
|
||||
case TUNE_STATUS_STREAM_DETECTED:
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
|
||||
FE_HAS_VITERBI;
|
||||
break;
|
||||
case TUNE_STATUS_STREAM_TUNED:
|
||||
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
|
||||
FE_HAS_LOCK | FE_HAS_VITERBI;
|
||||
break;
|
||||
default:
|
||||
*status = TUNE_STATUS_NOT_TUNED;
|
||||
}
|
||||
|
||||
pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
|
||||
tstate.tune_state, tstate.signal_strength,
|
||||
tstate.PER, tstate.BER);
|
||||
|
||||
if (!(*status & FE_HAS_LOCK)) {
|
||||
memset(&state->demod_stats, 0, sizeof(state->demod_stats));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = state->ops->get_stats(state->priv, &state->demod_stats);
|
||||
if (ret < 0)
|
||||
memset(&state->demod_stats, 0, sizeof(state->demod_stats));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* - in AS102 SNR=MER
|
||||
* - the SNR will be returned in linear terms, i.e. not in dB
|
||||
* - the accuracy equals ±2dB for a SNR range from 4dB to 30dB
|
||||
* - the accuracy is >2dB for SNR values outside this range
|
||||
*/
|
||||
static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
|
||||
*snr = state->demod_stats.mer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
|
||||
*ber = state->ber;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *strength)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
|
||||
*strength = (((0xffff * 400) * state->signal_strength + 41000) * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
|
||||
if (state->demod_stats.has_started)
|
||||
*ucblocks = state->demod_stats.bad_frame_count;
|
||||
else
|
||||
*ucblocks = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
|
||||
return state->ops->stream_ctrl(state->priv, acquire,
|
||||
state->elna_cfg);
|
||||
}
|
||||
|
||||
static void as102_fe_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct as102_state *state = fe->demodulator_priv;
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops as102_fe_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "Abilis AS102 DVB-T",
|
||||
.frequency_min = 174000000,
|
||||
.frequency_max = 862000000,
|
||||
.frequency_stepsize = 166667,
|
||||
.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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
|
||||
| FE_CAN_QAM_AUTO
|
||||
| FE_CAN_TRANSMISSION_MODE_AUTO
|
||||
| FE_CAN_GUARD_INTERVAL_AUTO
|
||||
| FE_CAN_HIERARCHY_AUTO
|
||||
| FE_CAN_RECOVER
|
||||
| FE_CAN_MUTE_TS
|
||||
},
|
||||
|
||||
.set_frontend = as102_fe_set_frontend,
|
||||
.get_frontend = as102_fe_get_frontend,
|
||||
.get_tune_settings = as102_fe_get_tune_settings,
|
||||
|
||||
.read_status = as102_fe_read_status,
|
||||
.read_snr = as102_fe_read_snr,
|
||||
.read_ber = as102_fe_read_ber,
|
||||
.read_signal_strength = as102_fe_read_signal_strength,
|
||||
.read_ucblocks = as102_fe_read_ucblocks,
|
||||
.ts_bus_ctrl = as102_fe_ts_bus_ctrl,
|
||||
.release = as102_fe_release,
|
||||
};
|
||||
|
||||
struct dvb_frontend *as102_attach(const char *name,
|
||||
const struct as102_fe_ops *ops,
|
||||
void *priv,
|
||||
uint8_t elna_cfg)
|
||||
{
|
||||
struct as102_state *state;
|
||||
struct dvb_frontend *fe;
|
||||
|
||||
state = kzalloc(sizeof(struct as102_state), GFP_KERNEL);
|
||||
if (state == NULL) {
|
||||
pr_err("%s: unable to allocate memory for state\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
fe = &state->frontend;
|
||||
fe->demodulator_priv = state;
|
||||
state->ops = ops;
|
||||
state->priv = priv;
|
||||
state->elna_cfg = elna_cfg;
|
||||
|
||||
/* init frontend callback ops */
|
||||
memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name));
|
||||
|
||||
return fe;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(as102_attach);
|
||||
|
||||
MODULE_DESCRIPTION("as102-fe");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
|
||||
29
drivers/media/dvb-frontends/as102_fe.h
Normal file
29
drivers/media/dvb-frontends/as102_fe.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Abilis Systems Single DVB-T Receiver
|
||||
* Copyright (C) 2014 Mauro Carvalho Chehab <m.chehab@samsung.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, 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.
|
||||
*/
|
||||
|
||||
#include "as102_fe_types.h"
|
||||
|
||||
struct as102_fe_ops {
|
||||
int (*set_tune)(void *priv, struct as10x_tune_args *tune_args);
|
||||
int (*get_tps)(void *priv, struct as10x_tps *tps);
|
||||
int (*get_status)(void *priv, struct as10x_tune_status *tstate);
|
||||
int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats);
|
||||
int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg);
|
||||
};
|
||||
|
||||
struct dvb_frontend *as102_attach(const char *name,
|
||||
const struct as102_fe_ops *ops,
|
||||
void *priv,
|
||||
uint8_t elna_cfg);
|
||||
188
drivers/media/dvb-frontends/as102_fe_types.h
Normal file
188
drivers/media/dvb-frontends/as102_fe_types.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Abilis Systems Single DVB-T Receiver
|
||||
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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.
|
||||
*/
|
||||
#ifndef _AS10X_TYPES_H_
|
||||
#define _AS10X_TYPES_H_
|
||||
|
||||
/*********************************/
|
||||
/* MACRO DEFINITIONS */
|
||||
/*********************************/
|
||||
|
||||
/* bandwidth constant values */
|
||||
#define BW_5_MHZ 0x00
|
||||
#define BW_6_MHZ 0x01
|
||||
#define BW_7_MHZ 0x02
|
||||
#define BW_8_MHZ 0x03
|
||||
|
||||
/* hierarchy priority selection values */
|
||||
#define HIER_NO_PRIORITY 0x00
|
||||
#define HIER_LOW_PRIORITY 0x01
|
||||
#define HIER_HIGH_PRIORITY 0x02
|
||||
|
||||
/* constellation available values */
|
||||
#define CONST_QPSK 0x00
|
||||
#define CONST_QAM16 0x01
|
||||
#define CONST_QAM64 0x02
|
||||
#define CONST_UNKNOWN 0xFF
|
||||
|
||||
/* hierarchy available values */
|
||||
#define HIER_NONE 0x00
|
||||
#define HIER_ALPHA_1 0x01
|
||||
#define HIER_ALPHA_2 0x02
|
||||
#define HIER_ALPHA_4 0x03
|
||||
#define HIER_UNKNOWN 0xFF
|
||||
|
||||
/* interleaving available values */
|
||||
#define INTLV_NATIVE 0x00
|
||||
#define INTLV_IN_DEPTH 0x01
|
||||
#define INTLV_UNKNOWN 0xFF
|
||||
|
||||
/* code rate available values */
|
||||
#define CODE_RATE_1_2 0x00
|
||||
#define CODE_RATE_2_3 0x01
|
||||
#define CODE_RATE_3_4 0x02
|
||||
#define CODE_RATE_5_6 0x03
|
||||
#define CODE_RATE_7_8 0x04
|
||||
#define CODE_RATE_UNKNOWN 0xFF
|
||||
|
||||
/* guard interval available values */
|
||||
#define GUARD_INT_1_32 0x00
|
||||
#define GUARD_INT_1_16 0x01
|
||||
#define GUARD_INT_1_8 0x02
|
||||
#define GUARD_INT_1_4 0x03
|
||||
#define GUARD_UNKNOWN 0xFF
|
||||
|
||||
/* transmission mode available values */
|
||||
#define TRANS_MODE_2K 0x00
|
||||
#define TRANS_MODE_8K 0x01
|
||||
#define TRANS_MODE_4K 0x02
|
||||
#define TRANS_MODE_UNKNOWN 0xFF
|
||||
|
||||
/* DVBH signalling available values */
|
||||
#define TIMESLICING_PRESENT 0x01
|
||||
#define MPE_FEC_PRESENT 0x02
|
||||
|
||||
/* tune state available */
|
||||
#define TUNE_STATUS_NOT_TUNED 0x00
|
||||
#define TUNE_STATUS_IDLE 0x01
|
||||
#define TUNE_STATUS_LOCKING 0x02
|
||||
#define TUNE_STATUS_SIGNAL_DVB_OK 0x03
|
||||
#define TUNE_STATUS_STREAM_DETECTED 0x04
|
||||
#define TUNE_STATUS_STREAM_TUNED 0x05
|
||||
#define TUNE_STATUS_ERROR 0xFF
|
||||
|
||||
/* available TS FID filter types */
|
||||
#define TS_PID_TYPE_TS 0
|
||||
#define TS_PID_TYPE_PSI_SI 1
|
||||
#define TS_PID_TYPE_MPE 2
|
||||
|
||||
/* number of echos available */
|
||||
#define MAX_ECHOS 15
|
||||
|
||||
/* Context types */
|
||||
#define CONTEXT_LNA 1010
|
||||
#define CONTEXT_ELNA_HYSTERESIS 4003
|
||||
#define CONTEXT_ELNA_GAIN 4004
|
||||
#define CONTEXT_MER_THRESHOLD 5005
|
||||
#define CONTEXT_MER_OFFSET 5006
|
||||
#define CONTEXT_IR_STATE 7000
|
||||
#define CONTEXT_TSOUT_MSB_FIRST 7004
|
||||
#define CONTEXT_TSOUT_FALLING_EDGE 7005
|
||||
|
||||
/* Configuration modes */
|
||||
#define CFG_MODE_ON 0
|
||||
#define CFG_MODE_OFF 1
|
||||
#define CFG_MODE_AUTO 2
|
||||
|
||||
struct as10x_tps {
|
||||
uint8_t modulation;
|
||||
uint8_t hierarchy;
|
||||
uint8_t interleaving_mode;
|
||||
uint8_t code_rate_HP;
|
||||
uint8_t code_rate_LP;
|
||||
uint8_t guard_interval;
|
||||
uint8_t transmission_mode;
|
||||
uint8_t DVBH_mask_HP;
|
||||
uint8_t DVBH_mask_LP;
|
||||
uint16_t cell_ID;
|
||||
} __packed;
|
||||
|
||||
struct as10x_tune_args {
|
||||
/* frequency */
|
||||
uint32_t freq;
|
||||
/* bandwidth */
|
||||
uint8_t bandwidth;
|
||||
/* hierarchy selection */
|
||||
uint8_t hier_select;
|
||||
/* constellation */
|
||||
uint8_t modulation;
|
||||
/* hierarchy */
|
||||
uint8_t hierarchy;
|
||||
/* interleaving mode */
|
||||
uint8_t interleaving_mode;
|
||||
/* code rate */
|
||||
uint8_t code_rate;
|
||||
/* guard interval */
|
||||
uint8_t guard_interval;
|
||||
/* transmission mode */
|
||||
uint8_t transmission_mode;
|
||||
} __packed;
|
||||
|
||||
struct as10x_tune_status {
|
||||
/* tune status */
|
||||
uint8_t tune_state;
|
||||
/* signal strength */
|
||||
int16_t signal_strength;
|
||||
/* packet error rate 10^-4 */
|
||||
uint16_t PER;
|
||||
/* bit error rate 10^-4 */
|
||||
uint16_t BER;
|
||||
} __packed;
|
||||
|
||||
struct as10x_demod_stats {
|
||||
/* frame counter */
|
||||
uint32_t frame_count;
|
||||
/* Bad frame counter */
|
||||
uint32_t bad_frame_count;
|
||||
/* Number of wrong bytes fixed by Reed-Solomon */
|
||||
uint32_t bytes_fixed_by_rs;
|
||||
/* Averaged MER */
|
||||
uint16_t mer;
|
||||
/* statistics calculation state indicator (started or not) */
|
||||
uint8_t has_started;
|
||||
} __packed;
|
||||
|
||||
struct as10x_ts_filter {
|
||||
uint16_t pid; /* valid PID value 0x00 : 0x2000 */
|
||||
uint8_t type; /* Red TS_PID_TYPE_<N> values */
|
||||
uint8_t idx; /* index in filtering table */
|
||||
} __packed;
|
||||
|
||||
struct as10x_register_value {
|
||||
uint8_t mode;
|
||||
union {
|
||||
uint8_t value8; /* 8 bit value */
|
||||
uint16_t value16; /* 16 bit value */
|
||||
uint32_t value32; /* 32 bit value */
|
||||
} __packed u;
|
||||
} __packed;
|
||||
|
||||
struct as10x_register_addr {
|
||||
/* register addr */
|
||||
uint32_t addr;
|
||||
/* register mode access */
|
||||
uint8_t mode;
|
||||
};
|
||||
|
||||
#endif
|
||||
508
drivers/media/dvb-frontends/atbm8830.c
Normal file
508
drivers/media/dvb-frontends/atbm8830.c
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
|
||||
* ATBM8830, ATBM8831
|
||||
*
|
||||
* Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.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 <asm/div64.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "atbm8830.h"
|
||||
#include "atbm8830_priv.h"
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "atbm8830: " args); \
|
||||
} while (0)
|
||||
|
||||
static int debug;
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 dev_addr;
|
||||
u8 buf1[] = { reg >> 8, reg & 0xFF };
|
||||
u8 buf2[] = { data };
|
||||
struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
|
||||
struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
|
||||
|
||||
dev_addr = priv->config->demod_address;
|
||||
msg1.addr = dev_addr;
|
||||
msg2.addr = dev_addr;
|
||||
|
||||
if (debug >= 2)
|
||||
dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg1, 1);
|
||||
if (ret != 1)
|
||||
return -EIO;
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg2, 1);
|
||||
return (ret != 1) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
|
||||
{
|
||||
int ret;
|
||||
u8 dev_addr;
|
||||
|
||||
u8 buf1[] = { reg >> 8, reg & 0xFF };
|
||||
u8 buf2[] = { 0 };
|
||||
struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
|
||||
struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
|
||||
|
||||
dev_addr = priv->config->demod_address;
|
||||
msg1.addr = dev_addr;
|
||||
msg2.addr = dev_addr;
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg1, 1);
|
||||
if (ret != 1) {
|
||||
dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg2, 1);
|
||||
if (ret != 1)
|
||||
return -EIO;
|
||||
|
||||
*p_data = buf2[0];
|
||||
if (debug >= 2)
|
||||
dprintk("%s: reg=0x%04X, data=0x%02X\n",
|
||||
__func__, reg, buf2[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lock register latch so that multi-register read is atomic */
|
||||
static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
|
||||
{
|
||||
return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
|
||||
}
|
||||
|
||||
static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
|
||||
{
|
||||
u32 val;
|
||||
u64 t;
|
||||
|
||||
/* 0x100000 * freq / 30.4MHz */
|
||||
t = (u64)0x100000 * freq;
|
||||
do_div(t, 30400);
|
||||
val = t;
|
||||
|
||||
atbm8830_write_reg(priv, REG_OSC_CLK, val);
|
||||
atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
|
||||
atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
|
||||
{
|
||||
|
||||
u32 fs = priv->config->osc_clk_freq;
|
||||
u64 t;
|
||||
u32 val;
|
||||
u8 dat;
|
||||
|
||||
if (freq != 0) {
|
||||
/* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
|
||||
t = (u64) 2 * 31416 * (freq - fs);
|
||||
t <<= 22;
|
||||
do_div(t, fs);
|
||||
do_div(t, 1000);
|
||||
val = t;
|
||||
|
||||
atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
|
||||
atbm8830_write_reg(priv, REG_IF_FREQ, val);
|
||||
atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
|
||||
atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
|
||||
|
||||
atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
|
||||
dat &= 0xFC;
|
||||
atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
|
||||
} else {
|
||||
/* Zero IF */
|
||||
atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
|
||||
|
||||
atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
|
||||
dat &= 0xFC;
|
||||
dat |= 0x02;
|
||||
atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
|
||||
|
||||
if (priv->config->zif_swap_iq)
|
||||
atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
|
||||
else
|
||||
atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_locked(struct atbm_state *priv, u8 *locked)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
|
||||
|
||||
if (locked != NULL)
|
||||
*locked = (status == 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_agc_config(struct atbm_state *priv,
|
||||
u8 min, u8 max, u8 hold_loop)
|
||||
{
|
||||
/* no effect if both min and max are zero */
|
||||
if (!min && !max)
|
||||
return 0;
|
||||
|
||||
atbm8830_write_reg(priv, REG_AGC_MIN, min);
|
||||
atbm8830_write_reg(priv, REG_AGC_MAX, max);
|
||||
atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_static_channel_mode(struct atbm_state *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
atbm8830_write_reg(priv, 0x099B + i, 0x08);
|
||||
|
||||
atbm8830_write_reg(priv, 0x095B, 0x7F);
|
||||
atbm8830_write_reg(priv, 0x09CB, 0x01);
|
||||
atbm8830_write_reg(priv, 0x09CC, 0x7F);
|
||||
atbm8830_write_reg(priv, 0x09CD, 0x7F);
|
||||
atbm8830_write_reg(priv, 0x0E01, 0x20);
|
||||
|
||||
/* For single carrier */
|
||||
atbm8830_write_reg(priv, 0x0B03, 0x0A);
|
||||
atbm8830_write_reg(priv, 0x0935, 0x10);
|
||||
atbm8830_write_reg(priv, 0x0936, 0x08);
|
||||
atbm8830_write_reg(priv, 0x093E, 0x08);
|
||||
atbm8830_write_reg(priv, 0x096E, 0x06);
|
||||
|
||||
/* frame_count_max0 */
|
||||
atbm8830_write_reg(priv, 0x0B09, 0x00);
|
||||
/* frame_count_max1 */
|
||||
atbm8830_write_reg(priv, 0x0B0A, 0x08);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_ts_config(struct atbm_state *priv)
|
||||
{
|
||||
const struct atbm8830_config *cfg = priv->config;
|
||||
|
||||
/*Set parallel/serial ts mode*/
|
||||
atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
|
||||
atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
|
||||
/*Set ts sampling edge*/
|
||||
atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
|
||||
cfg->ts_sampling_edge ? 1 : 0);
|
||||
/*Set ts clock freerun*/
|
||||
atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
|
||||
cfg->ts_clk_gated ? 0 : 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
const struct atbm8830_config *cfg = priv->config;
|
||||
|
||||
/*Set oscillator frequency*/
|
||||
set_osc_freq(priv, cfg->osc_clk_freq);
|
||||
|
||||
/*Set IF frequency*/
|
||||
set_if_freq(priv, cfg->if_freq);
|
||||
|
||||
/*Set AGC Config*/
|
||||
set_agc_config(priv, cfg->agc_min, cfg->agc_max,
|
||||
cfg->agc_hold_loop);
|
||||
|
||||
/*Set static channel mode*/
|
||||
set_static_channel_mode(priv);
|
||||
|
||||
set_ts_config(priv);
|
||||
/*Turn off DSP reset*/
|
||||
atbm8830_write_reg(priv, 0x000A, 0);
|
||||
|
||||
/*SW version test*/
|
||||
atbm8830_write_reg(priv, 0x020C, 11);
|
||||
|
||||
/* Run */
|
||||
atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void atbm8830_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct atbm_state *state = fe->demodulator_priv;
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static int atbm8830_set_fe(struct dvb_frontend *fe)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
int i;
|
||||
u8 locked = 0;
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* set frequency */
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
fe->ops.tuner_ops.set_params(fe);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
/* start auto lock */
|
||||
for (i = 0; i < 10; i++) {
|
||||
mdelay(100);
|
||||
dprintk("Try %d\n", i);
|
||||
is_locked(priv, &locked);
|
||||
if (locked != 0) {
|
||||
dprintk("ATBM8830 locked!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_get_fe(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* TODO: get real readings from device */
|
||||
/* inversion status */
|
||||
c->inversion = INVERSION_OFF;
|
||||
|
||||
/* bandwidth */
|
||||
c->bandwidth_hz = 8000000;
|
||||
|
||||
c->code_rate_HP = FEC_AUTO;
|
||||
c->code_rate_LP = FEC_AUTO;
|
||||
|
||||
c->modulation = QAM_AUTO;
|
||||
|
||||
/* transmission mode */
|
||||
c->transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
|
||||
/* guard interval */
|
||||
c->guard_interval = GUARD_INTERVAL_AUTO;
|
||||
|
||||
/* hierarchy */
|
||||
c->hierarchy = HIERARCHY_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *fesettings)
|
||||
{
|
||||
fesettings->min_delay_ms = 0;
|
||||
fesettings->step_size = 0;
|
||||
fesettings->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
u8 locked = 0;
|
||||
u8 agc_locked = 0;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
*fe_status = 0;
|
||||
|
||||
is_locked(priv, &locked);
|
||||
if (locked) {
|
||||
*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
}
|
||||
dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
|
||||
|
||||
atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
|
||||
dprintk("AGC Lock: %d\n", agc_locked);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
u32 frame_err;
|
||||
u8 t;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
atbm8830_reglatch_lock(priv, 1);
|
||||
|
||||
atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
|
||||
frame_err = t & 0x7F;
|
||||
frame_err <<= 8;
|
||||
atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
|
||||
frame_err |= t;
|
||||
|
||||
atbm8830_reglatch_lock(priv, 0);
|
||||
|
||||
*ber = frame_err * 100 / 32767;
|
||||
|
||||
dprintk("%s: ber=0x%x\n", __func__, *ber);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
u32 pwm;
|
||||
u8 t;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
atbm8830_reglatch_lock(priv, 1);
|
||||
|
||||
atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
|
||||
pwm = t & 0x03;
|
||||
pwm <<= 8;
|
||||
atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
|
||||
pwm |= t;
|
||||
|
||||
atbm8830_reglatch_lock(priv, 0);
|
||||
|
||||
dprintk("AGC PWM = 0x%02X\n", pwm);
|
||||
pwm = 0x400 - pwm;
|
||||
|
||||
*signal = pwm * 0x10000 / 0x400;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
dprintk("%s\n", __func__);
|
||||
*snr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
dprintk("%s\n", __func__);
|
||||
*ucblocks = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
|
||||
return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops atbm8830_ops = {
|
||||
.delsys = { SYS_DTMB },
|
||||
.info = {
|
||||
.name = "AltoBeam ATBM8830/8831 DMB-TH",
|
||||
.frequency_min = 474000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 10000,
|
||||
.caps =
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO
|
||||
},
|
||||
|
||||
.release = atbm8830_release,
|
||||
|
||||
.init = atbm8830_init,
|
||||
.sleep = NULL,
|
||||
.write = NULL,
|
||||
.i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
|
||||
|
||||
.set_frontend = atbm8830_set_fe,
|
||||
.get_frontend = atbm8830_get_fe,
|
||||
.get_tune_settings = atbm8830_get_tune_settings,
|
||||
|
||||
.read_status = atbm8830_read_status,
|
||||
.read_ber = atbm8830_read_ber,
|
||||
.read_signal_strength = atbm8830_read_signal_strength,
|
||||
.read_snr = atbm8830_read_snr,
|
||||
.read_ucblocks = atbm8830_read_ucblocks,
|
||||
};
|
||||
|
||||
struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct atbm_state *priv = NULL;
|
||||
u8 data = 0;
|
||||
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
if (config == NULL || i2c == NULL)
|
||||
return NULL;
|
||||
|
||||
priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
goto error_out;
|
||||
|
||||
priv->config = config;
|
||||
priv->i2c = i2c;
|
||||
|
||||
/* check if the demod is there */
|
||||
if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
|
||||
dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
|
||||
__func__, priv->config->demod_address);
|
||||
goto error_out;
|
||||
}
|
||||
dprintk("atbm8830 chip id: 0x%02X\n", data);
|
||||
|
||||
memcpy(&priv->frontend.ops, &atbm8830_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
priv->frontend.demodulator_priv = priv;
|
||||
|
||||
atbm8830_init(&priv->frontend);
|
||||
|
||||
atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
|
||||
|
||||
return &priv->frontend;
|
||||
|
||||
error_out:
|
||||
dprintk("%s() error_out\n", __func__);
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(atbm8830_attach);
|
||||
|
||||
MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
|
||||
MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
76
drivers/media/dvb-frontends/atbm8830.h
Normal file
76
drivers/media/dvb-frontends/atbm8830.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
|
||||
* ATBM8830, ATBM8831
|
||||
*
|
||||
* Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.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 __ATBM8830_H__
|
||||
#define __ATBM8830_H__
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define ATBM8830_PROD_8830 0
|
||||
#define ATBM8830_PROD_8831 1
|
||||
|
||||
struct atbm8830_config {
|
||||
|
||||
/* product type */
|
||||
u8 prod;
|
||||
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* parallel or serial transport stream */
|
||||
u8 serial_ts;
|
||||
|
||||
/* transport stream clock output only when receiving valid stream */
|
||||
u8 ts_clk_gated;
|
||||
|
||||
/* Decoder sample TS data at rising edge of clock */
|
||||
u8 ts_sampling_edge;
|
||||
|
||||
/* Oscillator clock frequency */
|
||||
u32 osc_clk_freq; /* in kHz */
|
||||
|
||||
/* IF frequency */
|
||||
u32 if_freq; /* in kHz */
|
||||
|
||||
/* Swap I/Q for zero IF */
|
||||
u8 zif_swap_iq;
|
||||
|
||||
/* Tuner AGC settings */
|
||||
u8 agc_min;
|
||||
u8 agc_max;
|
||||
u8 agc_hold_loop;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_ATBM8830)
|
||||
extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
|
||||
struct i2c_adapter *i2c) {
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_ATBM8830 */
|
||||
|
||||
#endif /* __ATBM8830_H__ */
|
||||
75
drivers/media/dvb-frontends/atbm8830_priv.h
Normal file
75
drivers/media/dvb-frontends/atbm8830_priv.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
|
||||
* ATBM8830, ATBM8831
|
||||
*
|
||||
* Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.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 __ATBM8830_PRIV_H
|
||||
#define __ATBM8830_PRIV_H
|
||||
|
||||
struct atbm_state {
|
||||
struct i2c_adapter *i2c;
|
||||
/* configuration settings */
|
||||
const struct atbm8830_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
};
|
||||
|
||||
#define REG_CHIP_ID 0x0000
|
||||
#define REG_TUNER_BASEBAND 0x0001
|
||||
#define REG_DEMOD_RUN 0x0004
|
||||
#define REG_DSP_RESET 0x0005
|
||||
#define REG_RAM_RESET 0x0006
|
||||
#define REG_ADC_RESET 0x0007
|
||||
#define REG_TSPORT_RESET 0x0008
|
||||
#define REG_BLKERR_POL 0x000C
|
||||
#define REG_I2C_GATE 0x0103
|
||||
#define REG_TS_SAMPLE_EDGE 0x0301
|
||||
#define REG_TS_PKT_LEN_204 0x0302
|
||||
#define REG_TS_PKT_LEN_AUTO 0x0303
|
||||
#define REG_TS_SERIAL 0x0305
|
||||
#define REG_TS_CLK_FREERUN 0x0306
|
||||
#define REG_TS_VALID_MODE 0x0307
|
||||
#define REG_TS_CLK_MODE 0x030B /* 1 for serial, 0 for parallel */
|
||||
|
||||
#define REG_TS_ERRBIT_USE 0x030C
|
||||
#define REG_LOCK_STATUS 0x030D
|
||||
#define REG_ADC_CONFIG 0x0602
|
||||
#define REG_CARRIER_OFFSET 0x0827 /* 0x0827-0x0829 little endian */
|
||||
#define REG_DETECTED_PN_MODE 0x082D
|
||||
#define REG_READ_LATCH 0x084D
|
||||
#define REG_IF_FREQ 0x0A00 /* 0x0A00-0x0A02 little endian */
|
||||
#define REG_OSC_CLK 0x0A03 /* 0x0A03-0x0A05 little endian */
|
||||
#define REG_BYPASS_CCI 0x0A06
|
||||
#define REG_ANALOG_LUMA_DETECTED 0x0A25
|
||||
#define REG_ANALOG_AUDIO_DETECTED 0x0A26
|
||||
#define REG_ANALOG_CHROMA_DETECTED 0x0A39
|
||||
#define REG_FRAME_ERR_CNT 0x0B04
|
||||
#define REG_USE_EXT_ADC 0x0C00
|
||||
#define REG_SWAP_I_Q 0x0C01
|
||||
#define REG_TPS_MANUAL 0x0D01
|
||||
#define REG_TPS_CONFIG 0x0D02
|
||||
#define REG_BYPASS_DEINTERLEAVER 0x0E00
|
||||
#define REG_AGC_TARGET 0x1003 /* 0x1003-0x1005 little endian */
|
||||
#define REG_AGC_MIN 0x1020
|
||||
#define REG_AGC_MAX 0x1023
|
||||
#define REG_AGC_LOCK 0x1027
|
||||
#define REG_AGC_PWM_VAL 0x1028 /* 0x1028-0x1029 little endian */
|
||||
#define REG_AGC_HOLD_LOOP 0x1031
|
||||
|
||||
#endif
|
||||
|
||||
98
drivers/media/dvb-frontends/au8522.h
Normal file
98
drivers/media/dvb-frontends/au8522.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Auvitek AU8522 QAM/8VSB demodulator driver
|
||||
|
||||
Copyright (C) 2008 Steven Toth <stoth@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; 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 __AU8522_H__
|
||||
#define __AU8522_H__
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
enum au8522_if_freq {
|
||||
AU8522_IF_6MHZ = 0,
|
||||
AU8522_IF_4MHZ,
|
||||
AU8522_IF_3_25MHZ,
|
||||
};
|
||||
|
||||
struct au8522_led_config {
|
||||
u16 vsb8_strong;
|
||||
u16 qam64_strong;
|
||||
u16 qam256_strong;
|
||||
|
||||
u16 gpio_output;
|
||||
/* unset hi bits, set low bits */
|
||||
u16 gpio_output_enable;
|
||||
u16 gpio_output_disable;
|
||||
|
||||
u16 gpio_leds;
|
||||
u8 *led_states;
|
||||
unsigned int num_led_states;
|
||||
};
|
||||
|
||||
struct au8522_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* Return lock status based on tuner lock, or demod lock */
|
||||
#define AU8522_TUNERLOCKING 0
|
||||
#define AU8522_DEMODLOCKING 1
|
||||
u8 status_mode;
|
||||
|
||||
struct au8522_led_config *led_cfg;
|
||||
|
||||
enum au8522_if_freq vsb_if;
|
||||
enum au8522_if_freq qam_if;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_AU8522_DTV)
|
||||
extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *au8522_attach(const struct au8522_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_AU8522 */
|
||||
|
||||
/* Other modes may need to be added later */
|
||||
enum au8522_video_input {
|
||||
AU8522_COMPOSITE_CH1 = 1,
|
||||
AU8522_COMPOSITE_CH2,
|
||||
AU8522_COMPOSITE_CH3,
|
||||
AU8522_COMPOSITE_CH4,
|
||||
AU8522_COMPOSITE_CH4_SIF,
|
||||
AU8522_SVIDEO_CH13,
|
||||
AU8522_SVIDEO_CH24,
|
||||
};
|
||||
|
||||
enum au8522_audio_input {
|
||||
AU8522_AUDIO_NONE,
|
||||
AU8522_AUDIO_SIF,
|
||||
};
|
||||
|
||||
#endif /* __AU8522_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
*/
|
||||
277
drivers/media/dvb-frontends/au8522_common.c
Normal file
277
drivers/media/dvb-frontends/au8522_common.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
Auvitek AU8522 QAM/8VSB demodulator driver
|
||||
|
||||
Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
|
||||
Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
|
||||
Copyright (C) 2005-2008 Auvitek International, Ltd.
|
||||
Copyright (C) 2012 Michael Krufky <mkrufky@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; 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/i2c.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "au8522_priv.h"
|
||||
|
||||
static int debug;
|
||||
|
||||
#define dprintk(arg...)\
|
||||
do { if (debug)\
|
||||
printk(arg);\
|
||||
} while (0)
|
||||
|
||||
/* Despite the name "hybrid_tuner", the framework works just as well for
|
||||
hybrid demodulators as well... */
|
||||
static LIST_HEAD(hybrid_tuner_instance_list);
|
||||
static DEFINE_MUTEX(au8522_list_mutex);
|
||||
|
||||
/* 16 bit registers, 8 bit values */
|
||||
int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
|
||||
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address,
|
||||
.flags = 0, .buf = buf, .len = 3 };
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
|
||||
if (ret != 1)
|
||||
printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
|
||||
"ret == %i)\n", __func__, reg, data, ret);
|
||||
|
||||
return (ret != 1) ? -1 : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_writereg);
|
||||
|
||||
u8 au8522_readreg(struct au8522_state *state, u16 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
|
||||
u8 b1[] = { 0 };
|
||||
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = state->config->demod_address, .flags = 0,
|
||||
.buf = b0, .len = 2 },
|
||||
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
|
||||
.buf = b1, .len = 1 } };
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2)
|
||||
printk(KERN_ERR "%s: readreg error (ret == %i)\n",
|
||||
__func__, ret);
|
||||
return b1[0];
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_readreg);
|
||||
|
||||
int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s(%d)\n", __func__, enable);
|
||||
|
||||
if (state->operational_mode == AU8522_ANALOG_MODE) {
|
||||
/* We're being asked to manage the gate even though we're
|
||||
not in digital mode. This can occur if we get switched
|
||||
over to analog mode before the dvb_frontend kernel thread
|
||||
has completely shutdown */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
return au8522_writereg(state, 0x106, 1);
|
||||
else
|
||||
return au8522_writereg(state, 0x106, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
|
||||
|
||||
int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s(%d)\n", __func__, enable);
|
||||
|
||||
if (enable)
|
||||
return au8522_writereg(state, 0x106, 1);
|
||||
else
|
||||
return au8522_writereg(state, 0x106, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
|
||||
|
||||
/* Reset the demod hardware and reset all of the configuration registers
|
||||
to a default state. */
|
||||
int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
|
||||
u8 client_address)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&au8522_list_mutex);
|
||||
ret = hybrid_tuner_request_state(struct au8522_state, (*state),
|
||||
hybrid_tuner_instance_list,
|
||||
i2c, client_address, "au8522");
|
||||
mutex_unlock(&au8522_list_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_get_state);
|
||||
|
||||
void au8522_release_state(struct au8522_state *state)
|
||||
{
|
||||
mutex_lock(&au8522_list_mutex);
|
||||
if (state != NULL)
|
||||
hybrid_tuner_release_state(state);
|
||||
mutex_unlock(&au8522_list_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_release_state);
|
||||
|
||||
static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
|
||||
{
|
||||
struct au8522_led_config *led_config = state->config->led_cfg;
|
||||
u8 val;
|
||||
|
||||
/* bail out if we can't control an LED */
|
||||
if (!led_config || !led_config->gpio_output ||
|
||||
!led_config->gpio_output_enable || !led_config->gpio_output_disable)
|
||||
return 0;
|
||||
|
||||
val = au8522_readreg(state, 0x4000 |
|
||||
(led_config->gpio_output & ~0xc000));
|
||||
if (onoff) {
|
||||
/* enable GPIO output */
|
||||
val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
|
||||
val |= (led_config->gpio_output_enable & 0xff);
|
||||
} else {
|
||||
/* disable GPIO output */
|
||||
val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
|
||||
val |= (led_config->gpio_output_disable & 0xff);
|
||||
}
|
||||
return au8522_writereg(state, 0x8000 |
|
||||
(led_config->gpio_output & ~0xc000), val);
|
||||
}
|
||||
|
||||
/* led = 0 | off
|
||||
* led = 1 | signal ok
|
||||
* led = 2 | signal strong
|
||||
* led < 0 | only light led if leds are currently off
|
||||
*/
|
||||
int au8522_led_ctrl(struct au8522_state *state, int led)
|
||||
{
|
||||
struct au8522_led_config *led_config = state->config->led_cfg;
|
||||
int i, ret = 0;
|
||||
|
||||
/* bail out if we can't control an LED */
|
||||
if (!led_config || !led_config->gpio_leds ||
|
||||
!led_config->num_led_states || !led_config->led_states)
|
||||
return 0;
|
||||
|
||||
if (led < 0) {
|
||||
/* if LED is already lit, then leave it as-is */
|
||||
if (state->led_state)
|
||||
return 0;
|
||||
else
|
||||
led *= -1;
|
||||
}
|
||||
|
||||
/* toggle LED if changing state */
|
||||
if (state->led_state != led) {
|
||||
u8 val;
|
||||
|
||||
dprintk("%s: %d\n", __func__, led);
|
||||
|
||||
au8522_led_gpio_enable(state, 1);
|
||||
|
||||
val = au8522_readreg(state, 0x4000 |
|
||||
(led_config->gpio_leds & ~0xc000));
|
||||
|
||||
/* start with all leds off */
|
||||
for (i = 0; i < led_config->num_led_states; i++)
|
||||
val &= ~led_config->led_states[i];
|
||||
|
||||
/* set selected LED state */
|
||||
if (led < led_config->num_led_states)
|
||||
val |= led_config->led_states[led];
|
||||
else if (led_config->num_led_states)
|
||||
val |=
|
||||
led_config->led_states[led_config->num_led_states - 1];
|
||||
|
||||
ret = au8522_writereg(state, 0x8000 |
|
||||
(led_config->gpio_leds & ~0xc000), val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
state->led_state = led;
|
||||
|
||||
if (led == 0)
|
||||
au8522_led_gpio_enable(state, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_led_ctrl);
|
||||
|
||||
int au8522_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
state->operational_mode = AU8522_DIGITAL_MODE;
|
||||
|
||||
/* Clear out any state associated with the digital side of the
|
||||
chip, so that when it gets powered back up it won't think
|
||||
that it is already tuned */
|
||||
state->current_frequency = 0;
|
||||
|
||||
au8522_writereg(state, 0xa4, 1 << 5);
|
||||
|
||||
au8522_i2c_gate_ctrl(fe, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_init);
|
||||
|
||||
int au8522_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
/* Only power down if the digital side is currently using the chip */
|
||||
if (state->operational_mode == AU8522_ANALOG_MODE) {
|
||||
/* We're not in one of the expected power modes, which means
|
||||
that the DVB thread is probably telling us to go to sleep
|
||||
even though the analog frontend has already started using
|
||||
the chip. So ignore the request */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* turn off led */
|
||||
au8522_led_ctrl(state, 0);
|
||||
|
||||
/* Power down the chip */
|
||||
au8522_writereg(state, 0xa4, 1 << 5);
|
||||
|
||||
state->current_frequency = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_sleep);
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
|
||||
|
||||
MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
|
||||
MODULE_AUTHOR("Steven Toth");
|
||||
MODULE_LICENSE("GPL");
|
||||
831
drivers/media/dvb-frontends/au8522_decoder.c
Normal file
831
drivers/media/dvb-frontends/au8522_decoder.c
Normal file
|
|
@ -0,0 +1,831 @@
|
|||
/*
|
||||
* Auvitek AU8522 QAM/8VSB demodulator driver and video decoder
|
||||
*
|
||||
* Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
|
||||
* Copyright (C) 2005-2008 Auvitek International, Ltd.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* Developer notes:
|
||||
*
|
||||
* VBI support is not yet working
|
||||
* Enough is implemented here for CVBS and S-Video inputs, but the actual
|
||||
* analog demodulator code isn't implemented (not needed for xc5000 since it
|
||||
* has its own demodulator and outputs CVBS)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include "au8522.h"
|
||||
#include "au8522_priv.h"
|
||||
|
||||
MODULE_AUTHOR("Devin Heitmueller");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int au8522_analog_debug;
|
||||
|
||||
|
||||
module_param_named(analog_debug, au8522_analog_debug, int, 0644);
|
||||
|
||||
MODULE_PARM_DESC(analog_debug,
|
||||
"Analog debugging messages [0=Off (default) 1=On]");
|
||||
|
||||
struct au8522_register_config {
|
||||
u16 reg_name;
|
||||
u8 reg_val[8];
|
||||
};
|
||||
|
||||
|
||||
/* Video Decoder Filter Coefficients
|
||||
The values are as follows from left to right
|
||||
0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13"
|
||||
*/
|
||||
static const struct au8522_register_config filter_coef[] = {
|
||||
{AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R413, {0xe6, 0x00, 0xe6, 0xe6, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R414, {0x40, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R415, {0x1b, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R416, {0xc0, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R417, {0x04, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R418, {0x8c, 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x00} },
|
||||
{AU8522_FILTER_COEF_R419, {0xa0, 0x40, 0xa0, 0xa0, 0x40, 0x40, 0x40} },
|
||||
{AU8522_FILTER_COEF_R41A, {0x21, 0x09, 0x21, 0x21, 0x09, 0x09, 0x09} },
|
||||
{AU8522_FILTER_COEF_R41B, {0x6c, 0x38, 0x6c, 0x6c, 0x38, 0x38, 0x38} },
|
||||
{AU8522_FILTER_COEF_R41C, {0x03, 0xff, 0x03, 0x03, 0xff, 0xff, 0xff} },
|
||||
{AU8522_FILTER_COEF_R41D, {0xbf, 0xc7, 0xbf, 0xbf, 0xc7, 0xc7, 0xc7} },
|
||||
{AU8522_FILTER_COEF_R41E, {0xa0, 0xdf, 0xa0, 0xa0, 0xdf, 0xdf, 0xdf} },
|
||||
{AU8522_FILTER_COEF_R41F, {0x10, 0x06, 0x10, 0x10, 0x06, 0x06, 0x06} },
|
||||
{AU8522_FILTER_COEF_R420, {0xae, 0x30, 0xae, 0xae, 0x30, 0x30, 0x30} },
|
||||
{AU8522_FILTER_COEF_R421, {0xc4, 0x01, 0xc4, 0xc4, 0x01, 0x01, 0x01} },
|
||||
{AU8522_FILTER_COEF_R422, {0x54, 0xdd, 0x54, 0x54, 0xdd, 0xdd, 0xdd} },
|
||||
{AU8522_FILTER_COEF_R423, {0xd0, 0xaf, 0xd0, 0xd0, 0xaf, 0xaf, 0xaf} },
|
||||
{AU8522_FILTER_COEF_R424, {0x1c, 0xf7, 0x1c, 0x1c, 0xf7, 0xf7, 0xf7} },
|
||||
{AU8522_FILTER_COEF_R425, {0x76, 0xdb, 0x76, 0x76, 0xdb, 0xdb, 0xdb} },
|
||||
{AU8522_FILTER_COEF_R426, {0x61, 0xc0, 0x61, 0x61, 0xc0, 0xc0, 0xc0} },
|
||||
{AU8522_FILTER_COEF_R427, {0xd1, 0x2f, 0xd1, 0xd1, 0x2f, 0x2f, 0x2f} },
|
||||
{AU8522_FILTER_COEF_R428, {0x84, 0xd8, 0x84, 0x84, 0xd8, 0xd8, 0xd8} },
|
||||
{AU8522_FILTER_COEF_R429, {0x06, 0xfb, 0x06, 0x06, 0xfb, 0xfb, 0xfb} },
|
||||
{AU8522_FILTER_COEF_R42A, {0x21, 0xd5, 0x21, 0x21, 0xd5, 0xd5, 0xd5} },
|
||||
{AU8522_FILTER_COEF_R42B, {0x0a, 0x3e, 0x0a, 0x0a, 0x3e, 0x3e, 0x3e} },
|
||||
{AU8522_FILTER_COEF_R42C, {0xe6, 0x15, 0xe6, 0xe6, 0x15, 0x15, 0x15} },
|
||||
{AU8522_FILTER_COEF_R42D, {0x01, 0x34, 0x01, 0x01, 0x34, 0x34, 0x34} },
|
||||
|
||||
};
|
||||
#define NUM_FILTER_COEF (sizeof(filter_coef)\
|
||||
/ sizeof(struct au8522_register_config))
|
||||
|
||||
|
||||
/* Registers 0x060b through 0x0652 are the LP Filter coefficients
|
||||
The values are as follows from left to right
|
||||
0="SIF" 1="ATVRF/ATVRF13"
|
||||
Note: the "ATVRF/ATVRF13" mode has never been tested
|
||||
*/
|
||||
static const struct au8522_register_config lpfilter_coef[] = {
|
||||
{0x060b, {0x21, 0x0b} },
|
||||
{0x060c, {0xad, 0xad} },
|
||||
{0x060d, {0x70, 0xf0} },
|
||||
{0x060e, {0xea, 0xe9} },
|
||||
{0x060f, {0xdd, 0xdd} },
|
||||
{0x0610, {0x08, 0x64} },
|
||||
{0x0611, {0x60, 0x60} },
|
||||
{0x0612, {0xf8, 0xb2} },
|
||||
{0x0613, {0x01, 0x02} },
|
||||
{0x0614, {0xe4, 0xb4} },
|
||||
{0x0615, {0x19, 0x02} },
|
||||
{0x0616, {0xae, 0x2e} },
|
||||
{0x0617, {0xee, 0xc5} },
|
||||
{0x0618, {0x56, 0x56} },
|
||||
{0x0619, {0x30, 0x58} },
|
||||
{0x061a, {0xf9, 0xf8} },
|
||||
{0x061b, {0x24, 0x64} },
|
||||
{0x061c, {0x07, 0x07} },
|
||||
{0x061d, {0x30, 0x30} },
|
||||
{0x061e, {0xa9, 0xed} },
|
||||
{0x061f, {0x09, 0x0b} },
|
||||
{0x0620, {0x42, 0xc2} },
|
||||
{0x0621, {0x1d, 0x2a} },
|
||||
{0x0622, {0xd6, 0x56} },
|
||||
{0x0623, {0x95, 0x8b} },
|
||||
{0x0624, {0x2b, 0x2b} },
|
||||
{0x0625, {0x30, 0x24} },
|
||||
{0x0626, {0x3e, 0x3e} },
|
||||
{0x0627, {0x62, 0xe2} },
|
||||
{0x0628, {0xe9, 0xf5} },
|
||||
{0x0629, {0x99, 0x19} },
|
||||
{0x062a, {0xd4, 0x11} },
|
||||
{0x062b, {0x03, 0x04} },
|
||||
{0x062c, {0xb5, 0x85} },
|
||||
{0x062d, {0x1e, 0x20} },
|
||||
{0x062e, {0x2a, 0xea} },
|
||||
{0x062f, {0xd7, 0xd2} },
|
||||
{0x0630, {0x15, 0x15} },
|
||||
{0x0631, {0xa3, 0xa9} },
|
||||
{0x0632, {0x1f, 0x1f} },
|
||||
{0x0633, {0xf9, 0xd1} },
|
||||
{0x0634, {0xc0, 0xc3} },
|
||||
{0x0635, {0x4d, 0x8d} },
|
||||
{0x0636, {0x21, 0x31} },
|
||||
{0x0637, {0x83, 0x83} },
|
||||
{0x0638, {0x08, 0x8c} },
|
||||
{0x0639, {0x19, 0x19} },
|
||||
{0x063a, {0x45, 0xa5} },
|
||||
{0x063b, {0xef, 0xec} },
|
||||
{0x063c, {0x8a, 0x8a} },
|
||||
{0x063d, {0xf4, 0xf6} },
|
||||
{0x063e, {0x8f, 0x8f} },
|
||||
{0x063f, {0x44, 0x0c} },
|
||||
{0x0640, {0xef, 0xf0} },
|
||||
{0x0641, {0x66, 0x66} },
|
||||
{0x0642, {0xcc, 0xd2} },
|
||||
{0x0643, {0x41, 0x41} },
|
||||
{0x0644, {0x63, 0x93} },
|
||||
{0x0645, {0x8e, 0x8e} },
|
||||
{0x0646, {0xa2, 0x42} },
|
||||
{0x0647, {0x7b, 0x7b} },
|
||||
{0x0648, {0x04, 0x04} },
|
||||
{0x0649, {0x00, 0x00} },
|
||||
{0x064a, {0x40, 0x40} },
|
||||
{0x064b, {0x8c, 0x98} },
|
||||
{0x064c, {0x00, 0x00} },
|
||||
{0x064d, {0x63, 0xc3} },
|
||||
{0x064e, {0x04, 0x04} },
|
||||
{0x064f, {0x20, 0x20} },
|
||||
{0x0650, {0x00, 0x00} },
|
||||
{0x0651, {0x40, 0x40} },
|
||||
{0x0652, {0x01, 0x01} },
|
||||
};
|
||||
#define NUM_LPFILTER_COEF (sizeof(lpfilter_coef)\
|
||||
/ sizeof(struct au8522_register_config))
|
||||
|
||||
static inline struct au8522_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct au8522_state, sd);
|
||||
}
|
||||
|
||||
static void setup_vbi(struct au8522_state *state, int aud_input)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* These are set to zero regardless of what mode we're in */
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_L_REG018H, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_THRESH1_REG01CH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H,
|
||||
0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H,
|
||||
0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H,
|
||||
0x00);
|
||||
|
||||
/* Setup the VBI registers */
|
||||
for (i = 0x30; i < 0x60; i++)
|
||||
au8522_writereg(state, i, 0x40);
|
||||
|
||||
/* For some reason, every register is 0x40 except register 0x44
|
||||
(confirmed via the HVR-950q USB capture) */
|
||||
au8522_writereg(state, 0x44, 0x60);
|
||||
|
||||
/* Enable VBI (we always do this regardless of whether the user is
|
||||
viewing closed caption info) */
|
||||
au8522_writereg(state, AU8522_TVDEC_VBI_CTRL_H_REG017H,
|
||||
AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON);
|
||||
|
||||
}
|
||||
|
||||
static void setup_decoder_defaults(struct au8522_state *state, bool is_svideo)
|
||||
{
|
||||
int i;
|
||||
int filter_coef_type;
|
||||
|
||||
/* Provide reasonable defaults for picture tuning values */
|
||||
au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
|
||||
au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
|
||||
au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
|
||||
|
||||
/* Other decoder registers */
|
||||
au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
|
||||
|
||||
if (is_svideo)
|
||||
au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
|
||||
else
|
||||
au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
|
||||
|
||||
au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
|
||||
AU8522_TVDEC_PGA_REG012H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_MODE_REG015H,
|
||||
AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
|
||||
AU8522_TVDED_DBG_MODE_REG060H_CVBS);
|
||||
|
||||
if (state->std == V4L2_STD_PAL_M) {
|
||||
au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
|
||||
AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
|
||||
AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
|
||||
AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO);
|
||||
au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
|
||||
AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M);
|
||||
} else {
|
||||
/* NTSC */
|
||||
au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
|
||||
AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
|
||||
AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
|
||||
AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
|
||||
au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
|
||||
AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
|
||||
}
|
||||
au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
|
||||
AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
|
||||
AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR1_REG065H,
|
||||
AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR2_REG066H,
|
||||
AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_VDIF_THR3_REG067H,
|
||||
AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_NOTCH_THR_REG068H,
|
||||
AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR1_REG069H,
|
||||
AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR2_REG06AH,
|
||||
AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
|
||||
AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
|
||||
if (is_svideo) {
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
|
||||
AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
|
||||
AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
|
||||
} else {
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
|
||||
AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
|
||||
AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
|
||||
}
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
|
||||
AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
|
||||
AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H,
|
||||
AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS);
|
||||
au8522_writereg(state, AU8522_REG071H, AU8522_REG071H_CVBS);
|
||||
au8522_writereg(state, AU8522_REG072H, AU8522_REG072H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H,
|
||||
AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS);
|
||||
au8522_writereg(state, AU8522_REG074H, AU8522_REG074H_CVBS);
|
||||
au8522_writereg(state, AU8522_REG075H, AU8522_REG075H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_DCAGC_CTRL_REG077H,
|
||||
AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_PIC_START_ADJ_REG078H,
|
||||
AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H,
|
||||
AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH,
|
||||
AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_INTRP_CTRL_REG07BH,
|
||||
AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS);
|
||||
au8522_writereg(state, AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H,
|
||||
AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS);
|
||||
au8522_writereg(state, AU8522_TOREGAAGC_REG0E5H,
|
||||
AU8522_TOREGAAGC_REG0E5H_CVBS);
|
||||
au8522_writereg(state, AU8522_REG016H, AU8522_REG016H_CVBS);
|
||||
|
||||
setup_vbi(state, 0);
|
||||
|
||||
if (is_svideo) {
|
||||
/* Despite what the table says, for the HVR-950q we still need
|
||||
to be in CVBS mode for the S-Video input (reason unknown). */
|
||||
/* filter_coef_type = 3; */
|
||||
filter_coef_type = 5;
|
||||
} else {
|
||||
filter_coef_type = 5;
|
||||
}
|
||||
|
||||
/* Load the Video Decoder Filter Coefficients */
|
||||
for (i = 0; i < NUM_FILTER_COEF; i++) {
|
||||
au8522_writereg(state, filter_coef[i].reg_name,
|
||||
filter_coef[i].reg_val[filter_coef_type]);
|
||||
}
|
||||
|
||||
/* It's not clear what these registers are for, but they are always
|
||||
set to the same value regardless of what mode we're in */
|
||||
au8522_writereg(state, AU8522_REG42EH, 0x87);
|
||||
au8522_writereg(state, AU8522_REG42FH, 0xa2);
|
||||
au8522_writereg(state, AU8522_REG430H, 0xbf);
|
||||
au8522_writereg(state, AU8522_REG431H, 0xcb);
|
||||
au8522_writereg(state, AU8522_REG432H, 0xa1);
|
||||
au8522_writereg(state, AU8522_REG433H, 0x41);
|
||||
au8522_writereg(state, AU8522_REG434H, 0x88);
|
||||
au8522_writereg(state, AU8522_REG435H, 0xc2);
|
||||
au8522_writereg(state, AU8522_REG436H, 0x3c);
|
||||
}
|
||||
|
||||
static void au8522_setup_cvbs_mode(struct au8522_state *state, u8 input_mode)
|
||||
{
|
||||
/* here we're going to try the pre-programmed route */
|
||||
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
|
||||
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
|
||||
|
||||
/* PGA in automatic mode */
|
||||
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
|
||||
|
||||
/* Enable clamping control */
|
||||
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
|
||||
|
||||
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
|
||||
|
||||
setup_decoder_defaults(state, false);
|
||||
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
|
||||
}
|
||||
|
||||
static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state,
|
||||
u8 input_mode)
|
||||
{
|
||||
/* here we're going to try the pre-programmed route */
|
||||
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
|
||||
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
|
||||
|
||||
/* It's not clear why we have to have the PGA in automatic mode while
|
||||
enabling clamp control, but it's what Windows does */
|
||||
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
|
||||
|
||||
/* Enable clamping control */
|
||||
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
|
||||
|
||||
/* Disable automatic PGA (since the CVBS is coming from the tuner) */
|
||||
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
|
||||
|
||||
/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
|
||||
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
|
||||
|
||||
setup_decoder_defaults(state, false);
|
||||
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
|
||||
}
|
||||
|
||||
static void au8522_setup_svideo_mode(struct au8522_state *state,
|
||||
u8 input_mode)
|
||||
{
|
||||
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
|
||||
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
|
||||
|
||||
/* Set input to Y on Channe1, C on Channel 3 */
|
||||
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
|
||||
|
||||
/* PGA in automatic mode */
|
||||
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
|
||||
|
||||
/* Enable clamping control */
|
||||
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
|
||||
|
||||
setup_decoder_defaults(state, true);
|
||||
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static void disable_audio_input(struct au8522_state *state)
|
||||
{
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
|
||||
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
|
||||
au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
|
||||
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
|
||||
}
|
||||
|
||||
/* 0=disable, 1=SIF */
|
||||
static void set_audio_input(struct au8522_state *state)
|
||||
{
|
||||
int aud_input = state->aud_input;
|
||||
int i;
|
||||
|
||||
/* Note that this function needs to be used in conjunction with setting
|
||||
the input routing via register 0x81 */
|
||||
|
||||
if (aud_input == AU8522_AUDIO_NONE) {
|
||||
disable_audio_input(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aud_input != AU8522_AUDIO_SIF) {
|
||||
/* The caller asked for a mode we don't currently support */
|
||||
printk(KERN_ERR "Unsupported audio mode requested! mode=%d\n",
|
||||
aud_input);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load the Audio Decoder Filter Coefficients */
|
||||
for (i = 0; i < NUM_LPFILTER_COEF; i++) {
|
||||
au8522_writereg(state, lpfilter_coef[i].reg_name,
|
||||
lpfilter_coef[i].reg_val[0]);
|
||||
}
|
||||
|
||||
/* Setup audio */
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
|
||||
au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
|
||||
au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
|
||||
msleep(150);
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
|
||||
msleep(10);
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
|
||||
msleep(50);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0xff);
|
||||
msleep(80);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
|
||||
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
|
||||
au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
|
||||
au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x82);
|
||||
msleep(70);
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x09);
|
||||
au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
|
||||
au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0xc2);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int au8522_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct au8522_state *state =
|
||||
container_of(ctrl->handler, struct au8522_state, hdl);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
|
||||
ctrl->val - 128);
|
||||
break;
|
||||
case V4L2_CID_CONTRAST:
|
||||
au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
|
||||
ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_SATURATION:
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
|
||||
ctrl->val);
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
|
||||
ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_HUE:
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
|
||||
ctrl->val >> 8);
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
|
||||
ctrl->val & 0xFF);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
static int au8522_g_register(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_register *reg)
|
||||
{
|
||||
struct au8522_state *state = to_state(sd);
|
||||
|
||||
reg->val = au8522_readreg(state, reg->reg & 0xffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_s_register(struct v4l2_subdev *sd,
|
||||
const struct v4l2_dbg_register *reg)
|
||||
{
|
||||
struct au8522_state *state = to_state(sd);
|
||||
|
||||
au8522_writereg(state, reg->reg, reg->val & 0xff);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void au8522_video_set(struct au8522_state *state)
|
||||
{
|
||||
u8 input_mode;
|
||||
|
||||
au8522_writereg(state, 0xa4, 1 << 5);
|
||||
|
||||
switch (state->vid_input) {
|
||||
case AU8522_COMPOSITE_CH1:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH1;
|
||||
au8522_setup_cvbs_mode(state, input_mode);
|
||||
break;
|
||||
case AU8522_COMPOSITE_CH2:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH2;
|
||||
au8522_setup_cvbs_mode(state, input_mode);
|
||||
break;
|
||||
case AU8522_COMPOSITE_CH3:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH3;
|
||||
au8522_setup_cvbs_mode(state, input_mode);
|
||||
break;
|
||||
case AU8522_COMPOSITE_CH4:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4;
|
||||
au8522_setup_cvbs_mode(state, input_mode);
|
||||
break;
|
||||
case AU8522_SVIDEO_CH13:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13;
|
||||
au8522_setup_svideo_mode(state, input_mode);
|
||||
break;
|
||||
case AU8522_SVIDEO_CH24:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24;
|
||||
au8522_setup_svideo_mode(state, input_mode);
|
||||
break;
|
||||
default:
|
||||
case AU8522_COMPOSITE_CH4_SIF:
|
||||
input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF;
|
||||
au8522_setup_cvbs_tuner_mode(state, input_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct au8522_state *state = to_state(sd);
|
||||
|
||||
if (enable) {
|
||||
/*
|
||||
* Clear out any state associated with the digital side of the
|
||||
* chip, so that when it gets powered back up it won't think
|
||||
* that it is already tuned
|
||||
*/
|
||||
state->current_frequency = 0;
|
||||
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
0x01);
|
||||
msleep(10);
|
||||
|
||||
au8522_video_set(state);
|
||||
set_audio_input(state);
|
||||
|
||||
state->operational_mode = AU8522_ANALOG_MODE;
|
||||
} else {
|
||||
/* This does not completely power down the device
|
||||
(it only reduces it from around 140ma to 80ma) */
|
||||
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
|
||||
1 << 5);
|
||||
state->operational_mode = AU8522_SUSPEND_MODE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_s_video_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct au8522_state *state = to_state(sd);
|
||||
|
||||
switch(input) {
|
||||
case AU8522_COMPOSITE_CH1:
|
||||
case AU8522_SVIDEO_CH13:
|
||||
case AU8522_COMPOSITE_CH4_SIF:
|
||||
state->vid_input = input;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "au8522 mode not currently supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (state->operational_mode == AU8522_ANALOG_MODE)
|
||||
au8522_video_set(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct au8522_state *state = to_state(sd);
|
||||
|
||||
if ((std & (V4L2_STD_PAL_M | V4L2_STD_NTSC_M)) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
state->std = std;
|
||||
|
||||
if (state->operational_mode == AU8522_ANALOG_MODE)
|
||||
au8522_video_set(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_s_audio_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct au8522_state *state = to_state(sd);
|
||||
|
||||
state->aud_input = input;
|
||||
|
||||
if (state->operational_mode == AU8522_ANALOG_MODE)
|
||||
set_audio_input(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
|
||||
{
|
||||
int val = 0;
|
||||
struct au8522_state *state = to_state(sd);
|
||||
u8 lock_status;
|
||||
|
||||
/* Interrogate the decoder to see if we are getting a real signal */
|
||||
lock_status = au8522_readreg(state, 0x00);
|
||||
if (lock_status == 0xa2)
|
||||
vt->signal = 0xffff;
|
||||
else
|
||||
vt->signal = 0x00;
|
||||
|
||||
vt->capability |=
|
||||
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
|
||||
V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
||||
|
||||
val = V4L2_TUNER_SUB_MONO;
|
||||
vt->rxsubchans = val;
|
||||
vt->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops au8522_core_ops = {
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = au8522_g_register,
|
||||
.s_register = au8522_s_register,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_tuner_ops au8522_tuner_ops = {
|
||||
.g_tuner = au8522_g_tuner,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
|
||||
.s_routing = au8522_s_audio_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops au8522_video_ops = {
|
||||
.s_routing = au8522_s_video_routing,
|
||||
.s_stream = au8522_s_stream,
|
||||
.s_std = au8522_s_std,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops au8522_ops = {
|
||||
.core = &au8522_core_ops,
|
||||
.tuner = &au8522_tuner_ops,
|
||||
.audio = &au8522_audio_ops,
|
||||
.video = &au8522_video_ops,
|
||||
};
|
||||
|
||||
static const struct v4l2_ctrl_ops au8522_ctrl_ops = {
|
||||
.s_ctrl = au8522_s_ctrl,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int au8522_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *did)
|
||||
{
|
||||
struct au8522_state *state;
|
||||
struct v4l2_ctrl_handler *hdl;
|
||||
struct v4l2_subdev *sd;
|
||||
int instance;
|
||||
struct au8522_config *demod_config;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
instance = au8522_get_state(&state, client->adapter, client->addr);
|
||||
switch (instance) {
|
||||
case 0:
|
||||
printk(KERN_ERR "au8522_decoder allocation failed\n");
|
||||
return -EIO;
|
||||
case 1:
|
||||
/* new demod instance */
|
||||
printk(KERN_INFO "au8522_decoder creating new instance...\n");
|
||||
break;
|
||||
default:
|
||||
/* existing demod instance */
|
||||
printk(KERN_INFO "au8522_decoder attach existing instance.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
|
||||
if (demod_config == NULL) {
|
||||
if (instance == 1)
|
||||
kfree(state);
|
||||
return -ENOMEM;
|
||||
}
|
||||
demod_config->demod_address = 0x8e >> 1;
|
||||
|
||||
state->config = demod_config;
|
||||
state->i2c = client->adapter;
|
||||
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &au8522_ops);
|
||||
|
||||
hdl = &state->hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 4);
|
||||
v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, 0, 255, 1, 109);
|
||||
v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
|
||||
V4L2_CID_CONTRAST, 0, 255, 1,
|
||||
AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
|
||||
v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
|
||||
V4L2_CID_SATURATION, 0, 255, 1, 128);
|
||||
v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
|
||||
V4L2_CID_HUE, -32768, 32767, 1, 0);
|
||||
sd->ctrl_handler = hdl;
|
||||
if (hdl->error) {
|
||||
int err = hdl->error;
|
||||
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
kfree(demod_config);
|
||||
kfree(state);
|
||||
return err;
|
||||
}
|
||||
|
||||
state->c = client;
|
||||
state->std = V4L2_STD_NTSC_M;
|
||||
state->vid_input = AU8522_COMPOSITE_CH1;
|
||||
state->aud_input = AU8522_AUDIO_NONE;
|
||||
state->id = 8522;
|
||||
state->rev = 0;
|
||||
|
||||
/* Jam open the i2c gate to the tuner */
|
||||
au8522_writereg(state, 0x106, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(sd->ctrl_handler);
|
||||
au8522_release_state(to_state(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id au8522_id[] = {
|
||||
{"au8522", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, au8522_id);
|
||||
|
||||
static struct i2c_driver au8522_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "au8522",
|
||||
},
|
||||
.probe = au8522_probe,
|
||||
.remove = au8522_remove,
|
||||
.id_table = au8522_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(au8522_driver);
|
||||
828
drivers/media/dvb-frontends/au8522_dig.c
Normal file
828
drivers/media/dvb-frontends/au8522_dig.c
Normal file
|
|
@ -0,0 +1,828 @@
|
|||
/*
|
||||
Auvitek AU8522 QAM/8VSB demodulator driver
|
||||
|
||||
Copyright (C) 2008 Steven Toth <stoth@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; 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "au8522.h"
|
||||
#include "au8522_priv.h"
|
||||
|
||||
static int debug;
|
||||
|
||||
#define dprintk(arg...)\
|
||||
do { if (debug)\
|
||||
printk(arg);\
|
||||
} while (0)
|
||||
|
||||
struct mse2snr_tab {
|
||||
u16 val;
|
||||
u16 data;
|
||||
};
|
||||
|
||||
/* VSB SNR lookup table */
|
||||
static struct mse2snr_tab vsb_mse2snr_tab[] = {
|
||||
{ 0, 270 },
|
||||
{ 2, 250 },
|
||||
{ 3, 240 },
|
||||
{ 5, 230 },
|
||||
{ 7, 220 },
|
||||
{ 9, 210 },
|
||||
{ 12, 200 },
|
||||
{ 13, 195 },
|
||||
{ 15, 190 },
|
||||
{ 17, 185 },
|
||||
{ 19, 180 },
|
||||
{ 21, 175 },
|
||||
{ 24, 170 },
|
||||
{ 27, 165 },
|
||||
{ 31, 160 },
|
||||
{ 32, 158 },
|
||||
{ 33, 156 },
|
||||
{ 36, 152 },
|
||||
{ 37, 150 },
|
||||
{ 39, 148 },
|
||||
{ 40, 146 },
|
||||
{ 41, 144 },
|
||||
{ 43, 142 },
|
||||
{ 44, 140 },
|
||||
{ 48, 135 },
|
||||
{ 50, 130 },
|
||||
{ 43, 142 },
|
||||
{ 53, 125 },
|
||||
{ 56, 120 },
|
||||
{ 256, 115 },
|
||||
};
|
||||
|
||||
/* QAM64 SNR lookup table */
|
||||
static struct mse2snr_tab qam64_mse2snr_tab[] = {
|
||||
{ 15, 0 },
|
||||
{ 16, 290 },
|
||||
{ 17, 288 },
|
||||
{ 18, 286 },
|
||||
{ 19, 284 },
|
||||
{ 20, 282 },
|
||||
{ 21, 281 },
|
||||
{ 22, 279 },
|
||||
{ 23, 277 },
|
||||
{ 24, 275 },
|
||||
{ 25, 273 },
|
||||
{ 26, 271 },
|
||||
{ 27, 269 },
|
||||
{ 28, 268 },
|
||||
{ 29, 266 },
|
||||
{ 30, 264 },
|
||||
{ 31, 262 },
|
||||
{ 32, 260 },
|
||||
{ 33, 259 },
|
||||
{ 34, 258 },
|
||||
{ 35, 256 },
|
||||
{ 36, 255 },
|
||||
{ 37, 254 },
|
||||
{ 38, 252 },
|
||||
{ 39, 251 },
|
||||
{ 40, 250 },
|
||||
{ 41, 249 },
|
||||
{ 42, 248 },
|
||||
{ 43, 246 },
|
||||
{ 44, 245 },
|
||||
{ 45, 244 },
|
||||
{ 46, 242 },
|
||||
{ 47, 241 },
|
||||
{ 48, 240 },
|
||||
{ 50, 239 },
|
||||
{ 51, 238 },
|
||||
{ 53, 237 },
|
||||
{ 54, 236 },
|
||||
{ 56, 235 },
|
||||
{ 57, 234 },
|
||||
{ 59, 233 },
|
||||
{ 60, 232 },
|
||||
{ 62, 231 },
|
||||
{ 63, 230 },
|
||||
{ 65, 229 },
|
||||
{ 67, 228 },
|
||||
{ 68, 227 },
|
||||
{ 70, 226 },
|
||||
{ 71, 225 },
|
||||
{ 73, 224 },
|
||||
{ 74, 223 },
|
||||
{ 76, 222 },
|
||||
{ 78, 221 },
|
||||
{ 80, 220 },
|
||||
{ 82, 219 },
|
||||
{ 85, 218 },
|
||||
{ 88, 217 },
|
||||
{ 90, 216 },
|
||||
{ 92, 215 },
|
||||
{ 93, 214 },
|
||||
{ 94, 212 },
|
||||
{ 95, 211 },
|
||||
{ 97, 210 },
|
||||
{ 99, 209 },
|
||||
{ 101, 208 },
|
||||
{ 102, 207 },
|
||||
{ 104, 206 },
|
||||
{ 107, 205 },
|
||||
{ 111, 204 },
|
||||
{ 114, 203 },
|
||||
{ 118, 202 },
|
||||
{ 122, 201 },
|
||||
{ 125, 200 },
|
||||
{ 128, 199 },
|
||||
{ 130, 198 },
|
||||
{ 132, 197 },
|
||||
{ 256, 190 },
|
||||
};
|
||||
|
||||
/* QAM256 SNR lookup table */
|
||||
static struct mse2snr_tab qam256_mse2snr_tab[] = {
|
||||
{ 15, 0 },
|
||||
{ 16, 400 },
|
||||
{ 17, 398 },
|
||||
{ 18, 396 },
|
||||
{ 19, 394 },
|
||||
{ 20, 392 },
|
||||
{ 21, 390 },
|
||||
{ 22, 388 },
|
||||
{ 23, 386 },
|
||||
{ 24, 384 },
|
||||
{ 25, 382 },
|
||||
{ 26, 380 },
|
||||
{ 27, 379 },
|
||||
{ 28, 378 },
|
||||
{ 29, 377 },
|
||||
{ 30, 376 },
|
||||
{ 31, 375 },
|
||||
{ 32, 374 },
|
||||
{ 33, 373 },
|
||||
{ 34, 372 },
|
||||
{ 35, 371 },
|
||||
{ 36, 370 },
|
||||
{ 37, 362 },
|
||||
{ 38, 354 },
|
||||
{ 39, 346 },
|
||||
{ 40, 338 },
|
||||
{ 41, 330 },
|
||||
{ 42, 328 },
|
||||
{ 43, 326 },
|
||||
{ 44, 324 },
|
||||
{ 45, 322 },
|
||||
{ 46, 320 },
|
||||
{ 47, 319 },
|
||||
{ 48, 318 },
|
||||
{ 49, 317 },
|
||||
{ 50, 316 },
|
||||
{ 51, 315 },
|
||||
{ 52, 314 },
|
||||
{ 53, 313 },
|
||||
{ 54, 312 },
|
||||
{ 55, 311 },
|
||||
{ 56, 310 },
|
||||
{ 57, 308 },
|
||||
{ 58, 306 },
|
||||
{ 59, 304 },
|
||||
{ 60, 302 },
|
||||
{ 61, 300 },
|
||||
{ 62, 298 },
|
||||
{ 65, 295 },
|
||||
{ 68, 294 },
|
||||
{ 70, 293 },
|
||||
{ 73, 292 },
|
||||
{ 76, 291 },
|
||||
{ 78, 290 },
|
||||
{ 79, 289 },
|
||||
{ 81, 288 },
|
||||
{ 82, 287 },
|
||||
{ 83, 286 },
|
||||
{ 84, 285 },
|
||||
{ 85, 284 },
|
||||
{ 86, 283 },
|
||||
{ 88, 282 },
|
||||
{ 89, 281 },
|
||||
{ 256, 280 },
|
||||
};
|
||||
|
||||
static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
|
||||
u16 *snr)
|
||||
{
|
||||
int i, ret = -EINVAL;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
if (mse < tab[i].val) {
|
||||
*snr = tab[i].data;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dprintk("%s() snr=%d\n", __func__, *snr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
u8 r0b5, r0b6, r0b7;
|
||||
char *ifmhz;
|
||||
|
||||
switch (if_freq) {
|
||||
case AU8522_IF_3_25MHZ:
|
||||
ifmhz = "3.25";
|
||||
r0b5 = 0x00;
|
||||
r0b6 = 0x3d;
|
||||
r0b7 = 0xa0;
|
||||
break;
|
||||
case AU8522_IF_4MHZ:
|
||||
ifmhz = "4.00";
|
||||
r0b5 = 0x00;
|
||||
r0b6 = 0x4b;
|
||||
r0b7 = 0xd9;
|
||||
break;
|
||||
case AU8522_IF_6MHZ:
|
||||
ifmhz = "6.00";
|
||||
r0b5 = 0xfb;
|
||||
r0b6 = 0x8e;
|
||||
r0b7 = 0x39;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s() IF Frequency not supported\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
dprintk("%s() %s MHz\n", __func__, ifmhz);
|
||||
au8522_writereg(state, 0x80b5, r0b5);
|
||||
au8522_writereg(state, 0x80b6, r0b6);
|
||||
au8522_writereg(state, 0x80b7, r0b7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VSB Modulation table */
|
||||
static struct {
|
||||
u16 reg;
|
||||
u16 data;
|
||||
} VSB_mod_tab[] = {
|
||||
{ 0x8090, 0x84 },
|
||||
{ 0x4092, 0x11 },
|
||||
{ 0x2005, 0x00 },
|
||||
{ 0x8091, 0x80 },
|
||||
{ 0x80a3, 0x0c },
|
||||
{ 0x80a4, 0xe8 },
|
||||
{ 0x8081, 0xc4 },
|
||||
{ 0x80a5, 0x40 },
|
||||
{ 0x80a7, 0x40 },
|
||||
{ 0x80a6, 0x67 },
|
||||
{ 0x8262, 0x20 },
|
||||
{ 0x821c, 0x30 },
|
||||
{ 0x80d8, 0x1a },
|
||||
{ 0x8227, 0xa0 },
|
||||
{ 0x8121, 0xff },
|
||||
{ 0x80a8, 0xf0 },
|
||||
{ 0x80a9, 0x05 },
|
||||
{ 0x80aa, 0x77 },
|
||||
{ 0x80ab, 0xf0 },
|
||||
{ 0x80ac, 0x05 },
|
||||
{ 0x80ad, 0x77 },
|
||||
{ 0x80ae, 0x41 },
|
||||
{ 0x80af, 0x66 },
|
||||
{ 0x821b, 0xcc },
|
||||
{ 0x821d, 0x80 },
|
||||
{ 0x80a4, 0xe8 },
|
||||
{ 0x8231, 0x13 },
|
||||
};
|
||||
|
||||
/* QAM64 Modulation table */
|
||||
static struct {
|
||||
u16 reg;
|
||||
u16 data;
|
||||
} QAM64_mod_tab[] = {
|
||||
{ 0x00a3, 0x09 },
|
||||
{ 0x00a4, 0x00 },
|
||||
{ 0x0081, 0xc4 },
|
||||
{ 0x00a5, 0x40 },
|
||||
{ 0x00aa, 0x77 },
|
||||
{ 0x00ad, 0x77 },
|
||||
{ 0x00a6, 0x67 },
|
||||
{ 0x0262, 0x20 },
|
||||
{ 0x021c, 0x30 },
|
||||
{ 0x00b8, 0x3e },
|
||||
{ 0x00b9, 0xf0 },
|
||||
{ 0x00ba, 0x01 },
|
||||
{ 0x00bb, 0x18 },
|
||||
{ 0x00bc, 0x50 },
|
||||
{ 0x00bd, 0x00 },
|
||||
{ 0x00be, 0xea },
|
||||
{ 0x00bf, 0xef },
|
||||
{ 0x00c0, 0xfc },
|
||||
{ 0x00c1, 0xbd },
|
||||
{ 0x00c2, 0x1f },
|
||||
{ 0x00c3, 0xfc },
|
||||
{ 0x00c4, 0xdd },
|
||||
{ 0x00c5, 0xaf },
|
||||
{ 0x00c6, 0x00 },
|
||||
{ 0x00c7, 0x38 },
|
||||
{ 0x00c8, 0x30 },
|
||||
{ 0x00c9, 0x05 },
|
||||
{ 0x00ca, 0x4a },
|
||||
{ 0x00cb, 0xd0 },
|
||||
{ 0x00cc, 0x01 },
|
||||
{ 0x00cd, 0xd9 },
|
||||
{ 0x00ce, 0x6f },
|
||||
{ 0x00cf, 0xf9 },
|
||||
{ 0x00d0, 0x70 },
|
||||
{ 0x00d1, 0xdf },
|
||||
{ 0x00d2, 0xf7 },
|
||||
{ 0x00d3, 0xc2 },
|
||||
{ 0x00d4, 0xdf },
|
||||
{ 0x00d5, 0x02 },
|
||||
{ 0x00d6, 0x9a },
|
||||
{ 0x00d7, 0xd0 },
|
||||
{ 0x0250, 0x0d },
|
||||
{ 0x0251, 0xcd },
|
||||
{ 0x0252, 0xe0 },
|
||||
{ 0x0253, 0x05 },
|
||||
{ 0x0254, 0xa7 },
|
||||
{ 0x0255, 0xff },
|
||||
{ 0x0256, 0xed },
|
||||
{ 0x0257, 0x5b },
|
||||
{ 0x0258, 0xae },
|
||||
{ 0x0259, 0xe6 },
|
||||
{ 0x025a, 0x3d },
|
||||
{ 0x025b, 0x0f },
|
||||
{ 0x025c, 0x0d },
|
||||
{ 0x025d, 0xea },
|
||||
{ 0x025e, 0xf2 },
|
||||
{ 0x025f, 0x51 },
|
||||
{ 0x0260, 0xf5 },
|
||||
{ 0x0261, 0x06 },
|
||||
{ 0x021a, 0x00 },
|
||||
{ 0x0546, 0x40 },
|
||||
{ 0x0210, 0xc7 },
|
||||
{ 0x0211, 0xaa },
|
||||
{ 0x0212, 0xab },
|
||||
{ 0x0213, 0x02 },
|
||||
{ 0x0502, 0x00 },
|
||||
{ 0x0121, 0x04 },
|
||||
{ 0x0122, 0x04 },
|
||||
{ 0x052e, 0x10 },
|
||||
{ 0x00a4, 0xca },
|
||||
{ 0x00a7, 0x40 },
|
||||
{ 0x0526, 0x01 },
|
||||
};
|
||||
|
||||
/* QAM256 Modulation table */
|
||||
static struct {
|
||||
u16 reg;
|
||||
u16 data;
|
||||
} QAM256_mod_tab[] = {
|
||||
{ 0x80a3, 0x09 },
|
||||
{ 0x80a4, 0x00 },
|
||||
{ 0x8081, 0xc4 },
|
||||
{ 0x80a5, 0x40 },
|
||||
{ 0x80aa, 0x77 },
|
||||
{ 0x80ad, 0x77 },
|
||||
{ 0x80a6, 0x67 },
|
||||
{ 0x8262, 0x20 },
|
||||
{ 0x821c, 0x30 },
|
||||
{ 0x80b8, 0x3e },
|
||||
{ 0x80b9, 0xf0 },
|
||||
{ 0x80ba, 0x01 },
|
||||
{ 0x80bb, 0x18 },
|
||||
{ 0x80bc, 0x50 },
|
||||
{ 0x80bd, 0x00 },
|
||||
{ 0x80be, 0xea },
|
||||
{ 0x80bf, 0xef },
|
||||
{ 0x80c0, 0xfc },
|
||||
{ 0x80c1, 0xbd },
|
||||
{ 0x80c2, 0x1f },
|
||||
{ 0x80c3, 0xfc },
|
||||
{ 0x80c4, 0xdd },
|
||||
{ 0x80c5, 0xaf },
|
||||
{ 0x80c6, 0x00 },
|
||||
{ 0x80c7, 0x38 },
|
||||
{ 0x80c8, 0x30 },
|
||||
{ 0x80c9, 0x05 },
|
||||
{ 0x80ca, 0x4a },
|
||||
{ 0x80cb, 0xd0 },
|
||||
{ 0x80cc, 0x01 },
|
||||
{ 0x80cd, 0xd9 },
|
||||
{ 0x80ce, 0x6f },
|
||||
{ 0x80cf, 0xf9 },
|
||||
{ 0x80d0, 0x70 },
|
||||
{ 0x80d1, 0xdf },
|
||||
{ 0x80d2, 0xf7 },
|
||||
{ 0x80d3, 0xc2 },
|
||||
{ 0x80d4, 0xdf },
|
||||
{ 0x80d5, 0x02 },
|
||||
{ 0x80d6, 0x9a },
|
||||
{ 0x80d7, 0xd0 },
|
||||
{ 0x8250, 0x0d },
|
||||
{ 0x8251, 0xcd },
|
||||
{ 0x8252, 0xe0 },
|
||||
{ 0x8253, 0x05 },
|
||||
{ 0x8254, 0xa7 },
|
||||
{ 0x8255, 0xff },
|
||||
{ 0x8256, 0xed },
|
||||
{ 0x8257, 0x5b },
|
||||
{ 0x8258, 0xae },
|
||||
{ 0x8259, 0xe6 },
|
||||
{ 0x825a, 0x3d },
|
||||
{ 0x825b, 0x0f },
|
||||
{ 0x825c, 0x0d },
|
||||
{ 0x825d, 0xea },
|
||||
{ 0x825e, 0xf2 },
|
||||
{ 0x825f, 0x51 },
|
||||
{ 0x8260, 0xf5 },
|
||||
{ 0x8261, 0x06 },
|
||||
{ 0x821a, 0x00 },
|
||||
{ 0x8546, 0x40 },
|
||||
{ 0x8210, 0x26 },
|
||||
{ 0x8211, 0xf6 },
|
||||
{ 0x8212, 0x84 },
|
||||
{ 0x8213, 0x02 },
|
||||
{ 0x8502, 0x01 },
|
||||
{ 0x8121, 0x04 },
|
||||
{ 0x8122, 0x04 },
|
||||
{ 0x852e, 0x10 },
|
||||
{ 0x80a4, 0xca },
|
||||
{ 0x80a7, 0x40 },
|
||||
{ 0x8526, 0x01 },
|
||||
};
|
||||
|
||||
static int au8522_enable_modulation(struct dvb_frontend *fe,
|
||||
fe_modulation_t m)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
int i;
|
||||
|
||||
dprintk("%s(0x%08x)\n", __func__, m);
|
||||
|
||||
switch (m) {
|
||||
case VSB_8:
|
||||
dprintk("%s() VSB_8\n", __func__);
|
||||
for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
|
||||
au8522_writereg(state,
|
||||
VSB_mod_tab[i].reg,
|
||||
VSB_mod_tab[i].data);
|
||||
au8522_set_if(fe, state->config->vsb_if);
|
||||
break;
|
||||
case QAM_64:
|
||||
dprintk("%s() QAM 64\n", __func__);
|
||||
for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
|
||||
au8522_writereg(state,
|
||||
QAM64_mod_tab[i].reg,
|
||||
QAM64_mod_tab[i].data);
|
||||
au8522_set_if(fe, state->config->qam_if);
|
||||
break;
|
||||
case QAM_256:
|
||||
dprintk("%s() QAM 256\n", __func__);
|
||||
for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
|
||||
au8522_writereg(state,
|
||||
QAM256_mod_tab[i].reg,
|
||||
QAM256_mod_tab[i].data);
|
||||
au8522_set_if(fe, state->config->qam_if);
|
||||
break;
|
||||
default:
|
||||
dprintk("%s() Invalid modulation\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
state->current_modulation = m;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
|
||||
static int au8522_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
int ret = -EINVAL;
|
||||
|
||||
dprintk("%s(frequency=%d)\n", __func__, c->frequency);
|
||||
|
||||
if ((state->current_frequency == c->frequency) &&
|
||||
(state->current_modulation == c->modulation))
|
||||
return 0;
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
ret = fe->ops.tuner_ops.set_params(fe);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Allow the tuner to settle */
|
||||
msleep(100);
|
||||
|
||||
au8522_enable_modulation(fe, c->modulation);
|
||||
|
||||
state->current_frequency = c->frequency;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
u8 reg;
|
||||
u32 tuner_status = 0;
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (state->current_modulation == VSB_8) {
|
||||
dprintk("%s() Checking VSB_8\n", __func__);
|
||||
reg = au8522_readreg(state, 0x4088);
|
||||
if ((reg & 0x03) == 0x03)
|
||||
*status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
|
||||
} else {
|
||||
dprintk("%s() Checking QAM\n", __func__);
|
||||
reg = au8522_readreg(state, 0x4541);
|
||||
if (reg & 0x80)
|
||||
*status |= FE_HAS_VITERBI;
|
||||
if (reg & 0x20)
|
||||
*status |= FE_HAS_LOCK | FE_HAS_SYNC;
|
||||
}
|
||||
|
||||
switch (state->config->status_mode) {
|
||||
case AU8522_DEMODLOCKING:
|
||||
dprintk("%s() DEMODLOCKING\n", __func__);
|
||||
if (*status & FE_HAS_VITERBI)
|
||||
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
|
||||
break;
|
||||
case AU8522_TUNERLOCKING:
|
||||
/* Get the tuner status */
|
||||
dprintk("%s() TUNERLOCKING\n", __func__);
|
||||
if (fe->ops.tuner_ops.get_status) {
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
fe->ops.tuner_ops.get_status(fe, &tuner_status);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
if (tuner_status)
|
||||
*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
|
||||
break;
|
||||
}
|
||||
state->fe_status = *status;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
/* turn on LED, if it isn't on already */
|
||||
au8522_led_ctrl(state, -1);
|
||||
else
|
||||
/* turn off LED */
|
||||
au8522_led_ctrl(state, 0);
|
||||
|
||||
dprintk("%s() status 0x%08x\n", __func__, *status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_led_status(struct au8522_state *state, const u16 *snr)
|
||||
{
|
||||
struct au8522_led_config *led_config = state->config->led_cfg;
|
||||
int led;
|
||||
u16 strong;
|
||||
|
||||
/* bail out if we can't control an LED */
|
||||
if (!led_config)
|
||||
return 0;
|
||||
|
||||
if (0 == (state->fe_status & FE_HAS_LOCK))
|
||||
return au8522_led_ctrl(state, 0);
|
||||
else if (state->current_modulation == QAM_256)
|
||||
strong = led_config->qam256_strong;
|
||||
else if (state->current_modulation == QAM_64)
|
||||
strong = led_config->qam64_strong;
|
||||
else /* (state->current_modulation == VSB_8) */
|
||||
strong = led_config->vsb8_strong;
|
||||
|
||||
if (*snr >= strong)
|
||||
led = 2;
|
||||
else
|
||||
led = 1;
|
||||
|
||||
if ((state->led_state) &&
|
||||
(((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10))
|
||||
/* snr didn't change enough to bother
|
||||
* changing the color of the led */
|
||||
return 0;
|
||||
|
||||
return au8522_led_ctrl(state, led);
|
||||
}
|
||||
|
||||
static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
int ret = -EINVAL;
|
||||
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
if (state->current_modulation == QAM_256)
|
||||
ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
|
||||
ARRAY_SIZE(qam256_mse2snr_tab),
|
||||
au8522_readreg(state, 0x4522),
|
||||
snr);
|
||||
else if (state->current_modulation == QAM_64)
|
||||
ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
|
||||
ARRAY_SIZE(qam64_mse2snr_tab),
|
||||
au8522_readreg(state, 0x4522),
|
||||
snr);
|
||||
else /* VSB_8 */
|
||||
ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
|
||||
ARRAY_SIZE(vsb_mse2snr_tab),
|
||||
au8522_readreg(state, 0x4311),
|
||||
snr);
|
||||
|
||||
if (state->config->led_cfg)
|
||||
au8522_led_status(state, snr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au8522_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *signal_strength)
|
||||
{
|
||||
/* borrowed from lgdt330x.c
|
||||
*
|
||||
* Calculate strength from SNR up to 35dB
|
||||
* Even though the SNR can go higher than 35dB,
|
||||
* there is some comfort factor in having a range of
|
||||
* strong signals that can show at 100%
|
||||
*/
|
||||
u16 snr;
|
||||
u32 tmp;
|
||||
int ret = au8522_read_snr(fe, &snr);
|
||||
|
||||
*signal_strength = 0;
|
||||
|
||||
if (0 == ret) {
|
||||
/* The following calculation method was chosen
|
||||
* purely for the sake of code re-use from the
|
||||
* other demod drivers that use this method */
|
||||
|
||||
/* Convert from SNR in dB * 10 to 8.24 fixed-point */
|
||||
tmp = (snr * ((1 << 24) / 10));
|
||||
|
||||
/* Convert from 8.24 fixed-point to
|
||||
* scale the range 0 - 35*2^24 into 0 - 65535*/
|
||||
if (tmp >= 8960 * 0x10000)
|
||||
*signal_strength = 0xffff;
|
||||
else
|
||||
*signal_strength = tmp / 8960;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
|
||||
if (state->current_modulation == VSB_8)
|
||||
*ucblocks = au8522_readreg(state, 0x4087);
|
||||
else
|
||||
*ucblocks = au8522_readreg(state, 0x4543);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
return au8522_read_ucblocks(fe, ber);
|
||||
}
|
||||
|
||||
static int au8522_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
|
||||
c->frequency = state->current_frequency;
|
||||
c->modulation = state->current_modulation;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au8522_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops au8522_ops;
|
||||
|
||||
|
||||
static void au8522_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct au8522_state *state = fe->demodulator_priv;
|
||||
au8522_release_state(state);
|
||||
}
|
||||
|
||||
struct dvb_frontend *au8522_attach(const struct au8522_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct au8522_state *state = NULL;
|
||||
int instance;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
instance = au8522_get_state(&state, i2c, config->demod_address);
|
||||
switch (instance) {
|
||||
case 0:
|
||||
dprintk("%s state allocation failed\n", __func__);
|
||||
break;
|
||||
case 1:
|
||||
/* new demod instance */
|
||||
dprintk("%s using new instance\n", __func__);
|
||||
break;
|
||||
default:
|
||||
/* existing demod instance */
|
||||
dprintk("%s using existing instance\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->operational_mode = AU8522_DIGITAL_MODE;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &au8522_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
state->frontend.ops.analog_ops.i2c_gate_ctrl = au8522_analog_i2c_gate_ctrl;
|
||||
|
||||
if (au8522_init(&state->frontend) != 0) {
|
||||
printk(KERN_ERR "%s: Failed to initialize correctly\n",
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Note: Leaving the I2C gate open here. */
|
||||
au8522_i2c_gate_ctrl(&state->frontend, 1);
|
||||
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
au8522_release_state(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(au8522_attach);
|
||||
|
||||
static struct dvb_frontend_ops au8522_ops = {
|
||||
.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
|
||||
.info = {
|
||||
.name = "Auvitek AU8522 QAM/8VSB Frontend",
|
||||
.frequency_min = 54000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 62500,
|
||||
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
|
||||
},
|
||||
|
||||
.init = au8522_init,
|
||||
.sleep = au8522_sleep,
|
||||
.i2c_gate_ctrl = au8522_i2c_gate_ctrl,
|
||||
.set_frontend = au8522_set_frontend,
|
||||
.get_frontend = au8522_get_frontend,
|
||||
.get_tune_settings = au8522_get_tune_settings,
|
||||
.read_status = au8522_read_status,
|
||||
.read_ber = au8522_read_ber,
|
||||
.read_signal_strength = au8522_read_signal_strength,
|
||||
.read_snr = au8522_read_snr,
|
||||
.read_ucblocks = au8522_read_ucblocks,
|
||||
.release = au8522_release,
|
||||
};
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
|
||||
|
||||
MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
|
||||
MODULE_AUTHOR("Steven Toth");
|
||||
MODULE_LICENSE("GPL");
|
||||
446
drivers/media/dvb-frontends/au8522_priv.h
Normal file
446
drivers/media/dvb-frontends/au8522_priv.h
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
Auvitek AU8522 QAM/8VSB demodulator driver
|
||||
|
||||
Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
|
||||
Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
|
||||
Copyright (C) 2005-2008 Auvitek International, Ltd.
|
||||
|
||||
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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <linux/i2c.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "au8522.h"
|
||||
#include "tuner-i2c.h"
|
||||
|
||||
#define AU8522_ANALOG_MODE 0
|
||||
#define AU8522_DIGITAL_MODE 1
|
||||
#define AU8522_SUSPEND_MODE 2
|
||||
|
||||
struct au8522_state {
|
||||
struct i2c_client *c;
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
u8 operational_mode;
|
||||
|
||||
/* Used for sharing of the state between analog and digital mode */
|
||||
struct tuner_i2c_props i2c_props;
|
||||
struct list_head hybrid_tuner_instance_list;
|
||||
|
||||
/* configuration settings */
|
||||
const struct au8522_config *config;
|
||||
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u32 current_frequency;
|
||||
fe_modulation_t current_modulation;
|
||||
|
||||
u32 fe_status;
|
||||
unsigned int led_state;
|
||||
|
||||
/* Analog settings */
|
||||
struct v4l2_subdev sd;
|
||||
v4l2_std_id std;
|
||||
int vid_input;
|
||||
int aud_input;
|
||||
u32 id;
|
||||
u32 rev;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
};
|
||||
|
||||
/* These are routines shared by both the VSB/QAM demodulator and the analog
|
||||
decoder */
|
||||
int au8522_writereg(struct au8522_state *state, u16 reg, u8 data);
|
||||
u8 au8522_readreg(struct au8522_state *state, u16 reg);
|
||||
int au8522_init(struct dvb_frontend *fe);
|
||||
int au8522_sleep(struct dvb_frontend *fe);
|
||||
|
||||
int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
|
||||
u8 client_address);
|
||||
void au8522_release_state(struct au8522_state *state);
|
||||
int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
|
||||
int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
|
||||
int au8522_led_ctrl(struct au8522_state *state, int led);
|
||||
|
||||
/* REGISTERS */
|
||||
#define AU8522_INPUT_CONTROL_REG081H 0x081
|
||||
#define AU8522_PGA_CONTROL_REG082H 0x082
|
||||
#define AU8522_CLAMPING_CONTROL_REG083H 0x083
|
||||
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H 0x0A3
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H 0x0A4
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H 0x0A5
|
||||
#define AU8522_AGC_CONTROL_RANGE_REG0A6H 0x0A6
|
||||
#define AU8522_SYSTEM_GAIN_CONTROL_REG0A7H 0x0A7
|
||||
#define AU8522_TUNER_AGC_RF_STOP_REG0A8H 0x0A8
|
||||
#define AU8522_TUNER_AGC_RF_START_REG0A9H 0x0A9
|
||||
#define AU8522_TUNER_RF_AGC_DEFAULT_REG0AAH 0x0AA
|
||||
#define AU8522_TUNER_AGC_IF_STOP_REG0ABH 0x0AB
|
||||
#define AU8522_TUNER_AGC_IF_START_REG0ACH 0x0AC
|
||||
#define AU8522_TUNER_AGC_IF_DEFAULT_REG0ADH 0x0AD
|
||||
#define AU8522_TUNER_AGC_STEP_REG0AEH 0x0AE
|
||||
#define AU8522_TUNER_GAIN_STEP_REG0AFH 0x0AF
|
||||
|
||||
/* Receiver registers */
|
||||
#define AU8522_FRMREGTHRD1_REG0B0H 0x0B0
|
||||
#define AU8522_FRMREGAGC1H_REG0B1H 0x0B1
|
||||
#define AU8522_FRMREGSHIFT1_REG0B2H 0x0B2
|
||||
#define AU8522_TOREGAGC1_REG0B3H 0x0B3
|
||||
#define AU8522_TOREGASHIFT1_REG0B4H 0x0B4
|
||||
#define AU8522_FRMREGBBH_REG0B5H 0x0B5
|
||||
#define AU8522_FRMREGBBM_REG0B6H 0x0B6
|
||||
#define AU8522_FRMREGBBL_REG0B7H 0x0B7
|
||||
/* 0xB8 TO 0xD7 are the filter coefficients */
|
||||
#define AU8522_FRMREGTHRD2_REG0D8H 0x0D8
|
||||
#define AU8522_FRMREGAGC2H_REG0D9H 0x0D9
|
||||
#define AU8522_TOREGAGC2_REG0DAH 0x0DA
|
||||
#define AU8522_TOREGSHIFT2_REG0DBH 0x0DB
|
||||
#define AU8522_FRMREGPILOTH_REG0DCH 0x0DC
|
||||
#define AU8522_FRMREGPILOTM_REG0DDH 0x0DD
|
||||
#define AU8522_FRMREGPILOTL_REG0DEH 0x0DE
|
||||
#define AU8522_TOREGFREQ_REG0DFH 0x0DF
|
||||
|
||||
#define AU8522_RX_PGA_RFOUT_REG0EBH 0x0EB
|
||||
#define AU8522_RX_PGA_IFOUT_REG0ECH 0x0EC
|
||||
#define AU8522_RX_PGA_PGAOUT_REG0EDH 0x0ED
|
||||
|
||||
#define AU8522_CHIP_MODE_REG0FEH 0x0FE
|
||||
|
||||
/* I2C bus control registers */
|
||||
#define AU8522_I2C_CONTROL_REG0_REG090H 0x090
|
||||
#define AU8522_I2C_CONTROL_REG1_REG091H 0x091
|
||||
#define AU8522_I2C_STATUS_REG092H 0x092
|
||||
#define AU8522_I2C_WR_DATA0_REG093H 0x093
|
||||
#define AU8522_I2C_WR_DATA1_REG094H 0x094
|
||||
#define AU8522_I2C_WR_DATA2_REG095H 0x095
|
||||
#define AU8522_I2C_WR_DATA3_REG096H 0x096
|
||||
#define AU8522_I2C_WR_DATA4_REG097H 0x097
|
||||
#define AU8522_I2C_WR_DATA5_REG098H 0x098
|
||||
#define AU8522_I2C_WR_DATA6_REG099H 0x099
|
||||
#define AU8522_I2C_WR_DATA7_REG09AH 0x09A
|
||||
#define AU8522_I2C_RD_DATA0_REG09BH 0x09B
|
||||
#define AU8522_I2C_RD_DATA1_REG09CH 0x09C
|
||||
#define AU8522_I2C_RD_DATA2_REG09DH 0x09D
|
||||
#define AU8522_I2C_RD_DATA3_REG09EH 0x09E
|
||||
#define AU8522_I2C_RD_DATA4_REG09FH 0x09F
|
||||
#define AU8522_I2C_RD_DATA5_REG0A0H 0x0A0
|
||||
#define AU8522_I2C_RD_DATA6_REG0A1H 0x0A1
|
||||
#define AU8522_I2C_RD_DATA7_REG0A2H 0x0A2
|
||||
|
||||
#define AU8522_ENA_USB_REG101H 0x101
|
||||
|
||||
#define AU8522_I2S_CTRL_0_REG110H 0x110
|
||||
#define AU8522_I2S_CTRL_1_REG111H 0x111
|
||||
#define AU8522_I2S_CTRL_2_REG112H 0x112
|
||||
|
||||
#define AU8522_FRMREGFFECONTROL_REG121H 0x121
|
||||
#define AU8522_FRMREGDFECONTROL_REG122H 0x122
|
||||
|
||||
#define AU8522_CARRFREQOFFSET0_REG201H 0x201
|
||||
#define AU8522_CARRFREQOFFSET1_REG202H 0x202
|
||||
|
||||
#define AU8522_DECIMATION_GAIN_REG21AH 0x21A
|
||||
#define AU8522_FRMREGIFSLP_REG21BH 0x21B
|
||||
#define AU8522_FRMREGTHRDL2_REG21CH 0x21C
|
||||
#define AU8522_FRMREGSTEP3DB_REG21DH 0x21D
|
||||
#define AU8522_DAGC_GAIN_ADJUSTMENT_REG21EH 0x21E
|
||||
#define AU8522_FRMREGPLLMODE_REG21FH 0x21F
|
||||
#define AU8522_FRMREGCSTHRD_REG220H 0x220
|
||||
#define AU8522_FRMREGCRLOCKDMAX_REG221H 0x221
|
||||
#define AU8522_FRMREGCRPERIODMASK_REG222H 0x222
|
||||
#define AU8522_FRMREGCRLOCK0THH_REG223H 0x223
|
||||
#define AU8522_FRMREGCRLOCK1THH_REG224H 0x224
|
||||
#define AU8522_FRMREGCRLOCK0THL_REG225H 0x225
|
||||
#define AU8522_FRMREGCRLOCK1THL_REG226H 0x226
|
||||
#define AU_FRMREGPLLACQPHASESCL_REG227H 0x227
|
||||
#define AU8522_FRMREGFREQFBCTRL_REG228H 0x228
|
||||
|
||||
/* Analog TV Decoder */
|
||||
#define AU8522_TVDEC_STATUS_REG000H 0x000
|
||||
#define AU8522_TVDEC_INT_STATUS_REG001H 0x001
|
||||
#define AU8522_TVDEC_MACROVISION_STATUS_REG002H 0x002
|
||||
#define AU8522_TVDEC_SHARPNESSREG009H 0x009
|
||||
#define AU8522_TVDEC_BRIGHTNESS_REG00AH 0x00A
|
||||
#define AU8522_TVDEC_CONTRAST_REG00BH 0x00B
|
||||
#define AU8522_TVDEC_SATURATION_CB_REG00CH 0x00C
|
||||
#define AU8522_TVDEC_SATURATION_CR_REG00DH 0x00D
|
||||
#define AU8522_TVDEC_HUE_H_REG00EH 0x00E
|
||||
#define AU8522_TVDEC_HUE_L_REG00FH 0x00F
|
||||
#define AU8522_TVDEC_INT_MASK_REG010H 0x010
|
||||
#define AU8522_VIDEO_MODE_REG011H 0x011
|
||||
#define AU8522_TVDEC_PGA_REG012H 0x012
|
||||
#define AU8522_TVDEC_COMB_MODE_REG015H 0x015
|
||||
#define AU8522_REG016H 0x016
|
||||
#define AU8522_TVDED_DBG_MODE_REG060H 0x060
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H 0x061
|
||||
#define AU8522_TVDEC_FORMAT_CTRL2_REG062H 0x062
|
||||
#define AU8522_TVDEC_VCR_DET_LLIM_REG063H 0x063
|
||||
#define AU8522_TVDEC_VCR_DET_HLIM_REG064H 0x064
|
||||
#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H 0x065
|
||||
#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H 0x066
|
||||
#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H 0x067
|
||||
#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H 0x068
|
||||
#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H 0x069
|
||||
#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH 0x06A
|
||||
#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH 0x06B
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH 0x06C
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH 0x06D
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH 0x06E
|
||||
#define AU8522_TVDEC_UV_SEP_THR_REG06FH 0x06F
|
||||
#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H 0x070
|
||||
#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H 0x073
|
||||
#define AU8522_TVDEC_DCAGC_CTRL_REG077H 0x077
|
||||
#define AU8522_TVDEC_PIC_START_ADJ_REG078H 0x078
|
||||
#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H 0x079
|
||||
#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH 0x07A
|
||||
#define AU8522_TVDEC_INTRP_CTRL_REG07BH 0x07B
|
||||
#define AU8522_TVDEC_PLL_STATUS_REG07EH 0x07E
|
||||
#define AU8522_TVDEC_FSC_FREQ_REG07FH 0x07F
|
||||
|
||||
#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H 0x0E4
|
||||
#define AU8522_TOREGAAGC_REG0E5H 0x0E5
|
||||
|
||||
#define AU8522_TVDEC_CHROMA_AGC_REG401H 0x401
|
||||
#define AU8522_TVDEC_CHROMA_SFT_REG402H 0x402
|
||||
#define AU8522_FILTER_COEF_R410 0x410
|
||||
#define AU8522_FILTER_COEF_R411 0x411
|
||||
#define AU8522_FILTER_COEF_R412 0x412
|
||||
#define AU8522_FILTER_COEF_R413 0x413
|
||||
#define AU8522_FILTER_COEF_R414 0x414
|
||||
#define AU8522_FILTER_COEF_R415 0x415
|
||||
#define AU8522_FILTER_COEF_R416 0x416
|
||||
#define AU8522_FILTER_COEF_R417 0x417
|
||||
#define AU8522_FILTER_COEF_R418 0x418
|
||||
#define AU8522_FILTER_COEF_R419 0x419
|
||||
#define AU8522_FILTER_COEF_R41A 0x41A
|
||||
#define AU8522_FILTER_COEF_R41B 0x41B
|
||||
#define AU8522_FILTER_COEF_R41C 0x41C
|
||||
#define AU8522_FILTER_COEF_R41D 0x41D
|
||||
#define AU8522_FILTER_COEF_R41E 0x41E
|
||||
#define AU8522_FILTER_COEF_R41F 0x41F
|
||||
#define AU8522_FILTER_COEF_R420 0x420
|
||||
#define AU8522_FILTER_COEF_R421 0x421
|
||||
#define AU8522_FILTER_COEF_R422 0x422
|
||||
#define AU8522_FILTER_COEF_R423 0x423
|
||||
#define AU8522_FILTER_COEF_R424 0x424
|
||||
#define AU8522_FILTER_COEF_R425 0x425
|
||||
#define AU8522_FILTER_COEF_R426 0x426
|
||||
#define AU8522_FILTER_COEF_R427 0x427
|
||||
#define AU8522_FILTER_COEF_R428 0x428
|
||||
#define AU8522_FILTER_COEF_R429 0x429
|
||||
#define AU8522_FILTER_COEF_R42A 0x42A
|
||||
#define AU8522_FILTER_COEF_R42B 0x42B
|
||||
#define AU8522_FILTER_COEF_R42C 0x42C
|
||||
#define AU8522_FILTER_COEF_R42D 0x42D
|
||||
|
||||
/* VBI Control Registers */
|
||||
#define AU8522_TVDEC_VBI_RX_FIFO_CONTAIN_REG004H 0x004
|
||||
#define AU8522_TVDEC_VBI_TX_FIFO_CONTAIN_REG005H 0x005
|
||||
#define AU8522_TVDEC_VBI_RX_FIFO_READ_REG006H 0x006
|
||||
#define AU8522_TVDEC_VBI_FIFO_STATUS_REG007H 0x007
|
||||
#define AU8522_TVDEC_VBI_CTRL_H_REG017H 0x017
|
||||
#define AU8522_TVDEC_VBI_CTRL_L_REG018H 0x018
|
||||
#define AU8522_TVDEC_VBI_USER_TOTAL_BITS_REG019H 0x019
|
||||
#define AU8522_TVDEC_VBI_USER_TUNIT_H_REG01AH 0x01A
|
||||
#define AU8522_TVDEC_VBI_USER_TUNIT_L_REG01BH 0x01B
|
||||
#define AU8522_TVDEC_VBI_USER_THRESH1_REG01CH 0x01C
|
||||
#define AU8522_TVDEC_VBI_USER_FRAME_PAT2_REG01EH 0x01E
|
||||
#define AU8522_TVDEC_VBI_USER_FRAME_PAT1_REG01FH 0x01F
|
||||
#define AU8522_TVDEC_VBI_USER_FRAME_PAT0_REG020H 0x020
|
||||
#define AU8522_TVDEC_VBI_USER_FRAME_MASK2_REG021H 0x021
|
||||
#define AU8522_TVDEC_VBI_USER_FRAME_MASK1_REG022H 0x022
|
||||
#define AU8522_TVDEC_VBI_USER_FRAME_MASK0_REG023H 0x023
|
||||
|
||||
#define AU8522_REG071H 0x071
|
||||
#define AU8522_REG072H 0x072
|
||||
#define AU8522_REG074H 0x074
|
||||
#define AU8522_REG075H 0x075
|
||||
|
||||
/* Digital Demodulator Registers */
|
||||
#define AU8522_FRAME_COUNT0_REG084H 0x084
|
||||
#define AU8522_RS_STATUS_G0_REG085H 0x085
|
||||
#define AU8522_RS_STATUS_B0_REG086H 0x086
|
||||
#define AU8522_RS_STATUS_E_REG087H 0x087
|
||||
#define AU8522_DEMODULATION_STATUS_REG088H 0x088
|
||||
#define AU8522_TOREGTRESTATUS_REG0E6H 0x0E6
|
||||
#define AU8522_TSPORT_CONTROL_REG10BH 0x10B
|
||||
#define AU8522_TSTHES_REG10CH 0x10C
|
||||
#define AU8522_FRMREGDFEKEEP_REG301H 0x301
|
||||
#define AU8522_DFE_AVERAGE_REG302H 0x302
|
||||
#define AU8522_FRMREGEQLERRWIN_REG303H 0x303
|
||||
#define AU8522_FRMREGFFEKEEP_REG304H 0x304
|
||||
#define AU8522_FRMREGDFECONTROL1_REG305H 0x305
|
||||
#define AU8522_FRMREGEQLERRLOW_REG306H 0x306
|
||||
|
||||
#define AU8522_REG42EH 0x42E
|
||||
#define AU8522_REG42FH 0x42F
|
||||
#define AU8522_REG430H 0x430
|
||||
#define AU8522_REG431H 0x431
|
||||
#define AU8522_REG432H 0x432
|
||||
#define AU8522_REG433H 0x433
|
||||
#define AU8522_REG434H 0x434
|
||||
#define AU8522_REG435H 0x435
|
||||
#define AU8522_REG436H 0x436
|
||||
|
||||
/* GPIO Registers */
|
||||
#define AU8522_GPIO_CONTROL_REG0E0H 0x0E0
|
||||
#define AU8522_GPIO_STATUS_REG0E1H 0x0E1
|
||||
#define AU8522_GPIO_DATA_REG0E2H 0x0E2
|
||||
|
||||
/* Audio Control Registers */
|
||||
#define AU8522_AUDIOAGC_REG0EEH 0x0EE
|
||||
#define AU8522_AUDIO_STATUS_REG0F0H 0x0F0
|
||||
#define AU8522_AUDIO_MODE_REG0F1H 0x0F1
|
||||
#define AU8522_AUDIO_VOLUME_L_REG0F2H 0x0F2
|
||||
#define AU8522_AUDIO_VOLUME_R_REG0F3H 0x0F3
|
||||
#define AU8522_AUDIO_VOLUME_REG0F4H 0x0F4
|
||||
#define AU8522_FRMREGAUPHASE_REG0F7H 0x0F7
|
||||
#define AU8522_REG0F9H 0x0F9
|
||||
|
||||
#define AU8522_AUDIOAGC2_REG605H 0x605
|
||||
#define AU8522_AUDIOFREQ_REG606H 0x606
|
||||
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Format control 1 */
|
||||
|
||||
/* VCR Mode 7-6 */
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_YES 0x80
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_NO 0x40
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_AUTO 0x00
|
||||
/* Field len 5-4 */
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_625 0x20
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 0x10
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_AUTO 0x00
|
||||
/* Line len (us) 3-2 */
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_64_000 0x0b
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 0x08
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_556 0x04
|
||||
/* Subcarrier freq 1-0 */
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO 0x03
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_443 0x02
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN 0x01
|
||||
#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_50 0x00
|
||||
|
||||
/* Format control 2 */
|
||||
#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_AUTODETECT 0x00
|
||||
#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC 0x01
|
||||
#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M 0x02
|
||||
|
||||
|
||||
#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4
|
||||
#define AU8522_INPUT_CONTROL_REG081H_ATVRF 0xC4
|
||||
#define AU8522_INPUT_CONTROL_REG081H_ATVRF13 0xC4
|
||||
#define AU8522_INPUT_CONTROL_REG081H_J83B64 0xC4
|
||||
#define AU8522_INPUT_CONTROL_REG081H_J83B256 0xC4
|
||||
#define AU8522_INPUT_CONTROL_REG081H_CVBS 0x20
|
||||
#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH1 0xA2
|
||||
#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH2 0xA0
|
||||
#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH3 0x69
|
||||
#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4 0x68
|
||||
#define AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF 0x28
|
||||
/* CH1 AS Y,CH3 AS C */
|
||||
#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 0x23
|
||||
/* CH2 AS Y,CH4 AS C */
|
||||
#define AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24 0x20
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATSC 0x0C
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B64 0x09
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_J83B256 0x09
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS 0x12
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF 0x1A
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_ATVRF13 0x1A
|
||||
#define AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO 0x02
|
||||
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CLEAR 0x00
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO 0x9C
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS 0x9D
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATSC 0xE8
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B256 0xCA
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_J83B64 0xCA
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF 0xDD
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_ATVRF13 0xDD
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_PAL 0xDD
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_FM 0xDD
|
||||
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATSC 0x80
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B256 0x80
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_J83B64 0x80
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_ATSC 0x40
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B256 0x40
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_J83B64 0x40
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_DONGLE_CLEAR 0x00
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF 0x01
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_ATVRF13 0x01
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_SVIDEO 0x04
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_CVBS 0x01
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PWM 0x03
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_IIS 0x09
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_PAL 0x01
|
||||
#define AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H_FM 0x01
|
||||
|
||||
/* STILL NEED TO BE REFACTORED @@@@@@@@@@@@@@ */
|
||||
#define AU8522_TVDEC_CONTRAST_REG00BH_CVBS 0x79
|
||||
#define AU8522_TVDEC_SATURATION_CB_REG00CH_CVBS 0x80
|
||||
#define AU8522_TVDEC_SATURATION_CR_REG00DH_CVBS 0x80
|
||||
#define AU8522_TVDEC_HUE_H_REG00EH_CVBS 0x00
|
||||
#define AU8522_TVDEC_HUE_L_REG00FH_CVBS 0x00
|
||||
#define AU8522_TVDEC_PGA_REG012H_CVBS 0x0F
|
||||
#define AU8522_TVDEC_COMB_MODE_REG015H_CVBS 0x00
|
||||
#define AU8522_REG016H_CVBS 0x00
|
||||
#define AU8522_TVDED_DBG_MODE_REG060H_CVBS 0x00
|
||||
#define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS 0x19
|
||||
#define AU8522_REG0F9H_AUDIO 0x20
|
||||
#define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS 0xA7
|
||||
#define AU8522_TVDEC_COMB_VDIF_THR1_REG065H_CVBS 0x0A
|
||||
#define AU8522_TVDEC_COMB_VDIF_THR2_REG066H_CVBS 0x32
|
||||
#define AU8522_TVDEC_COMB_VDIF_THR3_REG067H_CVBS 0x19
|
||||
#define AU8522_TVDEC_COMB_NOTCH_THR_REG068H_CVBS 0x23
|
||||
#define AU8522_TVDEC_COMB_HDIF_THR1_REG069H_CVBS 0x41
|
||||
#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A
|
||||
#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15
|
||||
#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E
|
||||
#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F
|
||||
#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80
|
||||
#define AU8522_REG071H_CVBS 0x18
|
||||
#define AU8522_REG072H_CVBS 0x30
|
||||
#define AU8522_TVDEC_COMB_DC_THR2_NTSC_REG073H_CVBS 0xF0
|
||||
#define AU8522_REG074H_CVBS 0x80
|
||||
#define AU8522_REG075H_CVBS 0xF0
|
||||
#define AU8522_TVDEC_DCAGC_CTRL_REG077H_CVBS 0xFB
|
||||
#define AU8522_TVDEC_PIC_START_ADJ_REG078H_CVBS 0x04
|
||||
#define AU8522_TVDEC_AGC_HIGH_LIMIT_REG079H_CVBS 0x00
|
||||
#define AU8522_TVDEC_MACROVISION_SYNC_THR_REG07AH_CVBS 0x00
|
||||
#define AU8522_TVDEC_INTRP_CTRL_REG07BH_CVBS 0xEE
|
||||
#define AU8522_TVDEC_AGC_LOW_LIMIT_REG0E4H_CVBS 0xFE
|
||||
#define AU8522_TOREGAAGC_REG0E5H_CVBS 0x00
|
||||
#define AU8522_TVDEC_VBI6A_REG035H_CVBS 0x40
|
||||
|
||||
/* Enables Closed captioning */
|
||||
#define AU8522_TVDEC_VBI_CTRL_H_REG017H_CCON 0x21
|
||||
869
drivers/media/dvb-frontends/bcm3510.c
Normal file
869
drivers/media/dvb-frontends/bcm3510.c
Normal file
|
|
@ -0,0 +1,869 @@
|
|||
/*
|
||||
* Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
|
||||
*
|
||||
* Copyright (C) 2001-5, B2C2 inc.
|
||||
*
|
||||
* GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* This driver is "hard-coded" to be used with the 1st generation of
|
||||
* Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
|
||||
* (Panasonic CT10S) is located here, which is actually wrong. Unless there is
|
||||
* another device with a BCM3510, this is no problem.
|
||||
*
|
||||
* The driver works also with QAM64 DVB-C, but had an unreasonable high
|
||||
* UNC. (Tested with the Air2PC ATSC 1st generation)
|
||||
*
|
||||
* You'll need a firmware for this driver in order to get it running. It is
|
||||
* called "dvb-fe-bcm3510-01.fw".
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "bcm3510.h"
|
||||
#include "bcm3510_priv.h"
|
||||
|
||||
/* Max transfer size done by bcm3510_do_hab_cmd() function */
|
||||
#define MAX_XFER_SIZE 128
|
||||
|
||||
struct bcm3510_state {
|
||||
|
||||
struct i2c_adapter* i2c;
|
||||
const struct bcm3510_config* config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
/* demodulator private data */
|
||||
struct mutex hab_mutex;
|
||||
u8 firmware_loaded:1;
|
||||
|
||||
unsigned long next_status_check;
|
||||
unsigned long status_check_interval;
|
||||
struct bcm3510_hab_cmd_status1 status1;
|
||||
struct bcm3510_hab_cmd_status2 status2;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able)).");
|
||||
|
||||
#define dprintk(level,x...) if (level & debug) printk(x)
|
||||
#define dbufout(b,l,m) {\
|
||||
int i; \
|
||||
for (i = 0; i < l; i++) \
|
||||
m("%02x ",b[i]); \
|
||||
}
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_i2c(args...) dprintk(0x02,args)
|
||||
#define deb_hab(args...) dprintk(0x04,args)
|
||||
|
||||
/* transfer functions */
|
||||
static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
|
||||
{
|
||||
u8 b[256];
|
||||
int err;
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 };
|
||||
|
||||
b[0] = reg;
|
||||
memcpy(&b[1],buf,len);
|
||||
|
||||
deb_i2c("i2c wr %02x: ",reg);
|
||||
dbufout(buf,len,deb_i2c);
|
||||
deb_i2c("\n");
|
||||
|
||||
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
|
||||
|
||||
deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
|
||||
__func__, state->config->demod_address, reg, err);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
|
||||
{
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 },
|
||||
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len }
|
||||
};
|
||||
int err;
|
||||
|
||||
memset(buf,0,len);
|
||||
|
||||
if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
|
||||
deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
|
||||
__func__, state->config->demod_address, reg, err);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
deb_i2c("i2c rd %02x: ",reg);
|
||||
dbufout(buf,len,deb_i2c);
|
||||
deb_i2c("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v)
|
||||
{
|
||||
return bcm3510_writebytes(state,reg,&v.raw,1);
|
||||
}
|
||||
|
||||
static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v)
|
||||
{
|
||||
return bcm3510_readbytes(state,reg,&v->raw,1);
|
||||
}
|
||||
|
||||
/* Host Access Buffer transfers */
|
||||
static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len)
|
||||
{
|
||||
bcm3510_register_value v;
|
||||
int ret,i;
|
||||
|
||||
v.HABADR_a6.HABADR = 0;
|
||||
if ((ret = bcm3510_writeB(st,0xa6,v)) < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((ret = bcm3510_readB(st,0xa7,&v)) < 0)
|
||||
return ret;
|
||||
buf[i] = v.HABDATA_a7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len)
|
||||
{
|
||||
bcm3510_register_value v,hab;
|
||||
int ret,i;
|
||||
unsigned long t;
|
||||
|
||||
/* Check if any previous HAB request still needs to be serviced by the
|
||||
* Acquisition Processor before sending new request */
|
||||
if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
|
||||
return ret;
|
||||
if (v.HABSTAT_a8.HABR) {
|
||||
deb_info("HAB is running already - clearing it.\n");
|
||||
v.HABSTAT_a8.HABR = 0;
|
||||
bcm3510_writeB(st,0xa8,v);
|
||||
// return -EBUSY;
|
||||
}
|
||||
|
||||
/* Send the start HAB Address (automatically incremented after write of
|
||||
* HABDATA) and write the HAB Data */
|
||||
hab.HABADR_a6.HABADR = 0;
|
||||
if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
hab.HABDATA_a7 = buf[i];
|
||||
if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to
|
||||
* be written) */
|
||||
v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1;
|
||||
if ((ret = bcm3510_writeB(st,0xa8,v)) < 0)
|
||||
return ret;
|
||||
|
||||
/* Polling method: Wait until the AP finishes processing the HAB request */
|
||||
t = jiffies + 1*HZ;
|
||||
while (time_before(jiffies, t)) {
|
||||
deb_info("waiting for HAB to complete\n");
|
||||
msleep(10);
|
||||
if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
|
||||
return ret;
|
||||
|
||||
if (!v.HABSTAT_a8.HABR)
|
||||
return 0;
|
||||
}
|
||||
|
||||
deb_info("send_request execution timed out.\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen)
|
||||
{
|
||||
u8 ob[MAX_XFER_SIZE], ib[MAX_XFER_SIZE];
|
||||
int ret = 0;
|
||||
|
||||
if (ilen + 2 > sizeof(ib)) {
|
||||
deb_hab("do_hab_cmd: ilen=%d is too big!\n", ilen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (olen + 2 > sizeof(ob)) {
|
||||
deb_hab("do_hab_cmd: olen=%d is too big!\n", olen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ob[0] = cmd;
|
||||
ob[1] = msgid;
|
||||
memcpy(&ob[2],obuf,olen);
|
||||
|
||||
deb_hab("hab snd: ");
|
||||
dbufout(ob,olen+2,deb_hab);
|
||||
deb_hab("\n");
|
||||
|
||||
if (mutex_lock_interruptible(&st->hab_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
|
||||
(ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0)
|
||||
goto error;
|
||||
|
||||
deb_hab("hab get: ");
|
||||
dbufout(ib,ilen+2,deb_hab);
|
||||
deb_hab("\n");
|
||||
|
||||
memcpy(ibuf,&ib[2],ilen);
|
||||
error:
|
||||
mutex_unlock(&st->hab_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* not needed, we use a semaphore to prevent HAB races */
|
||||
static int bcm3510_is_ap_ready(struct bcm3510_state *st)
|
||||
{
|
||||
bcm3510_register_value ap,hab;
|
||||
int ret;
|
||||
|
||||
if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 ||
|
||||
(ret = bcm3510_readB(st,0xa2,&ap) < 0))
|
||||
return ret;
|
||||
|
||||
if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) {
|
||||
deb_info("AP is busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int bcm3510_bert_reset(struct bcm3510_state *st)
|
||||
{
|
||||
bcm3510_register_value b;
|
||||
int ret;
|
||||
|
||||
if ((ret = bcm3510_readB(st,0xfa,&b)) < 0)
|
||||
return ret;
|
||||
|
||||
b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
|
||||
b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b);
|
||||
b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
|
||||
b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b);
|
||||
|
||||
/* clear residual bit counter TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_refresh_state(struct bcm3510_state *st)
|
||||
{
|
||||
if (time_after(jiffies,st->next_status_check)) {
|
||||
bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1));
|
||||
bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2));
|
||||
st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
bcm3510_refresh_state(st);
|
||||
|
||||
*status = 0;
|
||||
if (st->status1.STATUS1.RECEIVER_LOCK)
|
||||
*status |= FE_HAS_LOCK | FE_HAS_SYNC;
|
||||
|
||||
if (st->status1.STATUS1.FEC_LOCK)
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
if (st->status1.STATUS1.OUT_PLL_LOCK)
|
||||
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
st->status_check_interval = 1500;
|
||||
else /* more frequently checks if no lock has been achieved yet */
|
||||
st->status_check_interval = 500;
|
||||
|
||||
deb_info("real_status: %02x\n",*status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
bcm3510_refresh_state(st);
|
||||
|
||||
*ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
bcm3510_refresh_state(st);
|
||||
*unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
s32 t;
|
||||
|
||||
bcm3510_refresh_state(st);
|
||||
t = st->status2.SIGNAL;
|
||||
|
||||
if (t > 190)
|
||||
t = 190;
|
||||
if (t < 90)
|
||||
t = 90;
|
||||
|
||||
t -= 90;
|
||||
t = t * 0xff / 100;
|
||||
/* normalize if necessary */
|
||||
*strength = (t << 8) | t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
bcm3510_refresh_state(st);
|
||||
|
||||
*snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tuner frontend programming */
|
||||
static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a)
|
||||
{
|
||||
struct bcm3510_hab_cmd_tune c;
|
||||
memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune));
|
||||
|
||||
/* I2C Mode disabled, set 16 control / Data pairs */
|
||||
c.length = 0x10;
|
||||
c.clock_width = 0;
|
||||
/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to
|
||||
* logic high (as Configuration) */
|
||||
c.misc = 0x10;
|
||||
/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */
|
||||
c.TUNCTL_state = 0x40;
|
||||
|
||||
/* PRESCALER DIVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */
|
||||
c.ctl_dat[0].ctrl.size = BITS_8;
|
||||
c.ctl_dat[0].data = 0x80 | bc;
|
||||
|
||||
/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */
|
||||
c.ctl_dat[1].ctrl.size = BITS_8;
|
||||
c.ctl_dat[1].data = 4;
|
||||
|
||||
/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */
|
||||
c.ctl_dat[2].ctrl.size = BITS_3;
|
||||
c.ctl_dat[2].data = 0x20;
|
||||
|
||||
/* control CS0 pin, pulse byte ? */
|
||||
c.ctl_dat[3].ctrl.size = BITS_3;
|
||||
c.ctl_dat[3].ctrl.clk_off = 1;
|
||||
c.ctl_dat[3].ctrl.cs0 = 1;
|
||||
c.ctl_dat[3].data = 0x40;
|
||||
|
||||
/* PGM_S18 to PGM_S11 */
|
||||
c.ctl_dat[4].ctrl.size = BITS_8;
|
||||
c.ctl_dat[4].data = n >> 3;
|
||||
|
||||
/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */
|
||||
c.ctl_dat[5].ctrl.size = BITS_8;
|
||||
c.ctl_dat[5].data = ((n & 0x7) << 5) | (a >> 2);
|
||||
|
||||
/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */
|
||||
c.ctl_dat[6].ctrl.size = BITS_3;
|
||||
c.ctl_dat[6].data = (a << 6) & 0xdf;
|
||||
|
||||
/* control CS0 pin, pulse byte ? */
|
||||
c.ctl_dat[7].ctrl.size = BITS_3;
|
||||
c.ctl_dat[7].ctrl.clk_off = 1;
|
||||
c.ctl_dat[7].ctrl.cs0 = 1;
|
||||
c.ctl_dat[7].data = 0x40;
|
||||
|
||||
/* PRESCALER DIVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */
|
||||
c.ctl_dat[8].ctrl.size = BITS_8;
|
||||
c.ctl_dat[8].data = 0x80;
|
||||
|
||||
/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */
|
||||
c.ctl_dat[9].ctrl.size = BITS_8;
|
||||
c.ctl_dat[9].data = 0x10;
|
||||
|
||||
/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */
|
||||
c.ctl_dat[10].ctrl.size = BITS_3;
|
||||
c.ctl_dat[10].data = 0x20;
|
||||
|
||||
/* pulse byte */
|
||||
c.ctl_dat[11].ctrl.size = BITS_3;
|
||||
c.ctl_dat[11].ctrl.clk_off = 1;
|
||||
c.ctl_dat[11].ctrl.cs1 = 1;
|
||||
c.ctl_dat[11].data = 0x40;
|
||||
|
||||
/* PGM_S18 to PGM_S11 */
|
||||
c.ctl_dat[12].ctrl.size = BITS_8;
|
||||
c.ctl_dat[12].data = 0x2a;
|
||||
|
||||
/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */
|
||||
c.ctl_dat[13].ctrl.size = BITS_8;
|
||||
c.ctl_dat[13].data = 0x8e;
|
||||
|
||||
/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */
|
||||
c.ctl_dat[14].ctrl.size = BITS_3;
|
||||
c.ctl_dat[14].data = 0;
|
||||
|
||||
/* Pulse Byte */
|
||||
c.ctl_dat[15].ctrl.size = BITS_3;
|
||||
c.ctl_dat[15].ctrl.clk_off = 1;
|
||||
c.ctl_dat[15].ctrl.cs1 = 1;
|
||||
c.ctl_dat[15].data = 0x40;
|
||||
|
||||
return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);
|
||||
}
|
||||
|
||||
static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
|
||||
{
|
||||
u8 bc,a;
|
||||
u16 n;
|
||||
s32 YIntercept,Tfvco1;
|
||||
|
||||
freq /= 1000;
|
||||
|
||||
deb_info("%dkHz:",freq);
|
||||
/* set Band Switch */
|
||||
if (freq <= 168000)
|
||||
bc = 0x1c;
|
||||
else if (freq <= 378000)
|
||||
bc = 0x2c;
|
||||
else
|
||||
bc = 0x30;
|
||||
|
||||
if (freq >= 470000) {
|
||||
freq -= 470001;
|
||||
YIntercept = 18805;
|
||||
} else if (freq >= 90000) {
|
||||
freq -= 90001;
|
||||
YIntercept = 15005;
|
||||
} else if (freq >= 76000){
|
||||
freq -= 76001;
|
||||
YIntercept = 14865;
|
||||
} else {
|
||||
freq -= 54001;
|
||||
YIntercept = 14645;
|
||||
}
|
||||
|
||||
Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10;
|
||||
|
||||
n = Tfvco1 >> 6;
|
||||
a = Tfvco1 & 0x3f;
|
||||
|
||||
deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a);
|
||||
if (n >= 16 && n <= 2047)
|
||||
return bcm3510_tuner_cmd(st,bc,n,a);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bcm3510_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
struct bcm3510_hab_cmd_ext_acquire cmd;
|
||||
struct bcm3510_hab_cmd_bert_control bert;
|
||||
int ret;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
switch (c->modulation) {
|
||||
case QAM_256:
|
||||
cmd.ACQUIRE0.MODE = 0x1;
|
||||
cmd.ACQUIRE1.SYM_RATE = 0x1;
|
||||
cmd.ACQUIRE1.IF_FREQ = 0x1;
|
||||
break;
|
||||
case QAM_64:
|
||||
cmd.ACQUIRE0.MODE = 0x2;
|
||||
cmd.ACQUIRE1.SYM_RATE = 0x2;
|
||||
cmd.ACQUIRE1.IF_FREQ = 0x1;
|
||||
break;
|
||||
#if 0
|
||||
case QAM_256:
|
||||
cmd.ACQUIRE0.MODE = 0x3;
|
||||
break;
|
||||
case QAM_128:
|
||||
cmd.ACQUIRE0.MODE = 0x4;
|
||||
break;
|
||||
case QAM_64:
|
||||
cmd.ACQUIRE0.MODE = 0x5;
|
||||
break;
|
||||
case QAM_32:
|
||||
cmd.ACQUIRE0.MODE = 0x6;
|
||||
break;
|
||||
case QAM_16:
|
||||
cmd.ACQUIRE0.MODE = 0x7;
|
||||
break;
|
||||
#endif
|
||||
case VSB_8:
|
||||
cmd.ACQUIRE0.MODE = 0x8;
|
||||
cmd.ACQUIRE1.SYM_RATE = 0x0;
|
||||
cmd.ACQUIRE1.IF_FREQ = 0x0;
|
||||
break;
|
||||
case VSB_16:
|
||||
cmd.ACQUIRE0.MODE = 0x9;
|
||||
cmd.ACQUIRE1.SYM_RATE = 0x0;
|
||||
cmd.ACQUIRE1.IF_FREQ = 0x0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
cmd.ACQUIRE0.OFFSET = 0;
|
||||
cmd.ACQUIRE0.NTSCSWEEP = 1;
|
||||
cmd.ACQUIRE0.FA = 1;
|
||||
cmd.ACQUIRE0.BW = 0;
|
||||
|
||||
/* if (enableOffset) {
|
||||
cmd.IF_OFFSET0 = xx;
|
||||
cmd.IF_OFFSET1 = xx;
|
||||
|
||||
cmd.SYM_OFFSET0 = xx;
|
||||
cmd.SYM_OFFSET1 = xx;
|
||||
if (enableNtscSweep) {
|
||||
cmd.NTSC_OFFSET0;
|
||||
cmd.NTSC_OFFSET1;
|
||||
}
|
||||
} */
|
||||
bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);
|
||||
|
||||
/* doing it with different MSGIDs, data book and source differs */
|
||||
bert.BE = 0;
|
||||
bert.unused = 0;
|
||||
bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0);
|
||||
bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0);
|
||||
|
||||
bcm3510_bert_reset(st);
|
||||
|
||||
ret = bcm3510_set_freq(st, c->frequency);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memset(&st->status1,0,sizeof(st->status1));
|
||||
memset(&st->status2,0,sizeof(st->status2));
|
||||
st->status_check_interval = 500;
|
||||
|
||||
/* Give the AP some time */
|
||||
msleep(200);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s)
|
||||
{
|
||||
s->min_delay_ms = 1000;
|
||||
s->step_size = 0;
|
||||
s->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm3510_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct bcm3510_state* state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
/* firmware download:
|
||||
* firmware file is build up like this:
|
||||
* 16bit addr, 16bit length, 8byte of length
|
||||
*/
|
||||
#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"
|
||||
|
||||
static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, const u8 *b,
|
||||
u16 len)
|
||||
{
|
||||
int ret = 0,i;
|
||||
bcm3510_register_value vH, vL,vD;
|
||||
|
||||
vH.MADRH_a9 = addr >> 8;
|
||||
vL.MADRL_aa = addr;
|
||||
if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret;
|
||||
if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
vD.MDATA_ab = b[i];
|
||||
if ((ret = bcm3510_writeB(st,0xab,vD)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_download_firmware(struct dvb_frontend* fe)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
const struct firmware *fw;
|
||||
u16 addr,len;
|
||||
const u8 *b;
|
||||
int ret,i;
|
||||
|
||||
deb_info("requesting firmware\n");
|
||||
if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) {
|
||||
err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
|
||||
return ret;
|
||||
}
|
||||
deb_info("got firmware: %zu\n", fw->size);
|
||||
|
||||
b = fw->data;
|
||||
for (i = 0; i < fw->size;) {
|
||||
addr = le16_to_cpu(*((__le16 *)&b[i]));
|
||||
len = le16_to_cpu(*((__le16 *)&b[i+2]));
|
||||
deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
|
||||
if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
|
||||
err("firmware download failed: %d\n",ret);
|
||||
return ret;
|
||||
}
|
||||
i += 4 + len;
|
||||
}
|
||||
release_firmware(fw);
|
||||
deb_info("firmware download successfully completed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_check_firmware_version(struct bcm3510_state *st)
|
||||
{
|
||||
struct bcm3510_hab_cmd_get_version_info ver;
|
||||
bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver));
|
||||
|
||||
deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version);
|
||||
|
||||
if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION &&
|
||||
ver.config_version == BCM3510_DEF_CONFIG_VERSION &&
|
||||
ver.demod_version == BCM3510_DEF_DEMOD_VERSION)
|
||||
return 0;
|
||||
|
||||
deb_info("version check failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* (un)resetting the AP */
|
||||
static int bcm3510_reset(struct bcm3510_state *st)
|
||||
{
|
||||
int ret;
|
||||
unsigned long t;
|
||||
bcm3510_register_value v;
|
||||
|
||||
bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1;
|
||||
if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
|
||||
return ret;
|
||||
|
||||
t = jiffies + 3*HZ;
|
||||
while (time_before(jiffies, t)) {
|
||||
msleep(10);
|
||||
if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
|
||||
return ret;
|
||||
|
||||
if (v.APSTAT1_a2.RESET)
|
||||
return 0;
|
||||
}
|
||||
deb_info("reset timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int bcm3510_clear_reset(struct bcm3510_state *st)
|
||||
{
|
||||
bcm3510_register_value v;
|
||||
int ret;
|
||||
unsigned long t;
|
||||
|
||||
v.raw = 0;
|
||||
if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
|
||||
return ret;
|
||||
|
||||
t = jiffies + 3*HZ;
|
||||
while (time_before(jiffies, t)) {
|
||||
msleep(10);
|
||||
if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
|
||||
return ret;
|
||||
|
||||
/* verify that reset is cleared */
|
||||
if (!v.APSTAT1_a2.RESET)
|
||||
return 0;
|
||||
}
|
||||
deb_info("reset clear timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int bcm3510_init_cold(struct bcm3510_state *st)
|
||||
{
|
||||
int ret;
|
||||
bcm3510_register_value v;
|
||||
|
||||
/* read Acquisation Processor status register and check it is not in RUN mode */
|
||||
if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
|
||||
return ret;
|
||||
if (v.APSTAT1_a2.RUN) {
|
||||
deb_info("AP is already running - firmware already loaded.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
deb_info("reset?\n");
|
||||
if ((ret = bcm3510_reset(st)) < 0)
|
||||
return ret;
|
||||
|
||||
deb_info("tristate?\n");
|
||||
/* tri-state */
|
||||
v.TSTCTL_2e.CTL = 0;
|
||||
if ((ret = bcm3510_writeB(st,0x2e,v)) < 0)
|
||||
return ret;
|
||||
|
||||
deb_info("firmware?\n");
|
||||
if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 ||
|
||||
(ret = bcm3510_clear_reset(st)) < 0)
|
||||
return ret;
|
||||
|
||||
/* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm3510_init(struct dvb_frontend* fe)
|
||||
{
|
||||
struct bcm3510_state* st = fe->demodulator_priv;
|
||||
bcm3510_register_value j;
|
||||
struct bcm3510_hab_cmd_set_agc c;
|
||||
int ret;
|
||||
|
||||
if ((ret = bcm3510_readB(st,0xca,&j)) < 0)
|
||||
return ret;
|
||||
|
||||
deb_info("JDEC: %02x\n",j.raw);
|
||||
|
||||
switch (j.JDEC_ca.JDEC) {
|
||||
case JDEC_WAIT_AT_RAM:
|
||||
deb_info("attempting to download firmware\n");
|
||||
if ((ret = bcm3510_init_cold(st)) < 0)
|
||||
return ret;
|
||||
case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */
|
||||
deb_info("firmware is loaded\n");
|
||||
bcm3510_check_firmware_version(st);
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(&c,0,1);
|
||||
c.SEL = 1;
|
||||
bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops bcm3510_ops;
|
||||
|
||||
struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct bcm3510_state* state = NULL;
|
||||
int ret;
|
||||
bcm3510_register_value v;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
mutex_init(&state->hab_mutex);
|
||||
|
||||
if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
|
||||
goto error;
|
||||
|
||||
deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER);
|
||||
|
||||
if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */
|
||||
(v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */
|
||||
goto error;
|
||||
|
||||
info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER);
|
||||
|
||||
bcm3510_reset(state);
|
||||
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(bcm3510_attach);
|
||||
|
||||
static struct dvb_frontend_ops bcm3510_ops = {
|
||||
.delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
|
||||
.info = {
|
||||
.name = "Broadcom BCM3510 VSB/QAM frontend",
|
||||
.frequency_min = 54000000,
|
||||
.frequency_max = 803000000,
|
||||
/* stepsize is just a guess */
|
||||
.frequency_stepsize = 0,
|
||||
.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_FEC_AUTO |
|
||||
FE_CAN_8VSB | FE_CAN_16VSB |
|
||||
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256
|
||||
},
|
||||
|
||||
.release = bcm3510_release,
|
||||
|
||||
.init = bcm3510_init,
|
||||
.sleep = bcm3510_sleep,
|
||||
|
||||
.set_frontend = bcm3510_set_frontend,
|
||||
.get_tune_settings = bcm3510_get_tune_settings,
|
||||
|
||||
.read_status = bcm3510_read_status,
|
||||
.read_ber = bcm3510_read_ber,
|
||||
.read_signal_strength = bcm3510_read_signal_strength,
|
||||
.read_snr = bcm3510_read_snr,
|
||||
.read_ucblocks = bcm3510_read_unc,
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
49
drivers/media/dvb-frontends/bcm3510.h
Normal file
49
drivers/media/dvb-frontends/bcm3510.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
|
||||
*
|
||||
* Copyright (C) 2001-5, B2C2 inc.
|
||||
*
|
||||
* GPL/Linux driver written by 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; 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 BCM3510_H
|
||||
#define BCM3510_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
struct bcm3510_config
|
||||
{
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* request firmware for device */
|
||||
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_BCM3510)
|
||||
extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
|
||||
struct i2c_adapter* i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_BCM3510
|
||||
|
||||
#endif
|
||||
460
drivers/media/dvb-frontends/bcm3510_priv.h
Normal file
460
drivers/media/dvb-frontends/bcm3510_priv.h
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
|
||||
*
|
||||
* Copyright (C) 2001-5, B2C2 inc.
|
||||
*
|
||||
* GPL/Linux driver written by 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; 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 __BCM3510_PRIV_H__
|
||||
#define __BCM3510_PRIV_H__
|
||||
|
||||
#define PACKED __attribute__((packed))
|
||||
|
||||
#undef err
|
||||
#define err(format, arg...) printk(KERN_ERR "bcm3510: " format "\n" , ## arg)
|
||||
#undef info
|
||||
#define info(format, arg...) printk(KERN_INFO "bcm3510: " format "\n" , ## arg)
|
||||
#undef warn
|
||||
#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg)
|
||||
|
||||
|
||||
#define PANASONIC_FIRST_IF_BASE_IN_KHz 1407500
|
||||
#define BCM3510_SYMBOL_RATE 5381000
|
||||
|
||||
typedef union {
|
||||
u8 raw;
|
||||
|
||||
struct {
|
||||
u8 CTL :8;
|
||||
} TSTCTL_2e;
|
||||
|
||||
u8 LDCERC_4e;
|
||||
u8 LDUERC_4f;
|
||||
u8 LD_BER0_65;
|
||||
u8 LD_BER1_66;
|
||||
u8 LD_BER2_67;
|
||||
u8 LD_BER3_68;
|
||||
|
||||
struct {
|
||||
u8 RESET :1;
|
||||
u8 IDLE :1;
|
||||
u8 STOP :1;
|
||||
u8 HIRQ0 :1;
|
||||
u8 HIRQ1 :1;
|
||||
u8 na0 :1;
|
||||
u8 HABAV :1;
|
||||
u8 na1 :1;
|
||||
} HCTL1_a0;
|
||||
|
||||
struct {
|
||||
u8 na0 :1;
|
||||
u8 IDLMSK :1;
|
||||
u8 STMSK :1;
|
||||
u8 I0MSK :1;
|
||||
u8 I1MSK :1;
|
||||
u8 na1 :1;
|
||||
u8 HABMSK :1;
|
||||
u8 na2 :1;
|
||||
} HCTLMSK_a1;
|
||||
|
||||
struct {
|
||||
u8 RESET :1;
|
||||
u8 IDLE :1;
|
||||
u8 STOP :1;
|
||||
u8 RUN :1;
|
||||
u8 HABAV :1;
|
||||
u8 MEMAV :1;
|
||||
u8 ALDONE :1;
|
||||
u8 REIRQ :1;
|
||||
} APSTAT1_a2;
|
||||
|
||||
struct {
|
||||
u8 RSTMSK :1;
|
||||
u8 IMSK :1;
|
||||
u8 SMSK :1;
|
||||
u8 RMSK :1;
|
||||
u8 HABMSK :1;
|
||||
u8 MAVMSK :1;
|
||||
u8 ALDMSK :1;
|
||||
u8 REMSK :1;
|
||||
} APMSK1_a3;
|
||||
|
||||
u8 APSTAT2_a4;
|
||||
u8 APMSK2_a5;
|
||||
|
||||
struct {
|
||||
u8 HABADR :7;
|
||||
u8 na :1;
|
||||
} HABADR_a6;
|
||||
|
||||
u8 HABDATA_a7;
|
||||
|
||||
struct {
|
||||
u8 HABR :1;
|
||||
u8 LDHABR :1;
|
||||
u8 APMSK :1;
|
||||
u8 HMSK :1;
|
||||
u8 LDMSK :1;
|
||||
u8 na :3;
|
||||
} HABSTAT_a8;
|
||||
|
||||
u8 MADRH_a9;
|
||||
u8 MADRL_aa;
|
||||
u8 MDATA_ab;
|
||||
|
||||
struct {
|
||||
#define JDEC_WAIT_AT_RAM 0x7
|
||||
#define JDEC_EEPROM_LOAD_WAIT 0x4
|
||||
u8 JDEC :3;
|
||||
u8 na :5;
|
||||
} JDEC_ca;
|
||||
|
||||
struct {
|
||||
u8 REV :4;
|
||||
u8 LAYER :4;
|
||||
} REVID_e0;
|
||||
|
||||
struct {
|
||||
u8 unk0 :1;
|
||||
u8 CNTCTL :1;
|
||||
u8 BITCNT :1;
|
||||
u8 unk1 :1;
|
||||
u8 RESYNC :1;
|
||||
u8 unk2 :3;
|
||||
} BERCTL_fa;
|
||||
|
||||
struct {
|
||||
u8 CSEL0 :1;
|
||||
u8 CLKED0 :1;
|
||||
u8 CSEL1 :1;
|
||||
u8 CLKED1 :1;
|
||||
u8 CLKLEV :1;
|
||||
u8 SPIVAR :1;
|
||||
u8 na :2;
|
||||
} TUNSET_fc;
|
||||
|
||||
struct {
|
||||
u8 CLK :1;
|
||||
u8 DATA :1;
|
||||
u8 CS0 :1;
|
||||
u8 CS1 :1;
|
||||
u8 AGCSEL :1;
|
||||
u8 na0 :1;
|
||||
u8 TUNSEL :1;
|
||||
u8 na1 :1;
|
||||
} TUNCTL_fd;
|
||||
|
||||
u8 TUNSEL0_fe;
|
||||
u8 TUNSEL1_ff;
|
||||
|
||||
} bcm3510_register_value;
|
||||
|
||||
/* HAB commands */
|
||||
|
||||
/* version */
|
||||
#define CMD_GET_VERSION_INFO 0x3D
|
||||
#define MSGID_GET_VERSION_INFO 0x15
|
||||
struct bcm3510_hab_cmd_get_version_info {
|
||||
u8 microcode_version;
|
||||
u8 script_version;
|
||||
u8 config_version;
|
||||
u8 demod_version;
|
||||
} PACKED;
|
||||
|
||||
#define BCM3510_DEF_MICROCODE_VERSION 0x0E
|
||||
#define BCM3510_DEF_SCRIPT_VERSION 0x06
|
||||
#define BCM3510_DEF_CONFIG_VERSION 0x01
|
||||
#define BCM3510_DEF_DEMOD_VERSION 0xB1
|
||||
|
||||
/* acquire */
|
||||
#define CMD_ACQUIRE 0x38
|
||||
|
||||
#define MSGID_EXT_TUNER_ACQUIRE 0x0A
|
||||
struct bcm3510_hab_cmd_ext_acquire {
|
||||
struct {
|
||||
u8 MODE :4;
|
||||
u8 BW :1;
|
||||
u8 FA :1;
|
||||
u8 NTSCSWEEP :1;
|
||||
u8 OFFSET :1;
|
||||
} PACKED ACQUIRE0; /* control_byte */
|
||||
|
||||
struct {
|
||||
u8 IF_FREQ :3;
|
||||
u8 zero0 :1;
|
||||
u8 SYM_RATE :3;
|
||||
u8 zero1 :1;
|
||||
} PACKED ACQUIRE1; /* sym_if */
|
||||
|
||||
u8 IF_OFFSET0; /* IF_Offset_10hz */
|
||||
u8 IF_OFFSET1;
|
||||
u8 SYM_OFFSET0; /* SymbolRateOffset */
|
||||
u8 SYM_OFFSET1;
|
||||
u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
|
||||
u8 NTSC_OFFSET1;
|
||||
} PACKED;
|
||||
|
||||
#define MSGID_INT_TUNER_ACQUIRE 0x0B
|
||||
struct bcm3510_hab_cmd_int_acquire {
|
||||
struct {
|
||||
u8 MODE :4;
|
||||
u8 BW :1;
|
||||
u8 FA :1;
|
||||
u8 NTSCSWEEP :1;
|
||||
u8 OFFSET :1;
|
||||
} PACKED ACQUIRE0; /* control_byte */
|
||||
|
||||
struct {
|
||||
u8 IF_FREQ :3;
|
||||
u8 zero0 :1;
|
||||
u8 SYM_RATE :3;
|
||||
u8 zero1 :1;
|
||||
} PACKED ACQUIRE1; /* sym_if */
|
||||
|
||||
u8 TUNER_FREQ0;
|
||||
u8 TUNER_FREQ1;
|
||||
u8 TUNER_FREQ2;
|
||||
u8 TUNER_FREQ3;
|
||||
u8 IF_OFFSET0; /* IF_Offset_10hz */
|
||||
u8 IF_OFFSET1;
|
||||
u8 SYM_OFFSET0; /* SymbolRateOffset */
|
||||
u8 SYM_OFFSET1;
|
||||
u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
|
||||
u8 NTSC_OFFSET1;
|
||||
} PACKED;
|
||||
|
||||
/* modes */
|
||||
#define BCM3510_QAM16 = 0x01
|
||||
#define BCM3510_QAM32 = 0x02
|
||||
#define BCM3510_QAM64 = 0x03
|
||||
#define BCM3510_QAM128 = 0x04
|
||||
#define BCM3510_QAM256 = 0x05
|
||||
#define BCM3510_8VSB = 0x0B
|
||||
#define BCM3510_16VSB = 0x0D
|
||||
|
||||
/* IF_FREQS */
|
||||
#define BCM3510_IF_TERRESTRIAL 0x0
|
||||
#define BCM3510_IF_CABLE 0x1
|
||||
#define BCM3510_IF_USE_CMD 0x7
|
||||
|
||||
/* SYM_RATE */
|
||||
#define BCM3510_SR_8VSB 0x0 /* 5381119 s/sec */
|
||||
#define BCM3510_SR_256QAM 0x1 /* 5360537 s/sec */
|
||||
#define BCM3510_SR_16QAM 0x2 /* 5056971 s/sec */
|
||||
#define BCM3510_SR_MISC 0x3 /* 5000000 s/sec */
|
||||
#define BCM3510_SR_USE_CMD 0x7
|
||||
|
||||
/* special symbol rate */
|
||||
#define CMD_SET_VALUE_NOT_LISTED 0x2d
|
||||
#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c
|
||||
struct bcm3510_hab_cmd_set_sr_not_listed {
|
||||
u8 HOST_SYM_RATE0;
|
||||
u8 HOST_SYM_RATE1;
|
||||
u8 HOST_SYM_RATE2;
|
||||
u8 HOST_SYM_RATE3;
|
||||
} PACKED;
|
||||
|
||||
/* special IF */
|
||||
#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d
|
||||
struct bcm3510_hab_cmd_set_if_freq_not_listed {
|
||||
u8 HOST_IF_FREQ0;
|
||||
u8 HOST_IF_FREQ1;
|
||||
u8 HOST_IF_FREQ2;
|
||||
u8 HOST_IF_FREQ3;
|
||||
} PACKED;
|
||||
|
||||
/* auto reacquire */
|
||||
#define CMD_AUTO_PARAM 0x2a
|
||||
#define MSGID_AUTO_REACQUIRE 0x0e
|
||||
struct bcm3510_hab_cmd_auto_reacquire {
|
||||
u8 ACQ :1; /* on/off*/
|
||||
u8 unused :7;
|
||||
} PACKED;
|
||||
|
||||
#define MSGID_SET_RF_AGC_SEL 0x12
|
||||
struct bcm3510_hab_cmd_set_agc {
|
||||
u8 LVL :1;
|
||||
u8 unused :6;
|
||||
u8 SEL :1;
|
||||
} PACKED;
|
||||
|
||||
#define MSGID_SET_AUTO_INVERSION 0x14
|
||||
struct bcm3510_hab_cmd_auto_inversion {
|
||||
u8 AI :1;
|
||||
u8 unused :7;
|
||||
} PACKED;
|
||||
|
||||
|
||||
/* bert control */
|
||||
#define CMD_STATE_CONTROL 0x12
|
||||
#define MSGID_BERT_CONTROL 0x0e
|
||||
#define MSGID_BERT_SET 0xfa
|
||||
struct bcm3510_hab_cmd_bert_control {
|
||||
u8 BE :1;
|
||||
u8 unused :7;
|
||||
} PACKED;
|
||||
|
||||
#define MSGID_TRI_STATE 0x2e
|
||||
struct bcm3510_hab_cmd_tri_state {
|
||||
u8 RE :1; /* a/d ram port pins */
|
||||
u8 PE :1; /* baud clock pin */
|
||||
u8 AC :1; /* a/d clock pin */
|
||||
u8 BE :1; /* baud clock pin */
|
||||
u8 unused :4;
|
||||
} PACKED;
|
||||
|
||||
|
||||
/* tune */
|
||||
#define CMD_TUNE 0x38
|
||||
#define MSGID_TUNE 0x16
|
||||
struct bcm3510_hab_cmd_tune_ctrl_data_pair {
|
||||
struct {
|
||||
#define BITS_8 0x07
|
||||
#define BITS_7 0x06
|
||||
#define BITS_6 0x05
|
||||
#define BITS_5 0x04
|
||||
#define BITS_4 0x03
|
||||
#define BITS_3 0x02
|
||||
#define BITS_2 0x01
|
||||
#define BITS_1 0x00
|
||||
u8 size :3;
|
||||
u8 unk :2;
|
||||
u8 clk_off :1;
|
||||
u8 cs0 :1;
|
||||
u8 cs1 :1;
|
||||
|
||||
} PACKED ctrl;
|
||||
|
||||
u8 data;
|
||||
} PACKED;
|
||||
|
||||
struct bcm3510_hab_cmd_tune {
|
||||
u8 length;
|
||||
u8 clock_width;
|
||||
u8 misc;
|
||||
u8 TUNCTL_state;
|
||||
|
||||
struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16];
|
||||
} PACKED;
|
||||
|
||||
#define CMD_STATUS 0x38
|
||||
#define MSGID_STATUS1 0x08
|
||||
struct bcm3510_hab_cmd_status1 {
|
||||
struct {
|
||||
u8 EQ_MODE :4;
|
||||
u8 reserved :2;
|
||||
u8 QRE :1; /* if QSE and the spectrum is inversed */
|
||||
u8 QSE :1; /* automatic spectral inversion */
|
||||
} PACKED STATUS0;
|
||||
|
||||
struct {
|
||||
u8 RECEIVER_LOCK :1;
|
||||
u8 FEC_LOCK :1;
|
||||
u8 OUT_PLL_LOCK :1;
|
||||
u8 reserved :5;
|
||||
} PACKED STATUS1;
|
||||
|
||||
struct {
|
||||
u8 reserved :2;
|
||||
u8 BW :1;
|
||||
u8 NTE :1; /* NTSC filter sweep enabled */
|
||||
u8 AQI :1; /* currently acquiring */
|
||||
u8 FA :1; /* fast acquisition */
|
||||
u8 ARI :1; /* auto reacquire */
|
||||
u8 TI :1; /* programming the tuner */
|
||||
} PACKED STATUS2;
|
||||
u8 STATUS3;
|
||||
u8 SNR_EST0;
|
||||
u8 SNR_EST1;
|
||||
u8 TUNER_FREQ0;
|
||||
u8 TUNER_FREQ1;
|
||||
u8 TUNER_FREQ2;
|
||||
u8 TUNER_FREQ3;
|
||||
u8 SYM_RATE0;
|
||||
u8 SYM_RATE1;
|
||||
u8 SYM_RATE2;
|
||||
u8 SYM_RATE3;
|
||||
u8 SYM_OFFSET0;
|
||||
u8 SYM_OFFSET1;
|
||||
u8 SYM_ERROR0;
|
||||
u8 SYM_ERROR1;
|
||||
u8 IF_FREQ0;
|
||||
u8 IF_FREQ1;
|
||||
u8 IF_FREQ2;
|
||||
u8 IF_FREQ3;
|
||||
u8 IF_OFFSET0;
|
||||
u8 IF_OFFSET1;
|
||||
u8 IF_ERROR0;
|
||||
u8 IF_ERROR1;
|
||||
u8 NTSC_FILTER0;
|
||||
u8 NTSC_FILTER1;
|
||||
u8 NTSC_FILTER2;
|
||||
u8 NTSC_FILTER3;
|
||||
u8 NTSC_OFFSET0;
|
||||
u8 NTSC_OFFSET1;
|
||||
u8 NTSC_ERROR0;
|
||||
u8 NTSC_ERROR1;
|
||||
u8 INT_AGC_LEVEL0;
|
||||
u8 INT_AGC_LEVEL1;
|
||||
u8 EXT_AGC_LEVEL0;
|
||||
u8 EXT_AGC_LEVEL1;
|
||||
} PACKED;
|
||||
|
||||
#define MSGID_STATUS2 0x14
|
||||
struct bcm3510_hab_cmd_status2 {
|
||||
struct {
|
||||
u8 EQ_MODE :4;
|
||||
u8 reserved :2;
|
||||
u8 QRE :1;
|
||||
u8 QSR :1;
|
||||
} PACKED STATUS0;
|
||||
struct {
|
||||
u8 RL :1;
|
||||
u8 FL :1;
|
||||
u8 OL :1;
|
||||
u8 reserved :5;
|
||||
} PACKED STATUS1;
|
||||
u8 SYMBOL_RATE0;
|
||||
u8 SYMBOL_RATE1;
|
||||
u8 SYMBOL_RATE2;
|
||||
u8 SYMBOL_RATE3;
|
||||
u8 LDCERC0;
|
||||
u8 LDCERC1;
|
||||
u8 LDCERC2;
|
||||
u8 LDCERC3;
|
||||
u8 LDUERC0;
|
||||
u8 LDUERC1;
|
||||
u8 LDUERC2;
|
||||
u8 LDUERC3;
|
||||
u8 LDBER0;
|
||||
u8 LDBER1;
|
||||
u8 LDBER2;
|
||||
u8 LDBER3;
|
||||
struct {
|
||||
u8 MODE_TYPE :4; /* acquire mode 0 */
|
||||
u8 reservd :4;
|
||||
} MODE_TYPE;
|
||||
u8 SNR_EST0;
|
||||
u8 SNR_EST1;
|
||||
u8 SIGNAL;
|
||||
} PACKED;
|
||||
|
||||
#define CMD_SET_RF_BW_NOT_LISTED 0x3f
|
||||
#define MSGID_SET_RF_BW_NOT_LISTED 0x11
|
||||
/* TODO */
|
||||
|
||||
#endif
|
||||
146
drivers/media/dvb-frontends/bsbe1-d01a.h
Normal file
146
drivers/media/dvb-frontends/bsbe1-d01a.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* bsbe1-d01a.h - ALPS BSBE1-D01A tuner support
|
||||
*
|
||||
* Copyright (C) 2011 Oliver Endriss <o.endriss@gmx.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
|
||||
*
|
||||
*
|
||||
* the project's page is at http://www.linuxtv.org
|
||||
*/
|
||||
|
||||
#ifndef BSBE1_D01A_H
|
||||
#define BSBE1_D01A_H
|
||||
|
||||
#include "stb6000.h"
|
||||
#include "stv0288.h"
|
||||
|
||||
static u8 stv0288_bsbe1_d01a_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x20,
|
||||
0x09, 0x0,
|
||||
0x0a, 0x4,
|
||||
0x0b, 0x0,
|
||||
0x0c, 0x0,
|
||||
0x0d, 0x0,
|
||||
0x0e, 0xd4,
|
||||
0x0f, 0x30,
|
||||
0x11, 0x80,
|
||||
0x12, 0x03,
|
||||
0x13, 0x48,
|
||||
0x14, 0x84,
|
||||
0x15, 0x45,
|
||||
0x16, 0xb7,
|
||||
0x17, 0x9c,
|
||||
0x18, 0x0,
|
||||
0x19, 0xa6,
|
||||
0x1a, 0x88,
|
||||
0x1b, 0x8f,
|
||||
0x1c, 0xf0,
|
||||
0x20, 0x0b,
|
||||
0x21, 0x54,
|
||||
0x22, 0x0,
|
||||
0x23, 0x0,
|
||||
0x2b, 0xff,
|
||||
0x2c, 0xf7,
|
||||
0x30, 0x0,
|
||||
0x31, 0x1e,
|
||||
0x32, 0x14,
|
||||
0x33, 0x0f,
|
||||
0x34, 0x09,
|
||||
0x35, 0x0c,
|
||||
0x36, 0x05,
|
||||
0x37, 0x2f,
|
||||
0x38, 0x16,
|
||||
0x39, 0xbd,
|
||||
0x3a, 0x03,
|
||||
0x3b, 0x13,
|
||||
0x3c, 0x11,
|
||||
0x3d, 0x30,
|
||||
0x40, 0x63,
|
||||
0x41, 0x04,
|
||||
0x42, 0x60,
|
||||
0x43, 0x00,
|
||||
0x44, 0x00,
|
||||
0x45, 0x00,
|
||||
0x46, 0x00,
|
||||
0x47, 0x00,
|
||||
0x4a, 0x00,
|
||||
0x50, 0x10,
|
||||
0x51, 0x36,
|
||||
0x52, 0x09,
|
||||
0x53, 0x94,
|
||||
0x54, 0x62,
|
||||
0x55, 0x29,
|
||||
0x56, 0x64,
|
||||
0x57, 0x2b,
|
||||
0x58, 0x54,
|
||||
0x59, 0x86,
|
||||
0x5a, 0x0,
|
||||
0x5b, 0x9b,
|
||||
0x5c, 0x08,
|
||||
0x5d, 0x7f,
|
||||
0x5e, 0x0,
|
||||
0x5f, 0xff,
|
||||
0x70, 0x0,
|
||||
0x71, 0x0,
|
||||
0x72, 0x0,
|
||||
0x74, 0x0,
|
||||
0x75, 0x0,
|
||||
0x76, 0x0,
|
||||
0x81, 0x0,
|
||||
0x82, 0x3f,
|
||||
0x83, 0x3f,
|
||||
0x84, 0x0,
|
||||
0x85, 0x0,
|
||||
0x88, 0x0,
|
||||
0x89, 0x0,
|
||||
0x8a, 0x0,
|
||||
0x8b, 0x0,
|
||||
0x8c, 0x0,
|
||||
0x90, 0x0,
|
||||
0x91, 0x0,
|
||||
0x92, 0x0,
|
||||
0x93, 0x0,
|
||||
0x94, 0x1c,
|
||||
0x97, 0x0,
|
||||
0xa0, 0x48,
|
||||
0xa1, 0x0,
|
||||
0xb0, 0xb8,
|
||||
0xb1, 0x3a,
|
||||
0xb2, 0x10,
|
||||
0xb3, 0x82,
|
||||
0xb4, 0x80,
|
||||
0xb5, 0x82,
|
||||
0xb6, 0x82,
|
||||
0xb7, 0x82,
|
||||
0xb8, 0x20,
|
||||
0xb9, 0x0,
|
||||
0xf0, 0x0,
|
||||
0xf1, 0x0,
|
||||
0xf2, 0xc0,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static struct stv0288_config stv0288_bsbe1_d01a_config = {
|
||||
.demod_address = 0x68,
|
||||
.min_delay_ms = 100,
|
||||
.inittab = stv0288_bsbe1_d01a_inittab,
|
||||
};
|
||||
|
||||
#endif
|
||||
106
drivers/media/dvb-frontends/bsbe1.h
Normal file
106
drivers/media/dvb-frontends/bsbe1.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* bsbe1.h - ALPS BSBE1 tuner support
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* the project's page is at http://www.linuxtv.org
|
||||
*/
|
||||
|
||||
#ifndef BSBE1_H
|
||||
#define BSBE1_H
|
||||
|
||||
static u8 alps_bsbe1_inittab[] = {
|
||||
0x01, 0x15, /* XTAL = 4MHz, VCO = 352 MHz */
|
||||
0x02, 0x30, /* MCLK = 88 MHz */
|
||||
0x03, 0x00, /* ACR output 0 */
|
||||
0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
|
||||
0x05, 0x05, /* I2CT = 0, SCLT = 1, SDAT = 1 */
|
||||
0x06, 0x00, /* DAC output 0 */
|
||||
0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
|
||||
0x09, 0x00, /* FIFO */
|
||||
0x0c, 0x51, /* OP1/OP0 normal, val = 1 (LNB power on) */
|
||||
0x0d, 0x82, /* DC offset compensation = on, beta_agc1 = 2 */
|
||||
0x0f, 0x92, /* AGC1R */
|
||||
0x10, 0x34, /* AGC2O */
|
||||
0x11, 0x84, /* TLSR */
|
||||
0x12, 0xb9, /* CFD */
|
||||
0x15, 0xc9, /* lock detector threshold */
|
||||
0x28, 0x00, /* out imp: normal, type: parallel, FEC mode: QPSK */
|
||||
0x33, 0xfc, /* RS control */
|
||||
0x34, 0x93, /* count viterbi bit errors per 2E18 bytes */
|
||||
0xff, 0xff
|
||||
};
|
||||
|
||||
|
||||
static int alps_bsbe1_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 alps_bsbe1_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
int ret;
|
||||
u8 data[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
|
||||
struct i2c_adapter *i2c = fe->tuner_priv;
|
||||
|
||||
if ((p->frequency < 950000) || (p->frequency > 2150000))
|
||||
return -EINVAL;
|
||||
|
||||
div = p->frequency / 1000;
|
||||
data[0] = (div >> 8) & 0x7f;
|
||||
data[1] = div & 0xff;
|
||||
data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1;
|
||||
data[3] = 0xe0;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
ret = i2c_transfer(i2c, &msg, 1);
|
||||
return (ret != 1) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static struct stv0299_config alps_bsbe1_config = {
|
||||
.demod_address = 0x68,
|
||||
.inittab = alps_bsbe1_inittab,
|
||||
.mclk = 88000000UL,
|
||||
.invert = 1,
|
||||
.skip_reinit = 0,
|
||||
.min_delay_ms = 100,
|
||||
.set_symbol_rate = alps_bsbe1_set_symbol_rate,
|
||||
};
|
||||
|
||||
#endif
|
||||
143
drivers/media/dvb-frontends/bsru6.h
Normal file
143
drivers/media/dvb-frontends/bsru6.h
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* the project's page is at http://www.linuxtv.org
|
||||
*/
|
||||
|
||||
#ifndef BSRU6_H
|
||||
#define BSRU6_H
|
||||
|
||||
static u8 alps_bsru6_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x30,
|
||||
0x03, 0x00,
|
||||
0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
|
||||
0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
|
||||
0x06, 0x40, /* DAC not used, set to high impendance mode */
|
||||
0x07, 0x00, /* DAC LSB */
|
||||
0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
|
||||
0x09, 0x00, /* FIFO */
|
||||
0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
|
||||
0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
|
||||
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
|
||||
0x10, 0x3f, // AGC2 0x3d
|
||||
0x11, 0x84,
|
||||
0x12, 0xb9,
|
||||
0x15, 0xc9, // lock detector threshold
|
||||
0x16, 0x00,
|
||||
0x17, 0x00,
|
||||
0x18, 0x00,
|
||||
0x19, 0x00,
|
||||
0x1a, 0x00,
|
||||
0x1f, 0x50,
|
||||
0x20, 0x00,
|
||||
0x21, 0x00,
|
||||
0x22, 0x00,
|
||||
0x23, 0x00,
|
||||
0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
|
||||
0x29, 0x1e, // 1/2 threshold
|
||||
0x2a, 0x14, // 2/3 threshold
|
||||
0x2b, 0x0f, // 3/4 threshold
|
||||
0x2c, 0x09, // 5/6 threshold
|
||||
0x2d, 0x05, // 7/8 threshold
|
||||
0x2e, 0x01,
|
||||
0x31, 0x1f, // test all FECs
|
||||
0x32, 0x19, // viterbi and synchro search
|
||||
0x33, 0xfc, // rs control
|
||||
0x34, 0x93, // error control
|
||||
0x0f, 0x52,
|
||||
0xff, 0xff
|
||||
};
|
||||
|
||||
static int alps_bsru6_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 alps_bsru6_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
struct i2c_adapter *i2c = fe->tuner_priv;
|
||||
|
||||
if ((p->frequency < 950000) || (p->frequency > 2150000))
|
||||
return -EINVAL;
|
||||
|
||||
div = (p->frequency + (125 - 1)) / 125; /* round correctly */
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = div & 0xff;
|
||||
buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
|
||||
buf[3] = 0xC4;
|
||||
|
||||
if (p->frequency > 1530000)
|
||||
buf[3] = 0xc0;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(i2c, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct stv0299_config alps_bsru6_config = {
|
||||
.demod_address = 0x68,
|
||||
.inittab = alps_bsru6_inittab,
|
||||
.mclk = 88000000UL,
|
||||
.invert = 1,
|
||||
.skip_reinit = 0,
|
||||
.lock_output = STV0299_LOCKOUTPUT_1,
|
||||
.volt13_op0_op1 = STV0299_VOLT13_OP1,
|
||||
.min_delay_ms = 100,
|
||||
.set_symbol_rate = alps_bsru6_set_symbol_rate,
|
||||
};
|
||||
|
||||
#endif
|
||||
443
drivers/media/dvb-frontends/cx22700.c
Normal file
443
drivers/media/dvb-frontends/cx22700.c
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
Conexant cx22700 DVB OFDM demodulator driver
|
||||
|
||||
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
|
||||
Holger Waechtler <holger@convergence.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.
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "cx22700.h"
|
||||
|
||||
|
||||
struct cx22700_state {
|
||||
|
||||
struct i2c_adapter* i2c;
|
||||
|
||||
const struct cx22700_config* config;
|
||||
|
||||
struct dvb_frontend frontend;
|
||||
};
|
||||
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) printk(KERN_DEBUG "cx22700: " args); \
|
||||
} while (0)
|
||||
|
||||
static u8 init_tab [] = {
|
||||
0x04, 0x10,
|
||||
0x05, 0x09,
|
||||
0x06, 0x00,
|
||||
0x08, 0x04,
|
||||
0x09, 0x00,
|
||||
0x0a, 0x01,
|
||||
0x15, 0x40,
|
||||
0x16, 0x10,
|
||||
0x17, 0x87,
|
||||
0x18, 0x17,
|
||||
0x1a, 0x10,
|
||||
0x25, 0x04,
|
||||
0x2e, 0x00,
|
||||
0x39, 0x00,
|
||||
0x3a, 0x04,
|
||||
0x45, 0x08,
|
||||
0x46, 0x02,
|
||||
0x47, 0x05,
|
||||
};
|
||||
|
||||
|
||||
static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf [] = { reg, data };
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
|
||||
ret = i2c_transfer (state->i2c, &msg, 1);
|
||||
|
||||
if (ret != 1)
|
||||
printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
|
||||
__func__, reg, data, ret);
|
||||
|
||||
return (ret != 1) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int cx22700_readreg (struct cx22700_state* state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b0 [] = { reg };
|
||||
u8 b1 [] = { 0 };
|
||||
struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
|
||||
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
|
||||
ret = i2c_transfer (state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2) return -EIO;
|
||||
|
||||
return b1[0];
|
||||
}
|
||||
|
||||
static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
|
||||
switch (inversion) {
|
||||
case INVERSION_AUTO:
|
||||
return -EOPNOTSUPP;
|
||||
case INVERSION_ON:
|
||||
val = cx22700_readreg (state, 0x09);
|
||||
return cx22700_writereg (state, 0x09, val | 0x01);
|
||||
case INVERSION_OFF:
|
||||
val = cx22700_readreg (state, 0x09);
|
||||
return cx22700_writereg (state, 0x09, val & 0xfe);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int cx22700_set_tps(struct cx22700_state *state,
|
||||
struct dtv_frontend_properties *p)
|
||||
{
|
||||
static const u8 qam_tab [4] = { 0, 1, 0, 2 };
|
||||
static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
|
||||
u8 val;
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
|
||||
if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
|
||||
return -EINVAL;
|
||||
|
||||
if ((int)p->guard_interval < GUARD_INTERVAL_1_32 ||
|
||||
p->guard_interval > GUARD_INTERVAL_1_4)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->transmission_mode != TRANSMISSION_MODE_2K &&
|
||||
p->transmission_mode != TRANSMISSION_MODE_8K)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->modulation != QPSK &&
|
||||
p->modulation != QAM_16 &&
|
||||
p->modulation != QAM_64)
|
||||
return -EINVAL;
|
||||
|
||||
if ((int)p->hierarchy < HIERARCHY_NONE ||
|
||||
p->hierarchy > HIERARCHY_4)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->bandwidth_hz == 7000000)
|
||||
cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
|
||||
else
|
||||
cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
|
||||
|
||||
val = qam_tab[p->modulation - QPSK];
|
||||
val |= p->hierarchy - HIERARCHY_NONE;
|
||||
|
||||
cx22700_writereg (state, 0x04, val);
|
||||
|
||||
val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
|
||||
val |= fec_tab[p->code_rate_LP - FEC_1_2];
|
||||
|
||||
cx22700_writereg (state, 0x05, val);
|
||||
|
||||
val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
|
||||
val |= p->transmission_mode - TRANSMISSION_MODE_2K;
|
||||
|
||||
cx22700_writereg (state, 0x06, val);
|
||||
|
||||
cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */
|
||||
cx22700_writereg (state, 0x08, 0x04); /* restart acquisition */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_get_tps(struct cx22700_state *state,
|
||||
struct dtv_frontend_properties *p)
|
||||
{
|
||||
static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
|
||||
static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
|
||||
FEC_5_6, FEC_7_8 };
|
||||
u8 val;
|
||||
|
||||
dprintk ("%s\n", __func__);
|
||||
|
||||
if (!(cx22700_readreg(state, 0x07) & 0x20)) /* tps valid? */
|
||||
return -EAGAIN;
|
||||
|
||||
val = cx22700_readreg (state, 0x01);
|
||||
|
||||
if ((val & 0x7) > 4)
|
||||
p->hierarchy = HIERARCHY_AUTO;
|
||||
else
|
||||
p->hierarchy = HIERARCHY_NONE + (val & 0x7);
|
||||
|
||||
if (((val >> 3) & 0x3) > 2)
|
||||
p->modulation = QAM_AUTO;
|
||||
else
|
||||
p->modulation = qam_tab[(val >> 3) & 0x3];
|
||||
|
||||
val = cx22700_readreg (state, 0x02);
|
||||
|
||||
if (((val >> 3) & 0x07) > 4)
|
||||
p->code_rate_HP = FEC_AUTO;
|
||||
else
|
||||
p->code_rate_HP = fec_tab[(val >> 3) & 0x07];
|
||||
|
||||
if ((val & 0x07) > 4)
|
||||
p->code_rate_LP = FEC_AUTO;
|
||||
else
|
||||
p->code_rate_LP = fec_tab[val & 0x07];
|
||||
|
||||
val = cx22700_readreg (state, 0x03);
|
||||
|
||||
p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
|
||||
p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_init (struct dvb_frontend* fe)
|
||||
|
||||
{ struct cx22700_state* state = fe->demodulator_priv;
|
||||
int i;
|
||||
|
||||
dprintk("cx22700_init: init chip\n");
|
||||
|
||||
cx22700_writereg (state, 0x00, 0x02); /* soft reset */
|
||||
cx22700_writereg (state, 0x00, 0x00);
|
||||
|
||||
msleep(10);
|
||||
|
||||
for (i=0; i<sizeof(init_tab); i+=2)
|
||||
cx22700_writereg (state, init_tab[i], init_tab[i+1]);
|
||||
|
||||
cx22700_writereg (state, 0x00, 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
|
||||
| (cx22700_readreg (state, 0x0e) << 1);
|
||||
u8 sync = cx22700_readreg (state, 0x07);
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (rs_ber < 0xff00)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
|
||||
if (sync & 0x20)
|
||||
*status |= FE_HAS_CARRIER;
|
||||
|
||||
if (sync & 0x10)
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
if (sync & 0x10)
|
||||
*status |= FE_HAS_SYNC;
|
||||
|
||||
if (*status == 0x0f)
|
||||
*status |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
*ber = cx22700_readreg (state, 0x0c) & 0x7f;
|
||||
cx22700_writereg (state, 0x0c, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
|
||||
| (cx22700_readreg (state, 0x0e) << 1);
|
||||
*signal_strength = ~rs_ber;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
|
||||
| (cx22700_readreg (state, 0x0e) << 1);
|
||||
*snr = ~rs_ber;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
*ucblocks = cx22700_readreg (state, 0x0f);
|
||||
cx22700_writereg (state, 0x0f, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
|
||||
cx22700_writereg (state, 0x00, 0x00);
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe);
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
cx22700_set_inversion(state, c->inversion);
|
||||
cx22700_set_tps(state, c);
|
||||
cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
|
||||
cx22700_writereg (state, 0x00, 0x01); /* restart acquire */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22700_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
u8 reg09 = cx22700_readreg (state, 0x09);
|
||||
|
||||
c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
|
||||
return cx22700_get_tps(state, c);
|
||||
}
|
||||
|
||||
static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
|
||||
if (enable) {
|
||||
return cx22700_writereg(state, 0x0a, 0x00);
|
||||
} else {
|
||||
return cx22700_writereg(state, 0x0a, 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
|
||||
{
|
||||
fesettings->min_delay_ms = 150;
|
||||
fesettings->step_size = 166667;
|
||||
fesettings->max_drift = 166667*2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx22700_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct cx22700_state* state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cx22700_ops;
|
||||
|
||||
struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
{
|
||||
struct cx22700_state* state = NULL;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct cx22700_state), GFP_KERNEL);
|
||||
if (state == NULL) goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
||||
/* check if the demod is there */
|
||||
if (cx22700_readreg(state, 0x07) < 0) goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cx22700_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "Conexant CX22700 DVB-T",
|
||||
.frequency_min = 470000000,
|
||||
.frequency_max = 860000000,
|
||||
.frequency_stepsize = 166667,
|
||||
.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_FEC_AUTO |
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
|
||||
FE_CAN_RECOVER
|
||||
},
|
||||
|
||||
.release = cx22700_release,
|
||||
|
||||
.init = cx22700_init,
|
||||
.i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
|
||||
|
||||
.set_frontend = cx22700_set_frontend,
|
||||
.get_frontend = cx22700_get_frontend,
|
||||
.get_tune_settings = cx22700_get_tune_settings,
|
||||
|
||||
.read_status = cx22700_read_status,
|
||||
.read_ber = cx22700_read_ber,
|
||||
.read_signal_strength = cx22700_read_signal_strength,
|
||||
.read_snr = cx22700_read_snr,
|
||||
.read_ucblocks = cx22700_read_ucblocks,
|
||||
};
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver");
|
||||
MODULE_AUTHOR("Holger Waechtler");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(cx22700_attach);
|
||||
46
drivers/media/dvb-frontends/cx22700.h
Normal file
46
drivers/media/dvb-frontends/cx22700.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Conexant CX22700 DVB OFDM demodulator driver
|
||||
|
||||
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
|
||||
Holger Waechtler <holger@convergence.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 CX22700_H
|
||||
#define CX22700_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct cx22700_config
|
||||
{
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_CX22700)
|
||||
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
|
||||
struct i2c_adapter* i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_CX22700
|
||||
|
||||
#endif // CX22700_H
|
||||
653
drivers/media/dvb-frontends/cx22702.c
Normal file
653
drivers/media/dvb-frontends/cx22702.c
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
/*
|
||||
Conexant 22702 DVB OFDM demodulator driver
|
||||
|
||||
based on:
|
||||
Alps TDMB7 DVB OFDM demodulator driver
|
||||
|
||||
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
|
||||
Holger Waechtler <holger@convergence.de>
|
||||
|
||||
Copyright (C) 2004 Steven Toth <stoth@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; 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include "cx22702.h"
|
||||
|
||||
struct cx22702_state {
|
||||
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
/* configuration settings */
|
||||
const struct cx22702_config *config;
|
||||
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
/* previous uncorrected block counter */
|
||||
u8 prevUCBlocks;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
|
||||
|
||||
#define dprintk if (debug) printk
|
||||
|
||||
/* Register values to initialise the demod */
|
||||
static const u8 init_tab[] = {
|
||||
0x00, 0x00, /* Stop acquisition */
|
||||
0x0B, 0x06,
|
||||
0x09, 0x01,
|
||||
0x0D, 0x41,
|
||||
0x16, 0x32,
|
||||
0x20, 0x0A,
|
||||
0x21, 0x17,
|
||||
0x24, 0x3e,
|
||||
0x26, 0xff,
|
||||
0x27, 0x10,
|
||||
0x28, 0x00,
|
||||
0x29, 0x00,
|
||||
0x2a, 0x10,
|
||||
0x2b, 0x00,
|
||||
0x2c, 0x10,
|
||||
0x2d, 0x00,
|
||||
0x48, 0xd4,
|
||||
0x49, 0x56,
|
||||
0x6b, 0x1e,
|
||||
0xc8, 0x02,
|
||||
0xf9, 0x00,
|
||||
0xfa, 0x00,
|
||||
0xfb, 0x00,
|
||||
0xfc, 0x00,
|
||||
0xfd, 0x00,
|
||||
};
|
||||
|
||||
static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config->demod_address, .flags = 0,
|
||||
.buf = buf, .len = 2 };
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
|
||||
if (unlikely(ret != 1)) {
|
||||
printk(KERN_ERR
|
||||
"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
|
||||
__func__, reg, data, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 data;
|
||||
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = state->config->demod_address, .flags = 0,
|
||||
.buf = ®, .len = 1 },
|
||||
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
|
||||
.buf = &data, .len = 1 } };
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (unlikely(ret != 2)) {
|
||||
printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
|
||||
__func__, reg, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
val = cx22702_readreg(state, 0x0C);
|
||||
switch (inversion) {
|
||||
case INVERSION_AUTO:
|
||||
return -EOPNOTSUPP;
|
||||
case INVERSION_ON:
|
||||
val |= 0x01;
|
||||
break;
|
||||
case INVERSION_OFF:
|
||||
val &= 0xfe;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return cx22702_writereg(state, 0x0C, val);
|
||||
}
|
||||
|
||||
/* Retrieve the demod settings */
|
||||
static int cx22702_get_tps(struct cx22702_state *state,
|
||||
struct dtv_frontend_properties *p)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
/* Make sure the TPS regs are valid */
|
||||
if (!(cx22702_readreg(state, 0x0A) & 0x20))
|
||||
return -EAGAIN;
|
||||
|
||||
val = cx22702_readreg(state, 0x01);
|
||||
switch ((val & 0x18) >> 3) {
|
||||
case 0:
|
||||
p->modulation = QPSK;
|
||||
break;
|
||||
case 1:
|
||||
p->modulation = QAM_16;
|
||||
break;
|
||||
case 2:
|
||||
p->modulation = QAM_64;
|
||||
break;
|
||||
}
|
||||
switch (val & 0x07) {
|
||||
case 0:
|
||||
p->hierarchy = HIERARCHY_NONE;
|
||||
break;
|
||||
case 1:
|
||||
p->hierarchy = HIERARCHY_1;
|
||||
break;
|
||||
case 2:
|
||||
p->hierarchy = HIERARCHY_2;
|
||||
break;
|
||||
case 3:
|
||||
p->hierarchy = HIERARCHY_4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
val = cx22702_readreg(state, 0x02);
|
||||
switch ((val & 0x38) >> 3) {
|
||||
case 0:
|
||||
p->code_rate_HP = FEC_1_2;
|
||||
break;
|
||||
case 1:
|
||||
p->code_rate_HP = FEC_2_3;
|
||||
break;
|
||||
case 2:
|
||||
p->code_rate_HP = FEC_3_4;
|
||||
break;
|
||||
case 3:
|
||||
p->code_rate_HP = FEC_5_6;
|
||||
break;
|
||||
case 4:
|
||||
p->code_rate_HP = FEC_7_8;
|
||||
break;
|
||||
}
|
||||
switch (val & 0x07) {
|
||||
case 0:
|
||||
p->code_rate_LP = FEC_1_2;
|
||||
break;
|
||||
case 1:
|
||||
p->code_rate_LP = FEC_2_3;
|
||||
break;
|
||||
case 2:
|
||||
p->code_rate_LP = FEC_3_4;
|
||||
break;
|
||||
case 3:
|
||||
p->code_rate_LP = FEC_5_6;
|
||||
break;
|
||||
case 4:
|
||||
p->code_rate_LP = FEC_7_8;
|
||||
break;
|
||||
}
|
||||
|
||||
val = cx22702_readreg(state, 0x03);
|
||||
switch ((val & 0x0c) >> 2) {
|
||||
case 0:
|
||||
p->guard_interval = GUARD_INTERVAL_1_32;
|
||||
break;
|
||||
case 1:
|
||||
p->guard_interval = GUARD_INTERVAL_1_16;
|
||||
break;
|
||||
case 2:
|
||||
p->guard_interval = GUARD_INTERVAL_1_8;
|
||||
break;
|
||||
case 3:
|
||||
p->guard_interval = GUARD_INTERVAL_1_4;
|
||||
break;
|
||||
}
|
||||
switch (val & 0x03) {
|
||||
case 0:
|
||||
p->transmission_mode = TRANSMISSION_MODE_2K;
|
||||
break;
|
||||
case 1:
|
||||
p->transmission_mode = TRANSMISSION_MODE_8K;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
u8 val;
|
||||
|
||||
dprintk("%s(%d)\n", __func__, enable);
|
||||
val = cx22702_readreg(state, 0x0D);
|
||||
if (enable)
|
||||
val &= 0xfe;
|
||||
else
|
||||
val |= 0x01;
|
||||
return cx22702_writereg(state, 0x0D, val);
|
||||
}
|
||||
|
||||
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
|
||||
static int cx22702_set_tps(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
u8 val;
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
/* set inversion */
|
||||
cx22702_set_inversion(state, p->inversion);
|
||||
|
||||
/* set bandwidth */
|
||||
val = cx22702_readreg(state, 0x0C) & 0xcf;
|
||||
switch (p->bandwidth_hz) {
|
||||
case 6000000:
|
||||
val |= 0x20;
|
||||
break;
|
||||
case 7000000:
|
||||
val |= 0x10;
|
||||
break;
|
||||
case 8000000:
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid bandwidth\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
cx22702_writereg(state, 0x0C, val);
|
||||
|
||||
p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
|
||||
|
||||
/* use auto configuration? */
|
||||
if ((p->hierarchy == HIERARCHY_AUTO) ||
|
||||
(p->modulation == QAM_AUTO) ||
|
||||
(p->code_rate_HP == FEC_AUTO) ||
|
||||
(p->code_rate_LP == FEC_AUTO) ||
|
||||
(p->guard_interval == GUARD_INTERVAL_AUTO) ||
|
||||
(p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
|
||||
|
||||
/* TPS Source - use hardware driven values */
|
||||
cx22702_writereg(state, 0x06, 0x10);
|
||||
cx22702_writereg(state, 0x07, 0x9);
|
||||
cx22702_writereg(state, 0x08, 0xC1);
|
||||
cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
|
||||
& 0xfc);
|
||||
cx22702_writereg(state, 0x0C,
|
||||
(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
|
||||
cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */
|
||||
dprintk("%s: Autodetecting\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* manually programmed values */
|
||||
switch (p->modulation) { /* mask 0x18 */
|
||||
case QPSK:
|
||||
val = 0x00;
|
||||
break;
|
||||
case QAM_16:
|
||||
val = 0x08;
|
||||
break;
|
||||
case QAM_64:
|
||||
val = 0x10;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid modulation\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (p->hierarchy) { /* mask 0x07 */
|
||||
case HIERARCHY_NONE:
|
||||
break;
|
||||
case HIERARCHY_1:
|
||||
val |= 0x01;
|
||||
break;
|
||||
case HIERARCHY_2:
|
||||
val |= 0x02;
|
||||
break;
|
||||
case HIERARCHY_4:
|
||||
val |= 0x03;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid hierarchy\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
cx22702_writereg(state, 0x06, val);
|
||||
|
||||
switch (p->code_rate_HP) { /* mask 0x38 */
|
||||
case FEC_NONE:
|
||||
case FEC_1_2:
|
||||
val = 0x00;
|
||||
break;
|
||||
case FEC_2_3:
|
||||
val = 0x08;
|
||||
break;
|
||||
case FEC_3_4:
|
||||
val = 0x10;
|
||||
break;
|
||||
case FEC_5_6:
|
||||
val = 0x18;
|
||||
break;
|
||||
case FEC_7_8:
|
||||
val = 0x20;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid code_rate_HP\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (p->code_rate_LP) { /* mask 0x07 */
|
||||
case FEC_NONE:
|
||||
case FEC_1_2:
|
||||
break;
|
||||
case FEC_2_3:
|
||||
val |= 0x01;
|
||||
break;
|
||||
case FEC_3_4:
|
||||
val |= 0x02;
|
||||
break;
|
||||
case FEC_5_6:
|
||||
val |= 0x03;
|
||||
break;
|
||||
case FEC_7_8:
|
||||
val |= 0x04;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid code_rate_LP\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
cx22702_writereg(state, 0x07, val);
|
||||
|
||||
switch (p->guard_interval) { /* mask 0x0c */
|
||||
case GUARD_INTERVAL_1_32:
|
||||
val = 0x00;
|
||||
break;
|
||||
case GUARD_INTERVAL_1_16:
|
||||
val = 0x04;
|
||||
break;
|
||||
case GUARD_INTERVAL_1_8:
|
||||
val = 0x08;
|
||||
break;
|
||||
case GUARD_INTERVAL_1_4:
|
||||
val = 0x0c;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid guard_interval\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (p->transmission_mode) { /* mask 0x03 */
|
||||
case TRANSMISSION_MODE_2K:
|
||||
break;
|
||||
case TRANSMISSION_MODE_8K:
|
||||
val |= 0x1;
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid transmission_mode\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
cx22702_writereg(state, 0x08, val);
|
||||
cx22702_writereg(state, 0x0B,
|
||||
(cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
|
||||
cx22702_writereg(state, 0x0C,
|
||||
(cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
|
||||
|
||||
/* Begin channel acquisition */
|
||||
cx22702_writereg(state, 0x00, 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset the demod hardware and reset all of the configuration registers
|
||||
to a default state. */
|
||||
static int cx22702_init(struct dvb_frontend *fe)
|
||||
{
|
||||
int i;
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
|
||||
cx22702_writereg(state, 0x00, 0x02);
|
||||
|
||||
msleep(10);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
|
||||
cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
|
||||
|
||||
cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
|
||||
& 0x02);
|
||||
|
||||
cx22702_i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
u8 reg0A;
|
||||
u8 reg23;
|
||||
|
||||
*status = 0;
|
||||
|
||||
reg0A = cx22702_readreg(state, 0x0A);
|
||||
reg23 = cx22702_readreg(state, 0x23);
|
||||
|
||||
dprintk("%s: status demod=0x%02x agc=0x%02x\n"
|
||||
, __func__, reg0A, reg23);
|
||||
|
||||
if (reg0A & 0x10) {
|
||||
*status |= FE_HAS_LOCK;
|
||||
*status |= FE_HAS_VITERBI;
|
||||
*status |= FE_HAS_SYNC;
|
||||
}
|
||||
|
||||
if (reg0A & 0x20)
|
||||
*status |= FE_HAS_CARRIER;
|
||||
|
||||
if (reg23 < 0xf0)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
|
||||
if (cx22702_readreg(state, 0xE4) & 0x02) {
|
||||
/* Realtime statistics */
|
||||
*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
|
||||
| (cx22702_readreg(state, 0xDF) & 0x7F);
|
||||
} else {
|
||||
/* Averagtine statistics */
|
||||
*ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
|
||||
| cx22702_readreg(state, 0xDF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *signal_strength)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
u8 reg23;
|
||||
|
||||
/*
|
||||
* Experience suggests that the strength signal register works as
|
||||
* follows:
|
||||
* - In the absence of signal, value is 0xff.
|
||||
* - In the presence of a weak signal, bit 7 is set, not sure what
|
||||
* the lower 7 bits mean.
|
||||
* - In the presence of a strong signal, the register holds a 7-bit
|
||||
* value (bit 7 is cleared), with greater values standing for
|
||||
* weaker signals.
|
||||
*/
|
||||
reg23 = cx22702_readreg(state, 0x23);
|
||||
if (reg23 & 0x80) {
|
||||
*signal_strength = 0;
|
||||
} else {
|
||||
reg23 = ~reg23 & 0x7f;
|
||||
/* Scale to 16 bit */
|
||||
*signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
|
||||
u16 rs_ber;
|
||||
if (cx22702_readreg(state, 0xE4) & 0x02) {
|
||||
/* Realtime statistics */
|
||||
rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
|
||||
| (cx22702_readreg(state, 0xDF) & 0x7F);
|
||||
} else {
|
||||
/* Averagine statistics */
|
||||
rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
|
||||
| cx22702_readreg(state, 0xDF);
|
||||
}
|
||||
*snr = ~rs_ber;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
|
||||
u8 _ucblocks;
|
||||
|
||||
/* RS Uncorrectable Packet Count then reset */
|
||||
_ucblocks = cx22702_readreg(state, 0xE3);
|
||||
if (state->prevUCBlocks < _ucblocks)
|
||||
*ucblocks = (_ucblocks - state->prevUCBlocks);
|
||||
else
|
||||
*ucblocks = state->prevUCBlocks - _ucblocks;
|
||||
state->prevUCBlocks = _ucblocks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx22702_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
|
||||
u8 reg0C = cx22702_readreg(state, 0x0C);
|
||||
|
||||
c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
|
||||
return cx22702_get_tps(state, c);
|
||||
}
|
||||
|
||||
static int cx22702_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx22702_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cx22702_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static const struct dvb_frontend_ops cx22702_ops;
|
||||
|
||||
struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct cx22702_state *state = NULL;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
||||
/* check if the demod is there */
|
||||
if (cx22702_readreg(state, 0x1f) != 0x3)
|
||||
goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &cx22702_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(cx22702_attach);
|
||||
|
||||
static const struct dvb_frontend_ops cx22702_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "Conexant CX22702 DVB-T",
|
||||
.frequency_min = 177000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 166666,
|
||||
.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_FEC_AUTO |
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
|
||||
},
|
||||
|
||||
.release = cx22702_release,
|
||||
|
||||
.init = cx22702_init,
|
||||
.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
|
||||
|
||||
.set_frontend = cx22702_set_tps,
|
||||
.get_frontend = cx22702_get_frontend,
|
||||
.get_tune_settings = cx22702_get_tune_settings,
|
||||
|
||||
.read_status = cx22702_read_status,
|
||||
.read_ber = cx22702_read_ber,
|
||||
.read_signal_strength = cx22702_read_signal_strength,
|
||||
.read_snr = cx22702_read_snr,
|
||||
.read_ucblocks = cx22702_read_ucblocks,
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
|
||||
MODULE_AUTHOR("Steven Toth");
|
||||
MODULE_LICENSE("GPL");
|
||||
58
drivers/media/dvb-frontends/cx22702.h
Normal file
58
drivers/media/dvb-frontends/cx22702.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Conexant 22702 DVB OFDM demodulator driver
|
||||
|
||||
based on:
|
||||
Alps TDMB7 DVB OFDM demodulator driver
|
||||
|
||||
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
|
||||
Holger Waechtler <holger@convergence.de>
|
||||
|
||||
Copyright (C) 2004 Steven Toth <stoth@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; 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 CX22702_H
|
||||
#define CX22702_H
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct cx22702_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* serial/parallel output */
|
||||
#define CX22702_PARALLEL_OUTPUT 0
|
||||
#define CX22702_SERIAL_OUTPUT 1
|
||||
u8 output_mode;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_CX22702)
|
||||
extern struct dvb_frontend *cx22702_attach(
|
||||
const struct cx22702_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *cx22702_attach(
|
||||
const struct cx22702_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
666
drivers/media/dvb-frontends/cx24110.c
Normal file
666
drivers/media/dvb-frontends/cx24110.c
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
cx24110 - Single Chip Satellite Channel Receiver driver module
|
||||
|
||||
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
|
||||
work
|
||||
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.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.
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "cx24110.h"
|
||||
|
||||
|
||||
struct cx24110_state {
|
||||
|
||||
struct i2c_adapter* i2c;
|
||||
|
||||
const struct cx24110_config* config;
|
||||
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
u32 lastber;
|
||||
u32 lastbler;
|
||||
u32 lastesn0;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) printk(KERN_DEBUG "cx24110: " args); \
|
||||
} while (0)
|
||||
|
||||
static struct {u8 reg; u8 data;} cx24110_regdata[]=
|
||||
/* Comments beginning with @ denote this value should
|
||||
be the default */
|
||||
{{0x09,0x01}, /* SoftResetAll */
|
||||
{0x09,0x00}, /* release reset */
|
||||
{0x01,0xe8}, /* MSB of code rate 27.5MS/s */
|
||||
{0x02,0x17}, /* middle byte " */
|
||||
{0x03,0x29}, /* LSB " */
|
||||
{0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */
|
||||
{0x06,0xa5}, /* @ PLL 60MHz */
|
||||
{0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
|
||||
{0x0a,0x00}, /* @ partial chip disables, do not set */
|
||||
{0x0b,0x01}, /* set output clock in gapped mode, start signal low
|
||||
active for first byte */
|
||||
{0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
|
||||
{0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
|
||||
{0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
|
||||
to avoid starting the BER counter. Reset the
|
||||
CRC test bit. Finite counting selected */
|
||||
{0x15,0xff}, /* @ size of the limited time window for RS BER
|
||||
estimation. It is <value>*256 RS blocks, this
|
||||
gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
|
||||
{0x16,0x00}, /* @ enable all RS output ports */
|
||||
{0x17,0x04}, /* @ time window allowed for the RS to sync */
|
||||
{0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
|
||||
for automatically */
|
||||
/* leave the current code rate and normalization
|
||||
registers as they are after reset... */
|
||||
{0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
|
||||
only once */
|
||||
{0x23,0x18}, /* @ size of the limited time window for Viterbi BER
|
||||
estimation. It is <value>*65536 channel bits, i.e.
|
||||
approx. 38ms at 27.5MS/s, rate 3/4 */
|
||||
{0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
|
||||
/* leave front-end AGC parameters at default values */
|
||||
/* leave decimation AGC parameters at default values */
|
||||
{0x35,0x40}, /* disable all interrupts. They are not connected anyway */
|
||||
{0x36,0xff}, /* clear all interrupt pending flags */
|
||||
{0x37,0x00}, /* @ fully enable AutoAcqq state machine */
|
||||
{0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */
|
||||
/* leave the equalizer parameters on their default values */
|
||||
/* leave the final AGC parameters on their default values */
|
||||
{0x41,0x00}, /* @ MSB of front-end derotator frequency */
|
||||
{0x42,0x00}, /* @ middle bytes " */
|
||||
{0x43,0x00}, /* @ LSB " */
|
||||
/* leave the carrier tracking loop parameters on default */
|
||||
/* leave the bit timing loop parameters at default */
|
||||
{0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */
|
||||
/* the cx24108 data sheet for symbol rates above 15MS/s */
|
||||
{0x57,0x00}, /* @ Filter sigma delta enabled, positive */
|
||||
{0x61,0x95}, /* GPIO pins 1-4 have special function */
|
||||
{0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */
|
||||
{0x63,0x00}, /* All GPIO pins use CMOS output characteristics */
|
||||
{0x64,0x20}, /* GPIO 6 is input, all others are outputs */
|
||||
{0x6d,0x30}, /* tuner auto mode clock freq 62kHz */
|
||||
{0x70,0x15}, /* use auto mode, tuner word is 21 bits long */
|
||||
{0x73,0x00}, /* @ disable several demod bypasses */
|
||||
{0x74,0x00}, /* @ " */
|
||||
{0x75,0x00} /* @ " */
|
||||
/* the remaining registers are for SEC */
|
||||
};
|
||||
|
||||
|
||||
static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
|
||||
{
|
||||
u8 buf [] = { reg, data };
|
||||
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
|
||||
int err;
|
||||
|
||||
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
|
||||
dprintk ("%s: writereg error (err == %i, reg == 0x%02x,"
|
||||
" data == 0x%02x)\n", __func__, err, reg, data);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_readreg (struct cx24110_state* state, u8 reg)
|
||||
{
|
||||
int ret;
|
||||
u8 b0 [] = { reg };
|
||||
u8 b1 [] = { 0 };
|
||||
struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
|
||||
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
|
||||
if (ret != 2) return ret;
|
||||
|
||||
return b1[0];
|
||||
}
|
||||
|
||||
static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion)
|
||||
{
|
||||
/* fixme (low): error handling */
|
||||
|
||||
switch (inversion) {
|
||||
case INVERSION_OFF:
|
||||
cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
|
||||
/* AcqSpectrInvDis on. No idea why someone should want this */
|
||||
cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
|
||||
/* Initial value 0 at start of acq */
|
||||
cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
|
||||
/* current value 0 */
|
||||
/* The cx24110 manual tells us this reg is read-only.
|
||||
But what the heck... set it ayways */
|
||||
break;
|
||||
case INVERSION_ON:
|
||||
cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
|
||||
/* AcqSpectrInvDis on. No idea why someone should want this */
|
||||
cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
|
||||
/* Initial value 1 at start of acq */
|
||||
cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
|
||||
/* current value 1 */
|
||||
break;
|
||||
case INVERSION_AUTO:
|
||||
cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
|
||||
/* AcqSpectrInvDis off. Leave initial & current states as is */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
|
||||
{
|
||||
/* fixme (low): error handling */
|
||||
|
||||
static const int rate[]={-1,1,2,3,5,7,-1};
|
||||
static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1};
|
||||
static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1};
|
||||
|
||||
/* Well, the AutoAcq engine of the cx24106 and 24110 automatically
|
||||
searches all enabled viterbi rates, and can handle non-standard
|
||||
rates as well. */
|
||||
|
||||
if (fec>FEC_AUTO)
|
||||
fec=FEC_AUTO;
|
||||
|
||||
if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
|
||||
cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf);
|
||||
/* clear AcqVitDis bit */
|
||||
cx24110_writereg(state,0x18,0xae);
|
||||
/* allow all DVB standard code rates */
|
||||
cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3);
|
||||
/* set nominal Viterbi rate 3/4 */
|
||||
cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3);
|
||||
/* set current Viterbi rate 3/4 */
|
||||
cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06);
|
||||
/* set the puncture registers for code rate 3/4 */
|
||||
return 0;
|
||||
} else {
|
||||
cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20);
|
||||
/* set AcqVitDis bit */
|
||||
if(rate[fec]>0) {
|
||||
cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]);
|
||||
/* set nominal Viterbi rate */
|
||||
cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]);
|
||||
/* set current Viterbi rate */
|
||||
cx24110_writereg(state,0x1a,g1[fec]);
|
||||
cx24110_writereg(state,0x1b,g2[fec]);
|
||||
/* not sure if this is the right way: I always used AutoAcq mode */
|
||||
} else
|
||||
return -EOPNOTSUPP;
|
||||
/* fixme (low): which is the correct return code? */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state)
|
||||
{
|
||||
int i;
|
||||
|
||||
i=cx24110_readreg(state,0x22)&0x0f;
|
||||
if(!(i&0x08)) {
|
||||
return FEC_1_2 + i - 1;
|
||||
} else {
|
||||
/* fixme (low): a special code rate has been selected. In theory, we need to
|
||||
return a denominator value, a numerator value, and a pair of puncture
|
||||
maps to correctly describe this mode. But this should never happen in
|
||||
practice, because it cannot be set by cx24110_get_fec. */
|
||||
return FEC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
|
||||
{
|
||||
/* fixme (low): add error handling */
|
||||
u32 ratio;
|
||||
u32 tmp, fclk, BDRI;
|
||||
|
||||
static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
|
||||
int i;
|
||||
|
||||
dprintk("cx24110 debug: entering %s(%d)\n",__func__,srate);
|
||||
if (srate>90999000UL/2)
|
||||
srate=90999000UL/2;
|
||||
if (srate<500000)
|
||||
srate=500000;
|
||||
|
||||
for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
|
||||
;
|
||||
/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
|
||||
and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
|
||||
R06[3:0] PLLphaseDetGain */
|
||||
tmp=cx24110_readreg(state,0x07)&0xfc;
|
||||
if(srate<90999000UL/4) { /* sample rate 45MHz*/
|
||||
cx24110_writereg(state,0x07,tmp);
|
||||
cx24110_writereg(state,0x06,0x78);
|
||||
fclk=90999000UL/2;
|
||||
} else if(srate<60666000UL/2) { /* sample rate 60MHz */
|
||||
cx24110_writereg(state,0x07,tmp|0x1);
|
||||
cx24110_writereg(state,0x06,0xa5);
|
||||
fclk=60666000UL;
|
||||
} else if(srate<80888000UL/2) { /* sample rate 80MHz */
|
||||
cx24110_writereg(state,0x07,tmp|0x2);
|
||||
cx24110_writereg(state,0x06,0x87);
|
||||
fclk=80888000UL;
|
||||
} else { /* sample rate 90MHz */
|
||||
cx24110_writereg(state,0x07,tmp|0x3);
|
||||
cx24110_writereg(state,0x06,0x78);
|
||||
fclk=90999000UL;
|
||||
}
|
||||
dprintk("cx24110 debug: fclk %d Hz\n",fclk);
|
||||
/* we need to divide two integers with approx. 27 bits in 32 bit
|
||||
arithmetic giving a 25 bit result */
|
||||
/* the maximum dividend is 90999000/2, 0x02b6446c, this number is
|
||||
also the most complex divisor. Hence, the dividend has,
|
||||
assuming 32bit unsigned arithmetic, 6 clear bits on top, the
|
||||
divisor 2 unused bits at the bottom. Also, the quotient is
|
||||
always less than 1/2. Borrowed from VES1893.c, of course */
|
||||
|
||||
tmp=srate<<6;
|
||||
BDRI=fclk>>2;
|
||||
ratio=(tmp/BDRI);
|
||||
|
||||
tmp=(tmp%BDRI)<<8;
|
||||
ratio=(ratio<<8)+(tmp/BDRI);
|
||||
|
||||
tmp=(tmp%BDRI)<<8;
|
||||
ratio=(ratio<<8)+(tmp/BDRI);
|
||||
|
||||
tmp=(tmp%BDRI)<<1;
|
||||
ratio=(ratio<<1)+(tmp/BDRI);
|
||||
|
||||
dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);
|
||||
dprintk("fclk = %d\n", fclk);
|
||||
dprintk("ratio= %08x\n", ratio);
|
||||
|
||||
cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
|
||||
cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
|
||||
cx24110_writereg(state, 0x3, (ratio)&0xff);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
if (len != 3)
|
||||
return -EINVAL;
|
||||
|
||||
/* tuner data is 21 bits long, must be left-aligned in data */
|
||||
/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
|
||||
/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
|
||||
|
||||
cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
|
||||
cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
|
||||
|
||||
/* if the auto tuner writer is still busy, clear it out */
|
||||
while (cx24110_readreg(state,0x6d)&0x80)
|
||||
cx24110_writereg(state,0x72,0);
|
||||
|
||||
/* write the topmost 8 bits */
|
||||
cx24110_writereg(state,0x72,buf[0]);
|
||||
|
||||
/* wait for the send to be completed */
|
||||
while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
|
||||
;
|
||||
|
||||
/* send another 8 bytes */
|
||||
cx24110_writereg(state,0x72,buf[1]);
|
||||
while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
|
||||
;
|
||||
|
||||
/* and the topmost 5 bits of this byte */
|
||||
cx24110_writereg(state,0x72,buf[2]);
|
||||
while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
|
||||
;
|
||||
|
||||
/* now strobe the enable line once */
|
||||
cx24110_writereg(state,0x6d,0x32);
|
||||
cx24110_writereg(state,0x6d,0x30);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_initfe(struct dvb_frontend* fe)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
/* fixme (low): error handling */
|
||||
int i;
|
||||
|
||||
dprintk("%s: init chip\n", __func__);
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
|
||||
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
switch (voltage) {
|
||||
case SEC_VOLTAGE_13:
|
||||
return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
|
||||
case SEC_VOLTAGE_18:
|
||||
return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
int rv, bit;
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
unsigned long timeout;
|
||||
|
||||
if (burst == SEC_MINI_A)
|
||||
bit = 0x00;
|
||||
else if (burst == SEC_MINI_B)
|
||||
bit = 0x08;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
rv = cx24110_readreg(state, 0x77);
|
||||
if (!(rv & 0x04))
|
||||
cx24110_writereg(state, 0x77, rv | 0x04);
|
||||
|
||||
rv = cx24110_readreg(state, 0x76);
|
||||
cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit));
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
|
||||
; /* wait for LNB ready */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
|
||||
struct dvb_diseqc_master_cmd *cmd)
|
||||
{
|
||||
int i, rv;
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
unsigned long timeout;
|
||||
|
||||
if (cmd->msg_len < 3 || cmd->msg_len > 6)
|
||||
return -EINVAL; /* not implemented */
|
||||
|
||||
for (i = 0; i < cmd->msg_len; i++)
|
||||
cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
|
||||
|
||||
rv = cx24110_readreg(state, 0x77);
|
||||
if (rv & 0x04) {
|
||||
cx24110_writereg(state, 0x77, rv & ~0x04);
|
||||
msleep(30); /* reportedly fixes switching problems */
|
||||
}
|
||||
|
||||
rv = cx24110_readreg(state, 0x76);
|
||||
|
||||
cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40))
|
||||
; /* wait for LNB ready */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
int sync = cx24110_readreg (state, 0x55);
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (sync & 0x10)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
|
||||
if (sync & 0x08)
|
||||
*status |= FE_HAS_CARRIER;
|
||||
|
||||
sync = cx24110_readreg (state, 0x08);
|
||||
|
||||
if (sync & 0x40)
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
if (sync & 0x20)
|
||||
*status |= FE_HAS_SYNC;
|
||||
|
||||
if ((sync & 0x60) == 0x60)
|
||||
*status |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
/* fixme (maybe): value range is 16 bit. Scale? */
|
||||
if(cx24110_readreg(state,0x24)&0x10) {
|
||||
/* the Viterbi error counter has finished one counting window */
|
||||
cx24110_writereg(state,0x24,0x04); /* select the ber reg */
|
||||
state->lastber=cx24110_readreg(state,0x25)|
|
||||
(cx24110_readreg(state,0x26)<<8);
|
||||
cx24110_writereg(state,0x24,0x04); /* start new count window */
|
||||
cx24110_writereg(state,0x24,0x14);
|
||||
}
|
||||
*ber = state->lastber;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
|
||||
u8 signal = cx24110_readreg (state, 0x27)+128;
|
||||
*signal_strength = (signal << 8) | signal;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
|
||||
if(cx24110_readreg(state,0x6a)&0x80) {
|
||||
/* the Es/N0 error counter has finished one counting window */
|
||||
state->lastesn0=cx24110_readreg(state,0x69)|
|
||||
(cx24110_readreg(state,0x68)<<8);
|
||||
cx24110_writereg(state,0x6a,0x84); /* start new count window */
|
||||
}
|
||||
*snr = state->lastesn0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
if(cx24110_readreg(state,0x10)&0x40) {
|
||||
/* the RS error counter has finished one counting window */
|
||||
cx24110_writereg(state,0x10,0x60); /* select the byer reg */
|
||||
(void)(cx24110_readreg(state, 0x12) |
|
||||
(cx24110_readreg(state, 0x13) << 8) |
|
||||
(cx24110_readreg(state, 0x14) << 16));
|
||||
cx24110_writereg(state,0x10,0x70); /* select the bler reg */
|
||||
state->lastbler=cx24110_readreg(state,0x12)|
|
||||
(cx24110_readreg(state,0x13)<<8)|
|
||||
(cx24110_readreg(state,0x14)<<16);
|
||||
cx24110_writereg(state,0x10,0x20); /* start new count window */
|
||||
}
|
||||
*ucblocks = state->lastbler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe);
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
cx24110_set_inversion(state, p->inversion);
|
||||
cx24110_set_fec(state, p->fec_inner);
|
||||
cx24110_set_symbolrate(state, p->symbol_rate);
|
||||
cx24110_writereg(state,0x04,0x05); /* start acquisition */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
s32 afc; unsigned sclk;
|
||||
|
||||
/* cannot read back tuner settings (freq). Need to have some private storage */
|
||||
|
||||
sclk = cx24110_readreg (state, 0x07) & 0x03;
|
||||
/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
|
||||
* Need 64 bit arithmetic. Is thiss possible in the kernel? */
|
||||
if (sclk==0) sclk=90999000L/2L;
|
||||
else if (sclk==1) sclk=60666000L;
|
||||
else if (sclk==2) sclk=80888000L;
|
||||
else sclk=90999000L;
|
||||
sclk>>=8;
|
||||
afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
|
||||
((sclk*cx24110_readreg (state, 0x45))>>8)+
|
||||
((sclk*cx24110_readreg (state, 0x46))>>16);
|
||||
|
||||
p->frequency += afc;
|
||||
p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
|
||||
INVERSION_ON : INVERSION_OFF;
|
||||
p->fec_inner = cx24110_get_fec(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct cx24110_state *state = fe->demodulator_priv;
|
||||
|
||||
return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
|
||||
}
|
||||
|
||||
static void cx24110_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct cx24110_state* state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cx24110_ops;
|
||||
|
||||
struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
{
|
||||
struct cx24110_state* state = NULL;
|
||||
int ret;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL);
|
||||
if (state == NULL) goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->lastber = 0;
|
||||
state->lastbler = 0;
|
||||
state->lastesn0 = 0;
|
||||
|
||||
/* check if the demod is there */
|
||||
ret = cx24110_readreg(state, 0x00);
|
||||
if ((ret != 0x5a) && (ret != 0x69)) goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cx24110_ops = {
|
||||
.delsys = { SYS_DVBS },
|
||||
.info = {
|
||||
.name = "Conexant CX24110 DVB-S",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
|
||||
.frequency_tolerance = 29500,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.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_RECOVER
|
||||
},
|
||||
|
||||
.release = cx24110_release,
|
||||
|
||||
.init = cx24110_initfe,
|
||||
.write = _cx24110_pll_write,
|
||||
.set_frontend = cx24110_set_frontend,
|
||||
.get_frontend = cx24110_get_frontend,
|
||||
.read_status = cx24110_read_status,
|
||||
.read_ber = cx24110_read_ber,
|
||||
.read_signal_strength = cx24110_read_signal_strength,
|
||||
.read_snr = cx24110_read_snr,
|
||||
.read_ucblocks = cx24110_read_ucblocks,
|
||||
|
||||
.diseqc_send_master_cmd = cx24110_send_diseqc_msg,
|
||||
.set_tone = cx24110_set_tone,
|
||||
.set_voltage = cx24110_set_voltage,
|
||||
.diseqc_send_burst = cx24110_diseqc_send_burst,
|
||||
};
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
|
||||
MODULE_AUTHOR("Peter Hettkamp");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(cx24110_attach);
|
||||
61
drivers/media/dvb-frontends/cx24110.h
Normal file
61
drivers/media/dvb-frontends/cx24110.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
cx24110 - Single Chip Satellite Channel Receiver driver module
|
||||
|
||||
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
|
||||
work
|
||||
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.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 CX24110_H
|
||||
#define CX24110_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct cx24110_config
|
||||
{
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
|
||||
{
|
||||
u8 buf[] = {
|
||||
(u8)((val >> 24) & 0xff),
|
||||
(u8)((val >> 16) & 0xff),
|
||||
(u8)((val >> 8) & 0xff)
|
||||
};
|
||||
|
||||
if (fe->ops.write)
|
||||
return fe->ops.write(fe, buf, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_CX24110)
|
||||
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
|
||||
struct i2c_adapter* i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
|
||||
struct i2c_adapter* i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_CX24110
|
||||
|
||||
#endif // CX24110_H
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue