diff options
-rw-r--r-- | Documentation/dvb/README.flexcop | 279 | ||||
-rw-r--r-- | drivers/media/dvb/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/Kconfig | 37 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/Makefile | 11 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-common.h | 161 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-dma.c | 149 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-eeprom.c | 157 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 403 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-hw-filter.c | 198 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-i2c.c | 204 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-misc.c | 66 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-pci.c | 365 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-reg.h | 700 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-sram.c | 403 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-usb.c | 530 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop-usb.h | 116 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop.c | 288 | ||||
-rw-r--r-- | drivers/media/dvb/b2c2/flexcop.h | 30 |
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 |