aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/dvb/dibusb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/dibusb')
-rw-r--r--drivers/media/dvb/dibusb/Kconfig62
-rw-r--r--drivers/media/dvb/dibusb/Makefile11
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-core.c558
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-dvb.c185
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c582
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-firmware.c87
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-remote.c316
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-usb.c303
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb.h327
-rw-r--r--drivers/media/dvb/dibusb/dvb-fe-dtt200u.c263
10 files changed, 2694 insertions, 0 deletions
diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig
new file mode 100644
index 00000000000..74dfc73ae5b
--- /dev/null
+++ b/drivers/media/dvb/dibusb/Kconfig
@@ -0,0 +1,62 @@
+config DVB_DIBUSB
+ tristate "DiBcom USB DVB-T devices (see help for a complete device list)"
+ depends on DVB_CORE && USB
+ select FW_LOADER
+ select DVB_DIB3000MB
+ select DVB_DIB3000MC
+ select DVB_MT352
+ help
+ Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
+ DiBcom (http://www.dibcom.fr) and C&E.
+
+ 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 USB-Box
+ DiBcom reference devices (non-public)
+ Ultima Electronic/Artec T1 USB TVBOX
+ Compro Videomate DVB-U2000 - DVB-T USB
+ Grandtec DVB-T USB
+ Avermedia AverTV DVBT USB
+ Artec T1 USB1.1 and USB2.0 boxes
+ Yakumo/Typhoon DVB-T USB2.0
+ Hanftek UMT-010 USB2.0
+ Hauppauge WinTV NOVA-T USB2
+
+ The VP7041 seems to be identical to "CTS Portable" (Chinese
+ Television System).
+
+ These devices can be understood as budget ones, they "only" deliver
+ (a part of) the MPEG2 transport stream.
+
+ A firmware is needed to get the device working. See Documentation/dvb/README.dibusb
+ details.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_DIBUSB_MISDESIGNED_DEVICES
+ bool "Enable support for some misdesigned (see help) devices, which identify with wrong IDs"
+ depends on DVB_DIBUSB
+ help
+ Somehow Artec/Ultima Electronic forgot to program the eeprom of some of their
+ USB1.1/USB2.0 devices.
+ So comes that they identify with the default Vendor and Product ID of the Cypress
+ CY7C64613 (AN2235) or Cypress FX2.
+
+ Affected device IDs:
+ 0x0574:0x2235 (Artec T1 USB1.1, cold)
+ 0x04b4:0x8613 (Artec T1 USB2.0, cold)
+ 0x0574:0x1002 (Artec T1 USB2.0, warm)
+ 0x0574:0x2131 (aged DiBcom USB1.1 test device)
+
+ Say Y if your device has one of the mentioned IDs.
+
+config DVB_DIBCOM_DEBUG
+ bool "Enable extended debug support for DiBcom USB device"
+ depends on DVB_DIBUSB
+ help
+ Say Y if you want to enable debuging. See modinfo dvb-dibusb for
+ debug levels.
diff --git a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile
new file mode 100644
index 00000000000..e941c508624
--- /dev/null
+++ b/drivers/media/dvb/dibusb/Makefile
@@ -0,0 +1,11 @@
+dvb-dibusb-objs = dvb-dibusb-core.o \
+ dvb-dibusb-dvb.o \
+ dvb-dibusb-fe-i2c.o \
+ dvb-dibusb-firmware.o \
+ dvb-dibusb-remote.o \
+ dvb-dibusb-usb.o \
+ dvb-fe-dtt200u.o
+
+obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
new file mode 100644
index 00000000000..26235f9247e
--- /dev/null
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
@@ -0,0 +1,558 @@
+/*
+ * Driver for mobile USB Budget DVB-T devices based on reference
+ * design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * dvb-dibusb-core.c
+ *
+ * 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)
+ *
+ * Remote control code added by David Matthews (dm@prolingua.co.uk)
+ *
+ * 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.
+ *
+ * Acknowledgements
+ *
+ * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ * sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/moduleparam.h>
+
+/* debug */
+int dvb_dibusb_debug;
+module_param_named(debug, dvb_dibusb_debug, int, 0644);
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define DBSTATUS ""
+#else
+#define DBSTATUS " (debugging is not enabled)"
+#endif
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))." DBSTATUS);
+#undef DBSTATUS
+
+static int pid_parse;
+module_param(pid_parse, int, 0644);
+MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
+
+static int rc_query_interval = 100;
+module_param(rc_query_interval, int, 0644);
+MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
+
+static int rc_key_repeat_count = 2;
+module_param(rc_key_repeat_count, int, 0644);
+MODULE_PARM_DESC(rc_key_repeat_count, "how many key repeats will be dropped before passing the key event again (default: 2)");
+
+/* Vendor IDs */
+#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_ANCHOR 0x0547
+#define USB_VID_AVERMEDIA 0x14aa
+#define USB_VID_COMPRO 0x185b
+#define USB_VID_COMPRO_UNK 0x145f
+#define USB_VID_CYPRESS 0x04b4
+#define USB_VID_DIBCOM 0x10b8
+#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_IMC_NETWORKS 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_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_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_YAKUMO_DTT200U_COLD 0x0201
+#define USB_PID_YAKUMO_DTT200U_WARM 0x0301
+#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
+
+/* USB Driver stuff
+ * table of devices that this driver is working with
+ *
+ * ATTENTION: Never ever change the order of this table, the particular
+ * devices depend on this order
+ *
+ * Each entry is used as a reference in the device_struct. Currently this is
+ * the only non-redundant way of assigning USB ids to actual devices I'm aware
+ * of, because there is only one place in the code where the assignment of
+ * vendor and product id is done, here.
+ */
+static struct usb_device_id dib_table [] = {
+/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 02 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_COLD) },
+/* 03 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_WARM) },
+
+/* 04 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
+/* 05 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
+/* 06 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) },
+/* 07 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
+/* 08 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
+/* 09 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
+/* 10 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
+/* 11 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
+/* 12 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
+/* 13 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
+/* 14 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
+/* 15 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
+/* 16 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) },
+/* 17 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) },
+/* 18 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) },
+/* 19 */ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_COLD) },
+/* 20 */ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_WARM) },
+/* 21 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
+/* 22 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
+/* 23 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 24 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 25 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 26 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 27 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+
+/* 28 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 29 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+
+/* 30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) },
+/* 31 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
+/* 32 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
+/* 33 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
+/*
+ * activate the following define when you have one of the devices and want to
+ * build it from build-2.6 in dvb-kernel
+ */
+// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
+#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
+/* 34 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 35 */ { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
+/* 36 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
+/* 37 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_DIBCOM_ANCHOR_2135_COLD) },
+#endif
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dib_table);
+
+static struct dibusb_usb_controller dibusb_usb_ctrl[] = {
+ { .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
+ { .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
+ { .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
+};
+
+struct dibusb_tuner dibusb_tuner[] = {
+ { DIBUSB_TUNER_CABLE_THOMSON,
+ 0x61
+ },
+ { DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
+ 0x60
+ },
+ { DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
+ 0x61
+ },
+ { DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
+ 0x60
+ },
+};
+
+static struct dibusb_demod dibusb_demod[] = {
+ { DIBUSB_DIB3000MB,
+ 16,
+ { 0x8, 0 },
+ },
+ { DIBUSB_DIB3000MC,
+ 32,
+ { 0x9, 0xa, 0xb, 0xc },
+ },
+ { DIBUSB_MT352,
+ 254,
+ { 0xf, 0 },
+ },
+ { DTT200U_FE,
+ 8,
+ { 0xff,0 }, /* there is no i2c bus in this device */
+ }
+};
+
+static struct dibusb_device_class dibusb_device_classes[] = {
+ { .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0],
+ .firmware = "dvb-dibusb-5.0.0.11.fw",
+ .pipe_cmd = 0x01, .pipe_data = 0x02,
+ .urb_count = 7, .urb_buffer_size = 4096,
+ DIBUSB_RC_NEC_PROTOCOL,
+ &dibusb_demod[DIBUSB_DIB3000MB],
+ &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+ },
+ { DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1],
+ "dvb-dibusb-an2235-1.fw",
+ 0x01, 0x02,
+ 7, 4096,
+ DIBUSB_RC_NEC_PROTOCOL,
+ &dibusb_demod[DIBUSB_DIB3000MB],
+ &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+ },
+ { DIBUSB2_0,&dibusb_usb_ctrl[2],
+ "dvb-dibusb-6.0.0.5.fw",
+ 0x01, 0x06,
+ 7, 4096,
+ DIBUSB_RC_NEC_PROTOCOL,
+ &dibusb_demod[DIBUSB_DIB3000MC],
+ &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
+ },
+ { UMT2_0, &dibusb_usb_ctrl[2],
+ "dvb-dibusb-umt-2.fw",
+ 0x01, 0x06,
+ 20, 512,
+ DIBUSB_RC_NO,
+ &dibusb_demod[DIBUSB_MT352],
+ &dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P],
+ },
+ { DIBUSB2_0B,&dibusb_usb_ctrl[2],
+ "dvb-dibusb-adstech-usb2-1.fw",
+ 0x01, 0x06,
+ 7, 4096,
+ DIBUSB_RC_NEC_PROTOCOL,
+ &dibusb_demod[DIBUSB_DIB3000MB],
+ &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
+ },
+ { NOVAT_USB2,&dibusb_usb_ctrl[2],
+ "dvb-dibusb-nova-t-1.fw",
+ 0x01, 0x06,
+ 7, 4096,
+ DIBUSB_RC_HAUPPAUGE_PROTO,
+ &dibusb_demod[DIBUSB_DIB3000MC],
+ &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
+ },
+ { DTT200U,&dibusb_usb_ctrl[2],
+ "dvb-dtt200u-1.fw",
+ 0x01, 0x02,
+ 7, 4096,
+ DIBUSB_RC_NO,
+ &dibusb_demod[DTT200U_FE],
+ NULL, /* no explicit tuner/pll-programming necessary (it has the ENV57H1XD5) */
+ },
+};
+
+static struct dibusb_usb_device dibusb_devices[] = {
+ { "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[19], &dib_table[21], NULL},
+ { &dib_table[20], &dib_table[22], NULL},
+ },
+ { "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[11], NULL },
+ { &dib_table[12], NULL },
+ },
+ { "Grandtec USB1.1 DVB-T",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[13], &dib_table[15], NULL },
+ { &dib_table[14], &dib_table[16], NULL },
+ },
+ { "DiBcom USB1.1 DVB-T reference design (MOD3000)",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[7], NULL },
+ { &dib_table[8], NULL },
+ },
+ { "Artec T1 USB1.1 TVBOX with AN2135",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[23], NULL },
+ { &dib_table[24], NULL },
+ },
+ { "Artec T1 USB1.1 TVBOX with AN2235",
+ &dibusb_device_classes[DIBUSB1_1_AN2235],
+ { &dib_table[25], NULL },
+ { &dib_table[26], NULL },
+ },
+ { "Avermedia AverTV DVBT USB1.1",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[0], NULL },
+ { &dib_table[1], NULL },
+ },
+ { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[4], &dib_table[6], NULL},
+ { &dib_table[5], NULL },
+ },
+ { "Unkown USB1.1 DVB-T device ???? please report the name to the author",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[17], NULL },
+ { &dib_table[18], NULL },
+ },
+ { "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+ &dibusb_device_classes[DIBUSB2_0],
+ { &dib_table[9], NULL },
+ { &dib_table[10], NULL },
+ },
+ { "Artec T1 USB2.0 TVBOX (please report the warm ID)",
+ &dibusb_device_classes[DIBUSB2_0],
+ { &dib_table[27], NULL },
+ { NULL },
+ },
+ { "Hauppauge WinTV NOVA-T USB2",
+ &dibusb_device_classes[NOVAT_USB2],
+ { &dib_table[30], NULL },
+ { &dib_table[31], NULL },
+ },
+ { "DTT200U (Yakumo/Hama/Typhoon) DVB-T USB2.0",
+ &dibusb_device_classes[DTT200U],
+ { &dib_table[2], NULL },
+ { &dib_table[3], NULL },
+ },
+ { "Hanftek UMT-010 DVB-T USB2.0",
+ &dibusb_device_classes[UMT2_0],
+ { &dib_table[28], NULL },
+ { &dib_table[29], NULL },
+ },
+ { "KWorld/ADSTech Instant DVB-T USB 2.0",
+ &dibusb_device_classes[DIBUSB2_0B],
+ { &dib_table[32], NULL },
+ { &dib_table[33], NULL }, /* device ID with default DIBUSB2_0-firmware */
+ },
+#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
+ { "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
+ &dibusb_device_classes[DIBUSB1_1_AN2235],
+ { &dib_table[34], NULL },
+ { NULL },
+ },
+ { "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
+ &dibusb_device_classes[DTT200U],
+ { &dib_table[35], NULL },
+ { &dib_table[36], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
+ },
+ { "DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
+ &dibusb_device_classes[DIBUSB1_1],
+ { &dib_table[37], NULL },
+ { NULL },
+ },
+#endif
+};
+
+static int dibusb_exit(struct usb_dibusb *dib)
+{
+ deb_info("init_state before exiting everything: %x\n",dib->init_state);
+ dibusb_remote_exit(dib);
+ dibusb_fe_exit(dib);
+ dibusb_i2c_exit(dib);
+ dibusb_dvb_exit(dib);
+ dibusb_urb_exit(dib);
+ deb_info("init_state should be zero now: %x\n",dib->init_state);
+ dib->init_state = DIBUSB_STATE_INIT;
+ kfree(dib);
+ return 0;
+}
+
+static int dibusb_init(struct usb_dibusb *dib)
+{
+ int ret = 0;
+ sema_init(&dib->usb_sem, 1);
+ sema_init(&dib->i2c_sem, 1);
+
+ dib->init_state = DIBUSB_STATE_INIT;
+
+ if ((ret = dibusb_urb_init(dib)) ||
+ (ret = dibusb_dvb_init(dib)) ||
+ (ret = dibusb_i2c_init(dib))) {
+ dibusb_exit(dib);
+ return ret;
+ }
+
+ if ((ret = dibusb_fe_init(dib)))
+ err("could not initialize a frontend.");
+
+ if ((ret = dibusb_remote_init(dib)))
+ err("could not initialize remote control.");
+
+ return 0;
+}
+
+static struct dibusb_usb_device * dibusb_device_class_quirk(struct usb_device *udev, struct dibusb_usb_device *dev)
+{
+ int i;
+
+ /* Quirk for the Kworld/ADSTech Instant USB2.0 device. It has the same USB
+ * IDs like the USB1.1 KWorld after loading the firmware. Which is a bad
+ * idea and make this quirk necessary.
+ */
+ if (dev->dev_cl->id == DIBUSB1_1 && udev->speed == USB_SPEED_HIGH) {
+ info("this seems to be the Kworld/ADSTech Instant USB2.0 device or equal.");
+ for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
+ if (dibusb_devices[i].dev_cl->id == DIBUSB2_0B) {
+ dev = &dibusb_devices[i];
+ break;
+ }
+ }
+ }
+
+ return dev;
+}
+
+static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold)
+{
+ int i,j;
+ struct dibusb_usb_device *dev = NULL;
+ *cold = -1;
+
+ for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
+ for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) {
+ deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct);
+ if (dibusb_devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+ dibusb_devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+ *cold = 1;
+ dev = &dibusb_devices[i];
+ break;
+ }
+ }
+
+ if (dev != NULL)
+ break;
+
+ for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) {
+ deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct);
+ if (dibusb_devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+ dibusb_devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+ *cold = 0;
+ dev = &dibusb_devices[i];
+ break;
+ }
+ }
+ }
+
+ if (dev != NULL)
+ dev = dibusb_device_class_quirk(udev,dev);
+
+ return dev;
+}
+
+/*
+ * USB
+ */
+static int dibusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_dibusb *dib = NULL;
+ struct dibusb_usb_device *dibdev = NULL;
+
+ int ret = -ENOMEM,cold=0;
+
+ if ((dibdev = dibusb_find_device(udev,&cold)) == NULL) {
+ err("something went very wrong, "
+ "unknown product ID: %.4x",le16_to_cpu(udev->descriptor.idProduct));
+ return -ENODEV;
+ }
+
+ if (cold == 1) {
+ info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
+ ret = dibusb_loadfirmware(udev,dibdev);
+ } else {
+ info("found a '%s' in warm state.",dibdev->name);
+ dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
+ if (dib == NULL) {
+ err("no memory");
+ return ret;
+ }
+ memset(dib,0,sizeof(struct usb_dibusb));
+
+ dib->udev = udev;
+ dib->dibdev = dibdev;
+
+ /* store parameters to structures */
+ dib->rc_query_interval = rc_query_interval;
+ dib->pid_parse = pid_parse;
+ dib->rc_key_repeat_count = rc_key_repeat_count;
+
+ usb_set_intfdata(intf, dib);
+
+ ret = dibusb_init(dib);
+ }
+
+ if (ret == 0)
+ info("%s successfully initialized and connected.",dibdev->name);
+ else
+ info("%s error while loading driver (%d)",dibdev->name,ret);
+ return ret;
+}
+
+static void dibusb_disconnect(struct usb_interface *intf)
+{
+ struct usb_dibusb *dib = usb_get_intfdata(intf);
+ const char *name = DRIVER_DESC;
+
+ usb_set_intfdata(intf,NULL);
+ if (dib != NULL && dib->dibdev != NULL) {
+ name = dib->dibdev->name;
+ dibusb_exit(dib);
+ }
+ info("%s successfully deinitialized and disconnected.",name);
+
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver dibusb_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_DESC,
+ .probe = dibusb_probe,
+ .disconnect = dibusb_disconnect,
+ .id_table = dib_table,
+};
+
+/* module stuff */
+static int __init usb_dibusb_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 usb_dibusb_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&dibusb_driver);
+}
+
+module_init (usb_dibusb_init);
+module_exit (usb_dibusb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
new file mode 100644
index 00000000000..04e54ec093f
--- /dev/null
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
@@ -0,0 +1,185 @@
+/*
+ * dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/usb.h>
+#include <linux/version.h>
+
+static u32 urb_compl_count;
+
+/*
+ * MPEG2 TS DVB stuff
+ */
+void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+ struct usb_dibusb *dib = urb->context;
+
+ deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
+ urb->actual_length);
+
+ urb_compl_count++;
+ if (urb_compl_count % 1000 == 0)
+ deb_info("%d urbs completed so far.\n",urb_compl_count);
+
+ 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 (dib->feedcount > 0 && urb->actual_length > 0) {
+ if (dib->init_state & DIBUSB_STATE_DVB)
+ dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
+ } else
+ deb_ts("URB dropped because of feedcount.\n");
+
+ usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+ struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
+ int newfeedcount;
+
+ if (dib == NULL)
+ return -ENODEV;
+
+ newfeedcount = dib->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 (dib->xfer_ops.fifo_ctrl != NULL) {
+ if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) {
+ err("error while inhibiting fifo.");
+ return -ENODEV;
+ }
+ }
+ dibusb_streaming(dib,0);
+ }
+
+ dib->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 (dib->pid_parse && dib->xfer_ops.pid_ctrl != NULL)
+ dib->xfer_ops.pid_ctrl(dib->fe,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+
+ /*
+ * start the feed if this was the first pid to set and there is still a pid
+ * for reception.
+ */
+ if (dib->feedcount == onoff && dib->feedcount > 0) {
+
+ deb_ts("controlling pid parser\n");
+ if (dib->xfer_ops.pid_parse != NULL) {
+ if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
+ err("could not handle pid_parser");
+ }
+ }
+
+ deb_ts("start feeding\n");
+ if (dib->xfer_ops.fifo_ctrl != NULL) {
+ if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
+ err("error while enabling fifo.");
+ return -ENODEV;
+ }
+ }
+ dibusb_streaming(dib,1);
+ }
+ return 0;
+}
+
+static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+ return dibusb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+ return dibusb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dibusb_dvb_init(struct usb_dibusb *dib)
+{
+ int ret;
+
+ urb_compl_count = 0;
+
+ if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC,
+ THIS_MODULE)) < 0) {
+ deb_info("dvb_register_adapter failed: error %d", ret);
+ goto err;
+ }
+ dib->adapter->priv = dib;
+
+/* i2c is done in dibusb_i2c_init */
+
+ dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+
+ dib->demux.priv = (void *)dib;
+ /* get pidcount from demod */
+ dib->demux.feednum = dib->demux.filternum = 255;
+ dib->demux.start_feed = dibusb_start_feed;
+ dib->demux.stop_feed = dibusb_stop_feed;
+ dib->demux.write_to_decoder = NULL;
+ if ((ret = dvb_dmx_init(&dib->demux)) < 0) {
+ err("dvb_dmx_init failed: error %d",ret);
+ goto err_dmx;
+ }
+
+ dib->dmxdev.filternum = dib->demux.filternum;
+ dib->dmxdev.demux = &dib->demux.dmx;
+ dib->dmxdev.capabilities = 0;
+ if ((ret = dvb_dmxdev_init(&dib->dmxdev, dib->adapter)) < 0) {
+ err("dvb_dmxdev_init failed: error %d",ret);
+ goto err_dmx_dev;
+ }
+
+ dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx);
+
+ goto success;
+err_dmx_dev:
+ dvb_dmx_release(&dib->demux);
+err_dmx:
+ dvb_unregister_adapter(dib->adapter);
+err:
+ return ret;
+success:
+ dib->init_state |= DIBUSB_STATE_DVB;
+ return 0;
+}
+
+int dibusb_dvb_exit(struct usb_dibusb *dib)
+{
+ if (dib->init_state & DIBUSB_STATE_DVB) {
+ dib->init_state &= ~DIBUSB_STATE_DVB;
+ deb_info("unregistering DVB part\n");
+ dvb_net_release(&dib->dvb_net);
+ dib->demux.dmx.close(&dib->demux.dmx);
+ dvb_dmxdev_release(&dib->dmxdev);
+ dvb_dmx_release(&dib->demux);
+ dvb_unregister_adapter(dib->adapter);
+ }
+ return 0;
+}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
new file mode 100644
index 00000000000..2ed89488c7c
--- /dev/null
+++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
@@ -0,0 +1,582 @@
+/*
+ * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices
+ * based on reference design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * see dvb-dibusb-core.c for more copyright details.
+ *
+ * This file contains functions for attaching, initializing of an appropriate
+ * demodulator/frontend. I2C-stuff is also located here.
+ *
+ */
+#include "dvb-dibusb.h"
+
+#include <linux/usb.h>
+
+static int dibusb_i2c_msg(struct usb_dibusb *dib, 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 dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen);
+}
+
+/*
+ * I2C master xfer function
+ */
+static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
+{
+ struct usb_dibusb *dib = i2c_get_adapdata(adap);
+ int i;
+
+ if (down_interruptible(&dib->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(dib, 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(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
+ break;
+ }
+
+ up(&dib->i2c_sem);
+ return i;
+}
+
+static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dibusb_algo = {
+ .name = "DiBcom USB i2c algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = dibusb_i2c_xfer,
+ .functionality = dibusb_i2c_func,
+};
+
+static int dibusb_general_demod_init(struct dvb_frontend *fe);
+static u8 dibusb_general_pll_addr(struct dvb_frontend *fe);
+static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]);
+static int dibusb_general_pll_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters* params, u8 pll_buf[5]);
+
+static struct mt352_config mt352_hanftek_umt_010_config = {
+ .demod_address = 0x1e,
+ .demod_init = dibusb_general_demod_init,
+ .pll_set = dibusb_general_pll_set,
+};
+
+static int dibusb_tuner_quirk(struct usb_dibusb *dib)
+{
+ switch (dib->dibdev->dev_cl->id) {
+ case DIBUSB1_1: /* some these device have the ENV77H11D5 and some the THOMSON CABLE */
+ case DIBUSB1_1_AN2235: { /* actually its this device, but in warm state they are indistinguishable */
+ struct dibusb_tuner *t;
+ u8 b[2] = { 0,0 } ,b2[1];
+ struct i2c_msg msg[2] = {
+ { .flags = 0, .buf = b, .len = 2 },
+ { .flags = I2C_M_RD, .buf = b2, .len = 1},
+ };
+
+ t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5];
+
+ msg[0].addr = msg[1].addr = t->pll_addr;
+
+ if (dib->xfer_ops.tuner_pass_ctrl != NULL)
+ dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr);
+ dibusb_i2c_xfer(&dib->i2c_adap,msg,2);
+ if (dib->xfer_ops.tuner_pass_ctrl != NULL)
+ dib->xfer_ops.tuner_pass_ctrl(dib->fe,0,t->pll_addr);
+
+ if (b2[0] == 0xfe)
+ info("this device has the Thomson Cable onboard. Which is default.");
+ else {
+ dib->tuner = t;
+ info("this device has the Panasonic ENV77H11D5 onboard.");
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+int dibusb_fe_init(struct usb_dibusb* dib)
+{
+ struct dib3000_config demod_cfg;
+ int i;
+
+ if (dib->init_state & DIBUSB_STATE_I2C) {
+ for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) &&
+ dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) {
+
+ demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
+ demod_cfg.pll_addr = dibusb_general_pll_addr;
+ demod_cfg.pll_set = dibusb_general_pll_set;
+ demod_cfg.pll_init = dibusb_general_pll_init;
+
+ deb_info("demod id: %d %d\n",dib->dibdev->dev_cl->demod->id,DTT200U_FE);
+
+ switch (dib->dibdev->dev_cl->demod->id) {
+ case DIBUSB_DIB3000MB:
+ dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
+ break;
+ case DIBUSB_DIB3000MC:
+ dib->fe = dib3000mc_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
+ break;
+ case DIBUSB_MT352:
+ mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
+ dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap);
+ break;
+ case DTT200U_FE:
+ dib->fe = dtt200u_fe_attach(dib,&dib->xfer_ops);
+ break;
+ }
+ if (dib->fe != NULL) {
+ info("found demodulator at i2c address 0x%x",dib->dibdev->dev_cl->demod->i2c_addrs[i]);
+ break;
+ }
+ }
+ /* if a frontend was found */
+ if (dib->fe != NULL) {
+ if (dib->fe->ops->sleep != NULL)
+ dib->fe_sleep = dib->fe->ops->sleep;
+ dib->fe->ops-