aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/common
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/common')
-rw-r--r--drivers/media/common/Kconfig28
-rw-r--r--drivers/media/common/Makefile12
-rw-r--r--drivers/media/common/b2c2/Kconfig23
-rw-r--r--drivers/media/common/b2c2/Makefile8
-rw-r--r--drivers/media/common/b2c2/flexcop-common.h185
-rw-r--r--drivers/media/common/b2c2/flexcop-eeprom.c147
-rw-r--r--drivers/media/common/b2c2/flexcop-fe-tuner.c678
-rw-r--r--drivers/media/common/b2c2/flexcop-hw-filter.c232
-rw-r--r--drivers/media/common/b2c2/flexcop-i2c.c288
-rw-r--r--drivers/media/common/b2c2/flexcop-misc.c86
-rw-r--r--drivers/media/common/b2c2/flexcop-reg.h166
-rw-r--r--drivers/media/common/b2c2/flexcop-sram.c363
-rw-r--r--drivers/media/common/b2c2/flexcop.c325
-rw-r--r--drivers/media/common/b2c2/flexcop.h29
-rw-r--r--drivers/media/common/b2c2/flexcop_ibi_value_be.h455
-rw-r--r--drivers/media/common/b2c2/flexcop_ibi_value_le.h455
-rw-r--r--drivers/media/common/btcx-risc.c260
-rw-r--r--drivers/media/common/btcx-risc.h34
-rw-r--r--drivers/media/common/cx2341x.c1726
-rw-r--r--drivers/media/common/cypress_firmware.c132
-rw-r--r--drivers/media/common/cypress_firmware.h28
-rw-r--r--drivers/media/common/ir-functions.c381
-rw-r--r--drivers/media/common/ir-keymaps.c2035
-rw-r--r--drivers/media/common/saa7146/Kconfig9
-rw-r--r--drivers/media/common/saa7146/Makefile5
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c (renamed from drivers/media/common/saa7146_core.c)113
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c (renamed from drivers/media/common/saa7146_fops.c)401
-rw-r--r--drivers/media/common/saa7146/saa7146_hlp.c (renamed from drivers/media/common/saa7146_hlp.c)48
-rw-r--r--drivers/media/common/saa7146/saa7146_i2c.c (renamed from drivers/media/common/saa7146_i2c.c)141
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c (renamed from drivers/media/common/saa7146_vbi.c)110
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c1309
-rw-r--r--drivers/media/common/saa7146_video.c1508
-rw-r--r--drivers/media/common/siano/Kconfig33
-rw-r--r--drivers/media/common/siano/Makefile16
-rw-r--r--drivers/media/common/siano/sms-cards.c358
-rw-r--r--drivers/media/common/siano/sms-cards.h137
-rw-r--r--drivers/media/common/siano/smscoreapi.c2200
-rw-r--r--drivers/media/common/siano/smscoreapi.h1192
-rw-r--r--drivers/media/common/siano/smsdvb-debugfs.c551
-rw-r--r--drivers/media/common/siano/smsdvb-main.c1232
-rw-r--r--drivers/media/common/siano/smsdvb.h130
-rw-r--r--drivers/media/common/siano/smsendian.c103
-rw-r--r--drivers/media/common/siano/smsendian.h32
-rw-r--r--drivers/media/common/siano/smsir.c114
-rw-r--r--drivers/media/common/siano/smsir.h63
-rw-r--r--drivers/media/common/tveeprom.c776
46 files changed, 14336 insertions, 4321 deletions
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 769c6f8142d..b85f88c8ddb 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -1,9 +1,25 @@
-config VIDEO_SAA7146
+# 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
- depends on I2C && PCI
-config VIDEO_SAA7146_VV
+config VIDEO_TVEEPROM
tristate
- depends on VIDEO_V4L2
- select VIDEOBUF_DMA_SG
- select VIDEO_SAA7146
+ 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"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 8e744823064..d208de3b7cc 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,7 +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
-ir-common-objs := ir-functions.o ir-keymaps.o
-
-obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
-obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
-obj-$(CONFIG_VIDEO_IR) += ir-common.o
+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
diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig
new file mode 100644
index 00000000000..a8c6cdfaa2f
--- /dev/null
+++ b/drivers/media/common/b2c2/Kconfig
@@ -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
diff --git a/drivers/media/common/b2c2/Makefile b/drivers/media/common/b2c2/Makefile
new file mode 100644
index 00000000000..24993a5b38b
--- /dev/null
+++ b/drivers/media/common/b2c2/Makefile
@@ -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/
diff --git a/drivers/media/common/b2c2/flexcop-common.h b/drivers/media/common/b2c2/flexcop-common.h
new file mode 100644
index 00000000000..437912e4982
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-common.h
@@ -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
diff --git a/drivers/media/common/b2c2/flexcop-eeprom.c b/drivers/media/common/b2c2/flexcop-eeprom.c
new file mode 100644
index 00000000000..a25373a9bd8
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-eeprom.c
@@ -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);
diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c
new file mode 100644
index 00000000000..7e14e90d292
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c
@@ -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;
+}
diff --git a/drivers/media/common/b2c2/flexcop-hw-filter.c b/drivers/media/common/b2c2/flexcop-hw-filter.c
new file mode 100644
index 00000000000..77e45475f4c
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-hw-filter.c
@@ -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);
+}
diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c
new file mode 100644
index 00000000000..965d5eb3375
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-i2c.c
@@ -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;
+}
diff --git a/drivers/media/common/b2c2/flexcop-misc.c b/drivers/media/common/b2c2/flexcop-misc.c
new file mode 100644
index 00000000000..f06f3a9070f
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-misc.c
@@ -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);
diff --git a/drivers/media/common/b2c2/flexcop-reg.h b/drivers/media/common/b2c2/flexcop-reg.h
new file mode 100644
index 00000000000..dc4528dcbb9
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-reg.h
@@ -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
diff --git a/drivers/media/common/b2c2/flexcop-sram.c b/drivers/media/common/b2c2/flexcop-sram.c
new file mode 100644
index 00000000000..185c285f70f
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop-sram.c
@@ -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
diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c
new file mode 100644
index 00000000000..412c5daf2b4
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop.c
@@ -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");
diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h
new file mode 100644
index 00000000000..897b10c85ad
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop.h
@@ -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
diff --git a/drivers/media/common/b2c2/flexcop_ibi_value_be.h b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
new file mode 100644
index 00000000000..8f64bdbd72b
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop_ibi_value_be.h
@@ -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
diff --git a/drivers/media/common/b2c2/flexcop_ibi_value_le.h b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
new file mode 100644
index 00000000000..c75830d7d94
--- /dev/null
+++ b/drivers/media/common/b2c2/flexcop_ibi_value_le.h
@@ -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
diff --git a/drivers/media/common/btcx-risc.c b/drivers/media/common/btcx-risc.c
new file mode 100644
index 00000000000..ac1b2687a20
--- /dev/null
+++ b/drivers/media/common/btcx-risc.c
@@ -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:
+ */
diff --git a/drivers/media/common/btcx-risc.h b/drivers/media/common/btcx-risc.h
new file mode 100644
index 00000000000..f8bc6e8e7b5
--- /dev/null
+++ b/drivers/media/common/btcx-risc.h
@@ -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:
+ */
diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
new file mode 100644
index 00000000000..103ef6bad2e
--- /dev/null
+++ b/drivers/media/common/cx2341x.c
@@ -0,0 +1,1726 @@
+/*
+ * cx2341x - generic code for cx23415/6/8 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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 <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6/8 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/********************** COMMON CODE *********************/
+
+/* definitions for audio properties bits 29-28 */
+#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0
+#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1
+#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2
+
+static const char *cx2341x_get_name(u32 id)
+{
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return "Spatial Filter Mode";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ return "Spatial Filter";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return "Spatial Luma Filter Type";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return "Spatial Chroma Filter Type";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return "Temporal Filter Mode";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ return "Temporal Filter";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return "Median Filter Type";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ return "Median Luma Filter Maximum";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ return "Median Luma Filter Minimum";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ return "Median Chroma Filter Maximum";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ return "Median Chroma Filter Minimum";
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ return "Insert Navigation Packets";
+ }
+ return NULL;
+}
+
+static const char **cx2341x_get_menu(u32 id)
+{
+ static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ "1D Vertical",
+ "2D H/V Separable",
+ "2D Symmetric non-separable",
+ NULL
+ };
+
+ static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ NULL
+ };
+
+ static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_median_filter_type_menu[] = {
+ "Off",
+ "Horizontal",
+ "Vertical",
+ "Horizontal/Vertical",
+ "Diagonal",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_video_spatial_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_luma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_chroma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_video_temporal_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_video_median_filter_type_menu;
+ }
+ return NULL;
+}
+
+static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+ s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags)
+{
+ *name = cx2341x_get_name(id);
+ *flags = 0;
+
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ *type = V4L2_CTRL_TYPE_MENU;
+ *min = 0;
+ *step = 0;
+ break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
+ default:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ *flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ *flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
+ }
+}
+
+
+/********************** OLD CODE *********************/
+
+/* Must be sorted from low to high control ID! */
+const u32 cx2341x_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_STREAM_VBI_FMT,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_CID_MPEG_AUDIO_MODE,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_CID_MPEG_AUDIO_MUTE,
+ V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ V4L2_CID_MPEG_VIDEO_MUTE,
+ V4L2_CID_MPEG_VIDEO_MUTE_YUV,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
+ 0
+};
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+static const struct cx2341x_mpeg_params default_params = {
+ /* misc */
+ .capabilities = 0,
+ .port = CX2341X_PORT_MEMORY,
+ .width = 720,
+ .height = 480,
+ .is_50hz = 0,
+
+ /* stream */
+ .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ .stream_insert_nav_packets = 0,
+
+ /* audio */
+ .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+ .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K,
+ .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+ .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+ .audio_mute = 0,
+
+ /* video */
+ .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+ .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .video_b_frames = 2,
+ .video_gop_size = 12,
+ .video_gop_closure = 1,
+ .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .video_bitrate = 6000000,
+ .video_bitrate_peak = 8000000,
+ .video_temporal_decimation = 0,
+ .video_mute = 0,
+ .video_mute_yuv = 0x008080, /* YCbCr value for black */
+
+ /* encoding filters */
+ .video_spatial_filter_mode =
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ .video_spatial_filter = 0,
+ .video_luma_spatial_filter_type =
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_chroma_spatial_filter_type =
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_temporal_filter_mode =
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ .video_temporal_filter = 8,
+ .video_median_filter_type =
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ .video_luma_median_filter_top = 255,
+ .video_luma_median_filter_bottom = 0,
+ .video_chroma_median_filter_top = 255,
+ .video_chroma_median_filter_bottom = 0,
+};
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ ctrl->value = params->audio_sampling_freq;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ ctrl->value = params->audio_encoding;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ ctrl->value = params->audio_l2_bitrate;
+ break;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ ctrl->value = params->audio_ac3_bitrate;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ ctrl->value = params->audio_mode;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ ctrl->value = params->audio_mode_extension;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ ctrl->value = params->audio_emphasis;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ ctrl->value = params->audio_crc;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ ctrl->value = params->audio_mute;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ ctrl->value = params->video_encoding;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ ctrl->value = params->video_aspect;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ ctrl->value = params->video_b_frames;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = params->video_gop_size;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ ctrl->value = params->video_gop_closure;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ ctrl->value = params->video_bitrate_mode;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = params->video_bitrate;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ ctrl->value = params->video_bitrate_peak;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ ctrl->value = params->video_temporal_decimation;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ ctrl->value = params->video_mute;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+ ctrl->value = params->video_mute_yuv;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = params->stream_type;
+ break;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ ctrl->value = params->stream_vbi_fmt;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ ctrl->value = params->video_spatial_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ ctrl->value = params->video_spatial_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_luma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_chroma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ ctrl->value = params->video_temporal_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ ctrl->value = params->video_temporal_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ ctrl->value = params->video_median_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_luma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_luma_median_filter_bottom;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_chroma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_chroma_median_filter_bottom;
+ break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ ctrl->value = params->stream_insert_nav_packets;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ if (busy)
+ return -EBUSY;
+ params->audio_sampling_freq = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ if (busy)
+ return -EBUSY;
+ if (params->capabilities & CX2341X_CAP_HAS_AC3)
+ if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
+ ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3)
+ return -ERANGE;
+ params->audio_encoding = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ if (busy)
+ return -EBUSY;
+ params->audio_l2_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ if (busy)
+ return -EBUSY;
+ if (!(params->capabilities & CX2341X_CAP_HAS_AC3))
+ return -EINVAL;
+ params->audio_ac3_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ params->audio_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ params->audio_mode_extension = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ params->audio_emphasis = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ params->audio_crc = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ params->audio_mute = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ params->video_aspect = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+ int b = ctrl->value + 1;
+ int gop = params->video_gop_size;
+ params->video_b_frames = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+ int b = params->video_b_frames + 1;
+ int gop = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ ctrl->value = params->video_gop_size;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ params->video_gop_closure = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (busy)
+ return -EBUSY;
+ /* MPEG-1 only allows CBR */
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
+ ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ return -EINVAL;
+ params->video_bitrate_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ if (busy)
+ return -EBUSY;
+ params->video_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ if (busy)
+ return -EBUSY;
+ params->video_bitrate_peak = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ params->video_temporal_decimation = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ params->video_mute = (ctrl->value != 0);
+ break;
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+ params->video_mute_yuv = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ if (busy)
+ return -EBUSY;
+ params->stream_type = ctrl->value;
+ params->video_encoding =
+ (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+ params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ /* MPEG-1 implies CBR */
+ params->video_bitrate_mode =
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ break;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ params->stream_vbi_fmt = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ params->video_spatial_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ params->video_spatial_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ params->video_luma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ params->video_chroma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ params->video_temporal_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ params->video_temporal_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ params->video_median_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ params->video_luma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ params->video_luma_median_filter_bottom = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ params->video_chroma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ params->video_chroma_median_filter_bottom = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ params->stream_insert_nav_packets = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
+ s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ switch (qctrl->id) {
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type,
+ &min, &max, &step, &def, &qctrl->flags);
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ return 0;
+
+ default:
+ return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+ }
+}
+
+int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
+ struct v4l2_queryctrl *qctrl)
+{
+ int err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE);
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+ default_params.stream_vbi_fmt);
+
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ if (params->capabilities & CX2341X_CAP_HAS_AC3) {
+ /*
+ * The state of L2 & AC3 bitrate controls can change
+ * when this control changes, but v4l2_ctrl_query_fill()
+ * already sets V4L2_CTRL_FLAG_UPDATE for
+ * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here.
+ */
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
+ default_params.audio_encoding);
+ }
+
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+ default_params.audio_encoding);
+
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ default_params.audio_l2_bitrate);
+ if (err)
+ return err;
+ if (params->capabilities & CX2341X_CAP_HAS_AC3 &&
+ params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_STEREO,
+ V4L2_MPEG_AUDIO_MODE_MONO, 1,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ if (err == 0 &&
+ params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_CRC_NONE,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_48K,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1,
+ default_params.audio_ac3_bitrate);
+ if (err)
+ return err;
+ if (params->capabilities & CX2341X_CAP_HAS_AC3) {
+ if (params->audio_encoding !=
+ V4L2_MPEG_AUDIO_ENCODING_AC3)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ } else
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ /* this setting is read-only for the cx2341x since the
+ V4L2_CID_MPEG_STREAM_TYPE really determines the
+ MPEG-1/2 setting */
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ if (err == 0)
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
+ params->is_50hz ? 12 : 15);
+
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ if (err == 0 &&
+ params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+ if (err == 0 &&
+ params->video_bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */
+ return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
+
+ /* CX23415/6 specific */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+ default_params.video_spatial_filter_mode);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 15, 1,
+ default_params.video_spatial_filter);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_spatial_filter_mode ==
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+ 1,
+ default_params.video_luma_spatial_filter_type);
+ if (params->video_spatial_filter_mode ==
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ 1,
+ default_params.video_chroma_spatial_filter_type);
+ if (params->video_spatial_filter_mode ==
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+ default_params.video_temporal_filter_mode);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 31, 1,
+ default_params.video_temporal_filter);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_temporal_filter_mode ==
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+ default_params.video_median_filter_type);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+ default_params.video_luma_median_filter_top);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type ==
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+ default_params.video_luma_median_filter_bottom);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type ==
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+ default_params.video_chroma_median_filter_top);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type ==
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
+ default_params.video_chroma_median_filter_bottom);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type ==
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1,
+ default_params.stream_insert_nav_packets);
+
+ default:
+ return -EINVAL;
+
+ }
+}
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+{
+ static const char * const mpeg_stream_type_without_ts[] = {
+ "MPEG-2 Program Stream",
+ "",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ static const char *mpeg_stream_type_with_ts[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ static const char *mpeg_audio_encoding_l2_ac3[] = {
+ "",
+ "MPEG-1/2 Layer II",
+ "",
+ "",
+ "AC-3",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return (p->capabilities & CX2341X_CAP_HAS_TS) ?
+ mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return (p->capabilities & CX2341X_CAP_HAS_AC3) ?
+ mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id);
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return NULL;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_get_menu(id);
+ default:
+ return v4l2_ctrl_get_menu(id);
+ }
+}
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+ params->audio_properties =
+ (params->audio_sampling_freq << 0) |
+ (params->audio_mode << 8) |
+ (params->audio_mode_extension << 10) |
+ (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+ ? 3 : params->audio_emphasis) << 12) |
+ (params->audio_crc << 14);
+
+ if ((params->capabilities & CX2341X_CAP_HAS_AC3) &&
+ params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+ params->audio_properties |=
+ /* Not sure if this MPEG Layer II setting is required */
+ ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
+ (params->audio_ac3_bitrate << 4) |
+ (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
+ } else {
+ /* Assuming MPEG Layer II */
+ params->audio_properties |=
+ ((3 - params->audio_encoding) << 2) |
+ ((1 + params->audio_l2_bitrate) << 4);
+ }
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
+ struct v4l2_ext_controls *ctrls, unsigned int cmd)
+{
+ int err = 0;
+ int i;
+
+ if (cmd == VIDIOC_G_EXT_CTRLS) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = cx2341x_get_ctrl(params, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+ struct v4l2_queryctrl qctrl;
+ const char * const *menu_items = NULL;
+
+ qctrl.id = ctrl->id;
+ err = cx2341x_ctrl_query(params, &qctrl);
+ if (err)
+ break;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = cx2341x_ctrl_get_menu(params, qctrl.id);
+ err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+ if (err)
+ break;
+ err = cx2341x_set_ctrl(params, busy, ctrl);
+ if (err)
+ break;
+ }
+ if (err == 0 &&
+ params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ params->video_bitrate_peak < params->video_bitrate) {
+ err = -ERANGE;
+ ctrls->error_idx = ctrls->count;
+ }
+ if (err)
+ ctrls->error_idx = i;
+ else
+ cx2341x_calc_audio_properties(params);
+ return err;
+}
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+ *p = default_params;
+ cx2341x_calc_audio_properties(p);
+}
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func,
+ u32 cmd, int args, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i;
+
+ va_start(vargs, args);
+
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(vargs, int);
+ va_end(vargs);
+ return func(priv, cmd, args, 0, data);
+}
+
+#define NEQ(field) (old->field != new->field)
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ const struct cx2341x_mpeg_params *old,
+ const struct cx2341x_mpeg_params *new)
+{
+ static int mpeg_stream_type[] = {
+ 0, /* MPEG-2 PS */
+ 1, /* MPEG-2 TS */
+ 2, /* MPEG-1 SS */
+ 14, /* DVD */
+ 11, /* VCD */
+ 12, /* SVCD */
+ };
+
+ int err = 0;
+ int force = (old == NULL);
+ u16 temporal = new->video_temporal_filter;
+
+ cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+ if (force || NEQ(is_50hz)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
+ new->is_50hz);
+ if (err) return err;
+ }
+
+ if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
+ u16 w = new->width;
+ u16 h = new->height;
+
+ if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ w /= 2;
+ h /= 2;
+ }
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
+ h, w);
+ if (err) return err;
+ }
+ if (force || NEQ(stream_type)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
+ mpeg_stream_type[new->stream_type]);
+ if (err) return err;
+ }
+ if (force || NEQ(video_aspect)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
+ 1 + new->video_aspect);
+ if (err) return err;
+ }
+ if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ new->video_gop_size, new->video_b_frames + 1);
+ if (err) return err;
+ }
+ if (force || NEQ(video_gop_closure)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
+ new->video_gop_closure);
+ if (err) return err;
+ }
+ if (force || NEQ(audio_properties)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
+ 1, new->audio_properties);
+ if (err) return err;
+ }
+ if (force || NEQ(audio_mute)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
+ new->audio_mute);
+ if (err) return err;
+ }
+ if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
+ NEQ(video_bitrate_peak)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+ new->video_bitrate_mode, new->video_bitrate,
+ new->video_bitrate_peak / 400, 0, 0);
+ if (err) return err;
+ }
+ if (force || NEQ(video_spatial_filter_mode) ||
+ NEQ(video_temporal_filter_mode) ||
+ NEQ(video_median_filter_type)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
+ 2, new->video_spatial_filter_mode |
+ (new->video_temporal_filter_mode << 1),
+ new->video_median_filter_type);
+ if (err) return err;
+ }
+ if (force || NEQ(video_luma_median_filter_bottom) ||
+ NEQ(video_luma_median_filter_top) ||
+ NEQ(video_chroma_median_filter_bottom) ||
+ NEQ(video_chroma_median_filter_top)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ new->video_luma_median_filter_bottom,
+ new->video_luma_median_filter_top,
+ new->video_chroma_median_filter_bottom,
+ new->video_chroma_median_filter_top);
+ if (err) return err;
+ }
+ if (force || NEQ(video_luma_spatial_filter_type) ||
+ NEQ(video_chroma_spatial_filter_type)) {
+ err = cx2341x_api(priv, func,
+ CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
+ 2, new->video_luma_spatial_filter_type,
+ new->video_chroma_spatial_filter_type);
+ if (err) return err;
+ }
+ if (force || NEQ(video_spatial_filter) ||
+ old->video_temporal_filter != temporal) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
+ 2, new->video_spatial_filter, temporal);
+ if (err) return err;
+ }
+ if (force || NEQ(video_temporal_decimation)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
+ 1, new->video_temporal_decimation);
+ if (err) return err;
+ }
+ if (force || NEQ(video_mute) ||
+ (new->video_mute && NEQ(video_mute_yuv))) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
+ new->video_mute | (new->video_mute_yuv << 8));
+ if (err) return err;
+ }
+ if (force || NEQ(stream_insert_nav_packets)) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
+ 7, new->stream_insert_nav_packets);
+ if (err) return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cx2341x_update);
+
+static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
+{
+ const char * const *menu = cx2341x_ctrl_get_menu(p, id);
+ struct v4l2_ext_control ctrl;
+
+ if (menu == NULL)
+ goto invalid;
+ ctrl.id = id;
+ if (cx2341x_get_ctrl(p, &ctrl))
+ goto invalid;
+ while (ctrl.value-- && *menu) menu++;
+ if (*menu == NULL)
+ goto invalid;
+ return *menu;
+
+invalid:
+ return "<invalid>";
+}
+
+void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
+{
+ int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+ /* Stream */
+ printk(KERN_INFO "%s: Stream: %s",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+ if (p->stream_insert_nav_packets)
+ printk(" (with navigation packets)");
+ printk("\n");
+ printk(KERN_INFO "%s: VBI Format: %s\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
+
+ /* Video */
+ printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
+ prefix,
+ p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+ p->is_50hz ? 25 : 30,
+ (p->video_mute) ? " (muted)" : "");
+ printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+ p->video_bitrate);
+ if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+ printk(", Peak %d", p->video_bitrate_peak);
+ printk("\n");
+ printk(KERN_INFO
+ "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
+ prefix,
+ p->video_gop_size, p->video_b_frames,
+ p->video_gop_closure ? "" : "No ");
+ if (p->video_temporal_decimation)
+ printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
+ prefix, p->video_temporal_decimation);
+
+ /* Audio */
+ printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+ cx2341x_menu_item(p,
+ p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3
+ ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE
+ : V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
+ p->audio_mute ? " (muted)" : "");
+ if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ printk(", %s", cx2341x_menu_item(p,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+ printk(", %s, %s\n",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+ /* Encoding filters */
+ printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
+ prefix,
+ cx2341x_menu_item(p,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+ cx2341x_menu_item(p,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+ cx2341x_menu_item(p,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+ p->video_spatial_filter);
+
+ printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
+ prefix,
+ cx2341x_menu_item(p,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+ p->video_temporal_filter);
+ printk(KERN_INFO
+ "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
+ prefix,
+ cx2341x_menu_item(p,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+ p->video_luma_median_filter_bottom,
+ p->video_luma_median_filter_top,
+ p->video_chroma_median_filter_bottom,
+ p->video_chroma_median_filter_top);
+}
+EXPORT_SYMBOL(cx2341x_log_status);
+
+
+
+/********************** NEW CODE *********************/
+
+static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct cx2341x_handler, hdl);
+}
+
+static int cx2341x_hdl_api(struct cx2341x_handler *hdl,
+ u32 cmd, int args, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i;
+
+ va_start(vargs, args);
+
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(vargs, int);
+ va_end(vargs);
+ return hdl->func(hdl->priv, cmd, args, 0, data);
+}
+
+/* ctrl->handler->lock is held, so it is safe to access cur.val */
+static inline int cx2341x_neq(struct v4l2_ctrl *ctrl)
+{
+ return ctrl && ctrl->val != ctrl->cur.val;
+}
+
+static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct cx2341x_handler *hdl = to_cxhdl(ctrl);
+ s32 val = ctrl->val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+ /* video gop cluster */
+ int b = val + 1;
+ int gop = hdl->video_gop_size->val;
+
+ gop = b * ((gop + b - 1) / b);
+
+ /* Max GOP size = 34 */
+ while (gop > 34)
+ gop -= b;
+ hdl->video_gop_size->val = gop;
+ break;
+ }
+
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ /* stream type cluster */
+ hdl->video_encoding->val =
+ (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+ hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ /* MPEG-1 implies CBR */
+ hdl->video_bitrate_mode->val =
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ /* peak bitrate shall be >= normal bitrate */
+ if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ hdl->video_bitrate_peak->val < hdl->video_bitrate->val)
+ hdl->video_bitrate_peak->val = hdl->video_bitrate->val;
+ break;
+ }
+ return 0;
+}
+
+static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ static const int mpeg_stream_type[] = {
+ 0, /* MPEG-2 PS */
+ 1, /* MPEG-2 TS */
+ 2, /* MPEG-1 SS */
+ 14, /* DVD */
+ 11, /* VCD */
+ 12, /* SVCD */
+ };
+ struct cx2341x_handler *hdl = to_cxhdl(ctrl);
+ s32 val = ctrl->val;
+ u32 props;
+ int err;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ if (hdl->ops && hdl->ops->s_stream_vbi_fmt)
+ return hdl->ops->s_stream_vbi_fmt(hdl, val);
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1);
+
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val);
+
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val);
+
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val);
+
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val);
+
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ /* audio properties cluster */
+ props = (hdl->audio_sampling_freq->val << 0) |
+ (hdl->audio_mode->val << 8) |
+ (hdl->audio_mode_extension->val << 10) |
+ (hdl->audio_crc->val << 14);
+ if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+ props |= 3 << 12;
+ else
+ props |= hdl->audio_emphasis->val << 12;
+
+ if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+ props |=
+#if 1
+ /* Not sure if this MPEG Layer II setting is required */
+ ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
+#endif
+ (hdl->audio_ac3_bitrate->val << 4) |
+ (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
+ } else {
+ /* Assuming MPEG Layer II */
+ props |=
+ ((3 - hdl->audio_encoding->val) << 2) |
+ ((1 + hdl->audio_l2_bitrate->val) << 4);
+ }
+ err = cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props);
+ if (err)
+ return err;
+
+ hdl->audio_properties = props;
+ if (hdl->audio_ac3_bitrate) {
+ int is_ac3 = hdl->audio_encoding->val ==
+ V4L2_MPEG_AUDIO_ENCODING_AC3;
+
+ v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3);
+ v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3);
+ }
+ v4l2_ctrl_activate(hdl->audio_mode_extension,
+ hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO);
+ if (cx2341x_neq(hdl->audio_sampling_freq) &&
+ hdl->ops && hdl->ops->s_audio_sampling_freq)
+ return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val);
+ if (cx2341x_neq(hdl->audio_mode) &&
+ hdl->ops && hdl->ops->s_audio_mode)
+ return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val);
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ /* video gop cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ hdl->video_gop_size->val,
+ hdl->video_b_frames->val + 1);
+
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ /* stream type cluster */
+ err = cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]);
+ if (err)
+ return err;
+
+ err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5,
+ hdl->video_bitrate_mode->val,
+ hdl->video_bitrate->val,
+ hdl->video_bitrate_peak->val / 400, 0, 0);
+ if (err)
+ return err;
+
+ v4l2_ctrl_activate(hdl->video_bitrate_mode,
+ hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1);
+ v4l2_ctrl_activate(hdl->video_bitrate_peak,
+ hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+ if (cx2341x_neq(hdl->video_encoding) &&
+ hdl->ops && hdl->ops->s_video_encoding)
+ return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val);
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ /* video mute cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1,
+ hdl->video_mute->val |
+ (hdl->video_mute_yuv->val << 8));
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: {
+ int active_filter;
+
+ /* video filter mode */
+ err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+ hdl->video_spatial_filter_mode->val |
+ (hdl->video_temporal_filter_mode->val << 1),
+ hdl->video_median_filter_type->val);
+ if (err)
+ return err;
+
+ active_filter = hdl->video_spatial_filter_mode->val !=
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO;
+ v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter);
+ v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter);
+ v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter);
+ active_filter = hdl->video_temporal_filter_mode->val !=
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO;
+ v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter);
+ active_filter = hdl->video_median_filter_type->val !=
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF;
+ v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter);
+ v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter);
+ v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter);
+ v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter);
+ return 0;
+ }
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ /* video filter type cluster */
+ return cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+ hdl->video_luma_spatial_filter_type->val,
+ hdl->video_chroma_spatial_filter_type->val);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ /* video filter cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+ hdl->video_spatial_filter->val,
+ hdl->video_temporal_filter->val);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ /* video median cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ hdl->video_luma_median_filter_bottom->val,
+ hdl->video_luma_median_filter_top->val,
+ hdl->video_chroma_median_filter_bottom->val,
+ hdl->video_chroma_median_filter_top->val);
+ }
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops cx2341x_ops = {
+ .try_ctrl = cx2341x_try_ctrl,
+ .s_ctrl = cx2341x_s_ctrl,
+};
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ u32 id, s32 min, s32 max, s32 step, s32 def)
+{
+ struct v4l2_ctrl_config cfg;
+
+ cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags);
+ cfg.ops = &cx2341x_ops;
+ cfg.id = id;
+ cfg.min = min;
+ cfg.max = max;
+ cfg.def = def;
+ if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+ cfg.step = 0;
+ cfg.menu_skip_mask = step;
+ cfg.qmenu = cx2341x_get_menu(id);
+ } else {
+ cfg.step = step;
+ cfg.menu_skip_mask = 0;
+ }
+ return v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+}
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ u32 id, s32 min, s32 max, s32 step, s32 def)
+{
+ return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def);
+}
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl,
+ u32 id, s32 max, s32 mask, s32 def)
+{
+ return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def);
+}
+
+int cx2341x_handler_init(struct cx2341x_handler *cxhdl,
+ unsigned nr_of_controls_hint)
+{
+ struct v4l2_ctrl_handler *hdl = &cxhdl->hdl;
+ u32 caps = cxhdl->capabilities;
+ int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI;
+ int has_ac3 = caps & CX2341X_CAP_HAS_AC3;
+ int has_ts = caps & CX2341X_CAP_HAS_TS;
+
+ cxhdl->width = 720;
+ cxhdl->height = 480;
+
+ v4l2_ctrl_handler_init(hdl, nr_of_controls_hint);
+
+ /* Add controls in ascending control ID order for fastest
+ insertion time. */
+ cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_STREAM_VBI_FMT,
+ V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE);
+ cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+ cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+ cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_MODE,
+ V4L2_MPEG_AUDIO_MODE_MONO, 0,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+ cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+ cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 0,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+
+ cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0);
+ if (has_ac3)
+ cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_224K);
+ cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 0,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+ cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2);
+ cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 1, 34, 1, cxhdl->is_50hz ? 12 : 15);
+ cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1);
+ cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 0, 27000000, 1, 6000000);
+ cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 0, 27000000, 1, 8000000);
+ cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0);
+ cxhdl->video_mute = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0);
+ cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080);
+
+ /* CX23415/6 specific */
+ cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+ cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ 0, 15, 1, 0);
+ cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR);
+ cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR);
+ cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+ cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ 0, 31, 1, 8);
+ cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+ cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ 0, 255, 1, 0);
+ cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ 0, 255, 1, 255);
+ cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ 0, 255, 1, 0);
+ cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ 0, 255, 1, 255);
+ cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ return err;
+ }
+
+ v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq);
+ v4l2_ctrl_cluster(2, &cxhdl->video_b_frames);
+ v4l2_ctrl_cluster(5, &cxhdl->stream_type);
+ v4l2_ctrl_cluster(2, &cxhdl->video_mute);
+ v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode);
+ v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type);
+ v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter);
+ v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top);
+
+ return 0;
+}
+EXPORT_SYMBOL(cx2341x_handler_init);
+
+void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz)
+{
+ cxhdl->is_50hz = is_50hz;
+ cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15;
+}
+EXPORT_SYMBOL(cx2341x_handler_set_50hz);
+
+int cx2341x_handler_setup(struct cx2341x_handler *cxhdl)
+{
+ int h = cxhdl->height;
+ int w = cxhdl->width;
+ int err;
+
+ err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0);
+ if (err)
+ return err;
+ err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz);
+ if (err)
+ return err;
+
+ if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ w /= 2;
+ h /= 2;
+ }
+ err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+ if (err)
+ return err;
+ return v4l2_ctrl_handler_setup(&cxhdl->hdl);
+}
+EXPORT_SYMBOL(cx2341x_handler_setup);
+
+void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy)
+{
+ v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy);
+ v4l2_ctrl_grab(cxhdl->audio_encoding, busy);
+ v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy);
+ v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy);
+ v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy);
+ v4l2_ctrl_grab(cxhdl->stream_type, busy);
+ v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy);
+ v4l2_ctrl_grab(cxhdl->video_bitrate, busy);
+ v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy);
+}
+EXPORT_SYMBOL(cx2341x_handler_set_busy);
diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c
new file mode 100644
index 00000000000..577e82058fd
--- /dev/null
+++ b/drivers/media/common/cypress_firmware.c
@@ -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");
diff --git a/drivers/media/common/cypress_firmware.h b/drivers/media/common/cypress_firmware.h
new file mode 100644
index 00000000000..e493cbc7a52
--- /dev/null
+++ b/drivers/media/common/cypress_firmware.h
@@ -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
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
deleted file mode 100644
index bb2a027b948..00000000000
--- a/drivers/media/common/ir-functions.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- *
- * some common structs and functions to handle infrared remotes via
- * input layer ...
- *
- * (c) 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-#include <media/ir-common.h>
-
-/* -------------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static int repeat = 1;
-module_param(repeat, int, 0444);
-MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-
-static int debug = 0; /* debug level (0,1,2) */
-module_param(debug, int, 0644);
-
-#define dprintk(level, fmt, arg...) if (debug >= level) \
- printk(KERN_DEBUG fmt , ## arg)
-
-/* -------------------------------------------------------------------------- */
-
-static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (KEY_RESERVED == ir->keycode) {
- printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
- dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
- return;
- }
- dprintk(1,"%s: key event code=%d down=%d\n",
- dev->name,ir->keycode,ir->keypressed);
- input_report_key(dev,ir->keycode,ir->keypressed);
- input_sync(dev);
-}
-
-/* -------------------------------------------------------------------------- */
-
-void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
- int ir_type, IR_KEYTAB_TYPE *ir_codes)
-{
- int i;
-
- ir->ir_type = ir_type;
- if (ir_codes)
- memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
-
-
- dev->keycode = ir->ir_codes;
- dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
- dev->keycodemax = IR_KEYTAB_SIZE;
- for (i = 0; i < IR_KEYTAB_SIZE; i++)
- set_bit(ir->ir_codes[i], dev->keybit);
- clear_bit(0, dev->keybit);
-
- set_bit(EV_KEY, dev->evbit);
- if (repeat)
- set_bit(EV_REP, dev->evbit);
-}
-
-void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (ir->keypressed) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
-}
-
-void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
- u32 ir_key, u32 ir_raw)
-{
- u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
-
- if (ir->keypressed && ir->keycode != keycode) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
- if (!ir->keypressed) {
- ir->ir_key = ir_key;
- ir->ir_raw = ir_raw;
- ir->keycode = keycode;
- ir->keypressed = 1;
- ir_input_key_event(dev,ir);
- }
-}
-
-/* -------------------------------------------------------------------------- */
-/* extract mask bits out of data and pack them into the result */
-u32 ir_extract_bits(u32 data, u32 mask)
-{
- u32 vbit = 1, value = 0;
-
- do {
- if (mask&1) {
- if (data&1)
- value |= vbit;
- vbit<<=1;
- }
- data>>=1;
- } while (mask>>=1);
-
- return value;
-}
-
-static int inline getbit(u32 *samples, int bit)
-{
- return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
-}
-
-/* sump raw samples for visual debugging ;) */
-int ir_dump_samples(u32 *samples, int count)
-{
- int i, bit, start;
-
- printk(KERN_DEBUG "ir samples: ");
- start = 0;
- for (i = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- start = 1;
- if (0 == start)
- continue;
- printk("%s", bit ? "#" : "_");
- }
- printk("\n");
- return 0;
-}
-
-/* decode raw samples, pulse distance coding used by NEC remotes */
-int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len;
- u32 curBit;
- u32 value;
-
- /* find start burst */
- for (i = len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- len++;
- } else {
- if (len >= 29)
- break;
- len = 0;
- }
- }
-
- /* start burst to short */
- if (len < 29)
- return 0xffffffff;
-
- /* find start silence */
- for (len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- break;
- } else {
- len++;
- }
- }
-
- /* silence to short */
- if (len < 7)
- return 0xffffffff;
-
- /* go decoding */
- len = 0;
- last = 1;
- value = 0; curBit = 1;
- for (; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (last) {
- if(bit) {
- continue;
- } else {
- len = 1;
- }
- } else {
- if (bit) {
- if (len > (low + high) /2)
- value |= curBit;
- curBit <<= 1;
- if (curBit == 1)
- break;
- } else {
- len++;
- }
- }
- last = bit;
- }
-
- return value;
-}
-
-/* decode raw samples, biphase coding, used by rc5 for example */
-int ir_decode_biphase(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len,flips;
- u32 value;
-
- /* find start bit (1) */
- for (i = 0; i < 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- break;
- }
-
- /* go decoding */
- len = 0;
- flips = 0;
- value = 1;
- for (; i < count * 32; i++) {
- if (len > high)
- break;
- if (flips > 1)
- break;
- last = bit;
- bit = getbit(samples,i);
- if (last == bit) {
- len++;
- continue;
- }
- if (len < low) {
- len++;
- flips++;
- continue;
- }
- value <<= 1;
- value |= bit;
- flips = 0;
- len = 1;
- }
- return value;
-}
-
-/* RC5 decoding stuff, moved from bttv-input.c to share it with
- * saa7134 */
-
-/* decode raw bit pattern to RC5 code */
-static u32 ir_rc5_decode(unsigned int code)
-{
- unsigned int org_code = code;
- unsigned int pair;
- unsigned int rc5 = 0;
- int i;
-
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
- dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
- return 0;
- }
- }
- dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
- return rc5;
-}
-
-void ir_rc5_timer_end(unsigned long data)
-{
- struct card_ir *ir = (struct card_ir *)data;
- struct timeval tv;
- unsigned long current_jiffies, timeout;
- u32 gap;
- u32 rc5 = 0;
-
- /* get time */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* signal we're ready to start a new code */
- ir->active = 0;
-
- /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
- if (gap < 28000) {
- dprintk(1, "ir-common: spurious timer_end\n");
- return;
- }
-
- if (ir->last_bit < 20) {
- /* ignore spurious codes (caused by light/other remotes) */
- dprintk(1, "ir-common: short code: %x\n", ir->code);
- } else {
- ir->code = (ir->code << ir->shift_by) | 1;
- rc5 = ir_rc5_decode(ir->code);
-
- /* two start bits? */
- if (RC5_START(rc5) != ir->start) {
- dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
-
- /* right address? */
- } else if (RC5_ADDR(rc5) == ir->addr) {
- u32 toggle = RC5_TOGGLE(rc5);
- u32 instr = RC5_INSTR(rc5);
-
- /* Good code, decide if repeat/repress */
- if (toggle != RC5_TOGGLE(ir->last_rc5) ||
- instr != RC5_INSTR(ir->last_rc5)) {
- dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
- toggle);
- ir_input_nokey(ir->dev, &ir->ir);
- ir_input_keydown(ir->dev, &ir->ir, instr,
- instr);
- }
-
- /* Set/reset key-up timer */
- timeout = current_jiffies +
- msecs_to_jiffies(ir->rc5_key_timeout);
- mod_timer(&ir->timer_keyup, timeout);
-
- /* Save code for repeat test */
- ir->last_rc5 = rc5;
- }
- }
-}
-
-void ir_rc5_timer_keyup(unsigned long data)
-{
- struct card_ir *ir = (struct card_ir *)data;
-
- dprintk(1, "ir-common: key released\n");
- ir_input_nokey(ir->dev, &ir->ir);
-}
-
-EXPORT_SYMBOL_GPL(ir_input_init);
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
-EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
deleted file mode 100644
index 2ab5a120470..00000000000
--- a/drivers/media/common/ir-keymaps.c
+++ /dev/null
@@ -1,2035 +0,0 @@
-/*
-
-
- Keytables for supported remote controls. This file is part of
- video4linux.
-
- 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/input.h>
-#include <media/ir-common.h>
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
- [ 0x2a ] = KEY_COFFEE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_empty);
-
-/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
-IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE] = {
- /* numeric */
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x5c ] = KEY_POWER, /* power */
- [ 0x20 ] = KEY_F, /* full screen */
- [ 0x0f ] = KEY_BACKSPACE, /* recall */
- [ 0x1b ] = KEY_ENTER, /* mute */
- [ 0x41 ] = KEY_RECORD, /* record */
- [ 0x43 ] = KEY_STOP, /* stop */
- [ 0x16 ] = KEY_S,
- [ 0x1a ] = KEY_Q, /* off */
- [ 0x2e ] = KEY_RED,
- [ 0x1f ] = KEY_DOWN, /* channel - */
- [ 0x1c ] = KEY_UP, /* channel + */
- [ 0x10 ] = KEY_LEFT, /* volume - */
- [ 0x1e ] = KEY_RIGHT, /* volume + */
- [ 0x14 ] = KEY_F1,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_proteus_2309);
-/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
- [ 0x28 ] = KEY_0, //'0' / 'enter'
- [ 0x22 ] = KEY_1, //'1'
- [ 0x12 ] = KEY_2, //'2' / 'up arrow'
- [ 0x32 ] = KEY_3, //'3'
- [ 0x24 ] = KEY_4, //'4' / 'left arrow'
- [ 0x14 ] = KEY_5, //'5'
- [ 0x34 ] = KEY_6, //'6' / 'right arrow'
- [ 0x26 ] = KEY_7, //'7'
- [ 0x16 ] = KEY_8, //'8' / 'down arrow'
- [ 0x36 ] = KEY_9, //'9'
-
- [ 0x20 ] = KEY_LIST, // 'source'
- [ 0x10 ] = KEY_TEXT, // 'teletext'
- [ 0x00 ] = KEY_POWER, // 'power'
- [ 0x04 ] = KEY_AUDIO, // 'audio'
- [ 0x06 ] = KEY_ZOOM, // 'full screen'
- [ 0x18 ] = KEY_VIDEO, // 'display'
- [ 0x38 ] = KEY_SEARCH, // 'loop'
- [ 0x08 ] = KEY_INFO, // 'preview'
- [ 0x2a ] = KEY_REWIND, // 'backward <<'
- [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
- [ 0x3a ] = KEY_RECORD, // 'capture'
- [ 0x0a ] = KEY_MUTE, // 'mute'
- [ 0x2c ] = KEY_RECORD, // 'record'
- [ 0x1c ] = KEY_PAUSE, // 'pause'
- [ 0x3c ] = KEY_STOP, // 'stop'
- [ 0x0c ] = KEY_PLAY, // 'play'
- [ 0x2e ] = KEY_RED, // 'red'
- [ 0x01 ] = KEY_BLUE, // 'blue' / 'cancel'
- [ 0x0e ] = KEY_YELLOW, // 'yellow' / 'ok'
- [ 0x21 ] = KEY_GREEN, // 'green'
- [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
- [ 0x31 ] = KEY_CHANNELUP, // 'channel +'
- [ 0x1e ] = KEY_VOLUMEDOWN, // 'volume -'
- [ 0x3e ] = KEY_VOLUMEUP, // 'volume +'
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
-
-/* Attila Kondoros <attila.kondoros@chello.hu> */
-IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
-
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
- [ 0x00 ] = KEY_0,
- [ 0x17 ] = KEY_LAST, // +100
- [ 0x0a ] = KEY_LIST, // recall
-
-
- [ 0x1c ] = KEY_TUNER, // TV/FM
- [ 0x15 ] = KEY_SEARCH, // scan
- [ 0x12 ] = KEY_POWER, // power
- [ 0x1f ] = KEY_VOLUMEDOWN, // vol up
- [ 0x1b ] = KEY_VOLUMEUP, // vol down
- [ 0x1e ] = KEY_CHANNELDOWN, // chn up
- [ 0x1a ] = KEY_CHANNELUP, // chn down
-
- [ 0x11 ] = KEY_VIDEO, // video
- [ 0x0f ] = KEY_ZOOM, // full screen
- [ 0x13 ] = KEY_MUTE, // mute/unmute
- [ 0x10 ] = KEY_TEXT, // min
-
- [ 0x0d ] = KEY_STOP, // freeze
- [ 0x0e ] = KEY_RECORD, // record
- [ 0x1d ] = KEY_PLAYPAUSE, // stop
- [ 0x19 ] = KEY_PLAY, // play
-
- [ 0x16 ] = KEY_GOTO, // osd
- [ 0x14 ] = KEY_REFRESH, // default
- [ 0x0c ] = KEY_KPPLUS, // fine tune >>>>
- [ 0x18 ] = KEY_KPMINUS // fine tune <<<<
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp);
-
-/* ---------------------------------------------------------------------- */
-
-IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
-
- [ 0x1e ] = KEY_POWER, // power
- [ 0x07 ] = KEY_MEDIA, // source
- [ 0x1c ] = KEY_SEARCH, // scan
-
-/* FIXME: duplicate keycodes?
- *
- * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
- * The GPIO values are
- * 6397fb for both "Scan <" and "CH -",
- * 639ffb for "Scan >" and "CH+",
- * 6384fb for "Tune <" and "<<<",
- * 638cfb for "Tune >" and ">>>", regardless of the mask.
- *
- * [ 0x17 ] = KEY_BACK, // fm scan <<
- * [ 0x1f ] = KEY_FORWARD, // fm scan >>
- *
- * [ 0x04 ] = KEY_LEFT, // fm tuning <
- * [ 0x0c ] = KEY_RIGHT, // fm tuning >
- *
- * For now, these four keys are disabled. Pressing them will generate
- * the CH+/CH-/<<</>>> events
- */
-
- [ 0x03 ] = KEY_TUNER, // TV/FM
-
- [ 0x00 ] = KEY_RECORD,
- [ 0x08 ] = KEY_STOP,
- [ 0x11 ] = KEY_PLAY,
-
- [ 0x1a ] = KEY_PLAYPAUSE, // freeze
- [ 0x19 ] = KEY_ZOOM, // zoom
- [ 0x0f ] = KEY_TEXT, // min
-
- [ 0x01 ] = KEY_1,
- [ 0x0b ] = KEY_2,
- [ 0x1b ] = KEY_3,
- [ 0x05 ] = KEY_4,
- [ 0x09 ] = KEY_5,
- [ 0x15 ] = KEY_6,
- [ 0x06 ] = KEY_7,
- [ 0x0a ] = KEY_8,
- [ 0x12 ] = KEY_9,
- [ 0x02 ] = KEY_0,
- [ 0x10 ] = KEY_LAST, // +100
- [ 0x13 ] = KEY_LIST, // recall
-
- [ 0x1f ] = KEY_CHANNELUP, // chn down
- [ 0x17 ] = KEY_CHANNELDOWN, // chn up
- [ 0x16 ] = KEY_VOLUMEUP, // vol down
- [ 0x14 ] = KEY_VOLUMEDOWN, // vol up
-
- [ 0x04 ] = KEY_KPMINUS, // <<<
- [ 0x0e ] = KEY_SETUP, // function
- [ 0x0c ] = KEY_KPPLUS, // >>>
-
- [ 0x0d ] = KEY_GOTO, // mts
- [ 0x1d ] = KEY_REFRESH, // reset
- [ 0x18 ] = KEY_MUTE // mute/unmute
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pixelview);
-
-IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
- [ 0x0a ] = KEY_TV,
- [ 0x0b ] = KEY_AUX,
- [ 0x0c ] = KEY_DVD,
- [ 0x0d ] = KEY_POWER,
- [ 0x0e ] = KEY_MHP, /* labelled 'Picture' */
- [ 0x0f ] = KEY_AUDIO,
- [ 0x10 ] = KEY_INFO,
- [ 0x11 ] = KEY_F13, /* 16:9 */
- [ 0x12 ] = KEY_F14, /* 14:9 */
- [ 0x13 ] = KEY_EPG,
- [ 0x14 ] = KEY_EXIT,
- [ 0x15 ] = KEY_MENU,
- [ 0x16 ] = KEY_UP,
- [ 0x17 ] = KEY_DOWN,
- [ 0x18 ] = KEY_LEFT,
- [ 0x19 ] = KEY_RIGHT,
- [ 0x1a ] = KEY_ENTER,
- [ 0x1b ] = KEY_CHANNELUP,
- [ 0x1c ] = KEY_CHANNELDOWN,
- [ 0x1d ] = KEY_VOLUMEUP,
- [ 0x1e ] = KEY_VOLUMEDOWN,
- [ 0x1f ] = KEY_RED,
- [ 0x20 ] = KEY_GREEN,
- [ 0x21 ] = KEY_YELLOW,
- [ 0x22 ] = KEY_BLUE,
- [ 0x23 ] = KEY_SUBTITLE,
- [ 0x24 ] = KEY_F15, /* AD */
- [ 0x25 ] = KEY_TEXT,
- [ 0x26 ] = KEY_MUTE,
- [ 0x27 ] = KEY_REWIND,
- [ 0x28 ] = KEY_STOP,
- [ 0x29 ] = KEY_PLAY,
- [ 0x2a ] = KEY_FASTFORWARD,
- [ 0x2b ] = KEY_F16, /* chapter */
- [ 0x2c ] = KEY_PAUSE,
- [ 0x2d ] = KEY_PLAY,
- [ 0x2e ] = KEY_RECORD,
- [ 0x2f ] = KEY_F17, /* picture in picture */
- [ 0x30 ] = KEY_KPPLUS, /* zoom in */
- [ 0x31 ] = KEY_KPMINUS, /* zoom out */
- [ 0x32 ] = KEY_F18, /* capture */
- [ 0x33 ] = KEY_F19, /* web */
- [ 0x34 ] = KEY_EMAIL,
- [ 0x35 ] = KEY_PHONE,
- [ 0x36 ] = KEY_PC
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_nebula);
-
-/* DigitalNow DNTV Live DVB-T Remote */
-IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_ESC, /* 'go up a level?' */
- /* Keys 0 to 9 */
- [ 0x0a ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x0b ] = KEY_TUNER, /* tv/fm */
- [ 0x0c ] = KEY_SEARCH, /* scan */
- [ 0x0d ] = KEY_STOP,
- [ 0x0e ] = KEY_PAUSE,
- [ 0x0f ] = KEY_LIST, /* source */
-
- [ 0x10 ] = KEY_MUTE,
- [ 0x11 ] = KEY_REWIND, /* backward << */
- [ 0x12 ] = KEY_POWER,
- [ 0x13 ] = KEY_S, /* snap */
- [ 0x14 ] = KEY_AUDIO, /* stereo */
- [ 0x15 ] = KEY_CLEAR, /* reset */
- [ 0x16 ] = KEY_PLAY,
- [ 0x17 ] = KEY_ENTER,
- [ 0x18 ] = KEY_ZOOM, /* full screen */
- [ 0x19 ] = KEY_FASTFORWARD, /* forward >> */
- [ 0x1a ] = KEY_CHANNELUP,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x1c ] = KEY_INFO, /* preview */
- [ 0x1d ] = KEY_RECORD, /* record */
- [ 0x1e ] = KEY_CHANNELDOWN,
- [ 0x1f ] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t);
-
-/* ---------------------------------------------------------------------- */
-
-/* IO-DATA BCTV7E Remote */
-IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
- [ 0x40 ] = KEY_TV,
- [ 0x20 ] = KEY_RADIO, /* FM */
- [ 0x60 ] = KEY_EPG,
- [ 0x00 ] = KEY_POWER,
-
- /* Keys 0 to 9 */
- [ 0x44 ] = KEY_0, /* 10 */
- [ 0x50 ] = KEY_1,
- [ 0x30 ] = KEY_2,
- [ 0x70 ] = KEY_3,
- [ 0x48 ] = KEY_4,
- [ 0x28 ] = KEY_5,
- [ 0x68 ] = KEY_6,
- [ 0x58 ] = KEY_7,
- [ 0x38 ] = KEY_8,
- [ 0x78 ] = KEY_9,
-
- [ 0x10 ] = KEY_L, /* Live */
- [ 0x08 ] = KEY_T, /* Time Shift */
-
- [ 0x18 ] = KEY_PLAYPAUSE, /* Play */
-
- [ 0x24 ] = KEY_ENTER, /* 11 */
- [ 0x64 ] = KEY_ESC, /* 12 */
- [ 0x04 ] = KEY_M, /* Multi */
-
- [ 0x54 ] = KEY_VIDEO,
- [ 0x34 ] = KEY_CHANNELUP,
- [ 0x74 ] = KEY_VOLUMEUP,
- [ 0x14 ] = KEY_MUTE,
-
- [ 0x4c ] = KEY_S, /* SVIDEO */
- [ 0x2c ] = KEY_CHANNELDOWN,
- [ 0x6c ] = KEY_VOLUMEDOWN,
- [ 0x0c ] = KEY_ZOOM,
-
- [ 0x5c ] = KEY_PAUSE,
- [ 0x3c ] = KEY_C, /* || (red) */
- [ 0x7c ] = KEY_RECORD, /* recording */
- [ 0x1c ] = KEY_STOP,
-
- [ 0x41 ] = KEY_REWIND, /* backward << */
- [ 0x21 ] = KEY_PLAY,
- [ 0x61 ] = KEY_FASTFORWARD, /* forward >> */
- [ 0x01 ] = KEY_NEXT, /* skip >| */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e);
-
-/* ---------------------------------------------------------------------- */
-
-/* ADS Tech Instant TV DVB-T PCI Remote */
-IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x4d ] = KEY_0,
- [ 0x57 ] = KEY_1,
- [ 0x4f ] = KEY_2,
- [ 0x53 ] = KEY_3,
- [ 0x56 ] = KEY_4,
- [ 0x4e ] = KEY_5,
- [ 0x5e ] = KEY_6,
- [ 0x54 ] = KEY_7,
- [ 0x4c ] = KEY_8,
- [ 0x5c ] = KEY_9,
-
- [ 0x5b ] = KEY_POWER,
- [ 0x5f ] = KEY_MUTE,
- [ 0x55 ] = KEY_GOTO,
- [ 0x5d ] = KEY_SEARCH,
- [ 0x17 ] = KEY_EPG, /* Guide */
- [ 0x1f ] = KEY_MENU,
- [ 0x0f ] = KEY_UP,
- [ 0x46 ] = KEY_DOWN,
- [ 0x16 ] = KEY_LEFT,
- [ 0x1e ] = KEY_RIGHT,
- [ 0x0e ] = KEY_SELECT, /* Enter */
- [ 0x5a ] = KEY_INFO,
- [ 0x52 ] = KEY_EXIT,
- [ 0x59 ] = KEY_PREVIOUS,
- [ 0x51 ] = KEY_NEXT,
- [ 0x58 ] = KEY_REWIND,
- [ 0x50 ] = KEY_FORWARD,
- [ 0x44 ] = KEY_PLAYPAUSE,
- [ 0x07 ] = KEY_STOP,
- [ 0x1b ] = KEY_RECORD,
- [ 0x13 ] = KEY_TUNER, /* Live */
- [ 0x0a ] = KEY_A,
- [ 0x12 ] = KEY_B,
- [ 0x03 ] = KEY_PROG1, /* 1 */
- [ 0x01 ] = KEY_PROG2, /* 2 */
- [ 0x00 ] = KEY_PROG3, /* 3 */
- [ 0x06 ] = KEY_DVD,
- [ 0x48 ] = KEY_AUX, /* Photo */
- [ 0x40 ] = KEY_VIDEO,
- [ 0x19 ] = KEY_AUDIO, /* Music */
- [ 0x0b ] = KEY_CHANNELUP,
- [ 0x08 ] = KEY_CHANNELDOWN,
- [ 0x15 ] = KEY_VOLUMEUP,
- [ 0x1c ] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
-
-/* ---------------------------------------------------------------------- */
-
-/* MSI TV@nywhere remote */
-IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x0c ] = KEY_MUTE,
- [ 0x0f ] = KEY_SCREEN, /* Full Screen */
- [ 0x10 ] = KEY_F, /* Funtion */
- [ 0x11 ] = KEY_T, /* Time shift */
- [ 0x12 ] = KEY_POWER,
- [ 0x13 ] = KEY_MEDIA, /* MTS */
- [ 0x14 ] = KEY_SLOW,
- [ 0x16 ] = KEY_REWIND, /* backward << */
- [ 0x17 ] = KEY_ENTER, /* Return */
- [ 0x18 ] = KEY_FASTFORWARD, /* forward >> */
- [ 0x1a ] = KEY_CHANNELUP,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x1e ] = KEY_CHANNELDOWN,
- [ 0x1f ] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
-
-/* ---------------------------------------------------------------------- */
-
-/* Cinergy 1400 DVB-T */
-IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
- [ 0x01 ] = KEY_POWER,
- [ 0x02 ] = KEY_1,
- [ 0x03 ] = KEY_2,
- [ 0x04 ] = KEY_3,
- [ 0x05 ] = KEY_4,
- [ 0x06 ] = KEY_5,
- [ 0x07 ] = KEY_6,
- [ 0x08 ] = KEY_7,
- [ 0x09 ] = KEY_8,
- [ 0x0a ] = KEY_9,
- [ 0x0c ] = KEY_0,
-
- [ 0x0b ] = KEY_VIDEO,
- [ 0x0d ] = KEY_REFRESH,
- [ 0x0e ] = KEY_SELECT,
- [ 0x0f ] = KEY_EPG,
- [ 0x10 ] = KEY_UP,
- [ 0x11 ] = KEY_LEFT,
- [ 0x12 ] = KEY_OK,
- [ 0x13 ] = KEY_RIGHT,
- [ 0x14 ] = KEY_DOWN,
- [ 0x15 ] = KEY_TEXT,
- [ 0x16 ] = KEY_INFO,
-
- [ 0x17 ] = KEY_RED,
- [ 0x18 ] = KEY_GREEN,
- [ 0x19 ] = KEY_YELLOW,
- [ 0x1a ] = KEY_BLUE,
-
- [ 0x1b ] = KEY_CHANNELUP,
- [ 0x1c ] = KEY_VOLUMEUP,
- [ 0x1d ] = KEY_MUTE,
- [ 0x1e ] = KEY_VOLUMEDOWN,
- [ 0x1f ] = KEY_CHANNELDOWN,
-
- [ 0x40 ] = KEY_PAUSE,
- [ 0x4c ] = KEY_PLAY,
- [ 0x58 ] = KEY_RECORD,
- [ 0x54 ] = KEY_PREVIOUS,
- [ 0x48 ] = KEY_STOP,
- [ 0x5c ] = KEY_NEXT,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400);
-
-/* ---------------------------------------------------------------------- */
-
-/* AVERTV STUDIO 303 Remote */
-IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
- [ 0x2a ] = KEY_1,
- [ 0x32 ] = KEY_2,
- [ 0x3a ] = KEY_3,
- [ 0x4a ] = KEY_4,
- [ 0x52 ] = KEY_5,
- [ 0x5a ] = KEY_6,
- [ 0x6a ] = KEY_7,
- [ 0x72 ] = KEY_8,
- [ 0x7a ] = KEY_9,
- [ 0x0e ] = KEY_0,
-
- [ 0x02 ] = KEY_POWER,
- [ 0x22 ] = KEY_VIDEO,
- [ 0x42 ] = KEY_AUDIO,
- [ 0x62 ] = KEY_ZOOM,
- [ 0x0a ] = KEY_TV,
- [ 0x12 ] = KEY_CD,
- [ 0x1a ] = KEY_TEXT,
-
- [ 0x16 ] = KEY_SUBTITLE,
- [ 0x1e ] = KEY_REWIND,
- [ 0x06 ] = KEY_PRINT,
-
- [ 0x2e ] = KEY_SEARCH,
- [ 0x36 ] = KEY_SLEEP,
- [ 0x3e ] = KEY_SHUFFLE,
- [ 0x26 ] = KEY_MUTE,
-
- [ 0x4e ] = KEY_RECORD,
- [ 0x56 ] = KEY_PAUSE,
- [ 0x5e ] = KEY_STOP,
- [ 0x46 ] = KEY_PLAY,
-
- [ 0x6e ] = KEY_RED,
- [ 0x0b ] = KEY_GREEN,
- [ 0x66 ] = KEY_YELLOW,
- [ 0x03 ] = KEY_BLUE,
-
- [ 0x76 ] = KEY_LEFT,
- [ 0x7e ] = KEY_RIGHT,
- [ 0x13 ] = KEY_DOWN,
- [ 0x1b ] = KEY_UP,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_avertv_303);
-
-/* ---------------------------------------------------------------------- */
-
-/* DigitalNow DNTV Live! DVB-T Pro Remote */
-IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
- [ 0x16 ] = KEY_POWER,
- [ 0x5b ] = KEY_HOME,
-
- [ 0x55 ] = KEY_TV, /* live tv */
- [ 0x58 ] = KEY_TUNER, /* digital Radio */
- [ 0x5a ] = KEY_RADIO, /* FM radio */
- [ 0x59 ] = KEY_DVD, /* dvd menu */
- [ 0x03 ] = KEY_1,
- [ 0x01 ] = KEY_2,
- [ 0x06 ] = KEY_3,
- [ 0x09 ] = KEY_4,
- [ 0x1d ] = KEY_5,
- [ 0x1f ] = KEY_6,
- [ 0x0d ] = KEY_7,
- [ 0x19 ] = KEY_8,
- [ 0x1b ] = KEY_9,
- [ 0x0c ] = KEY_CANCEL,
- [ 0x15 ] = KEY_0,
- [ 0x4a ] = KEY_CLEAR,
- [ 0x13 ] = KEY_BACK,
- [ 0x00 ] = KEY_TAB,
- [ 0x4b ] = KEY_UP,
- [ 0x4e ] = KEY_LEFT,
- [ 0x4f ] = KEY_OK,
- [ 0x52 ] = KEY_RIGHT,
- [ 0x51 ] = KEY_DOWN,
- [ 0x1e ] = KEY_VOLUMEUP,
- [ 0x0a ] = KEY_VOLUMEDOWN,
- [ 0x02 ] = KEY_CHANNELDOWN,
- [ 0x05 ] = KEY_CHANNELUP,
- [ 0x11 ] = KEY_RECORD,
- [ 0x14 ] = KEY_PLAY,
- [ 0x4c ] = KEY_PAUSE,
- [ 0x1a ] = KEY_STOP,
- [ 0x40 ] = KEY_REWIND,
- [ 0x12 ] = KEY_FASTFORWARD,
- [ 0x41 ] = KEY_PREVIOUSSONG, /* replay |< */
- [ 0x42 ] = KEY_NEXTSONG, /* skip >| */
- [ 0x54 ] = KEY_CAMERA, /* capture */
- [ 0x50 ] = KEY_LANGUAGE, /* sap */
- [ 0x47 ] = KEY_TV2, /* pip */
- [ 0x4d ] = KEY_SCREEN,
- [ 0x43 ] = KEY_SUBTITLE,
- [ 0x10 ] = KEY_MUTE,
- [ 0x49 ] = KEY_AUDIO, /* l/r */
- [ 0x07 ] = KEY_SLEEP,
- [ 0x08 ] = KEY_VIDEO, /* a/v */
- [ 0x0e ] = KEY_PREVIOUS, /* recall */
- [ 0x45 ] = KEY_ZOOM, /* zoom + */
- [ 0x46 ] = KEY_ANGLE, /* zoom - */
- [ 0x56 ] = KEY_RED,
- [ 0x57 ] = KEY_GREEN,
- [ 0x5c ] = KEY_YELLOW,
- [ 0x5d ] = KEY_BLUE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro);
-
-IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
- [ 0x01 ] = KEY_CHANNEL,
- [ 0x02 ] = KEY_SELECT,
- [ 0x03 ] = KEY_MUTE,
- [ 0x04 ] = KEY_POWER,
- [ 0x05 ] = KEY_1,
- [ 0x06 ] = KEY_2,
- [ 0x07 ] = KEY_3,
- [ 0x08 ] = KEY_CHANNELUP,
- [ 0x09 ] = KEY_4,
- [ 0x0a ] = KEY_5,
- [ 0x0b ] = KEY_6,
- [ 0x0c ] = KEY_CHANNELDOWN,
- [ 0x0d ] = KEY_7,
- [ 0x0e ] = KEY_8,
- [ 0x0f ] = KEY_9,
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_0,
- [ 0x12 ] = KEY_MENU,
- [ 0x13 ] = KEY_PRINT,
- [ 0x14 ] = KEY_VOLUMEDOWN,
- [ 0x16 ] = KEY_PAUSE,
- [ 0x18 ] = KEY_RECORD,
- [ 0x19 ] = KEY_REWIND,
- [ 0x1a ] = KEY_PLAY,
- [ 0x1b ] = KEY_FORWARD,
- [ 0x1c ] = KEY_BACKSPACE,
- [ 0x1e ] = KEY_STOP,
- [ 0x40 ] = KEY_ZOOM,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
- [ 0x3a ] = KEY_0,
- [ 0x31 ] = KEY_1,
- [ 0x32 ] = KEY_2,
- [ 0x33 ] = KEY_3,
- [ 0x34 ] = KEY_4,
- [ 0x35 ] = KEY_5,
- [ 0x36 ] = KEY_6,
- [ 0x37 ] = KEY_7,
- [ 0x38 ] = KEY_8,
- [ 0x39 ] = KEY_9,
-
- [ 0x2f ] = KEY_POWER,
-
- [ 0x2e ] = KEY_P,
- [ 0x1f ] = KEY_L,
- [ 0x2b ] = KEY_I,
-
- [ 0x2d ] = KEY_SCREEN,
- [ 0x1e ] = KEY_ZOOM,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x0f ] = KEY_VOLUMEDOWN,
- [ 0x17 ] = KEY_CHANNELUP,
- [ 0x1c ] = KEY_CHANNELDOWN,
- [ 0x25 ] = KEY_INFO,
-
- [ 0x3c ] = KEY_MUTE,
-
- [ 0x3d ] = KEY_LEFT,
- [ 0x3b ] = KEY_RIGHT,
-
- [ 0x3f ] = KEY_UP,
- [ 0x3e ] = KEY_DOWN,
- [ 0x1a ] = KEY_ENTER,
-
- [ 0x1d ] = KEY_MENU,
- [ 0x19 ] = KEY_AGAIN,
- [ 0x16 ] = KEY_PREVIOUSSONG,
- [ 0x13 ] = KEY_NEXTSONG,
- [ 0x15 ] = KEY_PAUSE,
- [ 0x0e ] = KEY_REWIND,
- [ 0x0d ] = KEY_PLAY,
- [ 0x0b ] = KEY_STOP,
- [ 0x07 ] = KEY_FORWARD,
- [ 0x27 ] = KEY_RECORD,
- [ 0x26 ] = KEY_TUNER,
- [ 0x29 ] = KEY_TEXT,
- [ 0x2a ] = KEY_MEDIA,
- [ 0x18 ] = KEY_EPG,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
-
-IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
- [ 0x0f ] = KEY_0,
- [ 0x03 ] = KEY_1,
- [ 0x04 ] = KEY_2,
- [ 0x05 ] = KEY_3,
- [ 0x07 ] = KEY_4,
- [ 0x08 ] = KEY_5,
- [ 0x09 ] = KEY_6,
- [ 0x0b ] = KEY_7,
- [ 0x0c ] = KEY_8,
- [ 0x0d ] = KEY_9,
-
- [ 0x0e ] = KEY_MODE, // Air/Cable
- [ 0x11 ] = KEY_VIDEO, // Video
- [ 0x15 ] = KEY_AUDIO, // Audio
- [ 0x00 ] = KEY_POWER, // Power
- [ 0x18 ] = KEY_TUNER, // AV Source
- [ 0x02 ] = KEY_ZOOM, // Fullscreen
- [ 0x1a ] = KEY_LANGUAGE, // Stereo
- [ 0x1b ] = KEY_MUTE, // Mute
- [ 0x14 ] = KEY_VOLUMEUP, // Volume +
- [ 0x17 ] = KEY_VOLUMEDOWN, // Volume -
- [ 0x12 ] = KEY_CHANNELUP, // Channel +
- [ 0x13 ] = KEY_CHANNELDOWN, // Channel -
- [ 0x06 ] = KEY_AGAIN, // Recall
- [ 0x10 ] = KEY_ENTER, // Enter
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
-
-IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE] = {
- [ 0x01 ] = KEY_ZOOM, // Full Screen
- [ 0x00 ] = KEY_POWER, // Power
-
- [ 0x03 ] = KEY_1,
- [ 0x04 ] = KEY_2,
- [ 0x05 ] = KEY_3,
- [ 0x07 ] = KEY_4,
- [ 0x08 ] = KEY_5,
- [ 0x09 ] = KEY_6,
- [ 0x0b ] = KEY_7,
- [ 0x0c ] = KEY_8,
- [ 0x0d ] = KEY_9,
- [ 0x06 ] = KEY_AGAIN, // Recall
- [ 0x0f ] = KEY_0,
- [ 0x10 ] = KEY_MUTE, // Mute
- [ 0x02 ] = KEY_RADIO, // TV/Radio
- [ 0x1b ] = KEY_LANGUAGE, // SAP (Second Audio Program)
-
- [ 0x14 ] = KEY_VOLUMEUP, // VOL+
- [ 0x17 ] = KEY_VOLUMEDOWN, // VOL-
- [ 0x12 ] = KEY_CHANNELUP, // CH+
- [ 0x13 ] = KEY_CHANNELDOWN, // CH-
- [ 0x1d ] = KEY_ENTER, // Enter
-
- [ 0x1a ] = KEY_MODE, // PIP
- [ 0x18 ] = KEY_TUNER, // Source
-
- [ 0x1e ] = KEY_RECORD, // Record/Pause
- [ 0x15 ] = KEY_ANGLE, // Swap (no label on key)
- [ 0x1c ] = KEY_PAUSE, // Timeshift/Pause
- [ 0x19 ] = KEY_BACK, // Rewind <<
- [ 0x0a ] = KEY_PLAYPAUSE, // Play/Pause
- [ 0x1f ] = KEY_FORWARD, // Forward >>
- [ 0x16 ] = KEY_PREVIOUS, // Back |<<
- [ 0x11 ] = KEY_STOP, // Stop
- [ 0x0e ] = KEY_NEXT, // End >>|
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_flydvb);
-
-IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x0a ] = KEY_POWER,
- [ 0x0b ] = KEY_PROG1, // app
- [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen
- [ 0x0d ] = KEY_CHANNELUP, // channel
- [ 0x0e ] = KEY_CHANNELDOWN, // channel-
- [ 0x0f ] = KEY_VOLUMEUP,
- [ 0x10 ] = KEY_VOLUMEDOWN,
- [ 0x11 ] = KEY_TUNER, // AV
- [ 0x12 ] = KEY_NUMLOCK, // -/--
- [ 0x13 ] = KEY_AUDIO, // audio
- [ 0x14 ] = KEY_MUTE,
- [ 0x15 ] = KEY_UP,
- [ 0x16 ] = KEY_DOWN,
- [ 0x17 ] = KEY_LEFT,
- [ 0x18 ] = KEY_RIGHT,
- [ 0x19 ] = BTN_LEFT,
- [ 0x1a ] = BTN_RIGHT,
- [ 0x1b ] = KEY_WWW, // text
- [ 0x1c ] = KEY_REWIND,
- [ 0x1d ] = KEY_FORWARD,
- [ 0x1e ] = KEY_RECORD,
- [ 0x1f ] = KEY_PLAY,
- [ 0x20 ] = KEY_PREVIOUSSONG,
- [ 0x21 ] = KEY_NEXTSONG,
- [ 0x22 ] = KEY_PAUSE,
- [ 0x23 ] = KEY_STOP,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_cinergy);
-
-/* Alfons Geser <a.geser@cox.net>
- * updates from Job D. R. Borges <jobdrb@ig.com.br> */
-IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE] = {
- [ 0x12 ] = KEY_POWER,
- [ 0x01 ] = KEY_TV, // DVR
- [ 0x15 ] = KEY_DVD, // DVD
- [ 0x17 ] = KEY_AUDIO, // music
- // DVR mode / DVD mode / music mode
-
- [ 0x1b ] = KEY_MUTE, // mute
- [ 0x02 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
- [ 0x1e ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
- [ 0x16 ] = KEY_ZOOM, // full screen
- [ 0x1c ] = KEY_VIDEO, // video source / eject / delall
- [ 0x1d ] = KEY_RESTART, // playback / angle / del
- [ 0x2f ] = KEY_SEARCH, // scan / menu / playlist
- [ 0x30 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
-
- [ 0x31 ] = KEY_HELP, // help
- [ 0x32 ] = KEY_MODE, // num/memo
- [ 0x33 ] = KEY_ESC, // cancel
-
- [ 0x0c ] = KEY_UP, // up
- [ 0x10 ] = KEY_DOWN, // down
- [ 0x08 ] = KEY_LEFT, // left
- [ 0x04 ] = KEY_RIGHT, // right
- [ 0x03 ] = KEY_SELECT, // select
-
- [ 0x1f ] = KEY_REWIND, // rewind
- [ 0x20 ] = KEY_PLAYPAUSE, // play/pause
- [ 0x29 ] = KEY_FORWARD, // forward
- [ 0x14 ] = KEY_AGAIN, // repeat
- [ 0x2b ] = KEY_RECORD, // recording
- [ 0x2c ] = KEY_STOP, // stop
- [ 0x2d ] = KEY_PLAY, // play
- [ 0x2e ] = KEY_SHUFFLE, // snapshot / shuffle
-
- [ 0x00 ] = KEY_0,
- [ 0x05 ] = KEY_1,
- [ 0x06 ] = KEY_2,
- [ 0x07 ] = KEY_3,
- [ 0x09 ] = KEY_4,
- [ 0x0a ] = KEY_5,
- [ 0x0b ] = KEY_6,
- [ 0x0d ] = KEY_7,
- [ 0x0e ] = KEY_8,
- [ 0x0f ] = KEY_9,
-
- [ 0x2a ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_VOLUMEDOWN,
- [ 0x18 ] = KEY_CHANNELUP, // CH.tracking up
- [ 0x19 ] = KEY_CHANNELDOWN, // CH.tracking down
-
- [ 0x13 ] = KEY_ENTER, // enter
- [ 0x21 ] = KEY_DOT, // . (decimal dot)
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_eztv);
-
-/* Alex Hermann <gaaf@gmx.net> */
-IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
- [ 0x28 ] = KEY_1,
- [ 0x18 ] = KEY_2,
- [ 0x38 ] = KEY_3,
- [ 0x24 ] = KEY_4,
- [ 0x14 ] = KEY_5,
- [ 0x34 ] = KEY_6,
- [ 0x2c ] = KEY_7,
- [ 0x1c ] = KEY_8,
- [ 0x3c ] = KEY_9,
- [ 0x22 ] = KEY_0,
-
- [ 0x20 ] = KEY_TV, /* TV/FM */
- [ 0x10 ] = KEY_CD, /* CD */
- [ 0x30 ] = KEY_TEXT, /* TELETEXT */
- [ 0x00 ] = KEY_POWER, /* POWER */
-
- [ 0x08 ] = KEY_VIDEO, /* VIDEO */
- [ 0x04 ] = KEY_AUDIO, /* AUDIO */
- [ 0x0c ] = KEY_ZOOM, /* FULL SCREEN */
-
- [ 0x12 ] = KEY_SUBTITLE, /* DISPLAY */
- [ 0x32 ] = KEY_REWIND, /* LOOP */
- [ 0x02 ] = KEY_PRINT, /* PREVIEW */
-
- [ 0x2a ] = KEY_SEARCH, /* AUTOSCAN */
- [ 0x1a ] = KEY_SLEEP, /* FREEZE */
- [ 0x3a ] = KEY_SHUFFLE, /* SNAPSHOT */
- [ 0x0a ] = KEY_MUTE, /* MUTE */
-
- [ 0x26 ] = KEY_RECORD, /* RECORD */
- [ 0x16 ] = KEY_PAUSE, /* PAUSE */
- [ 0x36 ] = KEY_STOP, /* STOP */
- [ 0x06 ] = KEY_PLAY, /* PLAY */
-
- [ 0x2e ] = KEY_RED, /* RED */
- [ 0x21 ] = KEY_GREEN, /* GREEN */
- [ 0x0e ] = KEY_YELLOW, /* YELLOW */
- [ 0x01 ] = KEY_BLUE, /* BLUE */
-
- [ 0x1e ] = KEY_VOLUMEDOWN, /* VOLUME- */
- [ 0x3e ] = KEY_VOLUMEUP, /* VOLUME+ */
- [ 0x11 ] = KEY_CHANNELDOWN, /* CHANNEL/PAGE- */
- [ 0x31 ] = KEY_CHANNELUP /* CHANNEL/PAGE+ */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_avermedia);
-
-IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE] = {
- [ 0x14 ] = KEY_MUTE,
- [ 0x24 ] = KEY_ZOOM,
-
- [ 0x01 ] = KEY_DVD,
- [ 0x23 ] = KEY_RADIO,
- [ 0x00 ] = KEY_TV,
-
- [ 0x0a ] = KEY_REWIND,
- [ 0x08 ] = KEY_PLAYPAUSE,
- [ 0x0f ] = KEY_FORWARD,
-
- [ 0x02 ] = KEY_PREVIOUS,
- [ 0x07 ] = KEY_STOP,
- [ 0x06 ] = KEY_NEXT,
-
- [ 0x0c ] = KEY_UP,
- [ 0x0e ] = KEY_DOWN,
- [ 0x0b ] = KEY_LEFT,
- [ 0x0d ] = KEY_RIGHT,
- [ 0x11 ] = KEY_OK,
-
- [ 0x03 ] = KEY_MENU,
- [ 0x09 ] = KEY_SETUP,
- [ 0x05 ] = KEY_VIDEO,
- [ 0x22 ] = KEY_CHANNEL,
-
- [ 0x12 ] = KEY_VOLUMEUP,
- [ 0x15 ] = KEY_VOLUMEDOWN,
- [ 0x10 ] = KEY_CHANNELUP,
- [ 0x13 ] = KEY_CHANNELDOWN,
-
- [ 0x04 ] = KEY_RECORD,
-
- [ 0x16 ] = KEY_1,
- [ 0x17 ] = KEY_2,
- [ 0x18 ] = KEY_3,
- [ 0x19 ] = KEY_4,
- [ 0x1a ] = KEY_5,
- [ 0x1b ] = KEY_6,
- [ 0x1c ] = KEY_7,
- [ 0x1d ] = KEY_8,
- [ 0x1e ] = KEY_9,
- [ 0x1f ] = KEY_0,
-
- [ 0x20 ] = KEY_LANGUAGE,
- [ 0x21 ] = KEY_SLEEP,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr);
-
-/* Michael Tokarev <mjt@tls.msk.ru>
- http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
- keytable is used by MANLI MTV00[ 0x0c ] and BeholdTV 40[13] at
- least, and probably other cards too.
- The "ascii-art picture" below (in comments, first row
- is the keycode in hex, and subsequent row(s) shows
- the button labels (several variants when appropriate)
- helps to descide which keycodes to assign to the buttons.
- */
-IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
-
- /* 0x1c 0x12 *
- * FUNCTION POWER *
- * FM (|) *
- * */
- [ 0x1c ] = KEY_RADIO, /*XXX*/
- [ 0x12 ] = KEY_POWER,
-
- /* 0x01 0x02 0x03 *
- * 1 2 3 *
- * *
- * 0x04 0x05 0x06 *
- * 4 5 6 *
- * *
- * 0x07 0x08 0x09 *
- * 7 8 9 *
- * */
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- /* 0x0a 0x00 0x17 *
- * RECALL 0 +100 *
- * PLUS *
- * */
- [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */
- [ 0x00 ] = KEY_0,
- [ 0x17 ] = KEY_DIGITS, /*XXX*/
-
- /* 0x14 0x10 *
- * MENU INFO *
- * OSD */
- [ 0x14 ] = KEY_MENU,
- [ 0x10 ] = KEY_INFO,
-
- /* 0x0b *
- * Up *
- * *
- * 0x18 0x16 0x0c *
- * Left Ok Right *
- * *
- * 0x015 *
- * Down *
- * */
- [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */
- [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */
- [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */
- [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */
- [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */
-
- /* 0x11 0x0d *
- * TV/AV MODE *
- * SOURCE STEREO *
- * */
- [ 0x11 ] = KEY_TV, /*XXX*/
- [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */
-
- /* 0x0f 0x1b 0x1a *
- * AUDIO Vol+ Chan+ *
- * TIMESHIFT??? *
- * *
- * 0x0e 0x1f 0x1e *
- * SLEEP Vol- Chan- *
- * */
- [ 0x0f ] = KEY_AUDIO,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x1a ] = KEY_CHANNELUP,
- [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */
- [ 0x1f ] = KEY_VOLUMEDOWN,
- [ 0x1e ] = KEY_CHANNELDOWN,
-
- /* 0x13 0x19 *
- * MUTE SNAPSHOT*
- * */
- [ 0x13 ] = KEY_MUTE,
- [ 0x19 ] = KEY_RECORD, /*XXX*/
-
- // 0x1d unused ?
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_manli);
-
-/* Mike Baikov <mike@baikov.com> */
-IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
-
- [ 0x11 ] = KEY_POWER,
- [ 0x35 ] = KEY_TV,
- [ 0x1b ] = KEY_0,
- [ 0x29 ] = KEY_1,
- [ 0x19 ] = KEY_2,
- [ 0x39 ] = KEY_3,
- [ 0x1f ] = KEY_4,
- [ 0x2c ] = KEY_5,
- [ 0x21 ] = KEY_6,
- [ 0x24 ] = KEY_7,
- [ 0x18 ] = KEY_8,
- [ 0x2b ] = KEY_9,
- [ 0x3b ] = KEY_AGAIN, /* LOOP */
- [ 0x06 ] = KEY_AUDIO,
- [ 0x31 ] = KEY_PRINT, /* PREVIEW */
- [ 0x3e ] = KEY_VIDEO,
- [ 0x10 ] = KEY_CHANNELUP,
- [ 0x20 ] = KEY_CHANNELDOWN,
- [ 0x0c ] = KEY_VOLUMEDOWN,
- [ 0x28 ] = KEY_VOLUMEUP,
- [ 0x08 ] = KEY_MUTE,
- [ 0x26 ] = KEY_SEARCH, /*SCAN*/
- [ 0x3f ] = KEY_SHUFFLE, /* SNAPSHOT */
- [ 0x12 ] = KEY_RECORD,
- [ 0x32 ] = KEY_STOP,
- [ 0x3c ] = KEY_PLAY,
- [ 0x1d ] = KEY_REWIND,
- [ 0x2d ] = KEY_PAUSE,
- [ 0x0d ] = KEY_FORWARD,
- [ 0x05 ] = KEY_ZOOM, /*FULL*/
-
- [ 0x2a ] = KEY_F21, /* LIVE TIMESHIFT */
- [ 0x0e ] = KEY_F22, /* MIN TIMESHIFT */
- [ 0x1e ] = KEY_F23, /* TIMESHIFT */
- [ 0x38 ] = KEY_F24, /* NORMAL TIMESHIFT */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
-
-IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
- [ 0x03 ] = KEY_POWER,
- [ 0x6f ] = KEY_MUTE,
- [ 0x10 ] = KEY_BACKSPACE, /* Recall */
-
- [ 0x11 ] = KEY_0,
- [ 0x04 ] = KEY_1,
- [ 0x05 ] = KEY_2,
- [ 0x06 ] = KEY_3,
- [ 0x08 ] = KEY_4,
- [ 0x09 ] = KEY_5,
- [ 0x0a ] = KEY_6,
- [ 0x0c ] = KEY_7,
- [ 0x0d ] = KEY_8,
- [ 0x0e ] = KEY_9,
- [ 0x12 ] = KEY_DOT, /* 100+ */
-
- [ 0x07 ] = KEY_VOLUMEUP,
- [ 0x0b ] = KEY_VOLUMEDOWN,
- [ 0x1a ] = KEY_KPPLUS,
- [ 0x18 ] = KEY_KPMINUS,
- [ 0x15 ] = KEY_UP,
- [ 0x1d ] = KEY_DOWN,
- [ 0x0f ] = KEY_CHANNELUP,
- [ 0x13 ] = KEY_CHANNELDOWN,
- [ 0x48 ] = KEY_ZOOM,
-
- [ 0x1b ] = KEY_VIDEO, /* Video source */
- [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
- [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
-
- [ 0x4b ] = KEY_RECORD,
- [ 0x46 ] = KEY_PLAY,
- [ 0x45 ] = KEY_PAUSE, /* Pause */
- [ 0x44 ] = KEY_STOP,
- [ 0x40 ] = KEY_FORWARD, /* Forward ? */
- [ 0x42 ] = KEY_REWIND, /* Backward ? */
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_purpletv);
-
-/* Mapping for the 28 key remote control as seen at
- http://www.sednacomputer.com/photo/cardbus-tv.jpg
- Pavel Mihaylov <bin@bash.info> */
-IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x0a ] = KEY_AGAIN, /* Recall */
- [ 0x0b ] = KEY_CHANNELUP,
- [ 0x0c ] = KEY_VOLUMEUP,
- [ 0x0d ] = KEY_MODE, /* Stereo */
- [ 0x0e ] = KEY_STOP,
- [ 0x0f ] = KEY_PREVIOUSSONG,
- [ 0x10 ] = KEY_ZOOM,
- [ 0x11 ] = KEY_TUNER, /* Source */
- [ 0x12 ] = KEY_POWER,
- [ 0x13 ] = KEY_MUTE,
- [ 0x15 ] = KEY_CHANNELDOWN,
- [ 0x18 ] = KEY_VOLUMEDOWN,
- [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */
- [ 0x1a ] = KEY_NEXTSONG,
- [ 0x1b ] = KEY_TEXT, /* Time Shift */
- [ 0x1c ] = KEY_RADIO, /* FM Radio */
- [ 0x1d ] = KEY_RECORD,
- [ 0x1e ] = KEY_PAUSE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
-
-/* Mark Phalan <phalanm@o2.ie> */
-IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x12 ] = KEY_POWER,
- [ 0x10 ] = KEY_MUTE,
- [ 0x1f ] = KEY_VOLUMEDOWN,
- [ 0x1b ] = KEY_VOLUMEUP,
- [ 0x1a ] = KEY_CHANNELUP,
- [ 0x1e ] = KEY_CHANNELDOWN,
- [ 0x0e ] = KEY_PAGEUP,
- [ 0x1d ] = KEY_PAGEDOWN,
- [ 0x13 ] = KEY_SOUND,
-
- [ 0x18 ] = KEY_KPPLUSMINUS, /* CH +/- */
- [ 0x16 ] = KEY_SUBTITLE, /* CC */
- [ 0x0d ] = KEY_TEXT, /* TTX */
- [ 0x0b ] = KEY_TV, /* AIR/CBL */
- [ 0x11 ] = KEY_PC, /* PC/TV */
- [ 0x17 ] = KEY_OK, /* CH RTN */
- [ 0x19 ] = KEY_MODE, /* FUNC */
- [ 0x0c ] = KEY_SEARCH, /* AUTOSCAN */
-
- /* Not sure what to do with these ones! */
- [ 0x0f ] = KEY_SELECT, /* SOURCE */
- [ 0x0a ] = KEY_KPPLUS, /* +100 */
- [ 0x14 ] = KEY_EQUAL, /* SYNC */
- [ 0x1c ] = KEY_MEDIA, /* PC/TV */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pv951);
-
-/* generic RC5 keytable */
-/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
-/* used by old (black) Hauppauge remotes */
-IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */
- [ 0x0c ] = KEY_POWER, /* standby */
- [ 0x0d ] = KEY_MUTE, /* mute / demute */
- [ 0x0f ] = KEY_TV, /* display */
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_VOLUMEDOWN,
- [ 0x12 ] = KEY_BRIGHTNESSUP,
- [ 0x13 ] = KEY_BRIGHTNESSDOWN,
- [ 0x1e ] = KEY_SEARCH, /* search + */
- [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
- [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
- [ 0x22 ] = KEY_CHANNEL, /* alt / channel */
- [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */
- [ 0x26 ] = KEY_SLEEP, /* sleeptimer */
- [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */
- [ 0x30 ] = KEY_PAUSE,
- [ 0x32 ] = KEY_REWIND,
- [ 0x33 ] = KEY_GOTO,
- [ 0x35 ] = KEY_PLAY,
- [ 0x36 ] = KEY_STOP,
- [ 0x37 ] = KEY_RECORD, /* recording */
- [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */
- [ 0x3d ] = KEY_SUSPEND, /* system standby */
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
-
-/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x12 ] = KEY_0,
- [ 0x05 ] = KEY_1,
- [ 0x06 ] = KEY_2,
- [ 0x07 ] = KEY_3,
- [ 0x09 ] = KEY_4,
- [ 0x0a ] = KEY_5,
- [ 0x0b ] = KEY_6,
- [ 0x0d ] = KEY_7,
- [ 0x0e ] = KEY_8,
- [ 0x0f ] = KEY_9,
-
- [ 0x00 ] = KEY_POWER,
- [ 0x1b ] = KEY_AUDIO, /* Audio Source */
- [ 0x02 ] = KEY_TUNER, /* TV/FM, not on Y0400052 */
- [ 0x1e ] = KEY_VIDEO, /* Video Source */
- [ 0x16 ] = KEY_INFO, /* Display information */
- [ 0x04 ] = KEY_VOLUMEUP,
- [ 0x08 ] = KEY_VOLUMEDOWN,
- [ 0x0c ] = KEY_CHANNELUP,
- [ 0x10 ] = KEY_CHANNELDOWN,
- [ 0x03 ] = KEY_ZOOM, /* fullscreen */
- [ 0x1f ] = KEY_TEXT, /* closed caption/teletext */
- [ 0x20 ] = KEY_SLEEP,
- [ 0x29 ] = KEY_CLEAR, /* boss key */
- [ 0x14 ] = KEY_MUTE,
- [ 0x2b ] = KEY_RED,
- [ 0x2c ] = KEY_GREEN,
- [ 0x2d ] = KEY_YELLOW,
- [ 0x2e ] = KEY_BLUE,
- [ 0x18 ] = KEY_KPPLUS, /* fine tune + , not on Y040052 */
- [ 0x19 ] = KEY_KPMINUS, /* fine tune - , not on Y040052 */
- [ 0x2a ] = KEY_MEDIA, /* PIP (Picture in picture */
- [ 0x21 ] = KEY_DOT,
- [ 0x13 ] = KEY_ENTER,
- [ 0x11 ] = KEY_LAST, /* Recall (last channel */
- [ 0x22 ] = KEY_PREVIOUS,
- [ 0x23 ] = KEY_PLAYPAUSE,
- [ 0x24 ] = KEY_NEXT,
- [ 0x25 ] = KEY_ARCHIVE, /* Time Shifting */
- [ 0x26 ] = KEY_STOP,
- [ 0x27 ] = KEY_RECORD,
- [ 0x28 ] = KEY_SAVE, /* Screenshot */
- [ 0x2f ] = KEY_MENU,
- [ 0x30 ] = KEY_CANCEL,
- [ 0x31 ] = KEY_CHANNEL, /* Channel Surf */
- [ 0x32 ] = KEY_SUBTITLE,
- [ 0x33 ] = KEY_LANGUAGE,
- [ 0x34 ] = KEY_REWIND,
- [ 0x35 ] = KEY_FASTFORWARD,
- [ 0x36 ] = KEY_TV,
- [ 0x37 ] = KEY_RADIO, /* FM */
- [ 0x38 ] = KEY_DVD,
-
- [ 0x3e ] = KEY_F21, /* MCE +VOL, on Y04G0033 */
- [ 0x3a ] = KEY_F22, /* MCE -VOL, on Y04G0033 */
- [ 0x3b ] = KEY_F23, /* MCE +CH, on Y04G0033 */
- [ 0x3f ] = KEY_F24 /* MCE -CH, on Y04G0033 */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_winfast);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
- [ 0x59 ] = KEY_MUTE,
- [ 0x4a ] = KEY_POWER,
-
- [ 0x18 ] = KEY_TEXT,
- [ 0x26 ] = KEY_TV,
- [ 0x3d ] = KEY_PRINT,
-
- [ 0x48 ] = KEY_RED,
- [ 0x04 ] = KEY_GREEN,
- [ 0x11 ] = KEY_YELLOW,
- [ 0x00 ] = KEY_BLUE,
-
- [ 0x2d ] = KEY_VOLUMEUP,
- [ 0x1e ] = KEY_VOLUMEDOWN,
-
- [ 0x49 ] = KEY_MENU,
-
- [ 0x16 ] = KEY_CHANNELUP,
- [ 0x17 ] = KEY_CHANNELDOWN,
-
- [ 0x20 ] = KEY_UP,
- [ 0x21 ] = KEY_DOWN,
- [ 0x22 ] = KEY_LEFT,
- [ 0x23 ] = KEY_RIGHT,
- [ 0x0d ] = KEY_SELECT,
-
-
-
- [ 0x08 ] = KEY_BACK,
- [ 0x07 ] = KEY_REFRESH,
-
- [ 0x2f ] = KEY_ZOOM,
- [ 0x29 ] = KEY_RECORD,
-
- [ 0x4b ] = KEY_PAUSE,
- [ 0x4d ] = KEY_REWIND,
- [ 0x2e ] = KEY_PLAY,
- [ 0x4e ] = KEY_FORWARD,
- [ 0x53 ] = KEY_PREVIOUS,
- [ 0x4c ] = KEY_STOP,
- [ 0x54 ] = KEY_NEXT,
-
- [ 0x69 ] = KEY_0,
- [ 0x6a ] = KEY_1,
- [ 0x6b ] = KEY_2,
- [ 0x6c ] = KEY_3,
- [ 0x6d ] = KEY_4,
- [ 0x6e ] = KEY_5,
- [ 0x6f ] = KEY_6,
- [ 0x70 ] = KEY_7,
- [ 0x71 ] = KEY_8,
- [ 0x72 ] = KEY_9,
-
- [ 0x74 ] = KEY_CHANNEL,
- [ 0x0a ] = KEY_BACKSPACE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
-
-/* Hauppauge: the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- * almost rc5 coding, but some non-standard keys */
-IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */
- [ 0x0b ] = KEY_RED, /* red button */
- [ 0x0c ] = KEY_RADIO,
- [ 0x0d ] = KEY_MENU,
- [ 0x0e ] = KEY_SUBTITLE, /* also the # key */
- [ 0x0f ] = KEY_MUTE,
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_VOLUMEDOWN,
- [ 0x12 ] = KEY_PREVIOUS, /* previous channel */
- [ 0x14 ] = KEY_UP,
- [ 0x15 ] = KEY_DOWN,
- [ 0x16 ] = KEY_LEFT,
- [ 0x17 ] = KEY_RIGHT,
- [ 0x18 ] = KEY_VIDEO, /* Videos */
- [ 0x19 ] = KEY_AUDIO, /* Music */
- /* 0x1a: Pictures - presume this means
- "Multimedia Home Platform" -
- no "PICTURES" key in input.h
- */
- [ 0x1a ] = KEY_MHP,
-
- [ 0x1b ] = KEY_EPG, /* Guide */
- [ 0x1c ] = KEY_TV,
- [ 0x1e ] = KEY_NEXTSONG, /* skip >| */
- [ 0x1f ] = KEY_EXIT, /* back/exit */
- [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
- [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
- [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */
- [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */
- [ 0x25 ] = KEY_ENTER, /* OK */
- [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */
- [ 0x29 ] = KEY_BLUE, /* blue key */
- [ 0x2e ] = KEY_GREEN, /* green button */
- [ 0x30 ] = KEY_PAUSE, /* pause */
- [ 0x32 ] = KEY_REWIND, /* backward << */
- [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */
- [ 0x35 ] = KEY_PLAY,
- [ 0x36 ] = KEY_STOP,
- [ 0x37 ] = KEY_RECORD, /* recording */
- [ 0x38 ] = KEY_YELLOW, /* yellow key */
- [ 0x3b ] = KEY_SELECT, /* top right button */
- [ 0x3c ] = KEY_ZOOM, /* full */
- [ 0x3d ] = KEY_POWER, /* system power (green button) */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
-
-IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
- [ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
- [ 0x2a ] = KEY_FRONT,
-
- [ 0x3e ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x06 ] = KEY_3,
- [ 0x0a ] = KEY_4,
- [ 0x0e ] = KEY_5,
- [ 0x12 ] = KEY_6,
- [ 0x16 ] = KEY_7,
- [ 0x1a ] = KEY_8,
- [ 0x1e ] = KEY_9,
- [ 0x3a ] = KEY_0,
- [ 0x22 ] = KEY_NUMLOCK, /* -/-- */
- [ 0x20 ] = KEY_REFRESH,
-
- [ 0x03 ] = KEY_BRIGHTNESSDOWN,
- [ 0x28 ] = KEY_AUDIO,
- [ 0x3c ] = KEY_UP,
- [ 0x3f ] = KEY_LEFT,
- [ 0x2e ] = KEY_MUTE,
- [ 0x3b ] = KEY_RIGHT,
- [ 0x00 ] = KEY_DOWN,
- [ 0x07 ] = KEY_BRIGHTNESSUP,
- [ 0x2c ] = KEY_TEXT,
-
- [ 0x37 ] = KEY_RECORD,
- [ 0x17 ] = KEY_PLAY,
- [ 0x13 ] = KEY_PAUSE,
- [ 0x26 ] = KEY_STOP,
- [ 0x18 ] = KEY_FASTFORWARD,
- [ 0x14 ] = KEY_REWIND,
- [ 0x33 ] = KEY_ZOOM,
- [ 0x32 ] = KEY_KEYBOARD,
- [ 0x30 ] = KEY_GOTO, /* Pointing arrow */
- [ 0x36 ] = KEY_MACRO, /* Maximize/Minimize (yellow) */
- [ 0x0b ] = KEY_RADIO,
- [ 0x10 ] = KEY_POWER,
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_npgtech);
-
-/* Norwood Micro (non-Pro) TV Tuner
- By Peter Naulls <peter@chocky.org>
- Key comments are the functions given in the manual */
-IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x20 ] = KEY_0,
- [ 0x21 ] = KEY_1,
- [ 0x22 ] = KEY_2,
- [ 0x23 ] = KEY_3,
- [ 0x24 ] = KEY_4,
- [ 0x25 ] = KEY_5,
- [ 0x26 ] = KEY_6,
- [ 0x27 ] = KEY_7,
- [ 0x28 ] = KEY_8,
- [ 0x29 ] = KEY_9,
-
- [ 0x78 ] = KEY_TUNER, /* Video Source */
- [ 0x2c ] = KEY_EXIT, /* Open/Close software */
- [ 0x2a ] = KEY_SELECT, /* 2 Digit Select */
- [ 0x69 ] = KEY_AGAIN, /* Recall */
-
- [ 0x32 ] = KEY_BRIGHTNESSUP, /* Brightness increase */
- [ 0x33 ] = KEY_BRIGHTNESSDOWN, /* Brightness decrease */
- [ 0x6b ] = KEY_KPPLUS, /* (not named >>>>>) */
- [ 0x6c ] = KEY_KPMINUS, /* (not named <<<<<) */
-
- [ 0x2d ] = KEY_MUTE, /* Mute */
- [ 0x30 ] = KEY_VOLUMEUP, /* Volume up */
- [ 0x31 ] = KEY_VOLUMEDOWN, /* Volume down */
- [ 0x60 ] = KEY_CHANNELUP, /* Channel up */
- [ 0x61 ] = KEY_CHANNELDOWN, /* Channel down */
-
- [ 0x3f ] = KEY_RECORD, /* Record */
- [ 0x37 ] = KEY_PLAY, /* Play */
- [ 0x36 ] = KEY_PAUSE, /* Pause */
- [ 0x2b ] = KEY_STOP, /* Stop */
- [ 0x67 ] = KEY_FASTFORWARD, /* Foward */
- [ 0x66 ] = KEY_REWIND, /* Rewind */
- [ 0x3e ] = KEY_SEARCH, /* Auto Scan */
- [ 0x2e ] = KEY_CAMERA, /* Capture Video */
- [ 0x6d ] = KEY_MENU, /* Show/Hide Control */
- [ 0x2f ] = KEY_ZOOM, /* Full Screen */
- [ 0x34 ] = KEY_RADIO, /* FM */
- [ 0x65 ] = KEY_POWER, /* Computer power */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_norwood);
-
-/* From reading the following remotes:
- * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
- * Hauppauge (from NOVA-CI-s box product)
- * This is a "middle of the road" approach, differences are noted
- */
-IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_0,
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
- [ 0x0a ] = KEY_ENTER,
- [ 0x0b ] = KEY_RED,
- [ 0x0c ] = KEY_POWER, /* RADIO on Hauppauge */
- [ 0x0d ] = KEY_MUTE,
- [ 0x0f ] = KEY_A, /* TV on Hauppauge */
- [ 0x10 ] = KEY_VOLUMEUP,
- [ 0x11 ] = KEY_VOLUMEDOWN,
- [ 0x14 ] = KEY_B,
- [ 0x1c ] = KEY_UP,
- [ 0x1d ] = KEY_DOWN,
- [ 0x1e ] = KEY_OPTION, /* RESERVED on Hauppauge */
- [ 0x1f ] = KEY_BREAK,
- [ 0x20 ] = KEY_CHANNELUP,
- [ 0x21 ] = KEY_CHANNELDOWN,
- [ 0x22 ] = KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
- [ 0x24 ] = KEY_RESTART,
- [ 0x25 ] = KEY_OK,
- [ 0x26 ] = KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
- [ 0x28 ] = KEY_ENTER, /* VCR mode on Zenith */
- [ 0x29 ] = KEY_PAUSE,
- [ 0x2b ] = KEY_RIGHT,
- [ 0x2c ] = KEY_LEFT,
- [ 0x2e ] = KEY_MENU, /* FULL SCREEN on Hauppauge */
- [ 0x30 ] = KEY_SLOW,
- [ 0x31 ] = KEY_PREVIOUS, /* VCR mode on Zenith */
- [ 0x32 ] = KEY_REWIND,
- [ 0x34 ] = KEY_FASTFORWARD,
- [ 0x35 ] = KEY_PLAY,
- [ 0x36 ] = KEY_STOP,
- [ 0x37 ] = KEY_RECORD,
- [ 0x38 ] = KEY_TUNER, /* TV/VCR on Zenith */
- [ 0x3a ] = KEY_C,
- [ 0x3c ] = KEY_EXIT,
- [ 0x3d ] = KEY_POWER2,
- [ 0x3e ] = KEY_TUNER,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
-
-/*
- * Marc Fargas <telenieko@telenieko.com>
- * this is the remote control that comes with the asus p7131
- * which has a label saying is "Model PC-39"
- */
-IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [ 0x15 ] = KEY_0,
- [ 0x29 ] = KEY_1,
- [ 0x2d ] = KEY_2,
- [ 0x2b ] = KEY_3,
- [ 0x09 ] = KEY_4,
- [ 0x0d ] = KEY_5,
- [ 0x0b ] = KEY_6,
- [ 0x31 ] = KEY_7,
- [ 0x35 ] = KEY_8,
- [ 0x33 ] = KEY_9,
-
- [ 0x3e ] = KEY_RADIO, /* radio */
- [ 0x03 ] = KEY_MENU, /* dvd/menu */
- [ 0x2a ] = KEY_VOLUMEUP,
- [ 0x19 ] = KEY_VOLUMEDOWN,
- [ 0x37 ] = KEY_UP,
- [ 0x3b ] = KEY_DOWN,
- [ 0x27 ] = KEY_LEFT,
- [ 0x2f ] = KEY_RIGHT,
- [ 0x25 ] = KEY_VIDEO, /* video */
- [ 0x39 ] = KEY_AUDIO, /* music */
-
- [ 0x21 ] = KEY_TV, /* tv */
- [ 0x1d ] = KEY_EXIT, /* back */
- [ 0x0a ] = KEY_CHANNELUP, /* channel / program + */
- [ 0x1b ] = KEY_CHANNELDOWN, /* channel / program - */
- [ 0x1a ] = KEY_ENTER, /* enter */
-
- [ 0x06 ] = KEY_PAUSE, /* play/pause */
- [ 0x1e ] = KEY_PREVIOUS, /* rew */
- [ 0x26 ] = KEY_NEXT, /* forward */
- [ 0x0e ] = KEY_REWIND, /* backward << */
- [ 0x3a ] = KEY_FASTFORWARD, /* forward >> */
- [ 0x36 ] = KEY_STOP,
- [ 0x2e ] = KEY_RECORD, /* recording */
- [ 0x16 ] = KEY_POWER, /* the button that reads "close" */
-
- [ 0x11 ] = KEY_ZOOM, /* full screen */
- [ 0x13 ] = KEY_MACRO, /* recall */
- [ 0x23 ] = KEY_HOME, /* home */
- [ 0x05 ] = KEY_PVR, /* picture */
- [ 0x3d ] = KEY_MUTE, /* mute */
- [ 0x01 ] = KEY_DVD, /* dvd */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_asus_pc39);
-
-
-/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
- Juan Pablo Sormani <sorman@gmail.com> */
-IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
-
- /* Power button does nothing, neither in Windows app,
- although it sends data (used for BIOS wakeup?) */
- [ 0x0d ] = KEY_MUTE,
-
- [ 0x1e ] = KEY_TV,
- [ 0x00 ] = KEY_VIDEO,
- [ 0x01 ] = KEY_AUDIO, /* music */
- [ 0x02 ] = KEY_MHP, /* picture */
-
- [ 0x1f ] = KEY_1,
- [ 0x03 ] = KEY_2,
- [ 0x04 ] = KEY_3,
- [ 0x05 ] = KEY_4,
- [ 0x1c ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x1d ] = KEY_9,
- [ 0x0a ] = KEY_0,
-
- [ 0x09 ] = KEY_LIST, /* -/-- */
- [ 0x0b ] = KEY_LAST, /* recall */
-
- [ 0x14 ] = KEY_HOME, /* win start menu */
- [ 0x15 ] = KEY_EXIT, /* exit */
- [ 0x16 ] = KEY_UP,
- [ 0x12 ] = KEY_DOWN,
- [ 0x0c ] = KEY_RIGHT,
- [ 0x17 ] = KEY_LEFT,
-
- [ 0x18 ] = KEY_ENTER, /* OK */
-
- [ 0x0e ] = KEY_ESC,
- [ 0x13 ] = KEY_D, /* desktop */
- [ 0x11 ] = KEY_TAB,
- [ 0x19 ] = KEY_SWITCHVIDEOMODE, /* switch */
-
- [ 0x1a ] = KEY_MENU,
- [ 0x1b ] = KEY_ZOOM, /* fullscreen */
- [ 0x44 ] = KEY_TIME, /* time shift */
- [ 0x40 ] = KEY_MODE, /* source */
-
- [ 0x5a ] = KEY_RECORD,
- [ 0x42 ] = KEY_PLAY, /* play/pause */
- [ 0x45 ] = KEY_STOP,
- [ 0x43 ] = KEY_CAMERA, /* camera icon */
-
- [ 0x48 ] = KEY_REWIND,
- [ 0x4a ] = KEY_FASTFORWARD,
- [ 0x49 ] = KEY_PREVIOUS,
- [ 0x4b ] = KEY_NEXT,
-
- [ 0x4c ] = KEY_FAVORITES, /* tv wall */
- [ 0x4d ] = KEY_SOUND, /* DVD sound */
- [ 0x4e ] = KEY_LANGUAGE, /* DVD lang */
- [ 0x4f ] = KEY_TEXT, /* DVD text */
-
- [ 0x50 ] = KEY_SLEEP, /* shutdown */
- [ 0x51 ] = KEY_MODE, /* stereo > main */
- [ 0x52 ] = KEY_SELECT, /* stereo > sap */
- [ 0x53 ] = KEY_PROG1, /* teletext */
-
-
- [ 0x59 ] = KEY_RED, /* AP1 */
- [ 0x41 ] = KEY_GREEN, /* AP2 */
- [ 0x47 ] = KEY_YELLOW, /* AP3 */
- [ 0x57 ] = KEY_BLUE, /* AP4 */
-
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
-
-/* for the Technotrend 1500 bundled remotes (grey and black): */
-IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
- [ 0x01 ] = KEY_POWER,
- [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
- [ 0x03 ] = KEY_1,
- [ 0x04 ] = KEY_2,
- [ 0x05 ] = KEY_3,
- [ 0x06 ] = KEY_4,
- [ 0x07 ] = KEY_5,
- [ 0x08 ] = KEY_6,
- [ 0x09 ] = KEY_7,
- [ 0x0a ] = KEY_8,
- [ 0x0b ] = KEY_9,
- [ 0x0c ] = KEY_0,
- [ 0x0d ] = KEY_UP,
- [ 0x0e ] = KEY_LEFT,
- [ 0x0f ] = KEY_OK,
- [ 0x10 ] = KEY_RIGHT,
- [ 0x11 ] = KEY_DOWN,
- [ 0x12 ] = KEY_INFO,
- [ 0x13 ] = KEY_EXIT,
- [ 0x14 ] = KEY_RED,
- [ 0x15 ] = KEY_GREEN,
- [ 0x16 ] = KEY_YELLOW,
- [ 0x17 ] = KEY_BLUE,
- [ 0x18 ] = KEY_MUTE,
- [ 0x19 ] = KEY_TEXT,
- [ 0x1a ] = KEY_MODE, /* ? TV/Radio */
- [ 0x21 ] = KEY_OPTION,
- [ 0x22 ] = KEY_EPG,
- [ 0x23 ] = KEY_CHANNELUP,
- [ 0x24 ] = KEY_CHANNELDOWN,
- [ 0x25 ] = KEY_VOLUMEUP,
- [ 0x26 ] = KEY_VOLUMEDOWN,
- [ 0x27 ] = KEY_SETUP,
- [ 0x3a ] = KEY_RECORD, /* these keys are only in the black remote */
- [ 0x3b ] = KEY_PLAY,
- [ 0x3c ] = KEY_STOP,
- [ 0x3d ] = KEY_REWIND,
- [ 0x3e ] = KEY_PAUSE,
- [ 0x3f ] = KEY_FORWARD,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
-
-/* DViCO FUSION HDTV MCE remote */
-IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
-
- [ 0x0b ] = KEY_1,
- [ 0x17 ] = KEY_2,
- [ 0x1b ] = KEY_3,
- [ 0x07 ] = KEY_4,
- [ 0x50 ] = KEY_5,
- [ 0x54 ] = KEY_6,
- [ 0x48 ] = KEY_7,
- [ 0x4c ] = KEY_8,
- [ 0x58 ] = KEY_9,
- [ 0x03 ] = KEY_0,
-
- [ 0x5e ] = KEY_OK,
- [ 0x51 ] = KEY_UP,
- [ 0x53 ] = KEY_DOWN,
- [ 0x5b ] = KEY_LEFT,
- [ 0x5f ] = KEY_RIGHT,
-
- [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */
- [ 0x0e ] = KEY_MP3,
- [ 0x1a ] = KEY_DVD,
- [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */
- [ 0x16 ] = KEY_SETUP,
- [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */
- [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */
-
- [ 0x49 ] = KEY_BACK,
- [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */
- [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */
- [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */
-
- [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */
- [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */
- [ 0x42 ] = KEY_ENTER, /* Labeled START with a green
- * MS windows logo on remote */
-
- [ 0x15 ] = KEY_VOLUMEUP,
- [ 0x05 ] = KEY_VOLUMEDOWN,
- [ 0x11 ] = KEY_CHANNELUP,
- [ 0x09 ] = KEY_CHANNELDOWN,
-
- [ 0x52 ] = KEY_CAMERA,
- [ 0x5a ] = KEY_TUNER,
- [ 0x19 ] = KEY_OPEN,
-
- [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */
- [ 0x1f ] = KEY_ZOOM,
-
- [ 0x43 ] = KEY_REWIND,
- [ 0x47 ] = KEY_PLAYPAUSE,
- [ 0x4f ] = KEY_FASTFORWARD,
- [ 0x57 ] = KEY_MUTE,
- [ 0x0d ] = KEY_STOP,
- [ 0x01 ] = KEY_RECORD,
- [ 0x4e ] = KEY_POWER,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
-
-/* Pinnacle PCTV HD 800i mini remote */
-IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
-
- [0x0f] = KEY_1,
- [0x15] = KEY_2,
- [0x10] = KEY_3,
- [0x18] = KEY_4,
- [0x1b] = KEY_5,
- [0x1e] = KEY_6,
- [0x11] = KEY_7,
- [0x21] = KEY_8,
- [0x12] = KEY_9,
- [0x27] = KEY_0,
-
- [0x24] = KEY_ZOOM,
- [0x2a] = KEY_SUBTITLE,
-
- [0x00] = KEY_MUTE,
- [0x01] = KEY_ENTER, /* Pinnacle Logo */
- [0x39] = KEY_POWER,
-
- [0x03] = KEY_VOLUMEUP,
- [0x09] = KEY_VOLUMEDOWN,
- [0x06] = KEY_CHANNELUP,
- [0x0c] = KEY_CHANNELDOWN,
-
- [0x2d] = KEY_REWIND,
- [0x30] = KEY_PLAYPAUSE,
- [0x33] = KEY_FASTFORWARD,
- [0x3c] = KEY_STOP,
- [0x36] = KEY_RECORD,
- [0x3f] = KEY_EPG, /* Labeled "?" */
-};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
-
-/*
- * Igor Kuznetsov <igk72@ya.ru>
- * Andrey J. Melnikov <temnota@kmv.ru>
- *
- * Keytable is used by BeholdTV 60x series, M6 series at
- * least, and probably other cards too.
- * The "ascii-art picture" below (in comments, first row
- * is the keycode in hex, and subsequent row(s) shows
- * the button labels (several variants when appropriate)
- * helps to descide which keycodes to assign to the buttons.
- */
-IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
-
- /* 0x1c 0x12 *
- * TV/FM POWER *
- * */
- [ 0x1c ] = KEY_TUNER, /*XXX KEY_TV KEY_RADIO */
- [ 0x12 ] = KEY_POWER,
-
- /* 0x01 0x02 0x03 *
- * 1 2 3 *
- * *
- * 0x04 0x05 0x06 *
- * 4 5 6 *
- * *
- * 0x07 0x08 0x09 *
- * 7 8 9 *
- * */
- [ 0x01 ] = KEY_1,
- [ 0x02 ] = KEY_2,
- [ 0x03 ] = KEY_3,
- [ 0x04 ] = KEY_4,
- [ 0x05 ] = KEY_5,
- [ 0x06 ] = KEY_6,
- [ 0x07 ] = KEY_7,
- [ 0x08 ] = KEY_8,
- [ 0x09 ] = KEY_9,
-
- /* 0x0a 0x00 0x17 *
- * RECALL 0 MODE *
- * */
- [ 0x0a ] = KEY_AGAIN,
- [ 0x00 ] = KEY_0,
- [ 0x17 ] = KEY_MODE,
-
- /* 0x14 0x10 *
- * ASPECT FULLSCREEN *
- * */
- [ 0x14 ] = KEY_SCREEN,
- [ 0x10 ] = KEY_ZOOM,
-
- /* 0x0b *
- * Up *
- * *
- * 0x18 0x16 0x0c *
- * Left Ok Right *
- * *
- * 0x015 *
- * Down *
- * */
- [ 0x0b ] = KEY_CHANNELUP, /*XXX KEY_UP */
- [ 0x18 ] = KEY_VOLUMEDOWN, /*XXX KEY_LEFT */
- [ 0x16 ] = KEY_OK, /*XXX KEY_ENTER */
- [ 0x0c ] = KEY_VOLUMEUP, /*XXX KEY_RIGHT */
- [ 0x15 ] = KEY_CHANNELDOWN, /*XXX KEY_DOWN */
-
- /* 0x11 0x0d *
- * MUTE INFO *
- * */
- [ 0x11 ] = KEY_MUTE,
- [ 0x0d ] = KEY_INFO,
-
- /* 0x0f 0x1b 0x1a *
- * RECORD PLAY/PAUSE STOP *
- * *
- * 0x0e 0x1f 0x1e *
- *TELETEXT AUDIO SOURCE *
- * RED YELLOW *
- * */
- [ 0x0f ] = KEY_RECORD,
- [ 0x1b ] = KEY_PLAYPAUSE,
- [ 0x1a ] = KEY_STOP,
- [ 0x0e ] = KEY_TEXT,
- [ 0x1f ] = KEY_RED, /*XXX KEY_AUDIO */
- [ 0x1e ] = KEY_YELLOW, /*XXX KEY_SOURCE */
-
- /* 0x1d 0x13 0x19 *
- * SLEEP PREVIEW DVB *
- * GREEN BLUE *
- * */
- [ 0x1d ] = KEY_SLEEP,
- [ 0x13 ] = KEY_GREEN,
- [ 0x19 ] = KEY_BLUE, /*XXX KEY_SAT */
-
- /* 0x58 0x5c *
- * FREEZE SNAPSHOT *
- * */
- [ 0x58 ] = KEY_SLOW,
- [ 0x5c ] = KEY_SAVE,
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_behold);
-
-/*
- * Remote control for the Genius TVGO A11MCE
- * Adrian Pardini <pardo.bsso@gmail.com>
- */
-IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE] = {
- /* Keys 0 to 9 */
- [0x48] = KEY_0,
- [0x09] = KEY_1,
- [0x1d] = KEY_2,
- [0x1f] = KEY_3,
- [0x19] = KEY_4,
- [0x1b] = KEY_5,
- [0x11] = KEY_6,
- [0x17] = KEY_7,
- [0x12] = KEY_8,
- [0x16] = KEY_9,
-
- [0x54] = KEY_RECORD, /* recording */
- [0x06] = KEY_MUTE, /* mute */
- [0x10] = KEY_POWER,
- [0x40] = KEY_LAST, /* recall */
- [0x4c] = KEY_CHANNELUP, /* channel / program + */
- [0x00] = KEY_CHANNELDOWN, /* channel / program - */
- [0x0d] = KEY_VOLUMEUP,
- [0x15] = KEY_VOLUMEDOWN,
- [0x4d] = KEY_OK, /* also labeled as Pause */
- [0x1c] = KEY_ZOOM, /* full screen and Stop*/
- [0x02] = KEY_MODE, /* AV Source or Rewind*/
- [0x04] = KEY_LIST, /* -/-- */
- /* small arrows above numbers */
- [0x1a] = KEY_NEXT, /* also Fast Forward */
- [0x0e] = KEY_PREVIOUS, /* also Rewind */
- /* these are in a rather non standard layout and have
- an alternate name written */
- [0x1e] = KEY_UP, /* Video Setting */
- [0x0a] = KEY_DOWN, /* Video Default */
- [0x05] = KEY_LEFT, /* Snapshot */
- [0x0c] = KEY_RIGHT, /* Hide Panel */
- /* Four buttons without label */
- [0x49] = KEY_RED,
- [0x0b] = KEY_GREEN,
- [0x13] = KEY_YELLOW,
- [0x50] = KEY_BLUE,
-};
-EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce);
diff --git a/drivers/media/common/saa7146/Kconfig b/drivers/media/common/saa7146/Kconfig
new file mode 100644
index 00000000000..769c6f8142d
--- /dev/null
+++ b/drivers/media/common/saa7146/Kconfig
@@ -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
diff --git a/drivers/media/common/saa7146/Makefile b/drivers/media/common/saa7146/Makefile
new file mode 100644
index 00000000000..3219b00a877
--- /dev/null
+++ b/drivers/media/common/saa7146/Makefile
@@ -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
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index 7707b8c7394..34b0d0ddeef 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -18,10 +18,10 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <media/saa7146.h>
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-LIST_HEAD(saa7146_devices);
-DEFINE_MUTEX(saa7146_devices_lock);
+#include <media/saa7146.h>
+#include <linux/module.h>
static int saa7146_num;
@@ -35,10 +35,9 @@ static void dump_registers(struct saa7146_dev* dev)
{
int i = 0;
- INFO((" @ %li jiffies:\n",jiffies));
- for(i = 0; i <= 0x148; i+=4) {
- printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i));
- }
+ 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
@@ -72,9 +71,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
if (saa7146_read(dev, MC2) & 2)
break;
if (err) {
- printk(KERN_ERR "%s: %s timed out while waiting for "
- "registers getting programmed\n",
- dev->name, __FUNCTION__);
+ pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+ dev->name, __func__);
return -ETIMEDOUT;
}
msleep(1);
@@ -88,8 +86,8 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
break;
saa7146_read(dev, MC2);
if (err) {
- DEB_S(("%s: %s timed out while waiting for transfer "
- "completion\n", dev->name, __FUNCTION__));
+ DEB_S("%s: %s timed out while waiting for transfer completion\n",
+ dev->name, __func__);
return -ETIMEDOUT;
}
msleep(1);
@@ -109,9 +107,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
if (saa7146_read(dev, MC2) & 2)
break;
if (!loops--) {
- printk(KERN_ERR "%s: %s timed out while waiting for "
- "registers getting programmed\n",
- dev->name, __FUNCTION__);
+ pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+ dev->name, __func__);
return -ETIMEDOUT;
}
udelay(1);
@@ -124,8 +121,8 @@ static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
break;
saa7146_read(dev, MC2);
if (!loops--) {
- DEB_S(("%s: %s timed out while waiting for transfer "
- "completion\n", dev->name, __FUNCTION__));
+ DEB_S("%s: %s timed out while waiting for transfer completion\n",
+ dev->name, __func__);
return -ETIMEDOUT;
}
udelay(5);
@@ -233,8 +230,8 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
{
- u32 *cpu;
- dma_addr_t dma_addr;
+ __le32 *cpu;
+ dma_addr_t dma_addr = 0;
cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
if (NULL == cpu) {
@@ -250,7 +247,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,
struct scatterlist *list, int sglen )
{
- u32 *ptr, fill;
+ __le32 *ptr, fill;
int nr_pages = 0;
int i,p;
@@ -264,7 +261,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
ptr = pt->cpu;
for (i = 0; i < sglen; i++, list++) {
/*
- printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset);
+ 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);
@@ -281,9 +280,9 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
/*
ptr = pt->cpu;
- printk("offset: %d\n",pt->offset);
+ pr_debug("offset: %d\n", pt->offset);
for(i=0;i<5;i++) {
- printk("ptr1 %d: 0x%08x\n",i,ptr[i]);
+ pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]);
}
*/
return 0;
@@ -314,7 +313,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
}
}
if (0 != (isr & (MASK_27))) {
- DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
+ DEB_INT("irq: RPS0 (0x%08x)\n", isr);
if (dev->vv_data && dev->vv_callback)
dev->vv_callback(dev,isr);
isr &= ~MASK_27;
@@ -333,14 +332,15 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
} else {
u32 psr = saa7146_read(dev, PSR);
u32 ssr = saa7146_read(dev, SSR);
- printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
- dev->name, isr, psr, 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"));
+ 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);
@@ -360,15 +360,15 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
/* clear out mem for sure */
dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
if (!dev) {
- ERR(("out of memory.\n"));
+ ERR("out of memory\n");
goto out;
}
- DEB_EE(("pci:%p\n",pci));
+ DEB_EE("pci:%p\n", pci);
err = pci_enable_device(pci);
if (err < 0) {
- ERR(("pci_enable_device() failed.\n"));
+ ERR("pci_enable_device() failed\n");
goto err_free;
}
@@ -378,12 +378,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
dev->pci = pci;
/* get chip-revision; this is needed to enable bug-fixes */
- err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);
- if (err < 0) {
- ERR(("pci_read_config_dword() failed.\n"));
- goto err_disable;
- }
- dev->revision &= 0xf;
+ dev->revision = pci->revision;
/* remap the memory from virtual to physical address */
@@ -394,7 +389,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
dev->mem = ioremap(pci_resource_start(pci, 0),
pci_resource_len(pci, 0));
if (!dev->mem) {
- ERR(("ioremap() failed.\n"));
+ ERR("ioremap() failed\n");
err = -ENODEV;
goto err_release;
}
@@ -416,10 +411,10 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
saa7146_write(dev, MC2, 0xf8000000);
/* request an interrupt for the saa7146 */
- err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
+ err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED,
dev->name, dev);
if (err < 0) {
- ERR(("request_irq() failed.\n"));
+ ERR("request_irq() failed\n");
goto err_unmap;
}
@@ -449,12 +444,12 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
/* create a nice device name */
sprintf(dev->name, "saa7146 (%d)", saa7146_num);
- 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));
+ 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;
- pci_set_drvdata(pci, dev);
-
- mutex_init(&dev->lock);
+ mutex_init(&dev->v4l2_lock);
spin_lock_init(&dev->int_slock);
spin_lock_init(&dev->slock);
@@ -471,25 +466,25 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
err = -ENODEV;
if (ext->probe && ext->probe(dev)) {
- DEB_D(("ext->probe() failed for %p. skipping device.\n",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_unprobe;
+ 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);
- INIT_LIST_HEAD(&dev->item);
- list_add_tail(&dev->item,&saa7146_devices);
saa7146_num++;
err = 0;
out:
return err;
-err_unprobe:
- pci_set_drvdata(pci, NULL);
err_free_i2c:
pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
dev->d_i2c.dma_handle);
@@ -514,7 +509,8 @@ err_free:
static void saa7146_remove_one(struct pci_dev *pdev)
{
- struct saa7146_dev* dev = pci_get_drvdata(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;
@@ -525,7 +521,7 @@ static void saa7146_remove_one(struct pci_dev *pdev)
{ NULL, 0 }
}, *p;
- DEB_EE(("dev:%p\n",dev));
+ DEB_EE("dev:%p\n", dev);
dev->ext->detach(dev);
@@ -542,7 +538,6 @@ static void saa7146_remove_one(struct pci_dev *pdev)
iounmap(dev->mem);
pci_release_region(pdev, 0);
- list_del(&dev->item);
pci_disable_device(pdev);
kfree(dev);
@@ -554,21 +549,21 @@ static void saa7146_remove_one(struct pci_dev *pdev)
int saa7146_register_extension(struct saa7146_extension* ext)
{
- DEB_EE(("ext:%p\n",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;
- printk("saa7146: register extension '%s'.\n",ext->name);
+ 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));
- printk("saa7146: unregister extension '%s'.\n",ext->name);
+ DEB_EE("ext:%p\n", ext);
+ pr_info("unregister extension '%s'\n", ext->name);
pci_unregister_driver(&ext->driver);
return 0;
}
@@ -589,8 +584,6 @@ EXPORT_SYMBOL_GPL(saa7146_setgpio);
EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
EXPORT_SYMBOL_GPL(saa7146_debug);
-EXPORT_SYMBOL_GPL(saa7146_devices);
-EXPORT_SYMBOL_GPL(saa7146_devices_lock);
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index 171afe7da6b..eda01bc68ab 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -1,6 +1,7 @@
-#include <media/saa7146_vv.h>
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1)
+#include <media/saa7146_vv.h>
+#include <linux/module.h>
/****************************************************************************/
/* resource management functions, shamelessly stolen from saa7134 driver */
@@ -11,24 +12,23 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
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));
+ DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n",
+ bit, vv->resources);
/* have it already allocated */
return 1;
}
/* is it free? */
- mutex_lock(&dev->lock);
if (vv->resources & bit) {
- DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
+ DEB_D("locked! vv->resources:0x%02x, we want:0x%02x\n",
+ vv->resources, bit);
/* no, someone else uses it */
- mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
- fh->resources |= bit;
+ fh->resources |= bit;
vv->resources |= bit;
- DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
- mutex_unlock(&dev->lock);
+ DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources);
return 1;
}
@@ -39,11 +39,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
BUG_ON((fh->resources & bits) != bits);
- mutex_lock(&dev->lock);
- fh->resources &= ~bits;
+ fh->resources &= ~bits;
vv->resources &= ~bits;
- DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
- mutex_unlock(&dev->lock);
+ DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources);
}
@@ -54,12 +52,12 @@ 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));
+ DEB_EE("dev:%p, buf:%p\n", dev, buf);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -73,18 +71,19 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
struct saa7146_buf *buf)
{
assert_spin_locked(&dev->slock);
- DEB_EE(("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf));
+ 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));
+ 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));
+ DEB_D("adding buffer %p to queue. (active buffer present)\n",
+ buf);
}
return 0;
}
@@ -94,19 +93,19 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
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));
+ 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"));
+ DEB_D("aiii. no current buffer\n");
return;
}
q->curr->vb.state = state;
- do_gettimeofday(&q->curr->vb.ts);
+ v4l2_get_timestamp(&q->curr->vb.ts);
wake_up(&q->curr->vb.done);
q->curr = NULL;
@@ -119,7 +118,7 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
BUG_ON(!q);
- DEB_INT(("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi));
+ DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi);
assert_spin_locked(&dev->slock);
if (!list_empty(&q->queue)) {
@@ -129,10 +128,11 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
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));
+ 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"));
+ DEB_INT("no next buffer. stopping.\n");
if( 0 != vbi ) {
/* turn off video-dma3 */
saa7146_write(dev,MC1, MASK_20);
@@ -169,11 +169,11 @@ void saa7146_buffer_timeout(unsigned long data)
struct saa7146_dev *dev = q->dev;
unsigned long flags;
- DEB_EE(("dev:%p, dmaq:%p\n", dev, q));
+ 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));
+ DEB_D("timeout on %p\n", q->curr);
saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
}
@@ -192,48 +192,23 @@ void saa7146_buffer_timeout(unsigned long data)
/********************************************************************************/
/* file operations */
-static int fops_open(struct inode *inode, struct file *file)
+static int fops_open(struct file *file)
{
- unsigned int minor = iminor(inode);
- struct saa7146_dev *h = NULL, *dev = NULL;
- struct list_head *list;
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_fh *fh = NULL;
int result = 0;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
- DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor));
-
- if (mutex_lock_interruptible(&saa7146_devices_lock))
+ if (mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
- list_for_each(list,&saa7146_devices) {
- h = list_entry(list, struct saa7146_dev, item);
- if( NULL == h->vv_data ) {
- DEB_D(("device %p has not registered video devices.\n",h));
- continue;
- }
- DEB_D(("trying: %p @ major %d,%d\n",h,h->vv_data->video_minor,h->vv_data->vbi_minor));
-
- if (h->vv_data->video_minor == minor) {
- dev = h;
- }
- if (h->vv_data->vbi_minor == minor) {
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- dev = h;
- }
- }
- if (NULL == dev) {
- DEB_S(("no such video device.\n"));
- result = -ENODEV;
- goto out;
- }
-
- DEB_D(("using: %p\n",dev));
+ 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"));
+ DEB_S("no extension registered for this device\n");
result = -ENODEV;
goto out;
}
@@ -241,23 +216,24 @@ static int fops_open(struct inode *inode, struct file *file)
/* allocate per open data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
if (NULL == fh) {
- DEB_S(("cannot allocate memory for per open data.\n"));
+ DEB_S("cannot allocate memory for per open data\n");
result = -ENOMEM;
goto out;
}
- file->private_data = fh;
+ v4l2_fh_init(&fh->fh, vdev);
+
+ file->private_data = &fh->fh;
fh->dev = dev;
- fh->type = type;
- if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- DEB_S(("initializing vbi...\n"));
+ 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(inode, file);
+ dev->ext_vv_data->vbi_fops.open(file);
} else {
- DEB_S(("initializing video...\n"));
+ DEB_S("initializing video...\n");
result = saa7146_video_uops.open(dev,file);
}
@@ -271,64 +247,65 @@ static int fops_open(struct inode *inode, struct file *file)
}
result = 0;
+ v4l2_fh_add(&fh->fh);
out:
if (fh && result != 0) {
kfree(fh);
file->private_data = NULL;
}
- mutex_unlock(&saa7146_devices_lock);
+ mutex_unlock(vdev->lock);
return result;
}
-static int fops_release(struct inode *inode, struct file *file)
+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(("inode:%p, file:%p\n",inode,file));
+ DEB_EE("file:%p\n", file);
- if (mutex_lock_interruptible(&saa7146_devices_lock))
- return -ERESTARTSYS;
+ mutex_lock(vdev->lock);
- if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ 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(inode, file);
+ 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(&saa7146_devices_lock);
+ mutex_unlock(vdev->lock);
return 0;
}
-static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-/*
- DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg));
-*/
- return video_usercopy(inode, file, cmd, arg, saa7146_video_do_ioctl);
-}
-
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 (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",file, vma));
+ 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 V4L2_BUF_TYPE_VBI_CAPTURE: {
- DEB_EE(("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",file, vma));
+ 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;
}
@@ -337,23 +314,31 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
return 0;
}
- return videobuf_mmap_mapper(q,vma);
+ 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)
+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));
+ DEB_EE("file:%p, poll:%p\n", file, wait);
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+ 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 videobuf_poll_stream(file, &fh->vbi_q, wait);
+ return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
q = &fh->vbi_q;
} else {
- DEB_D(("using video queue.\n"));
+ DEB_D("using video queue\n");
q = &fh->video_q;
}
@@ -361,37 +346,57 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
if (!buf) {
- DEB_D(("buf == NULL!\n"));
- return POLLERR;
+ 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 POLLIN|POLLRDNORM;
+ DEB_D("poll succeeded!\n");
+ return res | POLLIN | POLLRDNORM;
}
- DEB_D(("nothing to poll for, buf->state:%d\n",buf->state));
- return 0;
+ 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 (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
-// DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", file, data, (unsigned long)count));
+ 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;
}
- case V4L2_BUF_TYPE_VBI_CAPTURE: {
-// 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)
- return saa7146_vbi_uops.read(file,data,count,ppos);
- else
- return -EINVAL;
- }
- break;
+ return -EINVAL;
default:
BUG();
return 0;
@@ -400,23 +405,29 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
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 (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ 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;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (fh->dev->ext_vv_data->vbi_fops.write)
- return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
- else
- return -EINVAL;
default:
BUG();
return -EINVAL;
}
}
-static const struct file_operations video_fops =
+static const struct v4l2_file_operations video_fops =
{
.owner = THIS_MODULE,
.open = fops_open,
@@ -425,49 +436,78 @@ static const struct file_operations video_fops =
.write = fops_write,
.poll = fops_poll,
.mmap = fops_mmap,
- .ioctl = fops_ioctl,
- .llseek = no_llseek,
+ .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));
+ DEB_INT("dev:%p, isr:0x%08x\n", dev, (u32)status);
if (0 != (isr & (MASK_27))) {
- DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
+ 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));
+ 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));
+ DEB_INT("irq: RPS1 (0x%08x)\n", isr);
saa7146_vbi_uops.irq_done(dev,isr);
}
}
-static struct video_device device_template =
-{
- .fops = &video_fops,
- .minor = -1,
+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 saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL);
- if( NULL == vv ) {
- ERR(("out of memory. aborting.\n"));
- return -1;
+ 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));
+ DEB_EE("dev:%p\n", dev);
/* set default values for video parts of the saa7146 */
saa7146_write(dev, BCS_CTRL, 0x80400040);
@@ -480,13 +520,11 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
configuration data) */
dev->ext_vv_data = ext_vv;
- vv->video_minor = -1;
- vv->vbi_minor = -1;
-
vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle);
if( NULL == vv->d_clipping.cpu_addr ) {
- ERR(("out of memory. aborting.\n"));
+ ERR("out of memory. aborting.\n");
kfree(vv);
+ v4l2_ctrl_handler_free(hdl);
return -1;
}
memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
@@ -495,6 +533,39 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.init(dev,vv);
+ fmt = &vv->ov_fb.fmt;
+ fmt->width = vv->standard->h_max_out;
+ fmt->height = vv->standard->v_max_out;
+ fmt->pixelformat = V4L2_PIX_FMT_RGB565;
+ fmt->bytesperline = 2 * fmt->width;
+ fmt->sizeimage = fmt->bytesperline * fmt->height;
+ 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;
@@ -506,9 +577,11 @@ int saa7146_vv_release(struct saa7146_dev* dev)
{
struct saa7146_vv *vv = dev->vv_data;
- DEB_EE(("dev:%p\n",dev));
+ 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;
@@ -520,37 +593,41 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release);
int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
char *name, int type)
{
- struct saa7146_vv *vv = dev->vv_data;
struct video_device *vfd;
+ int err;
+ int i;
- DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
+ 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;
- memcpy(vfd, &device_template, sizeof(struct video_device));
- strlcpy(vfd->name, name, sizeof(vfd->name));
+ 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->priv = dev;
+ vfd->lock = &dev->v4l2_lock;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->tvnorms = 0;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ 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);
- // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
- if (video_register_device(vfd, type, -1) < 0) {
- ERR(("cannot register v4l2 device. skipping.\n"));
+ err = video_register_device(vfd, type, -1);
+ if (err < 0) {
+ ERR("cannot register v4l2 device. skipping.\n");
video_device_release(vfd);
- return -1;
+ return err;
}
- if( VFL_TYPE_GRABBER == type ) {
- vv->video_minor = vfd->minor;
- INFO(("%s: registered device video%d [v4l2]\n",
- dev->name, vfd->minor & 0x1f));
- } else {
- vv->vbi_minor = vfd->minor;
- INFO(("%s: registered device vbi%d [v4l2]\n",
- dev->name, vfd->minor & 0x1f));
- }
+ pr_info("%s: registered device %s [v4l2]\n",
+ dev->name, video_device_node_name(vfd));
*vid = vfd;
return 0;
@@ -559,15 +636,7 @@ EXPORT_SYMBOL_GPL(saa7146_register_device);
int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
{
- struct saa7146_vv *vv = dev->vv_data;
-
- DEB_EE(("dev:%p\n",dev));
-
- if( VFL_TYPE_GRABBER == (*vid)->type ) {
- vv->video_minor = -1;
- } else {
- vv->vbi_minor = -1;
- }
+ DEB_EE("dev:%p\n", dev);
video_unregister_device(*vid);
*vid = NULL;
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
index 9c905399a23..be746d1aee9 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
@@ -1,4 +1,7 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
+#include <linux/export.h>
#include <media/saa7146_vv.h>
static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
@@ -338,11 +341,11 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
{
struct saa7146_vv *vv = dev->vv_data;
- u32 *clipping = vv->d_clipping.cpu_addr;
+ __le32 *clipping = vv->d_clipping.cpu_addr;
- int width = fh->ov.win.w.width;
- int height = fh->ov.win.w.height;
- int clipcount = fh->ov.nclips;
+ int width = vv->ov.win.w.width;
+ int height = vv->ov.win.w.height;
+ int clipcount = vv->ov.nclips;
u32 line_list[32];
u32 pixel_list[32];
@@ -362,10 +365,10 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
for(i = 0; i < clipcount; i++) {
int l = 0, r = 0, t = 0, b = 0;
- x[i] = fh->ov.clips[i].c.left;
- y[i] = fh->ov.clips[i].c.top;
- w[i] = fh->ov.clips[i].c.width;
- h[i] = fh->ov.clips[i].c.height;
+ x[i] = vv->ov.clips[i].c.left;
+ y[i] = vv->ov.clips[i].c.top;
+ w[i] = vv->ov.clips[i].c.width;
+ h[i] = vv->ov.clips[i].c.height;
if( w[i] < 0) {
x[i] += w[i]; w[i] = -w[i];
@@ -482,13 +485,14 @@ static void saa7146_disable_clipping(struct saa7146_dev *dev)
static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
{
struct saa7146_dev *dev = fh->dev;
- enum v4l2_field field = fh->ov.win.field;
+ struct saa7146_vv *vv = dev->vv_data;
+ enum v4l2_field field = vv->ov.win.field;
struct saa7146_video_dma vdma2;
u32 clip_format;
u32 arbtr_ctrl;
/* check clipcount, disable clipping if clipcount == 0*/
- if( fh->ov.nclips == 0 ) {
+ if (vv->ov.nclips == 0) {
saa7146_disable_clipping(dev);
return;
}
@@ -558,7 +562,7 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e
static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
{
struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
int b_depth = vv->ov_fmt->depth;
int b_bpl = vv->ov_fb.fmt.bytesperline;
@@ -648,8 +652,8 @@ int saa7146_enable_overlay(struct saa7146_fh *fh)
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
- saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);
- saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat);
+ saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
+ saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
saa7146_set_output_format(dev, vv->ov_fmt->trans);
saa7146_set_clipping_rect(fh);
@@ -702,7 +706,7 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_video_dma vdma1;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
@@ -711,8 +715,8 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
int depth = sfmt->depth;
- DEB_CAP(("[size=%dx%d,fields=%s]\n",
- width,height,v4l2_field_names[field]));
+ DEB_CAP("[size=%dx%d,fields=%s]\n",
+ width, height, v4l2_field_names[field]);
if( bytesperline != 0) {
vdma1.pitch = bytesperline*2;
@@ -827,7 +831,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
struct saa7146_video_dma vdma2;
struct saa7146_video_dma vdma3;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
@@ -837,8 +841,8 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
BUG_ON(0 == buf->pt[1].dma);
BUG_ON(0 == buf->pt[2].dma);
- DEB_CAP(("[size=%dx%d,fields=%s]\n",
- width,height,v4l2_field_names[field]));
+ DEB_CAP("[size=%dx%d,fields=%s]\n",
+ width, height, v4l2_field_names[field]);
/* fixme: look at bytesperline! */
@@ -994,16 +998,16 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar)
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
{
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
struct saa7146_vv *vv = dev->vv_data;
u32 vdma1_prot_addr;
- DEB_CAP(("buf:%p, next:%p\n",buf,next));
+ DEB_CAP("buf:%p, next:%p\n", buf, next);
vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
if( 0 == vdma1_prot_addr ) {
/* clear out beginning of streaming bit (rps register 0)*/
- DEB_CAP(("forcing sync to new frame\n"));
+ DEB_CAP("forcing sync to new frame\n");
saa7146_write(dev, MC2, MASK_27 );
}
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
index 7e7689afae6..22027198129 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146/saa7146_i2c.c
@@ -1,8 +1,10 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <media/saa7146_vv.h>
static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
{
-//fm DEB_I2C(("'%s'.\n", adapter->name));
+ /* DEB_I2C("'%s'\n", adapter->name); */
return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_QUICK
@@ -14,9 +16,7 @@ static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
{
u32 iicsta = saa7146_read(dev, I2C_STATUS);
-/*
- DEB_I2C(("status: 0x%08x\n",iicsta));
-*/
+ /* DEB_I2C("status: 0x%08x\n", iicsta); */
return iicsta;
}
@@ -24,7 +24,7 @@ static inline u32 saa7146_i2c_status(struct saa7146_dev *dev)
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, u32 *op)
+static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op)
{
int h1, h2;
int i, j, addr;
@@ -39,15 +39,16 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
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 ) {
-//fm DEB_I2C(("cannot prepare i2c-message.\n"));
+ /* 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(u32)*mem);
+ memset(op,0,sizeof(__le32)*mem);
/* loop through all messages */
for(i = 0; i < num; i++) {
@@ -57,16 +58,16 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
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] |= ( (u8)addr << ((3-h2)*8));
- op[h1] |= (SAA7146_I2C_START << ((3-h2)*2));
+ 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] |= ( (u32)((u8)m[i].buf[j]) << ((3-h2)*8));
- op[h1] |= ( SAA7146_I2C_CONT << ((3-h2)*2));
+ 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++;
}
@@ -75,9 +76,9 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
/* 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 & (op[h1] >> ((3-h2)*2))) ) {
- op[h1] &= ~(0x2 << ((3-h2)*2));
- op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2));
+ 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 */
@@ -88,7 +89,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, u32 *op)
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, u32 *op)
+static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, __le32 *op)
{
int i, j;
int op_count = 0;
@@ -98,10 +99,10 @@ static int saa7146_i2c_msg_cleanup(const struct i2c_msg *m, int num, u32 *op)
op_count++;
- /* loop throgh all bytes of message i */
+ /* 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] = (op[op_count/3] >> ((3-(op_count%3))*8));
+ m[i].buf[j] = (le32_to_cpu(op[op_count/3]) >> ((3-(op_count%3))*8));
op_count++;
}
}
@@ -123,7 +124,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
/* yes, kill ongoing operation */
- DEB_I2C(("busy_state detected.\n"));
+ DEB_I2C("busy_state detected\n");
/* set "ABORT-OPERATION"-bit (bit 7)*/
saa7146_write(dev, I2C_STATUS, (dev->i2c_bitrate | MASK_07));
@@ -141,7 +142,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
if ( dev->i2c_bitrate != status ) {
- DEB_I2C(("error_state detected. status:0x%08x\n",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 */
@@ -161,10 +162,10 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
msleep(SAA7146_I2C_DELAY);
}
- /* if any error is still present, a fatal error has occured ... */
+ /* 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));
+ DEB_I2C("fatal error. status:0x%08x\n", status);
return -1;
}
@@ -174,19 +175,20 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev)
/* 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, u32* dword, int short_delay)
+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));
+ 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, *dword);
+ saa7146_write(dev, I2C_TRANSFER, le32_to_cpu(*dword));
dev->i2c_op = 1;
SAA7146_ISR_CLEAR(dev, MASK_16|MASK_17);
@@ -202,14 +204,14 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
/* a signal arrived */
return -ERESTARTSYS;
- printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
- dev->name, __FUNCTION__);
+ 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, *dword);
+ 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 */
@@ -220,8 +222,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
break;
}
if (time_after(jiffies,timeout)) {
- printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
- dev->name, __FUNCTION__);
+ pr_warn("%s %s: timed out waiting for MC2\n",
+ dev->name, __func__);
return -EIO;
}
}
@@ -237,8 +239,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
/* this is normal when probing the bus
* (no answer from nonexisistant device...)
*/
- printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
- dev->name, __FUNCTION__);
+ pr_warn("%s %s [poll]: timed out waiting for end of xfer\n",
+ dev->name, __func__);
return -EIO;
}
if (++trial < 50 && short_delay)
@@ -257,24 +259,24 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
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));
+ DEB_I2C("unexpected i2c status %04x\n", status);
}
if( 0 != (status & SAA7146_I2C_SPERR) ) {
- DEB_I2C(("error due to invalid start/stop condition.\n"));
+ DEB_I2C("error due to invalid start/stop condition\n");
}
if( 0 != (status & SAA7146_I2C_DTERR) ) {
- DEB_I2C(("error in data transmission.\n"));
+ DEB_I2C("error in data transmission\n");
}
if( 0 != (status & SAA7146_I2C_DRERR) ) {
- DEB_I2C(("error when receiving data.\n"));
+ DEB_I2C("error when receiving data\n");
}
if( 0 != (status & SAA7146_I2C_AL) ) {
- DEB_I2C(("error because arbitration lost.\n"));
+ 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"));
+ DEB_I2C("error in address phase\n");
return -EREMOTEIO;
}
@@ -282,25 +284,24 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
}
/* read back data, just in case we were reading ... */
- *dword = saa7146_read(dev, I2C_TRANSFER);
+ *dword = cpu_to_le32(saa7146_read(dev, I2C_TRANSFER));
- DEB_I2C(("after: 0x%08x\n",*dword));
+ 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;
- u32* buffer = dev->d_i2c.cpu_addr;
+ __le32 *buffer = dev->d_i2c.cpu_addr;
int err = 0;
- int address_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));
+ DEB_I2C("msg:%d/%d\n", i+1, num);
}
/* prepare the message(s), get number of u32s to transfer */
@@ -317,7 +318,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
/* reset the i2c-device if necessary */
err = saa7146_i2c_reset(dev);
if ( 0 > err ) {
- DEB_I2C(("could not reset i2c-device.\n"));
+ DEB_I2C("could not reset i2c-device\n");
goto out;
}
@@ -327,24 +328,17 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
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 occured. in that case, the
+ thinks that an address error occurred. in that case, the
transaction should be retrying, even if an address error
- occured. analog saa7146 based cards extensively rely on
+ 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. because of the fact, that only
- analog based cards use irq based i2c transactions (for dvb
- cards, this screwes up other interrupt sources), we bail out
- completely for analog cards after an address error and trust
- the saa7146 address error detection. */
- if ( -EREMOTEIO == err ) {
- if( 0 != (SAA7146_USE_I2C_IRQ & dev->ext->flags)) {
- goto out;
- }
- address_err++;
- }
- DEB_I2C(("error while sending message(s). starting again.\n"));
+ 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;
}
}
@@ -358,28 +352,27 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m
} while (err != num && retries--);
- /* if every retry had an address error, exit right away */
- if (address_err == 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"));
+ 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));
+ 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 continueing */
+ uploads, so we better clear them out before continuing */
if( 0 == dev->revision ) {
- u32 zero = 0;
+ __le32 zero = 0;
saa7146_i2c_reset(dev);
if( 0 != saa7146_i2c_writeout(dev, &zero, short_delay)) {
- INFO(("revision 0 error. this should never happen.\n"));
+ pr_info("revision 0 error. this should never happen\n");
}
}
@@ -390,7 +383,8 @@ out:
/* utility functions */
static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
{
- struct saa7146_dev* dev = i2c_get_adapdata(adapter);
+ 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);
@@ -399,7 +393,6 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in
/*****************************************************************************/
/* i2c-adapter helper functions */
-#include <linux/i2c-id.h>
/* exported algorithm data */
static struct i2c_algorithm saa7146_algo = {
@@ -409,7 +402,7 @@ static struct i2c_algorithm saa7146_algo = {
int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate)
{
- DEB_EE(("bitrate: 0x%08x\n",bitrate));
+ DEB_EE("bitrate: 0x%08x\n", bitrate);
/* enable i2c-port pins */
saa7146_write(dev, MC1, (MASK_08 | MASK_24));
@@ -417,13 +410,11 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
dev->i2c_bitrate = bitrate;
saa7146_i2c_reset(dev);
- if( NULL != i2c_adapter ) {
- BUG_ON(!i2c_adapter->class);
- i2c_set_adapdata(i2c_adapter,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->id = I2C_HW_SAA7146;
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
i2c_adapter->retries = SAA7146_I2C_RETRIES;
}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index bfbd5a841eb..1e71e374bbf 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -14,7 +14,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
DECLARE_WAITQUEUE(wait, current);
- DEB_VBI(("dev:%p\n",dev));
+ 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
@@ -40,14 +40,14 @@ static int vbi_workaround(struct saa7146_dev *dev)
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"));
+ 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"));
+ DEB_D("...using port a\n");
WRITE_RPS1(CMD_PAUSE | MASK_10);
}
/* upload brs */
@@ -103,7 +103,7 @@ static int vbi_workaround(struct saa7146_dev *dev)
schedule();
- DEB_VBI(("brs bug workaround %d/1.\n",i));
+ DEB_VBI("brs bug workaround %d/1\n", i);
remove_wait_queue(&vv->vbi_wq, &wait);
current->state = TASK_RUNNING;
@@ -116,7 +116,8 @@ static int vbi_workaround(struct saa7146_dev *dev)
if(signal_pending(current)) {
- DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1)));
+ DEB_VBI("aborted (rps:0x%08x)\n",
+ saa7146_read(dev, RPS_ADDR1));
/* stop rps1 for sure */
saa7146_write(dev, MC1, MASK_29);
@@ -207,10 +208,10 @@ static int buffer_activate(struct saa7146_dev *dev,
struct saa7146_vv *vv = dev->vv_data;
buf->vb.state = VIDEOBUF_ACTIVE;
- DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
+ DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
saa7146_set_vbi_capture(dev,buf,next);
- mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
+ mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -228,10 +229,10 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
llength = vbi_pixel_to_capture;
size = lines * llength;
- DEB_VBI(("vb:%p\n",vb));
+ DEB_VBI("vb:%p\n", vb);
if (0 != buf->vb.baddr && buf->vb.bsize < size) {
- DEB_VBI(("size mismatch.\n"));
+ DEB_VBI("size mismatch\n");
return -EINVAL;
}
@@ -263,7 +264,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
return 0;
oops:
- DEB_VBI(("error out.\n"));
+ DEB_VBI("error out\n");
saa7146_dma_free(dev,q,buf);
return err;
@@ -279,7 +280,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned
*size = lines * llength;
*count = 2;
- DEB_VBI(("count:%d, size:%d\n",*count,*size));
+ DEB_VBI("count:%d, size:%d\n", *count, *size);
return 0;
}
@@ -292,8 +293,8 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
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_q,buf);
+ 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)
@@ -303,7 +304,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_dev *dev = fh->dev;
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
- DEB_VBI(("vb:%p\n",vb));
+ DEB_VBI("vb:%p\n", vb);
saa7146_dma_free(dev,q,buf);
}
@@ -321,7 +322,7 @@ 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));
+ DEB_VBI("dev:%p, fh:%p\n", dev, fh);
spin_lock_irqsave(&dev->slock,flags);
@@ -334,16 +335,15 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
/* shut down dma 3 transfers */
saa7146_write(dev, MC1, MASK_20);
- if (vv->vbi_q.curr) {
- saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
- }
+ 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_q.timeout);
- del_timer(&fh->vbi_read_timeout);
+ del_timer(&vv->vbi_dmaq.timeout);
+ del_timer(&vv->vbi_read_timeout);
spin_unlock_irqrestore(&dev->slock, flags);
}
@@ -354,37 +354,38 @@ static void vbi_read_timeout(unsigned long data)
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
- DEB_VBI(("dev:%p, fh:%p\n",dev, fh));
+ 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));
+ DEB_VBI("dev:%p\n", dev);
- INIT_LIST_HEAD(&vv->vbi_q.queue);
+ INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
- init_timer(&vv->vbi_q.timeout);
- vv->vbi_q.timeout.function = saa7146_buffer_timeout;
- vv->vbi_q.timeout.data = (unsigned long)(&vv->vbi_q);
- vv->vbi_q.dev = dev;
+ 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 = (struct saa7146_fh *)file->private_data;
+ 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));
+ 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"));
+ DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
return -EBUSY;
}
@@ -394,29 +395,15 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
saa7146_write(dev, MC2, (MASK_04|MASK_20));
- memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt));
-
- fh->vbi_fmt.sampling_rate = 27000000;
- fh->vbi_fmt.offset = 248; /* todo */
- fh->vbi_fmt.samples_per_line = vbi_pixel_to_capture;
- fh->vbi_fmt.sample_format = V4L2_PIX_FMT_GREY;
-
- /* fixme: this only works for PAL */
- fh->vbi_fmt.start[0] = 5;
- fh->vbi_fmt.count[0] = 16;
- fh->vbi_fmt.start[1] = 312;
- fh->vbi_fmt.count[1] = 16;
-
- videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
- dev->pci, &dev->slock,
+ 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);
+ file, &dev->v4l2_lock);
- init_timer(&fh->vbi_read_timeout);
- fh->vbi_read_timeout.function = vbi_read_timeout;
- fh->vbi_read_timeout.data = (unsigned long)file;
+ 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)) {
@@ -425,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
saa7146_write(dev, BRS_CTRL, 0x00000001);
if (0 != (ret = vbi_workaround(dev))) {
- DEB_VBI(("vbi workaround failed!\n"));
+ DEB_VBI("vbi workaround failed!\n");
/* return ret;*/
}
}
@@ -437,9 +424,9 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
static void vbi_close(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
- DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
+ DEB_VBI("dev:%p, fh:%p\n", dev, fh);
if( fh == vv->vbi_streaming ) {
vbi_stop(fh, file);
@@ -452,16 +439,16 @@ 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_q.curr) {
- DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr));
+ 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_q.curr->vb.field_count = vv->vbi_fieldcount;
- saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
+ 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));
+ DEB_VBI("dev:%p\n", dev);
}
- saa7146_buffer_next(dev,&vv->vbi_q,1);
+ saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
spin_unlock(&dev->slock);
}
@@ -473,7 +460,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
struct saa7146_vv *vv = dev->vv_data;
ssize_t ret = 0;
- DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
+ DEB_VBI("dev:%p, fh:%p\n", dev, fh);
if( NULL == vv->vbi_streaming ) {
// fixme: check if dma3 is available
@@ -482,11 +469,12 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
}
if( fh != vv->vbi_streaming ) {
- DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming));
+ DEB_VBI("open %p is already using vbi capture\n",
+ vv->vbi_streaming);
return -EBUSY;
}
- mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
+ 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);
/*
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
new file mode 100644
index 00000000000..30779498c17
--- /dev/null
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -0,0 +1,1309 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <media/saa7146_vv.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/module.h>
+
+static int max_memory = 32;
+
+module_param(max_memory, int, 0644);
+MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");
+
+#define IS_CAPTURE_ACTIVE(fh) \
+ (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
+
+#define IS_OVERLAY_ACTIVE(fh) \
+ (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
+
+/* format descriptions for capture and preview */
+static struct saa7146_format formats[] = {
+ {
+ .name = "RGB-8 (3-3-2)",
+ .pixelformat = V4L2_PIX_FMT_RGB332,
+ .trans = RGB08_COMPOSED,
+ .depth = 8,
+ .flags = 0,
+ }, {
+ .name = "RGB-16 (5/B-6/G-5/R)",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .trans = RGB16_COMPOSED,
+ .depth = 16,
+ .flags = 0,
+ }, {
+ .name = "RGB-24 (B-G-R)",
+ .pixelformat = V4L2_PIX_FMT_BGR24,
+ .trans = RGB24_COMPOSED,
+ .depth = 24,
+ .flags = 0,
+ }, {
+ .name = "RGB-32 (B-G-R)",
+ .pixelformat = V4L2_PIX_FMT_BGR32,
+ .trans = RGB32_COMPOSED,
+ .depth = 32,
+ .flags = 0,
+ }, {
+ .name = "RGB-32 (R-G-B)",
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .trans = RGB32_COMPOSED,
+ .depth = 32,
+ .flags = 0,
+ .swap = 0x2,
+ }, {
+ .name = "Greyscale-8",
+ .pixelformat = V4L2_PIX_FMT_GREY,
+ .trans = Y8,
+ .depth = 8,
+ .flags = 0,
+ }, {
+ .name = "YUV 4:2:2 planar (Y-Cb-Cr)",
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .trans = YUV422_DECOMPOSED,
+ .depth = 16,
+ .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
+ }, {
+ .name = "YVU 4:2:0 planar (Y-Cb-Cr)",
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .trans = YUV420_DECOMPOSED,
+ .depth = 12,
+ .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
+ }, {
+ .name = "YUV 4:2:0 planar (Y-Cb-Cr)",
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .trans = YUV420_DECOMPOSED,
+ .depth = 12,
+ .flags = FORMAT_IS_PLANAR,
+ }, {
+ .name = "YUV 4:2:2 (U-Y-V-Y)",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .trans = YUV422_COMPOSED,
+ .depth = 16,
+ .flags = 0,
+ }
+};
+
+/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
+ due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
+ (like V4L2_PIX_FMT_YUYV) ... 8-( */
+
+static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
+
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
+{
+ int i, j = NUM_FORMATS;
+
+ for (i = 0; i < j; i++) {
+ if (formats[i].pixelformat == fourcc) {
+ return formats+i;
+ }
+ }
+
+ DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+ return NULL;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f);
+
+int saa7146_start_preview(struct saa7146_fh *fh)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct v4l2_format fmt;
+ int ret = 0, err = 0;
+
+ DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+ /* check if we have overlay information */
+ if (vv->ov.fh == NULL) {
+ DEB_D("no overlay data available. try S_FMT first.\n");
+ return -EAGAIN;
+ }
+
+ /* check if streaming capture is running */
+ if (IS_CAPTURE_ACTIVE(fh) != 0) {
+ DEB_D("streaming capture is active\n");
+ return -EBUSY;
+ }
+
+ /* check if overlay is running */
+ if (IS_OVERLAY_ACTIVE(fh) != 0) {
+ if (vv->video_fh == fh) {
+ DEB_D("overlay is already active\n");
+ return 0;
+ }
+ DEB_D("overlay is already active in another open\n");
+ return -EBUSY;
+ }
+
+ if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
+ DEB_D("cannot get necessary overlay resources\n");
+ return -EBUSY;
+ }
+
+ fmt.fmt.win = vv->ov.win;
+ err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
+ if (0 != err) {
+ saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+ return -EBUSY;
+ }
+ vv->ov.win = fmt.fmt.win;
+
+ DEB_D("%dx%d+%d+%d %s field=%s\n",
+ vv->ov.win.w.width, vv->ov.win.w.height,
+ vv->ov.win.w.left, vv->ov.win.w.top,
+ vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
+
+ if (0 != (ret = saa7146_enable_overlay(fh))) {
+ DEB_D("enabling overlay failed: %d\n", ret);
+ saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+ return ret;
+ }
+
+ vv->video_status = STATUS_OVERLAY;
+ vv->video_fh = fh;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
+
+int saa7146_stop_preview(struct saa7146_fh *fh)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+ /* check if streaming capture is running */
+ if (IS_CAPTURE_ACTIVE(fh) != 0) {
+ DEB_D("streaming capture is active\n");
+ return -EBUSY;
+ }
+
+ /* check if overlay is running at all */
+ if ((vv->video_status & STATUS_OVERLAY) == 0) {
+ DEB_D("no active overlay\n");
+ return 0;
+ }
+
+ if (vv->video_fh != fh) {
+ DEB_D("overlay is active, but in another open\n");
+ return -EBUSY;
+ }
+
+ vv->video_status = 0;
+ vv->video_fh = NULL;
+
+ saa7146_disable_overlay(fh);
+
+ saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
+
+/********************************************************************************/
+/* common pagetable functions */
+
+static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
+{
+ struct pci_dev *pci = dev->pci;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ struct scatterlist *list = dma->sglist;
+ int length = dma->sglen;
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+
+ DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);
+
+ if( 0 != IS_PLANAR(sfmt->trans)) {
+ struct saa7146_pgtable *pt1 = &buf->pt[0];
+ struct saa7146_pgtable *pt2 = &buf->pt[1];
+ struct saa7146_pgtable *pt3 = &buf->pt[2];
+ __le32 *ptr1, *ptr2, *ptr3;
+ __le32 fill;
+
+ int size = buf->fmt->width*buf->fmt->height;
+ int i,p,m1,m2,m3,o1,o2;
+
+ switch( sfmt->depth ) {
+ case 12: {
+ /* create some offsets inside the page table */
+ m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
+ m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
+ m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
+ o1 = size%PAGE_SIZE;
+ o2 = (size+(size/4))%PAGE_SIZE;
+ DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
+ size, m1, m2, m3, o1, o2);
+ break;
+ }
+ case 16: {
+ /* create some offsets inside the page table */
+ m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
+ m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
+ m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
+ o1 = size%PAGE_SIZE;
+ o2 = (size+(size/2))%PAGE_SIZE;
+ DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",
+ size, m1, m2, m3, o1, o2);
+ break;
+ }
+ default: {
+ return -1;
+ }
+ }
+
+ ptr1 = pt1->cpu;
+ ptr2 = pt2->cpu;
+ ptr3 = pt3->cpu;
+
+ /* walk all pages, copy all page addresses to ptr1 */
+ for (i = 0; i < length; i++, list++) {
+ for (p = 0; p * 4096 < list->length; p++, ptr1++) {
+ *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
+ }
+ }
+/*
+ ptr1 = pt1->cpu;
+ for(j=0;j<40;j++) {
+ printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
+ }
+*/
+
+ /* if we have a user buffer, the first page may not be
+ aligned to a page boundary. */
+ pt1->offset = dma->sglist->offset;
+ pt2->offset = pt1->offset+o1;
+ pt3->offset = pt1->offset+o2;
+
+ /* create video-dma2 page table */
+ ptr1 = pt1->cpu;
+ for(i = m1; i <= m2 ; i++, ptr2++) {
+ *ptr2 = ptr1[i];
+ }
+ fill = *(ptr2-1);
+ for(;i<1024;i++,ptr2++) {
+ *ptr2 = fill;
+ }
+ /* create video-dma3 page table */
+ ptr1 = pt1->cpu;
+ for(i = m2; i <= m3; i++,ptr3++) {
+ *ptr3 = ptr1[i];
+ }
+ fill = *(ptr3-1);
+ for(;i<1024;i++,ptr3++) {
+ *ptr3 = fill;
+ }
+ /* finally: finish up video-dma1 page table */
+ ptr1 = pt1->cpu+m1;
+ fill = pt1->cpu[m1];
+ for(i=m1;i<1024;i++,ptr1++) {
+ *ptr1 = fill;
+ }
+/*
+ ptr1 = pt1->cpu;
+ ptr2 = pt2->cpu;
+ ptr3 = pt3->cpu;
+ for(j=0;j<40;j++) {
+ printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
+ }
+ for(j=0;j<40;j++) {
+ printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
+ }
+ for(j=0;j<40;j++) {
+ printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
+ }
+*/
+ } else {
+ struct saa7146_pgtable *pt = &buf->pt[0];
+ return saa7146_pgtable_build_single(pci, pt, list, length);
+ }
+
+ return 0;
+}
+
+
+/********************************************************************************/
+/* file operations */
+
+static int video_begin(struct saa7146_fh *fh)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_format *fmt = NULL;
+ unsigned int resource;
+ int ret = 0, err = 0;
+
+ DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+ if ((vv->video_status & STATUS_CAPTURE) != 0) {
+ if (vv->video_fh == fh) {
+ DEB_S("already capturing\n");
+ return 0;
+ }
+ DEB_S("already capturing in another open\n");
+ return -EBUSY;
+ }
+
+ if ((vv->video_status & STATUS_OVERLAY) != 0) {
+ DEB_S("warning: suspending overlay video for streaming capture\n");
+ vv->ov_suspend = vv->video_fh;
+ err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+ if (0 != err) {
+ DEB_D("suspending video failed. aborting\n");
+ return err;
+ }
+ }
+
+ fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
+ /* we need to have a valid format set here */
+ BUG_ON(NULL == fmt);
+
+ if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
+ resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
+ } else {
+ resource = RESOURCE_DMA1_HPS;
+ }
+
+ ret = saa7146_res_get(fh, resource);
+ if (0 == ret) {
+ DEB_S("cannot get capture resource %d\n", resource);
+ if (vv->ov_suspend != NULL) {
+ saa7146_start_preview(vv->ov_suspend);
+ vv->ov_suspend = NULL;
+ }
+ return -EBUSY;
+ }
+
+ /* clear out beginning of streaming bit (rps register 0)*/
+ saa7146_write(dev, MC2, MASK_27 );
+
+ /* enable rps0 irqs */
+ SAA7146_IER_ENABLE(dev, MASK_27);
+
+ vv->video_fh = fh;
+ vv->video_status = STATUS_CAPTURE;
+
+ return 0;
+}
+
+static int video_end(struct saa7146_fh *fh, struct file *file)
+{
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_format *fmt = NULL;
+ unsigned long flags;
+ unsigned int resource;
+ u32 dmas = 0;
+ DEB_EE("dev:%p, fh:%p\n", dev, fh);
+
+ if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
+ DEB_S("not capturing\n");
+ return 0;
+ }
+
+ if (vv->video_fh != fh) {
+ DEB_S("capturing, but in another open\n");
+ return -EBUSY;
+ }
+
+ fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
+ /* we need to have a valid format set here */
+ BUG_ON(NULL == fmt);
+
+ if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
+ resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
+ dmas = MASK_22 | MASK_21 | MASK_20;
+ } else {
+ resource = RESOURCE_DMA1_HPS;
+ dmas = MASK_22;
+ }
+ spin_lock_irqsave(&dev->slock,flags);
+
+ /* disable rps0 */
+ saa7146_write(dev, MC1, MASK_28);
+
+ /* disable rps0 irqs */
+ SAA7146_IER_DISABLE(dev, MASK_27);
+
+ /* shut down all used video dma transfers */
+ saa7146_write(dev, MC1, dmas);
+
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ vv->video_fh = NULL;
+ vv->video_status = 0;
+
+ saa7146_res_free(fh, resource);
+
+ if (vv->ov_suspend != NULL) {
+ saa7146_start_preview(vv->ov_suspend);
+ vv->ov_suspend = NULL;
+ }
+
+ return 0;
+}
+
+static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+ strcpy((char *)cap->driver, "saa7146 v4l2");
+ strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+ sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
+ cap->device_caps =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ cap->device_caps |= dev->ext_vv_data->capabilities;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps &=
+ ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
+ else
+ cap->device_caps &=
+ ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
+ return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ *fb = vv->ov_fb;
+ fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ fb->flags = V4L2_FBUF_FLAG_PRIMARY;
+ return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_format *fmt;
+
+ DEB_EE("VIDIOC_S_FBUF\n");
+
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* check args */
+ fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+
+ /* planar formats are not allowed for overlay video, clipping and video dma would clash */
+ if (fmt->flags & FORMAT_IS_PLANAR)
+ DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n",
+ (char *)&fmt->pixelformat);
+
+ /* check if overlay is running */
+ if (IS_OVERLAY_ACTIVE(fh) != 0) {
+ if (vv->video_fh != fh) {
+ DEB_D("refusing to change framebuffer informations while overlay is active in another open\n");
+ return -EBUSY;
+ }
+ }
+
+ /* ok, accept it */
+ vv->ov_fb = *fb;
+ vv->ov_fmt = fmt;
+
+ if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
+ vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
+ DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline);
+ }
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ if (f->index >= NUM_FORMATS)
+ return -EINVAL;
+ strlcpy((char *)f->description, formats[f->index].name,
+ sizeof(f->description));
+ f->pixelformat = formats[f->index].pixelformat;
+ return 0;
+}
+
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct saa7146_dev *dev = container_of(ctrl->handler,
+ struct saa7146_dev, ctrl_handler);
+ struct saa7146_vv *vv = dev->vv_data;
+ u32 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ val = saa7146_read(dev, BCS_CTRL);
+ val &= 0x00ffffff;
+ val |= (ctrl->val << 24);
+ saa7146_write(dev, BCS_CTRL, val);
+ saa7146_write(dev, MC2, MASK_22 | MASK_06);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ val = saa7146_read(dev, BCS_CTRL);
+ val &= 0xff00ffff;
+ val |= (ctrl->val << 16);
+ saa7146_write(dev, BCS_CTRL, val);
+ saa7146_write(dev, MC2, MASK_22 | MASK_06);
+ break;
+
+ case V4L2_CID_SATURATION:
+ val = saa7146_read(dev, BCS_CTRL);
+ val &= 0xffffff00;
+ val |= (ctrl->val << 0);
+ saa7146_write(dev, BCS_CTRL, val);
+ saa7146_write(dev, MC2, MASK_22 | MASK_06);
+ break;
+
+ case V4L2_CID_HFLIP:
+ /* fixme: we can support changing VFLIP and HFLIP here... */
+ if ((vv->video_status & STATUS_CAPTURE))
+ return -EBUSY;
+ vv->hflip = ctrl->val;
+ break;
+
+ case V4L2_CID_VFLIP:
+ if ((vv->video_status & STATUS_CAPTURE))
+ return -EBUSY;
+ vv->vflip = ctrl->val;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
+ struct saa7146_fh *fh = vv->video_fh;
+
+ saa7146_stop_preview(fh);
+ saa7146_start_preview(fh);
+ }
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ parm->parm.capture.readbuffers = 1;
+ v4l2_video_std_frame_period(vv->standard->id,
+ &parm->parm.capture.timeperframe);
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ f->fmt.pix = vv->video_fmt;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ f->fmt.win = vv->ov.win;
+ return 0;
+}
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ f->fmt.vbi = vv->vbi_fmt;
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_format *fmt;
+ enum v4l2_field field;
+ int maxw, maxh;
+ int calc_bpl;
+
+ DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
+
+ fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ maxw = vv->standard->h_max_out;
+ maxh = vv->standard->v_max_out;
+
+ if (V4L2_FIELD_ANY == field) {
+ field = (f->fmt.pix.height > maxh / 2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ }
+ switch (field) {
+ case V4L2_FIELD_ALTERNATE:
+ vv->last_field = V4L2_FIELD_TOP;
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ vv->last_field = V4L2_FIELD_INTERLACED;
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ vv->last_field = V4L2_FIELD_INTERLACED;
+ break;
+ default:
+ DEB_D("no known field mode '%d'\n", field);
+ return -EINVAL;
+ }
+
+ f->fmt.pix.field = field;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+
+ calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;
+
+ if (f->fmt.pix.bytesperline < calc_bpl)
+ f->fmt.pix.bytesperline = calc_bpl;
+
+ if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */
+ f->fmt.pix.bytesperline = calc_bpl;
+
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+ DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",
+ f->fmt.pix.width, f->fmt.pix.height,
+ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+
+ return 0;
+}
+
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct v4l2_window *win = &f->fmt.win;
+ enum v4l2_field field;
+ int maxw, maxh;
+
+ DEB_EE("dev:%p\n", dev);
+
+ if (NULL == vv->ov_fb.base) {
+ DEB_D("no fb base set\n");
+ return -EINVAL;
+ }
+ if (NULL == vv->ov_fmt) {
+ DEB_D("no fb fmt set\n");
+ return -EINVAL;
+ }
+ if (win->w.width < 48 || win->w.height < 32) {
+ DEB_D("min width/height. (%d,%d)\n",
+ win->w.width, win->w.height);
+ return -EINVAL;
+ }
+ if (win->clipcount > 16) {
+ DEB_D("clipcount too big\n");
+ return -EINVAL;
+ }
+
+ field = win->field;
+ maxw = vv->standard->h_max_out;
+ maxh = vv->standard->v_max_out;
+
+ if (V4L2_FIELD_ANY == field) {
+ field = (win->w.height > maxh / 2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_TOP;
+ }
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_ALTERNATE:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ DEB_D("no known field mode '%d'\n", field);
+ return -EINVAL;
+ }
+
+ win->field = field;
+ if (win->w.width > maxw)
+ win->w.width = maxw;
+ if (win->w.height > maxh)
+ win->w.height = maxh;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f)
+{
+ struct saa7146_fh *fh = __fh;
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ int err;
+
+ DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);
+ if (IS_CAPTURE_ACTIVE(fh) != 0) {
+ DEB_EE("streaming capture is active\n");
+ return -EBUSY;
+ }
+ err = vidioc_try_fmt_vid_cap(file, fh, f);
+ if (0 != err)
+ return err;
+ vv->video_fmt = f->fmt.pix;
+ DEB_EE("set to pixelformat '%4.4s'\n",
+ (char *)&vv->video_fmt.pixelformat);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f)
+{
+ struct saa7146_fh *fh = __fh;
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ int err;
+
+ DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh);
+ err = vidioc_try_fmt_vid_overlay(file, fh, f);
+ if (0 != err)
+ return err;
+ vv->ov.win = f->fmt.win;
+ vv->ov.nclips = f->fmt.win.clipcount;
+ if (vv->ov.nclips > 16)
+ vv->ov.nclips = 16;
+ if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
+ sizeof(struct v4l2_clip) * vv->ov.nclips)) {
+ return -EFAULT;
+ }
+
+ /* vv->ov.fh is used to indicate that we have valid overlay informations, too */
+ vv->ov.fh = fh;
+
+ /* check if our current overlay is active */
+ if (IS_OVERLAY_ACTIVE(fh) != 0) {
+ saa7146_stop_preview(fh);
+ saa7146_start_preview(fh);
+ }
+ return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ *norm = vv->standard->id;
+ return 0;
+}
+
+ /* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
+ PAL / NTSC / SECAM. if your hardware does not (or does more)
+ -- override this function in your extension */
+/*
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+ if (e->index < 0 )
+ return -EINVAL;
+ if( e->index < dev->ext_vv_data->num_stds ) {
+ DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index);
+ v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
+ return 0;
+ }
+ return -EINVAL;
+ }
+ */
+
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ int found = 0;
+ int err, i;
+
+ DEB_EE("VIDIOC_S_STD\n");
+
+ if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
+ DEB_D("cannot change video standard while streaming capture is active\n");
+ return -EBUSY;
+ }
+
+ if ((vv->video_status & STATUS_OVERLAY) != 0) {
+ vv->ov_suspend = vv->video_fh;
+ err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
+ if (0 != err) {
+ DEB_D("suspending video failed. aborting\n");
+ return err;
+ }
+ }
+
+ for (i = 0; i < dev->ext_vv_data->num_stds; i++)
+ if (id & dev->ext_vv_data->stds[i].id)
+ break;
+ if (i != dev->ext_vv_data->num_stds) {
+ vv->standard = &dev->ext_vv_data->stds[i];
+ if (NULL != dev->ext_vv_data->std_callback)
+ dev->ext_vv_data->std_callback(dev, vv->standard);
+ found = 1;
+ }
+
+ if (vv->ov_suspend != NULL) {
+ saa7146_start_preview(vv->ov_suspend);
+ vv->ov_suspend = NULL;
+ }
+
+ if (!found) {
+ DEB_EE("VIDIOC_S_STD: standard not found\n");
+ return -EINVAL;
+ }
+
+ DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);
+ return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned int on)
+{
+ int err;
+
+ DEB_D("VIDIOC_OVERLAY on:%d\n", on);
+ if (on)
+ err = saa7146_start_preview(fh);
+ else
+ err = saa7146_stop_preview(fh);
+ return err;
+}
+
+static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b)
+{
+ struct saa7146_fh *fh = __fh;
+
+ if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_reqbufs(&fh->video_q, b);
+ if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ return videobuf_reqbufs(&fh->vbi_q, b);
+ return -EINVAL;
+}
+
+static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+ struct saa7146_fh *fh = __fh;
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_querybuf(&fh->video_q, buf);
+ if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ return videobuf_querybuf(&fh->vbi_q, buf);
+ return -EINVAL;
+}
+
+static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+ struct saa7146_fh *fh = __fh;
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_qbuf(&fh->video_q, buf);
+ if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ return videobuf_qbuf(&fh->vbi_q, buf);
+ return -EINVAL;
+}
+
+static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
+{
+ struct saa7146_fh *fh = __fh;
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK);
+ if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK);
+ return -EINVAL;
+}
+
+static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+ struct saa7146_fh *fh = __fh;
+ int err;
+
+ DEB_D("VIDIOC_STREAMON, type:%d\n", type);
+
+ err = video_begin(fh);
+ if (err)
+ return err;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return videobuf_streamon(&fh->video_q);
+ if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ return videobuf_streamon(&fh->vbi_q);
+ return -EINVAL;
+}
+
+static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
+{
+ struct saa7146_fh *fh = __fh;
+ struct saa7146_dev *dev = fh->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+ int err;
+
+ DEB_D("VIDIOC_STREAMOFF, type:%d\n", type);
+
+ /* ugly: we need to copy some checks from video_end(),
+ because videobuf_streamoff() relies on the capture running.
+ check and fix this */
+ if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
+ DEB_S("not capturing\n");
+ return 0;
+ }
+
+ if (vv->video_fh != fh) {
+ DEB_S("capturing, but in another open\n");
+ return -EBUSY;
+ }
+
+ err = -EINVAL;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ err = videobuf_streamoff(&fh->video_q);
+ else if (type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ err = videobuf_streamoff(&fh->vbi_q);
+ if (0 != err) {
+ DEB_D("warning: videobuf_streamoff() failed\n");
+ video_end(fh, file);
+ } else {
+ err = video_end(fh, file);
+ }
+ return err;
+}
+
+const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
+
+ .vidioc_overlay = vidioc_overlay,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+ .vidioc_s_fbuf = vidioc_s_fbuf,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*********************************************************************************/
+/* buffer handling functions */
+
+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;
+ saa7146_set_capture(dev,buf,next);
+
+ mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
+ return 0;
+}
+
+static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
+{
+ saa7146_pgtable_free(dev->pci, &buf->pt[0]);
+ saa7146_pgtable_free(dev->pci, &buf->pt[1]);
+ saa7146_pgtable_free(dev->pci, &buf->pt[2]);
+}
+
+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_vv *vv = dev->vv_data;
+ struct saa7146_buf *buf = (struct saa7146_buf *)vb;
+ int size,err = 0;
+
+ DEB_CAP("vbuf:%p\n", vb);
+
+ /* sanity checks */
+ if (vv->video_fmt.width < 48 ||
+ vv->video_fmt.height < 32 ||
+ vv->video_fmt.width > vv->standard->h_max_out ||
+ vv->video_fmt.height > vv->standard->v_max_out) {
+ DEB_D("w (%d) / h (%d) out of bounds\n",
+ vv->video_fmt.width, vv->video_fmt.height);
+ return -EINVAL;
+ }
+
+ size = vv->video_fmt.sizeimage;
+ if (0 != buf->vb.baddr && buf->vb.bsize < size) {
+ DEB_D("size mismatch\n");
+ return -EINVAL;
+ }
+
+ DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
+ vv->video_fmt.width, vv->video_fmt.height,
+ size, v4l2_field_names[vv->video_fmt.field]);
+ if (buf->vb.width != vv->video_fmt.width ||
+ buf->vb.bytesperline != vv->video_fmt.bytesperline ||
+ buf->vb.height != vv->video_fmt.height ||
+ buf->vb.size != size ||
+ buf->vb.field != field ||
+ buf->vb.field != vv->video_fmt.field ||
+ buf->fmt != &vv->video_fmt) {
+ saa7146_dma_free(dev,q,buf);
+ }
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ struct saa7146_format *sfmt;
+
+ buf->vb.bytesperline = vv->video_fmt.bytesperline;
+ buf->vb.width = vv->video_fmt.width;
+ buf->vb.height = vv->video_fmt.height;
+ buf->vb.size = size;
+ buf->vb.field = field;
+ buf->fmt = &vv->video_fmt;
+ buf->vb.field = vv->video_fmt.field;
+
+ sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
+
+ release_all_pagetables(dev, buf);
+ if( 0 != IS_PLANAR(sfmt->trans)) {
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
+ } else {
+ saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
+ }
+
+ err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
+ if (err)
+ goto oops;
+ err = saa7146_pgtable_build(dev,buf);
+ if (err)
+ goto oops;
+ }
+ buf->vb.state = VIDEOBUF_PREPARED;
+ buf->activate = buffer_activate;
+
+ return 0;
+
+ oops:
+ DEB_D("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)
+{
+ struct file *file = q->priv_data;
+ struct saa7146_fh *fh = file->private_data;
+ struct saa7146_vv *vv = fh->dev->vv_data;
+
+ if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
+ *count = MAX_SAA7146_CAPTURE_BUFFERS;
+
+ *size = vv->video_fmt.sizeimage;
+
+ /* check if we exceed the "max_memory" parameter */
+ if( (*count * *size) > (max_memory*1048576) ) {
+ *count = (max_memory*1048576) / *size;
+ }
+
+ DEB_CAP("%d buffers, %d bytes each\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_CAP("vbuf:%p\n", vb);
+ saa7146_buffer_queue(fh->dev, &vv->video_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_CAP("vbuf:%p\n", vb);
+
+ saa7146_dma_free(dev,q,buf);
+
+ release_all_pagetables(dev, buf);
+}
+
+static struct videobuf_queue_ops video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************************************************************************/
+/* file operations */
+
+static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
+{
+ INIT_LIST_HEAD(&vv->video_dmaq.queue);
+
+ init_timer(&vv->video_dmaq.timeout);
+ vv->video_dmaq.timeout.function = saa7146_buffer_timeout;
+ vv->video_dmaq.timeout.data = (unsigned long)(&vv->video_dmaq);
+ vv->video_dmaq.dev = dev;
+
+ /* set some default values */
+ vv->standard = &dev->ext_vv_data->stds[0];
+
+ /* FIXME: what's this? */
+ vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
+ vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
+}
+
+
+static int video_open(struct saa7146_dev *dev, struct file *file)
+{
+ struct saa7146_fh *fh = file->private_data;
+
+ videobuf_queue_sg_init(&fh->video_q, &video_qops,
+ &dev->pci->dev, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct saa7146_buf),
+ file, &dev->v4l2_lock);
+
+ return 0;
+}
+
+
+static void video_close(struct saa7146_dev *dev, struct file *file)
+{
+ struct saa7146_fh *fh = file->private_data;
+ struct saa7146_vv *vv = dev->vv_data;
+ struct videobuf_queue *q = &fh->video_q;
+
+ if (IS_CAPTURE_ACTIVE(fh) != 0)
+ video_end(fh, file);
+ else if (IS_OVERLAY_ACTIVE(fh) != 0)
+ saa7146_stop_preview(fh);
+
+ videobuf_stop(q);
+ /* hmm, why is this function declared void? */
+}
+
+
+static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
+{
+ struct saa7146_vv *vv = dev->vv_data;
+ struct saa7146_dmaqueue *q = &vv->video_dmaq;
+
+ spin_lock(&dev->slock);
+ DEB_CAP("called\n");
+
+ /* only finish the buffer if we have one... */
+ if( NULL != q->curr ) {
+ saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
+ }
+ saa7146_buffer_next(dev,q,0);
+
+ spin_unlock(&dev->slock);
+}
+
+static ssize_t video_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_EE("called\n");
+
+ if ((vv->video_status & STATUS_CAPTURE) != 0) {
+ /* fixme: should we allow read() captures while streaming capture? */
+ if (vv->video_fh == fh) {
+ DEB_S("already capturing\n");
+ return -EBUSY;
+ }
+ DEB_S("already capturing in another open\n");
+ return -EBUSY;
+ }
+
+ ret = video_begin(fh);
+ if( 0 != ret) {
+ goto out;
+ }
+
+ ret = videobuf_read_one(&fh->video_q , data, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ if (ret != 0) {
+ video_end(fh, file);
+ } else {
+ ret = video_end(fh, file);
+ }
+out:
+ /* restart overlay if it was active before */
+ if (vv->ov_suspend != NULL) {
+ saa7146_start_preview(vv->ov_suspend);
+ vv->ov_suspend = NULL;
+ }
+
+ return ret;
+}
+
+struct saa7146_use_ops saa7146_video_uops = {
+ .init = video_init,
+ .open = video_open,
+ .release = video_close,
+ .irq_done = video_irq_done,
+ .read = video_read,
+};
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
deleted file mode 100644
index 66fdbd0e6a6..00000000000
--- a/drivers/media/common/saa7146_video.c
+++ /dev/null
@@ -1,1508 +0,0 @@
-#include <media/saa7146_vv.h>
-
-static int max_memory = 32;
-
-module_param(max_memory, int, 0644);
-MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)");
-
-#define IS_CAPTURE_ACTIVE(fh) \
- (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh))
-
-#define IS_OVERLAY_ACTIVE(fh) \
- (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh))
-
-/* format descriptions for capture and preview */
-static struct saa7146_format formats[] = {
- {
- .name = "RGB-8 (3-3-2)",
- .pixelformat = V4L2_PIX_FMT_RGB332,
- .trans = RGB08_COMPOSED,
- .depth = 8,
- .flags = 0,
- }, {
- .name = "RGB-16 (5/B-6/G-5/R)",
- .pixelformat = V4L2_PIX_FMT_RGB565,
- .trans = RGB16_COMPOSED,
- .depth = 16,
- .flags = 0,
- }, {
- .name = "RGB-24 (B-G-R)",
- .pixelformat = V4L2_PIX_FMT_BGR24,
- .trans = RGB24_COMPOSED,
- .depth = 24,
- .flags = 0,
- }, {
- .name = "RGB-32 (B-G-R)",
- .pixelformat = V4L2_PIX_FMT_BGR32,
- .trans = RGB32_COMPOSED,
- .depth = 32,
- .flags = 0,
- }, {
- .name = "RGB-32 (R-G-B)",
- .pixelformat = V4L2_PIX_FMT_RGB32,
- .trans = RGB32_COMPOSED,
- .depth = 32,
- .flags = 0,
- .swap = 0x2,
- }, {
- .name = "Greyscale-8",
- .pixelformat = V4L2_PIX_FMT_GREY,
- .trans = Y8,
- .depth = 8,
- .flags = 0,
- }, {
- .name = "YUV 4:2:2 planar (Y-Cb-Cr)",
- .pixelformat = V4L2_PIX_FMT_YUV422P,
- .trans = YUV422_DECOMPOSED,
- .depth = 16,
- .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
- }, {
- .name = "YVU 4:2:0 planar (Y-Cb-Cr)",
- .pixelformat = V4L2_PIX_FMT_YVU420,
- .trans = YUV420_DECOMPOSED,
- .depth = 12,
- .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,
- }, {
- .name = "YUV 4:2:0 planar (Y-Cb-Cr)",
- .pixelformat = V4L2_PIX_FMT_YUV420,
- .trans = YUV420_DECOMPOSED,
- .depth = 12,
- .flags = FORMAT_IS_PLANAR,
- }, {
- .name = "YUV 4:2:2 (U-Y-V-Y)",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- .trans = YUV422_COMPOSED,
- .depth = 16,
- .flags = 0,
- }
-};
-
-/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.
- due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped
- (like V4L2_PIX_FMT_YUYV) ... 8-( */
-
-static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
-
-struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
-{
- int i, j = NUM_FORMATS;
-
- for (i = 0; i < j; i++) {
- if (formats[i].pixelformat == fourcc) {
- return formats+i;
- }
- }
-
- DEB_D(("unknown pixelformat:'%4.4s'\n",(char *)&fourcc));
- return NULL;
-}
-
-static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
-{
- struct saa7146_dev *dev = fh->dev;
- DEB_EE(("dev:%p, fh:%p\n",dev,fh));
-
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- f->fmt.pix = fh->video_fmt;
- return 0;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- f->fmt.win = fh->ov.win;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- {
- f->fmt.vbi = fh->vbi_fmt;
- return 0;
- }
- default:
- DEB_D(("invalid format type '%d'.\n",f->type));
- return -EINVAL;
- }
-}
-
-static int try_win(struct saa7146_dev *dev, struct v4l2_window *win)
-{
- struct saa7146_vv *vv = dev->vv_data;
- enum v4l2_field field;
- int maxw, maxh;
-
- DEB_EE(("dev:%p\n",dev));
-
- if (NULL == vv->ov_fb.base) {
- DEB_D(("no fb base set.\n"));
- return -EINVAL;
- }
- if (NULL == vv->ov_fmt) {
- DEB_D(("no fb fmt set.\n"));
- return -EINVAL;
- }
- if (win->w.width < 48 || win->w.height < 32) {
- DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height));
- return -EINVAL;
- }
- if (win->clipcount > 16) {
- DEB_D(("clipcount too big.\n"));
- return -EINVAL;
- }
-
- field = win->field;
- maxw = vv->standard->h_max_out;
- maxh = vv->standard->v_max_out;
-
- if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_ALTERNATE:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default: {
- DEB_D(("no known field mode '%d'.\n",field));
- return -EINVAL;
- }
- }
-
- win->field = field;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
-
- return 0;
-}
-
-static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- int err;
-
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- struct saa7146_format *fmt;
- enum v4l2_field field;
- int maxw, maxh;
- int calc_bpl;
-
- DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
-
- fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat);
- if (NULL == fmt) {
- return -EINVAL;
- }
-
- field = f->fmt.pix.field;
- maxw = vv->standard->h_max_out;
- maxh = vv->standard->v_max_out;
-
- if (V4L2_FIELD_ANY == field) {
- field = (f->fmt.pix.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_BOTTOM;
- }
- switch (field) {
- case V4L2_FIELD_ALTERNATE: {
- vv->last_field = V4L2_FIELD_TOP;
- maxh = maxh / 2;
- break;
- }
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- vv->last_field = V4L2_FIELD_INTERLACED;
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- vv->last_field = V4L2_FIELD_INTERLACED;
- break;
- default: {
- DEB_D(("no known field mode '%d'.\n",field));
- return -EINVAL;
- }
- }
-
- f->fmt.pix.field = field;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
-
- calc_bpl = (f->fmt.pix.width * fmt->depth)/8;
-
- if (f->fmt.pix.bytesperline < calc_bpl)
- f->fmt.pix.bytesperline = calc_bpl;
-
- if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */
- f->fmt.pix.bytesperline = calc_bpl;
-
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
- DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage));
-
- return 0;
- }
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
- err = try_win(dev,&f->fmt.win);
- if (0 != err) {
- return err;
- }
- return 0;
- default:
- DEB_EE(("unknown format type '%d'\n",f->type));
- return -EINVAL;
- }
-}
-
-int saa7146_start_preview(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- int ret = 0, err = 0;
-
- DEB_EE(("dev:%p, fh:%p\n",dev,fh));
-
- /* check if we have overlay informations */
- if( NULL == fh->ov.fh ) {
- DEB_D(("no overlay data available. try S_FMT first.\n"));
- return -EAGAIN;
- }
-
- /* check if streaming capture is running */
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D(("streaming capture is active.\n"));
- return -EBUSY;
- }
-
- /* check if overlay is running */
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- if (vv->video_fh == fh) {
- DEB_D(("overlay is already active.\n"));
- return 0;
- }
- DEB_D(("overlay is already active in another open.\n"));
- return -EBUSY;
- }
-
- if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) {
- DEB_D(("cannot get necessary overlay resources\n"));
- return -EBUSY;
- }
-
- err = try_win(dev,&fh->ov.win);
- if (0 != err) {
- saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
- return -EBUSY;
- }
-
- vv->ov_data = &fh->ov;
-
- DEB_D(("%dx%d+%d+%d %s field=%s\n",
- fh->ov.win.w.width,fh->ov.win.w.height,
- fh->ov.win.w.left,fh->ov.win.w.top,
- vv->ov_fmt->name,v4l2_field_names[fh->ov.win.field]));
-
- if (0 != (ret = saa7146_enable_overlay(fh))) {
- DEB_D(("enabling overlay failed: %d\n",ret));
- saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
- return ret;
- }
-
- vv->video_status = STATUS_OVERLAY;
- vv->video_fh = fh;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-
-int saa7146_stop_preview(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- DEB_EE(("dev:%p, fh:%p\n",dev,fh));
-
- /* check if streaming capture is running */
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D(("streaming capture is active.\n"));
- return -EBUSY;
- }
-
- /* check if overlay is running at all */
- if ((vv->video_status & STATUS_OVERLAY) == 0) {
- DEB_D(("no active overlay.\n"));
- return 0;
- }
-
- if (vv->video_fh != fh) {
- DEB_D(("overlay is active, but in another open.\n"));
- return -EBUSY;
- }
-
- vv->video_status = 0;
- vv->video_fh = NULL;
-
- saa7146_disable_overlay(fh);
-
- saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- int err;
-
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh));
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_EE(("streaming capture is active\n"));
- return -EBUSY;
- }
- err = try_fmt(fh,f);
- if (0 != err)
- return err;
- fh->video_fmt = f->fmt.pix;
- DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat));
- return 0;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh));
- err = try_win(dev,&f->fmt.win);
- if (0 != err)
- return err;
- mutex_lock(&dev->lock);
- fh->ov.win = f->fmt.win;
- fh->ov.nclips = f->fmt.win.clipcount;
- if (fh->ov.nclips > 16)
- fh->ov.nclips = 16;
- if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
-
- /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
- fh->ov.fh = fh;
-
- mutex_unlock(&dev->lock);
-
- /* check if our current overlay is active */
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- saa7146_stop_preview(fh);
- saa7146_start_preview(fh);
- }
- return 0;
- default:
- DEB_D(("unknown format type '%d'\n",f->type));
- return -EINVAL;
- }
-}
-
-/********************************************************************************/
-/* device controls */
-
-static struct v4l2_queryctrl controls[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_VFLIP,
- .name = "Vertical flip",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_HFLIP,
- .name = "Horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl);
-
-#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 0)
-
-static struct v4l2_queryctrl* ctrl_by_id(int id)
-{
- int i;
-
- for (i = 0; i < NUM_CONTROLS; i++)
- if (controls[i].id == id)
- return controls+i;
- return NULL;
-}
-
-static int get_control(struct saa7146_fh *fh, struct v4l2_control *c)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- const struct v4l2_queryctrl* ctrl;
- u32 value = 0;
-
- ctrl = ctrl_by_id(c->id);
- if (NULL == ctrl)
- return -EINVAL;
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- value = saa7146_read(dev, BCS_CTRL);
- c->value = 0xff & (value >> 24);
- DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value));
- break;
- case V4L2_CID_CONTRAST:
- value = saa7146_read(dev, BCS_CTRL);
- c->value = 0x7f & (value >> 16);
- DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value));
- break;
- case V4L2_CID_SATURATION:
- value = saa7146_read(dev, BCS_CTRL);
- c->value = 0x7f & (value >> 0);
- DEB_D(("V4L2_CID_SATURATION: %d\n",c->value));
- break;
- case V4L2_CID_VFLIP:
- c->value = vv->vflip;
- DEB_D(("V4L2_CID_VFLIP: %d\n",c->value));
- break;
- case V4L2_CID_HFLIP:
- c->value = vv->hflip;
- DEB_D(("V4L2_CID_HFLIP: %d\n",c->value));
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- const struct v4l2_queryctrl* ctrl;
-
- ctrl = ctrl_by_id(c->id);
- if (NULL == ctrl) {
- DEB_D(("unknown control %d\n",c->id));
- return -EINVAL;
- }
-
- mutex_lock(&dev->lock);
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_BOOLEAN:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER:
- if (c->value < ctrl->minimum)
- c->value = ctrl->minimum;
- if (c->value > ctrl->maximum)
- c->value = ctrl->maximum;
- break;
- default:
- /* nothing */;
- };
-
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS: {
- u32 value = saa7146_read(dev, BCS_CTRL);
- value &= 0x00ffffff;
- value |= (c->value << 24);
- saa7146_write(dev, BCS_CTRL, value);
- saa7146_write(dev, MC2, MASK_22 | MASK_06 );
- break;
- }
- case V4L2_CID_CONTRAST: {
- u32 value = saa7146_read(dev, BCS_CTRL);
- value &= 0xff00ffff;
- value |= (c->value << 16);
- saa7146_write(dev, BCS_CTRL, value);
- saa7146_write(dev, MC2, MASK_22 | MASK_06 );
- break;
- }
- case V4L2_CID_SATURATION: {
- u32 value = saa7146_read(dev, BCS_CTRL);
- value &= 0xffffff00;
- value |= (c->value << 0);
- saa7146_write(dev, BCS_CTRL, value);
- saa7146_write(dev, MC2, MASK_22 | MASK_06 );
- break;
- }
- case V4L2_CID_HFLIP:
- /* fixme: we can support changing VFLIP and HFLIP here... */
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
- vv->hflip = c->value;
- break;
- case V4L2_CID_VFLIP:
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
- vv->vflip = c->value;
- break;
- default: {
- return -EINVAL;
- }
- }
- mutex_unlock(&dev->lock);
-
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- saa7146_stop_preview(fh);
- saa7146_start_preview(fh);
- }
- return 0;
-}
-
-/********************************************************************************/
-/* common pagetable functions */
-
-static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
-{
- struct pci_dev *pci = dev->pci;
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- struct scatterlist *list = dma->sglist;
- int length = dma->sglen;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
-
- DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
-
- if( 0 != IS_PLANAR(sfmt->trans)) {
- struct saa7146_pgtable *pt1 = &buf->pt[0];
- struct saa7146_pgtable *pt2 = &buf->pt[1];
- struct saa7146_pgtable *pt3 = &buf->pt[2];
- u32 *ptr1, *ptr2, *ptr3;
- u32 fill;
-
- int size = buf->fmt->width*buf->fmt->height;
- int i,p,m1,m2,m3,o1,o2;
-
- switch( sfmt->depth ) {
- case 12: {
- /* create some offsets inside the page table */
- m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
- m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1;
- m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
- o1 = size%PAGE_SIZE;
- o2 = (size+(size/4))%PAGE_SIZE;
- DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
- break;
- }
- case 16: {
- /* create some offsets inside the page table */
- m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1;
- m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1;
- m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1;
- o1 = size%PAGE_SIZE;
- o2 = (size+(size/2))%PAGE_SIZE;
- DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2));
- break;
- }
- default: {
- return -1;
- }
- }
-
- ptr1 = pt1->cpu;
- ptr2 = pt2->cpu;
- ptr3 = pt3->cpu;
-
- /* walk all pages, copy all page addresses to ptr1 */
- for (i = 0; i < length; i++, list++) {
- for (p = 0; p * 4096 < list->length; p++, ptr1++) {
- *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset);
- }
- }
-/*
- ptr1 = pt1->cpu;
- for(j=0;j<40;j++) {
- printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
- }
-*/
-
- /* if we have a user buffer, the first page may not be
- aligned to a page boundary. */
- pt1->offset = list->offset;
- pt2->offset = pt1->offset+o1;
- pt3->offset = pt1->offset+o2;
-
- /* create video-dma2 page table */
- ptr1 = pt1->cpu;
- for(i = m1; i <= m2 ; i++, ptr2++) {
- *ptr2 = ptr1[i];
- }
- fill = *(ptr2-1);
- for(;i<1024;i++,ptr2++) {
- *ptr2 = fill;
- }
- /* create video-dma3 page table */
- ptr1 = pt1->cpu;
- for(i = m2; i <= m3; i++,ptr3++) {
- *ptr3 = ptr1[i];
- }
- fill = *(ptr3-1);
- for(;i<1024;i++,ptr3++) {
- *ptr3 = fill;
- }
- /* finally: finish up video-dma1 page table */
- ptr1 = pt1->cpu+m1;
- fill = pt1->cpu[m1];
- for(i=m1;i<1024;i++,ptr1++) {
- *ptr1 = fill;
- }
-/*
- ptr1 = pt1->cpu;
- ptr2 = pt2->cpu;
- ptr3 = pt3->cpu;
- for(j=0;j<40;j++) {
- printk("ptr1 %d: 0x%08x\n",j,ptr1[j]);
- }
- for(j=0;j<40;j++) {
- printk("ptr2 %d: 0x%08x\n",j,ptr2[j]);
- }
- for(j=0;j<40;j++) {
- printk("ptr3 %d: 0x%08x\n",j,ptr3[j]);
- }
-*/
- } else {
- struct saa7146_pgtable *pt = &buf->pt[0];
- return saa7146_pgtable_build_single(pci, pt, list, length);
- }
-
- return 0;
-}
-
-
-/********************************************************************************/
-/* file operations */
-
-static int video_begin(struct saa7146_fh *fh)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *fmt = NULL;
- unsigned int resource;
- int ret = 0, err = 0;
-
- DEB_EE(("dev:%p, fh:%p\n",dev,fh));
-
- if ((vv->video_status & STATUS_CAPTURE) != 0) {
- if (vv->video_fh == fh) {
- DEB_S(("already capturing.\n"));
- return 0;
- }
- DEB_S(("already capturing in another open.\n"));
- return -EBUSY;
- }
-
- if ((vv->video_status & STATUS_OVERLAY) != 0) {
- DEB_S(("warning: suspending overlay video for streaming capture.\n"));
- vv->ov_suspend = vv->video_fh;
- err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
- if (0 != err) {
- DEB_D(("suspending video failed. aborting\n"));
- return err;
- }
- }
-
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
- /* we need to have a valid format set here */
- BUG_ON(NULL == fmt);
-
- if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
- resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
- } else {
- resource = RESOURCE_DMA1_HPS;
- }
-
- ret = saa7146_res_get(fh, resource);
- if (0 == ret) {
- DEB_S(("cannot get capture resource %d\n",resource));
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
- return -EBUSY;
- }
-
- /* clear out beginning of streaming bit (rps register 0)*/
- saa7146_write(dev, MC2, MASK_27 );
-
- /* enable rps0 irqs */
- SAA7146_IER_ENABLE(dev, MASK_27);
-
- vv->video_fh = fh;
- vv->video_status = STATUS_CAPTURE;
-
- return 0;
-}
-
-static int video_end(struct saa7146_fh *fh, struct file *file)
-{
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *fmt = NULL;
- unsigned long flags;
- unsigned int resource;
- u32 dmas = 0;
- DEB_EE(("dev:%p, fh:%p\n",dev,fh));
-
- if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
- DEB_S(("not capturing.\n"));
- return 0;
- }
-
- if (vv->video_fh != fh) {
- DEB_S(("capturing, but in another open.\n"));
- return -EBUSY;
- }
-
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
- /* we need to have a valid format set here */
- BUG_ON(NULL == fmt);
-
- if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
- resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;
- dmas = MASK_22 | MASK_21 | MASK_20;
- } else {
- resource = RESOURCE_DMA1_HPS;
- dmas = MASK_22;
- }
- spin_lock_irqsave(&dev->slock,flags);
-
- /* disable rps0 */
- saa7146_write(dev, MC1, MASK_28);
-
- /* disable rps0 irqs */
- SAA7146_IER_DISABLE(dev, MASK_27);
-
- /* shut down all used video dma transfers */
- saa7146_write(dev, MC1, dmas);
-
- spin_unlock_irqrestore(&dev->slock, flags);
-
- vv->video_fh = NULL;
- vv->video_status = 0;
-
- saa7146_res_free(fh, resource);
-
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
-
- return 0;
-}
-
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others). userspace
- * copying is done already, arg is a kernel pointer.
- */
-
-int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
-{
- struct saa7146_fh *fh = file->private_data;
- struct saa7146_dev *dev = fh->dev;
- struct saa7146_vv *vv = dev->vv_data;
-
- int err = 0, result = 0, ee = 0;
-
- struct saa7146_use_ops *ops;
- struct videobuf_queue *q;
-
- /* check if extension handles the command */
- for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) {
- if( cmd == dev->ext_vv_data->ioctls[ee].cmd )
- break;
- }
-
- if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) {
- DEB_D(("extension handles ioctl exclusive.\n"));
- result = dev->ext_vv_data->ioctl(fh, cmd, arg);
- return result;
- }
- if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) {
- DEB_D(("extension handles ioctl before.\n"));
- result = dev->ext_vv_data->ioctl(fh, cmd, arg);
- if( -EAGAIN != result ) {
- return result;
- }
- }
-
- /* fixme: add handle "after" case (is it still needed?) */
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- ops = &saa7146_video_uops;
- q = &fh->video_q;
- break;
- }
- case V4L2_BUF_TYPE_VBI_CAPTURE: {
- ops = &saa7146_vbi_uops;
- q = &fh->vbi_q;
- break;
- }
- default:
- BUG();
- return 0;
- }
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
- memset(cap,0,sizeof(*cap));
-
- DEB_EE(("VIDIOC_QUERYCAP\n"));
-
- strcpy((char *)cap->driver, "saa7146 v4l2");
- strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
- sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
- cap->version = SAA7146_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities |= dev->ext_vv_data->capabilities;
- return 0;
- }
- case VIDIOC_G_FBUF:
- {
- struct v4l2_framebuffer *fb = arg;
-
- DEB_EE(("VIDIOC_G_FBUF\n"));
-
- *fb = vv->ov_fb;
- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- return 0;
- }
- case VIDIOC_S_FBUF:
- {
- struct v4l2_framebuffer *fb = arg;
- struct saa7146_format *fmt;
-
- DEB_EE(("VIDIOC_S_FBUF\n"));
-
- if(!capable(CAP_SYS_ADMIN) &&
- !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- /* check args */
- fmt = format_by_fourcc(dev,fb->fmt.pixelformat);
- if (NULL == fmt) {
- return -EINVAL;
- }
-
- /* planar formats are not allowed for overlay video, clipping and video dma would clash */
- if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {
- DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat));
- }
-
- /* check if overlay is running */
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
- if (vv->video_fh != fh) {
- DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n"));
- return -EBUSY;
- }
- }
-
- mutex_lock(&dev->lock);
-
- /* ok, accept it */
- vv->ov_fb = *fb;
- vv->ov_fmt = fmt;
- if (0 == vv->ov_fb.fmt.bytesperline)
- vv->ov_fb.fmt.bytesperline =
- vv->ov_fb.fmt.width*fmt->depth/8;
-
- mutex_unlock(&dev->lock);
-
- return 0;
- }
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- int index;
-
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- case V4L2_BUF_TYPE_VIDEO_OVERLAY: {
- index = f->index;
- if (index < 0 || index >= NUM_FORMATS) {
- return -EINVAL;
- }
- memset(f,0,sizeof(*f));
- f->index = index;
- strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
- f->pixelformat = formats[index].pixelformat;
- break;
- }
- default:
- return -EINVAL;
- }
-
- DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index));
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- const struct v4l2_queryctrl *ctrl;
- struct v4l2_queryctrl *c = arg;
-
- if ((c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1) &&
- (c->id < V4L2_CID_PRIVATE_BASE ||
- c->id >= V4L2_CID_PRIVATE_LASTP1))
- return -EINVAL;
-
- ctrl = ctrl_by_id(c->id);
- if( NULL == ctrl ) {
- return -EINVAL;
-/*
- c->flags = V4L2_CTRL_FLAG_DISABLED;
- return 0;
-*/
- }
-
- DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id));
- *c = *ctrl;
- return 0;
- }
- case VIDIOC_G_CTRL: {
- DEB_EE(("VIDIOC_G_CTRL\n"));
- return get_control(fh,arg);
- }
- case VIDIOC_S_CTRL:
- {
- DEB_EE(("VIDIOC_S_CTRL\n"));
- err = set_control(fh,arg);
- return err;
- }
- case VIDIOC_G_PARM:
- {
- struct v4l2_streamparm *parm = arg;
- if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) {
- return -EINVAL;
- }
- memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm));
- parm->parm.capture.readbuffers = 1;
- // fixme: only for PAL!
- parm->parm.capture.timeperframe.numerator = 1;
- parm->parm.capture.timeperframe.denominator = 25;
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
- DEB_EE(("VIDIOC_G_FMT\n"));
- return g_fmt(fh,f);
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
- DEB_EE(("VIDIOC_S_FMT\n"));
- return s_fmt(fh,f);
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- DEB_EE(("VIDIOC_TRY_FMT\n"));
- return try_fmt(fh,f);
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
- DEB_EE(("VIDIOC_G_STD\n"));
- *id = vv->standard->id;
- return 0;
- }
- /* the saa7146 supfhrts (used in conjunction with the saa7111a for example)
- PAL / NTSC / SECAM. if your hardware does not (or does more)
- -- override this function in your extension */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- if (e->index < 0 )
- return -EINVAL;
- if( e->index < dev->ext_vv_data->num_stds ) {
- DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index));
- v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name);
- return 0;
- }
- return -EINVAL;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- int found = 0;
- int i, err;
-
- DEB_EE(("VIDIOC_S_STD\n"));
-
- if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) {
- DEB_D(("cannot change video standard while streaming capture is active\n"));
- return -EBUSY;
- }
-
- if ((vv->video_status & STATUS_OVERLAY) != 0) {
- vv->ov_suspend = vv->video_fh;
- err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
- if (0 != err) {
- DEB_D(("suspending video failed. aborting\n"));
- return err;
- }
- }
-
- mutex_lock(&dev->lock);
-
- for(i = 0; i < dev->ext_vv_data->num_stds; i++)
- if (*id & dev->ext_vv_data->stds[i].id)
- break;
- if (i != dev->ext_vv_data->num_stds) {
- vv->standard = &dev->ext_vv_data->stds[i];
- if( NULL != dev->ext_vv_data->std_callback )
- dev->ext_vv_data->std_callback(dev, vv->standard);
- found = 1;
- }
-
- mutex_unlock(&dev->lock);
-
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
-
- if( 0 == found ) {
- DEB_EE(("VIDIOC_S_STD: standard not found.\n"));
- return -EINVAL;
- }
-
- DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name));
- return 0;
- }
- case VIDIOC_OVERLAY:
- {
- int on = *(int *)arg;
- int err = 0;
-
- DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
- if (on != 0) {
- err = saa7146_start_preview(fh);
- } else {
- err = saa7146_stop_preview(fh);
- }
- return err;
- }
- case VIDIOC_REQBUFS: {
- struct v4l2_requestbuffers *req = arg;
- DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type));
- return videobuf_reqbufs(q,req);
- }
- case VIDIOC_QUERYBUF: {
- struct v4l2_buffer *buf = arg;
- DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset));
- return videobuf_querybuf(q,buf);
- }
- case VIDIOC_QBUF: {
- struct v4l2_buffer *buf = arg;
- int ret = 0;
- ret = videobuf_qbuf(q,buf);
- DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index));
- return ret;
- }
- case VIDIOC_DQBUF: {
- struct v4l2_buffer *buf = arg;
- int ret = 0;
- ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK);
- DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index));
- return ret;
- }
- case VIDIOC_STREAMON: {
- int *type = arg;
- DEB_D(("VIDIOC_STREAMON, type:%d\n",*type));
-
- err = video_begin(fh);
- if( 0 != err) {
- return err;
- }
- err = videobuf_streamon(q);
- return err;
- }
- case VIDIOC_STREAMOFF: {
- int *type = arg;
-
- DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type));
-
- /* ugly: we need to copy some checks from video_end(),
- because videobuf_streamoff() relies on the capture running.
- check and fix this */
- if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) {
- DEB_S(("not capturing.\n"));
- return 0;
- }
-
- if (vv->video_fh != fh) {
- DEB_S(("capturing, but in another open.\n"));
- return -EBUSY;
- }
-
- err = videobuf_streamoff(q);
- if (0 != err) {
- DEB_D(("warning: videobuf_streamoff() failed.\n"));
- video_end(fh, file);
- } else {
- err = video_end(fh, file);
- }
- return err;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
- int i;
-
- /* fixme: number of capture buffers and sizes for v4l apps */
- int gbuffers = 2;
- int gbufsize = 768*576*4;
-
- DEB_D(("VIDIOCGMBUF \n"));
-
- q = &fh->video_q;
- err = videobuf_mmap_setup(q,gbuffers,gbufsize,
- V4L2_MEMORY_MMAP);
- if (err < 0)
- return err;
-
- gbuffers = err;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = gbuffers;
- mbuf->size = gbuffers * gbufsize;
- for (i = 0; i < gbuffers; i++)
- mbuf->offsets[i] = i * gbufsize;
- return 0;
- }
-#endif
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- saa7146_video_do_ioctl);
- }
- return 0;
-}
-
-/*********************************************************************************/
-/* buffer handling functions */
-
-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;
- saa7146_set_capture(dev,buf,next);
-
- mod_timer(&vv->video_q.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_vv *vv = dev->vv_data;
- struct saa7146_buf *buf = (struct saa7146_buf *)vb;
- int size,err = 0;
-
- DEB_CAP(("vbuf:%p\n",vb));
-
- /* sanity checks */
- if (fh->video_fmt.width < 48 ||
- fh->video_fmt.height < 32 ||
- fh->video_fmt.width > vv->standard->h_max_out ||
- fh->video_fmt.height > vv->standard->v_max_out) {
- DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height));
- return -EINVAL;
- }
-
- size = fh->video_fmt.sizeimage;
- if (0 != buf->vb.baddr && buf->vb.bsize < size) {
- DEB_D(("size mismatch.\n"));
- return -EINVAL;
- }
-
- DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
- fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field]));
- if (buf->vb.width != fh->video_fmt.width ||
- buf->vb.bytesperline != fh->video_fmt.bytesperline ||
- buf->vb.height != fh->video_fmt.height ||
- buf->vb.size != size ||
- buf->vb.field != field ||
- buf->vb.field != fh->video_fmt.field ||
- buf->fmt != &fh->video_fmt) {
- saa7146_dma_free(dev,q,buf);
- }
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- struct saa7146_format *sfmt;
-
- buf->vb.bytesperline = fh->video_fmt.bytesperline;
- buf->vb.width = fh->video_fmt.width;
- buf->vb.height = fh->video_fmt.height;
- buf->vb.size = size;
- buf->vb.field = field;
- buf->fmt = &fh->video_fmt;
- buf->vb.field = fh->video_fmt.field;
-
- sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
-
- if( 0 != IS_PLANAR(sfmt->trans)) {
- saa7146_pgtable_free(dev->pci, &buf->pt[0]);
- saa7146_pgtable_free(dev->pci, &buf->pt[1]);
- saa7146_pgtable_free(dev->pci, &buf->pt[2]);
-
- saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
- saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
- saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
- } else {
- saa7146_pgtable_free(dev->pci, &buf->pt[0]);
- saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
- }
-
- err = videobuf_iolock(q,&buf->vb, &vv->ov_fb);
- if (err)
- goto oops;
- err = saa7146_pgtable_build(dev,buf);
- if (err)
- goto oops;
- }
- buf->vb.state = VIDEOBUF_PREPARED;
- buf->activate = buffer_activate;
-
- return 0;
-
- oops:
- DEB_D(("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)
-{
- struct file *file = q->priv_data;
- struct saa7146_fh *fh = file->private_data;
-
- if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
- *count = MAX_SAA7146_CAPTURE_BUFFERS;
-
- *size = fh->video_fmt.sizeimage;
-
- /* check if we exceed the "max_memory" parameter */
- if( (*count * *size) > (max_memory*1048576) ) {
- *count = (max_memory*1048576) / *size;
- }
-
- DEB_CAP(("%d buffers, %d bytes each.\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_CAP(("vbuf:%p\n",vb));
- saa7146_buffer_queue(fh->dev,&vv->video_q,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_CAP(("vbuf:%p\n",vb));
- saa7146_dma_free(dev,q,buf);
-}
-
-static struct videobuf_queue_ops video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/********************************************************************************/
-/* file operations */
-
-static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
-{
- INIT_LIST_HEAD(&vv->video_q.queue);
-
- init_timer(&vv->video_q.timeout);
- vv->video_q.timeout.function = saa7146_buffer_timeout;
- vv->video_q.timeout.data = (unsigned long)(&vv->video_q);
- vv->video_q.dev = dev;
-
- /* set some default values */
- vv->standard = &dev->ext_vv_data->stds[0];
-
- /* FIXME: what's this? */
- vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;
- vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;
-}
-
-
-static int video_open(struct saa7146_dev *dev, struct file *file)
-{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
- struct saa7146_format *sfmt;
-
- fh->video_fmt.width = 384;
- fh->video_fmt.height = 288;
- fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24;
- fh->video_fmt.bytesperline = 0;
- fh->video_fmt.field = V4L2_FIELD_ANY;
- sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
- fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
-
- videobuf_queue_pci_init(&fh->video_q, &video_qops,
- dev->pci, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct saa7146_buf),
- file);
-
- return 0;
-}
-
-
-static void video_close(struct saa7146_dev *dev, struct file *file)
-{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
- struct saa7146_vv *vv = dev->vv_data;
- struct videobuf_queue *q = &fh->video_q;
- int err;
-
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- err = video_end(fh, file);
- } else if (IS_OVERLAY_ACTIVE(fh) != 0) {
- err = saa7146_stop_preview(fh);
- }
-
- videobuf_stop(q);
-
- /* hmm, why is this function declared void? */
- /* return err */
-}
-
-
-static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
-{
- struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_dmaqueue *q = &vv->video_q;
-
- spin_lock(&dev->slock);
- DEB_CAP(("called.\n"));
-
- /* only finish the buffer if we have one... */
- if( NULL != q->curr ) {
- saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
- }
- saa7146_buffer_next(dev,q,0);
-
- spin_unlock(&dev->slock);
-}
-
-static ssize_t video_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_EE(("called.\n"));
-
- if ((vv->video_status & STATUS_CAPTURE) != 0) {
- /* fixme: should we allow read() captures while streaming capture? */
- if (vv->video_fh == fh) {
- DEB_S(("already capturing.\n"));
- return -EBUSY;
- }
- DEB_S(("already capturing in another open.\n"));
- return -EBUSY;
- }
-
- ret = video_begin(fh);
- if( 0 != ret) {
- goto out;
- }
-
- ret = videobuf_read_one(&fh->video_q , data, count, ppos,
- file->f_flags & O_NONBLOCK);
- if (ret != 0) {
- video_end(fh, file);
- } else {
- ret = video_end(fh, file);
- }
-out:
- /* restart overlay if it was active before */
- if (vv->ov_suspend != NULL) {
- saa7146_start_preview(vv->ov_suspend);
- vv->ov_suspend = NULL;
- }
-
- return ret;
-}
-
-struct saa7146_use_ops saa7146_video_uops = {
- .init = video_init,
- .open = video_open,
- .release = video_close,
- .irq_done = video_irq_done,
- .read = video_read,
-};
diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig
new file mode 100644
index 00000000000..f953d33ee15
--- /dev/null
+++ b/drivers/media/common/siano/Kconfig
@@ -0,0 +1,33 @@
+#
+# 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
+ depends on CONFIG_SMS_USB_DRV = CONFIG_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.
diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile
new file mode 100644
index 00000000000..4c0567f106b
--- /dev/null
+++ b/drivers/media/common/siano/Makefile
@@ -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)
+
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
new file mode 100644
index 00000000000..82769993eeb
--- /dev/null
+++ b/drivers/media/common/siano/sms-cards.c
@@ -0,0 +1,358 @@
+/*
+ * 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,
+ },
+};
+
+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);
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
new file mode 100644
index 00000000000..c63b544c49c
--- /dev/null
+++ b/drivers/media/common/siano/sms-cards.h
@@ -0,0 +1,137 @@
+/*
+ * 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
+
+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__ */
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
new file mode 100644
index 00000000000..050984c5b1e
--- /dev/null
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -0,0 +1,2200 @@
+/*
+ * Siano core API module
+ *
+ * This file contains implementation for the interface to sms core component
+ *
+ * author: Uri Shkolnik
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <linux/firmware.h>
+#include <linux/wait.h>
+#include <asm/byteorder.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+#include "smsir.h"
+
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+struct smscore_device_notifyee_t {
+ struct list_head entry;
+ hotplug_t hotplug;
+};
+
+struct smscore_idlist_t {
+ struct list_head entry;
+ int id;
+ int data_type;
+};
+
+struct smscore_client_t {
+ struct list_head entry;
+ struct smscore_device_t *coredev;
+ void *context;
+ struct list_head idlist;
+ onresponse_t onresponse_handler;
+ onremove_t onremove_handler;
+};
+
+static char *siano_msgs[] = {
+ [MSG_TYPE_BASE_VAL - MSG_TYPE_BASE_VAL] = "MSG_TYPE_BASE_VAL",
+ [MSG_SMS_GET_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_REQ",
+ [MSG_SMS_GET_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_RES",
+ [MSG_SMS_MULTI_BRIDGE_CFG - MSG_TYPE_BASE_VAL] = "MSG_SMS_MULTI_BRIDGE_CFG",
+ [MSG_SMS_GPIO_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_REQ",
+ [MSG_SMS_GPIO_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_RES",
+ [MSG_SMS_GPIO_SET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_REQ",
+ [MSG_SMS_GPIO_SET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_RES",
+ [MSG_SMS_GPIO_GET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_REQ",
+ [MSG_SMS_GPIO_GET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_RES",
+ [MSG_SMS_EEPROM_BURN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_BURN_IND",
+ [MSG_SMS_LOG_ENABLE_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_REQ",
+ [MSG_SMS_LOG_ENABLE_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_RES",
+ [MSG_SMS_SET_MAX_TX_MSG_LEN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_REQ",
+ [MSG_SMS_SET_MAX_TX_MSG_LEN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_RES",
+ [MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE",
+ [MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST",
+ [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ",
+ [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES",
+ [MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND",
+ [MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND",
+ [MSG_SMS_CONFIGURE_RF_SWITCH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_REQ",
+ [MSG_SMS_CONFIGURE_RF_SWITCH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_RES",
+ [MSG_SMS_MRC_PATH_DISCONNECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_REQ",
+ [MSG_SMS_MRC_PATH_DISCONNECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_RES",
+ [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ",
+ [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES",
+ [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ",
+ [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES",
+ [MSG_WR_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_REQ",
+ [MSG_WR_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_RES",
+ [MSG_RD_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_REQ",
+ [MSG_RD_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_RES",
+ [MSG_RD_REG_ALL_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_REQ",
+ [MSG_RD_REG_ALL_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_RES",
+ [MSG_HELP_INT - MSG_TYPE_BASE_VAL] = "MSG_HELP_INT",
+ [MSG_RUN_SCRIPT_INT - MSG_TYPE_BASE_VAL] = "MSG_RUN_SCRIPT_INT",
+ [MSG_SMS_EWS_INBAND_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_REQ",
+ [MSG_SMS_EWS_INBAND_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_RES",
+ [MSG_SMS_RFS_SELECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_REQ",
+ [MSG_SMS_RFS_SELECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_RES",
+ [MSG_SMS_MB_GET_VER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_REQ",
+ [MSG_SMS_MB_GET_VER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_RES",
+ [MSG_SMS_MB_WRITE_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_REQ",
+ [MSG_SMS_MB_WRITE_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_RES",
+ [MSG_SMS_MB_READ_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_REQ",
+ [MSG_SMS_MB_READ_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_RES",
+ [MSG_SMS_RD_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_REQ",
+ [MSG_SMS_RD_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_RES",
+ [MSG_SMS_WR_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_REQ",
+ [MSG_SMS_WR_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_RES",
+ [MSG_SMS_UPDATE_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_REQ",
+ [MSG_SMS_UPDATE_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_RES",
+ [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ",
+ [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES",
+ [MSG_SMS_RF_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_REQ",
+ [MSG_SMS_RF_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_RES",
+ [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ",
+ [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES",
+ [MSG_SMS_ISDBT_SB_RECEPTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_REQ",
+ [MSG_SMS_ISDBT_SB_RECEPTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_RES",
+ [MSG_SMS_GENERIC_EPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_REQ",
+ [MSG_SMS_GENERIC_EPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_RES",
+ [MSG_SMS_GENERIC_EPROM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_REQ",
+ [MSG_SMS_GENERIC_EPROM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_RES",
+ [MSG_SMS_EEPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_REQ",
+ [MSG_SMS_EEPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_RES",
+ [MSG_SMS_CUSTOM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_REQ",
+ [MSG_SMS_CUSTOM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_RES",
+ [MSG_SMS_CUSTOM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_REQ",
+ [MSG_SMS_CUSTOM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_RES",
+ [MSG_SMS_INIT_DEVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_REQ",
+ [MSG_SMS_INIT_DEVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_RES",
+ [MSG_SMS_ATSC_SET_ALL_IP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_REQ",
+ [MSG_SMS_ATSC_SET_ALL_IP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_RES",
+ [MSG_SMS_ATSC_START_ENSEMBLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_REQ",
+ [MSG_SMS_ATSC_START_ENSEMBLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_RES",
+ [MSG_SMS_SET_OUTPUT_MODE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_REQ",
+ [MSG_SMS_SET_OUTPUT_MODE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_RES",
+ [MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES",
+ [MSG_SMS_SUB_CHANNEL_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_REQ",
+ [MSG_SMS_SUB_CHANNEL_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_RES",
+ [MSG_SMS_SUB_CHANNEL_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_REQ",
+ [MSG_SMS_SUB_CHANNEL_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_RES",
+ [MSG_SMS_ATSC_IP_FILTER_ADD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_ADD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_RES",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_RES",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES",
+ [MSG_SMS_WAIT_CMD - MSG_TYPE_BASE_VAL] = "MSG_SMS_WAIT_CMD",
+ [MSG_SMS_ADD_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_REQ",
+ [MSG_SMS_ADD_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_RES",
+ [MSG_SMS_REMOVE_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_REQ",
+ [MSG_SMS_REMOVE_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_RES",
+ [MSG_SMS_FAST_INFORMATION_CHANNEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_REQ",
+ [MSG_SMS_FAST_INFORMATION_CHANNEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_RES",
+ [MSG_SMS_DAB_CHANNEL - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_CHANNEL",
+ [MSG_SMS_GET_PID_FILTER_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_REQ",
+ [MSG_SMS_GET_PID_FILTER_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_RES",
+ [MSG_SMS_POWER_DOWN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_REQ",
+ [MSG_SMS_POWER_DOWN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_RES",
+ [MSG_SMS_ATSC_SLT_EXIST_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SLT_EXIST_IND",
+ [MSG_SMS_ATSC_NO_SLT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_NO_SLT_IND",
+ [MSG_SMS_GET_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_REQ",
+ [MSG_SMS_GET_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_RES",
+ [MSG_SMS_SEND_DUMP - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_DUMP",
+ [MSG_SMS_SCAN_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_REQ",
+ [MSG_SMS_SCAN_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_RES",
+ [MSG_SMS_SCAN_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_REQ",
+ [MSG_SMS_SCAN_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_RES",
+ [MSG_SMS_SCAN_PROGRESS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_PROGRESS_IND",
+ [MSG_SMS_SCAN_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_COMPLETE_IND",
+ [MSG_SMS_LOG_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ITEM",
+ [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ",
+ [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES",
+ [MSG_SMS_HO_PER_SLICES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PER_SLICES_IND",
+ [MSG_SMS_HO_INBAND_POWER_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_INBAND_POWER_IND",
+ [MSG_SMS_MANUAL_DEMOD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MANUAL_DEMOD_REQ",
+ [MSG_SMS_HO_TUNE_ON_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_REQ",
+ [MSG_SMS_HO_TUNE_ON_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_RES",
+ [MSG_SMS_HO_TUNE_OFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_REQ",
+ [MSG_SMS_HO_TUNE_OFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_RES",
+ [MSG_SMS_HO_PEEK_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_REQ",
+ [MSG_SMS_HO_PEEK_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_RES",
+ [MSG_SMS_HO_PEEK_FREQ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_IND",
+ [MSG_SMS_MB_ATTEN_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_REQ",
+ [MSG_SMS_MB_ATTEN_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_RES",
+ [MSG_SMS_ENABLE_STAT_IN_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_REQ",
+ [MSG_SMS_ENABLE_STAT_IN_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_RES",
+ [MSG_SMS_SET_ANTENNA_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_REQ",
+ [MSG_SMS_SET_ANTENNA_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_RES",
+ [MSG_SMS_GET_STATISTICS_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_REQ",
+ [MSG_SMS_GET_STATISTICS_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_RES",
+ [MSG_SMS_SLEEP_RESUME_COMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLEEP_RESUME_COMP_IND",
+ [MSG_SMS_SWITCH_HOST_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_REQ",
+ [MSG_SMS_SWITCH_HOST_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_RES",
+ [MSG_SMS_DATA_DOWNLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_REQ",
+ [MSG_SMS_DATA_DOWNLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_RES",
+ [MSG_SMS_DATA_VALIDITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_REQ",
+ [MSG_SMS_DATA_VALIDITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_RES",
+ [MSG_SMS_SWDOWNLOAD_TRIGGER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_REQ",
+ [MSG_SMS_SWDOWNLOAD_TRIGGER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_RES",
+ [MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ",
+ [MSG_SMS_SWDOWNLOAD_BACKDOOR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_RES",
+ [MSG_SMS_GET_VERSION_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_REQ",
+ [MSG_SMS_GET_VERSION_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_RES",
+ [MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ",
+ [MSG_SMS_CLOCK_OUTPUT_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_RES",
+ [MSG_SMS_I2C_SET_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_REQ",
+ [MSG_SMS_I2C_SET_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_RES",
+ [MSG_SMS_GENERIC_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_REQ",
+ [MSG_SMS_GENERIC_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_RES",
+ [MSG_SMS_DVBT_BDA_DATA - MSG_TYPE_BASE_VAL] = "MSG_SMS_DVBT_BDA_DATA",
+ [MSG_SW_RELOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_REQ",
+ [MSG_SMS_DATA_MSG - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_MSG",
+ [MSG_TABLE_UPLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_REQ",
+ [MSG_TABLE_UPLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_RES",
+ [MSG_SW_RELOAD_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_REQ",
+ [MSG_SW_RELOAD_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_RES",
+ [MSG_SW_RELOAD_EXEC_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_REQ",
+ [MSG_SW_RELOAD_EXEC_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_RES",
+ [MSG_SMS_SPI_INT_LINE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_REQ",
+ [MSG_SMS_SPI_INT_LINE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_RES",
+ [MSG_SMS_GPIO_CONFIG_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_REQ",
+ [MSG_SMS_GPIO_CONFIG_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_RES",
+ [MSG_SMS_WATCHDOG_ACT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_REQ",
+ [MSG_SMS_WATCHDOG_ACT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_RES",
+ [MSG_SMS_LOOPBACK_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_REQ",
+ [MSG_SMS_LOOPBACK_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_RES",
+ [MSG_SMS_RAW_CAPTURE_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_REQ",
+ [MSG_SMS_RAW_CAPTURE_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_RES",
+ [MSG_SMS_RAW_CAPTURE_ABORT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_REQ",
+ [MSG_SMS_RAW_CAPTURE_ABORT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_RES",
+ [MSG_SMS_RAW_CAPTURE_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_COMPLETE_IND",
+ [MSG_SMS_DATA_PUMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_IND",
+ [MSG_SMS_DATA_PUMP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_REQ",
+ [MSG_SMS_DATA_PUMP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_RES",
+ [MSG_SMS_FLASH_DL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FLASH_DL_REQ",
+ [MSG_SMS_EXEC_TEST_1_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_REQ",
+ [MSG_SMS_EXEC_TEST_1_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_RES",
+ [MSG_SMS_ENBALE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_REQ",
+ [MSG_SMS_ENBALE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_RES",
+ [MSG_SMS_SPI_SET_BUS_WIDTH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_REQ",
+ [MSG_SMS_SPI_SET_BUS_WIDTH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_RES",
+ [MSG_SMS_SEND_EMM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_REQ",
+ [MSG_SMS_SEND_EMM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_RES",
+ [MSG_SMS_DISABLE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_REQ",
+ [MSG_SMS_DISABLE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_RES",
+ [MSG_SMS_IS_BUF_FREE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_REQ",
+ [MSG_SMS_IS_BUF_FREE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_RES",
+ [MSG_SMS_EXT_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_REQ",
+ [MSG_SMS_EXT_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_RES",
+ [MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE",
+ [MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE",
+ [MSG_SMS_BATTERY_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_REQ",
+ [MSG_SMS_BATTERY_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_RES",
+ [MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE",
+ [MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE",
+ [MSG_SMS_FM_RADIO_BLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_FM_RADIO_BLOCK_IND",
+ [MSG_SMS_HOST_NOTIFICATION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HOST_NOTIFICATION_IND",
+ [MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE",
+ [MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE",
+ [MSG_SMS_CMMB_GET_NETWORKS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_REQ",
+ [MSG_SMS_CMMB_GET_NETWORKS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_RES",
+ [MSG_SMS_CMMB_START_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_REQ",
+ [MSG_SMS_CMMB_START_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_RES",
+ [MSG_SMS_CMMB_STOP_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_REQ",
+ [MSG_SMS_CMMB_STOP_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_RES",
+ [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ",
+ [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES",
+ [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ",
+ [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES",
+ [MSG_SMS_CMMB_START_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_REQ",
+ [MSG_SMS_CMMB_START_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_RES",
+ [MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ",
+ [MSG_SMS_CMMB_STOP_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_RES",
+ [MSG_SMS_ISDBT_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_REQ",
+ [MSG_SMS_ISDBT_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_RES",
+ [MSG_SMS_TRANSMISSION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_TRANSMISSION_IND",
+ [MSG_SMS_PID_STATISTICS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_PID_STATISTICS_IND",
+ [MSG_SMS_POWER_DOWN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_IND",
+ [MSG_SMS_POWER_DOWN_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_CONF",
+ [MSG_SMS_POWER_UP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_IND",
+ [MSG_SMS_POWER_UP_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_CONF",
+ [MSG_SMS_POWER_MODE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_REQ",
+ [MSG_SMS_POWER_MODE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_RES",
+ [MSG_SMS_DEBUG_HOST_EVENT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_REQ",
+ [MSG_SMS_DEBUG_HOST_EVENT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_RES",
+ [MSG_SMS_NEW_CRYSTAL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_REQ",
+ [MSG_SMS_NEW_CRYSTAL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_RES",
+ [MSG_SMS_CONFIG_SPI_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_REQ",
+ [MSG_SMS_CONFIG_SPI_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_RES",
+ [MSG_SMS_I2C_SHORT_STAT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SHORT_STAT_IND",
+ [MSG_SMS_START_IR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_REQ",
+ [MSG_SMS_START_IR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_RES",
+ [MSG_SMS_IR_SAMPLES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_IR_SAMPLES_IND",
+ [MSG_SMS_CMMB_CA_SERVICE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_CA_SERVICE_IND",
+ [MSG_SMS_SLAVE_DEVICE_DETECTED - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLAVE_DEVICE_DETECTED",
+ [MSG_SMS_INTERFACE_LOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_LOCK_IND",
+ [MSG_SMS_INTERFACE_UNLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_UNLOCK_IND",
+ [MSG_SMS_SEND_ROSUM_BUFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_REQ",
+ [MSG_SMS_SEND_ROSUM_BUFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_RES",
+ [MSG_SMS_ROSUM_BUFF - MSG_TYPE_BASE_VAL] = "MSG_SMS_ROSUM_BUFF",
+ [MSG_SMS_SET_AES128_KEY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_REQ",
+ [MSG_SMS_SET_AES128_KEY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_RES",
+ [MSG_SMS_MBBMS_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_REQ",
+ [MSG_SMS_MBBMS_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_RES",
+ [MSG_SMS_MBBMS_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_READ_IND",
+ [MSG_SMS_IQ_STREAM_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_REQ",
+ [MSG_SMS_IQ_STREAM_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_RES",
+ [MSG_SMS_IQ_STREAM_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_REQ",
+ [MSG_SMS_IQ_STREAM_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_RES",
+ [MSG_SMS_IQ_STREAM_DATA_BLOCK - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_DATA_BLOCK",
+ [MSG_SMS_GET_EEPROM_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_REQ",
+ [MSG_SMS_GET_EEPROM_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_RES",
+ [MSG_SMS_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SIGNAL_DETECTED_IND",
+ [MSG_SMS_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_NO_SIGNAL_IND",
+ [MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ",
+ [MSG_SMS_MRC_SHUTDOWN_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_RES",
+ [MSG_SMS_MRC_BRINGUP_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_REQ",
+ [MSG_SMS_MRC_BRINGUP_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_RES",
+ [MSG_SMS_EXTERNAL_LNA_CTRL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_REQ",
+ [MSG_SMS_EXTERNAL_LNA_CTRL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_RES",
+ [MSG_SMS_SET_PERIODIC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_REQ",
+ [MSG_SMS_SET_PERIODIC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_RES",
+ [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ",
+ [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES",
+ [LOCAL_TUNE - MSG_TYPE_BASE_VAL] = "LOCAL_TUNE",
+ [LOCAL_IFFT_H_ICI - MSG_TYPE_BASE_VAL] = "LOCAL_IFFT_H_ICI",
+ [MSG_RESYNC_REQ - MSG_TYPE_BASE_VAL] = "MSG_RESYNC_REQ",
+ [MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ",
+ [MSG_SMS_CMMB_GET_MRC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_RES",
+ [MSG_SMS_LOG_EX_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_EX_ITEM",
+ [MSG_SMS_DEVICE_DATA_LOSS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEVICE_DATA_LOSS_IND",
+ [MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND",
+ [MSG_SMS_USER_MSG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_REQ",
+ [MSG_SMS_USER_MSG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_RES",
+ [MSG_SMS_SMART_CARD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_REQ",
+ [MSG_SMS_SMART_CARD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_RES",
+ [MSG_SMS_SMART_CARD_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_REQ",
+ [MSG_SMS_SMART_CARD_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_RES",
+ [MSG_SMS_SMART_CARD_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_READ_IND",
+ [MSG_SMS_TSE_ENABLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_REQ",
+ [MSG_SMS_TSE_ENABLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_RES",
+ [MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ",
+ [MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES",
+ [MSG_SMS_LED_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_REQ",
+ [MSG_SMS_LED_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_RES",
+ [MSG_PWM_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_REQ",
+ [MSG_PWM_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_RES",
+ [MSG_SMS_CMMB_SMD_SN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_REQ",
+ [MSG_SMS_CMMB_SMD_SN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_RES",
+ [MSG_SMS_CMMB_SET_CA_CW_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_REQ",
+ [MSG_SMS_CMMB_SET_CA_CW_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_RES",
+ [MSG_SMS_CMMB_SET_CA_SALT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_REQ",
+ [MSG_SMS_CMMB_SET_CA_SALT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_RES",
+ [MSG_SMS_NSCD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_REQ",
+ [MSG_SMS_NSCD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_RES",
+ [MSG_SMS_NSCD_PROCESS_SECTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_REQ",
+ [MSG_SMS_NSCD_PROCESS_SECTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_RES",
+ [MSG_SMS_DBD_CREATE_OBJECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_REQ",
+ [MSG_SMS_DBD_CREATE_OBJECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_RES",
+ [MSG_SMS_DBD_CONFIGURE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_REQ",
+ [MSG_SMS_DBD_CONFIGURE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_RES",
+ [MSG_SMS_DBD_SET_KEYS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_REQ",
+ [MSG_SMS_DBD_SET_KEYS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_RES",
+ [MSG_SMS_DBD_PROCESS_HEADER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_REQ",
+ [MSG_SMS_DBD_PROCESS_HEADER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_RES",
+ [MSG_SMS_DBD_PROCESS_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_REQ",
+ [MSG_SMS_DBD_PROCESS_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_RES",
+ [MSG_SMS_DBD_PROCESS_GET_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_REQ",
+ [MSG_SMS_DBD_PROCESS_GET_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_RES",
+ [MSG_SMS_NSCD_OPEN_SESSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_REQ",
+ [MSG_SMS_NSCD_OPEN_SESSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_RES",
+ [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ",
+ [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES",
+ [MSG_LAST_MSG_TYPE - MSG_TYPE_BASE_VAL] = "MSG_LAST_MSG_TYPE",
+};
+
+char *smscore_translate_msg(enum msg_types msgtype)
+{
+ int i = msgtype - MSG_TYPE_BASE_VAL;
+ char *msg;
+
+ if (i < 0 || i >= ARRAY_SIZE(siano_msgs))
+ return "Unknown msg type";
+
+ msg = siano_msgs[i];
+
+ if (!*msg)
+ return "Unknown msg type";
+
+ return msg;
+}
+EXPORT_SYMBOL_GPL(smscore_translate_msg);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id)
+{
+ core->board_id = id;
+}
+
+int smscore_led_state(struct smscore_device_t *core, int led)
+{
+ if (led >= 0)
+ core->led_state = led;
+ return core->led_state;
+}
+EXPORT_SYMBOL_GPL(smscore_set_board_id);
+
+int smscore_get_board_id(struct smscore_device_t *core)
+{
+ return core->board_id;
+}
+EXPORT_SYMBOL_GPL(smscore_get_board_id);
+
+struct smscore_registry_entry_t {
+ struct list_head entry;
+ char devpath[32];
+ int mode;
+ enum sms_device_type_st type;
+};
+
+static struct list_head g_smscore_notifyees;
+static struct list_head g_smscore_devices;
+static struct mutex g_smscore_deviceslock;
+
+static struct list_head g_smscore_registry;
+static struct mutex g_smscore_registrylock;
+
+static int default_mode = DEVICE_MODE_NONE;
+
+module_param(default_mode, int, 0644);
+MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
+
+static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
+{
+ struct smscore_registry_entry_t *entry;
+ struct list_head *next;
+
+ kmutex_lock(&g_smscore_registrylock);
+ for (next = g_smscore_registry.next;
+ next != &g_smscore_registry;
+ next = next->next) {
+ entry = (struct smscore_registry_entry_t *) next;
+ if (!strcmp(entry->devpath, devpath)) {
+ kmutex_unlock(&g_smscore_registrylock);
+ return entry;
+ }
+ }
+ entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
+ if (entry) {
+ entry->mode = default_mode;
+ strcpy(entry->devpath, devpath);
+ list_add(&entry->entry, &g_smscore_registry);
+ } else
+ sms_err("failed to create smscore_registry.");
+ kmutex_unlock(&g_smscore_registrylock);
+ return entry;
+}
+
+int smscore_registry_getmode(char *devpath)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ return entry->mode;
+ else
+ sms_err("No registry found.");
+
+ return default_mode;
+}
+EXPORT_SYMBOL_GPL(smscore_registry_getmode);
+
+static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ return entry->type;
+ else
+ sms_err("No registry found.");
+
+ return -EINVAL;
+}
+
+static void smscore_registry_setmode(char *devpath, int mode)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ entry->mode = mode;
+ else
+ sms_err("No registry found.");
+}
+
+static void smscore_registry_settype(char *devpath,
+ enum sms_device_type_st type)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ entry->type = type;
+ else
+ sms_err("No registry found.");
+}
+
+
+static void list_add_locked(struct list_head *new, struct list_head *head,
+ spinlock_t *lock)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+
+ list_add(new, head);
+
+ spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * register a client callback that called when device plugged in/unplugged
+ * NOTE: if devices exist callback is called immediately for each device
+ *
+ * @param hotplug callback
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_hotplug(hotplug_t hotplug)
+{
+ struct smscore_device_notifyee_t *notifyee;
+ struct list_head *next, *first;
+ int rc = 0;
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
+ GFP_KERNEL);
+ if (notifyee) {
+ /* now notify callback about existing devices */
+ first = &g_smscore_devices;
+ for (next = first->next;
+ next != first && !rc;
+ next = next->next) {
+ struct smscore_device_t *coredev =
+ (struct smscore_device_t *) next;
+ rc = hotplug(coredev, coredev->device, 1);
+ }
+
+ if (rc >= 0) {
+ notifyee->hotplug = hotplug;
+ list_add(&notifyee->entry, &g_smscore_notifyees);
+ } else
+ kfree(notifyee);
+ } else
+ rc = -ENOMEM;
+
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(smscore_register_hotplug);
+
+/**
+ * unregister a client callback that called when device plugged in/unplugged
+ *
+ * @param hotplug callback
+ *
+ */
+void smscore_unregister_hotplug(hotplug_t hotplug)
+{
+ struct list_head *next, *first;
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ first = &g_smscore_notifyees;
+
+ for (next = first->next; next != first;) {
+ struct smscore_device_notifyee_t *notifyee =
+ (struct smscore_device_notifyee_t *) next;
+ next = next->next;
+
+ if (notifyee->hotplug == hotplug) {
+ list_del(&notifyee->entry);
+ kfree(notifyee);
+ }
+ }
+
+ kmutex_unlock(&g_smscore_deviceslock);
+}
+EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
+
+static void smscore_notify_clients(struct smscore_device_t *coredev)
+{
+ struct smscore_client_t *client;
+
+ /* the client must call smscore_unregister_client from remove handler */
+ while (!list_empty(&coredev->clients)) {
+ client = (struct smscore_client_t *) coredev->clients.next;
+ client->onremove_handler(client->context);
+ }
+}
+
+static int smscore_notify_callbacks(struct smscore_device_t *coredev,
+ struct device *device, int arrival)
+{
+ struct smscore_device_notifyee_t *elem;
+ int rc = 0;
+
+ /* note: must be called under g_deviceslock */
+
+ list_for_each_entry(elem, &g_smscore_notifyees, entry) {
+ rc = elem->hotplug(coredev, device, arrival);
+ if (rc < 0)
+ break;
+ }
+
+ return rc;
+}
+
+static struct
+smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
+ dma_addr_t common_buffer_phys)
+{
+ struct smscore_buffer_t *cb;
+
+ cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
+ if (!cb) {
+ sms_info("kzalloc(...) failed");
+ return NULL;
+ }
+
+ cb->p = buffer;
+ cb->offset_in_common = buffer - (u8 *) common_buffer;
+ cb->phys = common_buffer_phys + cb->offset_in_common;
+
+ return cb;
+}
+
+/**
+ * creates coredev object for a device, prepares buffers,
+ * creates buffer mappings, notifies registered hotplugs about new device.
+ *
+ * @param params device pointer to struct with device specific parameters
+ * and handlers
+ * @param coredev pointer to a value that receives created coredev object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_device(struct smsdevice_params_t *params,
+ struct smscore_device_t **coredev)
+{
+ struct smscore_device_t *dev;
+ u8 *buffer;
+
+ dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
+ if (!dev) {
+ sms_info("kzalloc(...) failed");
+ return -ENOMEM;
+ }
+
+ /* init list entry so it could be safe in smscore_unregister_device */
+ INIT_LIST_HEAD(&dev->entry);
+
+ /* init queues */
+ INIT_LIST_HEAD(&dev->clients);
+ INIT_LIST_HEAD(&dev->buffers);
+
+ /* init locks */
+ spin_lock_init(&dev->clientslock);
+ spin_lock_init(&dev->bufferslock);
+
+ /* init completion events */
+ init_completion(&dev->version_ex_done);
+ init_completion(&dev->data_download_done);
+ init_completion(&dev->data_validity_done);
+ init_completion(&dev->trigger_done);
+ init_completion(&dev->init_device_done);
+ init_completion(&dev->reload_start_done);
+ init_completion(&dev->resume_done);
+ init_completion(&dev->gpio_configuration_done);
+ init_completion(&dev->gpio_set_level_done);
+ init_completion(&dev->gpio_get_level_done);
+ init_completion(&dev->ir_init_done);
+
+ /* Buffer management */
+ init_waitqueue_head(&dev->buffer_mng_waitq);
+
+ /* alloc common buffer */
+ dev->common_buffer_size = params->buffer_size * params->num_buffers;
+ dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
+ &dev->common_buffer_phys,
+ GFP_KERNEL | GFP_DMA);
+ if (!dev->common_buffer) {
+ smscore_unregister_device(dev);
+ return -ENOMEM;
+ }
+
+ /* prepare dma buffers */
+ for (buffer = dev->common_buffer;
+ dev->num_buffers < params->num_buffers;
+ dev->num_buffers++, buffer += params->buffer_size) {
+ struct smscore_buffer_t *cb;
+
+ cb = smscore_createbuffer(buffer, dev->common_buffer,
+ dev->common_buffer_phys);
+ if (!cb) {
+ smscore_unregister_device(dev);
+ return -ENOMEM;
+ }
+
+ smscore_putbuffer(dev, cb);
+ }
+
+ sms_info("allocated %d buffers", dev->num_buffers);
+
+ dev->mode = DEVICE_MODE_NONE;
+ dev->board_id = SMS_BOARD_UNKNOWN;
+ dev->context = params->context;
+ dev->device = params->device;
+ dev->setmode_handler = params->setmode_handler;
+ dev->detectmode_handler = params->detectmode_handler;
+ dev->sendrequest_handler = params->sendrequest_handler;
+ dev->preload_handler = params->preload_handler;
+ dev->postload_handler = params->postload_handler;
+
+ dev->device_flags = params->flags;
+ strcpy(dev->devpath, params->devpath);
+
+ smscore_registry_settype(dev->devpath, params->device_type);
+
+ /* add device to devices list */
+ kmutex_lock(&g_smscore_deviceslock);
+ list_add(&dev->entry, &g_smscore_devices);
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ *coredev = dev;
+
+ sms_info("device %p created", dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(smscore_register_device);
+
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+ void *buffer, size_t size, struct completion *completion) {
+ int rc;
+
+ if (completion == NULL)
+ return -EINVAL;
+ init_completion(completion);
+
+ rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+ if (rc < 0) {
+ sms_info("sendrequest returned error %d", rc);
+ return rc;
+ }
+
+ return wait_for_completion_timeout(completion,
+ msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
+ 0 : -ETIME;
+}
+
+/**
+ * Starts & enables IR operations
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int smscore_init_ir(struct smscore_device_t *coredev)
+{
+ int ir_io;
+ int rc;
+ void *buffer;
+
+ coredev->ir.dev = NULL;
+ ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
+ if (ir_io) {/* only if IR port exist we use IR sub-module */
+ sms_info("IR loading");
+ rc = sms_ir_init(coredev);
+
+ if (rc != 0)
+ sms_err("Error initialization DTV IR sub-module");
+ else {
+ buffer = kmalloc(sizeof(struct sms_msg_data2) +
+ SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (buffer) {
+ struct sms_msg_data2 *msg =
+ (struct sms_msg_data2 *)
+ SMS_ALIGN_ADDRESS(buffer);
+
+ SMS_INIT_MSG(&msg->x_msg_header,
+ MSG_SMS_START_IR_REQ,
+ sizeof(struct sms_msg_data2));
+ msg->msg_data[0] = coredev->ir.controller;
+ msg->msg_data[1] = coredev->ir.timeout;
+
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header. msg_length,
+ &coredev->ir_init_done);
+
+ kfree(buffer);
+ } else
+ sms_err
+ ("Sending IR initialization message failed");
+ }
+ } else
+ sms_info("IR port has not been detected");
+
+ return 0;
+}
+
+/**
+ * configures device features according to board configuration structure.
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_configure_board(struct smscore_device_t *coredev)
+{
+ struct sms_board *board;
+
+ board = sms_get_board(coredev->board_id);
+ if (!board) {
+ sms_err("no board configuration exist.");
+ return -EINVAL;
+ }
+
+ if (board->mtu) {
+ struct sms_msg_data mtu_msg;
+ sms_debug("set max transmit unit %d", board->mtu);
+
+ mtu_msg.x_msg_header.msg_src_id = 0;
+ mtu_msg.x_msg_header.msg_dst_id = HIF_TASK;
+ mtu_msg.x_msg_header.msg_flags = 0;
+ mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ;
+ mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg);
+ mtu_msg.msg_data[0] = board->mtu;
+
+ coredev->sendrequest_handler(coredev->context, &mtu_msg,
+ sizeof(mtu_msg));
+ }
+
+ if (board->crystal) {
+ struct sms_msg_data crys_msg;
+ sms_debug("set crystal value %d", board->crystal);
+
+ SMS_INIT_MSG(&crys_msg.x_msg_header,
+ MSG_SMS_NEW_CRYSTAL_REQ,
+ sizeof(crys_msg));
+ crys_msg.msg_data[0] = board->crystal;
+
+ coredev->sendrequest_handler(coredev->context, &crys_msg,
+ sizeof(crys_msg));
+ }
+
+ return 0;
+}
+
+/**
+ * sets initial device mode and notifies client hotplugs that device is ready
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_start_device(struct smscore_device_t *coredev)
+{
+ int rc;
+ int board_id = smscore_get_board_id(coredev);
+ int mode = smscore_registry_getmode(coredev->devpath);
+
+ /* Device is initialized as DEVICE_MODE_NONE */
+ if (board_id != SMS_BOARD_UNKNOWN && mode == DEVICE_MODE_NONE)
+ mode = sms_get_board(board_id)->default_mode;
+
+ rc = smscore_set_device_mode(coredev, mode);
+ if (rc < 0) {
+ sms_info("set device mode faile , rc %d", rc);
+ return rc;
+ }
+ rc = smscore_configure_board(coredev);
+ if (rc < 0) {
+ sms_info("configure board failed , rc %d", rc);
+ return rc;
+ }
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+ smscore_init_ir(coredev);
+
+ sms_info("device %p started, rc %d", coredev, rc);
+
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(smscore_start_device);
+
+
+static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
+ void *buffer, size_t size)
+{
+ struct sms_firmware *firmware = (struct sms_firmware *) buffer;
+ struct sms_msg_data4 *msg;
+ u32 mem_address, calc_checksum = 0;
+ u32 i, *ptr;
+ u8 *payload = firmware->payload;
+ int rc = 0;
+ firmware->start_address = le32_to_cpup((__le32 *)&firmware->start_address);
+ firmware->length = le32_to_cpup((__le32 *)&firmware->length);
+
+ mem_address = firmware->start_address;
+
+ sms_info("loading FW to addr 0x%x size %d",
+ mem_address, firmware->length);
+ if (coredev->preload_handler) {
+ rc = coredev->preload_handler(coredev->context);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* PAGE_SIZE buffer shall be enough and dma aligned */
+ msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!msg)
+ return -ENOMEM;
+
+ if (coredev->mode != DEVICE_MODE_NONE) {
+ sms_debug("sending reload command.");
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_START_REQ,
+ sizeof(struct sms_msg_hdr));
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header.msg_length,
+ &coredev->reload_start_done);
+ if (rc < 0) {
+ sms_err("device reload failed, rc %d", rc);
+ goto exit_fw_download;
+ }
+ mem_address = *(u32 *) &payload[20];
+ }
+
+ for (i = 0, ptr = (u32 *)firmware->payload; i < firmware->length/4 ;
+ i++, ptr++)
+ calc_checksum += *ptr;
+
+ while (size && rc >= 0) {
+ struct sms_data_download *data_msg =
+ (struct sms_data_download *) msg;
+ int payload_size = min_t(int, size, SMS_MAX_PAYLOAD_SIZE);
+
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_DOWNLOAD_REQ,
+ (u16)(sizeof(struct sms_msg_hdr) +
+ sizeof(u32) + payload_size));
+
+ data_msg->mem_addr = mem_address;
+ memcpy(data_msg->payload, payload, payload_size);
+
+ rc = smscore_sendrequest_and_wait(coredev, data_msg,
+ data_msg->x_msg_header.msg_length,
+ &coredev->data_download_done);
+
+ payload += payload_size;
+ size -= payload_size;
+ mem_address += payload_size;
+ }
+
+ if (rc < 0)
+ goto exit_fw_download;
+
+ sms_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
+ calc_checksum);
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ,
+ sizeof(msg->x_msg_header) +
+ sizeof(u32) * 3);
+ msg->msg_data[0] = firmware->start_address;
+ /* Entry point */
+ msg->msg_data[1] = firmware->length;
+ msg->msg_data[2] = 0; /* Regular checksum*/
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header.msg_length,
+ &coredev->data_validity_done);
+ if (rc < 0)
+ goto exit_fw_download;
+
+ if (coredev->mode == DEVICE_MODE_NONE) {
+ struct sms_msg_data *trigger_msg =
+ (struct sms_msg_data *) msg;
+
+ sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
+ SMS_INIT_MSG(&msg->x_msg_header,
+ MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+ sizeof(struct sms_msg_hdr) +
+ sizeof(u32) * 5);
+
+ trigger_msg->msg_data[0] = firmware->start_address;
+ /* Entry point */
+ trigger_msg->msg_data[1] = 6; /* Priority */
+ trigger_msg->msg_data[2] = 0x200; /* Stack size */
+ trigger_msg->msg_data[3] = 0; /* Parameter */
+ trigger_msg->msg_data[4] = 4; /* Task ID */
+
+ rc = smscore_sendrequest_and_wait(coredev, trigger_msg,
+ trigger_msg->x_msg_header.msg_length,
+ &coredev->trigger_done);
+ } else {
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ,
+ sizeof(struct sms_msg_hdr));
+ rc = coredev->sendrequest_handler(coredev->context, msg,
+ msg->x_msg_header.msg_length);
+ }
+
+ if (rc < 0)
+ goto exit_fw_download;
+
+ /*
+ * backward compatibility - wait to device_ready_done for
+ * not more than 400 ms
+ */
+ msleep(400);
+
+exit_fw_download:
+ kfree(msg);
+
+ if (coredev->postload_handler) {
+ sms_debug("rc=%d, postload=0x%p", rc, coredev->postload_handler);
+ if (rc >= 0)
+ return coredev->postload_handler(coredev->context);
+ }
+
+ sms_debug("rc=%d", rc);
+ return rc;
+}
+
+static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = {
+ [SMS_NOVA_A0] = {
+ [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ,
+ [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ,
+ [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ,
+ [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ,
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ,
+ },
+ [SMS_NOVA_B0] = {
+ [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ_B0,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ_B0,
+ [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO,
+ [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO,
+ },
+ [SMS_VEGA] = {
+ [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VEGA_12MHZ,
+ },
+ [SMS_VENICE] = {
+ [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VENICE_12MHZ,
+ },
+ [SMS_MING] = {
+ [DEVICE_MODE_CMMB] = SMS_FW_CMMB_MING_APP,
+ },
+ [SMS_PELE] = {
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_PELE,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_PELE,
+ },
+ [SMS_RIO] = {
+ [DEVICE_MODE_DVBT] = SMS_FW_DVB_RIO,
+ [DEVICE_MODE_DVBH] = SMS_FW_DVBH_RIO,
+ [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_RIO,
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_RIO,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_RIO,
+ [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO_RIO,
+ [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO_RIO,
+ },
+ [SMS_DENVER_1530] = {
+ [DEVICE_MODE_ATSC] = SMS_FW_ATSC_DENVER,
+ },
+ [SMS_DENVER_2160] = {
+ [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_DENVER,
+ },
+};
+
+/**
+ * get firmware file name from one of the two mechanisms : sms_boards or
+ * smscore_fw_lkup.
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ * @param lookup if 1, always get the fw filename from smscore_fw_lkup
+ * table. if 0, try first to get from sms_boards
+ *
+ * @return 0 on success, <0 on error.
+ */
+static char *smscore_get_fw_filename(struct smscore_device_t *coredev,
+ int mode)
+{
+ char **fw;
+ int board_id = smscore_get_board_id(coredev);
+ enum sms_device_type_st type;
+
+ type = smscore_registry_gettype(coredev->devpath);
+
+ /* Prevent looking outside the smscore_fw_lkup table */
+ if (type <= SMS_UNKNOWN_TYPE || type >= SMS_NUM_OF_DEVICE_TYPES)
+ return NULL;
+ if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX)
+ return NULL;
+
+ sms_debug("trying to get fw name from sms_boards board_id %d mode %d",
+ board_id, mode);
+ fw = sms_get_board(board_id)->fw;
+ if (!fw || !fw[mode]) {
+ sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d",
+ mode, type);
+ return smscore_fw_lkup[type][mode];
+ }
+
+ return fw[mode];
+}
+
+/**
+ * loads specified firmware into a buffer and calls device loadfirmware_handler
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param filename null-terminated string specifies firmware file name
+ * @param loadfirmware_handler device handler that loads firmware
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
+ int mode,
+ loadfirmware_t loadfirmware_handler)
+{
+ int rc = -ENOENT;
+ u8 *fw_buf;
+ u32 fw_buf_size;
+ const struct firmware *fw;
+
+ char *fw_filename = smscore_get_fw_filename(coredev, mode);
+ if (!fw_filename) {
+ sms_err("mode %d not supported on this device", mode);
+ return -ENOENT;
+ }
+ sms_debug("Firmware name: %s", fw_filename);
+
+ if (loadfirmware_handler == NULL && !(coredev->device_flags
+ & SMS_DEVICE_FAMILY2))
+ return -EINVAL;
+
+ rc = request_firmware(&fw, fw_filename, coredev->device);
+ if (rc < 0) {
+ sms_err("failed to open firmware file \"%s\"", fw_filename);
+ return rc;
+ }
+ sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size);
+ fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+ GFP_KERNEL | GFP_DMA);
+ if (!fw_buf) {
+ sms_err("failed to allocate firmware buffer");
+ rc = -ENOMEM;
+ } else {
+ memcpy(fw_buf, fw->data, fw->size);
+ fw_buf_size = fw->size;
+
+ rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+ smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
+ : loadfirmware_handler(coredev->context, fw_buf,
+ fw_buf_size);
+ }
+
+ kfree(fw_buf);
+ release_firmware(fw);
+
+ return rc;
+}
+
+/**
+ * notifies all clients registered with the device, notifies hotplugs,
+ * frees all buffers and coredev object
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+void smscore_unregister_device(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb;
+ int num_buffers = 0;
+ int retry = 0;
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ /* Release input device (IR) resources */
+ sms_ir_exit(coredev);
+
+ smscore_notify_clients(coredev);
+ smscore_notify_callbacks(coredev, NULL, 0);
+
+ /* at this point all buffers should be back
+ * onresponse must no longer be called */
+
+ while (1) {
+ while (!list_empty(&coredev->buffers)) {
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
+ kfree(cb);
+ num_buffers++;
+ }
+ if (num_buffers == coredev->num_buffers)
+ break;
+ if (++retry > 10) {
+ sms_info("exiting although not all buffers released.");
+ break;
+ }
+
+ sms_info("waiting for %d buffer(s)",
+ coredev->num_buffers - num_buffers);
+ kmutex_unlock(&g_smscore_deviceslock);
+ msleep(100);
+ kmutex_lock(&g_smscore_deviceslock);
+ }
+
+ sms_info("freed %d buffers", num_buffers);
+
+ if (coredev->common_buffer)
+ dma_free_coherent(NULL, coredev->common_buffer_size,
+ coredev->common_buffer, coredev->common_buffer_phys);
+
+ kfree(coredev->fw_buf);
+
+ list_del(&coredev->entry);
+ kfree(coredev);
+
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ sms_info("device %p destroyed", coredev);
+}
+EXPORT_SYMBOL_GPL(smscore_unregister_device);
+
+static int smscore_detect_mode(struct smscore_device_t *coredev)
+{
+ void *buffer = kmalloc(sizeof(struct sms_msg_hdr) + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ struct sms_msg_hdr *msg =
+ (struct sms_msg_hdr *) SMS_ALIGN_ADDRESS(buffer);
+ int rc;
+
+ if (!buffer)
+ return -ENOMEM;
+
+ SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+ sizeof(struct sms_msg_hdr));
+
+ rc = smscore_sendrequest_and_wait(coredev, msg, msg->msg_length,
+ &coredev->version_ex_done);
+ if (rc == -ETIME) {
+ sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+
+ if (wait_for_completion_timeout(&coredev->resume_done,
+ msecs_to_jiffies(5000))) {
+ rc = smscore_sendrequest_and_wait(
+ coredev, msg, msg->msg_length,
+ &coredev->version_ex_done);
+ if (rc < 0)
+ sms_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d",
+ rc);
+ } else
+ rc = -ETIME;
+ }
+
+ kfree(buffer);
+
+ return rc;
+}
+
+/**
+ * send init device request and wait for response
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_init_device(struct smscore_device_t *coredev, int mode)
+{
+ void *buffer;
+ struct sms_msg_data *msg;
+ int rc = 0;
+
+ buffer = kmalloc(sizeof(struct sms_msg_data) +
+ SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ sms_err("Could not allocate buffer for init device message.");
+ return -ENOMEM;
+ }
+
+ msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer);
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
+ sizeof(struct sms_msg_data));
+ msg->msg_data[0] = mode;
+
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header. msg_length,
+ &coredev->init_device_done);
+
+ kfree(buffer);
+ return rc;
+}
+
+/**
+ * calls device handler to change mode of operation
+ * NOTE: stellar/usb may disconnect when changing mode
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
+{
+ int rc = 0;
+
+ sms_debug("set device mode to %d", mode);
+ if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+ if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) {
+ sms_err("invalid mode specified %d", mode);
+ return -EINVAL;
+ }
+
+ smscore_registry_setmode(coredev->devpath, mode);
+
+ if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
+ rc = smscore_detect_mode(coredev);
+ if (rc < 0) {
+ sms_err("mode detect failed %d", rc);
+ return rc;
+ }
+ }
+
+ if (coredev->mode == mode) {
+ sms_info("device mode %d already set", mode);
+ return 0;
+ }
+
+ if (!(coredev->modes_supported & (1 << mode))) {
+ rc = smscore_load_firmware_from_file(coredev,
+ mode, NULL);
+ if (rc >= 0)
+ sms_info("firmware download success");
+ } else {
+ sms_info("mode %d is already supported by running firmware",
+ mode);
+ }
+ if (coredev->fw_version >= 0x800) {
+ rc = smscore_init_device(coredev, mode);
+ if (rc < 0)
+ sms_err("device init failed, rc %d.", rc);
+ }
+ } else {
+ if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) {
+ sms_err("invalid mode specified %d", mode);
+ return -EINVAL;
+ }
+
+ smscore_registry_setmode(coredev->devpath, mode);
+
+ if (coredev->detectmode_handler)
+ coredev->detectmode_handler(coredev->context,
+ &coredev->mode);
+
+ if (coredev->mode != mode && coredev->setmode_handler)
+ rc = coredev->setmode_handler(coredev->context, mode);
+ }
+
+ if (rc >= 0) {
+ char *buffer;
+ coredev->mode = mode;
+ coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+
+ buffer = kmalloc(sizeof(struct sms_msg_data) +
+ SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+ if (buffer) {
+ struct sms_msg_data *msg = (struct sms_msg_data *) SMS_ALIGN_ADDRESS(buffer);
+
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
+ sizeof(struct sms_msg_data));
+ msg->msg_data[0] = mode;
+
+ rc = smscore_sendrequest_and_wait(
+ coredev, msg, msg->x_msg_header.msg_length,
+ &coredev->init_device_done);
+
+ kfree(buffer);
+ }
+ }
+
+ if (rc < 0)
+ sms_err("return error code %d.", rc);
+ else
+ sms_debug("Success setting device mode.");
+
+ return rc;
+}
+
+/**
+ * calls device handler to get current mode of operation
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return current mode
+ */
+int smscore_get_device_mode(struct smscore_device_t *coredev)
+{
+ return coredev->mode;
+}
+EXPORT_SYMBOL_GPL(smscore_get_device_mode);
+
+/**
+ * find client by response id & type within the clients list.
+ * return client handle or NULL.
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param data_type client data type (SMS_DONT_CARE for all types)
+ * @param id client id (SMS_DONT_CARE for all id)
+ *
+ */
+static struct
+smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
+ int data_type, int id)
+{
+ struct list_head *first;
+ struct smscore_client_t *client;
+ unsigned long flags;
+ struct list_head *firstid;
+ struct smscore_idlist_t *client_id;
+
+ spin_lock_irqsave(&coredev->clientslock, flags);
+ first = &coredev->clients;
+ list_for_each_entry(client, first, entry) {
+ firstid = &client->idlist;
+ list_for_each_entry(client_id, firstid, entry) {
+ if ((client_id->id == id) &&
+ (client_id->data_type == data_type ||
+ (client_id->data_type == 0)))
+ goto found;
+ }
+ }
+ client = NULL;
+found:
+ spin_unlock_irqrestore(&coredev->clientslock, flags);
+ return client;
+}
+
+/**
+ * find client by response id/type, call clients onresponse handler
+ * return buffer to pool on error
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param cb pointer to response buffer descriptor
+ *
+ */
+void smscore_onresponse(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb) {
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) ((u8 *) cb->p
+ + cb->offset);
+ struct smscore_client_t *client;
+ int rc = -EBUSY;
+ static unsigned long last_sample_time; /* = 0; */
+ static int data_total; /* = 0; */
+ unsigned long time_now = jiffies_to_msecs(jiffies);
+
+ if (!last_sample_time)
+ last_sample_time = time_now;
+
+ if (time_now - last_sample_time > 10000) {
+ sms_debug("data rate %d bytes/secs",
+ (int)((data_total * 1000) /
+ (time_now - last_sample_time)));
+
+ last_sample_time = time_now;
+ data_total = 0;
+ }
+
+ data_total += cb->size;
+ /* Do we need to re-route? */
+ if ((phdr->msg_type == MSG_SMS_HO_PER_SLICES_IND) ||
+ (phdr->msg_type == MSG_SMS_TRANSMISSION_IND)) {
+ if (coredev->mode == DEVICE_MODE_DVBT_BDA)
+ phdr->msg_dst_id = DVBT_BDA_CONTROL_MSG_ID;
+ }
+
+
+ client = smscore_find_client(coredev, phdr->msg_type, phdr->msg_dst_id);
+
+ /* If no client registered for type & id,
+ * check for control client where type is not registered */
+ if (client)
+ rc = client->onresponse_handler(client->context, cb);
+
+ if (rc < 0) {
+ switch (phdr->msg_type) {
+ case MSG_SMS_ISDBT_TUNE_RES:
+ break;
+ case MSG_SMS_RF_TUNE_RES:
+ break;
+ case MSG_SMS_SIGNAL_DETECTED_IND:
+ break;
+ case MSG_SMS_NO_SIGNAL_IND:
+ break;
+ case MSG_SMS_SPI_INT_LINE_SET_RES:
+ break;
+ case MSG_SMS_INTERFACE_LOCK_IND:
+ break;
+ case MSG_SMS_INTERFACE_UNLOCK_IND:
+ break;
+ case MSG_SMS_GET_VERSION_EX_RES:
+ {
+ struct sms_version_res *ver =
+ (struct sms_version_res *) phdr;
+ sms_debug("Firmware id %d prots 0x%x ver %d.%d",
+ ver->firmware_id, ver->supported_protocols,
+ ver->rom_ver_major, ver->rom_ver_minor);
+
+ coredev->mode = ver->firmware_id == 255 ?
+ DEVICE_MODE_NONE : ver->firmware_id;
+ coredev->modes_supported = ver->supported_protocols;
+ coredev->fw_version = ver->rom_ver_major << 8 |
+ ver->rom_ver_minor;
+
+ complete(&coredev->version_ex_done);
+ break;
+ }
+ case MSG_SMS_INIT_DEVICE_RES:
+ complete(&coredev->init_device_done);
+ break;
+ case MSG_SW_RELOAD_START_RES:
+ complete(&coredev->reload_start_done);
+ break;
+ case MSG_SMS_DATA_VALIDITY_RES:
+ {
+ struct sms_msg_data *validity = (struct sms_msg_data *) phdr;
+
+ sms_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
+ validity->msg_data[0]);
+ complete(&coredev->data_validity_done);
+ break;
+ }
+ case MSG_SMS_DATA_DOWNLOAD_RES:
+ complete(&coredev->data_download_done);
+ break;
+ case MSG_SW_RELOAD_EXEC_RES:
+ break;
+ case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
+ complete(&coredev->trigger_done);
+ break;
+ case MSG_SMS_SLEEP_RESUME_COMP_IND:
+ complete(&coredev->resume_done);
+ break;
+ case MSG_SMS_GPIO_CONFIG_EX_RES:
+ complete(&coredev->gpio_configuration_done);
+ break;
+ case MSG_SMS_GPIO_SET_LEVEL_RES:
+ complete(&coredev->gpio_set_level_done);
+ break;
+ case MSG_SMS_GPIO_GET_LEVEL_RES:
+ {
+ u32 *msgdata = (u32 *) phdr;
+ coredev->gpio_get_res = msgdata[1];
+ sms_debug("gpio level %d",
+ coredev->gpio_get_res);
+ complete(&coredev->gpio_get_level_done);
+ break;
+ }
+ case MSG_SMS_START_IR_RES:
+ complete(&coredev->ir_init_done);
+ break;
+ case MSG_SMS_IR_SAMPLES_IND:
+ sms_ir_event(coredev,
+ (const char *)
+ ((char *)phdr
+ + sizeof(struct sms_msg_hdr)),
+ (int)phdr->msg_length
+ - sizeof(struct sms_msg_hdr));
+ break;
+
+ case MSG_SMS_DVBT_BDA_DATA:
+ /*
+ * It can be received here, if the frontend is
+ * tuned into a valid channel and the proper firmware
+ * is loaded. That happens when the module got removed
+ * and re-inserted, without powering the device off
+ */
+ break;
+
+ default:
+ sms_debug("message %s(%d) not handled.",
+ smscore_translate_msg(phdr->msg_type),
+ phdr->msg_type);
+ break;
+ }
+ smscore_putbuffer(coredev, cb);
+ }
+}
+EXPORT_SYMBOL_GPL(smscore_onresponse);
+
+/**
+ * return pointer to next free buffer descriptor from core pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return pointer to descriptor on success, NULL on error.
+ */
+
+static struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&coredev->bufferslock, flags);
+ if (!list_empty(&coredev->buffers)) {
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
+ }
+ spin_unlock_irqrestore(&coredev->bufferslock, flags);
+ return cb;
+}
+
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb = NULL;
+
+ wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
+
+ return cb;
+}
+EXPORT_SYMBOL_GPL(smscore_getbuffer);
+
+/**
+ * return buffer descriptor to a pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param cb pointer buffer descriptor
+ *
+ */
+void smscore_putbuffer(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb) {
+ wake_up_interruptible(&coredev->buffer_mng_waitq);
+ list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+}
+EXPORT_SYMBOL_GPL(smscore_putbuffer);
+
+static int smscore_validate_client(struct smscore_device_t *coredev,
+ struct smscore_client_t *client,
+ int data_type, int id)
+{
+ struct smscore_idlist_t *listentry;
+ struct smscore_client_t *registered_client;
+
+ if (!client) {
+ sms_err("bad parameter.");
+ return -EINVAL;
+ }
+ registered_client = smscore_find_client(coredev, data_type, id);
+ if (registered_client == client)
+ return 0;
+
+ if (registered_client) {
+ sms_err("The msg ID already registered to another client.");
+ return -EEXIST;
+ }
+ listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
+ if (!listentry) {
+ sms_err("Can't allocate memory for client id.");
+ return -ENOMEM;
+ }
+ listentry->id = id;
+ listentry->data_type = data_type;
+ list_add_locked(&listentry->entry, &client->idlist,
+ &coredev->clientslock);
+ return 0;
+}
+
+/**
+ * creates smsclient object, check that id is taken by another client
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param initial_id all messages with this id would be sent to this client
+ * @param data_type all messages of this type would be sent to this client
+ * @param onresponse_handler client handler that is called to
+ * process incoming messages
+ * @param onremove_handler client handler that is called when device is removed
+ * @param context client-specific context
+ * @param client pointer to a value that receives created smsclient object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_client(struct smscore_device_t *coredev,
+ struct smsclient_params_t *params,
+ struct smscore_client_t **client)
+{
+ struct smscore_client_t *newclient;
+ /* check that no other channel with same parameters exists */
+ if (smscore_find_client(coredev, params->data_type,
+ params->initial_id)) {
+ sms_err("Client already exist.");
+ return -EEXIST;
+ }
+
+ newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
+ if (!newclient) {
+ sms_err("Failed to allocate memory for client.");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&newclient->idlist);
+ newclient->coredev = coredev;
+ newclient->onresponse_handler = params->onresponse_handler;
+ newclient->onremove_handler = params->onremove_handler;
+ newclient->context = params->context;
+ list_add_locked(&newclient->entry, &coredev->clients,
+ &coredev->clientslock);
+ smscore_validate_client(coredev, newclient, params->data_type,
+ params->initial_id);
+ *client = newclient;
+ sms_debug("%p %d %d", params->context, params->data_type,
+ params->initial_id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(smscore_register_client);
+
+/**
+ * frees smsclient object and all subclients associated with it
+ *
+ * @param client pointer to smsclient object returned by
+ * smscore_register_client
+ *
+ */
+void smscore_unregister_client(struct smscore_client_t *client)
+{
+ struct smscore_device_t *coredev = client->coredev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&coredev->clientslock, flags);
+
+
+ while (!list_empty(&client->idlist)) {
+ struct smscore_idlist_t *identry =
+ (struct smscore_idlist_t *) client->idlist.next;
+ list_del(&identry->entry);
+ kfree(identry);
+ }
+
+ sms_info("%p", client->context);
+
+ list_del(&client->entry);
+ kfree(client);
+
+ spin_unlock_irqrestore(&coredev->clientslock, flags);
+}
+EXPORT_SYMBOL_GPL(smscore_unregister_client);
+
+/**
+ * verifies that source id is not taken by another client,
+ * calls device handler to send requests to the device
+ *
+ * @param client pointer to smsclient object returned by
+ * smscore_register_client
+ * @param buffer pointer to a request buffer
+ * @param size size (in bytes) of request buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smsclient_sendrequest(struct smscore_client_t *client,
+ void *buffer, size_t size)
+{
+ struct smscore_device_t *coredev;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
+ int rc;
+
+ if (client == NULL) {
+ sms_err("Got NULL client");
+ return -EINVAL;
+ }
+
+ coredev = client->coredev;
+
+ /* check that no other channel with same id exists */
+ if (coredev == NULL) {
+ sms_err("Got NULL coredev");
+ return -EINVAL;
+ }
+
+ rc = smscore_validate_client(client->coredev, client, 0,
+ phdr->msg_src_id);
+ if (rc < 0)
+ return rc;
+
+ return coredev->sendrequest_handler(coredev->context, buffer, size);
+}
+EXPORT_SYMBOL_GPL(smsclient_sendrequest);
+
+
+/* old GPIO managements implementation */
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+ struct smscore_config_gpio *pinconfig)
+{
+ struct {
+ struct sms_msg_hdr hdr;
+ u32 data[6];
+ } msg;
+
+ if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+ msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.hdr.msg_dst_id = HIF_TASK;
+ msg.hdr.msg_flags = 0;
+ msg.hdr.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ;
+ msg.hdr.msg_length = sizeof(msg);
+
+ msg.data[0] = pin;
+ msg.data[1] = pinconfig->pullupdown;
+
+ /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
+ msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
+
+ switch (pinconfig->outputdriving) {
+ case SMS_GPIO_OUTPUTDRIVING_S_16mA:
+ msg.data[3] = 7; /* Nova - 16mA */
+ break;
+ case SMS_GPIO_OUTPUTDRIVING_S_12mA:
+ msg.data[3] = 5; /* Nova - 11mA */
+ break;
+ case SMS_GPIO_OUTPUTDRIVING_S_8mA:
+ msg.data[3] = 3; /* Nova - 7mA */
+ break;
+ case SMS_GPIO_OUTPUTDRIVING_S_4mA:
+ default:
+ msg.data[3] = 2; /* Nova - 4mA */
+ break;
+ }
+
+ msg.data[4] = pinconfig->direction;
+ msg.data[5] = 0;
+ } else /* TODO: SMS_DEVICE_FAMILY1 */
+ return -EINVAL;
+
+ return coredev->sendrequest_handler(coredev->context,
+ &msg, sizeof(msg));
+}
+
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
+{
+ struct {
+ struct sms_msg_hdr hdr;
+ u32 data[3];
+ } msg;
+
+ if (pin > MAX_GPIO_PIN_NUMBER)
+ return -EINVAL;
+
+ msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.hdr.msg_dst_id = HIF_TASK;
+ msg.hdr.msg_flags = 0;
+ msg.hdr.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ;
+ msg.hdr.msg_length = sizeof(msg);
+
+ msg.data[0] = pin;
+ msg.data[1] = level ? 1 : 0;
+ msg.data[2] = 0;
+
+ return coredev->sendrequest_handler(coredev->context,
+ &msg, sizeof(msg));
+}
+
+/* new GPIO management implementation */
+static int get_gpio_pin_params(u32 pin_num, u32 *p_translatedpin_num,
+ u32 *p_group_num, u32 *p_group_cfg) {
+
+ *p_group_cfg = 1;
+
+ if (pin_num <= 1) {
+ *p_translatedpin_num = 0;
+ *p_group_num = 9;
+ *p_group_cfg = 2;
+ } else if (pin_num >= 2 && pin_num <= 6) {
+ *p_translatedpin_num = 2;
+ *p_group_num = 0;
+ *p_group_cfg = 2;
+ } else if (pin_num >= 7 && pin_num <= 11) {
+ *p_translatedpin_num = 7;
+ *p_group_num = 1;
+ } else if (pin_num >= 12 && pin_num <= 15) {
+ *p_translatedpin_num = 12;
+ *p_group_num = 2;
+ *p_group_cfg = 3;
+ } else if (pin_num == 16) {
+ *p_translatedpin_num = 16;
+ *p_group_num = 23;
+ } else if (pin_num >= 17 && pin_num <= 24) {
+ *p_translatedpin_num = 17;
+ *p_group_num = 3;
+ } else if (pin_num == 25) {
+ *p_translatedpin_num = 25;
+ *p_group_num = 6;
+ } else if (pin_num >= 26 && pin_num <= 28) {
+ *p_translatedpin_num = 26;
+ *p_group_num = 4;
+ } else if (pin_num == 29) {
+ *p_translatedpin_num = 29;
+ *p_group_num = 5;
+ *p_group_cfg = 2;
+ } else if (pin_num == 30) {
+ *p_translatedpin_num = 30;
+ *p_group_num = 8;
+ } else if (pin_num == 31) {
+ *p_translatedpin_num = 31;
+ *p_group_num = 17;
+ } else
+ return -1;
+
+ *p_group_cfg <<= 24;
+
+ return 0;
+}
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num,
+ struct smscore_config_gpio *p_gpio_config) {
+
+ u32 total_len;
+ u32 translatedpin_num = 0;
+ u32 group_num = 0;
+ u32 electric_char;
+ u32 group_cfg;
+ void *buffer;
+ int rc;
+
+ struct set_gpio_msg {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[6];
+ } *p_msg;
+
+
+ if (pin_num > MAX_GPIO_PIN_NUMBER)
+ return -EINVAL;
+
+ if (p_gpio_config == NULL)
+ return -EINVAL;
+
+ total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6);
+
+ buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer);
+
+ p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ p_msg->x_msg_header.msg_dst_id = HIF_TASK;
+ p_msg->x_msg_header.msg_flags = 0;
+ p_msg->x_msg_header.msg_length = (u16) total_len;
+ p_msg->msg_data[0] = pin_num;
+
+ if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_REQ;
+ if (get_gpio_pin_params(pin_num, &translatedpin_num, &group_num,
+ &group_cfg) != 0) {
+ rc = -EINVAL;
+ goto free;
+ }
+
+ p_msg->msg_data[1] = translatedpin_num;
+ p_msg->msg_data[2] = group_num;
+ electric_char = (p_gpio_config->pullupdown)
+ | (p_gpio_config->inputcharacteristics << 2)
+ | (p_gpio_config->outputslewrate << 3)
+ | (p_gpio_config->outputdriving << 4);
+ p_msg->msg_data[3] = electric_char;
+ p_msg->msg_data[4] = p_gpio_config->direction;
+ p_msg->msg_data[5] = group_cfg;
+ } else {
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ;
+ p_msg->msg_data[1] = p_gpio_config->pullupdown;
+ p_msg->msg_data[2] = p_gpio_config->outputslewrate;
+ p_msg->msg_data[3] = p_gpio_config->outputdriving;
+ p_msg->msg_data[4] = p_gpio_config->direction;
+ p_msg->msg_data[5] = 0;
+ }
+
+ rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len,
+ &coredev->gpio_configuration_done);
+
+ if (rc != 0) {
+ if (rc == -ETIME)
+ sms_err("smscore_gpio_configure timeout");
+ else
+ sms_err("smscore_gpio_configure error");
+ }
+free:
+ kfree(buffer);
+
+ return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num,
+ u8 new_level) {
+
+ u32 total_len;
+ int rc;
+ void *buffer;
+
+ struct set_gpio_msg {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[3]; /* keep it 3 ! */
+ } *p_msg;
+
+ if ((new_level > 1) || (pin_num > MAX_GPIO_PIN_NUMBER))
+ return -EINVAL;
+
+ total_len = sizeof(struct sms_msg_hdr) +
+ (3 * sizeof(u32)); /* keep it 3 ! */
+
+ buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer);
+
+ p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ p_msg->x_msg_header.msg_dst_id = HIF_TASK;
+ p_msg->x_msg_header.msg_flags = 0;
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ;
+ p_msg->x_msg_header.msg_length = (u16) total_len;
+ p_msg->msg_data[0] = pin_num;
+ p_msg->msg_data[1] = new_level;
+
+ /* Send message to SMS */
+ rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len,
+ &coredev->gpio_set_level_done);
+
+ if (rc != 0) {
+ if (rc == -ETIME)
+ sms_err("smscore_gpio_set_level timeout");
+ else
+ sms_err("smscore_gpio_set_level error");
+ }
+ kfree(buffer);
+
+ return rc;
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
+ u8 *level) {
+
+ u32 total_len;
+ int rc;
+ void *buffer;
+
+ struct set_gpio_msg {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[2];
+ } *p_msg;
+
+
+ if (pin_num > MAX_GPIO_PIN_NUMBER)
+ return -EINVAL;
+
+ total_len = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32));
+
+ buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer);
+
+ p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ p_msg->x_msg_header.msg_dst_id = HIF_TASK;
+ p_msg->x_msg_header.msg_flags = 0;
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_GET_LEVEL_REQ;
+ p_msg->x_msg_header.msg_length = (u16) total_len;
+ p_msg->msg_data[0] = pin_num;
+ p_msg->msg_data[1] = 0;
+
+ /* Send message to SMS */
+ rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len,
+ &coredev->gpio_get_level_done);
+
+ if (rc != 0) {
+ if (rc == -ETIME)
+ sms_err("smscore_gpio_get_level timeout");
+ else
+ sms_err("smscore_gpio_get_level error");
+ }
+ kfree(buffer);
+
+ /* Its a race between other gpio_get_level() and the copy of the single
+ * global 'coredev->gpio_get_res' to the function's variable 'level'
+ */
+ *level = coredev->gpio_get_res;
+
+ return rc;
+}
+
+static int __init smscore_module_init(void)
+{
+ int rc = 0;
+
+ INIT_LIST_HEAD(&g_smscore_notifyees);
+ INIT_LIST_HEAD(&g_smscore_devices);
+ kmutex_init(&g_smscore_deviceslock);
+
+ INIT_LIST_HEAD(&g_smscore_registry);
+ kmutex_init(&g_smscore_registrylock);
+
+ return rc;
+}
+
+static void __exit smscore_module_exit(void)
+{
+ kmutex_lock(&g_smscore_deviceslock);
+ while (!list_empty(&g_smscore_notifyees)) {
+ struct smscore_device_notifyee_t *notifyee =
+ (struct smscore_device_notifyee_t *)
+ g_smscore_notifyees.next;
+
+ list_del(&notifyee->entry);
+ kfree(notifyee);
+ }
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ kmutex_lock(&g_smscore_registrylock);
+ while (!list_empty(&g_smscore_registry)) {
+ struct smscore_registry_entry_t *entry =
+ (struct smscore_registry_entry_t *)
+ g_smscore_registry.next;
+
+ list_del(&entry->entry);
+ kfree(entry);
+ }
+ kmutex_unlock(&g_smscore_registrylock);
+
+ sms_debug("");
+}
+
+module_init(smscore_module_init);
+module_exit(smscore_module_exit);
+
+MODULE_DESCRIPTION("Siano MDTV Core module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
+
+/* This should match what's defined at smscoreapi.h */
+MODULE_FIRMWARE(SMS_FW_ATSC_DENVER);
+MODULE_FIRMWARE(SMS_FW_CMMB_MING_APP);
+MODULE_FIRMWARE(SMS_FW_CMMB_VEGA_12MHZ);
+MODULE_FIRMWARE(SMS_FW_CMMB_VENICE_12MHZ);
+MODULE_FIRMWARE(SMS_FW_DVBH_RIO);
+MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ_B0);
+MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ);
+MODULE_FIRMWARE(SMS_FW_DVB_RIO);
+MODULE_FIRMWARE(SMS_FW_FM_RADIO);
+MODULE_FIRMWARE(SMS_FW_FM_RADIO_RIO);
+MODULE_FIRMWARE(SMS_FW_DVBT_HCW_55XXX);
+MODULE_FIRMWARE(SMS_FW_ISDBT_HCW_55XXX);
+MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ_B0);
+MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ);
+MODULE_FIRMWARE(SMS_FW_ISDBT_PELE);
+MODULE_FIRMWARE(SMS_FW_ISDBT_RIO);
+MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_A);
+MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_B);
+MODULE_FIRMWARE(SMS_FW_DVBT_STELLAR);
+MODULE_FIRMWARE(SMS_FW_TDMB_DENVER);
+MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ_B0);
+MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ);
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
new file mode 100644
index 00000000000..9c9063cd320
--- /dev/null
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -0,0 +1,1192 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
+
+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_CORE_API_H__
+#define __SMS_CORE_API_H__
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+#include <asm/page.h>
+
+#include "smsir.h"
+
+#define kmutex_init(_p_) mutex_init(_p_)
+#define kmutex_lock(_p_) mutex_lock(_p_)
+#define kmutex_trylock(_p_) mutex_trylock(_p_)
+#define kmutex_unlock(_p_) mutex_unlock(_p_)
+
+/*
+ * Define the firmware names used by the driver.
+ * Those should match what's used at smscoreapi.c and sms-cards.c
+ * including the MODULE_FIRMWARE() macros at the end of smscoreapi.c
+ */
+#define SMS_FW_ATSC_DENVER "atsc_denver.inp"
+#define SMS_FW_CMMB_MING_APP "cmmb_ming_app.inp"
+#define SMS_FW_CMMB_VEGA_12MHZ "cmmb_vega_12mhz.inp"
+#define SMS_FW_CMMB_VENICE_12MHZ "cmmb_venice_12mhz.inp"
+#define SMS_FW_DVBH_RIO "dvbh_rio.inp"
+#define SMS_FW_DVB_NOVA_12MHZ_B0 "dvb_nova_12mhz_b0.inp"
+#define SMS_FW_DVB_NOVA_12MHZ "dvb_nova_12mhz.inp"
+#define SMS_FW_DVB_RIO "dvb_rio.inp"
+#define SMS_FW_FM_RADIO "fm_radio.inp"
+#define SMS_FW_FM_RADIO_RIO "fm_radio_rio.inp"
+#define SMS_FW_DVBT_HCW_55XXX "sms1xxx-hcw-55xxx-dvbt-02.fw"
+#define SMS_FW_ISDBT_HCW_55XXX "sms1xxx-hcw-55xxx-isdbt-02.fw"
+#define SMS_FW_ISDBT_NOVA_12MHZ_B0 "isdbt_nova_12mhz_b0.inp"
+#define SMS_FW_ISDBT_NOVA_12MHZ "isdbt_nova_12mhz.inp"
+#define SMS_FW_ISDBT_PELE "isdbt_pele.inp"
+#define SMS_FW_ISDBT_RIO "isdbt_rio.inp"
+#define SMS_FW_DVBT_NOVA_A "sms1xxx-nova-a-dvbt-01.fw"
+#define SMS_FW_DVBT_NOVA_B "sms1xxx-nova-b-dvbt-01.fw"
+#define SMS_FW_DVBT_STELLAR "sms1xxx-stellar-dvbt-01.fw"
+#define SMS_FW_TDMB_DENVER "tdmb_denver.inp"
+#define SMS_FW_TDMB_NOVA_12MHZ_B0 "tdmb_nova_12mhz_b0.inp"
+#define SMS_FW_TDMB_NOVA_12MHZ "tdmb_nova_12mhz.inp"
+
+#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000)
+#define SMS_ALLOC_ALIGNMENT 128
+#define SMS_DMA_ALIGNMENT 16
+#define SMS_ALIGN_ADDRESS(addr) \
+ ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+
+#define SMS_DEVICE_FAMILY1 0
+#define SMS_DEVICE_FAMILY2 1
+#define SMS_ROM_NO_RESPONSE 2
+#define SMS_DEVICE_NOT_READY 0x8000000
+
+enum sms_device_type_st {
+ SMS_UNKNOWN_TYPE = -1,
+ SMS_STELLAR = 0,
+ SMS_NOVA_A0,
+ SMS_NOVA_B0,
+ SMS_VEGA,
+ SMS_VENICE,
+ SMS_MING,
+ SMS_PELE,
+ SMS_RIO,
+ SMS_DENVER_1530,
+ SMS_DENVER_2160,
+ SMS_NUM_OF_DEVICE_TYPES
+};
+
+enum sms_power_mode_st {
+ SMS_POWER_MODE_ACTIVE,
+ SMS_POWER_MODE_SUSPENDED
+};
+
+struct smscore_device_t;
+struct smscore_client_t;
+struct smscore_buffer_t;
+
+typedef int (*hotplug_t)(struct smscore_device_t *coredev,
+ struct device *device, int arrival);
+
+typedef int (*setmode_t)(void *context, int mode);
+typedef void (*detectmode_t)(void *context, int *mode);
+typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
+typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
+typedef int (*preload_t)(void *context);
+typedef int (*postload_t)(void *context);
+
+typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
+typedef void (*onremove_t)(void *context);
+
+struct smscore_buffer_t {
+ /* public members, once passed to clients can be changed freely */
+ struct list_head entry;
+ int size;
+ int offset;
+
+ /* private members, read-only for clients */
+ void *p;
+ dma_addr_t phys;
+ unsigned long offset_in_common;
+};
+
+struct smsdevice_params_t {
+ struct device *device;
+
+ int buffer_size;
+ int num_buffers;
+
+ char devpath[32];
+ unsigned long flags;
+
+ setmode_t setmode_handler;
+ detectmode_t detectmode_handler;
+ sendrequest_t sendrequest_handler;
+ preload_t preload_handler;
+ postload_t postload_handler;
+
+ void *context;
+ enum sms_device_type_st device_type;
+};
+
+struct smsclient_params_t {
+ int initial_id;
+ int data_type;
+ onresponse_t onresponse_handler;
+ onremove_t onremove_handler;
+ void *context;
+};
+
+struct smscore_device_t {
+ struct list_head entry;
+
+ struct list_head clients;
+ struct list_head subclients;
+ spinlock_t clientslock;
+
+ struct list_head buffers;
+ spinlock_t bufferslock;
+ int num_buffers;
+
+ void *common_buffer;
+ int common_buffer_size;
+ dma_addr_t common_buffer_phys;
+
+ void *context;
+ struct device *device;
+
+ char devpath[32];
+ unsigned long device_flags;
+
+ setmode_t setmode_handler;
+ detectmode_t detectmode_handler;
+ sendrequest_t sendrequest_handler;
+ preload_t preload_handler;
+ postload_t postload_handler;
+
+ int mode, modes_supported;
+
+ /* host <--> device messages */
+ struct completion version_ex_done, data_download_done, trigger_done;
+ struct completion data_validity_done, device_ready_done;
+ struct completion init_device_done, reload_start_done, resume_done;
+ struct completion gpio_configuration_done, gpio_set_level_done;
+ struct completion gpio_get_level_done, ir_init_done;
+
+ /* Buffer management */
+ wait_queue_head_t buffer_mng_waitq;
+
+ /* GPIO */
+ int gpio_get_res;
+
+ /* Target hardware board */
+ int board_id;
+
+ /* Firmware */
+ u8 *fw_buf;
+ u32 fw_buf_size;
+ u16 fw_version;
+
+ /* Infrared (IR) */
+ struct ir_t ir;
+
+ /*
+ * Identify if device is USB or not.
+ * Used by smsdvb-sysfs to know the root node for debugfs
+ */
+ bool is_usb_device;
+
+ int led_state;
+};
+
+/* GPIO definitions for antenna frequency domain control (SMS8021) */
+#define SMS_ANTENNA_GPIO_0 1
+#define SMS_ANTENNA_GPIO_1 0
+
+enum sms_bandwidth_mode {
+ BW_8_MHZ = 0,
+ BW_7_MHZ = 1,
+ BW_6_MHZ = 2,
+ BW_5_MHZ = 3,
+ BW_ISDBT_1SEG = 4,
+ BW_ISDBT_3SEG = 5,
+ BW_2_MHZ = 6,
+ BW_FM_RADIO = 7,
+ BW_ISDBT_13SEG = 8,
+ BW_1_5_MHZ = 15,
+ BW_UNKNOWN = 0xffff
+};
+
+
+#define MSG_HDR_FLAG_SPLIT_MSG 4
+
+#define MAX_GPIO_PIN_NUMBER 31
+
+#define HIF_TASK 11
+#define HIF_TASK_SLAVE 22
+#define HIF_TASK_SLAVE2 33
+#define HIF_TASK_SLAVE3 44
+#define SMS_HOST_LIB 150
+#define DVBT_BDA_CONTROL_MSG_ID 201
+
+#define SMS_MAX_PAYLOAD_SIZE 240
+#define SMS_TUNE_TIMEOUT 500
+
+enum msg_types {
+ MSG_TYPE_BASE_VAL = 500,
+ MSG_SMS_GET_VERSION_REQ = 503,
+ MSG_SMS_GET_VERSION_RES = 504,
+ MSG_SMS_MULTI_BRIDGE_CFG = 505,
+ MSG_SMS_GPIO_CONFIG_REQ = 507,
+ MSG_SMS_GPIO_CONFIG_RES = 508,
+ MSG_SMS_GPIO_SET_LEVEL_REQ = 509,
+ MSG_SMS_GPIO_SET_LEVEL_RES = 510,
+ MSG_SMS_GPIO_GET_LEVEL_REQ = 511,
+ MSG_SMS_GPIO_GET_LEVEL_RES = 512,
+ MSG_SMS_EEPROM_BURN_IND = 513,
+ MSG_SMS_LOG_ENABLE_CHANGE_REQ = 514,
+ MSG_SMS_LOG_ENABLE_CHANGE_RES = 515,
+ MSG_SMS_SET_MAX_TX_MSG_LEN_REQ = 516,
+ MSG_SMS_SET_MAX_TX_MSG_LEN_RES = 517,
+ MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE = 518,
+ MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST = 519,
+ MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ = 520,
+ MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES = 521,
+ MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND = 522,
+ MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND = 523,
+ MSG_SMS_CONFIGURE_RF_SWITCH_REQ = 524,
+ MSG_SMS_CONFIGURE_RF_SWITCH_RES = 525,
+ MSG_SMS_MRC_PATH_DISCONNECT_REQ = 526,
+ MSG_SMS_MRC_PATH_DISCONNECT_RES = 527,
+ MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ = 528,
+ MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES = 529,
+ MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ = 530,
+ MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES = 531,
+ MSG_WR_REG_RFT_REQ = 533,
+ MSG_WR_REG_RFT_RES = 534,
+ MSG_RD_REG_RFT_REQ = 535,
+ MSG_RD_REG_RFT_RES = 536,
+ MSG_RD_REG_ALL_RFT_REQ = 537,
+ MSG_RD_REG_ALL_RFT_RES = 538,
+ MSG_HELP_INT = 539,
+ MSG_RUN_SCRIPT_INT = 540,
+ MSG_SMS_EWS_INBAND_REQ = 541,
+ MSG_SMS_EWS_INBAND_RES = 542,
+ MSG_SMS_RFS_SELECT_REQ = 543,
+ MSG_SMS_RFS_SELECT_RES = 544,
+ MSG_SMS_MB_GET_VER_REQ = 545,
+ MSG_SMS_MB_GET_VER_RES = 546,
+ MSG_SMS_MB_WRITE_CFGFILE_REQ = 547,
+ MSG_SMS_MB_WRITE_CFGFILE_RES = 548,
+ MSG_SMS_MB_READ_CFGFILE_REQ = 549,
+ MSG_SMS_MB_READ_CFGFILE_RES = 550,
+ MSG_SMS_RD_MEM_REQ = 552,
+ MSG_SMS_RD_MEM_RES = 553,
+ MSG_SMS_WR_MEM_REQ = 554,
+ MSG_SMS_WR_MEM_RES = 555,
+ MSG_SMS_UPDATE_MEM_REQ = 556,
+ MSG_SMS_UPDATE_MEM_RES = 557,
+ MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ = 558,
+ MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES = 559,
+ MSG_SMS_RF_TUNE_REQ = 561,
+ MSG_SMS_RF_TUNE_RES = 562,
+ MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ = 563,
+ MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES = 564,
+ MSG_SMS_ISDBT_SB_RECEPTION_REQ = 565,
+ MSG_SMS_ISDBT_SB_RECEPTION_RES = 566,
+ MSG_SMS_GENERIC_EPROM_WRITE_REQ = 567,
+ MSG_SMS_GENERIC_EPROM_WRITE_RES = 568,
+ MSG_SMS_GENERIC_EPROM_READ_REQ = 569,
+ MSG_SMS_GENERIC_EPROM_READ_RES = 570,
+ MSG_SMS_EEPROM_WRITE_REQ = 571,
+ MSG_SMS_EEPROM_WRITE_RES = 572,
+ MSG_SMS_CUSTOM_READ_REQ = 574,
+ MSG_SMS_CUSTOM_READ_RES = 575,
+ MSG_SMS_CUSTOM_WRITE_REQ = 576,
+ MSG_SMS_CUSTOM_WRITE_RES = 577,
+ MSG_SMS_INIT_DEVICE_REQ = 578,
+ MSG_SMS_INIT_DEVICE_RES = 579,
+ MSG_SMS_ATSC_SET_ALL_IP_REQ = 580,
+ MSG_SMS_ATSC_SET_ALL_IP_RES = 581,
+ MSG_SMS_ATSC_START_ENSEMBLE_REQ = 582,
+ MSG_SMS_ATSC_START_ENSEMBLE_RES = 583,
+ MSG_SMS_SET_OUTPUT_MODE_REQ = 584,
+ MSG_SMS_SET_OUTPUT_MODE_RES = 585,
+ MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ = 586,
+ MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES = 587,
+ MSG_SMS_SUB_CHANNEL_START_REQ = 589,
+ MSG_SMS_SUB_CHANNEL_START_RES = 590,
+ MSG_SMS_SUB_CHANNEL_STOP_REQ = 591,
+ MSG_SMS_SUB_CHANNEL_STOP_RES = 592,
+ MSG_SMS_ATSC_IP_FILTER_ADD_REQ = 593,
+ MSG_SMS_ATSC_IP_FILTER_ADD_RES = 594,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ = 595,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_RES = 596,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ = 597,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES = 598,
+ MSG_SMS_WAIT_CMD = 599,
+ MSG_SMS_ADD_PID_FILTER_REQ = 601,
+ MSG_SMS_ADD_PID_FILTER_RES = 602,
+ MSG_SMS_REMOVE_PID_FILTER_REQ = 603,
+ MSG_SMS_REMOVE_PID_FILTER_RES = 604,
+ MSG_SMS_FAST_INFORMATION_CHANNEL_REQ = 605,
+ MSG_SMS_FAST_INFORMATION_CHANNEL_RES = 606,
+ MSG_SMS_DAB_CHANNEL = 607,
+ MSG_SMS_GET_PID_FILTER_LIST_REQ = 608,
+ MSG_SMS_GET_PID_FILTER_LIST_RES = 609,
+ MSG_SMS_POWER_DOWN_REQ = 610,
+ MSG_SMS_POWER_DOWN_RES = 611,
+ MSG_SMS_ATSC_SLT_EXIST_IND = 612,
+ MSG_SMS_ATSC_NO_SLT_IND = 613,
+ MSG_SMS_GET_STATISTICS_REQ = 615,
+ MSG_SMS_GET_STATISTICS_RES = 616,
+ MSG_SMS_SEND_DUMP = 617,
+ MSG_SMS_SCAN_START_REQ = 618,
+ MSG_SMS_SCAN_START_RES = 619,
+ MSG_SMS_SCAN_STOP_REQ = 620,
+ MSG_SMS_SCAN_STOP_RES = 621,
+ MSG_SMS_SCAN_PROGRESS_IND = 622,
+ MSG_SMS_SCAN_COMPLETE_IND = 623,
+ MSG_SMS_LOG_ITEM = 624,
+ MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ = 628,
+ MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES = 629,
+ MSG_SMS_HO_PER_SLICES_IND = 630,
+ MSG_SMS_HO_INBAND_POWER_IND = 631,
+ MSG_SMS_MANUAL_DEMOD_REQ = 632,
+ MSG_SMS_HO_TUNE_ON_REQ = 636,
+ MSG_SMS_HO_TUNE_ON_RES = 637,
+ MSG_SMS_HO_TUNE_OFF_REQ = 638,
+ MSG_SMS_HO_TUNE_OFF_RES = 639,
+ MSG_SMS_HO_PEEK_FREQ_REQ = 640,
+ MSG_SMS_HO_PEEK_FREQ_RES = 641,
+ MSG_SMS_HO_PEEK_FREQ_IND = 642,
+ MSG_SMS_MB_ATTEN_SET_REQ = 643,
+ MSG_SMS_MB_ATTEN_SET_RES = 644,
+ MSG_SMS_ENABLE_STAT_IN_I2C_REQ = 649,
+ MSG_SMS_ENABLE_STAT_IN_I2C_RES = 650,
+ MSG_SMS_SET_ANTENNA_CONFIG_REQ = 651,
+ MSG_SMS_SET_ANTENNA_CONFIG_RES = 652,
+ MSG_SMS_GET_STATISTICS_EX_REQ = 653,
+ MSG_SMS_GET_STATISTICS_EX_RES = 654,
+ MSG_SMS_SLEEP_RESUME_COMP_IND = 655,
+ MSG_SMS_SWITCH_HOST_INTERFACE_REQ = 656,
+ MSG_SMS_SWITCH_HOST_INTERFACE_RES = 657,
+ MSG_SMS_DATA_DOWNLOAD_REQ = 660,
+ MSG_SMS_DATA_DOWNLOAD_RES = 661,
+ MSG_SMS_DATA_VALIDITY_REQ = 662,
+ MSG_SMS_DATA_VALIDITY_RES = 663,
+ MSG_SMS_SWDOWNLOAD_TRIGGER_REQ = 664,
+ MSG_SMS_SWDOWNLOAD_TRIGGER_RES = 665,
+ MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ = 666,
+ MSG_SMS_SWDOWNLOAD_BACKDOOR_RES = 667,
+ MSG_SMS_GET_VERSION_EX_REQ = 668,
+ MSG_SMS_GET_VERSION_EX_RES = 669,
+ MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ = 670,
+ MSG_SMS_CLOCK_OUTPUT_CONFIG_RES = 671,
+ MSG_SMS_I2C_SET_FREQ_REQ = 685,
+ MSG_SMS_I2C_SET_FREQ_RES = 686,
+ MSG_SMS_GENERIC_I2C_REQ = 687,
+ MSG_SMS_GENERIC_I2C_RES = 688,
+ MSG_SMS_DVBT_BDA_DATA = 693,
+ MSG_SW_RELOAD_REQ = 697,
+ MSG_SMS_DATA_MSG = 699,
+ MSG_TABLE_UPLOAD_REQ = 700,
+ MSG_TABLE_UPLOAD_RES = 701,
+ MSG_SW_RELOAD_START_REQ = 702,
+ MSG_SW_RELOAD_START_RES = 703,
+ MSG_SW_RELOAD_EXEC_REQ = 704,
+ MSG_SW_RELOAD_EXEC_RES = 705,
+ MSG_SMS_SPI_INT_LINE_SET_REQ = 710,
+ MSG_SMS_SPI_INT_LINE_SET_RES = 711,
+ MSG_SMS_GPIO_CONFIG_EX_REQ = 712,
+ MSG_SMS_GPIO_CONFIG_EX_RES = 713,
+ MSG_SMS_WATCHDOG_ACT_REQ = 716,
+ MSG_SMS_WATCHDOG_ACT_RES = 717,
+ MSG_SMS_LOOPBACK_REQ = 718,
+ MSG_SMS_LOOPBACK_RES = 719,
+ MSG_SMS_RAW_CAPTURE_START_REQ = 720,
+ MSG_SMS_RAW_CAPTURE_START_RES = 721,
+ MSG_SMS_RAW_CAPTURE_ABORT_REQ = 722,
+ MSG_SMS_RAW_CAPTURE_ABORT_RES = 723,
+ MSG_SMS_RAW_CAPTURE_COMPLETE_IND = 728,
+ MSG_SMS_DATA_PUMP_IND = 729,
+ MSG_SMS_DATA_PUMP_REQ = 730,
+ MSG_SMS_DATA_PUMP_RES = 731,
+ MSG_SMS_FLASH_DL_REQ = 732,
+ MSG_SMS_EXEC_TEST_1_REQ = 734,
+ MSG_SMS_EXEC_TEST_1_RES = 735,
+ MSG_SMS_ENBALE_TS_INTERFACE_REQ = 736,
+ MSG_SMS_ENBALE_TS_INTERFACE_RES = 737,
+ MSG_SMS_SPI_SET_BUS_WIDTH_REQ = 738,
+ MSG_SMS_SPI_SET_BUS_WIDTH_RES = 739,
+ MSG_SMS_SEND_EMM_REQ = 740,
+ MSG_SMS_SEND_EMM_RES = 741,
+ MSG_SMS_DISABLE_TS_INTERFACE_REQ = 742,
+ MSG_SMS_DISABLE_TS_INTERFACE_RES = 743,
+ MSG_SMS_IS_BUF_FREE_REQ = 744,
+ MSG_SMS_IS_BUF_FREE_RES = 745,
+ MSG_SMS_EXT_ANTENNA_REQ = 746,
+ MSG_SMS_EXT_ANTENNA_RES = 747,
+ MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE = 748,
+ MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE = 749,
+ MSG_SMS_BATTERY_LEVEL_REQ = 750,
+ MSG_SMS_BATTERY_LEVEL_RES = 751,
+ MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE = 752,
+ MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE = 753,
+ MSG_SMS_FM_RADIO_BLOCK_IND = 754,
+ MSG_SMS_HOST_NOTIFICATION_IND = 755,
+ MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE = 756,
+ MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE = 757,
+ MSG_SMS_CMMB_GET_NETWORKS_REQ = 760,
+ MSG_SMS_CMMB_GET_NETWORKS_RES = 761,
+ MSG_SMS_CMMB_START_SERVICE_REQ = 762,
+ MSG_SMS_CMMB_START_SERVICE_RES = 763,
+ MSG_SMS_CMMB_STOP_SERVICE_REQ = 764,
+ MSG_SMS_CMMB_STOP_SERVICE_RES = 765,
+ MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ = 768,
+ MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES = 769,
+ MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ = 770,
+ MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES = 771,
+ MSG_SMS_CMMB_START_CONTROL_INFO_REQ = 772,
+ MSG_SMS_CMMB_START_CONTROL_INFO_RES = 773,
+ MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ = 774,
+ MSG_SMS_CMMB_STOP_CONTROL_INFO_RES = 775,
+ MSG_SMS_ISDBT_TUNE_REQ = 776,
+ MSG_SMS_ISDBT_TUNE_RES = 777,
+ MSG_SMS_TRANSMISSION_IND = 782,
+ MSG_SMS_PID_STATISTICS_IND = 783,
+ MSG_SMS_POWER_DOWN_IND = 784,
+ MSG_SMS_POWER_DOWN_CONF = 785,
+ MSG_SMS_POWER_UP_IND = 786,
+ MSG_SMS_POWER_UP_CONF = 787,
+ MSG_SMS_POWER_MODE_SET_REQ = 790,
+ MSG_SMS_POWER_MODE_SET_RES = 791,
+ MSG_SMS_DEBUG_HOST_EVENT_REQ = 792,
+ MSG_SMS_DEBUG_HOST_EVENT_RES = 793,
+ MSG_SMS_NEW_CRYSTAL_REQ = 794,
+ MSG_SMS_NEW_CRYSTAL_RES = 795,
+ MSG_SMS_CONFIG_SPI_REQ = 796,
+ MSG_SMS_CONFIG_SPI_RES = 797,
+ MSG_SMS_I2C_SHORT_STAT_IND = 798,
+ MSG_SMS_START_IR_REQ = 800,
+ MSG_SMS_START_IR_RES = 801,
+ MSG_SMS_IR_SAMPLES_IND = 802,
+ MSG_SMS_CMMB_CA_SERVICE_IND = 803,
+ MSG_SMS_SLAVE_DEVICE_DETECTED = 804,
+ MSG_SMS_INTERFACE_LOCK_IND = 805,
+ MSG_SMS_INTERFACE_UNLOCK_IND = 806,
+ MSG_SMS_SEND_ROSUM_BUFF_REQ = 810,
+ MSG_SMS_SEND_ROSUM_BUFF_RES = 811,
+ MSG_SMS_ROSUM_BUFF = 812,
+ MSG_SMS_SET_AES128_KEY_REQ = 815,
+ MSG_SMS_SET_AES128_KEY_RES = 816,
+ MSG_SMS_MBBMS_WRITE_REQ = 817,
+ MSG_SMS_MBBMS_WRITE_RES = 818,
+ MSG_SMS_MBBMS_READ_IND = 819,
+ MSG_SMS_IQ_STREAM_START_REQ = 820,
+ MSG_SMS_IQ_STREAM_START_RES = 821,
+ MSG_SMS_IQ_STREAM_STOP_REQ = 822,
+ MSG_SMS_IQ_STREAM_STOP_RES = 823,
+ MSG_SMS_IQ_STREAM_DATA_BLOCK = 824,
+ MSG_SMS_GET_EEPROM_VERSION_REQ = 825,
+ MSG_SMS_GET_EEPROM_VERSION_RES = 826,
+ MSG_SMS_SIGNAL_DETECTED_IND = 827,
+ MSG_SMS_NO_SIGNAL_IND = 828,
+ MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ = 830,
+ MSG_SMS_MRC_SHUTDOWN_SLAVE_RES = 831,
+ MSG_SMS_MRC_BRINGUP_SLAVE_REQ = 832,
+ MSG_SMS_MRC_BRINGUP_SLAVE_RES = 833,
+ MSG_SMS_EXTERNAL_LNA_CTRL_REQ = 834,
+ MSG_SMS_EXTERNAL_LNA_CTRL_RES = 835,
+ MSG_SMS_SET_PERIODIC_STATISTICS_REQ = 836,
+ MSG_SMS_SET_PERIODIC_STATISTICS_RES = 837,
+ MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ = 838,
+ MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES = 839,
+ LOCAL_TUNE = 850,
+ LOCAL_IFFT_H_ICI = 851,
+ MSG_RESYNC_REQ = 852,
+ MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ = 853,
+ MSG_SMS_CMMB_GET_MRC_STATISTICS_RES = 854,
+ MSG_SMS_LOG_EX_ITEM = 855,
+ MSG_SMS_DEVICE_DATA_LOSS_IND = 856,
+ MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND = 857,
+ MSG_SMS_USER_MSG_REQ = 858,
+ MSG_SMS_USER_MSG_RES = 859,
+ MSG_SMS_SMART_CARD_INIT_REQ = 860,
+ MSG_SMS_SMART_CARD_INIT_RES = 861,
+ MSG_SMS_SMART_CARD_WRITE_REQ = 862,
+ MSG_SMS_SMART_CARD_WRITE_RES = 863,
+ MSG_SMS_SMART_CARD_READ_IND = 864,
+ MSG_SMS_TSE_ENABLE_REQ = 866,
+ MSG_SMS_TSE_ENABLE_RES = 867,
+ MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ = 868,
+ MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES = 869,
+ MSG_SMS_LED_CONFIG_REQ = 870,
+ MSG_SMS_LED_CONFIG_RES = 871,
+ MSG_PWM_ANTENNA_REQ = 872,
+ MSG_PWM_ANTENNA_RES = 873,
+ MSG_SMS_CMMB_SMD_SN_REQ = 874,
+ MSG_SMS_CMMB_SMD_SN_RES = 875,
+ MSG_SMS_CMMB_SET_CA_CW_REQ = 876,
+ MSG_SMS_CMMB_SET_CA_CW_RES = 877,
+ MSG_SMS_CMMB_SET_CA_SALT_REQ = 878,
+ MSG_SMS_CMMB_SET_CA_SALT_RES = 879,
+ MSG_SMS_NSCD_INIT_REQ = 880,
+ MSG_SMS_NSCD_INIT_RES = 881,
+ MSG_SMS_NSCD_PROCESS_SECTION_REQ = 882,
+ MSG_SMS_NSCD_PROCESS_SECTION_RES = 883,
+ MSG_SMS_DBD_CREATE_OBJECT_REQ = 884,
+ MSG_SMS_DBD_CREATE_OBJECT_RES = 885,
+ MSG_SMS_DBD_CONFIGURE_REQ = 886,
+ MSG_SMS_DBD_CONFIGURE_RES = 887,
+ MSG_SMS_DBD_SET_KEYS_REQ = 888,
+ MSG_SMS_DBD_SET_KEYS_RES = 889,
+ MSG_SMS_DBD_PROCESS_HEADER_REQ = 890,
+ MSG_SMS_DBD_PROCESS_HEADER_RES = 891,
+ MSG_SMS_DBD_PROCESS_DATA_REQ = 892,
+ MSG_SMS_DBD_PROCESS_DATA_RES = 893,
+ MSG_SMS_DBD_PROCESS_GET_DATA_REQ = 894,
+ MSG_SMS_DBD_PROCESS_GET_DATA_RES = 895,
+ MSG_SMS_NSCD_OPEN_SESSION_REQ = 896,
+ MSG_SMS_NSCD_OPEN_SESSION_RES = 897,
+ MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ = 898,
+ MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES = 899,
+ MSG_LAST_MSG_TYPE = 900,
+};
+
+#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
+ (ptr)->msg_type = type; \
+ (ptr)->msg_src_id = src; \
+ (ptr)->msg_dst_id = dst; \
+ (ptr)->msg_length = len; \
+ (ptr)->msg_flags = 0; \
+} while (0)
+
+#define SMS_INIT_MSG(ptr, type, len) \
+ SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
+
+enum SMS_DVB3_EVENTS {
+ DVB3_EVENT_INIT = 0,
+ DVB3_EVENT_SLEEP,
+ DVB3_EVENT_HOTPLUG,
+ DVB3_EVENT_FE_LOCK,
+ DVB3_EVENT_FE_UNLOCK,
+ DVB3_EVENT_UNC_OK,
+ DVB3_EVENT_UNC_ERR
+};
+
+enum SMS_DEVICE_MODE {
+ DEVICE_MODE_NONE = -1,
+ DEVICE_MODE_DVBT = 0,
+ DEVICE_MODE_DVBH,
+ DEVICE_MODE_DAB_TDMB,
+ DEVICE_MODE_DAB_TDMB_DABIP,
+ DEVICE_MODE_DVBT_BDA,
+ DEVICE_MODE_ISDBT,
+ DEVICE_MODE_ISDBT_BDA,
+ DEVICE_MODE_CMMB,
+ DEVICE_MODE_RAW_TUNER,
+ DEVICE_MODE_FM_RADIO,
+ DEVICE_MODE_FM_RADIO_BDA,
+ DEVICE_MODE_ATSC,
+ DEVICE_MODE_MAX,
+};
+
+struct sms_msg_hdr {
+ u16 msg_type;
+ u8 msg_src_id;
+ u8 msg_dst_id;
+ u16 msg_length; /* length of entire message, including header */
+ u16 msg_flags;
+};
+
+struct sms_msg_data {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[1];
+};
+
+struct sms_msg_data2 {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[2];
+};
+
+struct sms_msg_data4 {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[4];
+};
+
+struct sms_data_download {
+ struct sms_msg_hdr x_msg_header;
+ u32 mem_addr;
+ u8 payload[SMS_MAX_PAYLOAD_SIZE];
+};
+
+struct sms_version_res {
+ struct sms_msg_hdr x_msg_header;
+
+ u16 chip_model; /* e.g. 0x1102 for SMS-1102 "Nova" */
+ u8 step; /* 0 - step A */
+ u8 metal_fix; /* 0 - Metal 0 */
+
+ /* firmware_id 0xFF if ROM, otherwise the
+ * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
+ u8 firmware_id;
+ /* supported_protocols Bitwise OR combination of
+ * supported protocols */
+ u8 supported_protocols;
+
+ u8 version_major;
+ u8 version_minor;
+ u8 version_patch;
+ u8 version_field_patch;
+
+ u8 rom_ver_major;
+ u8 rom_ver_minor;
+ u8 rom_ver_patch;
+ u8 rom_ver_field_patch;
+
+ u8 TextLabel[34];
+};
+
+struct sms_firmware {
+ u32 check_sum;
+ u32 length;
+ u32 start_address;
+ u8 payload[1];
+};
+
+/* statistics information returned as response for
+ * SmsHostApiGetstatistics_Req */
+struct sms_stats {
+ u32 reserved; /* reserved */
+
+ /* Common parameters */
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ /* Reception quality */
+ s32 SNR; /* dB */
+ u32 ber; /* Post Viterbi ber [1E-5] */
+ u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
+ u32 ts_per; /* Transport stream PER,
+ 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
+ u32 MFER; /* DVB-H frame error rate in percentage,
+ 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
+
+ /* Transmission parameters */
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz, valid only for DVB-T/H */
+ u32 transmission_mode; /* Transmission Mode, for DAB modes 1-4,
+ for DVB-T/H FFT mode carriers in Kilos */
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
+ valid only for DVB-T/H */
+ u32 guard_interval; /* Guard Interval from
+ SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */
+ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+ valid only for DVB-T/H */
+ u32 lp_code_rate; /* Low Priority Code Rate from
+ SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
+ u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET,
+ valid only for DVB-T/H */
+ u32 constellation; /* constellation from
+ SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
+
+ /* Burst parameters, valid only for DVB-H */
+ u32 burst_size; /* Current burst size in bytes,
+ valid only for DVB-H */
+ u32 burst_duration; /* Current burst duration in mSec,
+ valid only for DVB-H */
+ u32 burst_cycle_time; /* Current burst cycle time in mSec,
+ valid only for DVB-H */
+ u32 calc_burst_cycle_time;/* Current burst cycle time in mSec,
+ as calculated by demodulator, valid only for DVB-H */
+ u32 num_of_rows; /* Number of rows in MPE table,
+ valid only for DVB-H */
+ u32 num_of_padd_cols; /* Number of padding columns in MPE table,
+ valid only for DVB-H */
+ u32 num_of_punct_cols; /* Number of puncturing columns in MPE table,
+ valid only for DVB-H */
+ u32 error_ts_packets; /* Number of erroneous
+ transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+ u32 num_of_valid_mpe_tlbs; /* Number of MPE tables which do not include
+ errors after MPE RS decoding */
+ u32 num_of_invalid_mpe_tlbs;/* Number of MPE tables which include errors
+ after MPE RS decoding */
+ u32 num_of_corrected_mpe_tlbs;/* Number of MPE tables which were
+ corrected by MPE RS decoding */
+ /* Common params */
+ u32 ber_error_count; /* Number of errornous SYNC bits. */
+ u32 ber_bit_count; /* Total number of SYNC bits. */
+
+ /* Interface information */
+ u32 sms_to_host_tx_errors; /* Total number of transmission errors. */
+
+ /* DAB/T-DMB */
+ u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi ber [1E-5] */
+
+ /* DVB-H TPS parameters */
+ u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+ if set to 0xFFFFFFFF cell_id not yet recovered */
+ u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 -
+ Time Slicing indicator, bit 0 - MPE-FEC indicator */
+ u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 -
+ Time Slicing indicator, bit 0 - MPE-FEC indicator */
+
+ u32 num_mpe_received; /* DVB-H, Num MPE section received */
+
+ u32 reservedFields[10]; /* reserved */
+};
+
+struct sms_msg_statistics_info {
+ u32 request_result;
+
+ struct sms_stats stat;
+
+ /* Split the calc of the SNR in DAB */
+ u32 signal; /* dB */
+ u32 noise; /* dB */
+
+};
+
+struct sms_isdbt_layer_stats {
+ /* Per-layer information */
+ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+ * 255 means layer does not exist */
+ u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET,
+ * 255 means layer does not exist */
+ u32 ber; /* Post Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 ber_error_count; /* Post Viterbi Error Bits Count */
+ u32 ber_bit_count; /* Post Viterbi Total Bits Count */
+ u32 pre_ber; /* Pre Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 ts_per; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
+ u32 error_ts_packets; /* Number of erroneous transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+ u32 ti_ldepth_i; /* Time interleaver depth I parameter,
+ * 255 means layer does not exist */
+ u32 number_of_segments; /* Number of segments in layer A,
+ * 255 means layer does not exist */
+ u32 tmcc_errors; /* TMCC errors */
+};
+
+struct sms_isdbt_stats {
+ u32 statistics_type; /* Enumerator identifying the type of the
+ * structure. Values are the same as
+ * SMSHOSTLIB_DEVICE_MODES_E
+ *
+ * This field MUST always be first in any
+ * statistics structure */
+
+ u32 full_size; /* Total size of the structure returned by the modem.
+ * If the size requested by the host is smaller than
+ * full_size, the struct will be truncated */
+
+ /* Common parameters */
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ /* Reception quality */
+ s32 SNR; /* dB */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in Hz */
+
+ /* Transmission parameters */
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz */
+ u32 transmission_mode; /* ISDB-T transmission mode */
+ u32 modem_state; /* 0 - Acquisition, 1 - Locked */
+ u32 guard_interval; /* Guard Interval, 1 divided by value */
+ u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+ u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */
+ u32 num_of_layers; /* Number of ISDB-T layers in the network */
+
+ /* Per-layer information */
+ /* Layers A, B and C */
+ struct sms_isdbt_layer_stats layer_info[3];
+ /* Per-layer statistics, see sms_isdbt_layer_stats */
+
+ /* Interface information */
+ u32 sms_to_host_tx_errors; /* Total number of transmission errors. */
+};
+
+struct sms_isdbt_stats_ex {
+ u32 statistics_type; /* Enumerator identifying the type of the
+ * structure. Values are the same as
+ * SMSHOSTLIB_DEVICE_MODES_E
+ *
+ * This field MUST always be first in any
+ * statistics structure */
+
+ u32 full_size; /* Total size of the structure returned by the modem.
+ * If the size requested by the host is smaller than
+ * full_size, the struct will be truncated */
+
+ /* Common parameters */
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ /* Reception quality */
+ s32 SNR; /* dB */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in Hz */
+
+ /* Transmission parameters */
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz */
+ u32 transmission_mode; /* ISDB-T transmission mode */
+ u32 modem_state; /* 0 - Acquisition, 1 - Locked */
+ u32 guard_interval; /* Guard Interval, 1 divided by value */
+ u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+ u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */
+ u32 num_of_layers; /* Number of ISDB-T layers in the network */
+
+ u32 segment_number; /* Segment number for ISDB-Tsb */
+ u32 tune_bw; /* Tuned bandwidth - BW_ISDBT_1SEG / BW_ISDBT_3SEG */
+
+ /* Per-layer information */
+ /* Layers A, B and C */
+ struct sms_isdbt_layer_stats layer_info[3];
+ /* Per-layer statistics, see sms_isdbt_layer_stats */
+
+ /* Interface information */
+ u32 reserved1; /* Was sms_to_host_tx_errors - obsolete . */
+ /* Proprietary information */
+ u32 ext_antenna; /* Obsolete field. */
+ u32 reception_quality;
+ u32 ews_alert_active; /* signals if EWS alert is currently on */
+ u32 lna_on_off; /* Internal LNA state: 0: OFF, 1: ON */
+
+ u32 rf_agc_level; /* RF AGC Level [linear units], full gain = 65535 (20dB) */
+ u32 bb_agc_level; /* Baseband AGC level [linear units], full gain = 65535 (71.5dB) */
+ u32 fw_errors_counter; /* Application errors - should be always zero */
+ u8 FwErrorsHistoryArr[8]; /* Last FW errors IDs - first is most recent, last is oldest */
+
+ s32 MRC_SNR; /* dB */
+ u32 snr_full_res; /* dB x 65536 */
+ u32 reserved4[4];
+};
+
+
+struct sms_pid_stats_data {
+ struct PID_BURST_S {
+ u32 size;
+ u32 padding_cols;
+ u32 punct_cols;
+ u32 duration;
+ u32 cycle;
+ u32 calc_cycle;
+ } burst;
+
+ u32 tot_tbl_cnt;
+ u32 invalid_tbl_cnt;
+ u32 tot_cor_tbl;
+};
+
+struct sms_pid_data {
+ u32 pid;
+ u32 num_rows;
+ struct sms_pid_stats_data pid_statistics;
+};
+
+#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
+#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.bandwidth = 8 - _stat.bandwidth)
+#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
+ if (_stat.transmission_mode == 0) \
+ _stat.transmission_mode = 2; \
+ else if (_stat.transmission_mode == 1) \
+ _stat.transmission_mode = 8; \
+ else \
+ _stat.transmission_mode = 4;
+
+struct sms_tx_stats {
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz */
+ u32 transmission_mode; /* FFT mode carriers in Kilos */
+ u32 guard_interval; /* Guard Interval from
+ SMSHOSTLIB_GUARD_INTERVALS_ET */
+ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
+ u32 lp_code_rate; /* Low Priority Code Rate from
+ SMSHOSTLIB_CODE_RATE_ET */
+ u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET */
+ u32 constellation; /* constellation from
+ SMSHOSTLIB_CONSTELLATION_ET */
+
+ /* DVB-H TPS parameters */
+ u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+ if set to 0xFFFFFFFF cell_id not yet recovered */
+ u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 -
+ Time Slicing indicator, bit 0 - MPE-FEC indicator */
+ u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 -
+ Time Slicing indicator, bit 0 - MPE-FEC indicator */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+};
+
+struct sms_rx_stats {
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+ s32 SNR; /* dB */
+ u32 ber; /* Post Viterbi ber [1E-5] */
+ u32 ber_error_count; /* Number of erroneous SYNC bits. */
+ u32 ber_bit_count; /* Total number of SYNC bits. */
+ u32 ts_per; /* Transport stream PER,
+ 0xFFFFFFFF indicate N/A */
+ u32 MFER; /* DVB-H frame error rate in percentage,
+ 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
+ u32 error_ts_packets; /* Number of erroneous
+ transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+
+ s32 MRC_SNR; /* dB */
+ s32 MRC_RSSI; /* dBm */
+ s32 mrc_in_band_pwr; /* In band power in dBM */
+};
+
+struct sms_rx_stats_ex {
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+ s32 SNR; /* dB */
+ u32 ber; /* Post Viterbi ber [1E-5] */
+ u32 ber_error_count; /* Number of erroneous SYNC bits. */
+ u32 ber_bit_count; /* Total number of SYNC bits. */
+ u32 ts_per; /* Transport stream PER,
+ 0xFFFFFFFF indicate N/A */
+ u32 MFER; /* DVB-H frame error rate in percentage,
+ 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
+ u32 error_ts_packets; /* Number of erroneous
+ transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+
+ s32 ref_dev_ppm;
+ s32 freq_dev_hz;
+
+ s32 MRC_SNR; /* dB */
+ s32 MRC_RSSI; /* dBm */
+ s32 mrc_in_band_pwr; /* In band power in dBM */
+};
+
+
+/* statistics information returned as response for
+ * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */
+struct sms_stats_dvb {
+ /* Reception */
+ struct sms_rx_stats reception_data;
+
+ /* Transmission parameters */
+ struct sms_tx_stats transmission_data;
+
+ /* Burst parameters, valid only for DVB-H */
+#define SRVM_MAX_PID_FILTERS 8
+ struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS];
+};
+
+/* statistics information returned as response for
+ * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */
+struct sms_stats_dvb_ex {
+ /* Reception */
+ struct sms_rx_stats_ex reception_data;
+
+ /* Transmission parameters */
+ struct sms_tx_stats transmission_data;
+
+ /* Burst parameters, valid only for DVB-H */
+#define SRVM_MAX_PID_FILTERS 8
+ struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS];
+};
+
+struct sms_srvm_signal_status {
+ u32 result;
+ u32 snr;
+ 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;
+
+ s32 in_band_power;
+ u32 request_id;
+};
+
+struct sms_i2c_req {
+ u32 device_address; /* I2c device address */
+ u32 write_count; /* number of bytes to write */
+ u32 read_count; /* number of bytes to read */
+ u8 Data[1];
+};
+
+struct sms_i2c_res {
+ u32 status; /* non-zero value in case of failure */
+ u32 read_count; /* number of bytes read */
+ u8 Data[1];
+};
+
+
+struct smscore_config_gpio {
+#define SMS_GPIO_DIRECTION_INPUT 0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+ u8 direction;
+
+#define SMS_GPIO_PULLUPDOWN_NONE 0
+#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
+#define SMS_GPIO_PULLUPDOWN_PULLUP 2
+#define SMS_GPIO_PULLUPDOWN_KEEPER 3
+ u8 pullupdown;
+
+#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0
+#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
+ u8 inputcharacteristics;
+
+ /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0
+#define SMS_GPIO_OUTPUT_SLEW_WRATE_SLOW 1
+
+ /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3
+
+ u8 outputslewrate;
+
+ /* 10xx */
+#define SMS_GPIO_OUTPUTDRIVING_S_4mA 0
+#define SMS_GPIO_OUTPUTDRIVING_S_8mA 1
+#define SMS_GPIO_OUTPUTDRIVING_S_12mA 2
+#define SMS_GPIO_OUTPUTDRIVING_S_16mA 3
+
+ /* 11xx*/
+#define SMS_GPIO_OUTPUTDRIVING_1_5mA 0
+#define SMS_GPIO_OUTPUTDRIVING_2_8mA 1
+#define SMS_GPIO_OUTPUTDRIVING_4mA 2
+#define SMS_GPIO_OUTPUTDRIVING_7mA 3
+#define SMS_GPIO_OUTPUTDRIVING_10mA 4
+#define SMS_GPIO_OUTPUTDRIVING_11mA 5
+#define SMS_GPIO_OUTPUTDRIVING_14mA 6
+#define SMS_GPIO_OUTPUTDRIVING_16mA 7
+
+ u8 outputdriving;
+};
+
+char *smscore_translate_msg(enum msg_types msgtype);
+
+extern int smscore_registry_getmode(char *devpath);
+
+extern int smscore_register_hotplug(hotplug_t hotplug);
+extern void smscore_unregister_hotplug(hotplug_t hotplug);
+
+extern int smscore_register_device(struct smsdevice_params_t *params,
+ struct smscore_device_t **coredev);
+extern void smscore_unregister_device(struct smscore_device_t *coredev);
+
+extern int smscore_start_device(struct smscore_device_t *coredev);
+extern int smscore_load_firmware(struct smscore_device_t *coredev,
+ char *filename,
+ loadfirmware_t loadfirmware_handler);
+
+extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
+extern int smscore_get_device_mode(struct smscore_device_t *coredev);
+
+extern int smscore_register_client(struct smscore_device_t *coredev,
+ struct smsclient_params_t *params,
+ struct smscore_client_t **client);
+extern void smscore_unregister_client(struct smscore_client_t *client);
+
+extern int smsclient_sendrequest(struct smscore_client_t *client,
+ void *buffer, size_t size);
+extern void smscore_onresponse(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb);
+
+extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
+extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
+ struct vm_area_struct *vma);
+extern int smscore_send_fw_file(struct smscore_device_t *coredev,
+ u8 *ufwbuf, int size);
+
+extern
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
+extern void smscore_putbuffer(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb);
+
+/* old GPIO management */
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+ struct smscore_config_gpio *pinconfig);
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
+
+/* new GPIO management */
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num,
+ struct smscore_config_gpio *p_gpio_config);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num,
+ u8 new_level);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
+ u8 *level);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id);
+int smscore_get_board_id(struct smscore_device_t *core);
+
+int smscore_led_state(struct smscore_device_t *core, int led);
+
+
+/* ------------------------------------------------------------------------ */
+
+#define DBG_INFO 1
+#define DBG_ADV 2
+
+#define sms_printk(kern, fmt, arg...) \
+ printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+ if (sms_dbg & lvl) \
+ sms_printk(kern, fmt, ##arg); \
+} while (0)
+
+#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+#define sms_err(fmt, arg...) \
+ sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
+#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg)
+#define sms_info(fmt, arg...) \
+ dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
+#define sms_debug(fmt, arg...) \
+ dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
+
+
+#endif /* __SMS_CORE_API_H__ */
diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c
new file mode 100644
index 00000000000..2408d7e9451
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb-debugfs.c
@@ -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;
+}
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
new file mode 100644
index 00000000000..85151efdd94
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -0,0 +1,1232 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, 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/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/div64.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+#include "smsdvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct list_head g_smsdvb_clients;
+static struct mutex g_smsdvb_clientslock;
+
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+
+static u32 sms_to_guard_interval_table[] = {
+ [0] = GUARD_INTERVAL_1_32,
+ [1] = GUARD_INTERVAL_1_16,
+ [2] = GUARD_INTERVAL_1_8,
+ [3] = GUARD_INTERVAL_1_4,
+};
+
+static u32 sms_to_code_rate_table[] = {
+ [0] = FEC_1_2,
+ [1] = FEC_2_3,
+ [2] = FEC_3_4,
+ [3] = FEC_5_6,
+ [4] = FEC_7_8,
+};
+
+
+static u32 sms_to_hierarchy_table[] = {
+ [0] = HIERARCHY_NONE,
+ [1] = HIERARCHY_1,
+ [2] = HIERARCHY_2,
+ [3] = HIERARCHY_4,
+};
+
+static u32 sms_to_modulation_table[] = {
+ [0] = QPSK,
+ [1] = QAM_16,
+ [2] = QAM_64,
+ [3] = DQPSK,
+};
+
+
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+ enum SMS_DVB3_EVENTS event) {
+
+ struct smscore_device_t *coredev = client->coredev;
+ switch (event) {
+ case DVB3_EVENT_INIT:
+ sms_debug("DVB3_EVENT_INIT");
+ sms_board_event(coredev, BOARD_EVENT_BIND);
+ break;
+ case DVB3_EVENT_SLEEP:
+ sms_debug("DVB3_EVENT_SLEEP");
+ sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+ break;
+ case DVB3_EVENT_HOTPLUG:
+ sms_debug("DVB3_EVENT_HOTPLUG");
+ sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+ break;
+ case DVB3_EVENT_FE_LOCK:
+ if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+ client->event_fe_state = DVB3_EVENT_FE_LOCK;
+ sms_debug("DVB3_EVENT_FE_LOCK");
+ sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+ }
+ break;
+ case DVB3_EVENT_FE_UNLOCK:
+ if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+ client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+ sms_debug("DVB3_EVENT_FE_UNLOCK");
+ sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+ }
+ break;
+ case DVB3_EVENT_UNC_OK:
+ if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+ client->event_unc_state = DVB3_EVENT_UNC_OK;
+ sms_debug("DVB3_EVENT_UNC_OK");
+ sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+ }
+ break;
+ case DVB3_EVENT_UNC_ERR:
+ if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+ client->event_unc_state = DVB3_EVENT_UNC_ERR;
+ sms_debug("DVB3_EVENT_UNC_ERR");
+ sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+ }
+ break;
+
+ default:
+ sms_err("Unknown dvb3 api event");
+ break;
+ }
+}
+
+static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int i, n_layers;
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ n_layers = 4;
+ break;
+ default:
+ n_layers = 1;
+ }
+
+ /* Global stats */
+ c->strength.len = 1;
+ c->cnr.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+
+ /* Per-layer stats */
+ c->post_bit_error.len = n_layers;
+ c->post_bit_count.len = n_layers;
+ c->block_error.len = n_layers;
+ c->block_count.len = n_layers;
+
+ /*
+ * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically
+ * changed when the stats become available.
+ */
+ for (i = 0; i < n_layers; i++) {
+ c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+}
+
+static inline int sms_to_mode(u32 mode)
+{
+ switch (mode) {
+ case 2:
+ return TRANSMISSION_MODE_2K;
+ case 4:
+ return TRANSMISSION_MODE_4K;
+ case 8:
+ return TRANSMISSION_MODE_8K;
+ }
+ return TRANSMISSION_MODE_AUTO;
+}
+
+static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
+{
+ if (is_demod_locked)
+ return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+
+ if (is_rf_locked)
+ return FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+ return 0;
+}
+
+static inline u32 sms_to_bw(u32 value)
+{
+ return value * 1000000;
+}
+
+#define convert_from_table(value, table, defval) ({ \
+ u32 __ret; \
+ if (value < ARRAY_SIZE(table)) \
+ __ret = table[value]; \
+ else \
+ __ret = defval; \
+ __ret; \
+})
+
+#define sms_to_guard_interval(value) \
+ convert_from_table(value, sms_to_guard_interval_table, \
+ GUARD_INTERVAL_AUTO);
+
+#define sms_to_code_rate(value) \
+ convert_from_table(value, sms_to_code_rate_table, \
+ FEC_NONE);
+
+#define sms_to_hierarchy(value) \
+ convert_from_table(value, sms_to_hierarchy_table, \
+ FEC_NONE);
+
+#define sms_to_modulation(value) \
+ convert_from_table(value, sms_to_modulation_table, \
+ FEC_NONE);
+
+static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
+ struct sms_tx_stats *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ c->frequency = p->frequency;
+ client->fe_status = sms_to_status(p->is_demod_locked, 0);
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->code_rate_HP = sms_to_code_rate(p->code_rate);
+ c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
+ c->hierarchy = sms_to_hierarchy(p->hierarchy);
+ c->modulation = sms_to_modulation(p->constellation);
+}
+
+static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
+ struct RECEPTION_STATISTICS_PER_SLICES_S *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u64 tmp;
+
+ client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
+ c->modulation = sms_to_modulation(p->constellation);
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_power * 1000;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->snr * 1000;
+
+ /* PER/BER requires demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ /* TS PER */
+ client->last_per = c->block_error.stat[0].uvalue;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += p->ets_packets;
+ c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets;
+
+ /* ber */
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += p->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
+
+ /* Legacy PER/BER */
+ tmp = p->ets_packets * 65535;
+ if (p->ts_packets + p->ets_packets)
+ do_div(tmp, p->ts_packets + p->ets_packets);
+ client->legacy_per = tmp;
+}
+
+static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
+ struct sms_stats *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ if (client->prt_dvb_stats)
+ client->prt_dvb_stats(client->debug_data, p);
+
+ client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
+
+ /* Update DVB modulation parameters */
+ c->frequency = p->frequency;
+ client->fe_status = sms_to_status(p->is_demod_locked, 0);
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->code_rate_HP = sms_to_code_rate(p->code_rate);
+ c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
+ c->hierarchy = sms_to_hierarchy(p->hierarchy);
+ c->modulation = sms_to_modulation(p->constellation);
+
+ /* update reception data */
+ c->lna = p->is_external_lna_on ? 1 : 0;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->SNR * 1000;
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
+
+ /* PER/BER requires demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ /* TS PER */
+ client->last_per = c->block_error.stat[0].uvalue;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += p->error_ts_packets;
+ c->block_count.stat[0].uvalue += p->total_ts_packets;
+
+ /* ber */
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += p->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
+
+ /* Legacy PER/BER */
+ client->legacy_ber = p->ber;
+};
+
+static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
+ struct sms_isdbt_stats *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct sms_isdbt_layer_stats *lr;
+ int i, n_layers;
+
+ if (client->prt_isdb_stats)
+ client->prt_isdb_stats(client->debug_data, p);
+
+ client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
+
+ /*
+ * Firmware 2.1 seems to report only lock status and
+ * signal strength. The signal strength indicator is at the
+ * wrong field.
+ */
+ if (p->statistics_type == 0) {
+ c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return;
+ }
+
+ /* Update ISDB-T transmission parameters */
+ c->frequency = p->frequency;
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
+ n_layers = p->num_of_layers;
+ if (n_layers < 1)
+ n_layers = 1;
+ if (n_layers > 3)
+ n_layers = 3;
+ c->isdbt_layer_enabled = 0;
+
+ /* update reception data */
+ c->lna = p->is_external_lna_on ? 1 : 0;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->SNR * 1000;
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
+
+ /* PER/BER and per-layer stats require demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ client->last_per = c->block_error.stat[0].uvalue;
+
+ /* Clears global counters, as the code below will sum it again */
+ c->block_error.stat[0].uvalue = 0;
+ c->block_count.stat[0].uvalue = 0;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = 0;
+ c->post_bit_count.stat[0].uvalue = 0;
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+
+ for (i = 0; i < n_layers; i++) {
+ lr = &p->layer_info[i];
+
+ /* Update per-layer transmission parameters */
+ if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
+ c->isdbt_layer_enabled |= 1 << i;
+ c->layer[i].segment_count = lr->number_of_segments;
+ } else {
+ continue;
+ }
+ c->layer[i].modulation = sms_to_modulation(lr->constellation);
+
+ /* TS PER */
+ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
+ c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
+
+ /* Update global PER counter */
+ c->block_error.stat[0].uvalue += lr->error_ts_packets;
+ c->block_count.stat[0].uvalue += lr->total_ts_packets;
+
+ /* BER */
+ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
+
+ /* Update global BER counter */
+ c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
+ }
+}
+
+static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
+ struct sms_isdbt_stats_ex *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct sms_isdbt_layer_stats *lr;
+ int i, n_layers;
+
+ if (client->prt_isdb_stats_ex)
+ client->prt_isdb_stats_ex(client->debug_data, p);
+
+ /* Update ISDB-T transmission parameters */
+ c->frequency = p->frequency;
+ client->fe_status = sms_to_status(p->is_demod_locked, 0);
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
+ n_layers = p->num_of_layers;
+ if (n_layers < 1)
+ n_layers = 1;
+ if (n_layers > 3)
+ n_layers = 3;
+ c->isdbt_layer_enabled = 0;
+
+ /* update reception data */
+ c->lna = p->is_external_lna_on ? 1 : 0;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->SNR * 1000;
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
+
+ /* PER/BER and per-layer stats require demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ client->last_per = c->block_error.stat[0].uvalue;
+
+ /* Clears global counters, as the code below will sum it again */
+ c->block_error.stat[0].uvalue = 0;
+ c->block_count.stat[0].uvalue = 0;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = 0;
+ c->post_bit_count.stat[0].uvalue = 0;
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+
+ c->post_bit_error.len = n_layers + 1;
+ c->post_bit_count.len = n_layers + 1;
+ c->block_error.len = n_layers + 1;
+ c->block_count.len = n_layers + 1;
+ for (i = 0; i < n_layers; i++) {
+ lr = &p->layer_info[i];
+
+ /* Update per-layer transmission parameters */
+ if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
+ c->isdbt_layer_enabled |= 1 << i;
+ c->layer[i].segment_count = lr->number_of_segments;
+ } else {
+ continue;
+ }
+ c->layer[i].modulation = sms_to_modulation(lr->constellation);
+
+ /* TS PER */
+ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
+ c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
+
+ /* Update global PER counter */
+ c->block_error.stat[0].uvalue += lr->error_ts_packets;
+ c->block_count.stat[0].uvalue += lr->total_ts_packets;
+
+ /* ber */
+ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
+
+ /* Update global ber counter */
+ c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
+ }
+}
+
+static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+ struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p)
+ + cb->offset);
+ void *p = phdr + 1;
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ bool is_status_update = false;
+
+ switch (phdr->msg_type) {
+ case MSG_SMS_DVBT_BDA_DATA:
+ /*
+ * Only feed data to dvb demux if are there any feed listening
+ * to it and if the device has tuned
+ */
+ if (client->feed_users && client->has_tuned)
+ dvb_dmx_swfilter(&client->demux, p,
+ cb->size - sizeof(struct sms_msg_hdr));
+ break;
+
+ case MSG_SMS_RF_TUNE_RES:
+ case MSG_SMS_ISDBT_TUNE_RES:
+ complete(&client->tune_done);
+ break;
+
+ case MSG_SMS_SIGNAL_DETECTED_IND:
+ client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_NO_SIGNAL_IND:
+ client->fe_status = 0;
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_TRANSMISSION_IND:
+ smsdvb_update_tx_params(client, p);
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_HO_PER_SLICES_IND:
+ smsdvb_update_per_slices(client, p);
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_GET_STATISTICS_RES:
+ switch (smscore_get_device_mode(client->coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ smsdvb_update_isdbt_stats(client, p);
+ break;
+ default:
+ /* Skip sms_msg_statistics_info:request_result field */
+ smsdvb_update_dvb_stats(client, p + sizeof(u32));
+ }
+
+ is_status_update = true;
+ break;
+
+ /* Only for ISDB-T */
+ case MSG_SMS_GET_STATISTICS_EX_RES:
+ /* Skip sms_msg_statistics_info:request_result field? */
+ smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
+ is_status_update = true;
+ break;
+ default:
+ sms_info("message not handled");
+ }
+ smscore_putbuffer(client->coredev, cb);
+
+ if (is_status_update) {
+ if (client->fe_status & FE_HAS_LOCK) {
+ sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+ if (client->last_per == c->block_error.stat[0].uvalue)
+ sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+ else
+ sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
+ client->has_tuned = true;
+ } else {
+ smsdvb_stats_not_ready(fe);
+ client->has_tuned = false;
+ sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+ }
+ complete(&client->stats_done);
+ }
+
+ return 0;
+}
+
+static void smsdvb_unregister_client(struct smsdvb_client_t *client)
+{
+ /* must be called under clientslock */
+
+ list_del(&client->entry);
+
+ smsdvb_debugfs_release(client);
+ smscore_unregister_client(client->smsclient);
+ dvb_unregister_frontend(&client->frontend);
+ dvb_dmxdev_release(&client->dmxdev);
+ dvb_dmx_release(&client->demux);
+ dvb_unregister_adapter(&client->adapter);
+ kfree(client);
+}
+
+static void smsdvb_onremove(void *context)
+{
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ smsdvb_unregister_client((struct smsdvb_client_t *) context);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+static int smsdvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct smsdvb_client_t *client =
+ container_of(feed->demux, struct smsdvb_client_t, demux);
+ struct sms_msg_data pid_msg;
+
+ sms_debug("add pid %d(%x)",
+ feed->pid, feed->pid);
+
+ client->feed_users++;
+
+ pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ pid_msg.x_msg_header.msg_dst_id = HIF_TASK;
+ pid_msg.x_msg_header.msg_flags = 0;
+ pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ;
+ pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
+ pid_msg.msg_data[0] = feed->pid;
+
+ return smsclient_sendrequest(client->smsclient,
+ &pid_msg, sizeof(pid_msg));
+}
+
+static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct smsdvb_client_t *client =
+ container_of(feed->demux, struct smsdvb_client_t, demux);
+ struct sms_msg_data pid_msg;
+
+ sms_debug("remove pid %d(%x)",
+ feed->pid, feed->pid);
+
+ client->feed_users--;
+
+ pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ pid_msg.x_msg_header.msg_dst_id = HIF_TASK;
+ pid_msg.x_msg_header.msg_flags = 0;
+ pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ;
+ pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
+ pid_msg.msg_data[0] = feed->pid;
+
+ return smsclient_sendrequest(client->smsclient,
+ &pid_msg, sizeof(pid_msg));
+}
+
+static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
+ void *buffer, size_t size,
+ struct completion *completion)
+{
+ int rc;
+
+ rc = smsclient_sendrequest(client->smsclient, buffer, size);
+ if (rc < 0)
+ return rc;
+
+ return wait_for_completion_timeout(completion,
+ msecs_to_jiffies(2000)) ?
+ 0 : -ETIME;
+}
+
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+ int rc;
+ struct sms_msg_hdr msg;
+
+ /* Don't request stats too fast */
+ if (client->get_stats_jiffies &&
+ (!time_after(jiffies, client->get_stats_jiffies)))
+ return 0;
+ client->get_stats_jiffies = jiffies + msecs_to_jiffies(100);
+
+ msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.msg_dst_id = HIF_TASK;
+ msg.msg_flags = 0;
+ msg.msg_length = sizeof(msg);
+
+ switch (smscore_get_device_mode(client->coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ /*
+ * Check for firmware version, to avoid breaking for old cards
+ */
+ if (client->coredev->fw_version >= 0x800)
+ msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ;
+ else
+ msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
+ break;
+ default:
+ msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
+ }
+
+ rc = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->stats_done);
+
+ return rc;
+}
+
+static inline int led_feedback(struct smsdvb_client_t *client)
+{
+ if (!(client->fe_status & FE_HAS_LOCK))
+ return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+
+ return sms_board_led_feedback(client->coredev,
+ (client->legacy_ber == 0) ?
+ SMS_LED_HI : SMS_LED_LO);
+}
+
+static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ int rc;
+ struct smsdvb_client_t *client;
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ *stat = client->fe_status;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ int rc;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ *ber = client->legacy_ber;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+ s32 power = (s32) c->strength.stat[0].uvalue;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ if (power < -95)
+ *strength = 0;
+ else if (power > -29)
+ *strength = 65535;
+ else
+ *strength = (power + 95) * 65535 / 66;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ /* Preferred scale for SNR with legacy API: 0.1 dB */
+ *snr = ((u32)c->cnr.stat[0].svalue) / 100;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ int rc;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ *ucblocks = c->block_error.stat[0].uvalue;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ sms_debug("");
+
+ tune->min_delay_ms = 400;
+ tune->step_size = 250000;
+ tune->max_drift = 0;
+ return 0;
+}
+
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ struct {
+ struct sms_msg_hdr msg;
+ u32 Data[3];
+ } msg;
+
+ int ret;
+
+ client->fe_status = 0;
+ client->event_fe_state = -1;
+ client->event_unc_state = -1;
+ fe->dtv_property_cache.delivery_system = SYS_DVBT;
+
+ msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.msg.msg_dst_id = HIF_TASK;
+ msg.msg.msg_flags = 0;
+ msg.msg.msg_type = MSG_SMS_RF_TUNE_REQ;
+ msg.msg.msg_length = sizeof(msg);
+ msg.Data[0] = c->frequency;
+ msg.Data[2] = 12000000;
+
+ sms_info("%s: freq %d band %d", __func__, c->frequency,
+ c->bandwidth_hz);
+
+ switch (c->bandwidth_hz / 1000000) {
+ case 8:
+ msg.Data[1] = BW_8_MHZ;
+ break;
+ case 7:
+ msg.Data[1] = BW_7_MHZ;
+ break;
+ case 6:
+ msg.Data[1] = BW_6_MHZ;
+ break;
+ case 0:
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+ /* Disable LNA, if any. An error is returned if no LNA is present */
+ ret = sms_board_lna_control(client->coredev, 0);
+ if (ret == 0) {
+ fe_status_t status;
+
+ /* tune with LNA off at first */
+ ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+
+ smsdvb_read_status(fe, &status);
+
+ if (status & FE_HAS_LOCK)
+ return ret;
+
+ /* previous tune didn't lock - enable LNA and tune again */
+ sms_board_lna_control(client->coredev, 1);
+ }
+
+ return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+}
+
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int board_id = smscore_get_board_id(client->coredev);
+ struct sms_board *board = sms_get_board(board_id);
+ enum sms_device_type_st type = board->type;
+ int ret;
+
+ struct {
+ struct sms_msg_hdr msg;
+ u32 Data[4];
+ } msg;
+
+ fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+ msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.msg.msg_dst_id = HIF_TASK;
+ msg.msg.msg_flags = 0;
+ msg.msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ;
+ msg.msg.msg_length = sizeof(msg);
+
+ if (c->isdbt_sb_segment_idx == -1)
+ c->isdbt_sb_segment_idx = 0;
+
+ if (!c->isdbt_layer_enabled)
+ c->isdbt_layer_enabled = 7;
+
+ msg.Data[0] = c->frequency;
+ msg.Data[1] = BW_ISDBT_1SEG;
+ msg.Data[2] = 12000000;
+ msg.Data[3] = c->isdbt_sb_segment_idx;
+
+ if (c->isdbt_partial_reception) {
+ if ((type == SMS_PELE || type == SMS_RIO) &&
+ c->isdbt_sb_segment_count > 3)
+ msg.Data[1] = BW_ISDBT_13SEG;
+ else if (c->isdbt_sb_segment_count > 1)
+ msg.Data[1] = BW_ISDBT_3SEG;
+ } else if (type == SMS_PELE || type == SMS_RIO)
+ msg.Data[1] = BW_ISDBT_13SEG;
+
+ c->bandwidth_hz = 6000000;
+
+ sms_info("%s: freq %d segwidth %d segindex %d", __func__,
+ c->frequency, c->isdbt_sb_segment_count,
+ c->isdbt_sb_segment_idx);
+
+ /* Disable LNA, if any. An error is returned if no LNA is present */
+ ret = sms_board_lna_control(client->coredev, 0);
+ if (ret == 0) {
+ fe_status_t status;
+
+ /* tune with LNA off at first */
+ ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+
+ smsdvb_read_status(fe, &status);
+
+ if (status & FE_HAS_LOCK)
+ return ret;
+
+ /* previous tune didn't lock - enable LNA and tune again */
+ sms_board_lna_control(client->coredev, 1);
+ }
+ return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+
+ smsdvb_stats_not_ready(fe);
+ c->strength.stat[0].uvalue = 0;
+ c->cnr.stat[0].uvalue = 0;
+
+ client->has_tuned = false;
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ return smsdvb_dvbt_set_frontend(fe);
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ return smsdvb_isdbt_set_frontend(fe);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Nothing to do here, as stats are automatically updated */
+static int smsdvb_get_frontend(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int smsdvb_init(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_board_power(client->coredev, 1);
+
+ sms_board_dvb3_event(client, DVB3_EVENT_INIT);
+ return 0;
+}
+
+static int smsdvb_sleep(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+ sms_board_power(client->coredev, 0);
+
+ sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
+
+ return 0;
+}
+
+static void smsdvb_release(struct dvb_frontend *fe)
+{
+ /* do nothing */
+}
+
+static struct dvb_frontend_ops smsdvb_fe_ops = {
+ .info = {
+ .name = "Siano Mobile Digital MDTV Receiver",
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = smsdvb_release,
+
+ .set_frontend = smsdvb_set_frontend,
+ .get_frontend = smsdvb_get_frontend,
+ .get_tune_settings = smsdvb_get_tune_settings,
+
+ .read_status = smsdvb_read_status,
+ .read_ber = smsdvb_read_ber,
+ .read_signal_strength = smsdvb_read_signal_strength,
+ .read_snr = smsdvb_read_snr,
+ .read_ucblocks = smsdvb_read_ucblocks,
+
+ .init = smsdvb_init,
+ .sleep = smsdvb_sleep,
+};
+
+static int smsdvb_hotplug(struct smscore_device_t *coredev,
+ struct device *device, int arrival)
+{
+ struct smsclient_params_t params;
+ struct smsdvb_client_t *client;
+ int rc;
+
+ /* device removal handled by onremove callback */
+ if (!arrival)
+ return 0;
+ client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
+ if (!client) {
+ sms_err("kmalloc() failed");
+ return -ENOMEM;
+ }
+
+ /* register dvb adapter */
+ rc = dvb_register_adapter(&client->adapter,
+ sms_get_board(
+ smscore_get_board_id(coredev))->name,
+ THIS_MODULE, device, adapter_nr);
+ if (rc < 0) {
+ sms_err("dvb_register_adapter() failed %d", rc);
+ goto adapter_error;
+ }
+
+ /* init dvb demux */
+ client->demux.dmx.capabilities = DMX_TS_FILTERING;
+ client->demux.filternum = 32; /* todo: nova ??? */
+ client->demux.feednum = 32;
+ client->demux.start_feed = smsdvb_start_feed;
+ client->demux.stop_feed = smsdvb_stop_feed;
+
+ rc = dvb_dmx_init(&client->demux);
+ if (rc < 0) {
+ sms_err("dvb_dmx_init failed %d", rc);
+ goto dvbdmx_error;
+ }
+
+ /* init dmxdev */
+ client->dmxdev.filternum = 32;
+ client->dmxdev.demux = &client->demux.dmx;
+ client->dmxdev.capabilities = 0;
+
+ rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
+ if (rc < 0) {
+ sms_err("dvb_dmxdev_init failed %d", rc);
+ goto dmxdev_error;
+ }
+
+ /* init and register frontend */
+ memcpy(&client->frontend.ops, &smsdvb_fe_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ client->frontend.ops.delsys[0] = SYS_DVBT;
+ break;
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ client->frontend.ops.delsys[0] = SYS_ISDBT;
+ break;
+ }
+
+ rc = dvb_register_frontend(&client->adapter, &client->frontend);
+ if (rc < 0) {
+ sms_err("frontend registration failed %d", rc);
+ goto frontend_error;
+ }
+
+ params.initial_id = 1;
+ params.data_type = MSG_SMS_DVBT_BDA_DATA;
+ params.onresponse_handler = smsdvb_onresponse;
+ params.onremove_handler = smsdvb_onremove;
+ params.context = client;
+
+ rc = smscore_register_client(coredev, &params, &client->smsclient);
+ if (rc < 0) {
+ sms_err("smscore_register_client() failed %d", rc);
+ goto client_error;
+ }
+
+ client->coredev = coredev;
+
+ init_completion(&client->tune_done);
+ init_completion(&client->stats_done);
+
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ list_add(&client->entry, &g_smsdvb_clients);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+
+ client->event_fe_state = -1;
+ client->event_unc_state = -1;
+ sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
+
+ sms_info("success");
+ sms_board_setup(coredev);
+
+ if (smsdvb_debugfs_create(client) < 0)
+ sms_info("failed to create debugfs node");
+
+ return 0;
+
+client_error:
+ dvb_unregister_frontend(&client->frontend);
+
+frontend_error:
+ dvb_dmxdev_release(&client->dmxdev);
+
+dmxdev_error:
+ dvb_dmx_release(&client->demux);
+
+dvbdmx_error:
+ dvb_unregister_adapter(&client->adapter);
+
+adapter_error:
+ kfree(client);
+ return rc;
+}
+
+static int __init smsdvb_module_init(void)
+{
+ int rc;
+
+ INIT_LIST_HEAD(&g_smsdvb_clients);
+ kmutex_init(&g_smsdvb_clientslock);
+
+ smsdvb_debugfs_register();
+
+ rc = smscore_register_hotplug(smsdvb_hotplug);
+
+ sms_debug("");
+
+ return rc;
+}
+
+static void __exit smsdvb_module_exit(void)
+{
+ smscore_unregister_hotplug(smsdvb_hotplug);
+
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ while (!list_empty(&g_smsdvb_clients))
+ smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
+
+ smsdvb_debugfs_unregister();
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+module_init(smsdvb_module_init);
+module_exit(smsdvb_module_exit);
+
+MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h
new file mode 100644
index 00000000000..ae36d0ae0fb
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb.h
@@ -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
+
diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c
new file mode 100644
index 00000000000..bfe831c10b1
--- /dev/null
+++ b/drivers/media/common/siano/smsendian.c
@@ -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);
diff --git a/drivers/media/common/siano/smsendian.h b/drivers/media/common/siano/smsendian.h
new file mode 100644
index 00000000000..1624d6fd367
--- /dev/null
+++ b/drivers/media/common/siano/smsendian.h
@@ -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__ */
+
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
new file mode 100644
index 00000000000..6d7c0c858bd
--- /dev/null
+++ b/drivers/media/common/siano/smsir.c
@@ -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;
+ rc_set_allowed_protocols(dev, 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("");
+}
diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
new file mode 100644
index 00000000000..fc8b7925c53
--- /dev/null
+++ b/drivers/media/common/siano/smsir.h
@@ -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__ */
+
diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c
new file mode 100644
index 00000000000..c7dace671a9
--- /dev/null
+++ b/drivers/media/common/tveeprom.c
@@ -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);