aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/dvb/README.flexcop279
-rw-r--r--drivers/media/dvb/Kconfig2
-rw-r--r--drivers/media/dvb/b2c2/Kconfig37
-rw-r--r--drivers/media/dvb/b2c2/Makefile11
-rw-r--r--drivers/media/dvb/b2c2/flexcop-common.h161
-rw-r--r--drivers/media/dvb/b2c2/flexcop-dma.c149
-rw-r--r--drivers/media/dvb/b2c2/flexcop-eeprom.c157
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c403
-rw-r--r--drivers/media/dvb/b2c2/flexcop-hw-filter.c198
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c204
-rw-r--r--drivers/media/dvb/b2c2/flexcop-misc.c66
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c365
-rw-r--r--drivers/media/dvb/b2c2/flexcop-reg.h700
-rw-r--r--drivers/media/dvb/b2c2/flexcop-sram.c403
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c530
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.h116
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c288
-rw-r--r--drivers/media/dvb/b2c2/flexcop.h30
18 files changed, 4098 insertions, 1 deletions
diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop
new file mode 100644
index 00000000000..9ec735714e4
--- /dev/null
+++ b/Documentation/dvb/README.flexcop
@@ -0,0 +1,279 @@
+This README escorted the skystar2-driver rewriting procedure. It describes the
+state of the new flexcop-driver set and some internals are written down here
+too.
+
+How to do something in here?
+============================
+
+make -f Makefile.t
+make -C ../build-2.6
+./in.sh # load the drivers
+./rm.sh # unload the drivers
+
+Please read this file, if you want to contribute.
+
+This document hopefully describes things about the flexcop and its
+device-offsprings. Goal is to write a easy-to-write and easy-to-read set of
+drivers based on the skystar2.c and other information.
+
+This directory is temporary. It is used for rewriting the skystar2.c and to
+create shared code, which then can be used by the usb box as well.
+
+Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been
+touched and rewritten.
+
+General coding processing
+=========================
+
+We should proceed as follows (as long as no one complains):
+
+0) Think before start writing code!
+
+1) rewriting the skystar2.c with the help of the flexcop register descriptions
+and splitting up the files to a pci-bus-part and a flexcop-part.
+The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the
+device-specific part and b2c2-flexcop.ko for the common flexcop-functions.
+
+2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c
+and other pci drivers)
+
+3) make some beautification (see 'Improvements when rewriting (refactoring) is
+done')
+
+4) Testing the new driver and maybe substitute the skystar2.c with it, to reach
+a wider tester audience.
+
+5) creating an usb-bus-part using the already written flexcop code for the pci
+card.
+
+Idea: create a kernel-object for the flexcop and export all important
+functions. This option saves kernel-memory, but maybe a lot of functions have
+to be exported to kernel namespace.
+
+
+Current situation
+=================
+
+0) Done :)
+1) Done (some minor issues left)
+2) Done
+3) Not ready yet, more information is necessary
+4) next to be done (see the table below)
+5) USB driver is working (yes, there are some minor issues)
+
+What seems to be ready?
+-----------------------
+
+1) Rewriting
+1a) i2c is cut off from the flexcop-pci.c and seems to work
+1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c
+1e) eeprom (reading MAC address)
+1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me))
+1f) misc. register accesses for reading parameters (e.g. resetting, revision)
+1g) pid/mac filter (flexcop-hw-filter.c)
+1i) dvb-stuff initialization in flexcop.c (done)
+1h) dma stuff (now just using the size-irq, instead of all-together, to be done)
+1j) remove flexcop initialization from flexcop-pci.c completely (done)
+1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO')
+1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from
+non-static where possible, moved code to proper places)
+
+2) Search for errors in the leftover of flexcop-pci.c (partially done)
+5a) add MAC address reading
+
+What to do in the near future?
+--------------------------------------
+(no special order here)
+
+
+5) USB driver
+5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting)
+5c) feeding of ISOC data to the software demux (format of the isochronous data
+and speed optimization, no real error)
+
+Testing changes
+---------------
+
+O = item is working
+P = item is partially working
+X = item is not working
+N = item does not apply here
+<empty field> = item need to be examined
+
+ | PCI | USB
+item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312
+-------+-------+---------+---------+-------+-------+---------+---------+-------
+1a) | O | | | | N | N | N | N
+1b) | O | | | | | | O |
+1c) | N | N | | | N | N | O |
+1d) | O | O
+1e) | O | O
+1f) | P
+1g) | O
+1h) | P |
+1i) | O | N
+1j) | O | N
+1l) | O | N
+2) | O | N
+5a) | N | O
+5b)* | N |
+5c)* | N |
+
+* - not done yet
+
+Known bugs and problems and TODO
+--------------------------------
+
+1g/h/l) when pid filtering is enabled on the pci card
+
+DMA usage currently:
+ The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first
+ address and triggers an IRQ when it's full and starts writing to the second
+ address. When the second address is full, the IRQ is triggered again, and
+ the flexcop writes to first address again, and so on.
+ The buffersize of each address is currently 640*188 bytes.
+
+ Problem is, when using hw-pid-filtering and doing some low-bandwidth
+ operation (like scanning) the buffers won't be filled enough to trigger
+ the IRQ. That's why:
+
+ When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ
+ is triggered. Is the current write address of DMA1 different to the one
+ during the last IRQ, then the data is passed to the demuxer.
+
+ There is an additional DMA-IRQ-method: packet count IRQ. This isn't
+ implemented correctly yet.
+
+ The solution is to disable HW PID filtering, but I don't know how the DVB
+ API software demux behaves on slow systems with 45MBit/s TS.
+
+Solved bugs :)
+--------------
+1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't
+working)
+SOLUTION: also index 0 was affected, because net_translation is done for
+these indexes by default
+
+5b) isochronous transfer does only work in the first attempt (for the Sky2PC USB,
+Air2PC is working)
+SOLUTION: the flexcop was going asleep and never really woke up again (don't
+know if this need fixes, see flexcop-fe-tuner.c:flexcop_sleep)
+
+Improvements when rewriting (refactoring) is done
+=================================================
+
+- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control
+ (enable sleeping for other demods than dvb-s)
+- add support for CableStar (stv0297 Microtune 203x/ALPS)
+
+Debugging
+---------
+- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it
+ with this flexcop, this is important, because i2c is now using the
+ flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for
+ that, please tell us so).
+
+Everything which is identical in the following table, can be put into a common
+flexcop-module.
+
+ PCI USB
+-------------------------------------------------------------------------------
+Different:
+Register access: accessing IO memory USB control message
+I2C bus: I2C bus of the FC USB control message
+Data transfer: DMA isochronous transfer
+EEPROM transfer: through i2c bus not clear yet
+
+Identical:
+Streaming: accessing registers
+PID Filtering: accessing registers
+Sram destinations: accessing registers
+Tuner/Demod: I2C bus
+DVB-stuff: can be written for common use
+
+Restrictions:
+============
+
+We need to create a bus-specific-struct and a flexcop-struct.
+
+bus-specific-struct:
+
+struct flexcop_pci
+...
+
+struct flexcop_usb
+...
+
+
+struct flexcop_device {
+ void *bus_specific; /* container for bus-specific struct */
+...
+}
+
+PCI i2c can read/write max 4 bytes at a time, USB can more
+
+Functions
+=========
+
+Syntax
+------
+
+- Flexcop functions will be called "flexcop(_[a-z0-9]+)+" and exported as such
+ if needed.
+- Flexcop-device functions will be called "flexcop_device(_[a-z0-9]+)+" and
+ exported as such if needed.
+- Both will be compiled to b2c2-flexcop.ko and their source can be found in the
+ flexcop*.[hc]
+
+Callbacks and exports
+---------------------
+
+Bus-specific functions will be given as callbacks (function pointers) to the
+flexcop-module. (within the flexcop_device-struct)
+
+Initialization process
+======================
+
+b2c2-flexcop.ko is loaded
+b2c2-flexcop-<bus>.ko is loaded
+
+suppose a device is found:
+malloc flexcop and the bus-specific variables (via flexcop_device_malloc)
+fill the bus-specific variable
+fill the flexcop variable (especially the bus-specific callbacks)
+bus-specific initialization
+ - ...
+do the common initialization (via flexcop_device_initialize)
+ - reset the card
+ - determine flexcop type (II, IIB, III)
+ - hw_filters (bus dependent)
+ - 0x204
+ - set sram size
+ - create the dvb-stuff
+ - create i2c stuff
+ - frontend-initialization
+done
+bus specific:
+ - media_destination (this and the following 3 are bus specific)
+ - cai_dest
+ - cao_dest
+ - net_destination
+
+Bugs fixed while rewriting the driver
+=====================================
+
+- EEPROM access (to read the MAC address) was fixed to death some time last
+ year. (fixed here and in skystar2.c) (Bjarne, this was the piece of code
+ (fix-chipaddr) we were wondering about)
+
+
+Acknowledgements (just for the rewriting part)
+================
+
+Bjarne Steinsbo thought a lot in the first place of the pci part for this code
+sharing idea.
+
+Andreas Oberritter for providing a recent PCI initialization template (pluto2.c).
+
+comments, critics and ideas to linux-dvb@linuxtv.org or patrick.boettcher@desy.de
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 883ec08490f..4983e1b1bb1 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -33,7 +33,7 @@ source "drivers/media/dvb/dibusb/Kconfig"
source "drivers/media/dvb/cinergyT2/Kconfig"
comment "Supported FlexCopII (B2C2) Adapters"
- depends on DVB_CORE && PCI
+ depends on DVB_CORE && (PCI || USB)
source "drivers/media/dvb/b2c2/Kconfig"
comment "Supported BT878 Adapters"
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index f1f6187b7c1..99bd675df95 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,3 +1,40 @@
+config DVB_B2C2_FLEXCOP
+ tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
+ depends on DVB_CORE
+ select DVB_STV0299
+ select DVB_MT352
+ select DVB_MT312
+ select DVB_NXT2002
+ select DVB_STV0297
+ help
+ Support for the digital TV receiver chip made by B2C2 Inc. included in
+ Technisats PCI cards and USB boxes.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_PCI
+ tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI"
+ depends on DVB_B2C2_FLEXCOP && PCI
+ help
+ Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_USB
+ tristate "Technisat/B2C2 Air/Sky/Cable2PC USB"
+ depends on DVB_B2C2_FLEXCOP && USB
+ help
+ Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2,
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_B2C2_FLEXCOP_DEBUG
+ bool "Enable debug for the B2C2 FlexCop drivers"
+ depends on DVB_B2C2_FLEXCOP
+ help
+ Say Y if you want to enable the module option to control debug messages
+ of all B2C2 FlexCop drivers.
+
config DVB_B2C2_SKYSTAR
tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
depends on DVB_CORE && PCI
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index f9cdc6f052d..7703812af34 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -1,3 +1,14 @@
+b2c2-flexcop-objs = flexcop.o flexcop-fe-tuner.o flexcop-i2c.o \
+ flexcop-sram.o flexcop-eeprom.o flexcop-misc.o flexcop-hw-filter.o \
+ flexcop-dma.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
+
+b2c2-flexcop-pci-objs = flexcop-pci.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
+
+b2c2-flexcop-usb-objs = flexcop-usb.o
+obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
+
obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
new file mode 100644
index 00000000000..82b7f8fa7b9
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -0,0 +1,161 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-common.h - common header file for device-specific source files also.
+ *
+ * see flexcop.c for copyright information.
+ */
+#ifndef __FLEXCOP_COMMON_H__
+#define __FLEXCOP_COMMON_H__
+
+#include <linux/config.h>
+#include <linux/pci.h>
+
+#include "flexcop-reg.h"
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#define FC_MAX_FEED 256
+
+#ifndef FC_LOG_PREFIX
+#warning please define a log prefix for your file, using a default one
+#define FC_LOG_PREFIX "b2c2-undef"
+#endif
+
+/* Steal from usb.h */
+#undef err
+#define err(format, arg...) printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
+
+struct flexcop_dma {
+ struct pci_dev *pdev;
+
+ u8 *cpu_addr0;
+ dma_addr_t dma_addr0;
+ u8 *cpu_addr1;
+ dma_addr_t dma_addr1;
+ u32 size; /* size of each address in bytes */
+};
+
+/* Control structure for data definitions that are common to
+ * the B2C2-based PCI and USB devices.
+ */
+struct flexcop_device {
+ /* general */
+ struct device *dev; /* for firmware_class */
+
+#define FC_STATE_DVB_INIT 0x01
+#define FC_STATE_I2C_INIT 0x02
+#define FC_STATE_FE_INIT 0x04
+ int init_state;
+
+ /* device information */
+ u8 mac_address[6];
+ int has_32_hw_pid_filter;
+ flexcop_revision_t rev;
+ flexcop_device_type_t dev_type;
+ flexcop_bus_t bus_type;
+
+ /* dvb stuff */
+ struct dvb_adapter dvb_adapter;
+ struct dvb_frontend *fe;
+ struct dvb_net dvbnet;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ int (*fe_sleep) (struct dvb_frontend *);
+
+ struct i2c_adapter i2c_adap;
+ struct semaphore i2c_sem;
+
+ /* options and status */
+ int feedcount;
+ int pid_filtering;
+
+ /* bus specific callbacks */
+ flexcop_ibi_value (*read_ibi_reg) (struct flexcop_device *, flexcop_ibi_register);
+ int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
+
+
+ int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+ int (*stream_control) (struct flexcop_device*, int);
+
+ int (*get_mac_addr) (struct flexcop_device *fc, int extended);
+
+ void *bus_specific;
+};
+
+/* exported prototypes */
+
+/* from flexcop.c */
+void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
+void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
+
+struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
+void flexcop_device_kfree(struct flexcop_device*);
+
+int flexcop_device_initialize(struct flexcop_device*);
+void flexcop_device_exit(struct flexcop_device *fc);
+
+/* 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_control_packet_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,flexcop_dma_addr_index_t index);
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);
+
+/* from flexcop-eeprom.c */
+/* the PCI part uses this call to get the MAC address, the USB part has its own */
+int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
+
+/* from flexcop-i2c.c */
+/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
+ * one. We have it in flexcop-i2c.c, because it is going via the actual
+ * I2C-channel of the flexcop.
+ */
+int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t,
+ flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+
+/* from flexcop-sram.c */
+int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
+void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
+void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill);
+
+/* global prototypes for the flexcop-chip */
+/* from flexcop-fe-tuner.c */
+int flexcop_frontend_init(struct flexcop_device *card);
+void flexcop_frontend_exit(struct flexcop_device *fc);
+
+/* from flexcop-i2c.c */
+int flexcop_i2c_init(struct flexcop_device *fc);
+void flexcop_i2c_exit(struct flexcop_device *fc);
+
+/* from flexcop-sram.c */
+int flexcop_sram_init(struct flexcop_device *fc);
+
+/* from flexcop-misc.c */
+void flexcop_determine_revision(struct flexcop_device *fc);
+void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+
+/* 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/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
new file mode 100644
index 00000000000..8d270607536
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size)
+{
+ u8 *tcpu;
+ dma_addr_t tdma;
+
+ if (size % 2) {
+ err("dma buffersize has to be even.");
+ return -EINVAL;
+ }
+
+ if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
+ dma->pdev = pdev;
+ dma->cpu_addr0 = tcpu;
+ dma->dma_addr0 = tdma;
+ dma->cpu_addr1 = tcpu + size/2;
+ dma->dma_addr1 = tdma + size/2;
+ dma->size = size/2;
+ return 0;
+ }
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(flexcop_dma_allocate);
+
+void flexcop_dma_free(struct flexcop_dma *dma)
+{
+ pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0);
+ memset(dma,0,sizeof(struct flexcop_dma));
+}
+EXPORT_SYMBOL(flexcop_dma_free);
+
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+
+int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_size_irq);
+
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+{
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
+
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
+{
+
+ flexcop_ibi_value v0x0,v0x4,v0xc;
+ v0x0.raw = v0x4.raw = v0xc.raw = 0;
+
+ v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+ v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
+ v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
+
+ if (index & FC_DMA_SUBADDR_0)
+ v0x0.dma_0x0.dma_0start = 1;
+
+ if (index & FC_DMA_SUBADDR_1)
+ v0xc.dma_0xc.dma_1start = 1;
+
+ if (dma_idx & FC_DMA_1) {
+ fc->write_ibi_reg(fc,dma1_000,v0x0);
+ fc->write_ibi_reg(fc,dma1_004,v0x4);
+ fc->write_ibi_reg(fc,dma1_00c,v0xc);
+ } else { /* (dma_idx & FC_DMA_2) */
+ fc->write_ibi_reg(fc,dma2_010,v0x0);
+ fc->write_ibi_reg(fc,dma2_014,v0x4);
+ fc->write_ibi_reg(fc,dma2_01c,v0xc);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config);
+
+static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+ v.dma_0xc.remap_enable = onoff;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
+
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+ flexcop_dma_remap(fc,dma_idx,0);
+
+ v.dma_0x4_write.dmatimer = cycles >> 1;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
+
+int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+
+ flexcop_dma_remap(fc,dma_idx,1);
+
+ v.dma_0x4_remap.DMA_maxpackets = packets;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_config_packet_count);
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
new file mode 100644
index 00000000000..4dbedd81973
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c
@@ -0,0 +1,157 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used)
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#if 0
+/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
+static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
+{
+ return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
+}
+
+static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
+{
+ int i;
+
+ for (i = 0; i < retries; i++) {
+ if (eeprom_write(adapter, addr, wbuf, len) == len) {
+ if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* These functions could be used to unlock SkyStar2 cards. */
+
+static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
+{
+ u8 rbuf[20];
+ u8 wbuf[20];
+
+ if (len != 16)
+ return 0;
+
+ memcpy(wbuf, key, len);
+
+ wbuf[16] = 0;
+ wbuf[17] = 0;
+ wbuf[18] = 0;
+ wbuf[19] = calc_lrc(wbuf, 19);
+
+ return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
+}
+
+static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
+{
+ u8 buf[20];
+
+ if (len != 16)
+ return 0;
+
+ if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
+ return 0;
+
+ memcpy(key, buf, len);
+
+ return 1;
+}
+
+static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
+{
+ u8 tmp[8];
+
+ if (type != 0) {
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+ tmp[3] = mac[5];
+ tmp[4] = mac[6];
+ tmp[5] = mac[7];
+
+ } else {
+
+ tmp[0] = mac[0];
+ tmp[1] = mac[1];
+ tmp[2] = mac[2];
+ tmp[3] = mac[3];
+ tmp[4] = mac[4];
+ tmp[5] = mac[5];
+ }
+
+ tmp[6] = 0;
+ tmp[7] = calc_lrc(tmp, 7);
+
+ if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
+ return 1;
+
+ return 0;
+}
+
+static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len)
+{
+ return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
+}
+
+#endif
+
+static u8 calc_lrc(u8 *buf, int len)
+{
+ int i;
+ u8 sum = 0;
+ for (i = 0; i < len; i++)
+ sum = sum ^ buf[i];
+ return sum;
+}
+
+static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
+{
+ int i,ret = 0;
+ u8 chipaddr = 0x50 | ((addr >> 8) & 3);
+ for (i = 0; i < retries; i++)
+ if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
+ break;
+ return ret;
+}
+
+static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
+{
+ int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
+ if (ret == 0)
+ if (calc_lrc(buf, len - 1) != buf[len - 1])
+ ret = -EINVAL;
+ return ret;
+}
+
+/* TODO how is it handled in USB */
+
+/* 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;
+
+ memset(fc->mac_address,0,6);
+
+ if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
+ if (extended != 0) {
+ err("TODO: extended (EUI64) MAC addresses aren't completely supported yet");
+ ret = -EINVAL;
+/* memcpy(fc->mac_address,buf,3);
+ mac[3] = 0xfe;
+ mac[4] = 0xff;
+ memcpy(&fc->mac_address[3],&buf[5],3); */
+ } else
+ memcpy(fc->mac_address,buf,6);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
new file mode 100644
index 00000000000..b3dd16fb5bb
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
+ *
+ * see flexcop.c for copyright information.
+ */
+#include "flexcop.h"
+
+#include "stv0299.h"
+#include "mt352.h"
+#include "nxt2002.h"
+#include "stv0297.h"
+#include "mt312.h"
+
+/* lnb control */
+
+static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ flexcop_ibi_value v;
+ deb_tuner("polarity/voltage = %u\n", voltage);
+
+ v = fc->read_ibi_reg(fc, misc_204);
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ v.misc_204.ACPI1_sig = 1;
+ break;
+ case SEC_VOLTAGE_13:
+ v.misc_204.ACPI1_sig = 0;
+ v.misc_204.LNB_L_H_sig = 0;
+ break;
+ case SEC_VOLTAGE_18:
+ v.misc_204.ACPI1_sig = 0;
+ v.misc_204.LNB_L_H_sig = 1;
+ break;
+ default:
+ err("unknown SEC_VOLTAGE value");
+ return -EINVAL;
+ }
+ return fc->write_ibi_reg(fc, misc_204, v);
+}
+
+static int flexcop_sleep(struct dvb_frontend* fe)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
+
+ if (fc->fe_sleep)
+ return fc->fe_sleep(fe);
+
+/* v.misc_204.ACPI3_sig = 1;
+ fc->write_ibi_reg(fc,misc_204,v);*/
+
+ return 0;
+}
+
+static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+ struct flexcop_device *fc = fe->dvb->priv;
+ flexcop_ibi_value v;
+ u16 ax;
+ v.raw = 0;
+
+ deb_tuner("tone = %u\n",tone);
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ ax = 0x01ff;
+ break;
+ case SEC_TONE_OFF:
+ ax = 0;
+ break;
+ default:
+ err("unknown SEC_TONE value");
+ return -EINVAL;
+ }
+
+ v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
+
+ v.lnb_switch_freq_200.LNB_CTLHighCount_sig =
+ v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax;
+
+ return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
+}
+
+static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
+{
+ flexcop_set_tone(fe, SEC_TONE_ON);
+ udelay(data ? 500 : 1000);
+ flexcop_set_tone(fe, SEC_TONE_OFF);
+ udelay(data ? 1000 : 500);
+}
+
+static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
+{
+ int i, par = 1, d;
+
+ for (i = 7; i >= 0; i--) {
+ d = (data >> i) & 1;
+ par ^= d;
+ flexcop_diseqc_send_bit(fe, d);
+ }
+
+ flexcop_diseqc_send_bit(fe, par);
+}
+
+static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
+{
+ int i;
+
+ flexcop_set_tone(fe, SEC_TONE_OFF);
+ mdelay(16);
+
+ for (i = 0; i < len; i++)
+ flexcop_diseqc_send_byte(fe,msg[i]);
+
+ mdelay(16);
+
+ if (burst != -1) {
+ if (burst)
+ flexcop_diseqc_send_byte(fe, 0xff);
+ else {
+ flexcop_set_tone(fe, SEC_TONE_ON);
+ udelay(12500);
+ flexcop_set_tone(fe, SEC_TONE_OFF);
+ }
+ msleep(20);
+ }
+ return 0;
+}
+
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
+}
+
+static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t min