Commit 776338e1 authored by Johannes Stezenbach's avatar Johannes Stezenbach Committed by Linus Torvalds

[PATCH] dvb: Add generalized dvb-usb driver

Add generalized dvb-usb driver which supports a wide variety of devices.
Signed-off-by: default avatarPatrick Boettcher <pb@linuxtv.org>
Signed-off-by: default avatarJohannes Stezenbach <js@linuxtv.org>
Signed-off-by: default avatarRandy Dunlap <rdunlap@xenotime.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b6a235b1
Documentation for dvb-usb-framework module and its devices
Idea behind the dvb-usb-framework
=================================
In March 2005 I got the new Twinhan USB2.0 DVB-T device. They provided specs and a firmware.
Quite keen I wanted to put the driver (with some quirks of course) into dibusb.
After reading some specs and doing some USB snooping, it realized, that the
dibusb-driver would be a complete mess afterwards. So I decided to do it in a
different way: With the help of a dvb-usb-framework.
The framework provides generic functions (mostly kernel API calls), such as:
- Transport Stream URB handling in conjunction with dvb-demux-feed-control
(bulk and isoc (TODO) are supported)
- registering the device for the DVB-API
- registering an I2C-adapter if applicable
- remote-control/input-device handling
- firmware requesting and loading (currently just for the Cypress USB
controller)
- other functions/methods which can be shared by several drivers (such as
functions for bulk-control-commands)
The source code of the particular DVB USB devices does just the communication
with the device via the bus. The connection between the DVB-API-functionality
is done via callbacks, assigned in a static device-description (struct
dvb_usb_device) each device-driver has to have.
For an example have a look in drivers/media/dvb/dvb-usb/vp7045*.
Objective is to migrate all the usb-devices (dibusb, cinergyT2, maybe the
ttusb; flexcop-usb already benefits from the generic flexcop-device) to use
the dvb-usb-lib.
TODO: dynamic enabling and disabling of the pid-filter in regard to number of
feeds requested.
Supported devices USB1.1
========================
Produced and reselled by Twinhan:
---------------------------------
- TwinhanDTV USB-Ter DVB-T Device (VP7041)
http://www.twinhan.com/product_terrestrial_3.asp
- TwinhanDTV Magic Box (VP7041e)
http://www.twinhan.com/product_terrestrial_4.asp
- HAMA DVB-T USB device
http://www.hama.de/portal/articleId*110620/action*2598
- CTS Portable (Chinese Television System) (2)
http://www.2cts.tv/ctsportable/
- Unknown USB DVB-T device with vendor ID Hyper-Paltek
Produced and reselled by KWorld:
--------------------------------
- KWorld V-Stream XPERT DTV DVB-T USB
http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
- JetWay DTV DVB-T USB
http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
- ADSTech Instant TV DVB-T USB
http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
Others:
-------
- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
http://82.161.246.249/products-tvbox.html
- Compro Videomate DVB-U2000 - DVB-T USB (2)
http://www.comprousa.com/products/vmu2000.htm
- Grandtec USB DVB-T
http://www.grand.com.tw/
- AVerMedia AverTV DVBT USB
http://www.avermedia.com/
- DiBcom USB DVB-T reference device (non-public)
Supported devices USB2.0-only
=============================
- Twinhan MagicBox II
http://www.twinhan.com/product_terrestrial_7.asp
- TwinhanDTV Alpha
http://www.twinhan.com/product_terrestrial_8.asp
- DigitalNow TinyUSB 2 DVB-t Receiver
http://www.digitalnow.com.au/DigitalNow%20tinyUSB2%20Specifications.html
- Hanftek UMT-010
http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
Supported devices USB2.0 and USB1.1
=============================
- Typhoon/Yakumo/HAMA/Yuan DVB-T mobile USB2.0
http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
http://www.yuan.com.tw/en/products/vdo_ub300.html
http://www.hama.de/portal/articleId*114663/action*2563
http://www.anubisline.com/english/articlec.asp?id=50502&catid=002
- Artec T1 USB TVBOX (FX2) (2)
- Hauppauge WinTV NOVA-T USB2
http://www.hauppauge.com/
- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
- DiBcom USB2.0 DVB-T reference device (non-public)
- AVerMedia AverTV A800 DVB-T USB2.0
1) It is working almost - work-in-progress.
2) No test reports received yet.
0. History & News:
2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework
2005-04-02 - re-enabled and improved remote control code.
2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb.
2005-03-30 - first commit of the dvb-usb-module based on the dibusb-source. First device is a new driver for the
TwinhanDTV Alpha / MagicBox II USB2.0-only DVB-T device.
(change from dvb-dibusb to dvb-usb)
2005-03-28 - added support for the AVerMedia AverTV DVB-T USB2.0 device (Thanks to Glen Harris and Jiun-Kuei Jung, AVerMedia)
2005-03-14 - added support for the Typhoon/Yakumo/HAMA DVB-T mobile USB2.0
2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
2005-01-31 - distorted streaming is gone for USB1.1 devices
2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
- first almost working version for HanfTek UMT-010
- found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
2005-01-10 - refactoring completed, now everything is very delightful
- tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
2004-12-26 - refactored the dibusb-driver, splitted into separate files
- i2c-probing enabled
2004-12-06 - possibility for demod i2c-address probing
- new usb IDs (Compro, Artec)
2004-11-23 - merged changes from DiB3000MC_ver2.1
- revised the debugging
- possibility to deliver the complete TS for USB2.0
2004-11-21 - first working version of the dib3000mc/p frontend driver.
2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
2004-11-07 - added remote control support. Thanks to David Matthews.
2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
- merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
- moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems
better settled there (added xfer_ops-struct)
- created a common files for frontends (mc/p/mb)
2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
to Amaury Demol for reporting
- changed usb TS transfer method (several urbs, stopping transfer
before setting a new pid)
2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
to Christian Motschke for reporting
2004-09-05 - released the dibusb device and dib3000mb-frontend driver
(old news for vp7041.c)
2004-07-15 - found out, by accident, that the device has a TUA6010XS for
PLL
2004-07-12 - figured out, that the driver should also work with the
CTS Portable (Chinese Television System)
2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working
properly with firmware extracted from 2.422
- #if for 2.6.4 (dvb), compile issue
- changed firmware handling, see vp7041.txt sec 1.1
2004-07-02 - some tuner modifications, v0.1, cleanups, first public
2004-06-28 - now using the dvb_dmx_swfilter_packets, everything
runs fine now
2004-06-27 - able to watch and switching channels (pre-alpha)
- no section filtering yet
2004-06-06 - first TS received, but kernel oops :/
2004-05-14 - firmware loader is working
2004-05-11 - start writing the driver
1. How to use?
1.1. Firmware
Most of the USB drivers need to download a firmware to start working.
for USB1.1 (AN2135) you need: dvb-usb-dibusb-5.0.0.11.fw
for USB2.0 HanfTek: dvb-usb-umt-010-02.fw
for USB2.0 DiBcom: dvb-usb-dibusb-6.0.0.8.fw
for USB2.0 AVerMedia AverTV DVB-T USB2: dvb-usb-avertv-a800-01.fw
for USB2.0 TwinhanDTV Alpha/MagicBox II: dvb-usb-vp7045-01.fw
The files can be found on http://www.linuxtv.org/download/firmware/ .
We do not have the permission (yet) to publish the following firmware-files.
You'll need to extract them from the windows drivers.
You should be able to use "get_dvb_firmware dvb-usb" to get the firmware:
for USB1.1 (AN2235) (a few Artec T1 devices): dvb-usb-dibusb-an2235-01.fw
for USB2.0 Hauppauge: dvb-usb-nova-t-usb2-01.fw
for USB2.0 ADSTech/Kworld USB2.0: dvb-usb-adstech-usb2-01.fw
for USB2.0 Yakumo/Typhoon/Hama: dvb-usb-dtt200u-01.fw
1.2. Compiling
Since the driver is in the linux kernel, activating the driver in
your favorite config-environment should sufficient. I recommend
to compile the driver as module. Hotplug does the rest.
If you use dvb-kernel enter the build-2.6 directory run 'make' and 'insmod.sh
load' afterwards.
1.3. Loading the drivers
Hotplug is able to load the driver, when it is needed (because you plugged
in the device).
If you want to enable debug output, you have to load the driver manually and
from withing the dvb-kernel cvs repository.
first have a look, which debug level are available:
modinfo dvb-usb
modinfo dvb-usb-vp7045
etc.
modprobe dvb-usb debug=<level>
modprobe dvb-usb-vp7045 debug=<level>
etc.
should do the trick.
When the driver is loaded successfully, the firmware file was in
the right place and the device is connected, the "Power"-LED should be
turned on.
At this point you should be able to start a dvb-capable application. I'm use
(t|s)zap, mplayer and dvbscan to test the basics. VDR-xine provides the
long-term test scenario.
2. Known problems and bugs
- Don't remove the USB device while running an DVB application, your system
will go crazy or die most likely.
2.1. Adding support for devices
TODO
2.2. USB1.1 Bandwidth limitation
A lot of the currently supported devices are USB1.1 and thus they have a
maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
This is not enough for receiving the complete transport stream of a
DVB-T channel (which is about 16 MBit/s). Normally this is not a
problem, if you only want to watch TV (this does not apply for HDTV),
but watching a channel while recording another channel on the same
frequency simply does not work very well. This applies to all USB1.1
DVB-T devices, not just the dvb-usb-devices)
The bug, where the TS is distorted by a heavy usage of the device is gone
definitely. All dvb-usb-devices I was using (Twinhan, Kworld, DiBcom) are
working like charm now with VDR. Sometimes I even was able to record a channel
and watch another one.
2.3. Comments
Patches, comments and suggestions are very very welcome.
3. Acknowledgements
Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
providing specs, code and help, on which the dvb-dibusb, dib3000mb and
dib3000mc are based.
David Matthews for identifying a new device type (Artec T1 with AN2235)
and for extending dibusb with remote control event handling. Thank you.
Alex Woods for frequently answering question about usb and dvb
stuff, a big thank you.
Bernd Wagner for helping with huge bug reports and discussions.
Gunnar Wittich and Joachim von Caron for their trust for providing
root-shells on their machines to implement support for new devices.
Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei
Jung from AVerMedia who kindly provided a special firmware to get the device
up and running in Linux.
Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by
writing the vp7045-driver.
Some guys on the linux-dvb mailing list for encouraging me
Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
user-level firmware loader, which saves a lot of time
(when writing the vp7041 driver)
Ulf Hermenau for helping me out with traditional chinese.
André Smoktun and Christian Frömmel for supporting me with
hardware and listening to my problems very patient.
...@@ -27,6 +27,7 @@ source "drivers/media/dvb/ttpci/Kconfig" ...@@ -27,6 +27,7 @@ source "drivers/media/dvb/ttpci/Kconfig"
comment "Supported USB Adapters" comment "Supported USB Adapters"
depends on DVB_CORE && USB depends on DVB_CORE && USB
source "drivers/media/dvb/dvb-usb/Kconfig"
source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig"
source "drivers/media/dvb/ttusb-dec/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig"
source "drivers/media/dvb/cinergyT2/Kconfig" source "drivers/media/dvb/cinergyT2/Kconfig"
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
# Makefile for the kernel multimedia device drivers. # Makefile for the kernel multimedia device drivers.
# #
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/
config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB
select FW_LOADER
help
By enabling this you will be able to choose the various USB 1.1 and
USB2.0 DVB devices.
Almost every USB device needs a firmware, please look into
<file:Documentation/dvb/README.dvb-usb>
Say Y if you own an USB DVB device.
config DVB_USB_DEBUG
bool "Enable extended debug support for all DVB-USB devices"
depends on DVB_USB
help
Say Y if you want to enable debuging. See modinfo dvb-usb (and the
appropriate drivers) for debug levels.
config DVB_USB_A800
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
depends on DVB_USB
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
config DVB_USB_DIBUSB_MB
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
depends on DVB_USB
help
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
Devices supported by this driver:
TwinhanDTV USB-Ter (VP7041)
TwinhanDTV Magic Box (VP7041e)
KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
Hama DVB-T USB1.1-Box
DiBcom USB1.1 reference devices (non-public)
Ultima Electronic/Artec T1 USB TVBOX
Compro Videomate DVB-U2000 - DVB-T USB
Grandtec DVB-T USB
Avermedia AverTV DVBT USB1.1
Artec T1 USB1.1 boxes
The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System).
Say Y if you own such a device and want to use it. You should build it as
a module.
config DVB_USB_DIBUSB_MC
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB
help
Support for 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
Devices supported by this driver:
DiBcom USB2.0 reference devices (non-public)
Artec T1 USB2.0 boxes
Say Y if you own such a device and want to use it. You should build it as
a module.
config DVB_USB_UMT_010
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
depends on DVB_USB
help
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
help
Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
config DVB_USB_VP7045
tristate "TwinhanDTV Alpha/MagicBoxII and DNTV tinyUSB2 DVB-T USB2.0 support"
depends on DVB_USB
help
Say Y here to support the
TwinhanDTV Alpha (stick) (VP-7045),
TwinhanDTV MagicBox II (VP-7046) and
DigitalNow TinyUSB 2 DVB-t DVB-T USB2.0 receivers.
config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
config DVB_USB_DTT200U
tristate "Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support"
depends on DVB_USB
help
Say Y here to support the Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o
obj-$(CONFIG_DVB_USB) += dvb-usb.o
dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
dvb-usb-dibusb-common-objs = dibusb-common.o
dvb-usb-a800-objs = a800.o
obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
dvb-usb-dibusb-mb-objs = dibusb-mb.o
obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
dvb-usb-dibusb-mc-objs = dibusb-mc.o
obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
dvb-usb-nova-t-usb2-objs = nova-t-usb2.o
obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
dvb-usb-umt-010-objs = umt-010.o
obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
dvb-usb-digitv-objs = digitv.o
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
* USB2.0 (A800) DVB-T receiver.
*
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
*
* Thanks to
* - AVerMedia who kindly provided information and
* - Glen Harris who suffered from my mistakes during development.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dibusb.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
#define deb_rc(args...) dprintk(debug,0x01,args)
static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
{
/* do nothing for the AVerMedia */
return 0;
}
static struct dvb_usb_rc_key a800_rc_keys[] = {
{ 0x02, 0x01, KEY_PROG1 }, /* SOURCE */
{ 0x02, 0x00, KEY_POWER }, /* POWER */
{ 0x02, 0x05, KEY_1 }, /* 1 */
{ 0x02, 0x06, KEY_2 }, /* 2 */
{ 0x02, 0x07, KEY_3 }, /* 3 */
{ 0x02, 0x09, KEY_4 }, /* 4 */
{ 0x02, 0x0a, KEY_5 }, /* 5 */
{ 0x02, 0x0b, KEY_6 }, /* 6 */
{ 0x02, 0x0d, KEY_7 }, /* 7 */
{ 0x02, 0x0e, KEY_8 }, /* 8 */
{ 0x02, 0x0f, KEY_9 }, /* 9 */
{ 0x02, 0x12, KEY_LEFT }, /* L / DISPLAY */
{ 0x02, 0x11, KEY_0 }, /* 0 */
{ 0x02, 0x13, KEY_RIGHT }, /* R / CH RTN */
{ 0x02, 0x17, KEY_PROG2 }, /* SNAP SHOT */
{ 0x02, 0x10, KEY_PROG3 }, /* 16-CH PREV */
{ 0x02, 0x03, KEY_CHANNELUP }, /* CH UP */
{ 0x02, 0x1e, KEY_VOLUMEDOWN }, /* VOL DOWN */
{ 0x02, 0x0c, KEY_ZOOM }, /* FULL SCREEN */
{ 0x02, 0x1f, KEY_VOLUMEUP }, /* VOL UP */
{ 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
{ 0x02, 0x14, KEY_MUTE }, /* MUTE */
{ 0x02, 0x08, KEY_AUDIO }, /* AUDIO */
{ 0x02, 0x19, KEY_RECORD }, /* RECORD */
{ 0x02, 0x18, KEY_PLAY }, /* PLAY */
{ 0x02, 0x1b, KEY_STOP }, /* STOP */
{ 0x02, 0x1a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
{ 0x02, 0x1d, KEY_BACK }, /* << / RED */
{ 0x02, 0x1c, KEY_FORWARD }, /* >> / YELLOW */
{ 0x02, 0x03, KEY_TEXT }, /* TELETEXT */
{ 0x02, 0x01, KEY_FIRST }, /* |<< / GREEN */
{ 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */
{ 0x02, 0x04, KEY_EPG }, /* EPG */
{ 0x02, 0x15, KEY_MENU }, /* MENU */
};
int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[5];
if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
2*HZ) != 5)
return -ENODEV;
/* call the universal NEC remote processor, to find out the key's state and event */
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
}
/* USB Driver stuff */
static struct dvb_usb_properties a800_properties;
static int a800_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE);
}
/* do not change the order of the ID table */
static struct usb_device_id a800_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) },
/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, a800_table);
static struct dvb_usb_properties a800_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
.pid_filter_count = 32,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-avertv-a800-02.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = a800_power_ctrl,
.frontend_attach = dibusb_dib3000mc_frontend_attach,
.tuner_attach = dibusb_dib3000mc_tuner_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = a800_rc_keys,
.rc_key_map_size = ARRAY_SIZE(a800_rc_keys),
.rc_query = a800_rc_query,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 1,
.devices = {
{ "AVerMedia AverTV DVB-T USB 2.0 (A800)",
{ &a800_table[0], NULL },
{ &a800_table[1], NULL },
},
}
};
static struct usb_driver a800_driver = {
.owner = THIS_MODULE,
.name = "AVerMedia AverTV DVB-T USB 2.0 (A800)",
.probe = a800_probe,
.disconnect = dvb_usb_device_exit,
.id_table = a800_table,
};
/* module stuff */
static int __init a800_module_init(void)
{
int result;
if ((result = usb_register(&a800_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void __exit a800_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&a800_driver);
}
module_init (a800_module_init);
module_exit (a800_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* Common methods for dibusb-based-receivers.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dibusb.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
MODULE_LICENSE("GPL");
#define deb_info(args...) dprintk(debug,0x01,args)
/* common stuff used by the different dibusb modules */
int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
{
if (d->priv != NULL) {
struct dib_fe_xfer_ops *ops = d->priv;
if (ops->fifo_ctrl != NULL)
if (ops->fifo_ctrl(d->fe,onoff)) {
err("error while controlling the fifo of the demod.");
return -ENODEV;
}
}
return 0;
}
EXPORT_SYMBOL(dibusb_streaming_ctrl);
int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
{
if (d->priv != NULL) {
struct dib_fe_xfer_ops *ops = d->priv;
if (d->pid_filtering && ops->pid_ctrl != NULL)
ops->pid_ctrl(d->fe,index,pid,onoff);
}
return 0;
}
EXPORT_SYMBOL(dibusb_pid_filter);
int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff)
{
if (d->priv != NULL) {
struct dib_fe_xfer_ops *ops = d->priv;
if (ops->pid_parse != NULL)
if (ops->pid_parse(d->fe,onoff) < 0)
err("could not handle pid_parser");
}
return 0;
}
EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 b[3];
int ret;
b[0] = DIBUSB_REQ_SET_IOCTL;
b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
ret = dvb_usb_generic_write(d,b,3);
msleep(10);
return ret;
}
EXPORT_SYMBOL(dibusb_power_ctrl);
int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 b[2];
b[0] = DIBUSB_REQ_SET_IOCTL;
b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
dvb_usb_generic_write(d,b,3);
return dibusb_streaming_ctrl(d,onoff);
}
EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
{
if (onoff) {
u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
return dvb_usb_generic_write(d,b,3);
} else
return 0;
}
EXPORT_SYMBOL(dibusb2_0_power_ctrl);
static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
/* write only ? */
int wo = (rbuf == NULL || rlen == 0),
len = 2 + wlen + (wo ? 0 : 2);
sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
memcpy(&sndbuf[2],wbuf,wlen);
if (!wo) {
sndbuf[wlen+2] = (rlen >> 8) & 0xff;
sndbuf[wlen+3] = rlen & 0xff;
}
return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
}
/*
* I2C master xfer function
*/
static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
if (down_interruptible(&d->i2c_sem) < 0)
return -EAGAIN;
if (num > 2)
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
for (i = 0; i < num; i++) {
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
msg[i+1].buf,msg[i+1].len) < 0)
break;
i++;
} else
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
break;
}
up(&d->i2c_sem);
return i;
}
static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
struct i2c_algorithm dibusb_i2c_algo = {
.name = "DiBcom USB I2C algorithm",
.id = I2C_ALGO_BIT,
.master_xfer = dibusb_i2c_xfer,
.functionality = dibusb_i2c_func,
};
EXPORT_SYMBOL(dibusb_i2c_algo);
int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
{
u8 wbuf[1] = { offs };
return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
}
EXPORT_SYMBOL(dibusb_read_eeprom_byte);
int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
{
struct dib3000_config demod_cfg;
struct dibusb_state *st = d->priv;
demod_cfg.pll_set = dvb_usb_pll_set_i2c;
demod_cfg.pll_init = dvb_usb_pll_init_i2c;
for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
return 0;
}
return -ENODEV;
}
EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_env57h1xd5;
return 0;
}
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
/*
* common remote control stuff
*/
struct dvb_usb_rc_key dibusb_rc_keys[] = {
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{ 0x00, 0x16, KEY_POWER },
{ 0x00, 0x10, KEY_MUTE },
{ 0x00, 0x03, KEY_1 },
{ 0x00, 0x01, KEY_2 },
{ 0x00, 0x06, KEY_3 },
{ 0x00, 0x09, KEY_4 },
{ 0x00, 0x1d, KEY_5 },
{ 0x00, 0x1f, KEY_6 },
{ 0x00, 0x0d, KEY_7 },
{ 0x00, 0x19, KEY_8 },
{ 0x00, 0x1b, KEY_9 },
{ 0x00, 0x15, KEY_0 },
{ 0x00, 0x05, KEY_CHANNELUP },
{ 0x00, 0x02, KEY_CHANNELDOWN },
{ 0x00, 0x1e, KEY_VOLUMEUP },
{ 0x00, 0x0a, KEY_VOLUMEDOWN },
{ 0x00, 0x11, KEY_RECORD },
{ 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
{ 0x00, 0x14, KEY_PLAY },
{ 0x00, 0x1a, KEY_STOP },
{ 0x00, 0x40, KEY_REWIND },
{ 0x00, 0x12, KEY_FASTFORWARD },
{ 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
{ 0x00, 0x4c, KEY_PAUSE },
{ 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
{ 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
{ 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
{ 0x00, 0x1c, KEY_EPG }, /* EPG */
{ 0x00, 0x00, KEY_TAB }, /* Tab */
{ 0x00, 0x48, KEY_INFO }, /* Preview */
{ 0x00, 0x04, KEY_LIST }, /* RecordList */
{ 0x00, 0x0f, KEY_TEXT }, /* Teletext */
/* Key codes for the KWorld/ADSTech/JetWay remote. */
{ 0x86, 0x12, KEY_POWER },
{ 0x86, 0x0f, KEY_SELECT }, /* source */
{ 0x86, 0x0c, KEY_UNKNOWN }, /* scan */
{ 0x86, 0x0b, KEY_EPG },
{ 0x86, 0x10, KEY_MUTE },
{ 0x86, 0x01, KEY_1 },
{ 0x86, 0x02, KEY_2 },
{ 0x86, 0x03, KEY_3 },
{ 0x86, 0x04, KEY_4 },
{ 0x86, 0x05, KEY_5 },
{ 0x86, 0x06, KEY_6 },
{ 0x86, 0x07, KEY_7 },
{ 0x86, 0x08, KEY_8 },
{ 0x86, 0x09, KEY_9 },
{ 0x86, 0x0a, KEY_0 },
{ 0x86, 0x18, KEY_ZOOM },
{ 0x86, 0x1c, KEY_UNKNOWN }, /* preview */
{ 0x86, 0x13, KEY_UNKNOWN }, /* snap */
{ 0x86, 0x00, KEY_UNDO },
{ 0x86, 0x1d, KEY_RECORD },
{ 0x86, 0x0d, KEY_STOP },
{ 0x86, 0x0e, KEY_PAUSE },
{ 0x86, 0x16, KEY_PLAY },
{ 0x86, 0x11, KEY_BACK },
{ 0x86, 0x19, KEY_FORWARD },
{ 0x86, 0x14, KEY_UNKNOWN }, /* pip */
{ 0x86, 0x15, KEY_ESC },
{ 0x86, 0x1a, KEY_UP },
{ 0x86, 0x1e, KEY_DOWN },
{ 0x86, 0x1f, KEY_LEFT },
{ 0x86, 0x1b, KEY_RIGHT },
};
EXPORT_SYMBOL(dibusb_rc_keys);
int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
dvb_usb_generic_rw(d,&cmd,1,key,5,0);
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
}
EXPORT_SYMBOL(dibusb_rc_query);
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DiBcom, which has
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dibusb.h"
static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
{
struct dib3000_config demod_cfg;
struct dibusb_state *st = d->priv;
demod_cfg.demod_address = 0x8;
demod_cfg.pll_set = dvb_usb_pll_set_i2c;
demod_cfg.pll_init = dvb_usb_pll_init_i2c;
if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
return -ENODEV;
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
return 0;
}
/* some of the dibusb 1.1 device aren't equipped with the default tuner
* (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures
* this out. */
static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d)
{
u8 b[2] = { 0,0 }, b2[1];
int ret = 0;
struct i2c_msg msg[2] = {
{ .flags = 0, .buf = b, .len = 2 },
{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
};
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
msg[0].addr = msg[1].addr = 0x60;
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(d->fe,1,msg[0].addr);
if (i2c_transfer (&d->i2c_adap, msg, 2) != 2) {
err("tuner i2c write failed.");
ret = -EREMOTEIO;
}
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
if (b2[0] == 0xfe) {
info("this device has the Thomson Cable onboard. Which is default.");
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_tua6010xs;
} else {
u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("this device has the Panasonic ENV77H11D5 onboard.");
d->pll_addr = 0x60;
memcpy(d->pll_init,bpll,4);
d->pll_desc = &dvb_pll_tda665x;
}
return ret;
}
/* USB Driver stuff */
static struct dvb_usb_properties dibusb1_1_properties;
static struct dvb_usb_properties dibusb1_1_an2235_properties;
static struct dvb_usb_properties dibusb2_0b_properties;
static int dibusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE) == 0 ||
dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE) ||
dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE) == 0)
return 0;
return -EINVAL;
}
/* do not change the order of the ID table */
static struct usb_device_id dibusb_dib3000mb_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) },
/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) },
/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) },
/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) },
/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) },
/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) },
/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
static struct dvb_usb_properties dibusb1_1_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
.pid_filter_count = 16,
.usb_ctrl = CYPRESS_AN2135,
.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_dib3000mb_tuner_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
.rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 8,
.devices = {
{ "AVerMedia AverTV DVBT USB1.1",
{ &dibusb_dib3000mb_table[0], NULL },
{ &dibusb_dib3000mb_table[1], NULL },
},
{ "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
{ &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
{ &dibusb_dib3000mb_table[3], NULL },
},
{ "DiBcom USB1.1 DVB-T reference design (MOD3000)",
{ &dibusb_dib3000mb_table[5], NULL },
{ &dibusb_dib3000mb_table[6], NULL },
},
{ "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
{ &dibusb_dib3000mb_table[7], NULL },
{ &dibusb_dib3000mb_table[8], NULL },
},
{ "Grandtec USB1.1 DVB-T",
{ &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL },
{ &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
},
{ "Unkown USB1.1 DVB-T device ???? please report the name to the author",
{ &dibusb_dib3000mb_table[13], NULL },
{ &dibusb_dib3000mb_table[14], NULL },
},
{ "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
{ &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
{ &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
},
{ "Artec T1 USB1.1 TVBOX with AN2135",
{ &dibusb_dib3000mb_table[19], NULL },
{ &dibusb_dib3000mb_table[20], NULL },
},
}
};
static struct dvb_usb_properties dibusb1_1_an2235_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_AN2235,
.firmware = "dvb-usb-dibusb-an2235-01.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_dib3000mb_tuner_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
.rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 1,
.devices = {
{ "Artec T1 USB1.1 TVBOX with AN2235",
{ &dibusb_dib3000mb_table[20], NULL },
{ &dibusb_dib3000mb_table[21], NULL },
},
}
};
static struct dvb_usb_properties dibusb2_0b_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-adstech-usb2-01.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_dib3000mb_tuner_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
.rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
.rc_query = dibusb_rc_query,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 2,
.devices = {
{ "KWorld/ADSTech Instant DVB-T USB 2.0",
{ &dibusb_dib3000mb_table[23], NULL },
{ &dibusb_dib3000mb_table[24], NULL }, /* device ID with default DIBUSB2_0-firmware */
},
}
};
static struct usb_driver dibusb_driver = {
.owner = THIS_MODULE,
.name = "DiBcom based USB DVB-T devices (DiB3000M-B based)",
.probe = dibusb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = dibusb_dib3000mb_table,
};
/* module stuff */
static int __init dibusb_module_init(void)
{
int result;
if ((result = usb_register(&dibusb_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void __exit dibusb_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&dibusb_driver);
}
module_init (dibusb_module_init);
module_exit (dibusb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
* reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* based on GPL code from DiBcom, which has
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dibusb.h"
/* USB Driver stuff */
static struct dvb_usb_properties dibusb_mc_properties;
static int dibusb_mc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE);
}
/* do not change the order of the ID table */
static struct usb_device_id dibusb_dib3000mc_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
static struct dvb_usb_properties dibusb_mc_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
.pid_filter_count = 32,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mc_frontend_attach,
.tuner_attach = dibusb_dib3000mc_tuner_attach,
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dibusb_rc_keys,
.rc_key_map_size = 63, /* FIXME */
.rc_query = dibusb_rc_query,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 2,
.devices = {
{ "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
{ &dibusb_dib3000mc_table[0], NULL },
{ &dibusb_dib3000mc_table[1], NULL },
},
{ "Artec T1 USB2.0 TVBOX (please report the warm ID)",
{ &dibusb_dib3000mc_table[2], NULL },
{ NULL },
},
}
};
static struct usb_driver dibusb_mc_driver = {
.owner = THIS_MODULE,
.name = "DiBcom based USB2.0 DVB-T (DiB3000M-C/P based) devices",
.probe = dibusb_mc_probe,
.disconnect = dvb_usb_device_exit,
.id_table = dibusb_dib3000mc_table,
};
/* module stuff */
static int __init dibusb_mc_module_init(void)
{
int result;
if ((result = usb_register(&dibusb_mc_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void __exit dibusb_mc_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&dibusb_mc_driver);
}
module_init (dibusb_mc_module_init);
module_exit (dibusb_mc_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* Header file for all dibusb-based-receivers.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#ifndef _DVB_USB_DIBUSB_H_
#define _DVB_USB_DIBUSB_H_
#define DVB_USB_LOG_PREFIX "dibusb"
#include "dvb-usb.h"
#include "dib3000.h"
/*
* protocol of all dibusb related devices
*/
/*
* bulk msg to/from endpoint 0x01
*
* general structure:
* request_byte parameter_bytes
*/
#define DIBUSB_REQ_START_READ 0x00
#define DIBUSB_REQ_START_DEMOD 0x01
/*
* i2c read
* bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
* bulk read: byte_buffer (length_word bytes)
*/
#define DIBUSB_REQ_I2C_READ 0x02
/*
* i2c write
* bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
*/
#define DIBUSB_REQ_I2C_WRITE 0x03
/*
* polling the value of the remote control
* bulk write: 0x04
* bulk read: byte_buffer (5 bytes)
*/
#define DIBUSB_REQ_POLL_REMOTE 0x04
/* additional status values for Hauppauge Remote Control Protocol */
#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01
#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03
/* streaming mode:
* bulk write: 0x05 mode_byte
*
* mode_byte is mostly 0x00
*/
#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
/* interrupt the internal read loop, when blocking */
#define DIBUSB_REQ_INTR_READ 0x06
/* io control
* 0x07 cmd_byte param_bytes
*
* param_bytes can be up to 32 bytes
*
* cmd_byte function parameter name
* 0x00 power mode
* 0x00 sleep
* 0x01 wakeup
*
* 0x01 enable streaming
* 0x02 disable streaming
*
*
*/
#define DIBUSB_REQ_SET_IOCTL 0x07
/* IOCTL commands */
/* change the power mode in firmware */
#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00
#define DIBUSB_IOCTL_POWER_SLEEP 0x00
#define DIBUSB_IOCTL_POWER_WAKEUP 0x01
/* modify streaming of the FX2 */
#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02
struct dibusb_state {
struct dib_fe_xfer_ops ops;
/* for RC5 remote control */
int old_toggle;
int last_repeat_count;
};
extern struct i2c_algorithm dibusb_i2c_algo;
extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *);
extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *);
extern int dibusb_streaming_ctrl(struct dvb_usb_device *, int);
extern int dibusb_pid_filter(struct dvb_usb_device *, int, u16, int);
extern int dibusb_pid_filter_ctrl(struct dvb_usb_device *, int);
extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
extern int dibusb2_0_streaming_ctrl(struct dvb_usb_device *, int);
extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
#define DEFAULT_RC_INTERVAL 150
//#define DEFAULT_RC_INTERVAL 100000
extern struct dvb_usb_rc_key dibusb_rc_keys[];
extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
#endif
/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
* receiver
*
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) and
* Allan Third (allan.third@cs.man.ac.uk)
*
* partly based on the SDK published by Nebula Electronics (TODO do we want this line ?)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "digitv.h"
#include "mt352.h"
#include "nxt6000.h"
/* debug */
int dvb_usb_digitv_debug;
module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
static int digitv_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
int wo = (rbuf == NULL || rlen == 0); /* write-only */
u8 sndbuf[7],rcvbuf[7];
memset(sndbuf,0,7); memset(rcvbuf,0,7);
sndbuf[0] = cmd;
sndbuf[1] = vv;
sndbuf[2] = wo ? wlen : rlen;
if (!wo) {
memcpy(&sndbuf[3],wbuf,wlen);
dvb_usb_generic_write(d,sndbuf,7);
} else {
dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
memcpy(&rbuf,&rcvbuf[3],rlen);
}
return 0;
}
/* I2C */
static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
if (down_interruptible(&d->i2c_sem) < 0)
return -EAGAIN;
if (num > 2)
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
for (i = 0; i < num; i++) {
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
msg[i+1].buf,msg[i+1].len) < 0)
break;
i++;
} else
if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
&msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
break;
}
up(&d->i2c_sem);
return i;
}
static u32 digitv_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
static struct i2c_algorithm digitv_i2c_algo = {
.name = "Nebula DigiTV USB I2C algorithm",
.id = I2C_ALGO_BIT,
.master_xfer = digitv_i2c_xfer,
.functionality = digitv_i2c_func,
};
/* Callbacks for DVB USB */
static int digitv_identify_state (struct usb_device *udev, struct
dvb_usb_properties *props, struct dvb_usb_device_description **desc,
int *cold)
{
*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
return 0;
}
static int digitv_mt352_demod_init(struct dvb_frontend *fe)
{
static u8 mt352_clock_config[] = { 0x89, 0x38, 0x2d };
static u8 mt352_reset[] = { 0x50, 0x80 };
static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
static u8 mt352_agc_cfg[] = { 0x68, 0xa0 };
static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0xa0 };
static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
static u8 mt352_agc_target[] = { 0x67, 0x20 };
static u8 mt352_rs_err_per[] = { 0x7c, 0x00, 0x01 };
static u8 mt352_snr_select[] = { 0x79, 0x00, 0x20 };
static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x05 };
static u8 mt352_scan_ctl[] = { 0x88, 0x0f };
static u8 mt352_capt_range[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
msleep(1);
mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
mt352_write(fe, mt352_agc_target, sizeof(mt352_agc_target));
mt352_write(fe, mt352_rs_err_per, sizeof(mt352_rs_err_per));
mt352_write(fe, mt352_snr_select, sizeof(mt352_snr_select));
mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
mt352_write(fe, mt352_scan_ctl, sizeof(mt352_scan_ctl));
mt352_write(fe, mt352_capt_range, sizeof(mt352_capt_range));
return 0;
}
static struct mt352_config digitv_mt352_config = {
.demod_address = 0x0, /* ignored by the digitv anyway */
.demod_init = digitv_mt352_demod_init,
.pll_set = NULL, /* TODO */
};
static struct nxt6000_config digitv_nxt6000_config = {
.demod_address = 0x0, /* ignored by the digitv anyway */
.clock_inversion = 0x0,
.pll_init = NULL,
.pll_set = NULL,
};
static int digitv_frontend_attach(struct dvb_usb_device *d)
{
if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) == NULL)
return 0;
if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) == NULL) {
warn("nxt6000 support is not done yet, in fact you are one of the first "
"person who wants to use this device in Linux. Please report to "
"linux-dvb@linuxtv.org");
return 0;
}
return -EIO;
}
static struct dvb_usb_rc_key digitv_rc_keys[] = {
{ 0x00, 0x16, KEY_POWER }, /* dummy key */
};
/* TODO is it really the NEC protocol ? */
int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[5];
digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
/* TODO state, maybe it is VV ? */
if (key[1] != 0)
key[0] = 0x01; /* if something is inside the buffer, simulate key press */
/* call the universal NEC remote processor, to find out the key's state and event */
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
}
/* DVB USB Driver stuff */
static struct dvb_usb_properties digitv_properties;
static int digitv_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE);
}
static struct usb_device_id digitv_table [] = {
{ USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, digitv_table);
static struct dvb_usb_properties digitv_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-digitv-01.fw",
.size_of_priv = 0,
.streaming_ctrl = NULL,
.pid_filter = NULL,
.pid_filter_ctrl = NULL,
.power_ctrl = NULL,
.frontend_attach = digitv_frontend_attach,
.tuner_attach = NULL, // digitv_tuner_attach,
.read_mac_address = NULL,
.rc_interval = 1000,
.rc_key_map = digitv_rc_keys,
.rc_key_map_size = ARRAY_SIZE(digitv_rc_keys),
.rc_query = digitv_rc_query,
.identify_state = digitv_identify_state,
.i2c_algo = &digitv_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 2,
.devices = {
{ "Nebula Electronics uDigiTV DVB-T USB2.0)",
{ &digitv_table[0], NULL },
{ NULL },
},
}
};
static struct usb_driver digitv_driver = {
.owner = THIS_MODULE,
.name = "Nebula Electronics uDigiTV DVB-T USB2.0 device",
.probe = digitv_probe,
.disconnect = dvb_usb_device_exit,
.id_table = digitv_table,
};
/* module stuff */
static int __init digitv_module_init(void)
{
int result;
if ((result = usb_register(&digitv_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void __exit digitv_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&digitv_driver);
}
module_init (digitv_module_init);
module_exit (digitv_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
MODULE_VERSION("1.0-alpha");
MODULE_LICENSE("GPL");
#ifndef _DVB_USB_DIGITV_H_
#define _DVB_USB_DIGITV_H_
#define DVB_USB_LOG_PREFIX "digitv"
#include "dvb-usb.h"
extern int dvb_usb_digitv_debug;
#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
/* protocol (from usblogging and the SDK:
*
* Always 7 bytes bulk message(s) for controlling
*
* First byte describes the command. Reads are 2 consecutive transfer (as always).
*
* General structure:
*
* write or first message of a read:
* <cmdbyte> VV <len> B0 B1 B2 B3
*
* second message of a read
* <cmdbyte> VV <len> R0 R1 R2 R3
*
* whereas 0 < len <= 4
*
* I2C address is stored somewhere inside the device.
*
* 0x01 read from EEPROM
* VV = offset; B* = 0; R* = value(s)
*
* 0x02 read register of the COFDM
* VV = register; B* = 0; R* = value(s)
*
* 0x05 write register of the COFDM
* VV = register; B* = value(s);
*
* 0x06 write to the tuner (only for NXT6000)
* VV = 0; B* = PLL data; len = 4;
*
* 0x03 read remote control
* VV = 0; B* = 0; len = 4; R* = key
*
* 0x07 write to the remote (don't know why one should this, resetting ?)
* VV = 0; B* = key; len = 4;
*
* 0x08 write remote type
* VV = 0; B[0] = 0x01, len = 4
*
* 0x09 write device init
* TODO
*/
#define USB_READ_EEPROM 1
#define USB_READ_COFDM 2
#define USB_WRITE_COFDM 5
#define USB_WRITE_TUNER 6
#define USB_READ_REMOTE 3
#define USB_WRITE_REMOTE 7
#define USB_WRITE_REMOTE_TYPE 8
#define USB_DEV_INIT 9
#endif
/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T
* USB2.0 receiver.
*
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dtt200u.h"
struct dtt200u_fe_state {
struct dvb_usb_device *d;
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
};
#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw = GET_TUNE_STAT;
u8 br[3] = { 0 };
// u8 bdeb[5] = { 0 };
dvb_usb_generic_rw(state->d,&bw,1,br,3,0);
switch (br[0]) {
case 0x01:
*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
break;
case 0x00:
*stat = 0;
break;
default:
moan("br[0]",GET_TUNE_STAT);
break;
}
// bw[0] = 0x88;
// dvb_usb_generic_rw(state->d,bw,1,bdeb,5,0);
// deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
return 0;
}
static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw = GET_BER;
*ber = 0;
dvb_usb_generic_rw(state->d,&bw,1,(u8*) ber,3,0);
return 0;
}
static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw = GET_UNK;
*unc = 0;
dvb_usb_generic_rw(state->d,&bw,1,(u8*) unc,3,0);
return 0;
}
static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw = GET_SIG_STRENGTH, b;
dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
*strength = (b << 8) | b;
return 0;
}
static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw = GET_SNR,br;
dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
*snr = ~((br << 8) | br);
return 0;
}
static int dtt200u_fe_init(struct dvb_frontend* fe)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 b = RESET_DEMOD;
return dvb_usb_generic_write(state->d,&b,1);
}
static int dtt200u_fe_sleep(struct dvb_frontend* fe)
{
return dtt200u_fe_init(fe);
}
static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1500;
tune->step_size = 166667;
tune->max_drift = 166667 * 2;
return 0;
}
static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u16 freq = fep->frequency / 250000;
u8 bw,bwbuf[2] = { SET_BANDWIDTH, 0 }, freqbuf[3] = { SET_FREQUENCY, 0, 0 };
switch (fep->u.ofdm.bandwidth) {
case BANDWIDTH_8_MHZ: bw = 8; break;
case BANDWIDTH_7_MHZ: bw = 7; break;
case BANDWIDTH_6_MHZ: bw = 6; break;
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
default:
return -EINVAL;
}
deb_info("set_frontend\n");
bwbuf[1] = bw;
dvb_usb_generic_write(state->d,bwbuf,2);
freqbuf[1] = freq & 0xff;
freqbuf[2] = (freq >> 8) & 0xff;
dvb_usb_generic_write(state->d,freqbuf,3);
memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
return 0;
}
static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
return 0;
}
static void dtt200u_fe_release(struct dvb_frontend* fe)
{
struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops dtt200u_fe_ops;
struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
{
struct dtt200u_fe_state* state = NULL;
/* allocate memory for the internal state */
state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
if (state == NULL)
goto error;
memset(state,0,sizeof(struct dtt200u_fe_state));
deb_info("attaching frontend dtt200u\n");
state->d = d;
state->frontend.ops = &dtt200u_fe_ops;
state->frontend.demodulator_priv = state;
goto success;
error:
return NULL;
success:
return &state->frontend;
}
static struct dvb_frontend_ops dtt200u_fe_ops = {
.info = {
.name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 250000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_RECOVER |
FE_CAN_HIERARCHY_AUTO,
},
.release = dtt200u_fe_release,
.init = dtt200u_fe_init,
.sleep = dtt200u_fe_sleep,
.set_frontend = dtt200u_fe_set_frontend,
.get_frontend = dtt200u_fe_get_frontend,
.get_tune_settings = dtt200u_fe_get_tune_settings,
.read_status = dtt200u_fe_read_status,
.read_ber = dtt200u_fe_read_ber,
.read_signal_strength = dtt200u_fe_read_signal_strength,
.read_snr = dtt200u_fe_read_snr,
.read_ucblocks = dtt200u_fe_read_unc_blocks,
};
/* DVB USB library compliant Linux driver for the Yakumo/Hama/Typhoon DVB-T
* USB2.0 receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dtt200u.h"
/* debug */
int dvb_usb_dtt200u_debug;
module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 b_streaming[2] = { SET_TS_CTRL, onoff };
u8 b_rst_pid = RESET_PID_FILTER;
dvb_usb_generic_write(d,b_streaming,2);
if (!onoff)
dvb_usb_generic_write(d,&b_rst_pid,1);
return 0;
}
static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
{
u8 b_pid[4];
pid = onoff ? pid : 0;
b_pid[0] = SET_PID_FILTER;
b_pid[1] = index;
b_pid[2] = pid & 0xff;
b_pid[3] = (pid >> 8) & 0xff;
return dvb_usb_generic_write(d,b_pid,4);
}
/* remote control */
/* key list for the tiny remote control (Yakumo, don't know about the others) */
static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
{ 0x80, 0x01, KEY_MUTE },
{ 0x80, 0x02, KEY_CHANNELDOWN },
{ 0x80, 0x03, KEY_VOLUMEDOWN },
{ 0x80, 0x04, KEY_1 },
{ 0x80, 0x05, KEY_2 },
{ 0x80, 0x06, KEY_3 },
{ 0x80, 0x07, KEY_4 },
{ 0x80, 0x08, KEY_5 },
{ 0x80, 0x09, KEY_6 },
{ 0x80, 0x0a, KEY_7 },
{ 0x00, 0x0c, KEY_ZOOM },
{ 0x80, 0x0d, KEY_0 },
{ 0x00, 0x0e, KEY_SELECT },
{ 0x80, 0x12, KEY_POWER },
{ 0x80, 0x1a, KEY_CHANNELUP },
{ 0x80, 0x1b, KEY_8 },
{ 0x80, 0x1e, KEY_VOLUMEUP },
{ 0x80, 0x1f, KEY_9 },
};
static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[5],cmd = GET_RC_KEY;
dvb_usb_generic_rw(d,&cmd,1,key,5,0);
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
}
static int dtt200u_frontend_attach(struct dvb_usb_device *d)
{
d->fe = dtt200u_fe_attach(d);
return 0;
}
static struct dvb_usb_properties dtt200u_properties;
static int dtt200u_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE);
}
static struct usb_device_id dtt200u_usb_table [] = {
{ USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_COLD) },
{ USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_WARM) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
static struct dvb_usb_properties dtt200u_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
.pid_filter_count = 255, /* It is a guess, but there are at least 10 */
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-dtt200u-01.fw",
.streaming_ctrl = dtt200u_streaming_ctrl,
.pid_filter = dtt200u_pid_filter,
.frontend_attach = dtt200u_frontend_attach,
.rc_interval = 200,
.rc_key_map = dtt200u_rc_keys,
.rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
.rc_query = dtt200u_rc_query,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 1,
.devices = {
{ .name = "Yakumo/Hama/Typhoon DVB-T USB2.0)",
.cold_ids = { &dtt200u_usb_table[0], &dtt200u_usb_table[2] },
.warm_ids = { &dtt200u_usb_table[1], NULL },
},
{ 0 },
}
};
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver dtt200u_usb_driver = {
.owner = THIS_MODULE,
.name = "Yakumo/Hama/Typhoon DVB-T USB2.0",
.probe = dtt200u_usb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = dtt200u_usb_table,
};
/* module stuff */
static int __init dtt200u_usb_module_init(void)
{
int result;
if ((result = usb_register(&dtt200u_usb_driver))) {
err("usb_register failed. (%d)",result);
return result;
}
return 0;
}
static void __exit dtt200u_usb_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&dtt200u_usb_driver);
}
module_init(dtt200u_usb_module_init);
module_exit(dtt200u_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* Common header file of Linux driver for the Yakumo/Hama/Typhoon DVB-T
* USB2.0 receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#ifndef _DVB_USB_DTT200U_H_
#define _DVB_USB_DTT200U_H_
#define DVB_USB_LOG_PREFIX "dtt200u"
#include "dvb-usb.h"
extern int dvb_usb_dtt200u_debug;
#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args)
#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args)
/* guessed protocol description (reverse engineered):
* read
* 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
* 81 - <TS_LOCK> <current frequency divided by 250000>
* 82 - crash - do not touch
* 83 - crash - do not touch
* 84 - remote control
* 85 - crash - do not touch (OK, stop testing here)
* 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
* 89 - noise-to-signal
* 8a - unkown 1 byte - signal_strength
* 8c - ber ???
* 8d - ber
* 8e - unc
*/
#define GET_SPEED 0x00
#define GET_TUNE_STAT 0x81
#define GET_RC_KEY 0x84
#define GET_STATUS 0x88
#define GET_SNR 0x89
#define GET_SIG_STRENGTH 0x8a
#define GET_UNK 0x8c
#define GET_BER 0x8d
#define GET_UNC 0x8e
/* write
* 01 - reset the demod
* 02 - frequency (divided by 250000)
* 03 - bandwidth
* 04 - pid table (index pid(7:0) pid(12:8))
* 05 - reset the pid table
* 08 - demod transfer enabled or not (FX2 transfer is enabled by default)
*/
#define RESET_DEMOD 0x01
#define SET_FREQUENCY 0x02
#define SET_BANDWIDTH 0x03
#define SET_PID_FILTER 0x04
#define RESET_PID_FILTER 0x05
#define SET_TS_CTRL 0x08
extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
#endif
/* dvb-usb-common.h is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* a header file containing prototypes and types for internal use of the dvb-usb-lib
*/
#ifndef _DVB_USB_COMMON_H_
#define _DVB_USB_COMMON_H_
#define DVB_USB_LOG_PREFIX "dvb-usb"
#include "dvb-usb.h"
extern int dvb_usb_debug;
#define deb_info(args...) dprintk(dvb_usb_debug,0x01,args)
#define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args)
#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
#define deb_ts(args...) dprintk(dvb_usb_debug,0x08,args)
#define deb_err(args...) dprintk(dvb_usb_debug,0x10,args)
#define deb_rc(args...) dprintk(dvb_usb_debug,0x20,args)
#define deb_fw(args...) dprintk(dvb_usb_debug,0x40,args)
/* commonly used methods */
extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
extern int dvb_usb_urb_submit(struct dvb_usb_device *);
extern int dvb_usb_urb_kill(struct dvb_usb_device *);
extern int dvb_usb_urb_init(struct dvb_usb_device *);
extern int dvb_usb_urb_exit(struct dvb_usb_device *);
extern int dvb_usb_i2c_init(struct dvb_usb_device *);
extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
extern int dvb_usb_dvb_init(struct dvb_usb_device *);
extern int dvb_usb_dvb_exit(struct dvb_usb_device *);
extern int dvb_usb_fe_init(struct dvb_usb_device *);
extern int dvb_usb_fe_exit(struct dvb_usb_device *);
extern int dvb_usb_remote_init(struct dvb_usb_device *);
extern int dvb_usb_remote_exit(struct dvb_usb_device *);
#endif
/* dvb-usb-dvb.c is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for initializing and handling the
* linux-dvb API.
*/
#include "dvb-usb-common.h"
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
{
struct dvb_usb_device *d = dvbdmxfeed->demux->priv;
int newfeedcount,ret;
if (d == NULL)
return -ENODEV;
newfeedcount = d->feedcount + (onoff ? 1 : -1);
/*
* stop feed before setting a new pid if there will be no pid anymore
*/
if (newfeedcount == 0) {
deb_ts("stop feeding\n");
if (d->props.streaming_ctrl != NULL)
if ((ret = d->props.streaming_ctrl(d,0)))
err("error while stopping stream.");
dvb_usb_urb_kill(d);
}
d->feedcount = newfeedcount;
/* activate the pid on the device specific pid_filter */
deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
d->pid_filtering &&
d->props.pid_filter != NULL)
d->props.pid_filter(d,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
/* start the feed if this was the first feed and there is still a feed
* for reception.
*/
if (d->feedcount == onoff && d->feedcount > 0) {
deb_ts("controlling pid parser\n");
if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
d->props.caps & DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF &&
d->props.pid_filter_ctrl != NULL)
if (d->props.pid_filter_ctrl(d,d->pid_filtering) < 0)
err("could not handle pid_parser");
deb_ts("start feeding\n");
if (d->props.streaming_ctrl != NULL)
if (d->props.streaming_ctrl(d,1)) {
err("error while enabling fifo.");
return -ENODEV;
}
dvb_usb_urb_submit(d);
}
return 0;
}
static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
return dvb_usb_ctrl_feed(dvbdmxfeed,1);
}
static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
return dvb_usb_ctrl_feed(dvbdmxfeed,0);
}
int dvb_usb_dvb_init(struct dvb_usb_device *d)
{
int ret;
if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
d->owner)) < 0) {
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
d->dvb_adap.priv = d;
if (d->props.read_mac_address) {
if (d->props.read_mac_address(d,d->dvb_adap.proposed_mac) == 0)
info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",d->dvb_adap.proposed_mac[0],
d->dvb_adap.proposed_mac[1],d->dvb_adap.proposed_mac[2],
d->dvb_adap.proposed_mac[3],d->dvb_adap.proposed_mac[4],
d->dvb_adap.proposed_mac[5]);
else
err("MAC address reading failed.");
}
d->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
d->demux.priv = d;
d->demux.feednum = d->demux.filternum = d->max_feed_count;
d->demux.start_feed = dvb_usb_start_feed;
d->demux.stop_feed = dvb_usb_stop_feed;
d->demux.write_to_decoder = NULL;
if ((ret = dvb_dmx_init(&d->demux)) < 0) {
err("dvb_dmx_init failed: error %d",ret);
goto err_dmx;
}
d->dmxdev.filternum = d->demux.filternum;
d->dmxdev.demux = &d->demux.dmx;
d->dmxdev.capabilities = 0;
if ((ret = dvb_dmxdev_init(&d->dmxdev, &d->dvb_adap)) < 0) {
err("dvb_dmxdev_init failed: error %d",ret);
goto err_dmx_dev;
}
dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
goto success;
err_dmx_dev:
dvb_dmx_release(&d->demux);
err_dmx:
dvb_unregister_adapter(&d->dvb_adap);
err:
return ret;
success:
d->state |= DVB_USB_STATE_DVB;
return 0;
}
int dvb_usb_dvb_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_DVB) {
deb_info("unregistering DVB part\n");
dvb_net_release(&d->dvb_net);
d->demux.dmx.close(&d->demux.dmx);
dvb_dmxdev_release(&d->dmxdev);
dvb_dmx_release(&d->demux);
dvb_unregister_adapter(&d->dvb_adap);
d->state &= ~DVB_USB_STATE_DVB;
}
return 0;
}
static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
{
struct dvb_usb_device *d = fe->dvb->priv;
if (d->props.power_ctrl)
d->props.power_ctrl(d,1);
if (d->fe_init)
d->fe_init(fe);
return 0;
}
static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
{
struct dvb_usb_device *d = fe->dvb->priv;
if (d->fe_sleep)
d->fe_sleep(fe);
if (d->props.power_ctrl)
d->props.power_ctrl(d,0);
return 0;
}
int dvb_usb_fe_init(struct dvb_usb_device* d)
{
if (d->props.frontend_attach == NULL) {
err("strange '%s' don't want to attach a frontend.",d->desc->name);
return 0;
}
d->props.frontend_attach(d);
/* re-assign sleep and wakeup functions */
if (d->fe != NULL) {
d->fe_init = d->fe->ops->init; d->fe->ops->init = dvb_usb_fe_wakeup;
d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
err("Frontend registration failed.");
if (d->fe->ops->release)
d->fe->ops->release(d->fe);
d->fe = NULL;
return -ENODEV;
}
} else
err("no frontend was attached by '%s'",d->desc->name);
if (d->props.tuner_attach != NULL)
d->props.tuner_attach(d);
return 0;
}
int dvb_usb_fe_exit(struct dvb_usb_device *d)
{
if (d->fe != NULL)
dvb_unregister_frontend(d->fe);
return 0;
}
/* dvb-usb-firmware.c is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
*
* FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
*/
#include "dvb-usb-common.h"
#include <linux/firmware.h>
#include <linux/usb.h>
struct usb_cypress_controller {
int id;
const char *name; /* name of the usb controller */
u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */
};
static struct usb_cypress_controller cypress[] = {
{ .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
{ .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
{ .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
};
/*
* load a firmware packet to the device
*/
static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
{
return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
}
int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
{
const struct firmware *fw = NULL;
u16 addr;
u8 *b,*p;
int ret = 0,i;
if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
err("did not find the firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
filename);
return ret;
}
info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
p = kmalloc(fw->size,GFP_KERNEL);
if (p != NULL) {
u8 reset;
/*
* you cannot use the fw->data as buffer for
* usb_control_msg, a new buffer has to be
* created
*/
memcpy(p,fw->data,fw->size);
/* stop the CPU */
reset = 1;
if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
err("could not stop the USB controller CPU.");
for(i = 0; p[i+3] == 0 && i < fw->size; ) {
b = (u8 *) &p[i];
addr = cpu_to_le16( *((u16 *) &b[1]) );
deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
if (ret != b[0]) {
err("error while transferring firmware "
"(transferred size: %d, block size: %d)",
ret,b[0]);
ret = -EINVAL;
break;
}
i += 5 + b[0];
}
/* length in ret */
if (ret > 0)
ret = 0;
/* restart the CPU */
reset = 0;
if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
err("could not restart the USB controller CPU.");
ret = -EINVAL;
}
kfree(p);
} else {
ret = -ENOMEM;
}
release_firmware(fw);
return ret;
}
/* dvb-usb-i2c.c is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for (de-)initializing an I2C adapter.
*/
#include "dvb-usb-common.h"
int dvb_usb_i2c_init(struct dvb_usb_device *d)
{
int ret = 0;
if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
return 0;
if (d->props.i2c_algo == NULL) {
err("no i2c algorithm specified");
return -EINVAL;
}
strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
#else
d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
#endif
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
d->i2c_adap.id = I2C_ALGO_BIT;
i2c_set_adapdata(&d->i2c_adap, d);
if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
err("could not add i2c adapter");
d->state |= DVB_USB_STATE_I2C;
return ret;
}
int dvb_usb_i2c_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_I2C)
i2c_del_adapter(&d->i2c_adap);
d->state &= ~DVB_USB_STATE_I2C;
return 0;
}
int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
{
struct dvb_usb_device *d = fe->dvb->priv;
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
int ret = 0;
/* if there is nothing to initialize */
if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
return 0;
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,1,d->pll_addr);
deb_pll("pll init: %x\n",d->pll_addr);
deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
d->pll_init[2],d->pll_init[3]);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_init.");
ret = -EREMOTEIO;
}
msleep(1);
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,0,d->pll_addr);
return ret;
}
EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
{
struct dvb_usb_device *d = fe->dvb->priv;
deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
b[0] = d->pll_addr << 1;
dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
return 0;
}
EXPORT_SYMBOL(dvb_usb_pll_set);
int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
int ret = 0;
u8 b[5];
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
dvb_usb_pll_set(fe,fep,b);
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,1,d->pll_addr);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_set.");
ret = -EREMOTEIO;
}
msleep(1);
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,0,d->pll_addr);
return ret;
}
EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
/* dvb-usb-ids.h is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
* dvb-usb-init.c for copyright information.
*
* a header file containing define's for the USB device supported by the
* various drivers.
*/
#ifndef _DVB_USB_IDS_H_
#define _DVB_USB_IDS_H_
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA_UNK 0x14aa
#define USB_VID_AVERMEDIA 0x07ca
#define USB_VID_COMPRO 0x185b
#define USB_VID_COMPRO_UNK 0x145f
#define USB_VID_CYPRESS 0x04b4
#define USB_VID_DIBCOM 0x10b8
#define USB_VID_DVICO 0x0fe9
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GRANDTEC 0x5032
#define USB_VID_HANFTEK 0x15f4
#define USB_VID_HAUPPAUGE 0x2040
#define USB_VID_HYPER_PALTEK 0x1025
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
#define USB_PID_ADSTECH_USB2_WARM 0xa334
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801
#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7045_COLD 0x3205
#define USB_PID_TWINHAN_VP7045_WARM 0x3206
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
#define USB_PID_TWINHAN_VP7021_COLD 0x3207
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
#define USB_PID_DTT200U_COLD 0x0201
#define USB_PID_DTT200U_WARM 0x0301
#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGZ201 0xdb00
#define USB_PID_DVICO_BLUEBIRD_TH7579 0xdb10
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01
#define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11
#endif
/*
* DVB USB library - provides a generic interface for a DVB USB device driver.
*
* dvb-usb-init.c
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dvb-usb-common.h"
/* debug */
int dvb_usb_debug;
module_param_named(debug,dvb_usb_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
/* general initialization functions */
int dvb_usb_exit(struct dvb_usb_device *d)
{
deb_info("state before exiting everything: %x\n",d->state);
dvb_usb_remote_exit(d);
dvb_usb_fe_exit(d);
dvb_usb_i2c_exit(d);
dvb_usb_dvb_exit(d);
dvb_usb_urb_exit(d);
deb_info("state should be zero now: %x\n",d->state);
d->state = DVB_USB_STATE_INIT;
kfree(d->priv);
kfree(d);
return 0;
}
static int dvb_usb_init(struct dvb_usb_device *d)
{
int ret = 0;
sema_init(&d->usb_sem, 1);
sema_init(&d->i2c_sem, 1);
d->state = DVB_USB_STATE_INIT;
/* check the capabilites and set appropriate variables */
/* speed - when running at FULL speed we need a HW PID filter */
if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) {
err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a HW PID filter)");
return -ENODEV;
}
if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) ||
(d->props.caps & DVB_USB_NEED_PID_FILTERING)) {
info("will use the device's hw PID filter.");
d->pid_filtering = 1;
d->max_feed_count = d->props.pid_filter_count;
} else {
info("will pass the complete MPEG2 transport stream to the demuxer.");
d->pid_filtering = 0;
d->max_feed_count = 255;
}
if (d->props.power_ctrl)
d->props.power_ctrl(d,1);
if ((ret = dvb_usb_urb_init(d)) ||
(ret = dvb_usb_dvb_init(d)) ||
(ret = dvb_usb_i2c_init(d)) ||
(ret = dvb_usb_fe_init(d))) {
dvb_usb_exit(d);
return ret;
}
if ((ret = dvb_usb_remote_init(d)))
err("could not initialize remote control.");
if (d->props.power_ctrl)
d->props.power_ctrl(d,0);
return 0;
}
/* determine the name and the state of the just found USB device */
static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold)
{
int i,j;
struct dvb_usb_device_description *desc = NULL;
*cold = -1;
for (i = 0; i < props->num_device_descs; i++) {
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 1;
desc = &props->devices[i];
break;
}
}
if (desc != NULL)
break;
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 0;
desc = &props->devices[i];
break;
}
}
}
if (desc != NULL && props->identify_state != NULL)
props->identify_state(udev,props,&desc,cold);
return desc;
}
/*
* USB
*/
int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *props, struct module *owner)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct dvb_usb_device *d = NULL;
struct dvb_usb_device_description *desc = NULL;
int ret = -ENOMEM,cold=0;
if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
return -ENODEV;
}
if (cold) {
info("found a '%s' in cold state, will try to load a firmware",desc->name);
ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
} else {
info("found a '%s' in warm state.",desc->name);
d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
if (d == NULL) {
err("no memory for 'struct dvb_usb_device'");
return ret;
}
memset(d,0,sizeof(struct dvb_usb_device));
d->udev = udev;
memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
d->desc = desc;
d->owner = owner;
if (d->props.size_of_priv > 0) {
d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
if (d->priv == NULL) {
err("no memory for priv in 'struct dvb_usb_device'");
kfree(d);
return -ENOMEM;
}
memset(d->priv,0,d->props.size_of_priv);
}
usb_set_intfdata(intf, d);
ret = dvb_usb_init(d);
}
if (ret == 0)
info("%s successfully initialized and connected.",desc->name);
else
info("%s error while loading driver (%d)",desc->name,ret);
return ret;
}
EXPORT_SYMBOL(dvb_usb_device_init);
void dvb_usb_device_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
const char *name = "generic DVB-USB module";
usb_set_intfdata(intf,NULL);
if (d != NULL && d->desc != NULL) {
name = d->desc->name;
dvb_usb_exit(d);
}
info("%s successfully deinitialized and disconnected.",name);
}
EXPORT_SYMBOL(dvb_usb_device_exit);
/* module stuff */
static int __init dvb_usb_module_init(void)
{
return 0;
}
static void __exit dvb_usb_module_exit(void)
{
}
module_init (dvb_usb_module_init);
module_exit (dvb_usb_module_exit);
MODULE_VERSION("0.3");
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
MODULE_LICENSE("GPL");
/* dvb-usb-remote.c is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for initializing the the input-device and for handling remote-control-queries.
*/
#include "dvb-usb-common.h"
/* Remote-control poll function - called every dib->rc_query_interval ms to see
* whether the remote control has received anything.
*
* TODO: Fix the repeat rate of the input device.
*/
static void dvb_usb_read_remote_control(void *data)
{
struct dvb_usb_device *d = data;
u32 event;
int state;
/* TODO: need a lock here. We can simply skip checking for the remote control
if we're busy. */
if (d->props.rc_query(d,&event,&state)) {
err("error while querying for an remote control event.");
goto schedule;
}
switch (state) {
case REMOTE_NO_KEY_PRESSED:
break;
case REMOTE_KEY_PRESSED:
deb_rc("key pressed\n");
d->last_event = event;
case REMOTE_KEY_REPEAT:
deb_rc("key repeated\n");
input_event(&d->rc_input_dev, EV_KEY, event, 1);
input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
input_sync(&d->rc_input_dev);
break;
default:
break;
}
/* improved repeat handling ???
switch (state) {
case REMOTE_NO_KEY_PRESSED:
deb_rc("NO KEY PRESSED\n");
if (d->last_state != REMOTE_NO_KEY_PRESSED) {
deb_rc("releasing event %d\n",d->last_event);
input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
input_sync(&d->rc_input_dev);
}
d->last_state = REMOTE_NO_KEY_PRESSED;
d->last_event = 0;
break;
case REMOTE_KEY_PRESSED:
deb_rc("KEY PRESSED\n");
deb_rc("pressing event %d\n",event);
input_event(&d->rc_input_dev, EV_KEY, event, 1);
input_sync(&d->rc_input_dev);
d->last_event = event;
d->last_state = REMOTE_KEY_PRESSED;
break;
case REMOTE_KEY_REPEAT:
deb_rc("KEY_REPEAT\n");
if (d->last_state != REMOTE_NO_KEY_PRESSED) {
deb_rc("repeating event %d\n",d->last_event);
input_event(&d->rc_input_dev, EV_KEY, d->last_event, 2);
input_sync(&d->rc_input_dev);
d->last_state = REMOTE_KEY_REPEAT;
}
default:
break;
}
*/
schedule:
schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
}
int dvb_usb_remote_init(struct dvb_usb_device *d)
{
int i;
if (d->props.rc_key_map == NULL)
return 0;
/* Initialise the remote-control structures.*/
init_input_dev(&d->rc_input_dev);
d->rc_input_dev.evbit[0] = BIT(EV_KEY);
d->rc_input_dev.keycodesize = sizeof(unsigned char);
d->rc_input_dev.keycodemax = KEY_MAX;
d->rc_input_dev.name = "IR-receiver inside an USB DVB receiver";
/* set the bits for the keys */
deb_rc("key map size: %d\n",d->props.rc_key_map_size);
for (i = 0; i < d->props.rc_key_map_size; i++) {
deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i);
set_bit(d->props.rc_key_map[i].event, d->rc_input_dev.keybit);
}
/* Start the remote-control polling. */
if (d->props.rc_interval < 40)
d->props.rc_interval = 100; /* default */
/* setting these two values to non-zero, we have to manage key repeats */
d->rc_input_dev.rep[REP_PERIOD] = d->props.rc_interval;
d->rc_input_dev.rep[REP_DELAY] = d->props.rc_interval + 150;
input_register_device(&d->rc_input_dev);
INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d);
info("schedule remote query interval to %d msecs.",d->props.rc_interval);
schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
d->state |= DVB_USB_STATE_REMOTE;
return 0;
}
int dvb_usb_remote_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_REMOTE) {
cancel_delayed_work(&d->rc_query_work);
flush_scheduled_work();
input_unregister_device(&d->rc_input_dev);
}
d->state &= ~DVB_USB_STATE_REMOTE;
return 0;
}
#define DVB_USB_RC_NEC_EMPTY 0x00
#define DVB_USB_RC_NEC_KEY_PRESSED 0x01
#define DVB_USB_RC_NEC_KEY_REPEATED 0x02
int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
u8 keybuf[5], u32 *event, int *state)
{
int i;
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
switch (keybuf[0]) {
case DVB_USB_RC_NEC_EMPTY:
break;
case DVB_USB_RC_NEC_KEY_PRESSED:
if ((u8) ~keybuf[1] != keybuf[2] ||
(u8) ~keybuf[3] != keybuf[4]) {
deb_err("remote control checksum failed.\n");
break;
}
/* See if we can match the raw key code. */
for (i = 0; i < sizeof(keymap)/sizeof(struct dvb_usb_rc_key); i++)
if (keymap[i].custom == keybuf[1] &&
keymap[i].data == keybuf[3]) {
*event = keymap[i].event;
*state = REMOTE_KEY_PRESSED;
break;
}
deb_err("key mapping failed - no appropriate key found in keymapping\n");
break;
case DVB_USB_RC_NEC_KEY_REPEATED:
*state = REMOTE_KEY_REPEAT;
break;
default:
deb_err("unkown type of remote status: %d\n",keybuf[0]);
break;
}
return 0;
}
EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
/* dvb-usb-urb.c is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for initializing and handling the
* USB and URB stuff.
*/
#include "dvb-usb-common.h"
int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
u16 rlen, int delay_ms)
{
int actlen,ret = -ENOMEM;
if (d->props.generic_bulk_ctrl_endpoint == 0) {
err("endpoint for generic control not specified.");
return -EINVAL;
}
if (wbuf == NULL || wlen == 0)
return -EINVAL;
if ((ret = down_interruptible(&d->usb_sem)))
return ret;
debug_dump(wbuf,wlen,deb_xfer);
ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
2*HZ);
if (ret)
err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
else
ret = actlen != wlen ? -1 : 0;
/* an answer is expected, and no error before */
if (!ret && rbuf && rlen) {
if (delay_ms)
msleep(delay_ms);
ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
2*HZ);
if (ret)
err("recv bulk message failed: %d",ret);
else
debug_dump(rbuf,actlen,deb_xfer);
}
up(&d->usb_sem);
return ret;
}
EXPORT_SYMBOL(dvb_usb_generic_rw);
int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
{
return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
}
EXPORT_SYMBOL(dvb_usb_generic_write);
static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs)
{
struct dvb_usb_device *d = urb->context;
deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status,
urb->actual_length);
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
break;
case -ECONNRESET: /* kill */
case -ENOENT:
case -ESHUTDOWN:
return;
default: /* error */
deb_ts("urb completition error %d.", urb->status);
break;
}
if (d->feedcount > 0 && urb->actual_length > 0) {
if (d->state & DVB_USB_STATE_DVB)
dvb_dmx_swfilter(&d->demux, (u8*) urb->transfer_buffer,urb->actual_length);
} else
deb_ts("URB dropped because of feedcount.\n");
usb_submit_urb(urb,GFP_ATOMIC);
}
int dvb_usb_urb_kill(struct dvb_usb_device *d)
{
int i;
for (i = 0; i < d->urbs_submitted; i++) {
deb_info("killing URB no. %d.\n",i);
/* stop the URB */
usb_kill_urb(d->urb_list[i]);
}
d->urbs_submitted = 0;
return 0;
}
int dvb_usb_urb_submit(struct dvb_usb_device *d)
{
int i,ret;
for (i = 0; i < d->urbs_initialized; i++) {
deb_info("submitting URB no. %d\n",i);
if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) {
err("could not submit URB no. %d - get them all back\n",i);
dvb_usb_urb_kill(d);
return ret;
}
d->urbs_submitted++;
}
return 0;
}
static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
{
int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize;
deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
/* allocate the actual buffer for the URBs */
if ((d->buffer = usb_buffer_alloc(d->udev, bufsize, SLAB_ATOMIC, &d->dma_handle)) == NULL) {
deb_info("not enough memory for urb-buffer allocation.\n");
return -ENOMEM;
}
deb_info("allocation successful\n");
memset(d->buffer,0,bufsize);
d->state |= DVB_USB_STATE_URB_BUF;
/* allocate the URBs */
for (i = 0; i < d->props.urb.count; i++) {
if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
return -ENOMEM;
}
usb_fill_bulk_urb( d->urb_list[i], d->udev,
usb_rcvbulkpipe(d->udev,d->props.urb.endpoint),
&d->buffer[i*d->props.urb.u.bulk.buffersize],
d->props.urb.u.bulk.buffersize,
dvb_usb_bulk_urb_complete, d);
d->urb_list[i]->transfer_flags = 0;
d->urbs_initialized++;
}
return 0;
}
int dvb_usb_urb_init(struct dvb_usb_device *d)
{
/*
* when reloading the driver w/o replugging the device
* sometimes a timeout occures, this helps
*/
if (d->props.generic_bulk_ctrl_endpoint != 0) {
usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
}
usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint));
/* allocate the array for the data transfer URBs */
d->urb_list = kmalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL);
if (d->urb_list == NULL)
return -ENOMEM;
memset(d->urb_list,0,d->props.urb.count * sizeof(struct urb *));
d->state |= DVB_USB_STATE_URB_LIST;
switch (d->props.urb.type) {
case DVB_USB_BULK:
return dvb_usb_bulk_urb_init(d);
case DVB_USB_ISOC:
err("isochronous transfer not yet implemented in dvb-usb.");
return -EINVAL;
default:
err("unkown URB-type for data transfer.");
return -EINVAL;
}
}
int dvb_usb_urb_exit(struct dvb_usb_device *d)
{
int i;
dvb_usb_urb_kill(d);
if (d->state & DVB_USB_STATE_URB_LIST) {
for (i = 0; i < d->urbs_initialized; i++) {
if (d->urb_list[i] != NULL) {
deb_info("freeing URB no. %d.\n",i);
/* free the URBs */
usb_free_urb(d->urb_list[i]);
}
}
d->urbs_initialized = 0;
/* free the urb array */
kfree(d->urb_list);
d->state &= ~DVB_USB_STATE_URB_LIST;
}
if (d->state & DVB_USB_STATE_URB_BUF)
usb_buffer_free(d->udev, d->props.urb.u.bulk.buffersize * d->props.urb.count,
d->buffer, d->dma_handle);
d->state &= ~DVB_USB_STATE_URB_BUF;
return 0;
}
/* dvb-usb.h is part of the DVB USB library.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* the headerfile, all dvb-usb-drivers have to include.
*/
#ifndef __DVB_USB_H__
#define __DVB_USB_H__
#include <linux/config.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
#include "dvb_net.h"
#include "dmxdev.h"
#include "dvb-pll.h"
#include "dvb-usb-ids.h"
/* debug */
#ifdef CONFIG_DVB_USB_DEBUG
#define dprintk(var,level,args...) \
do { if ((var & level)) { printk(args); } } while (0)
#define debug_dump(b,l,func) {\
int loop_; \
for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
func("\n");\
}
#define DVB_USB_DEBUG_STATUS
#else
#define dprintk(args...)
#define debug_dump(b,l,func)
#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
#endif
/* generic log methods - taken from usb.h */
#ifndef DVB_USB_LOG_PREFIX
#define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
#endif
#undef err
#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
#undef info
#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
#undef warn
#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
/**
* struct dvb_usb_device_description - name and its according USB IDs
* @name: real name of the box, regardless which DVB USB device class is in use
* @cold_ids: array of struct usb_device_id which describe the device in
* pre-firmware state
* @warm_ids: array of struct usb_device_id which describe the device in
* post-firmware state
*
* Each DVB USB device class can have one or more actual devices, this struct
* assigns a name to it.
*/
struct dvb_usb_device_description {
const char *name;
#define DVB_USB_ID_MAX_NUM 15
struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
};
/**
* struct dvb_usb_rc_key - a remote control key and its input-event
* @custom: the vendor/custom part of the key
* @data: the actual key part
* @event: the input event assigned to key identified by custom and data
*/
struct dvb_usb_rc_key {
u8 custom,data;
u32 event;
};
struct dvb_usb_device;
/**
* struct dvb_usb_properties - properties of a dvb-usb-device
* @caps: capabilites of the DVB USB device.
* @pid_filter_count: number of PID filter position in the optional hardware
* PID-filter.
*
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
* download.
* @firmware: name of the firmware file.
*
* @size_of_priv: how many bytes shall be allocated for the private field
* of struct dvb_usb_device.
*
* @power_ctrl: called to enable/disable power of the device.
* @streaming_crtl: called to start and stop the MPEG2-TS streaming of the
* device (not URB submitting/killing).
* @pid_filter_ctrl: called to en/disable the PID filter, if any.
* @pid_filter: called to set/unset a PID for filtering.
*
* @read_mac_address: called to read the MAC address of the device.
*
* @frontend_attach: called to attach the possible frontends (fill fe-field
* of struct dvb_usb_device).
* @tuner_attach: called to attach the correct tuner and to fill pll_addr,
* pll_desc and pll_init_buf of struct dvb_usb_device).
* @identify_state: called to determine the state (cold or warm), when it
* is not distinguishable by the USB IDs.
*
* @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
* remote control handling).
* @rc_key_map_size: number of items in @rc_key_map.
* @rc_query: called to query an event event.
* @rc_interval: time in ms between two queries.
*
* @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
*
* @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
* endpoint which received control messages with bulk transfers. When this
* is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
* helper functions.
*
* @urb: describes the kind of USB transfer used for MPEG2-TS-streaming.
* Currently only BULK is implemented
*
* @num_device_descs: number of struct dvb_usb_device_description in @devices
* @devices: array of struct dvb_usb_device_description compatibles with these
* properties.
*/
struct dvb_usb_properties {
#define DVB_USB_HAS_PID_FILTER 0x01
#define DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF 0x02
#define DVB_USB_NEED_PID_FILTERING 0x04
#define DVB_USB_IS_AN_I2C_ADAPTER 0x08
int caps;
int pid_filter_count;
#define CYPRESS_AN2135 0
#define CYPRESS_AN2235 1
#define CYPRESS_FX2 2
int usb_ctrl;
const char *firmware;
int size_of_priv;
int (*power_ctrl) (struct dvb_usb_device *, int);
int (*streaming_ctrl) (struct dvb_usb_device *, int);
int (*pid_filter_ctrl) (struct dvb_usb_device *, int);
int (*pid_filter) (struct dvb_usb_device *, int, u16, int);
int (*read_mac_address) (struct dvb_usb_device *, u8 []);
int (*frontend_attach) (struct dvb_usb_device *);
int (*tuner_attach) (struct dvb_usb_device *);
int (*identify_state) (struct usb_device *, struct dvb_usb_properties *,
struct dvb_usb_device_description **, int *);
/* remote control properties */
#define REMOTE_NO_KEY_PRESSED 0x00
#define REMOTE_KEY_PRESSED 0x01
#define REMOTE_KEY_REPEAT 0x02
struct dvb_usb_rc_key *rc_key_map;
int rc_key_map_size;
int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
int rc_interval;
struct i2c_algorithm *i2c_algo;
int generic_bulk_ctrl_endpoint;
struct {
#define DVB_USB_BULK 1
#define DVB_USB_ISOC 2
int type;
int count;
int endpoint;
union {
struct {
int buffersize; /* per URB */
} bulk;
struct {
int framesperurb;
int framesize;
} isoc;
} u;
} urb;
int num_device_descs;
struct dvb_usb_device_description devices[8];
};
/**
* struct dvb_usb_device - object of a DVB USB device
* @props: copy of the struct dvb_usb_properties this device belongs to.
* @desc: pointer to the device's struct dvb_usb_device_description.
* @state: initialization and runtime state of the device.
*
* @udev: pointer to the device's struct usb_device.
* @urb_list: array of dynamically allocated struct urb for the MPEG2-TS-
* streaming.
* @buffer: buffer used to streaming.
* @dma_handle: dma_addr_t for buffer.
* @urbs_initialized: number of URBs initialized.
* @urbs_submitted: number of URBs submitted.
* @feedcount: number of reqested feeds (used for streaming-activation)
* @pid_filtering: is hardware pid_filtering used or not.
* @usb_sem: semaphore of USB control messages (reading needs two messages)
* @i2c_sem: semaphore for i2c-transfers
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
* @pll_addr: I2C address of the tuner for programming
* @pll_init: array containing the initialization buffer
* @pll_desc: pointer to the appropriate struct dvb_pll_desc
* @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod
* @dvb_adap: device's dvb_adapter.
* @dmxdev: device's dmxdev.
* @demux: device's software demuxer.
* @dvb_net: device's dvb_net interfaces.
* @dvb_frontend: device's frontend.
* @max_feed_count: how many feeds can be handled simultaneously by this
* device
* @fe_sleep: rerouted frontend-sleep function.
* @fe_init: rerouted frontend-init (wakeup) function.
* @rc_input_dev: input device for the remote control.
* @rc_query_work: struct work_struct frequent rc queries
* @last_event: last triggered event
* @last_state: last state (no, pressed, repeat)
* @owner: owner of the dvb_adapter
* @priv: private data of the actual driver (allocate by dvb-usb, size defined
* in size_of_priv of dvb_usb_properties).
*/
struct dvb_usb_device {
struct dvb_usb_properties props;
struct dvb_usb_device_description *desc;
#define DVB_USB_STATE_INIT 0x000
#define DVB_USB_STATE_URB_LIST 0x001
#define DVB_USB_STATE_URB_BUF 0x002
#define DVB_USB_STATE_DVB 0x004
#define DVB_USB_STATE_I2C 0x008
#define DVB_USB_STATE_REMOTE 0x010
#define DVB_USB_STATE_URB_SUBMIT 0x020
int state;
/* usb */
struct usb_device *udev;
struct urb **urb_list;
u8 *buffer;
dma_addr_t dma_handle;
int urbs_initialized;
int urbs_submitted;
int feedcount;
int pid_filtering;
/* locking */
struct semaphore usb_sem;
/* i2c */
struct semaphore i2c_sem;
struct i2c_adapter i2c_adap;
/* tuner programming information */
u8 pll_addr;
u8 pll_init[4];
struct dvb_pll_desc *pll_desc;
int (*tuner_pass_ctrl)(struct dvb_frontend *, int, u8);
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
struct dvb_frontend* fe;
int max_feed_count;
int (*fe_sleep) (struct dvb_frontend *);
int (*fe_init) (struct dvb_frontend *);
/* remote control */
struct input_dev rc_input_dev;
struct work_struct rc_query_work;
u32 last_event;
int last_state;
struct module *owner;
void *priv;
};
extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *);
extern void dvb_usb_device_exit(struct usb_interface *);
/* the generic read/write method for device control */
extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
/* commonly used remote control parsing */
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
/* commonly used pll init and set functions */
extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
#endif
/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
* DVB-T receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dibusb.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
#define deb_rc(args...) dprintk(debug,0x01,args)
#define deb_ee(args...) dprintk(debug,0x02,args)
/* Hauppauge NOVA-T USB2 keys */
static struct dvb_usb_rc_key haupp_rc_keys [] = {
{ 0x1e, 0x00, KEY_0 },
{ 0x1e, 0x01, KEY_1 },
{ 0x1e, 0x02, KEY_2 },
{ 0x1e, 0x03, KEY_3 },
{ 0x1e, 0x04, KEY_4 },
{ 0x1e, 0x05, KEY_5 },
{ 0x1e, 0x06, KEY_6 },
{ 0x1e, 0x07, KEY_7 },
{ 0x1e, 0x08, KEY_8 },
{ 0x1e, 0x09, KEY_9 },
{ 0x1e, 0x0a, KEY_KPASTERISK },
{ 0x1e, 0x0b, KEY_RED },
{ 0x1e, 0x0c, KEY_RADIO },
{ 0x1e, 0x0d, KEY_MENU },
{ 0x1e, 0x0e, KEY_GRAVE }, /* # */
{ 0x1e, 0x0f, KEY_MUTE },
{ 0x1e, 0x10, KEY_VOLUMEUP },
{ 0x1e, 0x11, KEY_VOLUMEDOWN },
{ 0x1e, 0x12, KEY_CHANNEL },
{ 0x1e, 0x14, KEY_UP },
{ 0x1e, 0x15, KEY_DOWN },
{ 0x1e, 0x16, KEY_LEFT },
{ 0x1e, 0x17, KEY_RIGHT },
{ 0x1e, 0x18, KEY_VIDEO },
{ 0x1e, 0x19, KEY_AUDIO },
{ 0x1e, 0x1a, KEY_MEDIA },
{ 0x1e, 0x1b, KEY_EPG },
{ 0x1e, 0x1c, KEY_TV },
{ 0x1e, 0x1e, KEY_NEXT },
{ 0x1e, 0x1f, KEY_BACK },
{ 0x1e, 0x20, KEY_CHANNELUP },
{ 0x1e, 0x21, KEY_CHANNELDOWN },
{ 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
{ 0x1e, 0x25, KEY_OK },
{ 0x1e, 0x29, KEY_BLUE},
{ 0x1e, 0x2e, KEY_GREEN },
{ 0x1e, 0x30, KEY_PAUSE },
{ 0x1e, 0x32, KEY_REWIND },
{ 0x1e, 0x34, KEY_FASTFORWARD },
{ 0x1e, 0x35, KEY_PLAY },
{ 0x1e, 0x36, KEY_STOP },
{ 0x1e, 0x37, KEY_RECORD },
{ 0x1e, 0x38, KEY_YELLOW },
{ 0x1e, 0x3b, KEY_GOTO },
{ 0x1e, 0x3d, KEY_POWER },
};
/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
* is delivered. No workaround yet, maybe a new firmware.
*/
static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
u16 raw;
int i;
struct dibusb_state *st = d->priv;
dvb_usb_generic_rw(d,cmd,2,key,5,0);
*state = REMOTE_NO_KEY_PRESSED;
switch (key[0]) {
case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
raw = ((key[1] << 8) | key[2]) >> 3;
toggle = !!(raw & 0x800);
data = raw & 0x3f;
custom = (raw >> 6) & 0x1f;
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
if (haupp_rc_keys[i].data == data &&
haupp_rc_keys[i].custom == custom) {
*event = haupp_rc_keys[i].event;
*state = REMOTE_KEY_PRESSED;
if (st->old_toggle == toggle) {
if (st->last_repeat_count++ < 2)
*state = REMOTE_NO_KEY_PRESSED;
} else {
st->last_repeat_count = 0;
st->old_toggle = toggle;
}
break;
}
}
break;
case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
default:
break;
}
return 0;
}
static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
{
int i;
u8 b;
mac[0] = 0x00;
mac[1] = 0x0d;
mac[2] = 0xfe;
/* this is a complete guess, but works for my box */
for (i = 136; i < 139; i++) {
dibusb_read_eeprom_byte(d,i, &b);
mac[5 - (i - 136)] = b;
/* deb_ee("%02x ",b);
if ((i+1) % 16 == 0)
deb_ee("\n");*/
}
return 0;
}
/* USB Driver stuff */
static struct dvb_usb_properties nova_t_properties;
static int nova_t_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE);
}
/* do not change the order of the ID table */
static struct usb_device_id nova_t_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) },
/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, nova_t_table);
static struct dvb_usb_properties nova_t_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
.pid_filter_count = 32,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-nova-t-usb2-01.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
.power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mc_frontend_attach,
.tuner_attach = dibusb_dib3000mc_tuner_attach,
.read_mac_address = nova_t_read_mac_address,
.rc_interval = 100,
.rc_key_map = haupp_rc_keys,
.rc_key_map_size = ARRAY_SIZE(haupp_rc_keys),
.rc_query = nova_t_rc_query,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 1,
.devices = {
{ "Hauppauge WinTV-NOVA-T usb2",
{ &nova_t_table[0], NULL },
{ &nova_t_table[1], NULL },
},
}
};
static struct usb_driver nova_t_driver = {
.owner = THIS_MODULE,
.name = "Hauppauge WinTV-NOVA-T usb2",
.probe = nova_t_probe,
.disconnect = dvb_usb_device_exit,
.id_table = nova_t_table,
};
/* module stuff */
static int __init nova_t_module_init(void)
{
int result;
if ((result = usb_register(&nova_t_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void __exit nova_t_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&nova_t_driver);
}
module_init (nova_t_module_init);
module_exit (nova_t_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
* DVB-T receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "dibusb.h"
#include "mt352.h"
static int umt_mt352_demod_init(struct dvb_frontend *fe)
{
static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
static u8 mt352_reset[] = { 0x50, 0x80 };
static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
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_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
return 0;
}
static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
{
struct mt352_config umt_config;
memset(&umt_config,0,sizeof(struct mt352_config));
umt_config.demod_init = umt_mt352_demod_init;
umt_config.demod_address = 0xf;
umt_config.pll_set = dvb_usb_pll_set;
d->fe = mt352_attach(&umt_config, &d->i2c_adap);
return 0;
}
static int umt_tuner_attach (struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_tua6034;
return 0;
}
/* USB Driver stuff */
static struct dvb_usb_properties umt_properties;
static int umt_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE) == 0)
return 0;
return -EINVAL;
}
/* do not change the order of the ID table */
static struct usb_device_id umt_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, umt_table);
static struct dvb_usb_properties umt_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-umt-010-02.fw",
.size_of_priv = sizeof(struct dibusb_state),
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.power_ctrl = dibusb_power_ctrl,
.frontend_attach = umt_mt352_frontend_attach,
.tuner_attach = umt_tuner_attach,
.i2c_algo = &dibusb_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 20,
.endpoint = 0x06,
.u = {
.bulk = {
.buffersize = 512,
}
}
},
.num_device_descs = 1,
.devices = {
{ "Hanftek UMT-010 DVB-T USB2.0",
{ &umt_table[0], NULL },
{ &umt_table[1], NULL },
},
}
};
static struct usb_driver umt_driver = {
.owner = THIS_MODULE,
.name = "HanfTek UMT-010 USB2.0 DVB-T devices",
.probe = umt_probe,
.disconnect = dvb_usb_device_exit,
.id_table = umt_table,
};
/* module stuff */
static int __init umt_module_init(void)
{
int result;
if ((result = usb_register(&umt_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void __exit umt_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&umt_driver);
}
module_init (umt_module_init);
module_exit (umt_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
* DVB-T receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* Thanks to Twinhan who kindly provided hardware and information.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*
*/
#include "vp7045.h"
/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
*
* Programming is hidden inside the firmware, so set_frontend is very easy.
* Even though there is a Firmware command that one can use to access the demod
* via its registers. This is used for status information.
*/
struct vp7045_fe_state {
struct dvb_frontend fe;
struct dvb_usb_device *d;
};
static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
u8 s0 = vp7045_read_reg(state->d,0x00),
s1 = vp7045_read_reg(state->d,0x01),
s3 = vp7045_read_reg(state->d,0x03);
*status = 0;
if (s0 & (1 << 4))
*status |= FE_HAS_CARRIER;
if (s0 & (1 << 1))
*status |= FE_HAS_VITERBI;
if (s0 & (1 << 5))
*status |= FE_HAS_LOCK;
if (s1 & (1 << 1))
*status |= FE_HAS_SYNC;
if (s3 & (1 << 6))
*status |= FE_HAS_SIGNAL;
if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
*status &= ~FE_HAS_LOCK;
return 0;
}
static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
*ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
(vp7045_read_reg(state->d, 0x0E) << 8) |
vp7045_read_reg(state->d, 0x0F);
return 0;
}
static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
*unc = (vp7045_read_reg(state->d, 0x10) << 8) |
vp7045_read_reg(state->d, 0x11);
return 0;
}
static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
vp7045_read_reg(state->d, 0x15);
*strength = ~signal;
return 0;
}
static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
u8 _snr = vp7045_read_reg(state->d, 0x09);
*snr = (_snr << 8) | _snr;
return 0;
}
static int vp7045_fe_init(struct dvb_frontend* fe)
{
return 0;
}
static int vp7045_fe_sleep(struct dvb_frontend* fe)
{
return 0;
}
static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 800;
return 0;
}
static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
u8 buf[5];
u32 freq = fep->frequency / 1000;
buf[0] = (freq >> 16) & 0xff;
buf[1] = (freq >> 8) & 0xff;
buf[2] = freq & 0xff;
buf[3] = 0;
switch (fep->u.ofdm.bandwidth) {
case BANDWIDTH_8_MHZ: buf[4] = 8; break;
case BANDWIDTH_7_MHZ: buf[4] = 7; break;
case BANDWIDTH_6_MHZ: buf[4] = 6; break;
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
default:
return -EINVAL;
}
vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
return 0;
}
static int vp7045_fe_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
return 0;
}
static void vp7045_fe_release(struct dvb_frontend* fe)
{
struct vp7045_fe_state *state = fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops vp7045_fe_ops;
struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
{
struct vp7045_fe_state *s = kmalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
if (s == NULL)
goto error;
memset(s,0,sizeof(struct vp7045_fe_state));
s->d = d;
s->fe.ops = &vp7045_fe_ops;
s->fe.demodulator_priv = s;
goto success;
error:
return NULL;
success:
return &s->fe;
}
static struct dvb_frontend_ops vp7045_fe_ops = {
.info = {
.name = "Twinhan VP7045/46 USB DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 1000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_RECOVER |
FE_CAN_HIERARCHY_AUTO,
},
.release = vp7045_fe_release,
.init = vp7045_fe_init,
.sleep = vp7045_fe_sleep,
.set_frontend = vp7045_fe_set_frontend,
.get_frontend = vp7045_fe_get_frontend,
.get_tune_settings = vp7045_fe_get_tune_settings,
.read_status = vp7045_fe_read_status,
.read_ber = vp7045_fe_read_ber,
.read_signal_strength = vp7045_fe_read_signal_strength,
.read_snr = vp7045_fe_read_snr,
.read_ucblocks = vp7045_fe_read_unc_blocks,
};
/* DVB USB compliant Linux driver for the
* - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
* - DigitalNow TinyUSB2 DVB-t receiver
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* Thanks to Twinhan who kindly provided hardware and information.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "vp7045.h"
/* debug */
int dvb_usb_vp7045_debug;
module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
{
int ret = 0;
u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
outbuf[0] = cmd;
if (outlen > 19)
outlen = 19;
if (inlen > 11)
inlen = 11;
if (out != NULL && outlen > 0)
memcpy(&outbuf[1], out, outlen);
deb_xfer("out buffer: ");
debug_dump(outbuf,outlen+1,deb_xfer);
if ((ret = down_interruptible(&d->usb_sem)))
return ret;
if (usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev,0),
TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
outbuf, 20, 2*HZ) != 20) {
err("USB control message 'out' went wrong.");
ret = -EIO;
goto unlock;
}
msleep(msec);
if (usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev,0),
TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
inbuf, 12, 2*HZ) != 12) {
err("USB control message 'in' went wrong.");
ret = -EIO;
goto unlock;
}
deb_xfer("in buffer: ");
debug_dump(inbuf,12,deb_xfer);
if (in != NULL && inlen > 0)
memcpy(in,&inbuf[1],inlen);
unlock:
up(&d->usb_sem);
return ret;
}
u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
{
u8 obuf[2] = { 0 },v;
obuf[1] = reg;
vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
return v;
}
static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 v = onoff;
return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
}
/* remote control stuff */
/* The keymapping struct. Somehow this should be loaded to the driver, but
* currently it is hardcoded. */
static struct dvb_usb_rc_key vp7045_rc_keys[] = {
/* insert the keys like this. to make the raw keys visible, enable
* debug=0x04 when loading dvb-usb-vp7045. */
/* these keys are probably wrong. I don't have a working IR-receiver on my
* vp7045, so I can't test it. Patches are welcome. */
{ 0x00, 0x01, KEY_1 },
{ 0x00, 0x02, KEY_2 },
};
static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state)
{
u8 key;
int i;
vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
deb_rc("remote query key: %x %d\n",key,key);
if (key == 0x44) {
*state = REMOTE_NO_KEY_PRESSED;
return 0;
}
for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
if (vp7045_rc_keys[i].data == key) {
*state = REMOTE_KEY_PRESSED;
*key_buf = vp7045_rc_keys[i].event;
break;
}
return 0;
}
static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
{
int i = 0;
u8 v,br[2];
for (i=0; i < len; i++) {
v = offset + i;
vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
buf[i] = br[1];
}
deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
debug_dump(buf,i,deb_info);
return 0;
}
static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
{
return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
}
static int vp7045_frontend_attach(struct dvb_usb_device *d)
{
u8 buf[255] = { 0 };
vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0);
buf[10] = '\0';
deb_info("firmware says: %s ",buf);
vp7045_usb_op(d,PRODUCT_STRING_READ,NULL,0,buf,20,0);
buf[10] = '\0';
deb_info("%s ",buf);
vp7045_usb_op(d,FW_VERSION_READ,NULL,0,buf,20,0);
buf[10] = '\0';
deb_info("v%s\n",buf);
/* Dump the EEPROM */
/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
d->fe = vp7045_fe_attach(d);
return 0;
}
static struct dvb_usb_properties vp7045_properties;
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE);
}
static struct usb_device_id vp7045_usb_table [] = {
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
static struct dvb_usb_properties vp7045_properties = {
.caps = 0,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
.power_ctrl = vp7045_power_ctrl,
.frontend_attach = vp7045_frontend_attach,
.read_mac_address = vp7045_read_mac_addr,
.rc_interval = 400,
.rc_key_map = vp7045_rc_keys,
.rc_key_map_size = ARRAY_SIZE(vp7045_rc_keys),
.rc_query = vp7045_rc_query,
/* parameter for the MPEG2-data transfer */
.urb = {
.type = DVB_USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
.num_device_descs = 2,
.devices = {
{ .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
.cold_ids = { &vp7045_usb_table[0], NULL },
.warm_ids = { &vp7045_usb_table[1], NULL },
},
{ .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
.cold_ids = { &vp7045_usb_table[2], NULL },
.warm_ids = { &vp7045_usb_table[3], NULL },
},
{ 0 },
}
};
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vp7045_usb_driver = {
.owner = THIS_MODULE,
.name = "dvb-usb-vp7045",
.probe = vp7045_usb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = vp7045_usb_table,
};
/* module stuff */
static int __init vp7045_usb_module_init(void)
{
int result;
if ((result = usb_register(&vp7045_usb_driver))) {
err("usb_register failed. (%d)",result);
return result;
}
return 0;
}
static void __exit vp7045_usb_module_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&vp7045_usb_driver);
}
module_init(vp7045_usb_module_init);
module_exit(vp7045_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII
* USB2.0 DVB-T receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* Thanks to Twinhan who kindly provided hardware and information.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
#ifndef _DVB_USB_VP7045_H_
#define _DVB_USB_VP7045_H_
#define DVB_USB_LOG_PREFIX "vp7045"
#include "dvb-usb.h"
extern int dvb_usb_vp7045_debug;
#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args)
/* vp7045 commands */
/* Twinhan Vendor requests */
#define TH_COMMAND_IN 0xC0
#define TH_COMMAND_OUT 0xC1
/* command bytes */
#define TUNER_REG_READ 0x03
#define TUNER_REG_WRITE 0x04
#define RC_VAL_READ 0x05
#define RC_NO_KEY 0x44
#define SET_TUNER_POWER 0x06
#define CHECK_TUNER_POWER 0x12
#define Tuner_Power_ON 1
#define Tuner_Power_OFF 0
#define GET_USB_SPEED 0x07
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
#define USB_SPEED_HIGH 2
#define LOCK_TUNER_COMMAND 0x09
#define TUNER_SIGNAL_READ 0x0A
/* FX2 eeprom */
#define SET_EE_VALUE 0x10
#define GET_EE_VALUE 0x11
#define FX2_ID_ADDR 0x00
#define VID_MSB_ADDR 0x02
#define VID_LSB_ADDR 0x01
#define PID_MSB_ADDR 0x04
#define PID_LSB_ADDR 0x03
#define MAC_0_ADDR 0x07
#define MAC_1_ADDR 0x08
#define MAC_2_ADDR 0x09
#define MAC_3_ADDR 0x0a
#define MAC_4_ADDR 0x0b
#define MAC_5_ADDR 0x0c
#define RESET_FX2 0x13
#define FW_VERSION_READ 0x0B
#define VENDOR_STRING_READ 0x0C
#define PRODUCT_STRING_READ 0x0D
#define FW_BCD_VERSION_READ 0x14
extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d);
extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec);
extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg);
#endif
...@@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ ...@@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
}; };
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de"); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb-frontend drivers"); MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(dib3000_seq); EXPORT_SYMBOL(dib3000_seq);
......
...@@ -32,9 +32,8 @@ struct dib3000_config ...@@ -32,9 +32,8 @@ struct dib3000_config
u8 demod_address; u8 demod_address;
/* PLL maintenance and the i2c address of the PLL */ /* PLL maintenance and the i2c address of the PLL */
u8 (*pll_addr)(struct dvb_frontend *fe); int (*pll_init)(struct dvb_frontend *fe);
int (*pll_init)(struct dvb_frontend *fe, u8 pll_buf[5]); int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params, u8 pll_buf[5]);
}; };
struct dib_fe_xfer_ops struct dib_fe_xfer_ops
......
...@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a ...@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
#define deb_setf(args...) dprintk(0x04,args) #define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args) #define deb_getf(args...) dprintk(0x08,args)
static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
static int dib3000mb_get_frontend(struct dvb_frontend* fe, static int dib3000mb_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep); struct dvb_frontend_parameters *fep);
...@@ -61,10 +59,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, ...@@ -61,10 +59,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
fe_code_rate_t fe_cr = FEC_NONE; fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq; int search_state, seq;
if (tuner && state->config.pll_addr && state->config.pll_set) { if (tuner && state->config.pll_set) {
dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); state->config.pll_set(fe, fep);
state->config.pll_set(fe, fep, NULL);
dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
deb_setf("bandwidth: "); deb_setf("bandwidth: ");
switch (ofdm->bandwidth) { switch (ofdm->bandwidth) {
...@@ -389,11 +385,8 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) ...@@ -389,11 +385,8 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF); wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
if (state->config.pll_init) { if (state->config.pll_init)
dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); state->config.pll_init(fe);
state->config.pll_init(fe,NULL);
dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
}
return 0; return 0;
} }
...@@ -623,7 +616,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) ...@@ -623,7 +616,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{ {
struct dib3000_state* state = fe->demodulator_priv; struct dib3000_state* state = fe->demodulator_priv;
*unc = rd(DIB3000MB_REG_UNC); *unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE);
return 0; return 0;
} }
...@@ -638,9 +631,6 @@ static int dib3000mb_sleep(struct dvb_frontend* fe) ...@@ -638,9 +631,6 @@ static int dib3000mb_sleep(struct dvb_frontend* fe)
static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{ {
tune->min_delay_ms = 800; tune->min_delay_ms = 800;
tune->step_size = 166667;
tune->max_drift = 166667 * 2;
return 0; return 0;
} }
......
...@@ -294,7 +294,7 @@ static u16 dib3000mb_reg_filter_coeffs[] = { ...@@ -294,7 +294,7 @@ static u16 dib3000mb_reg_filter_coeffs[] = {
static u16 dib3000mb_filter_coeffs[] = { static u16 dib3000mb_filter_coeffs[] = {
226, 160, 29, 226, 160, 29,
979, 998, 19, 979, 998, 19,
22, 1019, 1006, 22, 1019, 1006,
1022, 12, 6, 1022, 12, 6,
1017, 1017, 3, 1017, 1017, 3,
......
...@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=s ...@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=s
#define deb_getf(args...) dprintk(0x08,args) #define deb_getf(args...) dprintk(0x08,args)
#define deb_stat(args...) dprintk(0x10,args) #define deb_stat(args...) dprintk(0x10,args)
static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode, static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
{ {
...@@ -463,10 +461,8 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, ...@@ -463,10 +461,8 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
int search_state,auto_val; int search_state,auto_val;
u16 val; u16 val;
if (tuner && state->config.pll_addr && state->config.pll_set) { /* initial call from dvb */ if (tuner && state->config.pll_set) { /* initial call from dvb */
dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); state->config.pll_set(fe,fep);
state->config.pll_set(fe,fep,NULL);
dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
state->last_tuned_freq = fep->frequency; state->last_tuned_freq = fep->frequency;
// if (!scanboost) { // if (!scanboost) {
...@@ -554,19 +550,15 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, ...@@ -554,19 +550,15 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
dib3000mc_set_adp_cfg(state,ofdm->constellation); dib3000mc_set_adp_cfg(state,ofdm->constellation);
wr_foreach(dib3000mc_reg_offset, wr_foreach(dib3000mc_reg_offset,
dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
} }
return 0; return 0;
} }
static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
{ {
struct dib3000_state *state; struct dib3000_state *state = fe->demodulator_priv;
deb_info("init start\n"); deb_info("init start\n");
state = fe->demodulator_priv;
state->timing_offset = 0; state->timing_offset = 0;
state->timing_offset_comp_done = 0; state->timing_offset_comp_done = 0;
...@@ -649,11 +641,9 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) ...@@ -649,11 +641,9 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
/* if (state->config->pll_init) { if (state->config.pll_init)
dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); state->config.pll_init(fe);
state->config->pll_init(fe,NULL);
dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
}*/
deb_info("init end\n"); deb_info("init end\n");
return 0; return 0;
} }
...@@ -688,7 +678,7 @@ static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) ...@@ -688,7 +678,7 @@ static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{ {
struct dib3000_state* state = fe->demodulator_priv; struct dib3000_state* state = fe->demodulator_priv;
*unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT); *unc = rd(DIB3000MC_REG_PACKET_ERRORS);
return 0; return 0;
} }
...@@ -737,10 +727,7 @@ static int dib3000mc_sleep(struct dvb_frontend* fe) ...@@ -737,10 +727,7 @@ static int dib3000mc_sleep(struct dvb_frontend* fe)
static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{ {
tune->min_delay_ms = 2000; tune->min_delay_ms = 1000;
tune->step_size = 166667;
tune->max_drift = 166667 * 2;
return 0; return 0;
} }
......
/* /*
* $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $
*
* descriptions + helper functions for simple dvb plls. * descriptions + helper functions for simple dvb plls.
* *
* (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
...@@ -114,6 +112,92 @@ struct dvb_pll_desc dvb_pll_unknown_1 = { ...@@ -114,6 +112,92 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
}; };
EXPORT_SYMBOL(dvb_pll_unknown_1); EXPORT_SYMBOL(dvb_pll_unknown_1);
/* Infineon TUA6010XS
* used in Thomson Cable Tuner
*/
struct dvb_pll_desc dvb_pll_tua6010xs = {
.name = "Infineon TUA6010XS",
.min = 44250000,
.max = 858000000,
.count = 3,
.entries = {
{ 115750000, 36125000, 62500, 0x8e, 0x03 },
{ 403250000, 36125000, 62500, 0x8e, 0x06 },
{ 999999999, 36125000, 62500, 0x8e, 0x85 },
},
};
EXPORT_SYMBOL(dvb_pll_tua6010xs);
/* Panasonic env57h1xd5 (some Philips PLL ?) */
struct dvb_pll_desc dvb_pll_env57h1xd5 = {
.name = "Panasonic ENV57H1XD5",
.min = 44250000,
.max = 858000000,
.count = 4,
.entries = {
{ 153000000, 36291666, 166666, 0xc2, 0x41 },
{ 470000000, 36291666, 166666, 0xc2, 0x42 },
{ 526000000, 36291666, 166666, 0xc2, 0x84 },
{ 999999999, 36291666, 166666, 0xc2, 0xa4 },
},
};
EXPORT_SYMBOL(dvb_pll_env57h1xd5);
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
static void tda665x_bw(u8 *buf, int bandwidth)
{
if (bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x08;
}
struct dvb_pll_desc dvb_pll_tda665x = {
.name = "Philips TDA6650/TDA6651",
.min = 44250000,
.max = 858000000,
.setbw = tda665x_bw,
.count = 12,
.entries = {
{ 93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
{ 123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
{ 161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
{ 163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
{ 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
{ 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
{ 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
{ 444000000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
{ 583834000, 36249333, 166667, 0xca, 0x63 /* 011 0 0 0 11 */ },
{ 793834000, 36249333, 166667, 0xca, 0xa3 /* 101 0 0 0 11 */ },
{ 444834000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
{ 861000000, 36249333, 166667, 0xca, 0xe3 /* 111 0 0 0 11 */ },
}
};
EXPORT_SYMBOL(dvb_pll_tda665x);
/* Infineon TUA6034
* used in LG TDTP E102P
*/
static void tua6034_bw(u8 *buf, int bandwidth)
{
if (BANDWIDTH_7_MHZ != bandwidth)
buf[3] |= 0x08;
}
struct dvb_pll_desc dvb_pll_tua6034 = {
.name = "Infineon TUA6034",
.min = 44250000,
.max = 858000000,
.count = 3,
.setbw = tua6034_bw,
.entries = {
{ 174500000, 36166667, 62500, 0xce, 0x01 },
{ 230000000, 36166667, 62500, 0xce, 0x02 },
{ 999999999, 36166667, 62500, 0xce, 0x04 },
},
};
EXPORT_SYMBOL(dvb_pll_tua6034);
/* ----------------------------------------------------------- */ /* ----------------------------------------------------------- */
/* code */ /* code */
...@@ -160,9 +244,3 @@ EXPORT_SYMBOL(dvb_pll_configure); ...@@ -160,9 +244,3 @@ EXPORT_SYMBOL(dvb_pll_configure);
MODULE_DESCRIPTION("dvb pll library"); MODULE_DESCRIPTION("dvb pll library");
MODULE_AUTHOR("Gerd Knorr"); MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
/* /*
* $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $ * descriptions + helper functions for simple dvb plls.
*/ */
#ifndef __DVB_PLL_H__ #ifndef __DVB_PLL_H__
...@@ -17,7 +17,7 @@ struct dvb_pll_desc { ...@@ -17,7 +17,7 @@ struct dvb_pll_desc {
u32 stepsize; u32 stepsize;
u8 cb1; u8 cb1;
u8 cb2; u8 cb2;
} entries[9]; } entries[12];
}; };
extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
...@@ -26,6 +26,11 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; ...@@ -26,6 +26,11 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
extern struct dvb_pll_desc dvb_pll_lg_z201; extern struct dvb_pll_desc dvb_pll_lg_z201;
extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_unknown_1;
extern struct dvb_pll_desc dvb_pll_tua6010xs;
extern struct dvb_pll_desc dvb_pll_env57h1xd5;
extern struct dvb_pll_desc dvb_pll_tua6034;
extern struct dvb_pll_desc dvb_pll_tda665x;
int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth); u32 freq, int bandwidth);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment