[PATCH] dvb: b2c2/flexcop driver refactoring part 2: add modular Flexcop driver
b2c2/flexcop driver refactoring to support PCI and USB based cards part 2: add modular Flexcop driver Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
1ec3597299
commit
2add87a950
18 changed files with 4098 additions and 1 deletions
279
Documentation/dvb/README.flexcop
Normal file
279
Documentation/dvb/README.flexcop
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
161
drivers/media/dvb/b2c2/flexcop-common.h
Normal file
161
drivers/media/dvb/b2c2/flexcop-common.h
Normal file
|
@ -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
|
149
drivers/media/dvb/b2c2/flexcop-dma.c
Normal file
149
drivers/media/dvb/b2c2/flexcop-dma.c
Normal file
|
@ -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);
|
157
drivers/media/dvb/b2c2/flexcop-eeprom.c
Normal file
157
drivers/media/dvb/b2c2/flexcop-eeprom.c
Normal file
|
@ -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);
|
403
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
Normal file
403
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-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 minicmd)
|
||||
{
|
||||
return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
|
||||
}
|
||||
|
||||
/* dvb-s stv0299 */
|
||||
static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
|
||||
{
|
||||
u8 aclk = 0;
|
||||
u8 bclk = 0;
|
||||
|
||||
if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
|
||||
else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
|
||||
else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
|
||||
else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
|
||||
else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
|
||||
else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
|
||||
|
||||
stv0299_writereg (fe, 0x13, aclk);
|
||||
stv0299_writereg (fe, 0x14, bclk);
|
||||
stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
|
||||
stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
|
||||
stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
|
||||
{
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
|
||||
div = params->frequency / 125;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = div & 0xff;
|
||||
buf[2] = 0x84; /* 0xC4 */
|
||||
buf[3] = 0x08;
|
||||
|
||||
if (params->frequency < 1500000) buf[3] |= 0x10;
|
||||
|
||||
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 samsung_tbmu24112_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x30,
|
||||
0x03, 0x00,
|
||||
0x04, 0x7D,
|
||||
0x05, 0x35,
|
||||
0x06, 0x02,
|
||||
0x07, 0x00,
|
||||
0x08, 0xC3,
|
||||
0x0C, 0x00,
|
||||
0x0D, 0x81,
|
||||
0x0E, 0x23,
|
||||
0x0F, 0x12,
|
||||
0x10, 0x7E,
|
||||
0x11, 0x84,
|
||||
0x12, 0xB9,
|
||||
0x13, 0x88,
|
||||
0x14, 0x89,
|
||||
0x15, 0xC9,
|
||||
0x16, 0x00,
|
||||
0x17, 0x5C,
|
||||
0x18, 0x00,
|
||||
0x19, 0x00,
|
||||
0x1A, 0x00,
|
||||
0x1C, 0x00,
|
||||
0x1D, 0x00,
|
||||
0x1E, 0x00,
|
||||
0x1F, 0x3A,
|
||||
0x20, 0x2E,
|
||||
0x21, 0x80,
|
||||
0x22, 0xFF,
|
||||
0x23, 0xC1,
|
||||
0x28, 0x00,
|
||||
0x29, 0x1E,
|
||||
0x2A, 0x14,
|
||||
0x2B, 0x0F,
|
||||
0x2C, 0x09,
|
||||
0x2D, 0x05,
|
||||
0x31, 0x1F,
|
||||
0x32, 0x19,
|
||||
0x33, 0xFE,
|
||||
0x34, 0x93,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static struct stv0299_config samsung_tbmu24112_config = {
|
||||
.demod_address = 0x68,
|
||||
.inittab = samsung_tbmu24112_inittab,
|
||||
.mclk = 88000000UL,
|
||||
.invert = 0,
|
||||
.enhanced_tuning = 0,
|
||||
.skip_reinit = 0,
|
||||
.lock_output = STV0229_LOCKOUTPUT_LK,
|
||||
.volt13_op0_op1 = STV0299_VOLT13_OP1,
|
||||
.min_delay_ms = 100,
|
||||
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
|
||||
.pll_set = samsung_tbmu24112_pll_set,
|
||||
};
|
||||
|
||||
/* dvb-t mt352 */
|
||||
static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
|
||||
{
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
|
||||
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
|
||||
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
|
||||
if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
|
||||
if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = 0xcc;
|
||||
pllbuf[4] = bs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt352_config samsung_tdtc9251dh0_config = {
|
||||
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = samsung_tdtc9251dh0_demod_init,
|
||||
.pll_set = samsung_tdtc9251dh0_pll_set,
|
||||
};
|
||||
|
||||
static int nxt2002_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 nxt2002_config samsung_tbmv_config = {
|
||||
.demod_address = 0x0a,
|
||||
.request_firmware = nxt2002_request_firmware,
|
||||
};
|
||||
|
||||
static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
|
||||
{
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
|
||||
div = (params->frequency + (125/2)) / 125;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = (div >> 0) & 0xff;
|
||||
buf[2] = 0x84 | ((div >> 10) & 0x60);
|
||||
buf[3] = 0x80;
|
||||
|
||||
if (params->frequency < 1550000)
|
||||
buf[3] |= 0x02;
|
||||
|
||||
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt312_config skystar23_samsung_tbdu18132_config = {
|
||||
|
||||
.demod_address = 0x0e,
|
||||
.pll_set = skystar23_samsung_tbdu18132_pll_set,
|
||||
};
|
||||
|
||||
static struct stv0297_config alps_tdee4_stv0297_config = {
|
||||
.demod_address = 0x1c,
|
||||
// .invert = 1,
|
||||
// .pll_set = alps_tdee4_stv0297_pll_set,
|
||||
};
|
||||
|
||||
/* try to figure out the frontend, each card/box can have on of the following list */
|
||||
int flexcop_frontend_init(struct flexcop_device *fc)
|
||||
{
|
||||
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
|
||||
if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->fe->ops->set_voltage = flexcop_set_voltage;
|
||||
|
||||
fc->fe_sleep = fc->fe->ops->sleep;
|
||||
fc->fe->ops->sleep = flexcop_sleep;
|
||||
|
||||
fc->dev_type = FC_SKY;
|
||||
info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
|
||||
} else
|
||||
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
|
||||
if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
|
||||
fc->dev_type = FC_AIR_DVB;
|
||||
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
|
||||
} else
|
||||
/* try the air atsc (nxt2002) */
|
||||
if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->dev_type = FC_AIR_ATSC;
|
||||
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
|
||||
} else
|
||||
/* try the cable dvb (stv0297) */
|
||||
if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
|
||||
fc->dev_type = FC_CABLE;
|
||||
info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
|
||||
} else
|
||||
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
|
||||
if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
|
||||
fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
|
||||
fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
|
||||
fc->fe->ops->set_tone = flexcop_set_tone;
|
||||
fc->fe->ops->set_voltage = flexcop_set_voltage;
|
||||
|
||||
fc->fe_sleep = fc->fe->ops->sleep;
|
||||
fc->fe->ops->sleep = flexcop_sleep;
|
||||
|
||||
fc->dev_type = FC_SKY_OLD;
|
||||
info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
|
||||
}
|
||||
|
||||
if (fc->fe == NULL) {
|
||||
err("no frontend driver found for this B2C2/FlexCop adapter");
|
||||
return -ENODEV;
|
||||
} else {
|
||||
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
|
||||
err("frontend registration failed!");
|
||||
if (fc->fe->ops->release != NULL)
|
||||
fc->fe->ops->release(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);
|
||||
|
||||
fc->init_state &= ~FC_STATE_FE_INIT;
|
||||
}
|
198
drivers/media/dvb/b2c2/flexcop-hw-filter.c
Normal file
198
drivers/media/dvb/b2c2/flexcop-hw-filter.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
|
||||
}
|
||||
|
||||
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* when doing hw pid filtering, set the pid */
|
||||
if (fc->pid_filtering)
|
||||
flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
|
||||
|
||||
/* if it was the first feed request */
|
||||
if (fc->feedcount == onoff && onoff) {
|
||||
if (!fc->pid_filtering) {
|
||||
deb_ts("enabling full TS transfer\n");
|
||||
flexcop_pid_group_filter(fc, 0,0);
|
||||
flexcop_pid_group_filter_ctrl(fc,1);
|
||||
}
|
||||
|
||||
if (fc->stream_control)
|
||||
fc->stream_control(fc,1);
|
||||
flexcop_rcv_data_ctrl(fc,1);
|
||||
|
||||
/* if there is no more feed left to feed */
|
||||
} else if (fc->feedcount == onoff && !onoff) {
|
||||
if (!fc->pid_filtering) {
|
||||
deb_ts("disabling full TS transfer\n");
|
||||
flexcop_pid_group_filter(fc, 0x1fe0,0);
|
||||
flexcop_pid_group_filter_ctrl(fc,0);
|
||||
}
|
||||
|
||||
flexcop_rcv_data_ctrl(fc,0);
|
||||
if (fc->stream_control)
|
||||
fc->stream_control(fc,0);
|
||||
}
|
||||
|
||||
/* if pid_filtering is on and more pids than the hw-filter can provide are
|
||||
* requested enable the whole bandwidth.
|
||||
*/
|
||||
if (fc->pid_filtering && fc->feedcount > max_pid_filter) {
|
||||
flexcop_pid_group_filter(fc, 0,0);
|
||||
flexcop_pid_group_filter_ctrl(fc,1);
|
||||
} else if (fc->pid_filtering && fc->feedcount <= max_pid_filter) {
|
||||
flexcop_pid_group_filter(fc, 0x1fe0,0);
|
||||
flexcop_pid_group_filter_ctrl(fc,0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexcop_hw_filter_init(struct flexcop_device *fc)
|
||||
{
|
||||
int i;
|
||||
flexcop_ibi_value v;
|
||||
for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
|
||||
flexcop_pid_control(fc,i,0x1fff,0);
|
||||
|
||||
flexcop_pid_group_filter(fc, 0x1fe0,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);
|
||||
}
|
204
drivers/media/dvb/b2c2/flexcop-i2c.c
Normal file
204
drivers/media/dvb/b2c2/flexcop-i2c.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
#define FC_MAX_I2C_RETRIES 100000
|
||||
|
||||
static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100, int max_ack_errors)
|
||||
{
|
||||
int i,ack_errors = 0;
|
||||
flexcop_ibi_value r;
|
||||
|
||||
r100->tw_sm_c_100.working_start = 1;
|
||||
deb_i2c("r100 before: %08x\n",r100->raw);
|
||||
|
||||
fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
|
||||
fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
|
||||
|
||||
for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
|
||||
r = fc->read_ibi_reg(fc, tw_sm_c_100);
|
||||
|
||||
if (!r.tw_sm_c_100.no_base_addr_ack_error) {
|
||||
if (r.tw_sm_c_100.st_done) { /* && !r.tw_sm_c_100.working_start */
|
||||
*r100 = r;
|
||||
deb_i2c("i2c success\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
deb_i2c("suffering from an i2c ack_error\n");
|
||||
if (++ack_errors >= max_ack_errors)
|
||||
break;
|
||||
|
||||
fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
|
||||
fc->write_ibi_reg(fc, tw_sm_c_100, *r100);
|
||||
}
|
||||
}
|
||||
deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n",i);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
|
||||
{
|
||||
flexcop_ibi_value r104;
|
||||
int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
|
||||
ret;
|
||||
|
||||
if ((ret = flexcop_i2c_operation(fc,&r100,30)) != 0)
|
||||
return ret;
|
||||
|
||||
r104 = fc->read_ibi_reg(fc,tw_sm_c_104);
|
||||
|
||||
deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
|
||||
|
||||
/* there is at least one byte, otherwise we wouldn't be here */
|
||||
buf[0] = r100.tw_sm_c_100.data1_reg;
|
||||
|
||||
if (len > 0) 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,30);
|
||||
}
|
||||
|
||||
/* master xfer callback for demodulator */
|
||||
static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
|
||||
int i, ret = 0;
|
||||
|
||||
if (down_interruptible(&fc->i2c_sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* reading */
|
||||
if (num == 2 &&
|
||||
msgs[0].flags == 0 &&
|
||||
msgs[1].flags == I2C_M_RD &&
|
||||
msgs[0].buf != NULL &&
|
||||
msgs[1].buf != NULL) {
|
||||
|
||||
ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
|
||||
|
||||
} else for (i = 0; i < num; i++) { /* writing command */
|
||||
if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
err("i2c master_xfer failed");
|
||||
else
|
||||
ret = num;
|
||||
|
||||
up(&fc->i2c_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
|
||||
flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
int ret;
|
||||
u16 bytes_to_transfer;
|
||||
flexcop_ibi_value r100;
|
||||
|
||||
deb_i2c("op = %d\n",op);
|
||||
r100.raw = 0;
|
||||
r100.tw_sm_c_100.chipaddr = chipaddr;
|
||||
r100.tw_sm_c_100.twoWS_rw = op;
|
||||
r100.tw_sm_c_100.twoWS_port_reg = port;
|
||||
|
||||
while (len != 0) {
|
||||
bytes_to_transfer = len > 4 ? 4 : len;
|
||||
|
||||
r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
|
||||
r100.tw_sm_c_100.baseaddr = addr;
|
||||
|
||||
if (op == FC_READ)
|
||||
ret = flexcop_i2c_read4(fc, r100, buf);
|
||||
else
|
||||
ret = flexcop_i2c_write4(fc,r100, buf);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
buf += bytes_to_transfer;
|
||||
addr += bytes_to_transfer;
|
||||
len -= bytes_to_transfer;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* exported for PCI i2c */
|
||||
EXPORT_SYMBOL(flexcop_i2c_request);
|
||||
|
||||
static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm flexcop_algo = {
|
||||
.name = "FlexCop I2C algorithm",
|
||||
.id = I2C_ALGO_BIT,
|
||||
.master_xfer = flexcop_master_xfer,
|
||||
.functionality = flexcop_i2c_func,
|
||||
};
|
||||
|
||||
int flexcop_i2c_init(struct flexcop_device *fc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sema_init(&fc->i2c_sem,1);
|
||||
|
||||
memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
|
||||
strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
|
||||
|
||||
i2c_set_adapdata(&fc->i2c_adap,fc);
|
||||
|
||||
fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
|
||||
fc->i2c_adap.algo = &flexcop_algo;
|
||||
fc->i2c_adap.algo_data = NULL;
|
||||
fc->i2c_adap.id = I2C_ALGO_BIT;
|
||||
|
||||
if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
|
||||
return ret;
|
||||
|
||||
fc->init_state |= FC_STATE_I2C_INIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flexcop_i2c_exit(struct flexcop_device *fc)
|
||||
{
|
||||
if (fc->init_state & FC_STATE_I2C_INIT)
|
||||
i2c_del_adapter(&fc->i2c_adap);
|
||||
|
||||
fc->init_state &= ~FC_STATE_I2C_INIT;
|
||||
}
|
66
drivers/media/dvb/b2c2/flexcop-misc.c
Normal file
66
drivers/media/dvb/b2c2/flexcop-misc.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-misc.c - miscellaneous functions.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
void flexcop_determine_revision(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
|
||||
|
||||
switch (v.misc_204.Rev_N_sig_revision_hi) {
|
||||
case 0x2:
|
||||
deb_info("found a FlexCopII.\n");
|
||||
fc->rev = FLEXCOP_II;
|
||||
break;
|
||||
case 0x3:
|
||||
deb_info("found a FlexCopIIb.\n");
|
||||
fc->rev = FLEXCOP_IIB;
|
||||
break;
|
||||
case 0x0:
|
||||
deb_info("found a FlexCopIII.\n");
|
||||
fc->rev = FLEXCOP_III;
|
||||
break;
|
||||
default:
|
||||
err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
|
||||
deb_info("this FlexCop has the additional 32 hardware pid filter.\n");
|
||||
else
|
||||
deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n");
|
||||
/* bus parts have to decide if hw pid filtering is used or not. */
|
||||
}
|
||||
|
||||
const char *flexcop_revision_names[] = {
|
||||
"Unkown chip",
|
||||
"FlexCopII",
|
||||
"FlexCopIIb",
|
||||
"FlexCopIII",
|
||||
};
|
||||
|
||||
const char *flexcop_device_names[] = {
|
||||
"Unkown device",
|
||||
"AirStar 2 DVB-T",
|
||||
"AirStar 2 ATSC",
|
||||
"SkyStar 2 DVB-S",
|
||||
"SkyStar 2 DVB-S (old version)",
|
||||
"CableStar 2 DVB-C",
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
365
drivers/media/dvb/b2c2/flexcop-pci.c
Normal file
365
drivers/media/dvb/b2c2/flexcop-pci.c
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-pci.c - covers the PCI part including DMA transfers.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
|
||||
#define FC_LOG_PREFIX "flexcop-pci"
|
||||
#include "flexcop-common.h"
|
||||
|
||||
static int enable_pid_filtering = 0;
|
||||
module_param(enable_pid_filtering, int, 0444);
|
||||
MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
|
||||
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define dprintk(level,args...) \
|
||||
do { if ((debug & level)) printk(args); } while (0)
|
||||
#define DEBSTATUS ""
|
||||
#else
|
||||
#define dprintk(level,args...)
|
||||
#define DEBSTATUS " (debugging is not enabled)"
|
||||
#endif
|
||||
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_reg(args...) dprintk(0x02,args)
|
||||
#define deb_ts(args...) dprintk(0x04,args)
|
||||
#define deb_irq(args...) dprintk(0x08,args)
|
||||
|
||||
static int debug = 0;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
|
||||
|
||||
#define DRIVER_VERSION "0.1"
|
||||
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
|
||||
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
|
||||
|
||||
struct flexcop_pci {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
#define FC_PCI_INIT 0x01
|
||||
#define FC_PCI_DMA_INIT 0x02
|
||||
int init_state;
|
||||
|
||||
void __iomem *io_mem;
|
||||
u32 irq;
|
||||
/* buffersize (at least for DMA1, need to be % 188 == 0,
|
||||
* this is logic is required */
|
||||
#define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188)
|
||||
#define FC_DEFAULT_DMA2_BUFSIZE (10 * 188)
|
||||
struct flexcop_dma dma[2];
|
||||
|
||||
int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
|
||||
u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
|
||||
|
||||
struct flexcop_device *fc_dev;
|
||||
};
|
||||
|
||||
static int lastwreg,lastwval,lastrreg,lastrval;
|
||||
|
||||
static flexcop_ibi_value flexcop_pci_read_ibi_reg (struct flexcop_device *fc, flexcop_ibi_register r)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = fc->bus_specific;
|
||||
flexcop_ibi_value v;
|
||||
v.raw = readl(fc_pci->io_mem + r);
|
||||
|
||||
if (lastrreg != r || lastrval != v.raw) {
|
||||
lastrreg = r; lastrval = v.raw;
|
||||
deb_reg("new rd: %3x: %08x\n",r,v.raw);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register r, flexcop_ibi_value v)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = fc->bus_specific;
|
||||
|
||||
if (lastwreg != r || lastwval != v.raw) {
|
||||
lastwreg = r; lastwval = v.raw;
|
||||
deb_reg("new wr: %3x: %08x\n",r,v.raw);
|
||||
}
|
||||
|
||||
writel(v.raw, fc_pci->io_mem + r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* When PID filtering is turned on, we use the timer IRQ, because small amounts
|
||||
* of data need to be passed to the user space instantly as well. When PID
|
||||
* filtering is turned off, we use the page-change-IRQ */
|
||||
static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = dev_id;
|
||||
struct flexcop_device *fc = fc_pci->fc_dev;
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c);
|
||||
|
||||
deb_irq("irq: %08x cur_addr: %08x (%d), our addrs. 1: %08x 2: %08x; 0x000: "
|
||||
"%08x, 0x00c: %08x\n",v.raw,
|
||||
fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2,
|
||||
fc_pci->active_dma1_addr,
|
||||
fc_pci->dma[0].dma_addr0,fc_pci->dma[0].dma_addr1,
|
||||
fc->read_ibi_reg(fc,dma1_000).raw,
|
||||
fc->read_ibi_reg(fc,dma1_00c).raw);
|
||||
|
||||
if (v.irq_20c.DMA1_IRQ_Status == 1) {
|
||||
if (fc_pci->active_dma1_addr == 0)
|
||||
flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
|
||||
else
|
||||
flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr1,fc_pci->dma[0].size / 188);
|
||||
|
||||
deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
|
||||
fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr;
|
||||
} else if (v.irq_20c.DMA1_Timer_Status == 1) {
|
||||
/* for the timer IRQ we only can use buffer dmx feeding, because we don't have
|
||||
* complete TS packets when reading from the DMA memory */
|
||||
dma_addr_t cur_addr =
|
||||
fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
|
||||
u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
|
||||
|
||||
/* buffer end was reached, restarted from the beginning
|
||||
* pass the data from last_cur_pos to the buffer end to the demux
|
||||
*/
|
||||
if (cur_pos < fc_pci->last_dma1_cur_pos) {
|
||||
flexcop_pass_dmx_data(fc_pci->fc_dev,
|
||||
fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
|
||||
(fc_pci->dma[0].size*2 - 1) - fc_pci->last_dma1_cur_pos);
|
||||
fc_pci->last_dma1_cur_pos = 0;
|
||||
}
|
||||
|
||||
if (cur_pos > fc_pci->last_dma1_cur_pos) {
|
||||
flexcop_pass_dmx_data(fc_pci->fc_dev,
|
||||
fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
|
||||
cur_pos - fc_pci->last_dma1_cur_pos);
|
||||
}
|
||||
|
||||
fc_pci->last_dma1_cur_pos = cur_pos;
|
||||
}
|
||||
|
||||
/* packet count would be ideal for hw filtering, but it isn't working. Either
|
||||
* the data book is wrong, or I'm unable to read it correctly */
|
||||
|
||||
/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = fc->bus_specific;
|
||||
if (onoff) {
|
||||
flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
|
||||
flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
|
||||
flexcop_dma_config_timer(fc,FC_DMA_1,1);
|
||||
|
||||
if (fc_pci->fc_dev->pid_filtering) {
|
||||
fc_pci->last_dma1_cur_pos = 0;
|
||||
flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
|
||||
} else {
|
||||
fc_pci->active_dma1_addr = 0;
|
||||
flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
|
||||
}
|
||||
|
||||
/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0);
|
||||
flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */
|
||||
|
||||
deb_irq("irqs enabled\n");
|
||||
} else {
|
||||
if (fc_pci->fc_dev->pid_filtering)
|
||||
flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
|
||||
else
|
||||
flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
|
||||
|
||||
// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0);
|
||||
deb_irq("irqs disabled\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
|
||||
goto dma1_free;
|
||||
|
||||
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
|
||||
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
|
||||
|
||||
fc_pci->init_state |= FC_PCI_DMA_INIT;
|
||||
goto success;
|
||||
dma1_free:
|
||||
flexcop_dma_free(&fc_pci->dma[0]);
|
||||
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
if (fc_pci->init_state & FC_PCI_DMA_INIT) {
|
||||
flexcop_dma_free(&fc_pci->dma[0]);
|
||||
flexcop_dma_free(&fc_pci->dma[1]);
|
||||
}
|
||||
fc_pci->init_state &= ~FC_PCI_DMA_INIT;
|
||||
}
|
||||
|
||||
static int flexcop_pci_init(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
int ret;
|
||||
u8 card_rev;
|
||||
|
||||
pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
|
||||
info("card revision %x", card_rev);
|
||||
|
||||
if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
|
||||
return ret;
|
||||
|
||||
pci_set_master(fc_pci->pdev);
|
||||
|
||||
/* enable interrupts */
|
||||
// pci_write_config_dword(pdev, 0x6c, 0x8000);
|
||||
|
||||
if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
|
||||
goto err_pci_disable_device;
|
||||
|
||||
fc_pci->io_mem = pci_iomap(fc_pci->pdev, 0, 0x800);
|
||||
|
||||
if (!fc_pci->io_mem) {
|
||||
err("cannot map io memory\n");
|
||||
ret = -EIO;
|
||||
goto err_pci_release_regions;
|
||||
}
|
||||
|
||||
pci_set_drvdata(fc_pci->pdev, fc_pci);
|
||||
|
||||
if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq,
|
||||
SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
|
||||
goto err_pci_iounmap;
|
||||
|
||||
fc_pci->init_state |= FC_PCI_INIT;
|
||||
goto success;
|
||||
|
||||
err_pci_iounmap:
|
||||
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
|
||||
pci_set_drvdata(fc_pci->pdev, NULL);
|
||||
err_pci_release_regions:
|
||||
pci_release_regions(fc_pci->pdev);
|
||||
err_pci_disable_device:
|
||||
pci_disable_device(fc_pci->pdev);
|
||||
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_pci_exit(struct flexcop_pci *fc_pci)
|
||||
{
|
||||
if (fc_pci->init_state & FC_PCI_INIT) {
|
||||
free_irq(fc_pci->pdev->irq, fc_pci);
|
||||
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
|
||||
pci_set_drvdata(fc_pci->pdev, NULL);
|
||||
pci_release_regions(fc_pci->pdev);
|
||||
pci_disable_device(fc_pci->pdev);
|
||||
}
|
||||
fc_pci->init_state &= ~FC_PCI_INIT;
|
||||
}
|
||||
|
||||
|
||||
static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct flexcop_device *fc;
|
||||
struct flexcop_pci *fc_pci;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_pci))) == NULL) {
|
||||
err("out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* general flexcop init */
|
||||
fc_pci = fc->bus_specific;
|
||||
fc_pci->fc_dev = fc;
|
||||
|
||||
fc->read_ibi_reg = flexcop_pci_read_ibi_reg;
|
||||
fc->write_ibi_reg = flexcop_pci_write_ibi_reg;
|
||||
fc->i2c_request = flexcop_i2c_request;
|
||||
fc->get_mac_addr = flexcop_eeprom_check_mac_addr;
|
||||
|
||||
fc->stream_control = flexcop_pci_stream_control;
|
||||
|
||||
fc->pid_filtering = enable_pid_filtering;
|
||||
fc->bus_type = FC_PCI;
|
||||
|
||||
fc->dev = &pdev->dev;
|
||||
|
||||
/* bus specific part */
|
||||
fc_pci->pdev = pdev;
|
||||
if ((ret = flexcop_pci_init(fc_pci)) != 0)
|
||||
goto err_kfree;
|
||||
|
||||
/* init flexcop */
|
||||
if ((ret = flexcop_device_initialize(fc)) != 0)
|
||||
goto err_pci_exit;
|
||||
|
||||
/* init dma */
|
||||
if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
|
||||
goto err_fc_exit;
|
||||
|
||||
goto success;
|
||||
err_fc_exit:
|
||||
flexcop_device_exit(fc);
|
||||
err_pci_exit:
|
||||
flexcop_pci_exit(fc_pci);
|
||||
err_kfree:
|
||||
flexcop_device_kfree(fc);
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* in theory every _exit function should be called exactly two times,
|
||||
* here and in the bail-out-part of the _init-function
|
||||
*/
|
||||
static void flexcop_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
|
||||
|
||||
flexcop_pci_dma_exit(fc_pci);
|
||||
flexcop_device_exit(fc_pci->fc_dev);
|
||||
flexcop_pci_exit(fc_pci);
|
||||
flexcop_device_kfree(fc_pci->fc_dev);
|
||||
}
|
||||
|
||||
static struct pci_device_id flexcop_pci_tbl[] = {
|
||||
{ PCI_DEVICE(0x13d0, 0x2103) },
|
||||
/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
|
||||
|
||||
static struct pci_driver flexcop_pci_driver = {
|
||||
.name = "Technisat/B2C2 FlexCop II/IIb/III PCI",
|
||||
.id_table = flexcop_pci_tbl,
|
||||
.probe = flexcop_pci_probe,
|
||||
.remove = flexcop_pci_remove,
|
||||
};
|
||||
|
||||
static int __init flexcop_pci_module_init(void)
|
||||
{
|
||||
return pci_register_driver(&flexcop_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit flexcop_pci_module_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&flexcop_pci_driver);
|
||||
}
|
||||
|
||||
module_init(flexcop_pci_module_init);
|
||||
module_exit(flexcop_pci_module_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_NAME);
|
||||
MODULE_LICENSE("GPL");
|
700
drivers/media/dvb/b2c2/flexcop-reg.h
Normal file
700
drivers/media/dvb/b2c2/flexcop-reg.h
Normal file
|
@ -0,0 +1,700 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#ifndef __FLEXCOP_REG_H__
|
||||
#define __FLEXCOP_REG_H__
|
||||
|
||||
|
||||
typedef enum {
|
||||
FLEXCOP_UNK = 0,
|
||||
FLEXCOP_II,
|
||||
FLEXCOP_IIB,
|
||||
FLEXCOP_III,
|
||||
} flexcop_revision_t;
|
||||
|
||||
extern const char *flexcop_revision_names[];
|
||||
|
||||
typedef enum {
|
||||
FC_UNK = 0,
|
||||
FC_AIR_DVB,
|
||||
FC_AIR_ATSC,
|
||||
FC_SKY,
|
||||
FC_SKY_OLD,
|
||||
FC_CABLE,
|
||||
} flexcop_device_type_t;
|
||||
|
||||
typedef enum {
|
||||
FC_USB = 0,
|
||||
FC_PCI,
|
||||
} flexcop_bus_t;
|
||||
|
||||
extern const char *flexcop_device_names[];
|
||||
|
||||
/* FlexCop IBI Registers */
|
||||
|
||||
/* flexcop_ibi_reg - a huge union representing the register structure */
|
||||
typedef union {
|
||||
u32 raw;
|
||||
|
||||
/* DMA 0x000 to 0x01c
|
||||
* DMA1 0x000 to 0x00c
|
||||
* DMA2 0x010 to 0x01c
|
||||
*/
|
||||
struct {
|
||||
u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */
|
||||
u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */
|
||||
u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */
|
||||
} dma_0x0;
|
||||
|
||||
struct {
|
||||
u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable
|
||||
is able to be read and written while bit(1) of register
|
||||
0x00c (remap_enable) is set. This variable represents
|
||||
the number of packets that will be transmitted to the PCI
|
||||
host using PCI DMA1 before an interrupt to the PCI is
|
||||
asserted. This functionality may be enabled using bit(20)
|
||||
of register 0x208. N=0 disables the IRQ. */
|
||||
u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */
|
||||
} dma_0x4_remap;
|
||||
|
||||
struct {
|
||||
u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */
|
||||
u32 unused : 1;
|
||||
u32 dma_addr_size :24;
|
||||
} dma_0x4_read;
|
||||
|
||||
struct {
|
||||
u32 unused : 1;
|
||||
u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */
|
||||
u32 dma_addr_size :24;
|
||||
} dma_0x4_write;
|
||||
|
||||
struct {
|
||||
u32 unused : 2;
|
||||
u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */
|
||||
} dma_0x8;
|
||||
|
||||
struct {
|
||||
u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */
|
||||
u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */
|
||||
u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */
|
||||
} dma_0xc;
|
||||
|
||||
/* Two-wire Serial Master and Clock 0x100-0x110 */
|
||||
struct {
|
||||
// u32 slave_transmitter : 1; /* ???*/
|
||||
u32 chipaddr : 7; /* two-line serial address of the target slave */
|
||||
u32 reserved1 : 1;
|
||||
u32 baseaddr : 8; /* address of the location of the read/write operation */
|
||||
u32 data1_reg : 8; /* first byte in two-line serial read/write operation */
|
||||
u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready
|
||||
* set to 1 when doing a write operation */
|
||||
u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */
|
||||
u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/
|
||||
u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */
|
||||
u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o
|
||||
* preceding address assignment write frame
|
||||
* ACK_ERROR = 1 when no ACK from slave in the last transaction */
|
||||
u32 st_done : 1; /* indicator for transaction is done */
|
||||
} tw_sm_c_100;
|
||||
|
||||
struct {
|
||||
u32 data2_reg : 8; /* 2nd data byte */
|
||||
u32 data3_reg : 8; /* 3rd data byte */
|
||||
u32 data4_reg : 8; /* 4th data byte */
|
||||
u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */
|
||||
u32 force_stop : 1; /* isolated stop flag */
|
||||
u32 unused : 6;
|
||||
} tw_sm_c_104;
|
||||
|
||||
/* Clock. The register allows the FCIII to convert an incoming Master clock
|
||||
* (MCLK) signal into a lower frequency clock through the use of a LowCounter
|
||||
* (TLO) and a High- Counter (THI). The time counts for THI and TLO are
|
||||
* measured in MCLK; each count represents 4 MCLK input clock cycles.
|
||||
*
|
||||
* The default output for port #1 is set for Front End Demod communication. (0x108)
|
||||
* The default output for port #2 is set for EEPROM communication. (0x10c)
|
||||
* The default output for port #3 is set for Tuner communication. (0x110)
|
||||
*/
|
||||
struct {
|
||||
u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */
|
||||
u32 reserved1 : 2;
|
||||
u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */
|
||||
u32 reserved2 :19;
|
||||
} tw_sm_c_108;
|
||||
|
||||
struct {
|
||||
u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */
|
||||
u32 reserved1 : 2;
|
||||
u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */
|
||||
u32 reserved2 :19;
|
||||
} tw_sm_c_10c;
|
||||
|
||||
struct {
|
||||
u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */
|
||||
u32 reserved1 : 2;
|
||||
u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */
|
||||
u32 reserved2 :19;
|
||||
} tw_sm_c_110;
|
||||
|
||||
/* LNB Switch Frequency 0x200
|
||||
* Clock that creates the LNB switch tone. The default is set to have a fixed
|
||||
* low output (not oscillating) to the LNB_CTL line.
|
||||
*/
|
||||
struct {
|
||||
u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */
|
||||
u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master
|
||||
Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */
|
||||
u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */
|
||||
} lnb_switch_freq_200;
|
||||
|
||||
/* ACPI, Peripheral Reset, LNB Polarity
|
||||
* ACPI power conservation mode, LNB polarity selection (low or high voltage),
|
||||
* and peripheral reset.
|
||||
*/
|
||||
struct {
|
||||
u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */
|
||||
u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */
|
||||
u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */
|
||||
u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */
|
||||
u32 reserved :20;
|
||||
u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */
|
||||
u32 Rev_N_sig_reserved1 : 2;
|
||||
u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */
|
||||
u32 Rev_N_sig_reserved2 : 1;
|
||||
} misc_204;
|
||||
|
||||
/* Control and Status 0x208 to 0x21c */
|
||||
/* Gross enable and disable control */
|
||||
struct {
|
||||
u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */
|
||||
u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */
|
||||
u32 PCR_filter_sig : 1; /* PCR PID filter */
|
||||
u32 PMT_filter_sig : 1; /* PMT PID filter */
|
||||
|
||||
u32 EMM_filter_sig : 1; /* EMM PID filter */
|
||||
u32 ECM_filter_sig : 1; /* ECM PID filter */
|
||||
u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */
|
||||
u32 Mask_filter_sig : 1; /* mask PID filter */
|
||||
|
||||
u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */
|
||||
u32 WAN_CA_Enable_sig : 1; /* not in FCIII */
|
||||
u32 CA_Enable_sig : 1; /* not in FCIII */
|
||||
u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */
|
||||
|
||||
u32 Per_CA_Enable_sig : 1; /* not in FCIII */
|
||||
u32 Multi2_Enable_sig : 1; /* ? */
|
||||
u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */
|
||||
u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will
|
||||
examine and process packets according to all other (individual) PID
|
||||
filtering controls. If it a zero, no packet processing of any kind will
|
||||
take place. All data from the tuner will be thrown away. */
|
||||
|
||||
u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI
|
||||
* interrupt after the specified count for filling the buffer. */
|
||||
u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt
|
||||
after a specified amount of time. */
|
||||
u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */
|
||||
u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */
|
||||
|
||||
u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */
|
||||
u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */
|
||||
u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the
|
||||
PCI host to indicate that mailbox data is available. */
|
||||
|
||||
u32 unused : 9;
|
||||
} ctrl_208;
|
||||
|
||||
/* General status. When a PCI interrupt occurs, this register is read to
|
||||
* discover the reason for the interrupt.
|
||||
*/
|
||||
struct {
|
||||
u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */
|
||||
u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */
|
||||
u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */
|
||||
u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */
|
||||
u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */
|
||||
u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/
|
||||
u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */
|
||||
u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */
|
||||
u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */
|
||||
u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */
|
||||
u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */
|
||||
u32 reserved :21;
|
||||
} irq_20c;
|
||||
|
||||
|
||||
/* Software reset register */
|
||||
struct {
|
||||
u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00.
|
||||
Each bit location represents a 0x100 block of registers. Writing
|
||||
a one in a bit location resets that block of registers and the logic
|
||||
that it controls. */
|
||||
u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */
|
||||
u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A;
|
||||
Turns off pci encryption => 0xC259 Note: pci_encryption default
|
||||
at power-up is ON. */
|
||||
} sw_reset_210;
|
||||
|
||||
struct {
|
||||
u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART
|
||||
(RS-232 Smart Card interface). When set, the IBI interface
|
||||
defined by register 0x600 controls the serial UART. */
|
||||
u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line
|
||||
Serial Master EEPROM target. When set, the Two-line Serial Master
|
||||
EEPROM target interface is controlled by IBI register 0x100. */
|
||||
u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space
|
||||
bus masters. Once this signal is cleared, normal V8-space
|
||||
operations resume. */
|
||||
u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry
|
||||
to process section packed transport streams. */
|
||||
u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data
|
||||
within the FlexCop3 front end circuitry is converted from a serial
|
||||
stream into parallel data before downstream processing otherwise
|
||||
interprets the data. */
|
||||
u32 unused1 : 3;
|
||||
u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport
|
||||
stream CLOCK signal before any processing occurs on the transport
|
||||
stream within FlexCop3. */
|
||||
u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport
|
||||
stream VALID signal before any processing occurs on the transport
|
||||
stream within FlexCop3. */
|
||||
u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport
|
||||
stream SYNC signal before any processing occurs on the transport
|
||||
stream within FlexCop3. */
|
||||
u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport
|
||||
stream ERROR signal before any processing occurs on the transport
|
||||
stream within FlexCop3. */
|
||||
u32 unused2 :20;
|
||||
} misc_214;
|
||||
|
||||
/* Mailbox from V8 to host */
|
||||
struct {
|
||||
u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an
|
||||
end host, an interrupt is generated to the PCI host to indicate
|
||||
that mailbox data is available. Reading register 20c will clear
|
||||
the IRQ. */
|
||||
} mbox_v8_to_host_218;
|
||||
|
||||
/* Mailbox from host to v8 Mailbox_to_V8
|
||||
* Mailbox_to_V8 mailbox storage register
|
||||
* used to send messages from PCI to V8. Writing to this register will send an
|
||||
* IRQ to the V8. Then it can read the data from here. Reading this register
|
||||
* will clear the IRQ. If the V8 is halted and bit 31 of this register is set,
|
||||
* then this register is used instead as a direct interface to access the
|
||||
* V8space memory.
|
||||
*/
|
||||
struct {
|
||||
u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */
|
||||
u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */
|
||||
u32 unused : 7;
|
||||
u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */
|
||||
u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows
|
||||
this IBI register interface to directly drive the V8-space memory. */
|
||||
} mbox_host_to_v8_21c;
|
||||
|
||||
|
||||
/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */
|
||||
struct {
|
||||
u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally
|
||||
hold the PID value for the desired network stream. */
|
||||
u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */
|
||||
u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */
|
||||
u32 debug_flag_pid_saved : 1;
|
||||
u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */
|
||||
u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in
|
||||
Stream2_PID TS packets. */
|
||||
u32 debug_flag_write_status00 : 1;
|
||||
u32 debug_fifo_problem : 1;
|
||||
} pid_filter_300;
|
||||
|
||||
struct {
|
||||
u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */
|
||||
u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
|
||||
u32 debug_overrun3 : 1;
|
||||
u32 debug_overrun2 : 1;
|
||||
u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */
|
||||
u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
|
||||
u32 reserved : 2;
|
||||
} pid_filter_304;
|
||||
|
||||
struct {
|
||||
u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for
|
||||
conditional access-related data. */
|
||||
u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
|
||||
u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the
|
||||
first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */
|
||||
u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users
|
||||
complete 6-byte Smart Card ID number. */
|
||||
u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional
|
||||
access-related data. */
|
||||
u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
|
||||
u32 reserved : 2;
|
||||
} pid_filter_308;
|
||||
|
||||
struct {
|
||||
u32 Group_PID :13; /* PID value for group filtering. */
|
||||
u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
|
||||
u32 unused1 : 2;
|
||||
u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */
|
||||
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; /* default: 000100 */
|
||||
u32 stack_read :10;
|
||||
u32 reserved2 : 5; /* default: 00100 */
|
||||
} 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; /* (Index pointer) Points at an internal PIDn register. A binary code
|
||||
representing one of 32 internal PIDn registers as well as its
|
||||
corresponding internal MAC_lown register. */
|
||||
u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */
|
||||
u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register
|
||||
0=MAC_highB register, 1=MAC_highA */
|
||||
u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400.
|
||||
All types of networks (DVB, ATSC, ISDB) are passed. */
|
||||
u32 unused :22;
|
||||
} index_reg_310;
|
||||
|
||||
struct {
|
||||
u32 PID :13; /* PID value */
|
||||
u32 PID_trans : 1; /* translation will take place for packets filtered */
|
||||
u32 PID_enable_bit : 1; /* When set this PID filter is enabled */
|
||||
u32 reserved :17;
|
||||
} pid_n_reg_314;
|
||||
|
||||
struct {
|
||||
u32 A4_byte : 8;
|
||||
u32 A5_byte : 8;
|
||||
u32 A6_byte : 8;
|
||||
u32 Enable_bit : 1; /* enabled (1) or disabled (1) */
|
||||
u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */
|
||||
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;
|
||||
|
||||
/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */
|
||||
struct {
|
||||
u32 reserved :16;
|
||||
#define fc_data_Tag_ID_DVB 0x3e
|
||||
#define fc_data_Tag_ID_ATSC 0x3f
|
||||
#define fc_data_Tag_ID_IDSB 0x8b
|
||||
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;
|
||||
|
||||
/* holding the unique mac address of the receiver which houses the FlexCopIII */
|
||||
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; /* ??? not mentioned in data book */
|
||||
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;
|
||||
#define fc_key_code_default 0x1
|
||||
#define fc_key_code_even 0x2
|
||||
#define fc_key_code_odd 0x3
|
||||
u32 key_code : 2;
|
||||
u32 key_array_col : 3;
|
||||
u32 key_array_row : 5;
|
||||
u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */
|
||||
u32 rw_flag : 1;
|
||||
u32 reserved : 6;
|
||||
} dvb_reg_60c;
|
||||
|
||||
/* SRAM and Output Destination 0x700 to 0x714 */
|
||||
struct {
|
||||
u32 sram_addr :15;
|
||||
u32 sram_rw : 1; /* 0=write, 1=read */
|
||||
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;
|
||||
|
||||
extern flexcop_ibi_value ibi_zero;
|
||||
|
||||
typedef enum {
|
||||
FC_I2C_PORT_DEMOD = 1,
|
||||
FC_I2C_PORT_EEPROM = 2,
|
||||
FC_I2C_PORT_TUNER = 3,
|
||||
} flexcop_i2c_port_t;
|
||||
|
||||
typedef enum {
|
||||
FC_WRITE = 0,
|
||||
FC_READ = 1,
|
||||
} flexcop_access_op_t;
|
||||
|
||||
typedef enum {
|
||||
FC_SRAM_DEST_NET = 1,
|
||||
FC_SRAM_DEST_CAI = 2,
|
||||
FC_SRAM_DEST_CAO = 4,
|
||||
FC_SRAM_DEST_MEDIA = 8
|
||||
} flexcop_sram_dest_t;
|
||||
|
||||
typedef enum {
|
||||
FC_SRAM_DEST_TARGET_WAN_USB = 0,
|
||||
FC_SRAM_DEST_TARGET_DMA1 = 1,
|
||||
FC_SRAM_DEST_TARGET_DMA2 = 2,
|
||||
FC_SRAM_DEST_TARGET_FC3_CA = 3
|
||||
} flexcop_sram_dest_target_t;
|
||||
|
||||
typedef enum {
|
||||
FC_SRAM_2_32KB = 0, /* 64KB */
|
||||
FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */
|
||||
FC_SRAM_1_128KB = 2, /* 128KB */
|
||||
FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */
|
||||
} flexcop_sram_type_t;
|
||||
|
||||
typedef enum {
|
||||
FC_WAN_SPEED_4MBITS = 0,
|
||||
FC_WAN_SPEED_8MBITS = 1,
|
||||
FC_WAN_SPEED_12MBITS = 2,
|
||||
FC_WAN_SPEED_16MBITS = 3,
|
||||
} flexcop_wan_speed_t;
|
||||
|
||||
typedef enum {
|
||||
FC_DMA_1 = 1,
|
||||
FC_DMA_2 = 2,
|
||||
} flexcop_dma_index_t;
|
||||
|
||||
typedef enum {
|
||||
FC_DMA_SUBADDR_0 = 1,
|
||||
FC_DMA_SUBADDR_1 = 2,
|
||||
} flexcop_dma_addr_index_t;
|
||||
|
||||
/* names of the particular registers */
|
||||
typedef enum {
|
||||
dma1_000 = 0x000,
|
||||
dma1_004 = 0x004,
|
||||
dma1_008 = 0x008,
|
||||
dma1_00c = 0x00c,
|
||||
dma2_010 = 0x010,
|
||||
dma2_014 = 0x014,
|
||||
dma2_018 = 0x018,
|
||||
dma2_01c = 0x01c,
|
||||
|
||||
tw_sm_c_100 = 0x100,
|
||||
tw_sm_c_104 = 0x104,
|
||||
tw_sm_c_108 = 0x108,
|
||||
tw_sm_c_10c = 0x10c,
|
||||
tw_sm_c_110 = 0x110,
|
||||
|
||||
lnb_switch_freq_200 = 0x200,
|
||||
misc_204 = 0x204,
|
||||
ctrl_208 = 0x208,
|
||||
irq_20c = 0x20c,
|
||||
sw_reset_210 = 0x210,
|
||||
misc_214 = 0x214,
|
||||
mbox_v8_to_host_218 = 0x218,
|
||||
mbox_host_to_v8_21c = 0x21c,
|
||||
|
||||
pid_filter_300 = 0x300,
|
||||
pid_filter_304 = 0x304,
|
||||
pid_filter_308 = 0x308,
|
||||
pid_filter_30c = 0x30c,
|
||||
index_reg_310 = 0x310,
|
||||
pid_n_reg_314 = 0x314,
|
||||
mac_low_reg_318 = 0x318,
|
||||
mac_high_reg_31c = 0x31c,
|
||||
|
||||
data_tag_400 = 0x400,
|
||||
card_id_408 = 0x408,
|
||||
card_id_40c = 0x40c,
|
||||
mac_address_418 = 0x418,
|
||||
mac_address_41c = 0x41c,
|
||||
|
||||
ci_600 = 0x600,
|
||||
pi_604 = 0x604,
|
||||
pi_608 = 0x608,
|
||||
dvb_reg_60c = 0x60c,
|
||||
|
||||
sram_ctrl_reg_700 = 0x700,
|
||||
net_buf_reg_704 = 0x704,
|
||||
cai_buf_reg_708 = 0x708,
|
||||
cao_buf_reg_70c = 0x70c,
|
||||
media_buf_reg_710 = 0x710,
|
||||
sram_dest_reg_714 = 0x714,
|
||||
net_buf_reg_718 = 0x718,
|
||||
wan_ctrl_reg_71c = 0x71c,
|
||||
} flexcop_ibi_register;
|
||||
|
||||
#define flexcop_set_ibi_value(reg,attr,val) \
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
|
||||
v.reg.attr = val; \
|
||||
fc->write_ibi_reg(fc,reg,v); \
|
||||
|
||||
#endif
|
403
drivers/media/dvb/b2c2/flexcop-sram.c
Normal file
403
drivers/media/dvb/b2c2/flexcop-sram.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-sram.c - functions for controlling the SRAM.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#include "flexcop.h"
|
||||
|
||||
static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type)
|
||||
{
|
||||
flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type);
|
||||
}
|
||||
|
||||
int flexcop_sram_init(struct flexcop_device *fc)
|
||||
{
|
||||
switch (fc->rev) {
|
||||
case FLEXCOP_II:
|
||||
case FLEXCOP_IIB:
|
||||
flexcop_sram_set_chip(fc,FC_SRAM_1_32KB);
|
||||
break;
|
||||
case FLEXCOP_III:
|
||||
flexcop_sram_set_chip(fc,FC_SRAM_1_48KB);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target)
|
||||
{
|
||||
flexcop_ibi_value v;
|
||||
|
||||
v = fc->read_ibi_reg(fc,sram_dest_reg_714);
|
||||
|
||||
if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
|
||||
err("SRAM destination target to available on FlexCopII(b)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
deb_sram("sram dest: %x target: %x\n",dest, target);
|
||||
|
||||
if (dest & FC_SRAM_DEST_NET)
|
||||
v.sram_dest_reg_714.NET_Dest = target;
|
||||
if (dest & FC_SRAM_DEST_CAI)
|
||||
v.sram_dest_reg_714.CAI_Dest = target;
|
||||
if (dest & FC_SRAM_DEST_CAO)
|
||||
v.sram_dest_reg_714.CAO_Dest = target;
|
||||
if (dest & FC_SRAM_DEST_MEDIA)
|
||||
v.sram_dest_reg_714.MEDIA_Dest = target;
|
||||
|
||||
fc->write_ibi_reg(fc,sram_dest_reg_714,v);
|
||||
udelay(1000); /* TODO delay really necessary */
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_sram_set_dest);
|
||||
|
||||
void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
|
||||
{
|
||||
flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_wan_set_speed);
|
||||
|
||||
void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
|
||||
v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
|
||||
v.sram_dest_reg_714.ctrl_sramdma = sramdma;
|
||||
v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
|
||||
fc->write_ibi_reg(fc,sram_dest_reg_714,v);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_sram_ctrl);
|
||||
|
||||
#if 0
|
||||
static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
int i, retries;
|
||||
u32 command;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
command = bank | addr | 0x04000000 | (*buf << 0x10);
|
||||
|
||||
retries = 2;
|
||||
|
||||
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
|
||||
mdelay(1);
|
||||
retries--;
|
||||
};
|
||||
|
||||
if (retries == 0)
|
||||
printk("%s: SRAM timeout\n", __FUNCTION__);
|
||||
|
||||
write_reg_dw(adapter, 0x700, command);
|
||||
|
||||
buf++;
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
int i, retries;
|
||||
u32 command, value;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
command = bank | addr | 0x04008000;
|
||||
|
||||
retries = 10000;
|
||||
|
||||
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
|
||||
mdelay(1);
|
||||
retries--;
|
||||
};
|
||||
|
||||
if (retries == 0)
|
||||
printk("%s: SRAM timeout\n", __FUNCTION__);
|
||||
|
||||
write_reg_dw(adapter, 0x700, command);
|
||||
|
||||
retries = 10000;
|
||||
|
||||
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
|
||||
mdelay(1);
|
||||
retries--;
|
||||
};
|
||||
|
||||
if (retries == 0)
|
||||
printk("%s: SRAM timeout\n", __FUNCTION__);
|
||||
|
||||
value = read_reg_dw(adapter, 0x700) >> 0x10;
|
||||
|
||||
*buf = (value & 0xff);
|
||||
|
||||
addr++;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
|
||||
{
|
||||
u32 bank;
|
||||
|
||||
bank = 0;
|
||||
|
||||
if (adapter->dw_sram_type == 0x20000) {
|
||||
bank = (addr & 0x18000) << 0x0d;
|
||||
}
|
||||
|
||||
if (adapter->dw_sram_type == 0x00000) {
|
||||
if ((addr >> 0x0f) == 0)
|
||||
bank = 0x20000000;
|
||||
else
|
||||
bank = 0x10000000;
|
||||
}
|
||||
|
||||
flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
|
||||
}
|
||||
|
||||
static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
|
||||
{
|
||||
u32 bank;
|
||||
|
||||
bank = 0;
|
||||
|
||||
if (adapter->dw_sram_type == 0x20000) {
|
||||
bank = (addr & 0x18000) << 0x0d;
|
||||
}
|
||||
|
||||
if (adapter->dw_sram_type == 0x00000) {
|
||||
if ((addr >> 0x0f) == 0)
|
||||
bank = 0x20000000;
|
||||
else
|
||||
bank = 0x10000000;
|
||||
}
|
||||
|
||||
flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
|
||||
}
|
||||
|
||||
static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 length;
|
||||
|
||||
while (len != 0) {
|
||||
length = len;
|
||||
|
||||
// check if the address range belongs to the same
|
||||
// 32K memory chip. If not, the data is read from
|
||||
// one chip at a time.
|
||||
if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
|
||||
length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
|
||||
}
|
||||
|
||||
sram_read_chunk(adapter, addr, buf, length);
|
||||
|
||||
addr = addr + length;
|
||||
buf = buf + length;
|
||||
len = len - length;
|
||||
}
|
||||
}
|
||||
|
||||
static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
|
||||
{
|
||||
u32 length;
|
||||
|
||||
while (len != 0) {
|
||||
length = len;
|
||||
|
||||
// check if the address range belongs to the same
|
||||
// 32K memory chip. If not, the data is written to
|
||||
// one chip at a time.
|
||||
if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
|
||||
length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
|
||||
}
|
||||
|
||||
sram_write_chunk(adapter, addr, buf, length);
|
||||
|
||||
addr = addr + length;
|
||||
buf = buf + length;
|
||||
len = len - length;
|
||||
}
|
||||
}
|
||||
|
||||
static void sram_set_size(struct adapter *adapter, u32 mask)
|
||||
{
|
||||
write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
|
||||
}
|
||||
|
||||
static void sram_init(struct adapter *adapter)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = read_reg_dw(adapter, 0x71c);
|
||||
|
||||
write_reg_dw(adapter, 0x71c, 1);
|
||||
|
||||
if (read_reg_dw(adapter, 0x71c) != 0) {
|
||||
write_reg_dw(adapter, 0x71c, tmp);
|
||||
|
||||
adapter->dw_sram_type = tmp & 0x30000;
|
||||
|
||||
ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
|
||||
|
||||
} else {
|
||||
|
||||
adapter->dw_sram_type = 0x10000;
|
||||
|
||||
ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
|
||||
}
|
||||
|
||||
/* return value is never used? */
|
||||
/* return adapter->dw_sram_type; */
|
||||
}
|
||||
|
||||
static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
|
||||
{
|
||||
u8 tmp1, tmp2;
|
||||
|
||||
dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
|
||||
|
||||
sram_set_size(adapter, mask);
|
||||
sram_init(adapter);
|
||||
|
||||
tmp2 = 0xa5;
|
||||
tmp1 = 0x4f;
|
||||
|
||||
sram_write(adapter, addr, &tmp2, 1);
|
||||
sram_write(adapter, addr + 4, &tmp1, 1);
|
||||
|
||||
tmp2 = 0;
|
||||
|
||||
mdelay(20);
|
||||
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
|
||||
dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
|
||||
|
||||
if (tmp2 != 0xa5)
|
||||
return 0;
|
||||
|
||||
tmp2 = 0x5a;
|
||||
tmp1 = 0xf4;
|
||||
|
||||
sram_write(adapter, addr, &tmp2, 1);
|
||||
sram_write(adapter, addr + 4, &tmp1, 1);
|
||||
|
||||
tmp2 = 0;
|
||||
|
||||
mdelay(20);
|
||||
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
sram_read(adapter, addr, &tmp2, 1);
|
||||
|
||||
dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
|
||||
|
||||
if (tmp2 != 0x5a)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32 sram_length(struct adapter *adapter)
|
||||
{
|
||||
if (adapter->dw_sram_type == 0x10000)
|
||||
return 32768; // 32K
|
||||
if (adapter->dw_sram_type == 0x00000)
|
||||
return 65536; // 64K
|
||||
if (adapter->dw_sram_type == 0x20000)
|
||||
return 131072; // 128K
|
||||
|
||||
return 32768; // 32K
|
||||
}
|
||||
|
||||
/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
|
||||
- for 128K there are 4x32K chips at bank 0,1,2,3.
|
||||
- for 64K there are 2x32K chips at bank 1,2.
|
||||
- for 32K there is one 32K chip at bank 0.
|
||||
|
||||
FlexCop works only with one bank at a time. The bank is selected
|
||||
by bits 28-29 of the 0x700 register.
|
||||
|
||||
bank 0 covers addresses 0x00000-0x07fff
|
||||
bank 1 covers addresses 0x08000-0x0ffff
|
||||
bank 2 covers addresses 0x10000-0x17fff
|
||||
bank 3 covers addresses 0x18000-0x1ffff
|
||||
*/
|
||||
|
||||
static int flexcop_sram_detect(struct flexcop_device *fc)
|
||||
{
|
||||
flexcop_ibi_value r208,r71c_0,vr71c_1;
|
||||
|
||||
r208 = fc->read_ibi_reg(fc, ctrl_208);
|
||||
fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
|
||||
|
||||
r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
|
||||
|
||||
write_reg_dw(adapter, 0x71c, 1);
|
||||
|
||||
tmp3 = read_reg_dw(adapter, 0x71c);
|
||||
|
||||
dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
|
||||
|
||||
write_reg_dw(adapter, 0x71c, tmp2);
|
||||
|
||||
// check for internal SRAM ???
|
||||
tmp3--;
|
||||
if (tmp3 != 0) {
|
||||
sram_set_size(adapter, 0x10000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 32K\n", __FUNCTION__);
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
|
||||
sram_set_size(adapter, 0x20000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 128K\n", __FUNCTION__);
|
||||
|
||||
return 128;
|
||||
}
|
||||
|
||||
if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
|
||||
sram_set_size(adapter, 0x00000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 64K\n", __FUNCTION__);
|
||||
|
||||
return 64;
|
||||
}
|
||||
|
||||
if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
|
||||
sram_set_size(adapter, 0x10000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: sram size = 32K\n", __FUNCTION__);
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
sram_set_size(adapter, 0x10000);
|
||||
sram_init(adapter);
|
||||
write_reg_dw(adapter, 0x208, tmp);
|
||||
|
||||
dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sll_detect_sram_size(struct adapter *adapter)
|
||||
{
|
||||
sram_detect_for_flex2(adapter);
|
||||
}
|
||||
|
||||
#endif
|
530
drivers/media/dvb/b2c2/flexcop-usb.c
Normal file
530
drivers/media/dvb/b2c2/flexcop-usb.c
Normal file
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop-usb.c - covers the USB part.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
|
||||
#define FC_LOG_PREFIX "flexcop_usb"
|
||||
#include "flexcop-usb.h"
|
||||
#include "flexcop-common.h"
|
||||
|
||||
/* Version information */
|
||||
#define DRIVER_VERSION "0.1"
|
||||
#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
|
||||
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
|
||||
|
||||
/* debug */
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define dprintk(level,args...) \
|
||||
do { if ((debug & level)) { printk(args); } } while (0)
|
||||
#define debug_dump(b,l,method) {\
|
||||
int i; \
|
||||
for (i = 0; i < l; i++) method("%02x ", b[i]); \
|
||||
method("\n");\
|
||||
}
|
||||
|
||||
#define DEBSTATUS ""
|
||||
#else
|
||||
#define dprintk(level,args...)
|
||||
#define debug_dump(b,l,method)
|
||||
#define DEBSTATUS " (debugging is not enabled)"
|
||||
#endif
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
|
||||
#undef DEBSTATUS
|
||||
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_ts(args...) dprintk(0x02,args)
|
||||
#define deb_ctrl(args...) dprintk(0x04,args)
|
||||
#define deb_i2c(args...) dprintk(0x08,args)
|
||||
#define deb_v8(args...) dprintk(0x10,args)
|
||||
|
||||
/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
|
||||
* in the IBI address, to make the V8 code simpler.
|
||||
* PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
|
||||
* in general: 0000 0HHH 000L LL00
|
||||
* IBI ADDRESS FORMAT: RHHH BLLL
|
||||
*
|
||||
* where R is the read(1)/write(0) bit, B is the busy bit
|
||||
* and HHH and LLL are the two sets of three bits from the PCI address.
|
||||
*/
|
||||
#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
|
||||
#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
|
||||
|
||||
/*
|
||||
* DKT 020228
|
||||
* - forget about this VENDOR_BUFFER_SIZE, read and write register
|
||||
* deal with DWORD or 4 bytes, that should be should from now on
|
||||
* - from now on, we don't support anything older than firm 1.00
|
||||
* I eliminated the write register as a 2 trip of writing hi word and lo word
|
||||
* and force this to write only 4 bytes at a time.
|
||||
* NOTE: this should work with all the firmware from 1.00 and newer
|
||||
*/
|
||||
static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
|
||||
{
|
||||
struct flexcop_usb *fc_usb = fc->bus_specific;
|
||||
u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
|
||||
u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
|
||||
u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | (read ? 0x80 : 0);
|
||||
|
||||
int len = usb_control_msg(fc_usb->udev,
|
||||
read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
|
||||
request,
|
||||
request_type, /* 0xc0 read or 0x40 write*/
|
||||
wAddress,
|
||||
0,
|
||||
val,
|
||||
sizeof(u32),
|
||||
B2C2_WAIT_FOR_OPERATION_RDW * HZ);
|
||||
|
||||
if (len != sizeof(u32)) {
|
||||
err("error while %s dword from %d (%d).",read ? "reading" : "writing",
|
||||
wAddress,wRegOffsPCI);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DKT 010817 - add support for V8 memory read/write and flash update
|
||||
*/
|
||||
static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
|
||||
flexcop_usb_request_t req, u8 page, u16 wAddress,
|
||||
u8 *pbBuffer,u32 buflen)
|
||||
{
|
||||
// u8 dwRequestType;
|
||||
u8 request_type = USB_TYPE_VENDOR;
|
||||
u16 wIndex;
|
||||
int nWaitTime,pipe,len;
|
||||
|
||||
wIndex = page << 8;
|
||||
|
||||
switch (req) {
|
||||
case B2C2_USB_READ_V8_MEM:
|
||||
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
|
||||
request_type |= USB_DIR_IN;
|
||||
// dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
|
||||
pipe = B2C2_USB_CTRL_PIPE_IN;
|
||||
break;
|
||||
case B2C2_USB_WRITE_V8_MEM:
|
||||
wIndex |= pbBuffer[0];
|
||||
request_type |= USB_DIR_OUT;
|
||||
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
|
||||
// dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
|
||||
pipe = B2C2_USB_CTRL_PIPE_OUT;
|
||||
break;
|
||||
case B2C2_USB_FLASH_BLOCK:
|
||||
request_type |= USB_DIR_OUT;
|
||||
nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
|
||||
// dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
|
||||
pipe = B2C2_USB_CTRL_PIPE_OUT;
|
||||
break;
|
||||
default:
|
||||
deb_info("unsupported request for v8_mem_req %x.\n",req);
|
||||
return -EINVAL;
|
||||
}
|
||||
deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n",request_type,req,
|
||||
wAddress,wIndex,buflen);
|
||||
|
||||
len = usb_control_msg(fc_usb->udev,pipe,
|
||||
req,
|
||||
request_type,
|
||||
wAddress,
|
||||
wIndex,
|
||||
pbBuffer,
|
||||
buflen,
|
||||
nWaitTime * HZ);
|
||||
|
||||
debug_dump(pbBuffer,len,deb_v8);
|
||||
|
||||
return len == buflen ? 0 : -EIO;
|
||||
}
|
||||
|
||||
#define bytes_left_to_read_on_page(paddr,buflen) \
|
||||
((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
|
||||
? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
|
||||
|
||||
static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,flexcop_usb_request_t req,
|
||||
flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len)
|
||||
{
|
||||
int i,ret = 0;
|
||||
u16 wMax;
|
||||
u32 pagechunk = 0;
|
||||
|
||||
switch(req) {
|
||||
case B2C2_USB_READ_V8_MEM: wMax = USB_MEM_READ_MAX; break;
|
||||
case B2C2_USB_WRITE_V8_MEM: wMax = USB_MEM_WRITE_MAX; break;
|
||||
case B2C2_USB_FLASH_BLOCK: wMax = USB_FLASH_MAX; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < len;) {
|
||||
pagechunk = wMax < bytes_left_to_read_on_page(addr,len) ? wMax : bytes_left_to_read_on_page(addr,len);
|
||||
deb_info("%x\n",(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended));
|
||||
if ((ret = flexcop_usb_v8_memory_req(fc_usb,req,
|
||||
page_start + (addr / V8_MEMORY_PAGE_SIZE), /* actual page */
|
||||
(addr & V8_MEMORY_PAGE_MASK) | (V8_MEMORY_EXTENDED*extended),
|
||||
&buf[i],pagechunk)) < 0)
|
||||
return ret;
|
||||
|
||||
addr += pagechunk;
|
||||
len -= pagechunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
|
||||
{
|
||||
return flexcop_usb_memory_req(fc->bus_specific,B2C2_USB_READ_V8_MEM,V8_MEMORY_PAGE_FLASH,0x1f010,1,fc->mac_address,6);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
|
||||
flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
|
||||
u16 buflen, u8 *pvBuffer)
|
||||
{
|
||||
u16 wValue;
|
||||
u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
|
||||
// u8 dwRequestType = (u8) RTYPE_GENERIC,
|
||||
int nWaitTime = 2,
|
||||
pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
|
||||
len;
|
||||
|
||||
wValue = (func << 8) | extra;
|
||||
|
||||
len = usb_control_msg(fc_usb->udev,pipe,
|
||||
B2C2_USB_UTILITY,
|
||||
request_type,
|
||||
wValue,
|
||||
wIndex,
|
||||
pvBuffer,
|
||||
buflen,
|
||||
nWaitTime * HZ);
|
||||
return len == buflen ? 0 : -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* usb i2c stuff */
|
||||
static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb,
|
||||
flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
|
||||
flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
|
||||
{
|
||||
u16 wValue, wIndex;
|
||||
int nWaitTime,pipe,len;
|
||||
// u8 dwRequestType;
|
||||
u8 request_type = USB_TYPE_VENDOR;
|
||||
|
||||
switch (func) {
|
||||
case USB_FUNC_I2C_WRITE:
|
||||
case USB_FUNC_I2C_MULTIWRITE:
|
||||
case USB_FUNC_I2C_REPEATWRITE:
|
||||
/* DKT 020208 - add this to support special case of DiSEqC */
|
||||
case USB_FUNC_I2C_CHECKWRITE:
|
||||
pipe = B2C2_USB_CTRL_PIPE_OUT;
|
||||
nWaitTime = 2;
|
||||
// dwRequestType = (u8) RTYPE_GENERIC;
|
||||
request_type |= USB_DIR_OUT;
|
||||
break;
|
||||
case USB_FUNC_I2C_READ:
|
||||
case USB_FUNC_I2C_REPEATREAD:
|
||||
pipe = B2C2_USB_CTRL_PIPE_IN;
|
||||
nWaitTime = 2;
|
||||
// dwRequestType = (u8) RTYPE_GENERIC;
|
||||
request_type |= USB_DIR_IN;
|
||||
break;
|
||||
default:
|
||||
deb_info("unsupported function for i2c_req %x\n",func);
|
||||
return -EINVAL;
|
||||
}
|
||||
wValue = (func << 8 ) | (port << 4);
|
||||
wIndex = (chipaddr << 8 ) | addr;
|
||||
|
||||
deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
|
||||
((wValue && 0xff) << 8),wValue >> 8,((wIndex && 0xff) << 8),wIndex >> 8);
|
||||
|
||||
len = usb_control_msg(fc_usb->udev,pipe,
|
||||
req,
|
||||
request_type,
|
||||
wValue,
|
||||
wIndex,
|
||||
buf,
|
||||
buflen,
|
||||
nWaitTime * HZ);
|
||||
|
||||
return len == buflen ? 0 : -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* actual bus specific access functions, make sure prototype are/will be equal to pci */
|
||||
static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg)
|
||||
{
|
||||
flexcop_ibi_value val;
|
||||
val.raw = 0;
|
||||
flexcop_usb_readwrite_dw(fc,reg, &val.raw, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_register reg, flexcop_ibi_value val)
|
||||
{
|
||||
return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
|
||||
}
|
||||
|
||||
static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
|
||||
flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
|
||||
{
|
||||
if (op == FC_READ)
|
||||
return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len);
|
||||
else
|
||||
return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len);
|
||||
}
|
||||
|
||||
static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
|
||||
{
|
||||
struct flexcop_usb *fc_usb = urb->context;
|
||||
int i;
|
||||
|
||||
if (urb->actual_length > 0)
|
||||
deb_ts("urb completed, bufsize: %d actlen; %d\n",urb->transfer_buffer_length, urb->actual_length);
|
||||
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
if (urb->iso_frame_desc[i].status < 0) {
|
||||
err("iso frame descriptor %d has an error: %d\n",i,urb->iso_frame_desc[i].status);
|
||||
} else
|
||||
if (urb->iso_frame_desc[i].actual_length > 0) {
|
||||
deb_ts("passed %d bytes to the demux\n",urb->iso_frame_desc[i].actual_length);
|
||||
|
||||
flexcop_pass_dmx_data(fc_usb->fc_dev,
|
||||
urb->transfer_buffer + urb->iso_frame_desc[i].offset,
|
||||
urb->iso_frame_desc[i].actual_length);
|
||||
}
|
||||
urb->iso_frame_desc[i].status = 0;
|
||||
urb->iso_frame_desc[i].actual_length = 0;
|
||||
}
|
||||
|
||||
usb_submit_urb(urb,GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
|
||||
{
|
||||
/* submit/kill iso packets */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
|
||||
if (fc_usb->iso_urb[i] != NULL) {
|
||||
deb_ts("unlinking/killing urb no. %d\n",i);
|
||||
usb_kill_urb(fc_usb->iso_urb[i]);
|
||||
usb_free_urb(fc_usb->iso_urb[i]);
|
||||
}
|
||||
|
||||
if (fc_usb->iso_buffer != NULL)
|
||||
pci_free_consistent(NULL,fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr);
|
||||
}
|
||||
|
||||
static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
u16 frame_size = fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize;
|
||||
int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
|
||||
int buffer_offset = 0;
|
||||
|
||||
deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
|
||||
B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
|
||||
|
||||
fc_usb->iso_buffer = pci_alloc_consistent(NULL,bufsize,&fc_usb->dma_addr);
|
||||
if (fc_usb->iso_buffer == NULL)
|
||||
return -ENOMEM;
|
||||
memset(fc_usb->iso_buffer, 0, bufsize);
|
||||
fc_usb->buffer_size = bufsize;
|
||||
|
||||
/* creating iso urbs */
|
||||
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
|
||||
if (!(fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
|
||||
ret = -ENOMEM;
|
||||
goto urb_error;
|
||||
}
|
||||
/* initialising and submitting iso urbs */
|
||||
for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
|
||||
int frame_offset = 0;
|
||||
struct urb *urb = fc_usb->iso_urb[i];
|
||||
deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
|
||||
|
||||
urb->dev = fc_usb->udev;
|
||||
urb->context = fc_usb;
|
||||
urb->complete = flexcop_usb_urb_complete;
|
||||
urb->pipe = B2C2_USB_DATA_PIPE;
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
urb->interval = 1;
|
||||
urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
|
||||
urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
|
||||
urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
|
||||
|
||||
buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
|
||||
for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
|
||||
deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
|
||||
urb->iso_frame_desc[j].offset = frame_offset;
|
||||
urb->iso_frame_desc[j].length = frame_size;
|
||||
frame_offset += frame_size;
|
||||
}
|
||||
|
||||
if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
|
||||
err("submitting urb %d failed with %d.",i,ret);
|
||||
goto urb_error;
|
||||
}
|
||||
deb_ts("submitted urb no. %d.\n",i);
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
|
||||
flexcop_sram_set_dest(fc_usb->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET |
|
||||
FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_WAN_USB);
|
||||
flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
|
||||
flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
|
||||
|
||||
ret = 0;
|
||||
goto success;
|
||||
urb_error:
|
||||
flexcop_usb_transfer_exit(fc_usb);
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int flexcop_usb_init(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
/* use the alternate setting with the larges buffer */
|
||||
usb_set_interface(fc_usb->udev,0,1);
|
||||
switch (fc_usb->udev->speed) {
|
||||
case USB_SPEED_LOW:
|
||||
err("cannot handle USB speed because it is to sLOW.");
|
||||
return -ENODEV;
|
||||
break;
|
||||
case USB_SPEED_FULL:
|
||||
info("running at FULL speed.");
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
info("running at HIGH speed.");
|
||||
break;
|
||||
case USB_SPEED_UNKNOWN: /* fall through */
|
||||
default:
|
||||
err("cannot handle USB speed because it is unkown.");
|
||||
return -ENODEV;
|
||||
}
|
||||
usb_set_intfdata(fc_usb->uintf, fc_usb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
|
||||
{
|
||||
usb_set_intfdata(fc_usb->uintf, NULL);
|
||||
}
|
||||
|
||||
static int flexcop_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct flexcop_usb *fc_usb = NULL;
|
||||
struct flexcop_device *fc = NULL;
|
||||
int ret;
|
||||
|
||||
if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
|
||||
err("out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* general flexcop init */
|
||||
fc_usb = fc->bus_specific;
|
||||
fc_usb->fc_dev = fc;
|
||||
|
||||
fc->read_ibi_reg = flexcop_usb_read_ibi_reg;
|
||||
fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
|
||||
fc->i2c_request = flexcop_usb_i2c_request;
|
||||
fc->get_mac_addr = flexcop_usb_get_mac_addr;
|
||||
|
||||
fc->stream_control = flexcop_usb_stream_control;
|
||||
|
||||
fc->pid_filtering = 1;
|
||||
fc->bus_type = FC_USB;
|
||||
|
||||
fc->dev = &udev->dev;
|
||||
|
||||
/* bus specific part */
|
||||
fc_usb->udev = udev;
|
||||
fc_usb->uintf = intf;
|
||||
if ((ret = flexcop_usb_init(fc_usb)) != 0)
|
||||
goto err_kfree;
|
||||
|
||||
/* init flexcop */
|
||||
if ((ret = flexcop_device_initialize(fc)) != 0)
|
||||
goto err_usb_exit;
|
||||
|
||||
/* xfer init */
|
||||
if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
|
||||
goto err_fc_exit;
|
||||
|
||||
info("%s successfully initialized and connected.",DRIVER_NAME);
|
||||
ret = 0;
|
||||
goto success;
|
||||
err_fc_exit:
|
||||
flexcop_device_exit(fc);
|
||||
err_usb_exit:
|
||||
flexcop_usb_exit(fc_usb);
|
||||
err_kfree:
|
||||
flexcop_device_kfree(fc);
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void flexcop_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
|
||||
flexcop_usb_transfer_exit(fc_usb);
|
||||
flexcop_device_exit(fc_usb->fc_dev);
|
||||
flexcop_usb_exit(fc_usb);
|
||||
flexcop_device_kfree(fc_usb->fc_dev);
|
||||
info("%s successfully deinitialized and disconnected.",DRIVER_NAME);
|
||||
}
|
||||
|
||||
static struct usb_device_id flexcop_usb_table [] = {
|
||||
{ USB_DEVICE(0x0af7, 0x0101) },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver flexcop_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Technisat/B2C2 FlexCop II/IIb/III USB",
|
||||
.probe = flexcop_usb_probe,
|
||||
.disconnect = flexcop_usb_disconnect,
|
||||
.id_table = flexcop_usb_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init flexcop_usb_module_init(void)
|
||||
{
|
||||
int result;
|
||||
if ((result = usb_register(&flexcop_usb_driver))) {
|
||||
err("usb_register failed. (%d)",result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit flexcop_usb_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&flexcop_usb_driver);
|
||||
}
|
||||
|
||||
module_init(flexcop_usb_module_init);
|
||||
module_exit(flexcop_usb_module_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_NAME);
|
||||
MODULE_LICENSE("GPL");
|
116
drivers/media/dvb/b2c2/flexcop-usb.h
Normal file
116
drivers/media/dvb/b2c2/flexcop-usb.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
#ifndef __FLEXCOP_USB_H_INCLUDED__
|
||||
#define __FLEXCOP_USB_H_INCLUDED__
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
/* transfer parameters */
|
||||
#define B2C2_USB_FRAMES_PER_ISO 4
|
||||
#define B2C2_USB_NUM_ISO_URB 4
|
||||
|
||||
#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0)
|
||||
#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0)
|
||||
#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81)
|
||||
|
||||
struct flexcop_usb {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *uintf;
|
||||
|
||||
u8 *iso_buffer;
|
||||
int buffer_size;
|
||||
dma_addr_t dma_addr;
|
||||
struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
|
||||
|
||||
struct flexcop_device *fc_dev;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* request types TODO What is its use?*/
|
||||
typedef enum {
|
||||
|
||||
/* something is wrong with this part
|
||||
RTYPE_READ_DW = (1 << 6),
|
||||
RTYPE_WRITE_DW_1 = (3 << 6),
|
||||
RTYPE_READ_V8_MEMORY = (6 << 6),
|
||||
RTYPE_WRITE_V8_MEMORY = (7 << 6),
|
||||
RTYPE_WRITE_V8_FLASH = (8 << 6),
|
||||
RTYPE_GENERIC = (9 << 6),
|
||||
*/
|
||||
} flexcop_usb_request_type_t;
|
||||
#endif
|
||||
|
||||
/* request */
|
||||
typedef enum {
|
||||
B2C2_USB_WRITE_V8_MEM = 0x04,
|
||||
B2C2_USB_READ_V8_MEM = 0x05,
|
||||
B2C2_USB_READ_REG = 0x08,
|
||||
B2C2_USB_WRITE_REG = 0x0A,
|
||||
/* B2C2_USB_WRITEREGLO = 0x0A, */
|
||||
B2C2_USB_WRITEREGHI = 0x0B,
|
||||
B2C2_USB_FLASH_BLOCK = 0x10,
|
||||
B2C2_USB_I2C_REQUEST = 0x11,
|
||||
B2C2_USB_UTILITY = 0x12,
|
||||
} flexcop_usb_request_t;
|
||||
|
||||
/* function definition for I2C_REQUEST */
|
||||
typedef enum {
|
||||
USB_FUNC_I2C_WRITE = 0x01,
|
||||
USB_FUNC_I2C_MULTIWRITE = 0x02,
|
||||
USB_FUNC_I2C_READ = 0x03,
|
||||
USB_FUNC_I2C_REPEATWRITE = 0x04,
|
||||
USB_FUNC_GET_DESCRIPTOR = 0x05,
|
||||
USB_FUNC_I2C_REPEATREAD = 0x06,
|
||||
/* DKT 020208 - add this to support special case of DiSEqC */
|
||||
USB_FUNC_I2C_CHECKWRITE = 0x07,
|
||||
USB_FUNC_I2C_CHECKRESULT = 0x08,
|
||||
} flexcop_usb_i2c_function_t;
|
||||
|
||||
/*
|
||||
* function definition for UTILITY request 0x12
|
||||
* DKT 020304 - new utility function
|
||||
*/
|
||||
typedef enum {
|
||||
UTILITY_SET_FILTER = 0x01,
|
||||
UTILITY_DATA_ENABLE = 0x02,
|
||||
UTILITY_FLEX_MULTIWRITE = 0x03,
|
||||
UTILITY_SET_BUFFER_SIZE = 0x04,
|
||||
UTILITY_FLEX_OPERATOR = 0x05,
|
||||
UTILITY_FLEX_RESET300_START = 0x06,
|
||||
UTILITY_FLEX_RESET300_STOP = 0x07,
|
||||
UTILITY_FLEX_RESET300 = 0x08,
|
||||
UTILITY_SET_ISO_SIZE = 0x09,
|
||||
UTILITY_DATA_RESET = 0x0A,
|
||||
UTILITY_GET_DATA_STATUS = 0x10,
|
||||
UTILITY_GET_V8_REG = 0x11,
|
||||
/* DKT 020326 - add function for v1.14 */
|
||||
UTILITY_SRAM_WRITE = 0x12,
|
||||
UTILITY_SRAM_READ = 0x13,
|
||||
UTILITY_SRAM_TESTFILL = 0x14,
|
||||
UTILITY_SRAM_TESTSET = 0x15,
|
||||
UTILITY_SRAM_TESTVERIFY = 0x16,
|
||||
} flexcop_usb_utility_function_t;
|
||||
|
||||
#define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */
|
||||
|
||||
#define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */
|
||||
#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */
|
||||
|
||||
typedef enum {
|
||||
V8_MEMORY_PAGE_DVB_CI = 0x20,
|
||||
V8_MEMORY_PAGE_DVB_DS = 0x40,
|
||||
V8_MEMORY_PAGE_MULTI2 = 0x60,
|
||||
V8_MEMORY_PAGE_FLASH = 0x80
|
||||
} flexcop_usb_mem_page_t;
|
||||
|
||||
#define V8_MEMORY_EXTENDED (1 << 15)
|
||||
|
||||
#define USB_MEM_READ_MAX 32
|
||||
#define USB_MEM_WRITE_MAX 1
|
||||
#define USB_FLASH_MAX 8
|
||||
|
||||
#define V8_MEMORY_PAGE_SIZE 0x8000 // 32K
|
||||
#define V8_MEMORY_PAGE_MASK 0x7FFF
|
||||
|
||||
#endif
|
288
drivers/media/dvb/b2c2/flexcop.c
Normal file
288
drivers/media/dvb/b2c2/flexcop.c
Normal file
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* based on the skystar2-driver
|
||||
* Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
|
||||
*
|
||||
* Acknowledgements:
|
||||
* John Jurrius from BBTI, Inc. for extensive support with
|
||||
* code examples and data books
|
||||
*
|
||||
* Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
|
||||
*
|
||||
* Contributions to the skystar2-driver have been done by
|
||||
* Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
|
||||
* Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
|
||||
* Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "flexcop.h"
|
||||
|
||||
#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
|
||||
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
|
||||
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define DEBSTATUS ""
|
||||
#else
|
||||
#define DEBSTATUS " (debugging is not enabled)"
|
||||
#endif
|
||||
|
||||
int b2c2_flexcop_debug;
|
||||
module_param_named(debug, b2c2_flexcop_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS);
|
||||
#undef DEBSTATUS
|
||||
|
||||
/* global zero for ibi values */
|
||||
flexcop_ibi_value ibi_zero;
|
||||
|
||||
static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct flexcop_device *fc = dvbdmxfeed->demux->priv;
|
||||
return flexcop_pid_feed_control(fc,dvbdmxfeed,1);
|
||||
}
|
||||
|
||||
static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct flexcop_device *fc = dvbdmxfeed->demux->priv;
|
||||
return flexcop_pid_feed_control(fc,dvbdmxfeed,0);
|
||||
}
|
||||
|
||||
static int flexcop_dvb_init(struct flexcop_device *fc)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",THIS_MODULE)) < 0) {
|
||||
err("error registering DVB adapter");
|
||||
return ret;
|
||||
}
|
||||
fc->dvb_adapter.priv = fc;
|
||||
|
||||
fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
|
||||
fc->demux.priv = fc;
|
||||
|
||||
fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
|
||||
|
||||
fc->demux.start_feed = flexcop_dvb_start_feed;
|
||||
fc->demux.stop_feed = flexcop_dvb_stop_feed;
|
||||
fc->demux.write_to_decoder = NULL;
|
||||
|
||||
if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
|
||||
err("dvb_dmx failed: error %d",ret);
|
||||
goto err_dmx;
|
||||
}
|
||||
|
||||
fc->hw_frontend.source = DMX_FRONTEND_0;
|
||||
|
||||
fc->dmxdev.filternum = fc->demux.feednum;
|
||||
fc->dmxdev.demux = &fc->demux.dmx;
|
||||
fc->dmxdev.capabilities = 0;
|
||||
if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
|
||||
err("dvb_dmxdev_init failed: error %d",ret);
|
||||
goto err_dmx_dev;
|
||||
}
|
||||
|
||||
if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
|
||||
err("adding hw_frontend to dmx failed: error %d",ret);
|
||||
goto err_dmx_add_hw_frontend;
|
||||
}
|
||||
|
||||
fc->mem_frontend.source = DMX_MEMORY_FE;
|
||||
if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
|
||||
err("adding mem_frontend to dmx failed: error %d",ret);
|
||||
goto err_dmx_add_mem_frontend;
|
||||
}
|
||||
|
||||
if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
|
||||
err("connect frontend failed: error %d",ret);
|
||||
goto err_connect_frontend;
|
||||
}
|
||||
|
||||
dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
|
||||
|
||||
fc->init_state |= FC_STATE_DVB_INIT;
|
||||
goto success;
|
||||
|
||||
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;
|
||||
|
||||
success:
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_blocks = 0xff;
|
||||
v210.sw_reset_210.Block_reset_enable = 0xb2;
|
||||
fc->write_ibi_reg(fc,sw_reset_210,v210);
|
||||
|
||||
/* 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);
|
||||
v204.misc_204.Per_reset_sig = 1;
|
||||
fc->write_ibi_reg(fc,misc_204,v204);
|
||||
|
||||
/* v208.raw = 0;
|
||||
v208.ctrl_208.Null_filter_sig = 1;
|
||||
fc->write_ibi_reg(fc,ctrl_208,v208);*/
|
||||
}
|
||||
|
||||
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
|
||||
{
|
||||
void *bus;
|
||||
struct flexcop_device *fc = kmalloc(sizeof(struct flexcop_device), GFP_KERNEL);
|
||||
if (!fc) {
|
||||
err("no memory");
|
||||
return NULL;
|
||||
}
|
||||
memset(fc, 0, sizeof(struct flexcop_device));
|
||||
|
||||
bus = kmalloc(bus_specific_len, GFP_KERNEL);
|
||||
if (!bus) {
|
||||
err("no memory");
|
||||
kfree(fc);
|
||||
return NULL;
|
||||
}
|
||||
memset(bus, 0, bus_specific_len);
|
||||
|
||||
fc->bus_specific = bus;
|
||||
|
||||
return fc;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_device_kmalloc);
|
||||
|
||||
void flexcop_device_kfree(struct flexcop_device *fc)
|
||||
{
|
||||
kfree(fc->bus_specific);
|
||||
kfree(fc);
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_device_kfree);
|
||||
|
||||
int flexcop_device_initialize(struct flexcop_device *fc)
|
||||
{
|
||||
int ret;
|
||||
ibi_zero.raw = 0;
|
||||
|
||||
flexcop_reset(fc);
|
||||
flexcop_determine_revision(fc);
|
||||
flexcop_sram_init(fc);
|
||||
flexcop_hw_filter_init(fc);
|
||||
|
||||
flexcop_smc_ctrl(fc, 0);
|
||||
|
||||
if (fc->get_mac_addr(fc, 0) == 0) {
|
||||
u8 *b = fc->mac_address;
|
||||
info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]);
|
||||
flexcop_set_mac_filter(fc,fc->mac_address);
|
||||
flexcop_mac_filter_ctrl(fc,1);
|
||||
} else
|
||||
warn("reading of MAC address failed.\n");
|
||||
|
||||
if ((ret = flexcop_dvb_init(fc)))
|
||||
goto error;
|
||||
|
||||
if ((ret = flexcop_i2c_init(fc)))
|
||||
goto error;
|
||||
|
||||
if ((ret = flexcop_frontend_init(fc)))
|
||||
goto error;
|
||||
|
||||
flexcop_device_name(fc,"initialization of","complete");
|
||||
|
||||
ret = 0;
|
||||
goto success;
|
||||
error:
|
||||
flexcop_device_exit(fc);
|
||||
success:
|
||||
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");
|
30
drivers/media/dvb/b2c2/flexcop.h
Normal file
30
drivers/media/dvb/b2c2/flexcop.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
|
||||
*
|
||||
* flexcop.h - private header file for all flexcop-chip-source files.
|
||||
*
|
||||
* see flexcop.c for copyright information.
|
||||
*/
|
||||
#ifndef __FLEXCOP_H__
|
||||
#define __FLEXCOP_H___
|
||||
|
||||
#define FC_LOG_PREFIX "b2c2-flexcop"
|
||||
#include "flexcop-common.h"
|
||||
|
||||
extern int b2c2_flexcop_debug;
|
||||
|
||||
/* debug */
|
||||
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
|
||||
#define dprintk(level,args...) \
|
||||
do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
|
||||
#else
|
||||
#define dprintk(level,args...)
|
||||
#endif
|
||||
|
||||
#define deb_info(args...) dprintk(0x01,args)
|
||||
#define deb_tuner(args...) dprintk(0x02,args)
|
||||
#define deb_i2c(args...) dprintk(0x04,args)
|
||||
#define deb_ts(args...) dprintk(0x08,args)
|
||||
#define deb_sram(args...) dprintk(0x10,args)
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue