From b6a235b1186dda0800c8bedc2526830a4a36b44e Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 23 Jun 2005 22:02:29 -0700 Subject: [PATCH] dvb: drop obsolete dibusb driver Remove the dibusb driver which has been obsoleted by the generalized dvb-usb driver. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/Kconfig | 1 - drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/dibusb/Kconfig | 62 --- drivers/media/dvb/dibusb/Makefile | 11 - drivers/media/dvb/dibusb/dvb-dibusb-core.c | 558 ------------------------ drivers/media/dvb/dibusb/dvb-dibusb-dvb.c | 185 -------- drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c | 582 ------------------------- drivers/media/dvb/dibusb/dvb-dibusb-firmware.c | 87 ---- drivers/media/dvb/dibusb/dvb-dibusb-remote.c | 316 -------------- drivers/media/dvb/dibusb/dvb-dibusb-usb.c | 303 ------------- drivers/media/dvb/dibusb/dvb-dibusb.h | 327 -------------- drivers/media/dvb/dibusb/dvb-fe-dtt200u.c | 263 ----------- 12 files changed, 1 insertion(+), 2696 deletions(-) delete mode 100644 drivers/media/dvb/dibusb/Kconfig delete mode 100644 drivers/media/dvb/dibusb/Makefile delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb-core.c delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb-dvb.c delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb-firmware.c delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb-remote.c delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb-usb.c delete mode 100644 drivers/media/dvb/dibusb/dvb-dibusb.h delete mode 100644 drivers/media/dvb/dibusb/dvb-fe-dtt200u.c (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 4983e1b1bb1d..b81abdfde378 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -29,7 +29,6 @@ comment "Supported USB Adapters" depends on DVB_CORE && USB source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" -source "drivers/media/dvb/dibusb/Kconfig" source "drivers/media/dvb/cinergyT2/Kconfig" comment "Supported FlexCopII (B2C2) Adapters" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 520fc3902819..d2dd914f7776 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dibusb/ cinergyT2/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig deleted file mode 100644 index 74dfc73ae5b0..000000000000 --- a/drivers/media/dvb/dibusb/Kconfig +++ /dev/null @@ -1,62 +0,0 @@ -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 deleted file mode 100644 index e941c508624e..000000000000 --- a/drivers/media/dvb/dibusb/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 26235f9247e4..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb-core.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * 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 - -/* 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 deleted file mode 100644 index 400b439e804e..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 -#include - -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 deleted file mode 100644 index 5a71b88797d9..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * 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 - -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->sleep = dibusb_hw_sleep; - - if (dib->fe->ops->init != NULL ) - dib->fe_init = dib->fe->ops->init; - dib->fe->ops->init = dibusb_hw_wakeup; - - /* setting the default tuner */ - dib->tuner = dib->dibdev->dev_cl->tuner; - - /* check which tuner is mounted on this device, in case this is unsure */ - dibusb_tuner_quirk(dib); - } - } - if (dib->fe == NULL) { - err("A frontend driver was not found for device '%s'.", - dib->dibdev->name); - return -ENODEV; - } else { - if (dvb_register_frontend(&dib->adapter, dib->fe)) { - err("Frontend registration failed."); - if (dib->fe->ops->release) - dib->fe->ops->release(dib->fe); - dib->fe = NULL; - return -ENODEV; - } - } - - return 0; -} - -int dibusb_fe_exit(struct usb_dibusb *dib) -{ - if (dib->fe != NULL) - dvb_unregister_frontend(dib->fe); - return 0; -} - -int dibusb_i2c_init(struct usb_dibusb *dib) -{ - int ret = 0; - - dib->adapter.priv = dib; - - strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - dib->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, -#else - dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL, -#endif - dib->i2c_adap.algo = &dibusb_algo; - dib->i2c_adap.algo_data = NULL; - dib->i2c_adap.id = I2C_ALGO_BIT; - - i2c_set_adapdata(&dib->i2c_adap, dib); - - if ((ret = i2c_add_adapter(&dib->i2c_adap)) < 0) - err("could not add i2c adapter"); - - dib->init_state |= DIBUSB_STATE_I2C; - - return ret; -} - -int dibusb_i2c_exit(struct usb_dibusb *dib) -{ - if (dib->init_state & DIBUSB_STATE_I2C) - i2c_del_adapter(&dib->i2c_adap); - dib->init_state &= ~DIBUSB_STATE_I2C; - return 0; -} - - -/* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */ -static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4]) -{ - u32 tfreq = (fep->frequency + 36125000) / 62500; - int vu,p0,p1,p2; - - if (fep->frequency > 403250000) - vu = 1, p2 = 1, p1 = 0, p0 = 1; - else if (fep->frequency > 115750000) - vu = 0, p2 = 1, p1 = 1, p0 = 0; - else if (fep->frequency > 44250000) - vu = 0, p2 = 0, p1 = 1, p0 = 1; - else - return -EINVAL; - - pllbuf[0] = (tfreq >> 8) & 0x7f; - pllbuf[1] = tfreq & 0xff; - pllbuf[2] = 0x8e; - pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0; - return 0; -} - -static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4]) -{ - u32 freq_khz = fep->frequency / 1000; - u32 tfreq = ((freq_khz + 36125)*6 + 500) / 1000; - u8 TA, T210, R210, ctrl1, cp210, p4321; - if (freq_khz > 858000) { - err("frequency cannot be larger than 858 MHz."); - return -EINVAL; - } - - // contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0 - TA = 1; - T210 = 0; - R210 = 0x2; - ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210; - -// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES ***************** - if (freq_khz < 470000) - cp210 = 2; // VHF Low and High band ch E12 to E4 to E12 - else if (freq_khz < 526000) - cp210 = 4; // UHF band Ch E21 to E27 - else // if (freq < 862000000) - cp210 = 5; // UHF band ch E28 to E69 - -//********************* BW select ******************************* - if (freq_khz < 153000) - p4321 = 1; // BW selected for VHF low - else if (freq_khz < 470000) - p4321 = 2; // BW selected for VHF high E5 to E12 - else // if (freq < 862000000) - p4321 = 4; // BW selection for UHF E21 to E69 - - pllbuf[0] = (tfreq >> 8) & 0xff; - pllbuf[1] = (tfreq >> 0) & 0xff; - pllbuf[2] = 0xff & ctrl1; - pllbuf[3] = (cp210 << 5) | (p4321); - - return 0; -} - -/* - * 7 6 5 4 3 2 1 0 - * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0 - * - * Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8 - * Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0 - * - * Control byte 1 1 T/A=1 T2 T1 T0 R2 R1 R0 - * 1 T/A=0 0 0 ATC AL2 AL1 AL0 - * - * Control byte 2 CP2 CP1 CP0 BS5 BS4 BS3 BS2 BS1 - * - * MA0/1 = programmable address bits - * R/~W = read/write bit (0 for writing) - * N14-0 = programmable LO frequency - * - * T/A = test AGC bit (0 = next 6 bits AGC setting, - * 1 = next 6 bits test and reference divider ratio settings) - * T2-0 = test bits - * R2-0 = reference divider ratio and programmable frequency step - * ATC = AGC current setting and time constant - * ATC = 0: AGC current = 220nA, AGC time constant = 2s - * ATC = 1: AGC current = 9uA, AGC time constant = 50ms - * AL2-0 = AGC take-over point bits - * CP2-0 = charge pump current - * BS5-1 = PMOS ports control bits; - * BSn = 0 corresponding port is off, high-impedance state (at power-on) - * BSn = 1 corresponding port is on - */ -static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4]) -{ - pllbuf[0] = 0x0b; - pllbuf[1] = 0xf5; - pllbuf[2] = 0x85; - pllbuf[3] = 0xab; - return 0; -} - -static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameters *fep,u8 pllbuf[4]) -{ - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = fep->frequency + 36166000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (fep->frequency < 49000000) - return -EINVAL; - else if (fep->frequency < 161000000) - band = 1; - else if (fep->frequency < 444000000) - band = 2; - else if (fep->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - case BANDWIDTH_7_MHZ: - filter = 0; - break; - case BANDWIDTH_8_MHZ: - filter = 1; - break; - default: - return -EINVAL; - } - - // calculate divisor - // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((fep->frequency / 1000) * 6) + 217496) / 1000; - - // setup tuner buffer - pllbuf[0] = (tuner_frequency >> 8) & 0x7f; - pllbuf[1] = tuner_frequency & 0xff; - pllbuf[2] = 0xca; - pllbuf[3] = (cp << 5) | (filter << 3) | band; - return 0; -} - -/* - * 7 6 5 4 3 2 1 0 - * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0 - * - * Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8 - * Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0 - * - * Control byte 1 CP T2 T1 T0 RSA RSB OS - * - * Band Switch byte X X X P4 P3 P2 P1 P0 - * - * Auxiliary byte ATC AL2 AL1 AL0 0 0 0 0 - * - * Address: MA1 MA0 Address - * 0 0 c0 - * 0 1 c2 (always valid) - * 1 0 c4 - * 1 1 c6 - */ -static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4]) -{ - u32 div; - u8 p210, p3; - -#define TUNER_MUL 62500 - - div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL; -// div = ((fep->frequency/1000 + 36166) * 6) / 1000; - - if (fep->frequency < 174500000) - p210 = 1; // not supported by the tdtp_e102p - else if (fep->frequency < 230000000) // VHF - p210 = 2; - else - p210 = 4; - - if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - p3 = 0; - else - p3 = 1; - - pllbuf[0] = (div >> 8) & 0x7f; - pllbuf[1] = div & 0xff; - pllbuf[2] = 0xce; -// pllbuf[2] = 0xcc; - pllbuf[3] = (p3 << 3) | p210; - - return 0; -} - -static int lg_tdtp_e102p_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 dibusb_general_demod_init(struct dvb_frontend *fe) -{ - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - switch (dib->dibdev->dev_cl->id) { - case UMT2_0: - return lg_tdtp_e102p_mt352_demod_init(fe); - default: /* other device classes do not have device specific demod inits */ - break; - } - return 0; -} - -static u8 dibusb_general_pll_addr(struct dvb_frontend *fe) -{ - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - return dib->tuner->pll_addr; -} - -static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4]) -{ - if (pll_buf == NULL) { - struct i2c_msg msg = { - .addr = dib->tuner->pll_addr, - .flags = 0, - .buf = buf, - .len = sizeof(buf) - }; - if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) - return -EIO; - msleep(1); - } else { - pll_buf[0] = dib->tuner->pll_addr << 1; - memcpy(&pll_buf[1],buf,4); - } - - return 0; -} - -static int dibusb_general_pll_init(struct dvb_frontend *fe, - u8 pll_buf[5]) -{ - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - u8 buf[4]; - int ret=0; - switch (dib->tuner->id) { - case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5: - ret = panasonic_cofdm_env77h11d5_tda6650_init(fe,buf); - break; - default: - break; - } - - if (ret) - return ret; - - return dibusb_pll_i2c_helper(dib,pll_buf,buf); -} - -static int dibusb_general_pll_set(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep, u8 pll_buf[5]) -{ - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - u8 buf[4]; - int ret=0; - - switch (dib->tuner->id) { - case DIBUSB_TUNER_CABLE_THOMSON: - ret = thomson_cable_eu_pll_set(fep, buf); - break; - case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5: - ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf); - break; - case DIBUSB_TUNER_CABLE_LG_TDTP_E102P: - ret = lg_tdtp_e102p_tua6034(fep, buf); - break; - case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5: - ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf); - break; - default: - warn("no pll programming routine found for tuner %d.\n",dib->tuner->id); - ret = -ENODEV; - break; - } - - if (ret) - return ret; - - return dibusb_pll_i2c_helper(dib,pll_buf,buf); -} diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c deleted file mode 100644 index 504ba47afdf3..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * dvb-dibusb-firmware.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 downloading the firmware to the device. - */ -#include "dvb-dibusb.h" - -#include -#include - -/* - * load a firmware packet to the device - */ -static int dibusb_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, 5000); -} - -int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev) -{ - const struct firmware *fw = NULL; - u16 addr; - u8 *b,*p; - int ret = 0,i; - - if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", - dibdev->dev_cl->firmware); - return ret; - } - - info("downloading firmware from file '%s'.",dibdev->dev_cl->firmware); - - 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 = dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->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 = *((u16 *) &b[1]); - - ret = dibusb_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 || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->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; -} diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c deleted file mode 100644 index 9dc8b15517b7..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * dvb-dibusb-remote.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 handling the event device on the software - * side and the remote control on the hardware side. - */ -#include "dvb-dibusb.h" - -/* Table to map raw key codes to key events. This should not be hard-wired - into the kernel. */ -static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] = -{ - /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ - { 0x00, 0xff, 0x16, KEY_POWER }, - { 0x00, 0xff, 0x10, KEY_MUTE }, - { 0x00, 0xff, 0x03, KEY_1 }, - { 0x00, 0xff, 0x01, KEY_2 }, - { 0x00, 0xff, 0x06, KEY_3 }, - { 0x00, 0xff, 0x09, KEY_4 }, - { 0x00, 0xff, 0x1d, KEY_5 }, - { 0x00, 0xff, 0x1f, KEY_6 }, - { 0x00, 0xff, 0x0d, KEY_7 }, - { 0x00, 0xff, 0x19, KEY_8 }, - { 0x00, 0xff, 0x1b, KEY_9 }, - { 0x00, 0xff, 0x15, KEY_0 }, - { 0x00, 0xff, 0x05, KEY_CHANNELUP }, - { 0x00, 0xff, 0x02, KEY_CHANNELDOWN }, - { 0x00, 0xff, 0x1e, KEY_VOLUMEUP }, - { 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN }, - { 0x00, 0xff, 0x11, KEY_RECORD }, - { 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x00, 0xff, 0x14, KEY_PLAY }, - { 0x00, 0xff, 0x1a, KEY_STOP }, - { 0x00, 0xff, 0x40, KEY_REWIND }, - { 0x00, 0xff, 0x12, KEY_FASTFORWARD }, - { 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x00, 0xff, 0x4c, KEY_PAUSE }, - { 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */ - { 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ - { 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */ - { 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */ - { 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */ - { 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */ - { 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */ - { 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */ - /* Key codes for the KWorld/ADSTech/JetWay remote. */ - { 0x86, 0x6b, 0x12, KEY_POWER }, - { 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */ - { 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */ - { 0x86, 0x6b, 0x0b, KEY_EPG }, - { 0x86, 0x6b, 0x10, KEY_MUTE }, - { 0x86, 0x6b, 0x01, KEY_1 }, - { 0x86, 0x6b, 0x02, KEY_2 }, - { 0x86, 0x6b, 0x03, KEY_3 }, - { 0x86, 0x6b, 0x04, KEY_4 }, - { 0x86, 0x6b, 0x05, KEY_5 }, - { 0x86, 0x6b, 0x06, KEY_6 }, - { 0x86, 0x6b, 0x07, KEY_7 }, - { 0x86, 0x6b, 0x08, KEY_8 }, - { 0x86, 0x6b, 0x09, KEY_9 }, - { 0x86, 0x6b, 0x0a, KEY_0 }, - { 0x86, 0x6b, 0x18, KEY_ZOOM }, - { 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */ - { 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */ - { 0x86, 0x6b, 0x00, KEY_UNDO }, - { 0x86, 0x6b, 0x1d, KEY_RECORD }, - { 0x86, 0x6b, 0x0d, KEY_STOP }, - { 0x86, 0x6b, 0x0e, KEY_PAUSE }, - { 0x86, 0x6b, 0x16, KEY_PLAY }, - { 0x86, 0x6b, 0x11, KEY_BACK }, - { 0x86, 0x6b, 0x19, KEY_FORWARD }, - { 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */ - { 0x86, 0x6b, 0x15, KEY_ESC }, - { 0x86, 0x6b, 0x1a, KEY_UP }, - { 0x86, 0x6b, 0x1e, KEY_DOWN }, - { 0x86, 0x6b, 0x1f, KEY_LEFT }, - { 0x86, 0x6b, 0x1b, KEY_RIGHT }, -}; - -/* Hauppauge NOVA-T USB2 keys */ -static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = { - { 0xddf, KEY_GOTO }, - { 0xdef, KEY_POWER }, - { 0xce7, KEY_TV }, - { 0xcc7, KEY_VIDEO }, - { 0xccf, KEY_AUDIO }, - { 0xcd7, KEY_MEDIA }, - { 0xcdf, KEY_EPG }, - { 0xca7, KEY_UP }, - { 0xc67, KEY_RADIO }, - { 0xcb7, KEY_LEFT }, - { 0xd2f, KEY_OK }, - { 0xcbf, KEY_RIGHT }, - { 0xcff, KEY_BACK }, - { 0xcaf, KEY_DOWN }, - { 0xc6f, KEY_MENU }, - { 0xc87, KEY_VOLUMEUP }, - { 0xc8f, KEY_VOLUMEDOWN }, - { 0xc97, KEY_CHANNEL }, - { 0xc7f, KEY_MUTE }, - { 0xd07, KEY_CHANNELUP }, - { 0xd0f, KEY_CHANNELDOWN }, - { 0xdbf, KEY_RECORD }, - { 0xdb7, KEY_STOP }, - { 0xd97, KEY_REWIND }, - { 0xdaf, KEY_PLAY }, - { 0xda7, KEY_FASTFORWARD }, - { 0xd27, KEY_LAST }, /* Skip backwards */ - { 0xd87, KEY_PAUSE }, - { 0xcf7, KEY_NEXT }, - { 0xc07, KEY_0 }, - { 0xc0f, KEY_1 }, - { 0xc17, KEY_2 }, - { 0xc1f, KEY_3 }, - { 0xc27, KEY_4 }, - { 0xc2f, KEY_5 }, - { 0xc37, KEY_6 }, - { 0xc3f, KEY_7 }, - { 0xc47, KEY_8 }, - { 0xc4f, KEY_9 }, - { 0xc57, KEY_KPASTERISK }, - { 0xc77, KEY_GRAVE }, /* # */ - { 0xc5f, KEY_RED }, - { 0xd77, KEY_GREEN }, - { 0xdc7, KEY_YELLOW }, - { 0xd4f, KEY_BLUE}, -}; - -static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5]) -{ - int i; - switch (rb[0]) { - case DIBUSB_RC_NEC_KEY_PRESSED: - /* rb[1-3] is the actual key, rb[4] is a checksum */ - deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", - rb[1], rb[2], rb[3], rb[4]); - - if ((0xff - rb[3]) != rb[4]) { - deb_rc("remote control checksum failed.\n"); - break; - } - - /* See if we can match the raw key code. */ - for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) { - if (nec_rc_keys[i].c0 == rb[1] && - nec_rc_keys[i].c1 == rb[2] && - nec_rc_keys[i].c2 == rb[3]) { - - dib->last_event = nec_rc_keys[i].key; - return 1; - } - } - break; - case DIBUSB_RC_NEC_KEY_REPEATED: - /* rb[1]..rb[4] are always zero.*/ - /* Repeats often seem to occur so for the moment just ignore this. */ - return 0; - case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */ - default: - break; - } - return -1; -} - -static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4]) -{ - u16 raw; - int i,state; - switch (rb[0]) { - case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED: - raw = ((rb[1] & 0x0f) << 8) | rb[2]; - - state = !!(rb[1] & 0x40); - - deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state); - for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) { - if (haupp_rc_keys[i].raw == raw) { - if (dib->last_event == haupp_rc_keys[i].key && - dib->last_state == state) { - deb_rc("key repeat\n"); - return 0; - } else { - dib->last_event = haupp_rc_keys[i].key; - dib->last_state = state; - return 1; - } - } - } - - break; - case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY: - default: - break; - } - return -1; -} - -/* - * Read the remote control and feed the appropriate event. - * NEC protocol is used for remote controls - */ -static int dibusb_read_remote_control(struct usb_dibusb *dib) -{ - u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5]; - int ret,event = 0; - - if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5))) - return ret; - - switch (dib->dibdev->dev_cl->remote_type) { - case DIBUSB_RC_NEC_PROTOCOL: - event = dibusb_key2event_nec(dib,rb); - break; - case DIBUSB_RC_HAUPPAUGE_PROTO: - event = dibusb_key2event_hauppauge(dib,rb); - default: - break; - } - - /* key repeat */ - if (event == 0) - if (++dib->repeat_key_count < dib->rc_key_repeat_count) { - deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count); - event = -1; /* skip this key repeat */ - } - - if (event == 1 || event == 0) { - deb_rc("Translated key 0x%04x\n",event); - - /* Signal down and up events for this key. */ - input_report_key(&dib->rc_input_dev, dib->last_event, 1); - input_report_key(&dib->rc_input_dev, dib->last_event, 0); - input_sync(&dib->rc_input_dev); - - if (event == 1) - dib->repeat_key_count = 0; - } - return 0; -} - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - whether the remote control has received anything. */ -static void dibusb_remote_query(void *data) -{ - struct usb_dibusb *dib = (struct usb_dibusb *) data; - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ - dibusb_read_remote_control(dib); - schedule_delayed_work(&dib->rc_query_work, - msecs_to_jiffies(dib->rc_query_interval)); -} - -int dibusb_remote_init(struct usb_dibusb *dib) -{ - int i; - - if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO) - return 0; - - /* Initialise the remote-control structures.*/ - init_input_dev(&dib->rc_input_dev); - - dib->rc_input_dev.evbit[0] = BIT(EV_KEY); - dib->rc_input_dev.keycodesize = sizeof(unsigned char); - dib->rc_input_dev.keycodemax = KEY_MAX; - dib->rc_input_dev.name = DRIVER_DESC " remote control"; - - switch (dib->dibdev->dev_cl->remote_type) { - case DIBUSB_RC_NEC_PROTOCOL: - for (i=0; irc_input_dev.keybit); - break; - case DIBUSB_RC_HAUPPAUGE_PROTO: - for (i=0; irc_input_dev.keybit); - break; - default: - break; - } - - - input_register_device(&dib->rc_input_dev); - - INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib); - - /* Start the remote-control polling. */ - if (dib->rc_query_interval < 40) - dib->rc_query_interval = 100; /* default */ - - info("schedule remote query interval to %d msecs.",dib->rc_query_interval); - schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(dib->rc_query_interval)); - - dib->init_state |= DIBUSB_STATE_REMOTE; - - return 0; -} - -int dibusb_remote_exit(struct usb_dibusb *dib) -{ - if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO) - return 0; - - if (dib->init_state & DIBUSB_STATE_REMOTE) { - cancel_delayed_work(&dib->rc_query_work); - flush_scheduled_work(); - input_unregister_device(&dib->rc_input_dev); - } - dib->init_state &= ~DIBUSB_STATE_REMOTE; - return 0; -} diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c deleted file mode 100644 index 642f0596a5ba..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * dvb-dibusb-usb.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 - * usb specific stuff. - */ -#include "dvb-dibusb.h" - -#include -#include - -int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen) -{ - int actlen,ret = -ENOMEM; - - if (wbuf == NULL || wlen == 0) - return -EINVAL; - - if ((ret = down_interruptible(&dib->usb_sem))) - return ret; - - debug_dump(wbuf,wlen); - - ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev, - dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen, - DIBUSB_I2C_TIMEOUT); - - 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) { - ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev, - dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen, - DIBUSB_I2C_TIMEOUT); - - if (ret) - err("recv bulk message failed: %d",ret); - else { - deb_alot("rlen: %d\n",rlen); - debug_dump(rbuf,actlen); - } - } - - up(&dib->usb_sem); - return ret; -} - -/* - * Cypress controls - */ -int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len) -{ - return dibusb_readwrite_usb(dib,buf,len,NULL,0); -} - -#if 0 -/* - * #if 0'ing the following functions as they are not in use _now_, - * but probably will be sometime. - */ -/* - * do not use this, just a workaround for a bug, - * which will hopefully never occur :). - */ -int dibusb_interrupt_read_loop(struct usb_dibusb *dib) -{ - u8 b[1] = { DIBUSB_REQ_INTR_READ }; - return dibusb_write_usb(dib,b,1); -} -#endif - -/* - * ioctl for the firmware - */ -static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen) -{ - u8 b[34]; - int size = plen > 32 ? 32 : plen; - memset(b,0,34); - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = cmd; - - if (size > 0) - memcpy(&b[2],param,size); - - return dibusb_write_usb(dib,b,34); //2+size); -} - -/* - * ioctl for power control - */ -int dibusb_hw_wakeup(struct dvb_frontend *fe) -{ - struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv; - u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP }; - deb_info("dibusb-device is getting up.\n"); - - switch (dib->dibdev->dev_cl->id) { - case DTT200U: - break; - default: - dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); - break; - } - - if (dib->fe_init) - return dib->fe_init(fe); - - return 0; -} - -int dibusb_hw_sleep(struct dvb_frontend *fe) -{ - struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv; - u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP }; - deb_info("dibusb-device is going to bed.\n"); - /* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */ - switch (dib->dibdev->dev_cl->id) { - case DIBUSB1_1: - case NOVAT_USB2: - case DTT200U: - break; - default: - dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); - break; - } - if (dib->fe_sleep) - return dib->fe_sleep(fe); - - return 0; -} - -int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode) -{ - u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode }; - return dibusb_readwrite_usb(dib,b,2,NULL,0); -} - -static int dibusb_urb_kill(struct usb_dibusb *dib) -{ - int i; -deb_info("trying to kill urbs\n"); - if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) { - for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) { - deb_info("killing URB no. %d.\n",i); - - /* stop the URB */ - usb_kill_urb(dib->urb_list[i]); - } - } else - deb_info(" URBs not killed.\n"); - dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT; - return 0; -} - -static int dibusb_urb_submit(struct usb_dibusb *dib) -{ - int i,ret; - if (dib->init_state & DIBUSB_STATE_URB_INIT) { - for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) { - deb_info("submitting URB no. %d\n",i); - if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) { - err("could not submit buffer urb no. %d - get them all back\n",i); - dibusb_urb_kill(dib); - return ret; - } - dib->init_state |= DIBUSB_STATE_URB_SUBMIT; - } - } - return 0; -} - -int dibusb_streaming(struct usb_dibusb *dib,int onoff) -{ - if (onoff) - dibusb_urb_submit(dib); - else - dibusb_urb_kill(dib); - - switch (dib->dibdev->dev_cl->id) { - case DIBUSB2_0: - case DIBUSB2_0B: - case NOVAT_USB2: - case UMT2_0: - if (onoff) - return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0); - else - return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0); - break; - default: - break; - } - return 0; -} - -int dibusb_urb_init(struct usb_dibusb *dib) -{ - int i,bufsize,def_pid_parse = 1; - - /* - * when reloading the driver w/o replugging the device - * a timeout occures, this helps - */ - usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd)); - usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd)); - usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data)); - - /* allocate the array for the data transfer URBs */ - dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL); - if (dib->urb_list == NULL) - return -ENOMEM; - memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *)); - - dib->init_state |= DIBUSB_STATE_URB_LIST; - - bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size; - deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize); - /* allocate the actual buffer for the URBs */ - if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) { - deb_info("not enough memory.\n"); - return -ENOMEM; - } - deb_info("allocation complete\n"); - memset(dib->buffer,0,bufsize); - - dib->init_state |= DIBUSB_STATE_URB_BUF; - - /* allocate and submit the URBs */ - for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) { - if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) { - return -ENOMEM; - } - - usb_fill_bulk_urb( dib->urb_list[i], dib->udev, - usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data), - &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size], - dib->dibdev->dev_cl->urb_buffer_size, - dibusb_urb_complete, dib); - - dib->urb_list[i]->transfer_flags = 0; - - dib->init_state |= DIBUSB_STATE_URB_INIT; - } - - /* dib->pid_parse here contains the value of the module parameter */ - /* decide if pid parsing can be deactivated: - * is possible (by device type) and wanted (by user) - */ - switch (dib->dibdev->dev_cl->id) { - case DIBUSB2_0: - case DIBUSB2_0B: - if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) { - def_pid_parse = 0; - info("running at HIGH speed, will deliver the complete TS."); - } else - info("will use pid_parsing."); - break; - default: - break; - } - /* from here on it contains the device and user decision */ - dib->pid_parse = def_pid_parse; - - return 0; -} - -int dibusb_urb_exit(struct usb_dibusb *dib) -{ - int i; - - dibusb_urb_kill(dib); - - if (dib->init_state & DIBUSB_STATE_URB_LIST) { - for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) { - if (dib->urb_list[i] != NULL) { - deb_info("freeing URB no. %d.\n",i); - /* free the URBs */ - usb_free_urb(dib->urb_list[i]); - } - } - /* free the urb array */ - kfree(dib->urb_list); - dib->init_state &= ~DIBUSB_STATE_URB_LIST; - } - - if (dib->init_state & DIBUSB_STATE_URB_BUF) - pci_free_consistent(NULL, - dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count, - dib->buffer,dib->dma_handle); - - dib->init_state &= ~DIBUSB_STATE_URB_BUF; - dib->init_state &= ~DIBUSB_STATE_URB_INIT; - return 0; -} diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h deleted file mode 100644 index c965b64fb1ab..000000000000 --- a/drivers/media/dvb/dibusb/dvb-dibusb.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * dvb-dibusb.h - * - * 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. - * - * for more information see dvb-dibusb-core.c . - */ -#ifndef __DVB_DIBUSB_H__ -#define __DVB_DIBUSB_H__ - -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb_demux.h" -#include "dvb_net.h" -#include "dmxdev.h" - -#include "dib3000.h" -#include "mt352.h" - -/* debug */ -#ifdef CONFIG_DVB_DIBCOM_DEBUG -#define dprintk(level,args...) \ - do { if ((dvb_dibusb_debug & level)) { printk(args); } } while (0) - -#define debug_dump(b,l) {\ - int i; \ - for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \ - deb_xfer("\n");\ -} - -#else -#define dprintk(args...) -#define debug_dump(b,l) -#endif - -extern int dvb_dibusb_debug; - -/* Version information */ -#define DRIVER_VERSION "0.3" -#define DRIVER_DESC "DiBcom based USB Budget DVB-T device" -#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" - -#define deb_info(args...) dprintk(0x01,args) -#define deb_xfer(args...) dprintk(0x02,args) -#define deb_alot(args...) dprintk(0x04,args) -#define deb_ts(args...) dprintk(0x08,args) -#define deb_err(args...) dprintk(0x10,args) -#define deb_rc(args...) dprintk(0x20,args) - -/* generic log methods - taken from usb.h */ -#undef err -#define err(format, arg...) printk(KERN_ERR "dvb-dibusb: " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO "dvb-dibusb: " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING "dvb-dibusb: " format "\n" , ## arg) - -struct dibusb_usb_controller { - const char *name; /* name of the usb controller */ - u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ -}; - -typedef enum { - DIBUSB1_1 = 0, - DIBUSB1_1_AN2235, - DIBUSB2_0, - UMT2_0, - DIBUSB2_0B, - NOVAT_USB2, - DTT200U, -} dibusb_class_t; - -typedef enum { - DIBUSB_TUNER_CABLE_THOMSON = 0, - DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5, - DIBUSB_TUNER_CABLE_LG_TDTP_E102P, - DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5, -} dibusb_tuner_t; - -typedef enum { - DIBUSB_DIB3000MB = 0, - DIBUSB_DIB3000MC, - DIBUSB_MT352, - DTT200U_FE, -} dibusb_demodulator_t; - -typedef enum { - DIBUSB_RC_NO = 0, - DIBUSB_RC_NEC_PROTOCOL, - DIBUSB_RC_HAUPPAUGE_PROTO, -} dibusb_remote_t; - -struct dibusb_tuner { - dibusb_tuner_t id; - - u8 pll_addr; /* tuner i2c address */ -}; -extern struct dibusb_tuner dibusb_tuner[]; - -#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4 -struct dibusb_demod { - dibusb_demodulator_t id; - - int pid_filter_count; /* counter of the internal pid_filter */ - u8 i2c_addrs[DIBUSB_POSSIBLE_I2C_ADDR_NUM]; /* list of possible i2c addresses of the demod */ -}; - -#define DIBUSB_MAX_TUNER_NUM 2 -struct dibusb_device_class { - dibusb_class_t id; - - const struct dibusb_usb_controller *usb_ctrl; /* usb controller */ - const char *firmware; /* valid firmware filenames */ - - int pipe_cmd; /* command pipe (read/write) */ - int pipe_data; /* data pipe */ - - int urb_count; /* number of data URBs to be submitted */ - int urb_buffer_size; /* the size of the buffer for each URB */ - - dibusb_remote_t remote_type; /* does this device have a ir-receiver */ - - struct dibusb_demod *demod; /* which demodulator is mount */ - struct dibusb_tuner *tuner; /* which tuner can be found here */ -}; - -#define DIBUSB_ID_MAX_NUM 15 -struct dibusb_usb_device { - const char *name; /* real name of the box */ - struct dibusb_device_class *dev_cl; /* which dibusb_device_class is this device part of */ - - struct usb_device_id *cold_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at pre firmware state */ - struct usb_device_id *warm_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at post firmware state */ -}; - -/* a PID for the pid_filter list, when in use */ -struct dibusb_pid -{ - int index; - u16 pid; - int active; -}; - -struct usb_dibusb { - /* usb */ - struct usb_device * udev; - - struct dibusb_usb_device * dibdev; - -#define DIBUSB_STATE_INIT 0x000 -#define DIBUSB_STATE_URB_LIST 0x001 -#define DIBUSB_STATE_URB_BUF 0x002 -#define DIBUSB_STATE_URB_INIT 0x004 -#define DIBUSB_STATE_DVB 0x008 -#define DIBUSB_STATE_I2C 0x010 -#define DIBUSB_STATE_REMOTE 0x020 -#define DIBUSB_STATE_URB_SUBMIT 0x040 - int init_state; - - int feedcount; - struct dib_fe_xfer_ops xfer_ops; - - struct dibusb_tuner *tuner; - - struct urb **urb_list; - u8 *buffer; - dma_addr_t dma_handle; - - /* I2C */ - struct i2c_adapter i2c_adap; - - /* locking */ - struct semaphore usb_sem; - struct semaphore i2c_sem; - - /* dvb */ - struct dvb_adapter adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct dvb_frontend* fe; - - 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; - int last_event; - int last_state; /* for Hauppauge RC protocol */ - int repeat_key_count; - int rc_key_repeat_count; /* module parameter */ - - /* module parameters */ - int pid_parse; - int rc_query_interval; -}; - -/* commonly used functions in the separated files */ - -/* dvb-dibusb-firmware.c */ -int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev); - -/* dvb-dibusb-remote.c */ -int dibusb_remote_exit(struct usb_dibusb *dib); -int dibusb_remote_init(struct usb_dibusb *dib); - -/* dvb-dibusb-fe-i2c.c */ -int dibusb_fe_init(struct usb_dibusb* dib); -int dibusb_fe_exit(struct usb_dibusb *dib); -int dibusb_i2c_init(struct usb_dibusb *dib); -int dibusb_i2c_exit(struct usb_dibusb *dib); - -/* dvb-dibusb-dvb.c */ -void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs); -int dibusb_dvb_init(struct usb_dibusb *dib); -int dibusb_dvb_exit(struct usb_dibusb *dib); - -/* dvb-dibusb-usb.c */ -int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen); -int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len); - -int dibusb_hw_wakeup(struct dvb_frontend *); -int dibusb_hw_sleep(struct dvb_frontend *); -int dibusb_set_streaming_mode(struct usb_dibusb *,u8); -int dibusb_streaming(struct usb_dibusb *,int); - -int dibusb_urb_init(struct usb_dibusb *); -int dibusb_urb_exit(struct usb_dibusb *); - -/* dvb-fe-dtt200u.c */ -struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *,struct dib_fe_xfer_ops *); - -/* i2c and transfer stuff */ -#define DIBUSB_I2C_TIMEOUT 5000 - -/* - * 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) - * - * first byte of byte_buffer shows the status (0x00, 0x01, 0x02) - */ -#define DIBUSB_REQ_POLL_REMOTE 0x04 - -#define DIBUSB_RC_NEC_EMPTY 0x00 -#define DIBUSB_RC_NEC_KEY_PRESSED 0x01 -#define DIBUSB_RC_NEC_KEY_REPEATED 0x02 - -/* 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 - -#endif diff --git a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c b/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c deleted file mode 100644 index 1872aa6d200a..000000000000 --- a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * dvb-dtt200u-fe.c is a driver which implements the frontend-part of the - * Yakumo/Typhoon/Hama USB2.0 boxes. It is hard-wired to the dibusb-driver as - * it uses the usb-transfer functions directly (maybe creating a - * generic-dvb-usb-lib for all usb-drivers will be reduce some more code.) - * - * Copyright (C) 2005 Patrick Boettcher - * - * see dvb-dibusb-core.c for copyright details. - */ - -/* guessed protocol description (reverse engineered): - * read - * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 - * 81 - - * 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 - * - * write - * 02 - bandwidth - * 03 - frequency (divided by 250000) - * 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) - */ - -#include "dvb-dibusb.h" -#include "dvb_frontend.h" - -struct dtt200u_fe_state { - struct usb_dibusb *dib; - - 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[1] = { 0x81 }; - u8 br[3] = { 0 }; -// u8 bdeb[5] = { 0 }; - - dibusb_readwrite_usb(state->dib,bw,1,br,3); - 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]",0x81); - break; - } - -// bw[0] = 0x88; -// dibusb_readwrite_usb(state->dib,bw,1,bdeb,5); - -// 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[1] = { 0x8d }; - *ber = 0; - dibusb_readwrite_usb(state->dib,bw,1,(u8*) ber, 3); - 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[1] = { 0x8c }; - *unc = 0; - dibusb_readwrite_usb(state->dib,bw,1,(u8*) unc, 3); - 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[1] = { 0x8a }; - u8 b; - dibusb_readwrite_usb(state->dib,bw,1,&b, 1); - *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[1] = { 0x89 }; - u8 br[1] = { 0 }; - dibusb_readwrite_usb(state->dib,bw,1,br,1); - *snr = ((0xff - br[0]) << 8) | (0xff - br[0]); - return 0; -} - -static int dtt200u_fe_init(struct dvb_frontend* fe) -{ - struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 b[] = { 0x01 }; - return dibusb_write_usb(state->dib,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] = { 0x03, 0 }, freqbuf[3] = { 0x02, 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; - dibusb_write_usb(state->dib,bwbuf,2); - - freqbuf[1] = freq & 0xff; - freqbuf[2] = (freq >> 8) & 0xff; - dibusb_write_usb(state->dib,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 int dtt200u_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) -{ - struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; - u8 b_pid[4]; - pid = onoff ? pid : 0; - - b_pid[0] = 0x04; - b_pid[1] = index; - b_pid[2] = pid & 0xff; - b_pid[3] = (pid >> 8) & 0xff; - - dibusb_write_usb(state->dib,b_pid,4); - return 0; -} - -static int dtt200u_fifo_control(struct dvb_frontend *fe, int onoff) -{ - struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv; - u8 b_streaming[2] = { 0x08, onoff }; - u8 b_rst_pid[1] = { 0x05 }; - - dibusb_write_usb(state->dib,b_streaming,2); - - if (!onoff) - dibusb_write_usb(state->dib,b_rst_pid,1); - return 0; -} - -static struct dvb_frontend_ops dtt200u_fe_ops; - -struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfer_ops *xfer_ops) -{ - 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->dib = dib; - - state->frontend.ops = &dtt200u_fe_ops; - state->frontend.demodulator_priv = state; - - xfer_ops->fifo_ctrl = dtt200u_fifo_control; - xfer_ops->pid_ctrl = dtt200u_pid_control; - - 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, -}; -- cgit v1.2.2 From 776338e121b9db3156bfb4e21622a0219bbab9d4 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 23 Jun 2005 22:02:35 -0700 Subject: [PATCH] dvb: Add generalized dvb-usb driver Add generalized dvb-usb driver which supports a wide variety of devices. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/Kconfig | 1 + drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/dvb-usb/Kconfig | 99 +++++++++ drivers/media/dvb/dvb-usb/Makefile | 30 +++ drivers/media/dvb/dvb-usb/a800.c | 176 +++++++++++++++ drivers/media/dvb/dvb-usb/dibusb-common.c | 272 +++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dibusb-mb.c | 316 +++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dibusb-mc.c | 116 ++++++++++ drivers/media/dvb/dvb-usb/dibusb.h | 122 +++++++++++ drivers/media/dvb/dvb-usb/digitv.c | 282 ++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/digitv.h | 65 ++++++ drivers/media/dvb/dvb-usb/dtt200u-fe.c | 206 +++++++++++++++++ drivers/media/dvb/dvb-usb/dtt200u.c | 171 +++++++++++++++ drivers/media/dvb/dvb-usb/dtt200u.h | 66 ++++++ drivers/media/dvb/dvb-usb/dvb-usb-common.h | 44 ++++ drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 210 ++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-firmware.c | 100 +++++++++ drivers/media/dvb/dvb-usb/dvb-usb-i2c.c | 118 ++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 83 +++++++ drivers/media/dvb/dvb-usb/dvb-usb-init.c | 211 ++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 175 +++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 211 ++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb.h | 315 ++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/nova-t-usb2.c | 236 ++++++++++++++++++++ drivers/media/dvb/dvb-usb/umt-010.c | 162 ++++++++++++++ drivers/media/dvb/dvb-usb/vp7045-fe.c | 196 +++++++++++++++++ drivers/media/dvb/dvb-usb/vp7045.c | 263 ++++++++++++++++++++++ drivers/media/dvb/dvb-usb/vp7045.h | 78 +++++++ drivers/media/dvb/frontends/dib3000-common.c | 2 +- drivers/media/dvb/frontends/dib3000.h | 5 +- drivers/media/dvb/frontends/dib3000mb.c | 20 +- drivers/media/dvb/frontends/dib3000mb_priv.h | 2 +- drivers/media/dvb/frontends/dib3000mc.c | 29 +-- drivers/media/dvb/frontends/dvb-pll.c | 94 +++++++- drivers/media/dvb/frontends/dvb-pll.h | 9 +- 35 files changed, 4435 insertions(+), 52 deletions(-) create mode 100644 drivers/media/dvb/dvb-usb/Kconfig create mode 100644 drivers/media/dvb/dvb-usb/Makefile create mode 100644 drivers/media/dvb/dvb-usb/a800.c create mode 100644 drivers/media/dvb/dvb-usb/dibusb-common.c create mode 100644 drivers/media/dvb/dvb-usb/dibusb-mb.c create mode 100644 drivers/media/dvb/dvb-usb/dibusb-mc.c create mode 100644 drivers/media/dvb/dvb-usb/dibusb.h create mode 100644 drivers/media/dvb/dvb-usb/digitv.c create mode 100644 drivers/media/dvb/dvb-usb/digitv.h create mode 100644 drivers/media/dvb/dvb-usb/dtt200u-fe.c create mode 100644 drivers/media/dvb/dvb-usb/dtt200u.c create mode 100644 drivers/media/dvb/dvb-usb/dtt200u.h create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-common.h create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-dvb.c create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-firmware.c create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-i2c.c create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-ids.h create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-init.c create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-remote.c create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb-urb.c create mode 100644 drivers/media/dvb/dvb-usb/dvb-usb.h create mode 100644 drivers/media/dvb/dvb-usb/nova-t-usb2.c create mode 100644 drivers/media/dvb/dvb-usb/umt-010.c create mode 100644 drivers/media/dvb/dvb-usb/vp7045-fe.c create mode 100644 drivers/media/dvb/dvb-usb/vp7045.c create mode 100644 drivers/media/dvb/dvb-usb/vp7045.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index b81abdfde378..01387f883cdf 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -27,6 +27,7 @@ source "drivers/media/dvb/ttpci/Kconfig" comment "Supported USB Adapters" depends on DVB_CORE && USB +source "drivers/media/dvb/dvb-usb/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" source "drivers/media/dvb/cinergyT2/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index d2dd914f7776..3c6ff1619103 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # 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/ diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig new file mode 100644 index 000000000000..8aa32f6e447b --- /dev/null +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -0,0 +1,99 @@ +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 + + + 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 () 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 () 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). diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile new file mode 100644 index 000000000000..d65b50f9abb0 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -0,0 +1,30 @@ +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/ diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c new file mode 100644 index 000000000000..a3542935604f --- /dev/null +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -0,0 +1,176 @@ +/* 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 "); +MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c new file mode 100644 index 000000000000..63b626f70c81 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -0,0 +1,272 @@ +/* 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); diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c new file mode 100644 index 000000000000..fd103e4746e1 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -0,0 +1,316 @@ +/* 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 "); +MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c new file mode 100644 index 000000000000..aad8ed3fe005 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -0,0 +1,116 @@ +/* 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 "); +MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h new file mode 100644 index 000000000000..6611f62977c0 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dibusb.h @@ -0,0 +1,122 @@ +/* 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 diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c new file mode 100644 index 000000000000..5acf3fde9522 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -0,0 +1,282 @@ +/* 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 "); +MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h new file mode 100644 index 000000000000..477ee428a70e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/digitv.h @@ -0,0 +1,65 @@ +#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: + * VV B0 B1 B2 B3 + * + * second message of a read + * VV 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 diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c new file mode 100644 index 000000000000..d17d768038c6 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -0,0 +1,206 @@ +/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T + * USB2.0 receiver. + * + * Copyright (C) 2005 Patrick Boettcher + * + * 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, +}; diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c new file mode 100644 index 000000000000..fb2b5a2da137 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -0,0 +1,171 @@ +/* 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 "); +MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h new file mode 100644 index 000000000000..ed4142071518 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtt200u.h @@ -0,0 +1,66 @@ +/* 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 - + * 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 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h new file mode 100644 index 000000000000..67e0d73fbceb --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -0,0 +1,44 @@ +/* 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 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c new file mode 100644 index 000000000000..bdd72f779707 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -0,0 +1,210 @@ +/* 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; +} diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c new file mode 100644 index 000000000000..5244e39770a0 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c @@ -0,0 +1,100 @@ +/* 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 +#include + +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; +} diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c new file mode 100644 index 000000000000..9f0a8d90d146 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -0,0 +1,118 @@ +/* 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); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h new file mode 100644 index 000000000000..bcb34191868b --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -0,0 +1,83 @@ +/* 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 diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c new file mode 100644 index 000000000000..3aadec974cf1 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -0,0 +1,211 @@ +/* + * 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 "); +MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c new file mode 100644 index 000000000000..9f1e23f82bae --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -0,0 +1,175 @@ +/* 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); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c new file mode 100644 index 000000000000..83d476fb410a --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -0,0 +1,211 @@ +/* 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; +} diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h new file mode 100644 index 000000000000..abcee1943f64 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -0,0 +1,315 @@ +/* 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 +#include +#include +#include + +#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 diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c new file mode 100644 index 000000000000..9d83781aef95 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -0,0 +1,236 @@ +/* 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 "); +MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c new file mode 100644 index 000000000000..aa560422ce7c --- /dev/null +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -0,0 +1,162 @@ +/* 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 "); +MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c new file mode 100644 index 000000000000..2746edfeccba --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c @@ -0,0 +1,196 @@ +/* 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, +}; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c new file mode 100644 index 000000000000..02ecc9a8e3b6 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -0,0 +1,263 @@ +/* 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 "); +MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h new file mode 100644 index 000000000000..9ce21a20fa86 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp7045.h @@ -0,0 +1,78 @@ +/* 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 diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c index 47ab02e133d1..1a4f1f7c228a 100644 --- a/drivers/media/dvb/frontends/dib3000-common.c +++ b/drivers/media/dvb/frontends/dib3000-common.c @@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ }; MODULE_AUTHOR("Patrick Boettcher config.pll_addr && state->config.pll_set) { - dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); - state->config.pll_set(fe, fep, NULL); - dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); + if (tuner && state->config.pll_set) { + state->config.pll_set(fe, fep); deb_setf("bandwidth: "); switch (ofdm->bandwidth) { @@ -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); - if (state->config.pll_init) { - dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); - state->config.pll_init(fe,NULL); - dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); - } + if (state->config.pll_init) + state->config.pll_init(fe); return 0; } @@ -623,7 +616,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) { struct dib3000_state* state = fe->demodulator_priv; - *unc = rd(DIB3000MB_REG_UNC); + *unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE); return 0; } @@ -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) { tune->min_delay_ms = 800; - tune->step_size = 166667; - tune->max_drift = 166667 * 2; - return 0; } diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h index 57e61aa5b07b..999b19047816 100644 --- a/drivers/media/dvb/frontends/dib3000mb_priv.h +++ b/drivers/media/dvb/frontends/dib3000mb_priv.h @@ -294,7 +294,7 @@ static u16 dib3000mb_reg_filter_coeffs[] = { static u16 dib3000mb_filter_coeffs[] = { 226, 160, 29, - 979, 998, 19, + 979, 998, 19, 22, 1019, 1006, 1022, 12, 6, 1017, 1017, 3, diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 888f10a5e96b..cd33705a4320 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -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_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, fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) { @@ -463,10 +461,8 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, int search_state,auto_val; u16 val; - if (tuner && state->config.pll_addr && 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,NULL); - dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); + if (tuner && state->config.pll_set) { /* initial call from dvb */ + state->config.pll_set(fe,fep); state->last_tuned_freq = fep->frequency; // if (!scanboost) { @@ -554,19 +550,15 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, dib3000mc_set_adp_cfg(state,ofdm->constellation); wr_foreach(dib3000mc_reg_offset, dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); - - } return 0; } 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"); - state = fe->demodulator_priv; state->timing_offset = 0; state->timing_offset_comp_done = 0; @@ -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); -/* if (state->config->pll_init) { - dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); - state->config->pll_init(fe,NULL); - dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); - }*/ + if (state->config.pll_init) + state->config.pll_init(fe); + deb_info("init end\n"); return 0; } @@ -688,7 +678,7 @@ static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) { struct dib3000_state* state = fe->demodulator_priv; - *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT); + *unc = rd(DIB3000MC_REG_PACKET_ERRORS); return 0; } @@ -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) { - tune->min_delay_ms = 2000; - tune->step_size = 166667; - tune->max_drift = 166667 * 2; - + tune->min_delay_ms = 1000; return 0; } diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 2a3c2ce7b2aa..f73b5f48e235 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -1,6 +1,4 @@ /* - * $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $ - * * descriptions + helper functions for simple dvb plls. * * (c) 2004 Gerd Knorr [SuSE Labs] @@ -114,6 +112,92 @@ struct dvb_pll_desc 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 */ @@ -160,9 +244,3 @@ EXPORT_SYMBOL(dvb_pll_configure); MODULE_DESCRIPTION("dvb pll library"); MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index c4c3c56c4a81..b796778624b6 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -1,5 +1,5 @@ /* - * $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__ @@ -17,7 +17,7 @@ struct dvb_pll_desc { u32 stepsize; u8 cb1; u8 cb2; - } entries[9]; + } entries[12]; }; extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; @@ -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_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, u32 freq, int bandwidth); -- cgit v1.2.2 From f756ead1366092b73467fe3b1fb23f61034e94f9 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 23 Jun 2005 22:02:38 -0700 Subject: [PATCH] dvb-usb: fix init error checking Fix error checking during initialization. Thanks to Gerolf Wendland for discovering. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index fd103e4746e1..a0ffbb59fa14 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -81,7 +81,7 @@ 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,&dibusb1_1_an2235_properties,THIS_MODULE) == 0 || dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE) == 0) return 0; -- cgit v1.2.2 From cc89c229d9d7ec63cd33e960c20e75b77bc987d0 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 23 Jun 2005 22:02:39 -0700 Subject: [PATCH] dvb: dvb_frontend: use time_after() Use time_after() macro. Signed-off-by: Marcelo Feitoza Parisi Signed-off-by: Domen Puncer Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d19301d90a09..d6b7a9de471e 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -327,7 +328,8 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe) return 1; if (fepriv->dvbdev->writers == 1) - if (jiffies - fepriv->release_jiffies > dvb_shutdown_timeout * HZ) + if (time_after(jiffies, fepriv->release_jiffies + + dvb_shutdown_timeout * HZ)) return 1; return 0; -- cgit v1.2.2 From 55f51efdb696ff6e9d2056377d05268a97f3d4e4 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 23 Jun 2005 22:02:41 -0700 Subject: [PATCH] dvb: flexcop: add BCM3510 ATSC frontend support for Air2PC card Added support for the Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator used in the first generation of Air2PC ATSC PCI-cards/USB-boxes made by B2C2. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/Kconfig | 1 + drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 26 +- drivers/media/dvb/b2c2/flexcop-misc.c | 11 +- drivers/media/dvb/b2c2/flexcop-reg.h | 3 +- drivers/media/dvb/frontends/Kconfig | 8 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/bcm3510.c | 853 +++++++++++++++++++++++++++++ drivers/media/dvb/frontends/bcm3510.h | 40 ++ drivers/media/dvb/frontends/bcm3510_priv.h | 460 ++++++++++++++++ 9 files changed, 1389 insertions(+), 14 deletions(-) create mode 100644 drivers/media/dvb/frontends/bcm3510.c create mode 100644 drivers/media/dvb/frontends/bcm3510.h create mode 100644 drivers/media/dvb/frontends/bcm3510_priv.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 99bd675df955..fafd0ab3a28f 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -6,6 +6,7 @@ config DVB_B2C2_FLEXCOP select DVB_MT312 select DVB_NXT2002 select DVB_STV0297 + select DVB_BCM3510 help Support for the digital TV receiver chip made by B2C2 Inc. included in Technisats PCI cards and USB boxes. diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 71be400e9aeb..0410cc96a48e 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -10,6 +10,7 @@ #include "stv0299.h" #include "mt352.h" #include "nxt2002.h" +#include "bcm3510.h" #include "stv0297.h" #include "mt312.h" @@ -285,21 +286,25 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front } static struct mt352_config samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, - .pll_set = samsung_tdtc9251dh0_pll_set, + .demod_init = samsung_tdtc9251dh0_demod_init, + .pll_set = samsung_tdtc9251dh0_pll_set, }; -static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) { struct flexcop_device *fc = fe->dvb->priv; return request_firmware(fw, name, fc->dev); } static struct nxt2002_config samsung_tbmv_config = { - .demod_address = 0x0a, - .request_firmware = nxt2002_request_firmware, + .demod_address = 0x0a, + .request_firmware = flexcop_fe_request_firmware, +}; + +static struct bcm3510_config air2pc_atsc_first_gen_config = { + .demod_address = 0x0f, + .request_firmware = flexcop_fe_request_firmware, }; static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) @@ -354,11 +359,16 @@ int flexcop_frontend_init(struct flexcop_device *fc) fc->dev_type = FC_AIR_DVB; info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); } else - /* try the air atsc (nxt2002) */ + /* try the air atsc 2nd generation (nxt2002) */ if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) { - fc->dev_type = FC_AIR_ATSC; + fc->dev_type = FC_AIR_ATSC2; info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); } else + /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ + if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) { + fc->dev_type = FC_AIR_ATSC1; + info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address); + } else /* try the cable dvb (stv0297) */ if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) { fc->dev_type = FC_CABLE; diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c index 19e06da46774..23082545651f 100644 --- a/drivers/media/dvb/b2c2/flexcop-misc.c +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -45,11 +45,12 @@ const char *flexcop_revision_names[] = { const char *flexcop_device_names[] = { "Unkown device", - "AirStar 2 DVB-T", - "AirStar 2 ATSC", - "SkyStar 2 DVB-S", - "SkyStar 2 DVB-S (old version)", - "CableStar 2 DVB-C", + "Air2PC/AirStar 2 DVB-T", + "Air2PC/AirStar 2 ATSC 1st generation", + "Air2PC/AirStar 2 ATSC 2nd generation", + "Sky2PC/SkyStar 2 DVB-S", + "Sky2PC/SkyStar 2 DVB-S (old version)", + "Cable2PC/CableStar 2 DVB-C", }; const char *flexcop_bus_names[] = { diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 5e131be55cb3..75b50f21afe6 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -21,7 +21,8 @@ extern const char *flexcop_revision_names[]; typedef enum { FC_UNK = 0, FC_AIR_DVB, - FC_AIR_ATSC, + FC_AIR_ATSC1, + FC_AIR_ATSC2, FC_SKY, FC_SKY_OLD, FC_CABLE, diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 75fb556ec01f..b4fddf513ebe 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -173,4 +173,12 @@ config DVB_OR51132 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_BCM3510 + tristate "Broadcom BCM3510" + depends on DVB_CORE + select FW_LOADER + help + An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to + support this frontend. + endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 7f8784870eab..91d6d3576d3d 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_DVB_STV0297) += stv0297.o obj-$(CONFIG_DVB_NXT2002) += nxt2002.o obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o +obj-$(CONFIG_DVB_BCM3510) += bcm3510.o diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c new file mode 100644 index 000000000000..f5fdc5c3e605 --- /dev/null +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -0,0 +1,853 @@ +/* + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) + * + * Copyright (C) 2001-5, B2C2 inc. + * + * GPL/Linux driver written by Patrick Boettcher + * + * This driver is "hard-coded" to be used with the 1st generation of + * Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming + * (Panasonic CT10S) is located here, which is actually wrong. Unless there is + * another device with a BCM3510, this is no problem. + * + * The driver works also with QAM64 DVB-C, but had an unreasonable high + * UNC. (Tested with the Air2PC ATSC 1st generation) + * + * You'll need a firmware for this driver in order to get it running. It is + * called "dvb-fe-bcm3510-01.fw". + * + * 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; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 675 Mass + * Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "bcm3510.h" +#include "bcm3510_priv.h" + +struct bcm3510_state { + + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct bcm3510_config* config; + struct dvb_frontend frontend; + + /* demodulator private data */ + struct semaphore hab_sem; + u8 firmware_loaded:1; + + unsigned long next_status_check; + unsigned long status_check_interval; + struct bcm3510_hab_cmd_status1 status1; + struct bcm3510_hab_cmd_status2 status2; +}; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able))."); + +#define dprintk(level,x...) if (level & debug) printk(x) +#define dbufout(b,l,m) {\ + int i; \ + for (i = 0; i < l; i++) \ + m("%02x ",b[i]); \ +} +#define deb_info(args...) dprintk(0x01,args) +#define deb_i2c(args...) dprintk(0x02,args) +#define deb_hab(args...) dprintk(0x04,args) + +/* transfer functions */ +static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) +{ + u8 b[256]; + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 }; + + b[0] = reg; + memcpy(&b[1],buf,len); + + deb_i2c("i2c wr %02x: ",reg); + dbufout(buf,len,deb_i2c); + deb_i2c("\n"); + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + + deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n", + __FUNCTION__, state->config->demod_address, reg, err); + return -EREMOTEIO; + } + + return 0; +} + +static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len) +{ + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } + }; + int err; + + memset(buf,0,len); + + if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { + deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n", + __FUNCTION__, state->config->demod_address, reg, err); + return -EREMOTEIO; + } + deb_i2c("i2c rd %02x: ",reg); + dbufout(buf,len,deb_i2c); + deb_i2c("\n"); + + return 0; +} + +static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v) +{ + return bcm3510_writebytes(state,reg,&v.raw,1); +} + +static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v) +{ + return bcm3510_readbytes(state,reg,&v->raw,1); +} + +/* Host Access Buffer transfers */ +static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len) +{ + bcm3510_register_value v; + int ret,i; + + v.HABADR_a6.HABADR = 0; + if ((ret = bcm3510_writeB(st,0xa6,v)) < 0) + return ret; + + for (i = 0; i < len; i++) { + if ((ret = bcm3510_readB(st,0xa7,&v)) < 0) + return ret; + buf[i] = v.HABDATA_a7; + } + return 0; +} + +static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len) +{ + bcm3510_register_value v,hab; + int ret,i; + unsigned long t; + +/* Check if any previous HAB request still needs to be serviced by the + * Aquisition Processor before sending new request */ + if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) + return ret; + if (v.HABSTAT_a8.HABR) { + deb_info("HAB is running already - clearing it.\n"); + v.HABSTAT_a8.HABR = 0; + bcm3510_writeB(st,0xa8,v); +// return -EBUSY; + } + +/* Send the start HAB Address (automatically incremented after write of + * HABDATA) and write the HAB Data */ + hab.HABADR_a6.HABADR = 0; + if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0) + return ret; + + for (i = 0; i < len; i++) { + hab.HABDATA_a7 = buf[i]; + if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0) + return ret; + } + +/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to + * be written) */ + v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1; + if ((ret = bcm3510_writeB(st,0xa8,v)) < 0) + return ret; + +/* Polling method: Wait until the AP finishes processing the HAB request */ + t = jiffies + 1*HZ; + while (time_before(jiffies, t)) { + deb_info("waiting for HAB to complete\n"); + msleep(10); + if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) + return ret; + + if (!v.HABSTAT_a8.HABR) + return 0; + } + + deb_info("send_request execution timed out.\n"); + return -ETIMEDOUT; +} + +static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen) +{ + u8 ob[olen+2],ib[ilen+2]; + int ret = 0; + + ob[0] = cmd; + ob[1] = msgid; + memcpy(&ob[2],obuf,olen); + + deb_hab("hab snd: "); + dbufout(ob,olen+2,deb_hab); + deb_hab("\n"); + + if (down_interruptible(&st->hab_sem) < 0) + return -EAGAIN; + + if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 || + (ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0) + goto error; + + deb_hab("hab get: "); + dbufout(ib,ilen+2,deb_hab); + deb_hab("\n"); + + memcpy(ibuf,&ib[2],ilen); +error: + up(&st->hab_sem); + return ret; +} + +#if 0 +/* not needed, we use a semaphore to prevent HAB races */ +static int bcm3510_is_ap_ready(struct bcm3510_state *st) +{ + bcm3510_register_value ap,hab; + int ret; + + if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 || + (ret = bcm3510_readB(st,0xa2,&ap) < 0)) + return ret; + + if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) { + deb_info("AP is busy\n"); + return -EBUSY; + } + + return 0; +} +#endif + +static int bcm3510_bert_reset(struct bcm3510_state *st) +{ + bcm3510_register_value b; + int ret; + + if ((ret < bcm3510_readB(st,0xfa,&b)) < 0) + return ret; + + b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); + b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b); + b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); + b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b); + + /* clear residual bit counter TODO */ + return 0; +} + +static int bcm3510_refresh_state(struct bcm3510_state *st) +{ + if (time_after(jiffies,st->next_status_check)) { + bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1)); + bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2)); + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + + *status = 0; + if (st->status1.STATUS1.RECEIVER_LOCK) + *status |= FE_HAS_LOCK | FE_HAS_SYNC; + + if (st->status1.STATUS1.FEC_LOCK) + *status |= FE_HAS_VITERBI; + + if (st->status1.STATUS1.OUT_PLL_LOCK) + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1500; + else /* more frequently checks if no lock has been achieved yet */ + st->status_check_interval = 500; + + deb_info("real_status: %02x\n",*status); + return 0; +} + +static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + + *ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2; + return 0; +} + +static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + *unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1; + return 0; +} + +static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct bcm3510_state* st = fe->demodulator_priv; + s32 t; + + bcm3510_refresh_state(st); + t = st->status2.SIGNAL; + + if (t > 190) + t = 190; + if (t < 90) + t = 90; + + t -= 90; + t = t * 0xff / 100; + /* normalize if necessary */ + *strength = (t << 8) | t; + return 0; +} + +static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_refresh_state(st); + + *snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8); + return 0; +} + +/* tuner frontend programming */ +static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a) +{ + struct bcm3510_hab_cmd_tune c; + memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune)); + +/* I2C Mode disabled, set 16 control / Data pairs */ + c.length = 0x10; + c.clock_width = 0; +/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to + * logic high (as Configuration) */ + c.misc = 0x10; +/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */ + c.TUNCTL_state = 0x40; + +/* PRESCALER DEVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */ + c.ctl_dat[0].ctrl.size = BITS_8; + c.ctl_dat[0].data = 0x80 | bc; + +/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */ + c.ctl_dat[1].ctrl.size = BITS_8; + c.ctl_dat[1].data = 4; + +/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */ + c.ctl_dat[2].ctrl.size = BITS_3; + c.ctl_dat[2].data = 0x20; + +/* control CS0 pin, pulse byte ? */ + c.ctl_dat[3].ctrl.size = BITS_3; + c.ctl_dat[3].ctrl.clk_off = 1; + c.ctl_dat[3].ctrl.cs0 = 1; + c.ctl_dat[3].data = 0x40; + +/* PGM_S18 to PGM_S11 */ + c.ctl_dat[4].ctrl.size = BITS_8; + c.ctl_dat[4].data = n >> 3; + +/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */ + c.ctl_dat[5].ctrl.size = BITS_8; + c.ctl_dat[5].data = ((n & 0x7) << 5) | (a >> 2); + +/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */ + c.ctl_dat[6].ctrl.size = BITS_3; + c.ctl_dat[6].data = (a << 6) & 0xdf; + +/* control CS0 pin, pulse byte ? */ + c.ctl_dat[7].ctrl.size = BITS_3; + c.ctl_dat[7].ctrl.clk_off = 1; + c.ctl_dat[7].ctrl.cs0 = 1; + c.ctl_dat[7].data = 0x40; + +/* PRESCALER DEVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */ + c.ctl_dat[8].ctrl.size = BITS_8; + c.ctl_dat[8].data = 0x80; + +/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */ + c.ctl_dat[9].ctrl.size = BITS_8; + c.ctl_dat[9].data = 0x10; + +/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */ + c.ctl_dat[10].ctrl.size = BITS_3; + c.ctl_dat[10].data = 0x20; + +/* pulse byte */ + c.ctl_dat[11].ctrl.size = BITS_3; + c.ctl_dat[11].ctrl.clk_off = 1; + c.ctl_dat[11].ctrl.cs1 = 1; + c.ctl_dat[11].data = 0x40; + +/* PGM_S18 to PGM_S11 */ + c.ctl_dat[12].ctrl.size = BITS_8; + c.ctl_dat[12].data = 0x2a; + +/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */ + c.ctl_dat[13].ctrl.size = BITS_8; + c.ctl_dat[13].data = 0x8e; + +/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */ + c.ctl_dat[14].ctrl.size = BITS_3; + c.ctl_dat[14].data = 0; + +/* Pulse Byte */ + c.ctl_dat[15].ctrl.size = BITS_3; + c.ctl_dat[15].ctrl.clk_off = 1; + c.ctl_dat[15].ctrl.cs1 = 1; + c.ctl_dat[15].data = 0x40; + + return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0); +} + +static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq) +{ + u8 bc,a; + u16 n; + s32 YIntercept,Tfvco1; + + freq /= 1000; + + deb_info("%dkHz:",freq); + /* set Band Switch */ + if (freq <= 168000) + bc = 0x1c; + else if (freq <= 378000) + bc = 0x2c; + else + bc = 0x30; + + if (freq >= 470000) { + freq -= 470001; + YIntercept = 18805; + } else if (freq >= 90000) { + freq -= 90001; + YIntercept = 15005; + } else if (freq >= 76000){ + freq -= 76001; + YIntercept = 14865; + } else { + freq -= 54001; + YIntercept = 14645; + } + + Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10; + + n = Tfvco1 >> 6; + a = Tfvco1 & 0x3f; + + deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a); + if (n >= 16 && n <= 2047) + return bcm3510_tuner_cmd(st,bc,n,a); + + return -EINVAL; +} + +static int bcm3510_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct bcm3510_state* st = fe->demodulator_priv; + struct bcm3510_hab_cmd_ext_acquire cmd; + struct bcm3510_hab_cmd_bert_control bert; + int ret; + + memset(&cmd,0,sizeof(cmd)); + switch (p->u.vsb.modulation) { + case QAM_256: + cmd.ACQUIRE0.MODE = 0x1; + cmd.ACQUIRE1.SYM_RATE = 0x1; + cmd.ACQUIRE1.IF_FREQ = 0x1; + break; + case QAM_64: + cmd.ACQUIRE0.MODE = 0x2; + cmd.ACQUIRE1.SYM_RATE = 0x2; + cmd.ACQUIRE1.IF_FREQ = 0x1; + break; +/* case QAM_256: + cmd.ACQUIRE0.MODE = 0x3; + break; + case QAM_128: + cmd.ACQUIRE0.MODE = 0x4; + break; + case QAM_64: + cmd.ACQUIRE0.MODE = 0x5; + break; + case QAM_32: + cmd.ACQUIRE0.MODE = 0x6; + break; + case QAM_16: + cmd.ACQUIRE0.MODE = 0x7; + break;*/ + case VSB_8: + cmd.ACQUIRE0.MODE = 0x8; + cmd.ACQUIRE1.SYM_RATE = 0x0; + cmd.ACQUIRE1.IF_FREQ = 0x0; + break; + case VSB_16: + cmd.ACQUIRE0.MODE = 0x9; + cmd.ACQUIRE1.SYM_RATE = 0x0; + cmd.ACQUIRE1.IF_FREQ = 0x0; + default: + return -EINVAL; + }; + cmd.ACQUIRE0.OFFSET = 0; + cmd.ACQUIRE0.NTSCSWEEP = 1; + cmd.ACQUIRE0.FA = 1; + cmd.ACQUIRE0.BW = 0; + +/* if (enableOffset) { + cmd.IF_OFFSET0 = xx; + cmd.IF_OFFSET1 = xx; + + cmd.SYM_OFFSET0 = xx; + cmd.SYM_OFFSET1 = xx; + if (enableNtscSweep) { + cmd.NTSC_OFFSET0; + cmd.NTSC_OFFSET1; + } + } */ + bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0); + +/* doing it with different MSGIDs, data book and source differs */ + bert.BE = 0; + bert.unused = 0; + bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0); + bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0); + + bcm3510_bert_reset(st); + + if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) + return ret; + + memset(&st->status1,0,sizeof(st->status1)); + memset(&st->status2,0,sizeof(st->status2)); + st->status_check_interval = 500; + +/* Give the AP some time */ + msleep(200); + + return 0; +} + +static int bcm3510_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) +{ + s->min_delay_ms = 1000; + s->step_size = 0; + s->max_drift = 0; + return 0; +} + +static void bcm3510_release(struct dvb_frontend* fe) +{ + struct bcm3510_state* state = fe->demodulator_priv; + kfree(state); +} + +/* firmware download: + * firmware file is build up like this: + * 16bit addr, 16bit length, 8byte of length + */ +#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw" + +static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, u8 *b, u16 len) +{ + int ret = 0,i; + bcm3510_register_value vH, vL,vD; + + vH.MADRH_a9 = addr >> 8; + vL.MADRL_aa = addr; + if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret; + if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret; + + for (i = 0; i < len; i++) { + vD.MDATA_ab = b[i]; + if ((ret = bcm3510_writeB(st,0xab,vD)) < 0) + return ret; + } + + return 0; +} + +static int bcm3510_download_firmware(struct dvb_frontend* fe) +{ + struct bcm3510_state* st = fe->demodulator_priv; + const struct firmware *fw; + u16 addr,len; + u8 *b; + int ret,i; + + deb_info("requesting firmware\n"); + if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) { + err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); + return ret; + } + deb_info("got firmware: %d\n",fw->size); + + b = fw->data; + for (i = 0; i < fw->size;) { + addr = le16_to_cpu( *( (u16 *)&b[i] ) ); + len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); + deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size); + if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { + err("firmware download failed: %d\n",ret); + return ret; + } + i += 4 + len; + } + release_firmware(fw); + deb_info("firmware download successfully completed\n"); + return 0; +} + +static int bcm3510_check_firmware_version(struct bcm3510_state *st) +{ + struct bcm3510_hab_cmd_get_version_info ver; + bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver)); + + deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n", + ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version); + + if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION && + ver.config_version == BCM3510_DEF_CONFIG_VERSION && + ver.demod_version == BCM3510_DEF_DEMOD_VERSION) + return 0; + + deb_info("version check failed\n"); + return -ENODEV; +} + +/* (un)resetting the AP */ +static int bcm3510_reset(struct bcm3510_state *st) +{ + int ret; + unsigned long t; + bcm3510_register_value v; + + bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1; + if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) + return ret; + + t = jiffies + 3*HZ; + while (time_before(jiffies, t)) { + msleep(10); + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) + return ret; + + if (v.APSTAT1_a2.RESET) + return 0; + } + deb_info("reset timed out\n"); + return -ETIMEDOUT; +} + +static int bcm3510_clear_reset(struct bcm3510_state *st) +{ + bcm3510_register_value v; + int ret; + unsigned long t; + + v.raw = 0; + if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) + return ret; + + t = jiffies + 3*HZ; + while (time_before(jiffies, t)) { + msleep(10); + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) + return ret; + + /* verify that reset is cleared */ + if (!v.APSTAT1_a2.RESET) + return 0; + } + deb_info("reset clear timed out\n"); + return -ETIMEDOUT; +} + +static int bcm3510_init_cold(struct bcm3510_state *st) +{ + int ret; + bcm3510_register_value v; + + /* read Acquisation Processor status register and check it is not in RUN mode */ + if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) + return ret; + if (v.APSTAT1_a2.RUN) { + deb_info("AP is already running - firmware already loaded.\n"); + return 0; + } + + deb_info("reset?\n"); + if ((ret = bcm3510_reset(st)) < 0) + return ret; + + deb_info("tristate?\n"); + /* tri-state */ + v.TSTCTL_2e.CTL = 0; + if ((ret = bcm3510_writeB(st,0x2e,v)) < 0) + return ret; + + deb_info("firmware?\n"); + if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 || + (ret = bcm3510_clear_reset(st)) < 0) + return ret; + + /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */ + + return 0; +} + +static int bcm3510_init(struct dvb_frontend* fe) +{ + struct bcm3510_state* st = fe->demodulator_priv; + bcm3510_register_value j; + struct bcm3510_hab_cmd_set_agc c; + int ret; + + if ((ret = bcm3510_readB(st,0xca,&j)) < 0) + return ret; + + deb_info("JDEC: %02x\n",j.raw); + + switch (j.JDEC_ca.JDEC) { + case JDEC_WAIT_AT_RAM: + deb_info("attempting to download firmware\n"); + if ((ret = bcm3510_init_cold(st)) < 0) + return ret; + case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */ + deb_info("firmware is loaded\n"); + bcm3510_check_firmware_version(st); + break; + default: + return -ENODEV; + } + + memset(&c,0,1); + c.SEL = 1; + bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0); + + return 0; +} + + +static struct dvb_frontend_ops bcm3510_ops; + +struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, + struct i2c_adapter *i2c) +{ + struct bcm3510_state* state = NULL; + int ret; + bcm3510_register_value v; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct bcm3510_state), GFP_KERNEL); + if (state == NULL) + goto error; + memset(state,0,sizeof(struct bcm3510_state)); + + /* setup the state */ + + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + + sema_init(&state->hab_sem, 1); + + if ((ret = bcm3510_readB(state,0xe0,&v)) < 0) + goto error; + + deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER); + + if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */ + (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */ + goto error; + + info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER); + + bcm3510_reset(state); + + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(bcm3510_attach); + +static struct dvb_frontend_ops bcm3510_ops = { + + .info = { + .name = "Broadcom BCM3510 VSB/QAM frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 803000000, + /* stepsize is just a guess */ + .frequency_stepsize = 0, + .caps = + 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_8VSB | FE_CAN_16VSB | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 + }, + + .release = bcm3510_release, + + .init = bcm3510_init, + .sleep = bcm3510_sleep, + + .set_frontend = bcm3510_set_frontend, + .get_tune_settings = bcm3510_get_tune_settings, + + .read_status = bcm3510_read_status, + .read_ber = bcm3510_read_ber, + .read_signal_strength = bcm3510_read_signal_strength, + .read_snr = bcm3510_read_snr, + .read_ucblocks = bcm3510_read_unc, +}; + +MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h new file mode 100644 index 000000000000..80f5d0953d02 --- /dev/null +++ b/drivers/media/dvb/frontends/bcm3510.h @@ -0,0 +1,40 @@ +/* + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) + * + * Copyright (C) 2001-5, B2C2 inc. + * + * GPL/Linux driver written by Patrick Boettcher + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef BCM3510_H +#define BCM3510_H + +#include +#include + +struct bcm3510_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, + struct i2c_adapter* i2c); + +#endif diff --git a/drivers/media/dvb/frontends/bcm3510_priv.h b/drivers/media/dvb/frontends/bcm3510_priv.h new file mode 100644 index 000000000000..3bb1bc2a04f0 --- /dev/null +++ b/drivers/media/dvb/frontends/bcm3510_priv.h @@ -0,0 +1,460 @@ +/* + * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC) + * + * Copyright (C) 2001-5, B2C2 inc. + * + * GPL/Linux driver written by Patrick Boettcher + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __BCM3510_PRIV_H__ +#define __BCM3510_PRIV_H__ + +#define PACKED __attribute__((packed)) + +#undef err +#define err(format, arg...) printk(KERN_ERR "bcm3510: " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO "bcm3510: " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg) + + +#define PANASONIC_FIRST_IF_BASE_IN_KHz 1407500 +#define BCM3510_SYMBOL_RATE 5381000 + +typedef union { + u8 raw; + + struct { + u8 CTL :8; + } TSTCTL_2e; + + u8 LDCERC_4e; + u8 LDUERC_4f; + u8 LD_BER0_65; + u8 LD_BER1_66; + u8 LD_BER2_67; + u8 LD_BER3_68; + + struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 HIRQ0 :1; + u8 HIRQ1 :1; + u8 na0 :1; + u8 HABAV :1; + u8 na1 :1; + } HCTL1_a0; + + struct { + u8 na0 :1; + u8 IDLMSK :1; + u8 STMSK :1; + u8 I0MSK :1; + u8 I1MSK :1; + u8 na1 :1; + u8 HABMSK :1; + u8 na2 :1; + } HCTLMSK_a1; + + struct { + u8 RESET :1; + u8 IDLE :1; + u8 STOP :1; + u8 RUN :1; + u8 HABAV :1; + u8 MEMAV :1; + u8 ALDONE :1; + u8 REIRQ :1; + } APSTAT1_a2; + + struct { + u8 RSTMSK :1; + u8 IMSK :1; + u8 SMSK :1; + u8 RMSK :1; + u8 HABMSK :1; + u8 MAVMSK :1; + u8 ALDMSK :1; + u8 REMSK :1; + } APMSK1_a3; + + u8 APSTAT2_a4; + u8 APMSK2_a5; + + struct { + u8 HABADR :7; + u8 na :1; + } HABADR_a6; + + u8 HABDATA_a7; + + struct { + u8 HABR :1; + u8 LDHABR :1; + u8 APMSK :1; + u8 HMSK :1; + u8 LDMSK :1; + u8 na :3; + } HABSTAT_a8; + + u8 MADRH_a9; + u8 MADRL_aa; + u8 MDATA_ab; + + struct { +#define JDEC_WAIT_AT_RAM 0x7 +#define JDEC_EEPROM_LOAD_WAIT 0x4 + u8 JDEC :3; + u8 na :5; + } JDEC_ca; + + struct { + u8 REV :4; + u8 LAYER :4; + } REVID_e0; + + struct { + u8 unk0 :1; + u8 CNTCTL :1; + u8 BITCNT :1; + u8 unk1 :1; + u8 RESYNC :1; + u8 unk2 :3; + } BERCTL_fa; + + struct { + u8 CSEL0 :1; + u8 CLKED0 :1; + u8 CSEL1 :1; + u8 CLKED1 :1; + u8 CLKLEV :1; + u8 SPIVAR :1; + u8 na :2; + } TUNSET_fc; + + struct { + u8 CLK :1; + u8 DATA :1; + u8 CS0 :1; + u8 CS1 :1; + u8 AGCSEL :1; + u8 na0 :1; + u8 TUNSEL :1; + u8 na1 :1; + } TUNCTL_fd; + + u8 TUNSEL0_fe; + u8 TUNSEL1_ff; + +} bcm3510_register_value; + +/* HAB commands */ + +/* version */ +#define CMD_GET_VERSION_INFO 0x3D +#define MSGID_GET_VERSION_INFO 0x15 +struct bcm3510_hab_cmd_get_version_info { + u8 microcode_version; + u8 script_version; + u8 config_version; + u8 demod_version; +} PACKED; + +#define BCM3510_DEF_MICROCODE_VERSION 0x0E +#define BCM3510_DEF_SCRIPT_VERSION 0x06 +#define BCM3510_DEF_CONFIG_VERSION 0x01 +#define BCM3510_DEF_DEMOD_VERSION 0xB1 + +/* acquire */ +#define CMD_ACQUIRE 0x38 + +#define MSGID_EXT_TUNER_ACQUIRE 0x0A +struct bcm3510_hab_cmd_ext_acquire { + struct { + u8 MODE :4; + u8 BW :1; + u8 FA :1; + u8 NTSCSWEEP :1; + u8 OFFSET :1; + } PACKED ACQUIRE0; /* control_byte */ + + struct { + u8 IF_FREQ :3; + u8 zero0 :1; + u8 SYM_RATE :3; + u8 zero1 :1; + } PACKED ACQUIRE1; /* sym_if */ + + u8 IF_OFFSET0; /* IF_Offset_10hz */ + u8 IF_OFFSET1; + u8 SYM_OFFSET0; /* SymbolRateOffset */ + u8 SYM_OFFSET1; + u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ + u8 NTSC_OFFSET1; +} PACKED; + +#define MSGID_INT_TUNER_ACQUIRE 0x0B +struct bcm3510_hab_cmd_int_acquire { + struct { + u8 MODE :4; + u8 BW :1; + u8 FA :1; + u8 NTSCSWEEP :1; + u8 OFFSET :1; + } PACKED ACQUIRE0; /* control_byte */ + + struct { + u8 IF_FREQ :3; + u8 zero0 :1; + u8 SYM_RATE :3; + u8 zero1 :1; + } PACKED ACQUIRE1; /* sym_if */ + + u8 TUNER_FREQ0; + u8 TUNER_FREQ1; + u8 TUNER_FREQ2; + u8 TUNER_FREQ3; + u8 IF_OFFSET0; /* IF_Offset_10hz */ + u8 IF_OFFSET1; + u8 SYM_OFFSET0; /* SymbolRateOffset */ + u8 SYM_OFFSET1; + u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */ + u8 NTSC_OFFSET1; +} PACKED; + +/* modes */ +#define BCM3510_QAM16 = 0x01 +#define BCM3510_QAM32 = 0x02 +#define BCM3510_QAM64 = 0x03 +#define BCM3510_QAM128 = 0x04 +#define BCM3510_QAM256 = 0x05 +#define BCM3510_8VSB = 0x0B +#define BCM3510_16VSB = 0x0D + +/* IF_FREQS */ +#define BCM3510_IF_TERRESTRIAL 0x0 +#define BCM3510_IF_CABLE 0x1 +#define BCM3510_IF_USE_CMD 0x7 + +/* SYM_RATE */ +#define BCM3510_SR_8VSB 0x0 /* 5381119 s/sec */ +#define BCM3510_SR_256QAM 0x1 /* 5360537 s/sec */ +#define BCM3510_SR_16QAM 0x2 /* 5056971 s/sec */ +#define BCM3510_SR_MISC 0x3 /* 5000000 s/sec */ +#define BCM3510_SR_USE_CMD 0x7 + +/* special symbol rate */ +#define CMD_SET_VALUE_NOT_LISTED 0x2d +#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c +struct bcm3510_hab_cmd_set_sr_not_listed { + u8 HOST_SYM_RATE0; + u8 HOST_SYM_RATE1; + u8 HOST_SYM_RATE2; + u8 HOST_SYM_RATE3; +} PACKED; + +/* special IF */ +#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d +struct bcm3510_hab_cmd_set_if_freq_not_listed { + u8 HOST_IF_FREQ0; + u8 HOST_IF_FREQ1; + u8 HOST_IF_FREQ2; + u8 HOST_IF_FREQ3; +} PACKED; + +/* auto reacquire */ +#define CMD_AUTO_PARAM 0x2a +#define MSGID_AUTO_REACQUIRE 0x0e +struct bcm3510_hab_cmd_auto_reacquire { + u8 ACQ :1; /* on/off*/ + u8 unused :7; +} PACKED; + +#define MSGID_SET_RF_AGC_SEL 0x12 +struct bcm3510_hab_cmd_set_agc { + u8 LVL :1; + u8 unused :6; + u8 SEL :1; +} PACKED; + +#define MSGID_SET_AUTO_INVERSION 0x14 +struct bcm3510_hab_cmd_auto_inversion { + u8 AI :1; + u8 unused :7; +} PACKED; + + +/* bert control */ +#define CMD_STATE_CONTROL 0x12 +#define MSGID_BERT_CONTROL 0x0e +#define MSGID_BERT_SET 0xfa +struct bcm3510_hab_cmd_bert_control { + u8 BE :1; + u8 unused :7; +} PACKED; + +#define MSGID_TRI_STATE 0x2e +struct bcm3510_hab_cmd_tri_state { + u8 RE :1; /* a/d ram port pins */ + u8 PE :1; /* baud clock pin */ + u8 AC :1; /* a/d clock pin */ + u8 BE :1; /* baud clock pin */ + u8 unused :4; +} PACKED; + + +/* tune */ +#define CMD_TUNE 0x38 +#define MSGID_TUNE 0x16 +struct bcm3510_hab_cmd_tune_ctrl_data_pair { + struct { +#define BITS_8 0x07 +#define BITS_7 0x06 +#define BITS_6 0x05 +#define BITS_5 0x04 +#define BITS_4 0x03 +#define BITS_3 0x02 +#define BITS_2 0x01 +#define BITS_1 0x00 + u8 size :3; + u8 unk :2; + u8 clk_off :1; + u8 cs0 :1; + u8 cs1 :1; + + } PACKED ctrl; + + u8 data; +} PACKED; + +struct bcm3510_hab_cmd_tune { + u8 length; + u8 clock_width; + u8 misc; + u8 TUNCTL_state; + + struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16]; +} PACKED; + +#define CMD_STATUS 0x38 +#define MSGID_STATUS1 0x08 +struct bcm3510_hab_cmd_status1 { + struct { + u8 EQ_MODE :4; + u8 reserved :2; + u8 QRE :1; /* if QSE and the spectrum is inversed */ + u8 QSE :1; /* automatic spectral inversion */ + } PACKED STATUS0; + + struct { + u8 RECEIVER_LOCK :1; + u8 FEC_LOCK :1; + u8 OUT_PLL_LOCK :1; + u8 reserved :5; + } PACKED STATUS1; + + struct { + u8 reserved :2; + u8 BW :1; + u8 NTE :1; /* NTSC filter sweep enabled */ + u8 AQI :1; /* currently acquiring */ + u8 FA :1; /* fast acquisition */ + u8 ARI :1; /* auto reacquire */ + u8 TI :1; /* programming the tuner */ + } PACKED STATUS2; + u8 STATUS3; + u8 SNR_EST0; + u8 SNR_EST1; + u8 TUNER_FREQ0; + u8 TUNER_FREQ1; + u8 TUNER_FREQ2; + u8 TUNER_FREQ3; + u8 SYM_RATE0; + u8 SYM_RATE1; + u8 SYM_RATE2; + u8 SYM_RATE3; + u8 SYM_OFFSET0; + u8 SYM_OFFSET1; + u8 SYM_ERROR0; + u8 SYM_ERROR1; + u8 IF_FREQ0; + u8 IF_FREQ1; + u8 IF_FREQ2; + u8 IF_FREQ3; + u8 IF_OFFSET0; + u8 IF_OFFSET1; + u8 IF_ERROR0; + u8 IF_ERROR1; + u8 NTSC_FILTER0; + u8 NTSC_FILTER1; + u8 NTSC_FILTER2; + u8 NTSC_FILTER3; + u8 NTSC_OFFSET0; + u8 NTSC_OFFSET1; + u8 NTSC_ERROR0; + u8 NTSC_ERROR1; + u8 INT_AGC_LEVEL0; + u8 INT_AGC_LEVEL1; + u8 EXT_AGC_LEVEL0; + u8 EXT_AGC_LEVEL1; +} PACKED; + +#define MSGID_STATUS2 0x14 +struct bcm3510_hab_cmd_status2 { + struct { + u8 EQ_MODE :4; + u8 reserved :2; + u8 QRE :1; + u8 QSR :1; + } PACKED STATUS0; + struct { + u8 RL :1; + u8 FL :1; + u8 OL :1; + u8 reserved :5; + } PACKED STATUS1; + u8 SYMBOL_RATE0; + u8 SYMBOL_RATE1; + u8 SYMBOL_RATE2; + u8 SYMBOL_RATE3; + u8 LDCERC0; + u8 LDCERC1; + u8 LDCERC2; + u8 LDCERC3; + u8 LDUERC0; + u8 LDUERC1; + u8 LDUERC2; + u8 LDUERC3; + u8 LDBER0; + u8 LDBER1; + u8 LDBER2; + u8 LDBER3; + struct { + u8 MODE_TYPE :4; /* acquire mode 0 */ + u8 reservd :4; + } MODE_TYPE; + u8 SNR_EST0; + u8 SNR_EST1; + u8 SIGNAL; +} PACKED; + +#define CMD_SET_RF_BW_NOT_LISTED 0x3f +#define MSGID_SET_RF_BW_NOT_LISTED 0x11 +/* TODO */ + +#endif -- cgit v1.2.2 From 3e1d1d28d99dabe63c64f7f40f1ca1d646de1f73 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 24 Jun 2005 23:13:50 -0700 Subject: [PATCH] Cleanup patch for process freezing 1. Establish a simple API for process freezing defined in linux/include/sched.h: frozen(process) Check for frozen process freezing(process) Check if a process is being frozen freeze(process) Tell a process to freeze (go to refrigerator) thaw_process(process) Restart process frozen_process(process) Process is frozen now 2. Remove all references to PF_FREEZE and PF_FROZEN from all kernel sources except sched.h 3. Fix numerous locations where try_to_freeze is manually done by a driver 4. Remove the argument that is no longer necessary from two function calls. 5. Some whitespace cleanup 6. Clear potential race in refrigerator (provides an open window of PF_FREEZE cleared before setting PF_FROZEN, recalc_sigpending does not check PF_FROZEN). This patch does not address the problem of freeze_processes() violating the rule that a task may only modify its own flags by setting PF_FREEZE. This is not clean in an SMP environment. freeze(process) is therefore not SMP safe! Signed-off-by: Christoph Lameter Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d6b7a9de471e..f11daae91cd4 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -391,8 +391,7 @@ static int dvb_frontend_thread(void *data) break; } - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); if (down_interruptible(&fepriv->sem)) break; -- cgit v1.2.2 From 9d7495330be2fd88ab939fa5080d3ca9f64368c2 Mon Sep 17 00:00:00 2001 From: "Eddie C. Dost" Date: Wed, 6 Jul 2005 15:41:17 -0700 Subject: [DVB]: Do not include from drivers. Signed-off-by: David S. Miller --- drivers/media/dvb/frontends/tda80xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c index 032d348dafb7..88e125079ca1 100644 --- a/drivers/media/dvb/frontends/tda80xx.c +++ b/drivers/media/dvb/frontends/tda80xx.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.2 From 38b32d6237588e6dca9b9a84256b507a29207f68 Mon Sep 17 00:00:00 2001 From: Martin Loschwitz Date: Thu, 7 Jul 2005 17:57:31 -0700 Subject: [PATCH] dvb: cinergyT2: endianness fix for raw remote-control keys Fixed litte/big-endian conversion for raw remote-control keys. Signed-off-by: Martin Loschwitz Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/cinergyT2/cinergyT2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 96c57fde95a0..7d8b3cad350b 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -699,6 +699,8 @@ static void cinergyt2_query_rc (void *data) for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) { int i; +/* dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/ + if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC && rc_events[n].value == ~0) { @@ -714,7 +716,7 @@ static void cinergyt2_query_rc (void *data) cinergyt2->rc_input_event = KEY_MAX; for (i=0; irc_input_event = rc_keys[i+2]; break; -- cgit v1.2.2 From 25a26ec3b60b29300a652d7d81a69b6bc08b35b5 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:35 -0700 Subject: [PATCH] dvb: remove obsolete skystar2 driver Remove the skystar2 driver which has been obsoleted by the generalized flexcop-pci driver. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/Kconfig | 14 - drivers/media/dvb/b2c2/Makefile | 2 - drivers/media/dvb/b2c2/skystar2.c | 2644 ------------------------------------- 3 files changed, 2660 deletions(-) delete mode 100644 drivers/media/dvb/b2c2/skystar2.c (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index fafd0ab3a28f..d7417eac2aba 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -35,17 +35,3 @@ config DVB_B2C2_FLEXCOP_DEBUG help Say Y if you want to enable the module option to control debug messages of all B2C2 FlexCop drivers. - -config DVB_B2C2_SKYSTAR - tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI" - depends on DVB_CORE && PCI - select DVB_STV0299 - select DVB_MT352 - select DVB_MT312 - select DVB_NXT2002 - help - Support for the Skystar2 PCI DVB card by Technisat, which - is equipped with the FlexCopII chipset by B2C2, and - for the B2C2/BBTI Air2PC-ATSC card. - - Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 7703812af34f..1a1c3bca55fa 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -9,6 +9,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o -obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o - EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c deleted file mode 100644 index acbc4c34f72a..000000000000 --- a/drivers/media/dvb/b2c2/skystar2.c +++ /dev/null @@ -1,2644 +0,0 @@ -/* - * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card - * based on the FlexCopII by B2C2,Inc. - * - * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc - * - * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl() - * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped - * Vincenzo Di Massa, hawk.it at tiscalinet.it - * - * Converted to Linux coding style - * Misc reorganization, polishing, restyling - * Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it - * - * Added hardware filtering support, - * Niklas Peinecke, peinecke at gdv.uni-hannover.de - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "dvb_frontend.h" - -#include -#include -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_filter.h" -#include "dvbdev.h" -#include "demux.h" -#include "dvb_net.h" -#include "stv0299.h" -#include "mt352.h" -#include "mt312.h" -#include "nxt2002.h" - -static int debug; -static int enable_hw_filters = 2; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Set debugging level (0 = default, 1 = most messages, 2 = all messages)."); -module_param(enable_hw_filters, int, 0444); -MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2"); - -#define dprintk(x...) do { if (debug>=1) printk(x); } while (0) -#define ddprintk(x...) do { if (debug>=2) printk(x); } while (0) - -#define SIZE_OF_BUF_DMA1 0x3ac00 -#define SIZE_OF_BUF_DMA2 0x758 - -#define MAX_N_HW_FILTERS (6+32) -#define N_PID_SLOTS 256 - -struct dmaq { - u32 bus_addr; - u32 head; - u32 tail; - u32 buffer_size; - u8 *buffer; -}; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) -#define __iomem -#endif - -struct adapter { - struct pci_dev *pdev; - - u8 card_revision; - u32 b2c2_revision; - u32 pid_filter_max; - u32 mac_filter_max; - u32 irq; - void __iomem *io_mem; - unsigned long io_port; - u8 mac_addr[8]; - u32 dw_sram_type; - - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct i2c_adapter i2c_adap; - struct dvb_net dvbnet; - - struct semaphore i2c_sem; - - struct dmaq dmaq1; - struct dmaq dmaq2; - - u32 dma_ctrl; - u32 dma_status; - - int capturing; - - spinlock_t lock; - - int useable_hw_filters; - u16 hw_pids[MAX_N_HW_FILTERS]; - u16 pid_list[N_PID_SLOTS]; - int pid_rc[N_PID_SLOTS]; // ref counters for the pids - int pid_count; - int whole_bandwidth_count; - u32 mac_filter; - - struct dvb_frontend* fe; - int (*fe_sleep)(struct dvb_frontend* fe); -}; - -#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg) -#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg) - -static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue) -{ - u32 tmp; - - tmp = read_reg_dw(adapter, reg); - tmp = (tmp & ~zeromask) | orvalue; - write_reg_dw(adapter, reg, tmp); -} - -/* i2c functions */ -static int i2c_main_write_for_flex2(struct adapter *adapter, u32 command, u8 *buf, int retries) -{ - int i; - u32 value; - - write_reg_dw(adapter, 0x100, 0); - write_reg_dw(adapter, 0x100, command); - - for (i = 0; i < retries; i++) { - value = read_reg_dw(adapter, 0x100); - - if ((value & 0x40000000) == 0) { - if ((value & 0x81000000) == 0x80000000) { - if (buf != 0) - *buf = (value >> 0x10) & 0xff; - - return 1; - } - } else { - write_reg_dw(adapter, 0x100, 0); - write_reg_dw(adapter, 0x100, command); - } - } - - return 0; -} - -/* device = 0x10000000 for tuner, 0x20000000 for eeprom */ -static void i2c_main_setup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command) -{ - *command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr; - - if (op != 0) - *command = *command | 0x03000000; - else - *command = *command | 0x01000000; -} - -static int flex_i2c_read4(struct adapter *adapter, u32 device, u32 chip_addr, u16 addr, u8 *buf, u8 len) -{ - u32 command; - u32 value; - - int result, i; - - i2c_main_setup(device, chip_addr, 1, addr, 0, len, &command); - - result = i2c_main_write_for_flex2(adapter, command, buf, 100000); - - if ((result & 0xff) != 0) { - if (len > 1) { - value = read_reg_dw(adapter, 0x104); - - for (i = 1; i < len; i++) { - buf[i] = value & 0xff; - value = value >> 8; - } - } - } - - return result; -} - -static int flex_i2c_write4(struct adapter *adapter, u32 device, u32 chip_addr, u32 addr, u8 *buf, u8 len) -{ - u32 command; - u32 value; - int i; - - if (len > 1) { - value = 0; - - for (i = len; i > 1; i--) { - value = value << 8; - value = value | buf[i - 1]; - } - - write_reg_dw(adapter, 0x104, value); - } - - i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command); - - return i2c_main_write_for_flex2(adapter, command, NULL, 100000); -} - -static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret) -{ - if (device == 0x20000000) - *ret = bus | ((addr >> 8) & 3); - else - *ret = bus; -} - -static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len) -{ - u32 chipaddr; - u32 bytes_to_transfer; - u8 *start; - - ddprintk("%s:\n", __FUNCTION__); - - start = buf; - - while (len != 0) { - bytes_to_transfer = len; - - if (bytes_to_transfer > 4) - bytes_to_transfer = 4; - - fixchipaddr(device, bus, addr, &chipaddr); - - if (flex_i2c_read4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) - return buf - start; - - buf = buf + bytes_to_transfer; - addr = addr + bytes_to_transfer; - len = len - bytes_to_transfer; - }; - - return buf - start; -} - -static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len) -{ - u32 chipaddr; - u32 bytes_to_transfer; - u8 *start; - - ddprintk("%s:\n", __FUNCTION__); - - start = buf; - - while (len != 0) { - bytes_to_transfer = len; - - if (bytes_to_transfer > 4) - bytes_to_transfer = 4; - - fixchipaddr(device, bus, addr, &chipaddr); - - if (flex_i2c_write4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) - return buf - start; - - buf = buf + bytes_to_transfer; - addr = addr + bytes_to_transfer; - len = len - bytes_to_transfer; - } - - return buf - start; -} - -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num) -{ - struct adapter *tmp = i2c_get_adapdata(adapter); - int i, ret = 0; - - if (down_interruptible(&tmp->i2c_sem)) - return -ERESTARTSYS; - - ddprintk("%s: %d messages to transfer\n", __FUNCTION__, num); - - for (i = 0; i < num; i++) { - ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, - msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - } - - // read command - if ((num == 2) && (msgs[0].flags == 0) && (msgs[1].flags == I2C_M_RD) && (msgs[0].buf != NULL) && (msgs[1].buf != NULL)) { - - ret = flex_i2c_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); - - up(&tmp->i2c_sem); - - if (ret != msgs[1].len) { - dprintk("%s: read error !\n", __FUNCTION__); - - for (i = 0; i < 2; i++) { - dprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, - msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - } - - return -EREMOTEIO; - } - - return num; - } - // write command - for (i = 0; i < num; i++) { - - if ((msgs[i].flags != 0) || (msgs[i].buf == NULL) || (msgs[i].len < 2)) - return -EINVAL; - - ret = flex_i2c_write(tmp, 0x10000000, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); - - up(&tmp->i2c_sem); - - if (ret != msgs[0].len - 1) { - dprintk("%s: write error %i !\n", __FUNCTION__, ret); - - dprintk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i, - msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - - return -EREMOTEIO; - } - - return num; - } - - printk("%s: unknown command format !\n", __FUNCTION__); - - return -EINVAL; -} - -/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board, - but it seems that FlexCopII can work with more than one chip) */ -static void sram_set_net_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xfffffffc) | (dest & 3); - - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -static void sram_set_cai_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xfffffff3) | ((dest & 3) << 2); - - udelay(1000); - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -static void sram_set_cao_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xffffffcf) | ((dest & 3) << 4); - - udelay(1000); - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -static void sram_set_media_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xffffff3f) | ((dest & 3) << 6); - - udelay(1000); - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -/* SRAM memory is accessed through a buffer register in the FlexCop - chip (0x700). This register has the following structure: - bits 0-14 : address - bit 15 : read/write flag - bits 16-23 : 8-bit word to write - bits 24-27 : = 4 - bits 28-29 : memory bank selector - bit 31 : busy flag -*/ -static void flex_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04000000 | (*buf << 0x10); - - retries = 2; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __FUNCTION__); - - write_reg_dw(adapter, 0x700, command); - - buf++; - addr++; - } -} - -static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command, value; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04008000; - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __FUNCTION__); - - write_reg_dw(adapter, 0x700, command); - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __FUNCTION__); - - value = read_reg_dw(adapter, 0x700) >> 0x10; - - *buf = (value & 0xff); - - addr++; - buf++; - } -} - -static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - - flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - - flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - - while (len != 0) { - length = len; - - // check if the address range belongs to the same - // 32K memory chip. If not, the data is read from - // one chip at a time. - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_read_chunk(adapter, addr, buf, length); - - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - - while (len != 0) { - length = len; - - // check if the address range belongs to the same - // 32K memory chip. If not, the data is written to - // one chip at a time. - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_write_chunk(adapter, addr, buf, length); - - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_set_size(struct adapter *adapter, u32 mask) -{ - write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); -} - -static void sram_init(struct adapter *adapter) -{ - u32 tmp; - - tmp = read_reg_dw(adapter, 0x71c); - - write_reg_dw(adapter, 0x71c, 1); - - if (read_reg_dw(adapter, 0x71c) != 0) { - write_reg_dw(adapter, 0x71c, tmp); - - adapter->dw_sram_type = tmp & 0x30000; - - ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); - - } else { - - adapter->dw_sram_type = 0x10000; - - ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); - } - - /* return value is never used? */ -/* return adapter->dw_sram_type; */ -} - -static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) -{ - u8 tmp1, tmp2; - - dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr); - - sram_set_size(adapter, mask); - sram_init(adapter); - - tmp2 = 0xa5; - tmp1 = 0x4f; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2); - - if (tmp2 != 0xa5) - return 0; - - tmp2 = 0x5a; - tmp1 = 0xf4; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2); - - if (tmp2 != 0x5a) - return 0; - - return 1; -} - -static u32 sram_length(struct adapter *adapter) -{ - if (adapter->dw_sram_type == 0x10000) - return 32768; // 32K - if (adapter->dw_sram_type == 0x00000) - return 65536; // 64K - if (adapter->dw_sram_type == 0x20000) - return 131072; // 128K - - return 32768; // 32K -} - -/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. - - for 128K there are 4x32K chips at bank 0,1,2,3. - - for 64K there are 2x32K chips at bank 1,2. - - for 32K there is one 32K chip at bank 0. - - FlexCop works only with one bank at a time. The bank is selected - by bits 28-29 of the 0x700 register. - - bank 0 covers addresses 0x00000-0x07fff - bank 1 covers addresses 0x08000-0x0ffff - bank 2 covers addresses 0x10000-0x17fff - bank 3 covers addresses 0x18000-0x1ffff -*/ -static int sram_detect_for_flex2(struct adapter *adapter) -{ - u32 tmp, tmp2, tmp3; - - dprintk("%s:\n", __FUNCTION__); - - tmp = read_reg_dw(adapter, 0x208); - write_reg_dw(adapter, 0x208, 0); - - tmp2 = read_reg_dw(adapter, 0x71c); - - dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2); - - write_reg_dw(adapter, 0x71c, 1); - - tmp3 = read_reg_dw(adapter, 0x71c); - - dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3); - - write_reg_dw(adapter, 0x71c, tmp2); - - // check for internal SRAM ??? - tmp3--; - if (tmp3 != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 32K\n", __FUNCTION__); - - return 32; - } - - if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { - sram_set_size(adapter, 0x20000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 128K\n", __FUNCTION__); - - return 128; - } - - if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { - sram_set_size(adapter, 0x00000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 64K\n", __FUNCTION__); - - return 64; - } - - if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 32K\n", __FUNCTION__); - - return 32; - } - - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__); - - return 0; -} - -static void sll_detect_sram_size(struct adapter *adapter) -{ - sram_detect_for_flex2(adapter); -} - -/* EEPROM (Skystar2 has one "24LC08B" chip on board) */ -/* -static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) -{ - return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); -} -*/ - -static int eeprom_read(struct adapter *adapter, u16 addr, u8 *buf, u16 len) -{ - return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len); -} - -static u8 calc_lrc(u8 *buf, int len) -{ - int i; - u8 sum; - - sum = 0; - - for (i = 0; i < len; i++) - sum = sum ^ buf[i]; - - return sum; -} - -static int eeprom_lrc_read(struct adapter *adapter, u32 addr, u32 len, u8 *buf, int retries) -{ - int i; - - for (i = 0; i < retries; i++) { - if (eeprom_read(adapter, addr, buf, len) == len) { - if (calc_lrc(buf, len - 1) == buf[len - 1]) - return 1; - } - } - - return 0; -} - -/* -static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries) -{ - int i; - - for (i = 0; i < retries; i++) { - if (eeprom_write(adapter, addr, wbuf, len) == len) { - if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) - return 1; - } - } - - return 0; -} -*/ - - -/* These functions could be used to unlock SkyStar2 cards. */ - -/* -static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 rbuf[20]; - u8 wbuf[20]; - - if (len != 16) - return 0; - - memcpy(wbuf, key, len); - - wbuf[16] = 0; - wbuf[17] = 0; - wbuf[18] = 0; - wbuf[19] = calc_lrc(wbuf, 19); - - return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); -} - -static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 buf[20]; - - if (len != 16) - return 0; - - if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) - return 0; - - memcpy(key, buf, len); - - return 1; -} -*/ - -static int eeprom_get_mac_addr(struct adapter *adapter, char type, u8 *mac) -{ - u8 tmp[8]; - - if (eeprom_lrc_read(adapter, 0x3f8, 8, tmp, 4) != 0) { - if (type != 0) { - mac[0] = tmp[0]; - mac[1] = tmp[1]; - mac[2] = tmp[2]; - mac[3] = 0xfe; - mac[4] = 0xff; - mac[5] = tmp[3]; - mac[6] = tmp[4]; - mac[7] = tmp[5]; - - } else { - - mac[0] = tmp[0]; - mac[1] = tmp[1]; - mac[2] = tmp[2]; - mac[3] = tmp[3]; - mac[4] = tmp[4]; - mac[5] = tmp[5]; - } - - return 1; - - } else { - - if (type == 0) { - memset(mac, 0, 6); - - } else { - - memset(mac, 0, 8); - } - - return 0; - } -} - -/* -static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) -{ - u8 tmp[8]; - - if (type != 0) { - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[5]; - tmp[4] = mac[6]; - tmp[5] = mac[7]; - - } else { - - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[3]; - tmp[4] = mac[4]; - tmp[5] = mac[5]; - } - - tmp[6] = 0; - tmp[7] = calc_lrc(tmp, 7); - - if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) - return 1; - - return 0; -} -*/ - -/* PID filter */ - -/* every flexcop has 6 "lower" hw PID filters */ -/* these are enabled by setting bits 0-5 of 0x208 */ -/* for the 32 additional filters we have to select one */ -/* of them through 0x310 and modify through 0x314 */ -/* op: 0=disable, 1=enable */ -static void filter_enable_hw_filter(struct adapter *adapter, int id, u8 op) -{ - dprintk("%s: id=%d op=%d\n", __FUNCTION__, id, op); - if (id <= 5) { - u32 mask = (0x00000001 << id); - write_reg_bitfield(adapter, 0x208, mask, op ? mask : 0); - } else { - /* select */ - write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f); - /* modify */ - write_reg_bitfield(adapter, 0x314, 0x00006000, op ? 0x00004000 : 0); - } -} - -/* this sets the PID that should pass the specified filter */ -static void pid_set_hw_pid(struct adapter *adapter, int id, u16 pid) -{ - dprintk("%s: id=%d pid=%d\n", __FUNCTION__, id, pid); - if (id <= 5) { - u32 adr = 0x300 + ((id & 6) << 1); - int shift = (id & 1) ? 16 : 0; - dprintk("%s: id=%d addr=%x %c pid=%d\n", __FUNCTION__, id, adr, (id & 1) ? 'h' : 'l', pid); - write_reg_bitfield(adapter, adr, (0x7fff) << shift, (pid & 0x1fff) << shift); - } else { - /* select */ - write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f); - /* modify */ - write_reg_bitfield(adapter, 0x314, 0x1fff, pid & 0x1fff); - } -} - - -/* -static void filter_enable_null_filter(struct adapter *adapter, u32 op) -{ - dprintk("%s: op=%x\n", __FUNCTION__, op); - - write_reg_bitfield(adapter, 0x208, 0x00000040, op?0x00000040:0); -} -*/ - -static void filter_enable_mask_filter(struct adapter *adapter, u32 op) -{ - dprintk("%s: op=%x\n", __FUNCTION__, op); - - write_reg_bitfield(adapter, 0x208, 0x00000080, op ? 0x00000080 : 0); -} - - -static void ctrl_enable_mac(struct adapter *adapter, u32 op) -{ - write_reg_bitfield(adapter, 0x208, 0x00004000, op ? 0x00004000 : 0); -} - -static int ca_set_mac_dst_addr_filter(struct adapter *adapter, u8 *mac) -{ - u32 tmp1, tmp2; - - tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0]; - tmp2 = (mac[5] << 0x08) | mac[4]; - - write_reg_dw(adapter, 0x418, tmp1); - write_reg_dw(adapter, 0x41c, tmp2); - - return 0; -} - -/* -static void set_ignore_mac_filter(struct adapter *adapter, u8 op) -{ - if (op != 0) { - write_reg_bitfield(adapter, 0x208, 0x00004000, 0); - adapter->mac_filter = 1; - } else { - if (adapter->mac_filter != 0) { - adapter->mac_filter = 0; - write_reg_bitfield(adapter, 0x208, 0x00004000, 0x00004000); - } - } -} -*/ - -/* -static void check_null_filter_enable(struct adapter *adapter) -{ - filter_enable_null_filter(adapter, 1); - filter_enable_mask_filter(adapter, 1); -} -*/ - -static void pid_set_group_pid(struct adapter *adapter, u16 pid) -{ - u32 value; - - dprintk("%s: pid=%x\n", __FUNCTION__, pid); - value = (pid & 0x3fff) | (read_reg_dw(adapter, 0x30c) & 0xffff0000); - write_reg_dw(adapter, 0x30c, value); -} - -static void pid_set_group_mask(struct adapter *adapter, u16 pid) -{ - u32 value; - - dprintk("%s: pid=%x\n", __FUNCTION__, pid); - value = ((pid & 0x3fff) << 0x10) | (read_reg_dw(adapter, 0x30c) & 0xffff); - write_reg_dw(adapter, 0x30c, value); -} - -/* -static int pid_get_group_pid(struct adapter *adapter) -{ - return read_reg_dw(adapter, 0x30c) & 0x00001fff; -} - -static int pid_get_group_mask(struct adapter *adapter) -{ - return (read_reg_dw(adapter, 0x30c) >> 0x10)& 0x00001fff; -} -*/ - -/* -static void reset_hardware_pid_filter(struct adapter *adapter) -{ - pid_set_stream1_pid(adapter, 0x1fff); - - pid_set_stream2_pid(adapter, 0x1fff); - filter_enable_stream2_filter(adapter, 0); - - pid_set_pcr_pid(adapter, 0x1fff); - filter_enable_pcr_filter(adapter, 0); - - pid_set_pmt_pid(adapter, 0x1fff); - filter_enable_pmt_filter(adapter, 0); - - pid_set_ecm_pid(adapter, 0x1fff); - filter_enable_ecm_filter(adapter, 0); - - pid_set_emm_pid(adapter, 0x1fff); - filter_enable_emm_filter(adapter, 0); -} -*/ - -static void init_pids(struct adapter *adapter) -{ - int i; - - adapter->pid_count = 0; - adapter->whole_bandwidth_count = 0; - for (i = 0; i < adapter->useable_hw_filters; i++) { - dprintk("%s: setting filter %d to 0x1fff\n", __FUNCTION__, i); - adapter->hw_pids[i] = 0x1fff; - pid_set_hw_pid(adapter, i, 0x1fff); -} - - pid_set_group_pid(adapter, 0); - pid_set_group_mask(adapter, 0x1fe0); -} - -static void open_whole_bandwidth(struct adapter *adapter) -{ - dprintk("%s:\n", __FUNCTION__); - pid_set_group_pid(adapter, 0); - pid_set_group_mask(adapter, 0); -/* - filter_enable_mask_filter(adapter, 1); -*/ -} - -static void close_whole_bandwidth(struct adapter *adapter) -{ - dprintk("%s:\n", __FUNCTION__); - pid_set_group_pid(adapter, 0); - pid_set_group_mask(adapter, 0x1fe0); -/* - filter_enable_mask_filter(adapter, 1); -*/ -} - -static void whole_bandwidth_inc(struct adapter *adapter) -{ - if (adapter->whole_bandwidth_count++ == 0) - open_whole_bandwidth(adapter); -} - -static void whole_bandwidth_dec(struct adapter *adapter) -{ - if (--adapter->whole_bandwidth_count <= 0) - close_whole_bandwidth(adapter); -} - -/* The specified PID has to be let through the - hw filters. - We try to allocate an hardware filter and open whole - bandwidth when allocation is impossible. - All pids<=0x1f pass through the group filter. - Returns 1 on success, -1 on error */ -static int add_hw_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid <= 0x1f) - return 1; - - /* we can't use a filter for 0x2000, so no search */ - if (pid != 0x2000) { - /* find an unused hardware filter */ - for (i = 0; i < adapter->useable_hw_filters; i++) { - dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i); - if (adapter->hw_pids[i] == 0x1fff) { - dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i); - adapter->hw_pids[i] = pid; - pid_set_hw_pid(adapter, i, pid); - filter_enable_hw_filter(adapter, i, 1); - return 1; - } - } - } - /* if we have not used a filter, this pid depends on whole bandwidth */ - dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid); - whole_bandwidth_inc(adapter); - return 1; - } - -/* returns -1 if the pid was not present in the filters */ -static int remove_hw_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid <= 0x1f) - return 1; - - /* we can't use a filter for 0x2000, so no search */ - if (pid != 0x2000) { - for (i = 0; i < adapter->useable_hw_filters; i++) { - dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i); - if (adapter->hw_pids[i] == pid) { // find the pid slot - dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i); - adapter->hw_pids[i] = 0x1fff; - pid_set_hw_pid(adapter, i, 0x1fff); - filter_enable_hw_filter(adapter, i, 0); - return 1; - } - } - } - /* if we have not used a filter, this pid depended on whole bandwith */ - dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid); - whole_bandwidth_dec(adapter); - return 1; - } - -/* Adds a PID to the filters. - Adding a pid more than once is possible, we keep reference counts. - Whole stream available through pid==0x2000. - Returns 1 on success, -1 on error */ -static int add_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid > 0x1ffe && pid != 0x2000) - return -1; - - // check if the pid is already present - for (i = 0; i < adapter->pid_count; i++) - if (adapter->pid_list[i] == pid) { - adapter->pid_rc[i]++; // increment ref counter - return 1; - } - - if (adapter->pid_count == N_PID_SLOTS) - return -1; // no more pids can be added - adapter->pid_list[adapter->pid_count] = pid; // register pid - adapter->pid_rc[adapter->pid_count] = 1; - adapter->pid_count++; - // hardware setting - add_hw_pid(adapter, pid); - - return 1; - } - -/* Removes a PID from the filters. */ -static int remove_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid > 0x1ffe && pid != 0x2000) - return -1; - - // check if the pid is present (it must be!) - for (i = 0; i < adapter->pid_count; i++) { - if (adapter->pid_list[i] == pid) { - adapter->pid_rc[i]--; - if (adapter->pid_rc[i] <= 0) { - // remove from the list - adapter->pid_count--; - adapter->pid_list[i]=adapter->pid_list[adapter->pid_count]; - adapter->pid_rc[i] = adapter->pid_rc[adapter->pid_count]; - // hardware setting - remove_hw_pid(adapter, pid); - } - return 1; - } - } - - return -1; -} - - -/* dma & irq */ -static void ctrl_enable_smc(struct adapter *adapter, u32 op) -{ - write_reg_bitfield(adapter, 0x208, 0x00000800, op ? 0x00000800 : 0); -} - -static void dma_enable_disable_irq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3) -{ - adapter->dma_ctrl = adapter->dma_ctrl & 0x000f0000; - - if (flag1 == 0) { - if (flag2 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000; - - if (flag3 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000; - - } else { - - if (flag2 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000; - - if (flag3 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000; - } -} - -static void irq_dma_enable_disable_irq(struct adapter *adapter, u32 op) -{ - u32 value; - - value = read_reg_dw(adapter, 0x208) & 0xfff0ffff; - - if (op != 0) - value = value | (adapter->dma_ctrl & 0x000f0000); - - write_reg_dw(adapter, 0x208, value); -} - -/* FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to - system memory. - - The DMA1 buffer is divided in 2 subbuffers of equal size. - FlexCopII will transfer TS data to one subbuffer, signal an interrupt - when the subbuffer is full and continue fillig the second subbuffer. - - For DMA1: - subbuffer size in 32-bit words is stored in the first 24 bits of - register 0x004. The last 8 bits of register 0x004 contain the number - of subbuffers. - - the first 30 bits of register 0x000 contain the address of the first - subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1, - when dma1 is enabled. - - the first 30 bits of register 0x00c contain the address of the second - subbuffer. the last 2 bits contain 1. - - register 0x008 will contain the address of the subbuffer that was filled - with TS data, when FlexCopII will generate an interrupt. - - For DMA2: - subbuffer size in 32-bit words is stored in the first 24 bits of - register 0x014. The last 8 bits of register 0x014 contain the number - of subbuffers. - - the first 30 bits of register 0x010 contain the address of the first - subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1, - when dma1 is enabled. - - the first 30 bits of register 0x01c contain the address of the second - subbuffer. the last 2 bits contain 1. - - register 0x018 contains the address of the subbuffer that was filled - with TS data, when FlexCopII generates an interrupt. -*/ -static int dma_init_dma(struct adapter *adapter, u32 dma_channel) -{ - u32 subbuffers, subbufsize, subbuf0, subbuf1; - - if (dma_channel == 0) { - dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__); - - subbuffers = 2; - - subbufsize = (((adapter->dmaq1.buffer_size / 2) / 4) << 8) | subbuffers; - - subbuf0 = adapter->dmaq1.bus_addr & 0xfffffffc; - - subbuf1 = ((adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) & 0xfffffffc) | 1; - - dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0); - udelay(1000); - write_reg_dw(adapter, 0x000, subbuf0); - - dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4); - udelay(1000); - write_reg_dw(adapter, 0x004, subbufsize); - - dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1); - udelay(1000); - write_reg_dw(adapter, 0x00c, subbuf1); - - dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->dmaq1.bus_addr & 0xfffffffc); - write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc); - udelay(1000); - - dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0); - - irq_dma_enable_disable_irq(adapter, 1); - - sram_set_media_dest(adapter, 1); - sram_set_net_dest(adapter, 1); - sram_set_cai_dest(adapter, 2); - sram_set_cao_dest(adapter, 2); - } - - if (dma_channel == 1) { - dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__); - - subbuffers = 2; - - subbufsize = (((adapter->dmaq2.buffer_size / 2) / 4) << 8) | subbuffers; - - subbuf0 = adapter->dmaq2.bus_addr & 0xfffffffc; - - subbuf1 = ((adapter->dmaq2.bus_addr + adapter->dmaq2.buffer_size / 2) & 0xfffffffc) | 1; - - dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0); - udelay(1000); - write_reg_dw(adapter, 0x010, subbuf0); - - dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4); - udelay(1000); - write_reg_dw(adapter, 0x014, subbufsize); - - dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1); - udelay(1000); - write_reg_dw(adapter, 0x01c, subbuf1); - - sram_set_cai_dest(adapter, 2); - } - - return 0; -} - -static void ctrl_enable_receive_data(struct adapter *adapter, u32 op) -{ - if (op == 0) { - write_reg_bitfield(adapter, 0x208, 0x00008000, 0); - adapter->dma_status = adapter->dma_status & ~0x00000004; - } else { - write_reg_bitfield(adapter, 0x208, 0x00008000, 0x00008000); - adapter->dma_status = adapter->dma_status | 0x00000004; - } -} - -/* bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled - bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled -*/ -static void dma_start_stop(struct adapter *adapter, u32 dma_mask, int start_stop) -{ - u32 dma_enable, dma1_enable, dma2_enable; - - dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask); - - if (start_stop == 1) { - dprintk("%s: starting dma\n", __FUNCTION__); - - dma1_enable = 0; - dma2_enable = 0; - - if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->dmaq1.bus_addr != 0)) { - adapter->dma_status = adapter->dma_status | 1; - dma1_enable = 1; - } - - if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->dmaq2.bus_addr != 0)) { - adapter->dma_status = adapter->dma_status | 2; - dma2_enable = 1; - } - // enable dma1 and dma2 - if ((dma1_enable == 1) && (dma2_enable == 1)) { - write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1); - write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); - write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1); - - ctrl_enable_receive_data(adapter, 1); - - return; - } - // enable dma1 - if ((dma1_enable == 1) && (dma2_enable == 0)) { - write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1); - write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); - - ctrl_enable_receive_data(adapter, 1); - - return; - } - // enable dma2 - if ((dma1_enable == 0) && (dma2_enable == 1)) { - write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1); - - ctrl_enable_receive_data(adapter, 1); - - return; - } - // start dma - if ((dma1_enable == 0) && (dma2_enable == 0)) { - ctrl_enable_receive_data(adapter, 1); - - return; - } - - } else { - - dprintk("%s: stopping dma\n", __FUNCTION__); - - dma_enable = adapter->dma_status & 0x00000003; - - if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) { - dma_enable = dma_enable & 0xfffffffe; - } - - if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) { - dma_enable = dma_enable & 0xfffffffd; - } - //stop dma - if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) { - ctrl_enable_receive_data(adapter, 0); - - udelay(3000); - } - //disable dma1 - if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->dmaq1.bus_addr != 0)) { - write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr); - write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); - - adapter->dma_status = adapter->dma_status & ~0x00000001; - } - //disable dma2 - if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->dmaq2.bus_addr != 0)) { - write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr); - - adapter->dma_status = adapter->dma_status & ~0x00000002; - } - } -} - -static void open_stream(struct adapter *adapter, u16 pid) -{ - u32 dma_mask; - - ++adapter->capturing; - - filter_enable_mask_filter(adapter, 1); - - add_pid(adapter, pid); - - dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status); - - if ((adapter->dma_status & 7) != 7) { - dma_mask = 0; - - if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) { - dma_mask = dma_mask | 1; - - adapter->dmaq1.head = 0; - adapter->dmaq1.tail = 0; - - memset(adapter->dmaq1.buffer, 0, adapter->dmaq1.buffer_size); - } - - if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) { - dma_mask = dma_mask | 2; - - adapter->dmaq2.head = 0; - adapter->dmaq2.tail = 0; - } - - if (dma_mask != 0) { - irq_dma_enable_disable_irq(adapter, 1); - - dma_start_stop(adapter, dma_mask, 1); - } - } -} - -static void close_stream(struct adapter *adapter, u16 pid) -{ - if (adapter->capturing > 0) - --adapter->capturing; - - dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status); - - if (adapter->capturing == 0) { - u32 dma_mask = 0; - - if ((adapter->dma_status & 1) != 0) - dma_mask = dma_mask | 0x00000001; - if ((adapter->dma_status & 2) != 0) - dma_mask = dma_mask | 0x00000002; - - if (dma_mask != 0) { - dma_start_stop(adapter, dma_mask, 0); - } - } - remove_pid(adapter, pid); -} - -static void interrupt_service_dma1(struct adapter *adapter) -{ - struct dvb_demux *dvbdmx = &adapter->demux; - - int n_cur_dma_counter; - u32 n_num_bytes_parsed; - u32 n_num_new_bytes_transferred; - u32 dw_default_packet_size = 188; - u8 gb_tmp_buffer[188]; - u8 *pb_dma_buf_cur_pos; - - n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr; - n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size; - - if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) { - dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__); - return; - } - - adapter->dmaq1.head = n_cur_dma_counter; - - if (adapter->dmaq1.tail <= n_cur_dma_counter) { - n_num_new_bytes_transferred = n_cur_dma_counter - adapter->dmaq1.tail; - - } else { - - n_num_new_bytes_transferred = (adapter->dmaq1.buffer_size - adapter->dmaq1.tail) + n_cur_dma_counter; - } - - ddprintk("%s: n_cur_dma_counter = %d\n", __FUNCTION__, n_cur_dma_counter); - ddprintk("%s: dmaq1.tail = %d\n", __FUNCTION__, adapter->dmaq1.tail); - ddprintk("%s: bytes_transferred = %d\n", __FUNCTION__, n_num_new_bytes_transferred); - - if (n_num_new_bytes_transferred < dw_default_packet_size) - return; - - n_num_bytes_parsed = 0; - - while (n_num_bytes_parsed < n_num_new_bytes_transferred) { - pb_dma_buf_cur_pos = adapter->dmaq1.buffer + adapter->dmaq1.tail; - - if (adapter->dmaq1.buffer + adapter->dmaq1.buffer_size < adapter->dmaq1.buffer + adapter->dmaq1.tail + 188) { - memcpy(gb_tmp_buffer, adapter->dmaq1.buffer + adapter->dmaq1.tail, - adapter->dmaq1.buffer_size - adapter->dmaq1.tail); - memcpy(gb_tmp_buffer + (adapter->dmaq1.buffer_size - adapter->dmaq1.tail), adapter->dmaq1.buffer, - (188 - (adapter->dmaq1.buffer_size - adapter->dmaq1.tail))); - - pb_dma_buf_cur_pos = gb_tmp_buffer; - } - - if (adapter->capturing != 0) { - dvb_dmx_swfilter_packets(dvbdmx, pb_dma_buf_cur_pos, dw_default_packet_size / 188); - } - - n_num_bytes_parsed = n_num_bytes_parsed + dw_default_packet_size; - - adapter->dmaq1.tail = adapter->dmaq1.tail + dw_default_packet_size; - - if (adapter->dmaq1.tail >= adapter->dmaq1.buffer_size) - adapter->dmaq1.tail = adapter->dmaq1.tail - adapter->dmaq1.buffer_size; - }; -} - -static void interrupt_service_dma2(struct adapter *adapter) -{ - printk("%s:\n", __FUNCTION__); -} - -static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs) -{ - struct adapter *tmp = dev_id; - - u32 value; - - ddprintk("%s:\n", __FUNCTION__); - - spin_lock_irq(&tmp->lock); - - if (0 == ((value = read_reg_dw(tmp, 0x20c)) & 0x0f)) { - spin_unlock_irq(&tmp->lock); - return IRQ_NONE; - } - - while (value != 0) { - if ((value & 0x03) != 0) - interrupt_service_dma1(tmp); - if ((value & 0x0c) != 0) - interrupt_service_dma2(tmp); - value = read_reg_dw(tmp, 0x20c) & 0x0f; - } - - spin_unlock_irq(&tmp->lock); - return IRQ_HANDLED; -} - -static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq, - int size, int dmaq_offset) -{ - struct pci_dev *pdev = adapter->pdev; - dma_addr_t dma_addr; - - dmaq->head = 0; - dmaq->tail = 0; - - dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr); - if (!dmaq->buffer) - return -ENOMEM; - - dmaq->bus_addr = dma_addr; - dmaq->buffer_size = size; - - dma_init_dma(adapter, dmaq_offset); - - ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", - __FUNCTION__, dmaq->buffer, size); - - return 0; - } - -static int init_dma_queue(struct adapter *adapter) -{ - struct { - struct dmaq *dmaq; - u32 dma_status; - int size; - } dmaq_desc[] = { - { &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 }, - { &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 } - }, *p = dmaq_desc; - int i; - - for (i = 0; i < 2; i++, p++) { - if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0) - adapter->dma_status &= ~p->dma_status; - else - adapter->dma_status |= p->dma_status; - } - return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM; -} - -static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq) -{ - if (dmaq->buffer) { - pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80, - dmaq->buffer, dmaq->bus_addr); - memset(dmaq, 0, sizeof(*dmaq)); - } -} - -static void free_dma_queue(struct adapter *adapter) -{ - struct dmaq *dmaq[] = { - &adapter->dmaq1, - &adapter->dmaq2, - NULL - }, **p; - - for (p = dmaq; *p; p++) - free_dma_queue_one(adapter, *p); - } - -static void release_adapter(struct adapter *adapter) -{ - struct pci_dev *pdev = adapter->pdev; - - iounmap(adapter->io_mem); - pci_disable_device(pdev); - pci_release_region(pdev, 0); - pci_release_region(pdev, 1); -} - -static void free_adapter_object(struct adapter *adapter) -{ - dprintk("%s:\n", __FUNCTION__); - - close_stream(adapter, 0); - free_irq(adapter->irq, adapter); - free_dma_queue(adapter); - release_adapter(adapter); - kfree(adapter); -} - -static struct pci_driver skystar2_pci_driver; - -static int claim_adapter(struct adapter *adapter) -{ - struct pci_dev *pdev = adapter->pdev; - u16 var; - int ret; - - ret = pci_request_region(pdev, 1, skystar2_pci_driver.name); - if (ret < 0) - goto out; - - ret = pci_request_region(pdev, 0, skystar2_pci_driver.name); - if (ret < 0) - goto err_pci_release_1; - - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision); - - dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision); - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_pci_release_0; - - pci_read_config_word(pdev, 4, &var); - - if ((var & 4) == 0) - pci_set_master(pdev); - - adapter->io_port = pdev->resource[1].start; - - adapter->io_mem = ioremap(pdev->resource[0].start, 0x800); - - if (!adapter->io_mem) { - dprintk("%s: can not map io memory\n", __FUNCTION__); - ret = -EIO; - goto err_pci_disable; - } - - dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem); - - ret = 1; -out: - return ret; - -err_pci_disable: - pci_disable_device(pdev); -err_pci_release_0: - pci_release_region(pdev, 0); -err_pci_release_1: - pci_release_region(pdev, 1); - goto out; -} - -/* -static int sll_reset_flexcop(struct adapter *adapter) -{ - write_reg_dw(adapter, 0x208, 0); - write_reg_dw(adapter, 0x210, 0xb2ff); - - return 0; -} -*/ - -static void decide_how_many_hw_filters(struct adapter *adapter) -{ - int hw_filters; - int mod_option_hw_filters; - - // FlexCop IIb & III have 6+32 hw filters - // FlexCop II has 6 hw filters, every other should have at least 6 - switch (adapter->b2c2_revision) { - case 0x82: /* II */ - hw_filters = 6; - break; - case 0xc3: /* IIB */ - hw_filters = 6 + 32; - break; - case 0xc0: /* III */ - hw_filters = 6 + 32; - break; - default: - hw_filters = 6; - break; - } - printk("%s: the chip has %i hardware filters", __FILE__, hw_filters); - - mod_option_hw_filters = 0; - if (enable_hw_filters >= 1) - mod_option_hw_filters += 6; - if (enable_hw_filters >= 2) - mod_option_hw_filters += 32; - - if (mod_option_hw_filters >= hw_filters) { - adapter->useable_hw_filters = hw_filters; - } else { - adapter->useable_hw_filters = mod_option_hw_filters; - printk(", but only %d will be used because of module option", mod_option_hw_filters); - } - printk("\n"); - dprintk("%s: useable_hardware_filters set to %i\n", __FILE__, adapter->useable_hw_filters); -} - -static int driver_initialize(struct pci_dev *pdev) -{ - struct adapter *adapter; - u32 tmp; - int ret = -ENOMEM; - - adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL); - if (!adapter) { - dprintk("%s: out of memory!\n", __FUNCTION__); - goto out; - } - - memset(adapter, 0, sizeof(struct adapter)); - - pci_set_drvdata(pdev,adapter); - - adapter->pdev = pdev; - adapter->irq = pdev->irq; - - ret = claim_adapter(adapter); - if (ret < 0) - goto err_kfree; - - irq_dma_enable_disable_irq(adapter, 0); - - ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter); - if (ret < 0) { - dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq); - goto err_release_adapter; - } - - read_reg_dw(adapter, 0x208); - write_reg_dw(adapter, 0x208, 0); - write_reg_dw(adapter, 0x210, 0xb2ff); - write_reg_dw(adapter, 0x208, 0x40); - - ret = init_dma_queue(adapter); - if (ret < 0) - goto err_free_irq; - - adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18); - - switch (adapter->b2c2_revision) { - case 0x82: - printk("%s: FlexCopII(rev.130) chip found\n", __FILE__); - break; - case 0xc3: - printk("%s: FlexCopIIB(rev.195) chip found\n", __FILE__); - break; - case 0xc0: - printk("%s: FlexCopIII(rev.192) chip found\n", __FILE__); - break; - default: - printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision); - printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__); - ret = -ENODEV; - goto err_free_dma_queue; - } - - decide_how_many_hw_filters(adapter); - - init_pids(adapter); - - tmp = read_reg_dw(adapter, 0x204); - - write_reg_dw(adapter, 0x204, 0); - mdelay(20); - - write_reg_dw(adapter, 0x204, tmp); - mdelay(10); - - tmp = read_reg_dw(adapter, 0x308); - write_reg_dw(adapter, 0x308, 0x4000 | tmp); - - adapter->dw_sram_type = 0x10000; - - sll_detect_sram_size(adapter); - - dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, sram_length(adapter), adapter->dw_sram_type); - - sram_set_media_dest(adapter, 1); - sram_set_net_dest(adapter, 1); - - ctrl_enable_smc(adapter, 0); - - sram_set_cai_dest(adapter, 2); - sram_set_cao_dest(adapter, 2); - - dma_enable_disable_irq(adapter, 1, 0, 0); - - if (eeprom_get_mac_addr(adapter, 0, adapter->mac_addr) != 0) { - printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0], - adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5], - adapter->mac_addr[6], adapter->mac_addr[7] - ); - - ca_set_mac_dst_addr_filter(adapter, adapter->mac_addr); - ctrl_enable_mac(adapter, 1); - } - - spin_lock_init(&adapter->lock); - -out: - return ret; - -err_free_dma_queue: - free_dma_queue(adapter); -err_free_irq: - free_irq(pdev->irq, adapter); -err_release_adapter: - release_adapter(adapter); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(adapter); - goto out; -} - -static void driver_halt(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - irq_dma_enable_disable_irq(adapter, 0); - - ctrl_enable_receive_data(adapter, 0); - - free_adapter_object(adapter); - - pci_set_drvdata(pdev, NULL); -} - -static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct adapter *adapter = (struct adapter *) dvbdmx->priv; - - dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); - - open_stream(adapter, dvbdmxfeed->pid); - - return 0; -} - -static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct adapter *adapter = (struct adapter *) dvbdmx->priv; - - dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); - - close_stream(adapter, dvbdmxfeed->pid); - - return 0; -} - -/* lnb control */ -static void set_tuner_tone(struct adapter *adapter, u8 tone) -{ - u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; - u16 ax; - - dprintk("%s: %u\n", __FUNCTION__, tone); - - switch (tone) { - case 1: - ax = wz_half_period_for_45_mhz[0]; - break; - case 2: - ax = wz_half_period_for_45_mhz[1]; - break; - case 3: - ax = wz_half_period_for_45_mhz[2]; - break; - case 4: - ax = wz_half_period_for_45_mhz[3]; - break; - - default: - ax = 0; - } - - if (ax != 0) { - write_reg_dw(adapter, 0x200, ((ax << 0x0f) + (ax & 0x7fff)) | 0x40000000); - - } else { - - write_reg_dw(adapter, 0x200, 0x40ff8000); - } -} - -static void set_tuner_polarity(struct adapter *adapter, u8 polarity) -{ - u32 var; - - dprintk("%s : polarity = %u \n", __FUNCTION__, polarity); - - var = read_reg_dw(adapter, 0x204); - - if (polarity == 0) { - dprintk("%s: LNB power off\n", __FUNCTION__); - var = var | 1; - }; - - if (polarity == 1) { - var = var & ~1; - var = var & ~4; - }; - - if (polarity == 2) { - var = var & ~1; - var = var | 4; - } - - write_reg_dw(adapter, 0x204, var); -} - -static void diseqc_send_bit(struct adapter *adapter, int data) -{ - set_tuner_tone(adapter, 1); - udelay(data ? 500 : 1000); - set_tuner_tone(adapter, 0); - udelay(data ? 1000 : 500); -} - - -static void diseqc_send_byte(struct adapter *adapter, int data) - { - int i, par = 1, d; - - for (i = 7; i >= 0; i--) { - d = (data >> i) & 1; - par ^= d; - diseqc_send_bit(adapter, d); - } - - diseqc_send_bit(adapter, par); - } - - -static int send_diseqc_msg(struct adapter *adapter, int len, u8 *msg, unsigned long burst) -{ - int i; - - set_tuner_tone(adapter, 0); - mdelay(16); - - for (i = 0; i < len; i++) - diseqc_send_byte(adapter, msg[i]); - - mdelay(16); - - if (burst != -1) { - if (burst) - diseqc_send_byte(adapter, 0xff); - else { - set_tuner_tone(adapter, 1); - udelay(12500); - set_tuner_tone(adapter, 0); - } - msleep(20); - } - - return 0; -} - -static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - switch(tone) { - case SEC_TONE_ON: - set_tuner_tone(adapter, 1); - break; - case SEC_TONE_OFF: - set_tuner_tone(adapter, 0); - break; - default: - return -EINVAL; - }; - - return 0; -} - -static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) - { - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0); - - return 0; - } - -static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - send_diseqc_msg(adapter, 0, NULL, minicmd); - - return 0; -} - -static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) - { - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); - set_tuner_polarity(adapter, 1); - return 0; - - case SEC_VOLTAGE_18: - dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); - set_tuner_polarity(adapter, 2); - return 0; - - default: - return -EINVAL; - } - } - -static int flexcop_sleep(struct dvb_frontend* fe) - { - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - set_tuner_polarity(adapter, 0); - - if (adapter->fe_sleep) return adapter->fe_sleep(fe); - return 0; - } - -static u32 flexcop_i2c_func(struct i2c_adapter *adapter) - { - printk("flexcop_i2c_func\n"); - - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm flexcop_algo = { - .name = "flexcop i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = flexcop_i2c_func, -}; - - - - -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg (fe, 0x13, aclk); - stv0299_writereg (fe, 0x14, bclk); - stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - - return 0; -} - -static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - div = params->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x84; // 0xC4 - buf[3] = 0x08; - - if (params->frequency < 1500000) buf[3] |= 0x10; - - if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, - }; - -static struct stv0299_config samsung_tbmu24112_config = { - .demod_address = 0x68, - .inittab = samsung_tbmu24112_inittab, - .mclk = 88000000UL, - .invert = 0, - .enhanced_tuning = 0, - .skip_reinit = 0, - .lock_output = STV0229_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, - .pll_set = samsung_tbmu24112_pll_set, -}; - - - -static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - return request_firmware(fw, name, &adapter->pdev->dev); -} - - -static struct nxt2002_config samsung_tbmv_config = { - .demod_address = 0x0A, - .request_firmware = nxt2002_request_firmware, -}; - -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) -{ - u32 div; - unsigned char bs = 0; - - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; - if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; - if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; - - pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = 0xcc; - pllbuf[4] = bs; - - return 0; -} - -static struct mt352_config samsung_tdtc9251dh0_config = { - - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, - .pll_set = samsung_tdtc9251dh0_pll_set, -}; - -static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - div = (params->frequency + (125/2)) / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - buf[2] = 0x84 | ((div >> 10) & 0x60); - buf[3] = 0x80; - - if (params->frequency < 1550000) - buf[3] |= 0x02; - - if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct mt312_config skystar23_samsung_tbdu18132_config = { - - .demod_address = 0x0e, - .pll_set = skystar23_samsung_tbdu18132_pll_set, -}; - - - - -static void frontend_init(struct adapter *skystar2) -{ - switch(skystar2->pdev->device) { - case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC) - - // Attempt to load the Nextwave nxt2002 for ATSC support - skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe_sleep = skystar2->fe->ops->sleep; - skystar2->fe->ops->sleep = flexcop_sleep; - break; - } - - // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935)) - skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe->ops->set_voltage = flexcop_set_voltage; - skystar2->fe_sleep = skystar2->fe->ops->sleep; - skystar2->fe->ops->sleep = flexcop_sleep; - break; -} - - // try the airstar2 (mt352/Samsung tdtc9251dh0(??)) - skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe->ops->info.frequency_min = 474000000; - skystar2->fe->ops->info.frequency_max = 858000000; - break; - } - - // try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059)) - skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; - skystar2->fe->ops->set_tone = flexcop_set_tone; - skystar2->fe->ops->set_voltage = flexcop_set_voltage; - skystar2->fe_sleep = skystar2->fe->ops->sleep; - skystar2->fe->ops->sleep = flexcop_sleep; - break; - } - break; - } - - if (skystar2->fe == NULL) { - printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", - skystar2->pdev->vendor, - skystar2->pdev->device, - skystar2->pdev->subsystem_vendor, - skystar2->pdev->subsystem_device); - } else { - if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) { - printk("skystar2: Frontend registration failed!\n"); - if (skystar2->fe->ops->release) - skystar2->fe->ops->release(skystar2->fe); - skystar2->fe = NULL; - } - } -} - - -static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct adapter *adapter; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret = -ENODEV; - - if (!pdev) - goto out; - - ret = driver_initialize(pdev); - if (ret < 0) - goto out; - - adapter = pci_get_drvdata(pdev); - dvb_adapter = &adapter->dvb_adapter; - - ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name, - THIS_MODULE); - if (ret < 0) { - printk("%s: Error registering DVB adapter\n", __FUNCTION__); - goto err_halt; - } - - dvb_adapter->priv = adapter; - - - init_MUTEX(&adapter->i2c_sem); - - - memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter)); - strcpy(adapter->i2c_adap.name, "SkyStar2"); - - i2c_set_adapdata(&adapter->i2c_adap, adapter); - -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - adapter->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; -#else - adapter->i2c_adap.class = I2C_CLASS_TV_DIGITAL; -#endif - adapter->i2c_adap.algo = &flexcop_algo; - adapter->i2c_adap.algo_data = NULL; - adapter->i2c_adap.id = I2C_ALGO_BIT; - - ret = i2c_add_adapter(&adapter->i2c_adap); - if (ret < 0) - goto err_dvb_unregister; - - dvbdemux = &adapter->demux; - - dvbdemux->priv = adapter; - dvbdemux->filternum = N_PID_SLOTS; - dvbdemux->feednum = N_PID_SLOTS; - dvbdemux->start_feed = dvb_start_feed; - dvbdemux->stop_feed = dvb_stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - - ret = dvb_dmx_init(&adapter->demux); - if (ret < 0) - goto err_i2c_del; - - dmx = &dvbdemux->dmx; - - adapter->hw_frontend.source = DMX_FRONTEND_0; - adapter->dmxdev.filternum = N_PID_SLOTS; - adapter->dmxdev.demux = dmx; - adapter->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter); - if (ret < 0) - goto err_dmx_release; - - ret = dmx->add_frontend(dmx, &adapter->hw_frontend); - if (ret < 0) - goto err_dmxdev_release; - - adapter->mem_frontend.source = DMX_MEMORY_FE; - - ret = dmx->add_frontend(dmx, &adapter->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &adapter->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); - - frontend_init(adapter); -out: - return ret; - -err_remove_mem_frontend: - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend); -err_remove_hw_frontend: - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend); -err_dmxdev_release: - dvb_dmxdev_release(&adapter->dmxdev); -err_dmx_release: - dvb_dmx_release(&adapter->demux); -err_i2c_del: - i2c_del_adapter(&adapter->i2c_adap); -err_dvb_unregister: - dvb_unregister_adapter(&adapter->dvb_adapter); -err_halt: - driver_halt(pdev); - goto out; -} - -static void skystar2_remove(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - - if (!adapter) - return; - - dvb_net_release(&adapter->dvbnet); - dvbdemux = &adapter->demux; - dmx = &dvbdemux->dmx; - - dmx->close(dmx); - dmx->remove_frontend(dmx, &adapter->hw_frontend); - dmx->remove_frontend(dmx, &adapter->mem_frontend); - - dvb_dmxdev_release(&adapter->dmxdev); - dvb_dmx_release(dvbdemux); - - if (adapter->fe != NULL) - dvb_unregister_frontend(adapter->fe); - - dvb_unregister_adapter(&adapter->dvb_adapter); - - i2c_del_adapter(&adapter->i2c_adap); - - driver_halt(pdev); - } - -static struct pci_device_id skystar2_pci_tbl[] = { - {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, -/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl); - -static struct pci_driver skystar2_pci_driver = { - .name = "SkyStar2", - .id_table = skystar2_pci_tbl, - .probe = skystar2_probe, - .remove = skystar2_remove, -}; - -static int skystar2_init(void) -{ - return pci_register_driver(&skystar2_pci_driver); -} - -static void skystar2_cleanup(void) -{ - pci_unregister_driver(&skystar2_pci_driver); -} - -module_init(skystar2_init); -module_exit(skystar2_cleanup); - -MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 6757ccc57d2cc4ab4e63d8aee97f2e6b9f998990 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Thu, 7 Jul 2005 17:57:36 -0700 Subject: [PATCH] dvb: core: fix race condition in FE_READ_STATUS ioctl Fix a race condition where an application which issued a FE_READ_STATUS ioctl directly after FE_SET_FRONTEND would see an old status, i.e. FE_READ_STATUS would be executed before the frontend thread has even seen the tungin request from FE_SET_FRONTEND. Signed-off-by: Peter Beutner Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index f11daae91cd4..e561ac1e1b16 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -626,11 +626,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; } - case FE_READ_STATUS: + case FE_READ_STATUS: { + fe_status_t* status = parg; + + /* if retune was requested but hasn't occured yet, prevent + * that user get signal state from previous tuning */ + if(fepriv->state == FESTATE_RETUNE) { + err=0; + *status = 0; + break; + } + if (fe->ops->read_status) - err = fe->ops->read_status(fe, (fe_status_t*) parg); + err = fe->ops->read_status(fe, status); break; - + } case FE_READ_BER: if (fe->ops->read_ber) err = fe->ops->read_ber(fe, (__u32*) parg); -- cgit v1.2.2 From 4992775c8287145e86b94fe8d19bbb5f20148cc0 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:37 -0700 Subject: [PATCH] dvb: core: add workaround for tuning problem Add workaround for signal lock loss issue, where the frontend loses the signal after some hours without any visible reason. Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index e561ac1e1b16..a8bc84240b50 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -42,6 +42,8 @@ #include "dvb_frontend.h" #include "dvbdev.h" +// #define DEBUG_LOCKLOSS 1 + static int dvb_frontend_debug; static int dvb_shutdown_timeout = 5; static int dvb_force_auto_inversion; @@ -113,6 +115,7 @@ struct dvb_frontend_private { int exit; int wakeup; fe_status_t status; + fe_sec_tone_mode_t tone; }; @@ -434,9 +437,26 @@ static int dvb_frontend_thread(void *data) /* we're tuned, and the lock is still good... */ if (s & FE_HAS_LOCK) continue; - else { - /* if we _WERE_ tuned, but now don't have a lock, - * need to zigzag */ + else { /* if we _WERE_ tuned, but now don't have a lock */ +#ifdef DEBUG_LOCKLOSS + /* first of all try setting the tone again if it was on - this + * sometimes works around problems with noisy power supplies */ + if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) { + fe->ops->set_tone(fe, fepriv->tone); + mdelay(100); + s = 0; + fe->ops->read_status(fe, &s); + if (s & FE_HAS_LOCK) { + printk("DVB%i: Lock was lost, but regained by setting " + "the tone. This may indicate your power supply " + "is noisy/slightly incompatable with this DVB-S " + "adapter\n", fe->dvb->num); + fepriv->state = FESTATE_TUNED; + continue; + } + } +#endif + /* some other reason for losing the lock - start zigzagging */ fepriv->state = FESTATE_ZIGZAG_FAST; fepriv->started_auto_step = fepriv->auto_step; check_wrapped = 0; @@ -691,6 +711,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; + fepriv->tone = (fe_sec_tone_mode_t) parg; } break; @@ -893,6 +914,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->events.sem); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; + fepriv->tone = SEC_TONE_OFF; printk ("DVB: registering frontend %i (%s)...\n", fe->dvb->num, -- cgit v1.2.2 From 761979248adf83f5bece22e058ec445511984012 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Thu, 7 Jul 2005 17:57:38 -0700 Subject: [PATCH] dvb: core: demux error handling fix In dvb_dmxdev_filter_start if we go out because of an error, release previously allocated demux_feed. Signed-off-by: Peter Beutner Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dmxdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index c225de7ffd82..1624f4be5ea7 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -669,8 +669,10 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) ret = filter->feed.ts->start_filtering(filter->feed.ts); - if (ret < 0) + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); return ret; + } break; } -- cgit v1.2.2 From 3ec4a30771ed9a0ce6f05e637ea83b3781cc61d7 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Thu, 7 Jul 2005 17:57:39 -0700 Subject: [PATCH] dvb: core: dmxdev cleanups - remove void casts - not necessary to set filter state twice to STATE_FREE during dvb_dmxdev_init() Signed-off-by: Peter Beutner Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dmxdev.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 1624f4be5ea7..68050cd527cb 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -42,12 +42,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk if (debug) printk -static inline struct dmxdev_filter * -dvb_dmxdev_file_to_filter(struct file *file) -{ - return (struct dmxdev_filter *) file->private_data; -} - static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) { buffer->data=NULL; @@ -844,7 +838,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, static ssize_t dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter= file->private_data; int ret=0; if (down_interruptible(&dmxdevfilter->mutex)) @@ -865,7 +859,7 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev=dmxdevfilter->dev; unsigned long arg=(unsigned long) parg; int ret=0; @@ -962,7 +956,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file, static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) { - struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter = file->private_data; unsigned int mask = 0; if (!dmxdevfilter) @@ -987,7 +981,7 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) static int dvb_demux_release(struct inode *inode, struct file *file) { - struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev = dmxdevfilter->dev; return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); @@ -1111,7 +1105,6 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dmxdev->dvr[i].dev=dmxdev; dmxdev->dvr[i].buffer.data=NULL; - dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE); } -- cgit v1.2.2 From bbf24cec93b5966bdbd4f25be7a8a2d8716570db Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:40 -0700 Subject: [PATCH] dvb: frontend: remove unused I2C ids Remove I2C_DRIVERID_DVBFE_ cruft. Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.h | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index d2b021792791..9c2c1d1136bd 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -40,28 +40,6 @@ #include "dvbdev.h" -/* FIXME: Move to i2c-id.h */ -#define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_DIB3000MB I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_DST I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_DUMMY I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_L64781 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_MT312 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_MT352 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_NXT6000 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_SP887X I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_STV0299 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_TDA1004X I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2 - - struct dvb_frontend_tune_settings { int min_delay_ms; int step_size; -- cgit v1.2.2 From ecb60deb9d5bbcbab6c87ee5fde6f8368197fcac Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 7 Jul 2005 17:57:40 -0700 Subject: [PATCH] dvb: frontend: tda1004x update o added config options for IF frequency and AGC o support DSP boot from on board eeprom o added pll sleep call Signed-off-by: Hartmut Hackmann Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 193 +++++++++++++++++---------------- drivers/media/dvb/frontends/tda1004x.h | 27 ++++- drivers/media/dvb/ttpci/budget-av.c | 4 + drivers/media/dvb/ttpci/budget-ci.c | 4 + 4 files changed, 130 insertions(+), 98 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 0beb370792ae..8428c04914e4 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -49,10 +49,8 @@ struct tda1004x_state { /* private demod data */ u8 initialised; enum tda1004x_demod demod_type; - u8 fw_version; }; - static int debug; #define dprintk(args...) \ do { \ @@ -315,20 +313,35 @@ static int tda1004x_do_upload(struct tda1004x_state *state, memcpy(buf + 1, mem + pos, tx_size); fw_msg.len = tx_size + 1; if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) { - printk("tda1004x: Error during firmware upload\n"); + printk(KERN_ERR "tda1004x: Error during firmware upload\n"); return -EIO; } pos += tx_size; dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos); } + // give the DSP a chance to settle 03/10/05 Hac + msleep(100); return 0; } -static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) +static int tda1004x_check_upload_ok(struct tda1004x_state *state) { u8 data1, data2; + unsigned long timeout; + + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { + timeout = jiffies + 2 * HZ; + while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n"); + break; + } + msleep(1); + } + } else + msleep(100); // check upload was OK tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP @@ -336,9 +349,11 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); - if ((data1 != 0x67) || (data2 != dspVersion)) + if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2a) { + printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2); return -EIO; - + } + printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2); return 0; } @@ -349,14 +364,14 @@ static int tda10045_fwupload(struct dvb_frontend* fe) const struct firmware *fw; /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, 0x2c) == 0) + if (tda1004x_check_upload_ok(state) == 0) return 0; /* request the firmware, this will block until someone uploads it */ - printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); + printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); if (ret) { - printk("tda1004x: no firmware upload (timeout or file not found?)\n"); + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); return ret; } @@ -372,93 +387,81 @@ static int tda10045_fwupload(struct dvb_frontend* fe) ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); if (ret) return ret; - printk("tda1004x: firmware upload complete\n"); + printk(KERN_INFO "tda1004x: firmware upload complete\n"); /* wait for DSP to initialise */ /* DSPREADY doesn't seem to work on the TDA10045H */ msleep(100); - return tda1004x_check_upload_ok(state, 0x2c); + return tda1004x_check_upload_ok(state); } -static int tda10046_get_fw_version(struct tda1004x_state *state, - const struct firmware *fw) +static void tda10046_init_plls(struct dvb_frontend* fe) { - const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 }; - unsigned int i; - - /* area guessed from firmware v20, v21 and v25 */ - for (i = 0x660; i < 0x700; i++) { - if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) { - state->fw_version = fw->data[i + sizeof(pattern)]; - printk(KERN_INFO "tda1004x: using firmware v%02x\n", - state->fw_version); - return 0; - } - } + struct tda1004x_state* state = fe->demodulator_priv; - return -EINVAL; + tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 + if (state->config->xtal_freq == TDA10046_XTAL_4M ) { + dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 + } else { + dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 + } + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); + switch (state->config->if_freq) { + case TDA10046_FREQ_3617: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); + break; + case TDA10046_FREQ_3613: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13); + break; + } + tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz } static int tda10046_fwupload(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; - unsigned long timeout; int ret; const struct firmware *fw; /* reset + wake up chip */ - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); + tda1004x_write_byteI(state, TDA1004X_CONFC4, 0); tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); - msleep(100); + /* let the clocks recover from sleep */ + msleep(5); /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, state->fw_version) == 0) + if (tda1004x_check_upload_ok(state) == 0) return 0; - /* request the firmware, this will block until someone uploads it */ - printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE); - ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); - if (ret) { - printk("tda1004x: no firmware upload (timeout or file not found?)\n"); - return ret; - } - - if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */ - printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size); - return -EINVAL; - } - - ret = tda10046_get_fw_version(state, fw); - if (ret < 0) { - printk("tda1004x: unable to find firmware version\n"); - return ret; - } - /* set parameters */ - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST - - ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); - if (ret) - return ret; - printk("tda1004x: firmware upload complete\n"); - - /* wait for DSP to initialise */ - timeout = jiffies + HZ; - while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { - if (time_after(jiffies, timeout)) { - printk("tda1004x: DSP failed to initialised.\n"); - return -EIO; + tda10046_init_plls(fe); + + if (state->config->request_firmware != NULL) { + /* request the firmware, this will block until someone uploads it */ + printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); + ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); + if (ret) { + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); + return ret; } - msleep(1); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + if (ret) + return ret; + } else { + /* boot from firmware eeprom */ + /* Hac Note: we might need to do some GPIO Magic here */ + printk(KERN_INFO "tda1004x: booting from eeprom\n"); + tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); + msleep(300); } - - return tda1004x_check_upload_ok(state, state->fw_version); + return tda1004x_check_upload_ok(state); } static int tda1004x_encode_fec(int fec) @@ -560,12 +563,10 @@ static int tda10046_init(struct dvb_frontend* fe) if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); - return -EIO; + return -EIO; } - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip - - // Init the PLL + // Init the tuner PLL if (state->config->pll_init) { tda1004x_enable_tuner_i2c(state); state->config->pll_init(fe); @@ -574,32 +575,34 @@ static int tda10046_init(struct dvb_frontend* fe) // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40); - tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0 - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99 - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221 - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // } - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream + tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer + + tda10046_init_plls(fe); + switch (state->config->agc_config) { + case TDA10046_AGC_DEFAULT: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; + case TDA10046_AGC_IFO_AUTO_NEG: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; + } + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } - tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 - tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm + tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config - tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN + tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config + tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config - tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select - tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz - - tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); + tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select state->initialised = 1; return 0; @@ -629,9 +632,6 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, state->config->pll_set(fe, fe_params); tda1004x_disable_tuner_i2c(state); - if (state->demod_type == TDA1004X_DEMOD_TDA10046) - tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4); - // Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. if (state->demod_type == TDA1004X_DEMOD_TDA10045) { @@ -1090,6 +1090,8 @@ static int tda1004x_sleep(struct dvb_frontend* fe) case TDA1004X_DEMOD_TDA10046: tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); + if (state->config->pll_sleep != NULL) + state->config->pll_sleep(fe); break; } state->initialised = 0; @@ -1216,7 +1218,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10046; - state->fw_version = 0x20; /* dummy default value */ /* check if the demod is there */ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) { diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index c8e1d54ff262..103d08ff7b5d 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -26,6 +26,21 @@ #include #include +enum tda10046_xtal { + TDA10046_XTAL_4M, + TDA10046_XTAL_16M, +}; + +enum tda10046_agc { + TDA10046_AGC_DEFAULT, /* original configuration */ + TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ +}; + +enum tda10046_if { + TDA10046_FREQ_3617, /* original config, 36,166 MHZ */ + TDA10046_FREQ_3613, /* 36,13 MHZ */ +}; + struct tda1004x_config { /* the demodulator's i2c address */ @@ -37,14 +52,22 @@ struct tda1004x_config /* Does the OCLK signal need inverted? */ u8 invert_oclk; - /* value of N_I2C of the CONF_PLL3 register */ - u8 n_i2c; + /* Xtal frequency, 4 or 16MHz*/ + enum tda10046_xtal xtal_freq; + + /* IF frequency */ + enum tda10046_if if_freq; + + /* AGC configuration */ + enum tda10046_agc agc_config; /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); + void (*pll_sleep)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); /* request firmware for device */ + /* set this to NULL if the card has a firmware EEPROM */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 6e0f5d307c52..9e65bfd59c42 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -695,8 +695,12 @@ static struct tda1004x_config philips_tu1216_config = { .demod_address = 0x8, .invert = 1, .invert_oclk = 1, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, .pll_init = philips_tu1216_pll_init, .pll_set = philips_tu1216_pll_set, + .pll_sleep = NULL, .request_firmware = philips_tu1216_request_firmware, }; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index dce116111376..075eb40f5c16 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -838,8 +838,12 @@ static struct tda1004x_config philips_tdm1316l_config = { .demod_address = 0x8, .invert = 0, .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, .pll_init = philips_tdm1316l_pll_init, .pll_set = philips_tdm1316l_pll_set, + .pll_sleep = NULL, .request_firmware = philips_tdm1316l_request_firmware, }; -- cgit v1.2.2 From 3faadbb0fde3c53e1c4f13eabb478c0c7cb1e4dd Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 7 Jul 2005 17:57:42 -0700 Subject: [PATCH] dvb: frontend: bcm3510: fix firmware version check Fix limit for firmware version check was too low for tda10045. Signed-off-by: Hartmut Hackmann Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 8428c04914e4..237edc486122 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -349,7 +349,7 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state) data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); - if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2a) { + if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) { printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2); return -EIO; } -- cgit v1.2.2 From 0c744b010078bd65724477e75261e51712d290a0 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 7 Jul 2005 17:57:42 -0700 Subject: [PATCH] dvb: add missing release_firmware() calls Add missing release_firmware() calls to fix memory leaks. Signed-off-by: Anssi Hannula Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 2 ++ drivers/media/dvb/ttusb-dec/ttusb_dec.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 237edc486122..2d5f56cbf506 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -385,6 +385,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe) tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); + release_firmware(fw); if (ret) return ret; printk(KERN_INFO "tda1004x: firmware upload complete\n"); @@ -452,6 +453,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe) } tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + release_firmware(fw); if (ret) return ret; } else { diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 505bdaff5a7e..45c9a9a08e4d 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1281,6 +1281,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) if (firmware_size < 60) { printk("%s: firmware size too small for DSP code (%zu < 60).\n", __FUNCTION__, firmware_size); + release_firmware(fw_entry); return -1; } @@ -1294,6 +1295,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) printk("%s: crc32 check of DSP code failed (calculated " "0x%08x != 0x%08x in file), file invalid.\n", __FUNCTION__, crc32_csum, crc32_check); + release_firmware(fw_entry); return -1; } memcpy(idstring, &firmware[36], 20); @@ -1308,15 +1310,19 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); - if (result) + if (result) { + release_firmware(fw_entry); return result; + } trans_count = 0; j = 0; b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); - if (b == NULL) + if (b == NULL) { + release_firmware(fw_entry); return -ENOMEM; + } for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { size = firmware_size - i; @@ -1345,6 +1351,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); + release_firmware(fw_entry); kfree(b); return result; -- cgit v1.2.2 From f03cbea36ab9412dcea58e953be4933b36c9b7be Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 7 Jul 2005 17:57:43 -0700 Subject: [PATCH] dvb: frontend: tda1004x: support tda827x tuners o added preliminary support for tda827x tuners o set parameters for drift compensation to 0 makes no sense for DVB-T but can prevent lock Signed-off-by: Hartmut Hackmann Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 44 ++++++++++++++++++++++++++++++---- drivers/media/dvb/frontends/tda1004x.h | 4 ++++ 2 files changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 2d5f56cbf506..ab0c032472cc 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -120,6 +120,8 @@ static int debug; #define TDA10046H_GPIO_OUT_SEL 0x41 #define TDA10046H_GPIO_SELECT 0x42 #define TDA10046H_AGC_CONF 0x43 +#define TDA10046H_AGC_THR 0x44 +#define TDA10046H_AGC_RENORM 0x45 #define TDA10046H_AGC_GAINS 0x46 #define TDA10046H_AGC_TUN_MIN 0x47 #define TDA10046H_AGC_TUN_MAX 0x48 @@ -272,14 +274,26 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, switch (bandwidth) { case BANDWIDTH_6_MHZ: tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f); + } break; case BANDWIDTH_7_MHZ: tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79); + } break; case BANDWIDTH_8_MHZ: tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + } break; default: @@ -420,6 +434,14 @@ static void tda10046_init_plls(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13); break; + case TDA10046_FREQ_045: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + break; + case TDA10046_FREQ_052: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06); + break; } tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz } @@ -590,6 +612,16 @@ static int tda10046_init(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities break; + case TDA10046_AGC_IFO_AUTO_POS: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities + break; + case TDA10046_AGC_TDA827X: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup + tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; } tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } @@ -1091,9 +1123,12 @@ static int tda1004x_sleep(struct dvb_frontend* fe) break; case TDA1004X_DEMOD_TDA10046: - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); - if (state->config->pll_sleep != NULL) + if (state->config->pll_sleep != NULL) { + tda1004x_enable_tuner_i2c(state); state->config->pll_sleep(fe); + tda1004x_disable_tuner_i2c(state); + } + tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } state->initialised = 0; @@ -1104,8 +1139,9 @@ static int tda1004x_sleep(struct dvb_frontend* fe) static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { fesettings->min_delay_ms = 800; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; return 0; } diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index 103d08ff7b5d..8659c52647ad 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -34,11 +34,15 @@ enum tda10046_xtal { enum tda10046_agc { TDA10046_AGC_DEFAULT, /* original configuration */ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ + TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ + TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ }; enum tda10046_if { TDA10046_FREQ_3617, /* original config, 36,166 MHZ */ TDA10046_FREQ_3613, /* 36,13 MHZ */ + TDA10046_FREQ_045, /* low IF, 4.0, 4.5, or 5.0 MHZ */ + TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ }; struct tda1004x_config -- cgit v1.2.2 From f46dbb050b5c7585c34b9ef717d81d6fee883f9b Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:57:44 -0700 Subject: [PATCH] dvb: frontend: cx22702: support for cxusb Add .get_tune_settings callback (min_delay_ms = 1sec) and output_mode-field (parallel/serial) to support cxusb; minor cleanups. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/cx22702.c | 29 ++++++++++++++++++++--------- drivers/media/dvb/frontends/cx22702.h | 5 +++++ 2 files changed, 25 insertions(+), 9 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index f4aa44136c7c..9f639297a9f2 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -76,7 +76,6 @@ static u8 init_tab [] = { 0x49, 0x56, 0x6b, 0x1e, 0xc8, 0x02, - 0xf8, 0x02, 0xf9, 0x00, 0xfa, 0x00, 0xfb, 0x00, @@ -203,7 +202,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet struct cx22702_state* state = fe->demodulator_priv; /* set PLL */ - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); if (state->config->pll_set) { state->config->pll_set(fe, p); } else if (state->config->pll_desc) { @@ -217,7 +216,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet } else { BUG(); } - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); /* set inversion */ cx22702_set_inversion (state, p->inversion); @@ -256,7 +255,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc ); cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ - printk("%s: Autodetecting\n",__FUNCTION__); + dprintk("%s: Autodetecting\n",__FUNCTION__); return 0; } @@ -347,10 +346,11 @@ static int cx22702_init (struct dvb_frontend* fe) for (i=0; iconfig->output_mode << 1) & 0x02); /* init PLL */ if (state->config->pll_init) { - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe); state->config->pll_init(fe); cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); } @@ -440,8 +440,10 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) /* RS Uncorrectable Packet Count then reset */ _ucblocks = cx22702_readreg (state, 0xE3); - if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks); - else *ucblocks = state->prevUCBlocks - _ucblocks; + if (state->prevUCBlocks < _ucblocks) + *ucblocks = (_ucblocks - state->prevUCBlocks); + else + *ucblocks = state->prevUCBlocks - _ucblocks; state->prevUCBlocks = _ucblocks; return 0; @@ -457,6 +459,12 @@ static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return cx22702_get_tps (state, &p->u.ofdm); } +static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + static void cx22702_release(struct dvb_frontend* fe) { struct cx22702_state* state = fe->demodulator_priv; @@ -472,7 +480,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, /* allocate memory for the internal state */ state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); - if (state == NULL) goto error; + if (state == NULL) + goto error; /* setup the state */ state->config = config; @@ -481,7 +490,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, state->prevUCBlocks = 0; /* check if the demod is there */ - if (cx22702_readreg(state, 0x1f) != 0x3) goto error; + if (cx22702_readreg(state, 0x1f) != 0x3) + goto error; /* create dvb_frontend */ state->frontend.ops = &state->ops; @@ -514,6 +524,7 @@ static struct dvb_frontend_ops cx22702_ops = { .set_frontend = cx22702_set_tps, .get_frontend = cx22702_get_frontend, + .get_tune_settings = cx22702_get_tune_settings, .read_status = cx22702_read_status, .read_ber = cx22702_read_ber, diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 559fdb906669..11f86806756e 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -35,6 +35,11 @@ struct cx22702_config /* the demodulator's i2c address */ u8 demod_address; + /* serial/parallel output */ +#define CX22702_PARALLEL_OUTPUT 0 +#define CX22702_SERIAL_OUTPUT 1 + u8 output_mode; + /* PLL maintenance */ u8 pll_address; struct dvb_pll_desc *pll_desc; -- cgit v1.2.2 From 80064b803de140a65ca82bba5f0c40309b5a9f5e Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:45 -0700 Subject: [PATCH] dvb: frontend: l64781: improve tuning Disable zig-zag and set min_delay_ms = 4000 as suggested by Allan Guild to improve tuning with weak signal. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/l64781.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 031a1ddc7d11..faaad1ae8559 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -474,11 +474,12 @@ static int l64781_init(struct dvb_frontend* fe) return 0; } -static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +static int l64781_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) { - fesettings->min_delay_ms = 200; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; + fesettings->min_delay_ms = 4000; + fesettings->step_size = 0; + fesettings->max_drift = 0; return 0; } -- cgit v1.2.2 From 48e4cc2d210e817e808ac9db598ce3fb5d09c205 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:45 -0700 Subject: [PATCH] dvb: DVB update Increase some timeouts by a factor of 10 as suggested by Mikko Hamalainen and Timo Ketolainen, to improve tuning for QAM128 / weak signal. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/stv0297.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index e681263bf079..928aca052afe 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -617,7 +617,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* wait for WGAGC lock */ starttime = jiffies; - timeout = jiffies + (200 * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(2000); while (time_before(jiffies, timeout)) { msleep(10); if (stv0297_readreg(state, 0x43) & 0x08) @@ -629,7 +629,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par msleep(20); /* wait for equaliser partial convergence */ - timeout = jiffies + (50 * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(500); while (time_before(jiffies, timeout)) { msleep(10); @@ -642,7 +642,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } /* wait for equaliser full convergence */ - timeout = jiffies + (delay * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(delay); while (time_before(jiffies, timeout)) { msleep(10); @@ -659,7 +659,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_writereg_mask(state, 0x88, 8, 0); /* wait for main lock */ - timeout = jiffies + (20 * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(20); while (time_before(jiffies, timeout)) { msleep(10); -- cgit v1.2.2 From c7cadb3a02b5803c2f251b5cd84fbdc8fbec05e9 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Thu, 7 Jul 2005 17:57:46 -0700 Subject: [PATCH] dvb: add Pluto2 driver Add driver for the Satelco Easywatch Mobile DVB-T card (based on Pluto2 chip). Signed-off-by: Andreas Oberritter Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/Kconfig | 4 + drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/pluto2/Kconfig | 16 + drivers/media/dvb/pluto2/Makefile | 3 + drivers/media/dvb/pluto2/pluto2.c | 809 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 833 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/pluto2/Kconfig create mode 100644 drivers/media/dvb/pluto2/Makefile create mode 100644 drivers/media/dvb/pluto2/pluto2.c (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 01387f883cdf..3f0ec6be03ae 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -40,6 +40,10 @@ comment "Supported BT878 Adapters" depends on DVB_CORE && PCI source "drivers/media/dvb/bt8xx/Kconfig" +comment "Supported Pluto2 Adapters" + depends on DVB_CORE && PCI +source "drivers/media/dvb/pluto2/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 3c6ff1619103..a7ad0841e6fc 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig new file mode 100644 index 000000000000..f02842be0d60 --- /dev/null +++ b/drivers/media/dvb/pluto2/Kconfig @@ -0,0 +1,16 @@ +config DVB_PLUTO2 + tristate "Pluto2 cards" + depends on DVB_CORE && PCI + select I2C + select I2C_ALGOBIT + select DVB_TDA1004X + help + Support for PCI cards based on the Pluto2 FPGA like the Satelco + Easywatch Mobile Terrestrial DVB-T Receiver. + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the PCI bus, so you need + an external software decoder to watch TV on your computer. + + Say Y or M if you own such a device and want to use it. + diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile new file mode 100644 index 000000000000..86ca84b2be6e --- /dev/null +++ b/drivers/media/dvb/pluto2/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_PLUTO2) = pluto2.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c new file mode 100644 index 000000000000..706e0bcb5ede --- /dev/null +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -0,0 +1,809 @@ +/* + * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] + * + * Copyright (C) 2005 Andreas Oberritter + * + * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ + * by Dany Salman + * Copyright (c) 2004 TDF + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "tda1004x.h" + +#define DRIVER_NAME "pluto2" + +#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ +#define REG_PCAR 0x0020 /* PC address register */ +#define REG_TSCR 0x0024 /* TS ctrl & status */ +#define REG_MISC 0x0028 /* miscellaneous */ +#define REG_MMAC 0x002c /* MSB MAC address */ +#define REG_IMAC 0x0030 /* ISB MAC address */ +#define REG_LMAC 0x0034 /* LSB MAC address */ +#define REG_SPID 0x0038 /* SPI data */ +#define REG_SLCS 0x003c /* serial links ctrl/status */ + +#define PID0_NOFIL (0x0001 << 16) +#define PIDn_ENP (0x0001 << 15) +#define PID0_END (0x0001 << 14) +#define PID0_AFIL (0x0001 << 13) +#define PIDn_PID (0x1fff << 0) + +#define TSCR_NBPACKETS (0x00ff << 24) +#define TSCR_DEM (0x0001 << 17) +#define TSCR_DE (0x0001 << 16) +#define TSCR_RSTN (0x0001 << 15) +#define TSCR_MSKO (0x0001 << 14) +#define TSCR_MSKA (0x0001 << 13) +#define TSCR_MSKL (0x0001 << 12) +#define TSCR_OVR (0x0001 << 11) +#define TSCR_AFUL (0x0001 << 10) +#define TSCR_LOCK (0x0001 << 9) +#define TSCR_IACK (0x0001 << 8) +#define TSCR_ADEF (0x007f << 0) + +#define MISC_DVR (0x0fff << 4) +#define MISC_ALED (0x0001 << 3) +#define MISC_FRST (0x0001 << 2) +#define MISC_LED1 (0x0001 << 1) +#define MISC_LED0 (0x0001 << 0) + +#define SPID_SPIDR (0x00ff << 0) + +#define SLCS_SCL (0x0001 << 7) +#define SLCS_SDA (0x0001 << 6) +#define SLCS_CSN (0x0001 << 2) +#define SLCS_OVR (0x0001 << 1) +#define SLCS_SWC (0x0001 << 0) + +#define TS_DMA_PACKETS (8) +#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) + +#define I2C_ADDR_TDA10046 0x10 +#define I2C_ADDR_TUA6034 0xc2 +#define NHWFILTERS 8 + +struct pluto { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + unsigned int users; + + /* i2c */ + struct i2c_algo_bit_data i2c_bit; + struct i2c_adapter i2c_adap; + unsigned int i2cbug; + + /* irq */ + unsigned int overflow; + + /* dma */ + dma_addr_t dma_addr; + u8 dma_buf[TS_DMA_BYTES]; + u8 dummy[4096]; +}; + +static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct pluto, demux); +} + +static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct pluto, dvb_adapter); +} + +static inline u32 pluto_readreg(struct pluto *pluto, u32 reg) +{ + return readl(&pluto->io_mem[reg]); +} + +static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) +{ + writel(val, &pluto->io_mem[reg]); +} + +static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) +{ + u32 val = readl(&pluto->io_mem[reg]); + val &= ~mask; + val |= bits; + writel(val, &pluto->io_mem[reg]); +} + +static void pluto_setsda(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); + else + pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); +} + +static void pluto_setscl(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); + else + pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); + + /* try to detect i2c_inb() to workaround hardware bug: + * reset SDA to high after SCL has been set to low */ + if ((state) && (pluto->i2cbug == 0)) { + pluto->i2cbug = 1; + } else { + if ((!state) && (pluto->i2cbug == 1)) + pluto_setsda(pluto, 1); + pluto->i2cbug = 0; + } +} + +static int pluto_getsda(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; +} + +static int pluto_getscl(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; +} + +static void pluto_reset_frontend(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_MISC); + + if (val & MISC_FRST) { + val &= ~MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } + if (reenable) { + val |= MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } +} + +static void pluto_reset_ts(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + if (val & TSCR_RSTN) { + val &= ~TSCR_RSTN; + pluto_writereg(pluto, REG_TSCR, val); + } + if (reenable) { + val |= TSCR_RSTN; + pluto_writereg(pluto, REG_TSCR, val); + } +} + +static void pluto_set_dma_addr(struct pluto *pluto) +{ + pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr)); +} + +static int __devinit pluto_dma_map(struct pluto *pluto) +{ + pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + return pci_dma_mapping_error(pluto->dma_addr); +} + +static void pluto_dma_unmap(struct pluto *pluto) +{ + pci_unmap_single(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static int pluto_start_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* enable PID filtering */ + if (pluto->users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); + else if (pluto->full_ts_users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); + + return 0; +} + +static int pluto_stop_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* disable PID filtering */ + if (--pluto->users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); + else if (--pluto->full_ts_users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); + + return 0; +} + +static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) +{ + /* synchronize the DMA transfer with the CPU + * first so that we see updated contents. */ + pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + /* Workaround for broken hardware: + * [1] On startup NBPACKETS seems to contain an uninitialized value, + * but no packets have been transfered. + * [2] Sometimes (actually very often) NBPACKETS stays at zero + * although one packet has been transfered. + */ + if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { + unsigned int i = 0, valid; + while (pluto->dma_buf[i] == 0x47) + i += 188; + valid = i / 188; + if (nbpackets != valid) { + dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n", + nbpackets, valid); + nbpackets = valid; + } + } + + dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); + + /* clear the dma buffer. this is needed to be able to identify + * new valid ts packets above */ + memset(pluto->dma_buf, 0, nbpackets * 188); + + /* reset the dma address */ + pluto_set_dma_addr(pluto); + + /* sync the buffer and give it back to the card */ + pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pluto *pluto = dev_id; + u32 tscr; + + /* check whether an interrupt occured on this device */ + tscr = pluto_readreg(pluto, REG_TSCR); + if (!(tscr & (TSCR_DE | TSCR_OVR))) + return IRQ_NONE; + + if (tscr == 0xffffffff) { + // FIXME: maybe recover somehow + dev_err(&pluto->pdev->dev, "card hung up :(\n"); + return IRQ_HANDLED; + } + + /* dma end interrupt */ + if (tscr & TSCR_DE) { + pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); + /* overflow interrupt */ + if (tscr & TSCR_OVR) + pluto->overflow++; + if (pluto->overflow) { + dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", + pluto->overflow); + pluto_reset_ts(pluto, 1); + pluto->overflow = 0; + } + } else if (tscr & TSCR_OVR) { + pluto->overflow++; + } + + /* ACK the interrupt */ + pluto_writereg(pluto, REG_TSCR, tscr | TSCR_IACK); + + return IRQ_HANDLED; +} + +static void __devinit pluto_enable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* set the number of packets */ + val &= ~TSCR_ADEF; + val |= TS_DMA_PACKETS / 2; + /* disable AFUL and LOCK interrupts */ + val |= (TSCR_MSKA | TSCR_MSKL); + /* enable DMA and OVERFLOW interrupts */ + val &= ~(TSCR_DEM | TSCR_MSKO); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_writereg(pluto, REG_TSCR, val); +} + +static void pluto_disable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* disable all interrupts */ + val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_writereg(pluto, REG_TSCR, val); +} + +static int __devinit pluto_hw_init(struct pluto *pluto) +{ + pluto_reset_frontend(pluto, 1); + + /* set automatic LED control by FPGA */ + pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); + + /* set data endianess */ +#ifdef __LITTLE_ENDIAN + pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); +#else + pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); +#endif + /* map DMA and set address */ + pluto_dma_map(pluto); + pluto_set_dma_addr(pluto); + + /* enable interrupts */ + pluto_enable_irqs(pluto); + + /* reset TS logic */ + pluto_reset_ts(pluto, 1); + + return 0; +} + +static void pluto_hw_exit(struct pluto *pluto) +{ + /* disable interrupts */ + pluto_disable_irqs(pluto); + + pluto_reset_ts(pluto, 0); + + /* LED: disable automatic control, enable yellow, disable green */ + pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); + + /* unmap DMA */ + pluto_dma_unmap(pluto); + + pluto_reset_frontend(pluto, 0); +} + +static inline u32 divide(u32 numerator, u32 denominator) +{ + if (denominator == 0) + return ~0; + + return (numerator + denominator / 2) / denominator; +} + +/* LG Innotek TDTE-E001P (Infineon TUA6034) */ +static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct pluto *pluto = frontend_to_pluto(fe); + struct i2c_msg msg; + int ret; + u8 buf[4]; + u32 div; + + // Fref = 166.667 Hz + // Fref * 3 = 500.000 Hz + // IF = 36166667 + // IF / Fref = 217 + //div = divide(p->frequency + 36166667, 166667); + div = divide(p->frequency * 3, 500000) + 217; + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + + if (p->frequency < 611000000) + buf[2] = 0xb4; + else if (p->frequency < 811000000) + buf[2] = 0xbc; + else + buf[2] = 0xf4; + + // VHF: 174-230 MHz + // center: 350 MHz + // UHF: 470-862 MHz + if (p->frequency < 350000000) + buf[3] = 0x02; + else + buf[3] = 0x04; + + if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x08; + + if (sizeof(buf) == 6) { + buf[4] = buf[2]; + buf[4] &= ~0x1c; + buf[4] |= 0x18; + + buf[5] = (0 << 7) | (2 << 4); + } + + msg.addr = I2C_ADDR_TUA6034 >> 1; + msg.flags = 0; + msg.buf = buf; + msg.len = sizeof(buf); + + ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); + if (ret < 0) + return ret; + else if (ret == 0) + return -EREMOTEIO; + + return 0; +} + +static int pluto2_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct pluto *pluto = frontend_to_pluto(fe); + + return request_firmware(fw, name, &pluto->pdev->dev); +} + +static struct tda1004x_config pluto2_fe_config __devinitdata = { + .demod_address = I2C_ADDR_TDA10046 >> 1, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .pll_set = lg_tdtpe001p_pll_set, + .pll_sleep = NULL, + .request_firmware = pluto2_request_firmware, +}; + +static int __devinit frontend_init(struct pluto *pluto) +{ + int ret; + + pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); + if (!pluto->fe) { + dev_err(&pluto->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + + ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); + if (ret < 0) { + if (pluto->fe->ops->release) + pluto->fe->ops->release(pluto->fe); + return ret; + } + + return 0; +} + +static void __devinit pluto_read_rev(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; + dev_info(&pluto->pdev->dev, "board revision %d.%d\n", + (val >> 12) & 0x0f, (val >> 4) & 0xff); +} + +static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) +{ + u32 val = pluto_readreg(pluto, REG_MMAC); + mac[0] = (val >> 8) & 0xff; + mac[1] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_IMAC); + mac[2] = (val >> 8) & 0xff; + mac[3] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_LMAC); + mac[4] = (val >> 8) & 0xff; + mac[5] = (val >> 0) & 0xff; + + dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static int __devinit pluto_read_serial(struct pluto *pluto) +{ + struct pci_dev *pdev = pluto->pdev; + unsigned int i, j; + u8 __iomem *cis; + + cis = pci_iomap(pdev, 1, 0); + if (!cis) + return -EIO; + + dev_info(&pdev->dev, "S/N "); + + for (i = 0xe0; i < 0x100; i += 4) { + u32 val = readl(&cis[i]); + for (j = 0; j < 32; j += 8) { + if ((val & 0xff) == 0xff) + goto out; + printk("%c", val & 0xff); + val >>= 8; + } + } +out: + printk("\n"); + pci_iounmap(pdev, cis); + + return 0; +} + +static int __devinit pluto2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct pluto *pluto; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + + pluto = kmalloc(sizeof(struct pluto), GFP_KERNEL); + if (!pluto) + goto out; + + memset(pluto, 0, sizeof(struct pluto)); + pluto->pdev = pdev; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + /* enable interrupts */ + pci_write_config_dword(pdev, 0x6c, 0x8000); + + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (ret < 0) + goto err_pci_disable_device; + + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret < 0) + goto err_pci_disable_device; + + pluto->io_mem = pci_iomap(pdev, 0, 0x40); + if (!pluto->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(pdev, pluto); + + ret = request_irq(pdev->irq, pluto_irq, SA_SHIRQ, DRIVER_NAME, pluto); + if (ret < 0) + goto err_pci_iounmap; + + ret = pluto_hw_init(pluto); + if (ret < 0) + goto err_free_irq; + + /* i2c */ + i2c_set_adapdata(&pluto->i2c_adap, pluto); + strcpy(pluto->i2c_adap.name, DRIVER_NAME); + pluto->i2c_adap.owner = THIS_MODULE; + pluto->i2c_adap.id = I2C_ALGO_BIT; + pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL; + pluto->i2c_adap.dev.parent = &pdev->dev; + pluto->i2c_adap.algo_data = &pluto->i2c_bit; + pluto->i2c_bit.data = pluto; + pluto->i2c_bit.setsda = pluto_setsda; + pluto->i2c_bit.setscl = pluto_setscl; + pluto->i2c_bit.getsda = pluto_getsda; + pluto->i2c_bit.getscl = pluto_getscl; + pluto->i2c_bit.udelay = 10; + pluto->i2c_bit.timeout = 10; + + /* Raise SCL and SDA */ + pluto_setsda(pluto, 1); + pluto_setscl(pluto, 1); + + ret = i2c_bit_add_bus(&pluto->i2c_adap); + if (ret < 0) + goto err_pluto_hw_exit; + + /* dvb */ + ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE); + if (ret < 0) + goto err_i2c_bit_del_bus; + + dvb_adapter = &pluto->dvb_adapter; + + pluto_read_rev(pluto); + pluto_read_serial(pluto); + pluto_read_mac(pluto, dvb_adapter->proposed_mac); + + dvbdemux = &pluto->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = pluto_start_feed; + dvbdemux->stop_feed = pluto_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + pluto->hw_frontend.source = DMX_FRONTEND_0; + pluto->mem_frontend.source = DMX_MEMORY_FE; + pluto->dmxdev.filternum = NHWFILTERS; + pluto->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &pluto->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = frontend_init(pluto); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); +out: + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &pluto->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &pluto->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&pluto->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_i2c_bit_del_bus: + i2c_bit_del_bus(&pluto->i2c_adap); +err_pluto_hw_exit: + pluto_hw_exit(pluto); +err_free_irq: + free_irq(pdev->irq, pluto); +err_pci_iounmap: + pci_iounmap(pdev, pluto->io_mem); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(pluto); + goto out; +} + +static void __devexit pluto2_remove(struct pci_dev *pdev) +{ + struct pluto *pluto = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; + struct dvb_demux *dvbdemux = &pluto->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&pluto->dvbnet); + if (pluto->fe) + dvb_unregister_frontend(pluto->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &pluto->mem_frontend); + dmx->remove_frontend(dmx, &pluto->hw_frontend); + dvb_dmxdev_release(&pluto->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + i2c_bit_del_bus(&pluto->i2c_adap); + pluto_hw_exit(pluto); + free_irq(pdev->irq, pluto); + pci_iounmap(pdev, pluto->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(pluto); +} + +#ifndef PCI_VENDOR_ID_SCM +#define PCI_VENDOR_ID_SCM 0x0432 +#endif +#ifndef PCI_DEVICE_ID_PLUTO2 +#define PCI_DEVICE_ID_PLUTO2 0x0001 +#endif + +static struct pci_device_id pluto2_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SCM, + .device = PCI_DEVICE_ID_PLUTO2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, pluto2_id_table); + +static struct pci_driver pluto2_driver = { + .name = DRIVER_NAME, + .id_table = pluto2_id_table, + .probe = pluto2_probe, + .remove = __devexit_p(pluto2_remove), +}; + +static int __init pluto2_init(void) +{ + return pci_register_driver(&pluto2_driver); +} + +static void __exit pluto2_exit(void) +{ + pci_unregister_driver(&pluto2_driver); +} + +module_init(pluto2_init); +module_exit(pluto2_exit); + +MODULE_AUTHOR("Andreas Oberritter "); +MODULE_DESCRIPTION("Pluto2 driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 2819639b5630cd26d399ee0481be9a752280cf4d Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:57:48 -0700 Subject: [PATCH] dvb: flexcop: add big endian register definitions Add big-endian register definitions for running on a PowerPC. (Thanks to Paavo Hartikainen for testing.) Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-reg.h | 548 +------------------------- drivers/media/dvb/b2c2/flexcop_ibi_value_be.h | 451 +++++++++++++++++++++ drivers/media/dvb/b2c2/flexcop_ibi_value_le.h | 451 +++++++++++++++++++++ 3 files changed, 909 insertions(+), 541 deletions(-) create mode 100644 drivers/media/dvb/b2c2/flexcop_ibi_value_be.h create mode 100644 drivers/media/dvb/b2c2/flexcop_ibi_value_le.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 75b50f21afe6..4ae1eb5bfe98 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -36,555 +36,21 @@ typedef enum { extern const char *flexcop_device_names[]; /* FlexCop IBI Registers */ +#if defined(__LITTLE_ENDIAN) + #include "flexcop_ibi_value_le.h" +#elif defined(__BIG_ENDIAN) + #include "flexcop_ibi_value_be.h" +#else + #error no endian defined +#endif -/* flexcop_ibi_reg - a huge union representing the register structure */ -typedef union { - u32 raw; - -/* DMA 0x000 to 0x01c - * DMA1 0x000 to 0x00c - * DMA2 0x010 to 0x01c - */ - struct { - u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */ - u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */ - u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */ - } dma_0x0; - - struct { - u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable - is able to be read and written while bit(1) of register - 0x00c (remap_enable) is set. This variable represents - the number of packets that will be transmitted to the PCI - host using PCI DMA1 before an interrupt to the PCI is - asserted. This functionality may be enabled using bit(20) - of register 0x208. N=0 disables the IRQ. */ - u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */ - } dma_0x4_remap; - - struct { - u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */ - u32 unused : 1; - u32 dma_addr_size :24; - } dma_0x4_read; - - struct { - u32 unused : 1; - u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */ - u32 dma_addr_size :24; - } dma_0x4_write; - - struct { - u32 unused : 2; - u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */ - } dma_0x8; - - struct { - u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */ - u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */ - u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */ - } dma_0xc; - -/* Two-wire Serial Master and Clock 0x100-0x110 */ - struct { -// u32 slave_transmitter : 1; /* ???*/ - u32 chipaddr : 7; /* two-line serial address of the target slave */ - u32 reserved1 : 1; - u32 baseaddr : 8; /* address of the location of the read/write operation */ - u32 data1_reg : 8; /* first byte in two-line serial read/write operation */ - u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready - * set to 1 when doing a write operation */ - u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */ - u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/ - u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */ - u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o - * preceding address assignment write frame - * ACK_ERROR = 1 when no ACK from slave in the last transaction */ - u32 st_done : 1; /* indicator for transaction is done */ - } tw_sm_c_100; - - struct { - u32 data2_reg : 8; /* 2nd data byte */ - u32 data3_reg : 8; /* 3rd data byte */ - u32 data4_reg : 8; /* 4th data byte */ - u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */ - u32 force_stop : 1; /* isolated stop flag */ - u32 unused : 6; - } tw_sm_c_104; - -/* Clock. The register allows the FCIII to convert an incoming Master clock - * (MCLK) signal into a lower frequency clock through the use of a LowCounter - * (TLO) and a High- Counter (THI). The time counts for THI and TLO are - * measured in MCLK; each count represents 4 MCLK input clock cycles. - * - * The default output for port #1 is set for Front End Demod communication. (0x108) - * The default output for port #2 is set for EEPROM communication. (0x10c) - * The default output for port #3 is set for Tuner communication. (0x110) - */ - struct { - u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */ - u32 reserved1 : 2; - u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */ - u32 reserved2 :19; - } tw_sm_c_108; - - struct { - u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */ - u32 reserved1 : 2; - u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */ - u32 reserved2 :19; - } tw_sm_c_10c; - - struct { - u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */ - u32 reserved1 : 2; - u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */ - u32 reserved2 :19; - } tw_sm_c_110; - -/* LNB Switch Frequency 0x200 - * Clock that creates the LNB switch tone. The default is set to have a fixed - * low output (not oscillating) to the LNB_CTL line. - */ - struct { - u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */ - u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master - Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */ - u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */ - } lnb_switch_freq_200; - -/* ACPI, Peripheral Reset, LNB Polarity - * ACPI power conservation mode, LNB polarity selection (low or high voltage), - * and peripheral reset. - */ - struct { - u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */ - u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */ - u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */ - u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */ - u32 reserved :20; - u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */ - u32 Rev_N_sig_reserved1 : 2; - u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */ - u32 Rev_N_sig_reserved2 : 1; - } misc_204; - -/* Control and Status 0x208 to 0x21c */ -/* Gross enable and disable control */ - struct { - u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */ - u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */ - u32 PCR_filter_sig : 1; /* PCR PID filter */ - u32 PMT_filter_sig : 1; /* PMT PID filter */ - - u32 EMM_filter_sig : 1; /* EMM PID filter */ - u32 ECM_filter_sig : 1; /* ECM PID filter */ - u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */ - u32 Mask_filter_sig : 1; /* mask PID filter */ - - u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */ - u32 WAN_CA_Enable_sig : 1; /* not in FCIII */ - u32 CA_Enable_sig : 1; /* not in FCIII */ - u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */ - - u32 Per_CA_Enable_sig : 1; /* not in FCIII */ - u32 Multi2_Enable_sig : 1; /* ? */ - u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */ - u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will - examine and process packets according to all other (individual) PID - filtering controls. If it a zero, no packet processing of any kind will - take place. All data from the tuner will be thrown away. */ - - u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI - * interrupt after the specified count for filling the buffer. */ - u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt - after a specified amount of time. */ - u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */ - u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */ - - u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */ - u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */ - u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the - PCI host to indicate that mailbox data is available. */ - - u32 unused : 9; - } ctrl_208; - -/* General status. When a PCI interrupt occurs, this register is read to - * discover the reason for the interrupt. - */ - struct { - u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */ - u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */ - u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */ - u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */ - u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */ - u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/ - u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */ - u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */ - u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */ - u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */ - u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */ - u32 reserved :21; - } irq_20c; - - -/* Software reset register */ - struct { - u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00. - Each bit location represents a 0x100 block of registers. Writing - a one in a bit location resets that block of registers and the logic - that it controls. */ - u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */ - u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A; - Turns off pci encryption => 0xC259 Note: pci_encryption default - at power-up is ON. */ - } sw_reset_210; - - struct { - u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART - (RS-232 Smart Card interface). When set, the IBI interface - defined by register 0x600 controls the serial UART. */ - u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line - Serial Master EEPROM target. When set, the Two-line Serial Master - EEPROM target interface is controlled by IBI register 0x100. */ - u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space - bus masters. Once this signal is cleared, normal V8-space - operations resume. */ - u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry - to process section packed transport streams. */ - u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data - within the FlexCop3 front end circuitry is converted from a serial - stream into parallel data before downstream processing otherwise - interprets the data. */ - u32 unused1 : 3; - u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream CLOCK signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream VALID signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream SYNC signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream ERROR signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 unused2 :20; - } misc_214; - -/* Mailbox from V8 to host */ - struct { - u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an - end host, an interrupt is generated to the PCI host to indicate - that mailbox data is available. Reading register 20c will clear - the IRQ. */ - } mbox_v8_to_host_218; - -/* Mailbox from host to v8 Mailbox_to_V8 - * Mailbox_to_V8 mailbox storage register - * used to send messages from PCI to V8. Writing to this register will send an - * IRQ to the V8. Then it can read the data from here. Reading this register - * will clear the IRQ. If the V8 is halted and bit 31 of this register is set, - * then this register is used instead as a direct interface to access the - * V8space memory. - */ - struct { - u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */ - u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */ - u32 unused : 7; - u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */ - u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows - this IBI register interface to directly drive the V8-space memory. */ - } mbox_host_to_v8_21c; - - -/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */ - struct { - u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally - hold the PID value for the desired network stream. */ - u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */ - u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */ - u32 debug_flag_pid_saved : 1; - u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */ - u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in - Stream2_PID TS packets. */ - u32 debug_flag_write_status00 : 1; - u32 debug_fifo_problem : 1; - } pid_filter_300; - - struct { - u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */ - u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 debug_overrun3 : 1; - u32 debug_overrun2 : 1; - u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */ - u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 reserved : 2; - } pid_filter_304; - - struct { - u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for - conditional access-related data. */ - u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the - first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */ - u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users - complete 6-byte Smart Card ID number. */ - u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional - access-related data. */ - u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 reserved : 2; - } pid_filter_308; - - struct { - u32 Group_PID :13; /* PID value for group filtering. */ - u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 unused1 : 2; - u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */ - u32 unused2 : 3; - } pid_filter_30c_ext_ind_0_7; - - struct { - u32 net_master_read :17; - u32 unused :15; - } pid_filter_30c_ext_ind_1; - - struct { - u32 net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_2; - - struct { - u32 next_net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_3; - - struct { - u32 unused1 : 1; - u32 state_write :10; - u32 reserved1 : 6; /* default: 000100 */ - u32 stack_read :10; - u32 reserved2 : 5; /* default: 00100 */ - } pid_filter_30c_ext_ind_4; - - struct { - u32 stack_cnt :10; - u32 unused :22; - } pid_filter_30c_ext_ind_5; - - struct { - u32 pid_fsm_save_reg0 : 2; - u32 pid_fsm_save_reg1 : 2; - u32 pid_fsm_save_reg2 : 2; - u32 pid_fsm_save_reg3 : 2; - u32 pid_fsm_save_reg4 : 2; - u32 pid_fsm_save_reg300 : 2; - u32 write_status1 : 2; - u32 write_status4 : 2; - u32 data_size_reg :12; - u32 unused : 4; - } pid_filter_30c_ext_ind_6; - - struct { - u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code - representing one of 32 internal PIDn registers as well as its - corresponding internal MAC_lown register. */ - u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */ - u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register - 0=MAC_highB register, 1=MAC_highA */ - u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400. - All types of networks (DVB, ATSC, ISDB) are passed. */ - u32 unused :22; - } index_reg_310; - - struct { - u32 PID :13; /* PID value */ - u32 PID_trans : 1; /* translation will take place for packets filtered */ - u32 PID_enable_bit : 1; /* When set this PID filter is enabled */ - u32 reserved :17; - } pid_n_reg_314; - - struct { - u32 A4_byte : 8; - u32 A5_byte : 8; - u32 A6_byte : 8; - u32 Enable_bit : 1; /* enabled (1) or disabled (1) */ - u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */ - u32 reserved : 6; - } mac_low_reg_318; - - struct { - u32 A1_byte : 8; - u32 A2_byte : 8; - u32 A3_byte : 8; - u32 reserved : 8; - } mac_high_reg_31c; - -/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */ - struct { - u32 reserved :16; #define fc_data_Tag_ID_DVB 0x3e #define fc_data_Tag_ID_ATSC 0x3f #define fc_data_Tag_ID_IDSB 0x8b - u32 data_Tag_ID :16; - } data_tag_400; - - struct { - u32 Card_IDbyte6 : 8; - u32 Card_IDbyte5 : 8; - u32 Card_IDbyte4 : 8; - u32 Card_IDbyte3 : 8; - } card_id_408; - - struct { - u32 Card_IDbyte2 : 8; - u32 Card_IDbyte1 : 8; - } card_id_40c; - - /* holding the unique mac address of the receiver which houses the FlexCopIII */ - struct { - u32 MAC1 : 8; - u32 MAC2 : 8; - u32 MAC3 : 8; - u32 MAC6 : 8; - } mac_address_418; - - struct { - u32 MAC7 : 8; - u32 MAC8 : 8; - u32 reserved : 16; - } mac_address_41c; - - struct { - u32 transmitter_data_byte : 8; - u32 ReceiveDataReady : 1; - u32 ReceiveByteFrameError: 1; - u32 txbuffempty : 1; - u32 reserved :21; - } ci_600; - - struct { - u32 pi_d : 8; - u32 pi_ha :20; - u32 pi_rw : 1; - u32 pi_component_reg : 3; - } pi_604; - - struct { - u32 serialReset : 1; - u32 oncecycle_read : 1; - u32 Timer_Read_req : 1; - u32 Timer_Load_req : 1; - u32 timer_data : 7; - u32 unused : 1; /* ??? not mentioned in data book */ - u32 Timer_addr : 5; - u32 reserved : 3; - u32 pcmcia_a_mod_pwr_n : 1; - u32 pcmcia_b_mod_pwr_n : 1; - u32 config_Done_stat : 1; - u32 config_Init_stat : 1; - u32 config_Prog_n : 1; - u32 config_wr_n : 1; - u32 config_cs_n : 1; - u32 config_cclk : 1; - u32 pi_CiMax_IRQ_n : 1; - u32 pi_timeout_status : 1; - u32 pi_wait_n : 1; - u32 pi_busy_n : 1; - } pi_608; - struct { - u32 PID :13; - u32 key_enable : 1; #define fc_key_code_default 0x1 #define fc_key_code_even 0x2 #define fc_key_code_odd 0x3 - u32 key_code : 2; - u32 key_array_col : 3; - u32 key_array_row : 5; - u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */ - u32 rw_flag : 1; - u32 reserved : 6; - } dvb_reg_60c; - -/* SRAM and Output Destination 0x700 to 0x714 */ - struct { - u32 sram_addr :15; - u32 sram_rw : 1; /* 0=write, 1=read */ - u32 sram_data : 8; - u32 sc_xfer_bit : 1; - u32 reserved1 : 3; - u32 oe_pin_reg : 1; - u32 ce_pin_reg : 1; - u32 reserved2 : 1; - u32 start_sram_ibi : 1; - } sram_ctrl_reg_700; - - struct { - u32 net_addr_read :16; - u32 net_addr_write :16; - } net_buf_reg_704; - - struct { - u32 cai_read :11; - u32 reserved1 : 5; - u32 cai_write :11; - u32 reserved2 : 6; - u32 cai_cnt : 4; - } cai_buf_reg_708; - - struct { - u32 cao_read :11; - u32 reserved1 : 5; - u32 cap_write :11; - u32 reserved2 : 6; - u32 cao_cnt : 4; - } cao_buf_reg_70c; - - struct { - u32 media_read :11; - u32 reserved1 : 5; - u32 media_write :11; - u32 reserved2 : 6; - u32 media_cnt : 4; - } media_buf_reg_710; - - struct { - u32 NET_Dest : 2; - u32 CAI_Dest : 2; - u32 CAO_Dest : 2; - u32 MEDIA_Dest : 2; - u32 net_ovflow_error : 1; - u32 media_ovflow_error : 1; - u32 cai_ovflow_error : 1; - u32 cao_ovflow_error : 1; - u32 ctrl_usb_wan : 1; - u32 ctrl_sramdma : 1; - u32 ctrl_maximumfill : 1; - u32 reserved :17; - } sram_dest_reg_714; - - struct { - u32 net_cnt :12; - u32 reserved1 : 4; - u32 net_addr_read : 1; - u32 reserved2 : 3; - u32 net_addr_write : 1; - u32 reserved3 :11; - } net_buf_reg_718; - - struct { - u32 wan_speed_sig : 2; - u32 reserved1 : 6; - u32 wan_wait_state : 8; - u32 sram_chip : 2; - u32 sram_memmap : 2; - u32 reserved2 : 4; - u32 wan_pkt_frame : 4; - u32 reserved3 : 4; - } wan_ctrl_reg_71c; -} flexcop_ibi_value; extern flexcop_ibi_value ibi_zero; diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h new file mode 100644 index 000000000000..bf3cb5a71fb4 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h @@ -0,0 +1,451 @@ +/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * register descriptions + * + * see flexcop.c for copyright information. + */ + +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_address0 :30; + u32 dma_0No_update : 1; + u32 dma_0start : 1; + } dma_0x0; + + struct { + u32 dma_addr_size :24; + u32 DMA_maxpackets : 8; + } dma_0x4_remap; + + struct { + u32 dma_addr_size :24; + u32 unused : 1; + u32 dma1timer : 7; + } dma_0x4_read; + + struct { + u32 dma_addr_size :24; + u32 dmatimer : 7; + u32 unused : 1; + } dma_0x4_write; + + struct { + u32 dma_cur_addr :30; + u32 unused : 2; + } dma_0x8; + + struct { + u32 dma_address1 :30; + u32 remap_enable : 1; + u32 dma_1start : 1; + } dma_0xc; + + struct { + u32 st_done : 1; + u32 no_base_addr_ack_error : 1; + u32 twoWS_port_reg : 2; + u32 total_bytes : 2; + u32 twoWS_rw : 1; + u32 working_start : 1; + u32 data1_reg : 8; + u32 baseaddr : 8; + u32 reserved1 : 1; + u32 chipaddr : 7; + } tw_sm_c_100; + + struct { + u32 unused : 6; + u32 force_stop : 1; + u32 exlicit_stops : 1; + u32 data4_reg : 8; + u32 data3_reg : 8; + u32 data2_reg : 8; + } tw_sm_c_104; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_108; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_10c; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_110; + + struct { + u32 LNB_CTLPrescaler_sig : 2; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLHighCount_sig :15; + } lnb_switch_freq_200; + + struct { + u32 Rev_N_sig_reserved2 : 1; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_revision_hi : 4; + u32 reserved :20; + u32 Per_reset_sig : 1; + u32 LNB_L_H_sig : 1; + u32 ACPI3_sig : 1; + u32 ACPI1_sig : 1; + } misc_204; + + struct { + u32 unused : 9; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 Rcv_Data_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 WAN_Enable_sig : 1; + u32 Mask_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 Stream1_filter_sig : 1; + } ctrl_208; + + struct { + u32 reserved :21; + u32 Transport_Error : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Continuity_error_flag : 1; + u32 Data_receiver_error : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA1_IRQ_Status : 1; + } irq_20c; + + struct { + u32 Special_controls :16; + u32 Block_reset_enable : 8; + u32 reset_blocks : 8; + } sw_reset_210; + + struct { + u32 unused2 :20; + u32 polarity_PS_ERR_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_CLK_sig : 1; + u32 unused1 : 3; + u32 s2p_sel_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 halt_V8_sig : 1; + u32 v2WS_oe_sig : 1; + u32 vuart_oe_sig : 1; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_busmuster : 1; + u32 sysramaccess_write : 1; + u32 unused : 7; + u32 sysramaccess_addr :15; + u32 sysramaccess_data : 8; + } mbox_host_to_v8_21c; + + struct { + u32 debug_fifo_problem : 1; + u32 debug_flag_write_status00 : 1; + u32 Stream2_trans : 1; + u32 Stream2_PID :13; + u32 debug_flag_pid_saved : 1; + u32 MAC_Multicast_filter : 1; + u32 Stream1_trans : 1; + u32 Stream1_PID :13; + } pid_filter_300; + + struct { + u32 reserved : 2; + u32 PMT_trans : 1; + u32 PMT_PID :13; + u32 debug_overrun2 : 1; + u32 debug_overrun3 : 1; + u32 PCR_trans : 1; + u32 PCR_PID :13; + } pid_filter_304; + + struct { + u32 reserved : 2; + u32 ECM_trans : 1; + u32 ECM_PID :13; + u32 EMM_filter_6 : 1; + u32 EMM_filter_4 : 1; + u32 EMM_trans : 1; + u32 EMM_PID :13; + } pid_filter_308; + + struct { + u32 unused2 : 3; + u32 Group_mask :13; + u32 unused1 : 2; + u32 Group_trans : 1; + u32 Group_PID :13; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 unused :15; + u32 net_master_read :17; + } pid_filter_30c_ext_ind_1; + + struct { + u32 unused :15; + u32 net_master_write :17; + } pid_filter_30c_ext_ind_2; + + struct { + u32 unused :15; + u32 next_net_master_write :17; + } pid_filter_30c_ext_ind_3; + + struct { + u32 reserved2 : 5; + u32 stack_read :10; + u32 reserved1 : 6; + u32 state_write :10; + u32 unused1 : 1; + } pid_filter_30c_ext_ind_4; + + struct { + u32 unused :22; + u32 stack_cnt :10; + } pid_filter_30c_ext_ind_5; + + struct { + u32 unused : 4; + u32 data_size_reg :12; + u32 write_status4 : 2; + u32 write_status1 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg0 : 2; + } pid_filter_30c_ext_ind_6; + + struct { + u32 unused :22; + u32 pass_alltables : 1; + u32 AB_select : 1; + u32 extra_index_reg : 3; + u32 index_reg : 5; + } index_reg_310; + + struct { + u32 reserved :17; + u32 PID_enable_bit : 1; + u32 PID_trans : 1; + u32 PID :13; + } pid_n_reg_314; + + struct { + u32 reserved : 6; + u32 HighAB_bit : 1; + u32 Enable_bit : 1; + u32 A6_byte : 8; + u32 A5_byte : 8; + u32 A4_byte : 8; + } mac_low_reg_318; + + struct { + u32 reserved : 8; + u32 A3_byte : 8; + u32 A2_byte : 8; + u32 A1_byte : 8; + } mac_high_reg_31c; + + struct { + u32 data_Tag_ID :16; + u32 reserved :16; + } data_tag_400; + + struct { + u32 Card_IDbyte3 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte6 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte1 : 8; + u32 Card_IDbyte2 : 8; + } card_id_40c; + + struct { + u32 MAC6 : 8; + u32 MAC3 : 8; + u32 MAC2 : 8; + u32 MAC1 : 8; + } mac_address_418; + + struct { + u32 reserved :16; + u32 MAC8 : 8; + u32 MAC7 : 8; + } mac_address_41c; + + struct { + u32 reserved :21; + u32 txbuffempty : 1; + u32 ReceiveByteFrameError : 1; + u32 ReceiveDataReady : 1; + u32 transmitter_data_byte : 8; + } ci_600; + + struct { + u32 pi_component_reg : 3; + u32 pi_rw : 1; + u32 pi_ha :20; + u32 pi_d : 8; + } pi_604; + + struct { + u32 pi_busy_n : 1; + u32 pi_wait_n : 1; + u32 pi_timeout_status : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 config_cclk : 1; + u32 config_cs_n : 1; + u32 config_wr_n : 1; + u32 config_Prog_n : 1; + u32 config_Init_stat : 1; + u32 config_Done_stat : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 pcmcia_a_mod_pwr_n : 1; + u32 reserved : 3; + u32 Timer_addr : 5; + u32 unused : 1; + u32 timer_data : 7; + u32 Timer_Load_req : 1; + u32 Timer_Read_req : 1; + u32 oncecycle_read : 1; + u32 serialReset : 1; + } pi_608; + + struct { + u32 reserved : 6; + u32 rw_flag : 1; + u32 dvb_en : 1; + u32 key_array_row : 5; + u32 key_array_col : 3; + u32 key_code : 2; + u32 key_enable : 1; + u32 PID :13; + } dvb_reg_60c; + + struct { + u32 start_sram_ibi : 1; + u32 reserved2 : 1; + u32 ce_pin_reg : 1; + u32 oe_pin_reg : 1; + u32 reserved1 : 3; + u32 sc_xfer_bit : 1; + u32 sram_data : 8; + u32 sram_rw : 1; + u32 sram_addr :15; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_write :16; + u32 net_addr_read :16; + } net_buf_reg_704; + + struct { + u32 cai_cnt : 4; + u32 reserved2 : 6; + u32 cai_write :11; + u32 reserved1 : 5; + u32 cai_read :11; + } cai_buf_reg_708; + + struct { + u32 cao_cnt : 4; + u32 reserved2 : 6; + u32 cap_write :11; + u32 reserved1 : 5; + u32 cao_read :11; + } cao_buf_reg_70c; + + struct { + u32 media_cnt : 4; + u32 reserved2 : 6; + u32 media_write :11; + u32 reserved1 : 5; + u32 media_read :11; + } media_buf_reg_710; + + struct { + u32 reserved :17; + u32 ctrl_maximumfill : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_usb_wan : 1; + u32 cao_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 net_ovflow_error : 1; + u32 MEDIA_Dest : 2; + u32 CAO_Dest : 2; + u32 CAI_Dest : 2; + u32 NET_Dest : 2; + } sram_dest_reg_714; + + struct { + u32 reserved3 :11; + u32 net_addr_write : 1; + u32 reserved2 : 3; + u32 net_addr_read : 1; + u32 reserved1 : 4; + u32 net_cnt :12; + } net_buf_reg_718; + + struct { + u32 reserved3 : 4; + u32 wan_pkt_frame : 4; + u32 reserved2 : 4; + u32 sram_memmap : 2; + u32 sram_chip : 2; + u32 wan_wait_state : 8; + u32 reserved1 : 6; + u32 wan_speed_sig : 2; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h new file mode 100644 index 000000000000..bd4528d747d7 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h @@ -0,0 +1,451 @@ +/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * register descriptions + * + * see flexcop.c for copyright information. + */ + +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_0start : 1; + u32 dma_0No_update : 1; + u32 dma_address0 :30; + } dma_0x0; + + struct { + u32 DMA_maxpackets : 8; + u32 dma_addr_size :24; + } dma_0x4_remap; + + struct { + u32 dma1timer : 7; + u32 unused : 1; + u32 dma_addr_size :24; + } dma_0x4_read; + + struct { + u32 unused : 1; + u32 dmatimer : 7; + u32 dma_addr_size :24; + } dma_0x4_write; + + struct { + u32 unused : 2; + u32 dma_cur_addr :30; + } dma_0x8; + + struct { + u32 dma_1start : 1; + u32 remap_enable : 1; + u32 dma_address1 :30; + } dma_0xc; + + struct { + u32 chipaddr : 7; + u32 reserved1 : 1; + u32 baseaddr : 8; + u32 data1_reg : 8; + u32 working_start : 1; + u32 twoWS_rw : 1; + u32 total_bytes : 2; + u32 twoWS_port_reg : 2; + u32 no_base_addr_ack_error : 1; + u32 st_done : 1; + } tw_sm_c_100; + + struct { + u32 data2_reg : 8; + u32 data3_reg : 8; + u32 data4_reg : 8; + u32 exlicit_stops : 1; + u32 force_stop : 1; + u32 unused : 6; + } tw_sm_c_104; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_108; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_10c; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_110; + + struct { + u32 LNB_CTLHighCount_sig :15; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLPrescaler_sig : 2; + } lnb_switch_freq_200; + + struct { + u32 ACPI1_sig : 1; + u32 ACPI3_sig : 1; + u32 LNB_L_H_sig : 1; + u32 Per_reset_sig : 1; + u32 reserved :20; + u32 Rev_N_sig_revision_hi : 4; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved2 : 1; + } misc_204; + + struct { + u32 Stream1_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 Mask_filter_sig : 1; + u32 WAN_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Rcv_Data_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 unused : 9; + } ctrl_208; + + struct { + u32 DMA1_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 Data_receiver_error : 1; + u32 Continuity_error_flag : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Transport_Error : 1; + u32 reserved :21; + } irq_20c; + + struct { + u32 reset_blocks : 8; + u32 Block_reset_enable : 8; + u32 Special_controls :16; + } sw_reset_210; + + struct { + u32 vuart_oe_sig : 1; + u32 v2WS_oe_sig : 1; + u32 halt_V8_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 s2p_sel_sig : 1; + u32 unused1 : 3; + u32 polarity_PS_CLK_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_ERR_sig : 1; + u32 unused2 :20; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_data : 8; + u32 sysramaccess_addr :15; + u32 unused : 7; + u32 sysramaccess_write : 1; + u32 sysramaccess_busmuster : 1; + } mbox_host_to_v8_21c; + + struct { + u32 Stream1_PID :13; + u32 Stream1_trans : 1; + u32 MAC_Multicast_filter : 1; + u32 debug_flag_pid_saved : 1; + u32 Stream2_PID :13; + u32 Stream2_trans : 1; + u32 debug_flag_write_status00 : 1; + u32 debug_fifo_problem : 1; + } pid_filter_300; + + struct { + u32 PCR_PID :13; + u32 PCR_trans : 1; + u32 debug_overrun3 : 1; + u32 debug_overrun2 : 1; + u32 PMT_PID :13; + u32 PMT_trans : 1; + u32 reserved : 2; + } pid_filter_304; + + struct { + u32 EMM_PID :13; + u32 EMM_trans : 1; + u32 EMM_filter_4 : 1; + u32 EMM_filter_6 : 1; + u32 ECM_PID :13; + u32 ECM_trans : 1; + u32 reserved : 2; + } pid_filter_308; + + struct { + u32 Group_PID :13; + u32 Group_trans : 1; + u32 unused1 : 2; + u32 Group_mask :13; + u32 unused2 : 3; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 net_master_read :17; + u32 unused :15; + } pid_filter_30c_ext_ind_1; + + struct { + u32 net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_2; + + struct { + u32 next_net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_3; + + struct { + u32 unused1 : 1; + u32 state_write :10; + u32 reserved1 : 6; + u32 stack_read :10; + u32 reserved2 : 5; + } pid_filter_30c_ext_ind_4; + + struct { + u32 stack_cnt :10; + u32 unused :22; + } pid_filter_30c_ext_ind_5; + + struct { + u32 pid_fsm_save_reg0 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 write_status1 : 2; + u32 write_status4 : 2; + u32 data_size_reg :12; + u32 unused : 4; + } pid_filter_30c_ext_ind_6; + + struct { + u32 index_reg : 5; + u32 extra_index_reg : 3; + u32 AB_select : 1; + u32 pass_alltables : 1; + u32 unused :22; + } index_reg_310; + + struct { + u32 PID :13; + u32 PID_trans : 1; + u32 PID_enable_bit : 1; + u32 reserved :17; + } pid_n_reg_314; + + struct { + u32 A4_byte : 8; + u32 A5_byte : 8; + u32 A6_byte : 8; + u32 Enable_bit : 1; + u32 HighAB_bit : 1; + u32 reserved : 6; + } mac_low_reg_318; + + struct { + u32 A1_byte : 8; + u32 A2_byte : 8; + u32 A3_byte : 8; + u32 reserved : 8; + } mac_high_reg_31c; + + struct { + u32 reserved :16; + u32 data_Tag_ID :16; + } data_tag_400; + + struct { + u32 Card_IDbyte6 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte3 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte2 : 8; + u32 Card_IDbyte1 : 8; + } card_id_40c; + + struct { + u32 MAC1 : 8; + u32 MAC2 : 8; + u32 MAC3 : 8; + u32 MAC6 : 8; + } mac_address_418; + + struct { + u32 MAC7 : 8; + u32 MAC8 : 8; + u32 reserved :16; + } mac_address_41c; + + struct { + u32 transmitter_data_byte : 8; + u32 ReceiveDataReady : 1; + u32 ReceiveByteFrameError : 1; + u32 txbuffempty : 1; + u32 reserved :21; + } ci_600; + + struct { + u32 pi_d : 8; + u32 pi_ha :20; + u32 pi_rw : 1; + u32 pi_component_reg : 3; + } pi_604; + + struct { + u32 serialReset : 1; + u32 oncecycle_read : 1; + u32 Timer_Read_req : 1; + u32 Timer_Load_req : 1; + u32 timer_data : 7; + u32 unused : 1; + u32 Timer_addr : 5; + u32 reserved : 3; + u32 pcmcia_a_mod_pwr_n : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 config_Done_stat : 1; + u32 config_Init_stat : 1; + u32 config_Prog_n : 1; + u32 config_wr_n : 1; + u32 config_cs_n : 1; + u32 config_cclk : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 pi_timeout_status : 1; + u32 pi_wait_n : 1; + u32 pi_busy_n : 1; + } pi_608; + + struct { + u32 PID :13; + u32 key_enable : 1; + u32 key_code : 2; + u32 key_array_col : 3; + u32 key_array_row : 5; + u32 dvb_en : 1; + u32 rw_flag : 1; + u32 reserved : 6; + } dvb_reg_60c; + + struct { + u32 sram_addr :15; + u32 sram_rw : 1; + u32 sram_data : 8; + u32 sc_xfer_bit : 1; + u32 reserved1 : 3; + u32 oe_pin_reg : 1; + u32 ce_pin_reg : 1; + u32 reserved2 : 1; + u32 start_sram_ibi : 1; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_read :16; + u32 net_addr_write :16; + } net_buf_reg_704; + + struct { + u32 cai_read :11; + u32 reserved1 : 5; + u32 cai_write :11; + u32 reserved2 : 6; + u32 cai_cnt : 4; + } cai_buf_reg_708; + + struct { + u32 cao_read :11; + u32 reserved1 : 5; + u32 cap_write :11; + u32 reserved2 : 6; + u32 cao_cnt : 4; + } cao_buf_reg_70c; + + struct { + u32 media_read :11; + u32 reserved1 : 5; + u32 media_write :11; + u32 reserved2 : 6; + u32 media_cnt : 4; + } media_buf_reg_710; + + struct { + u32 NET_Dest : 2; + u32 CAI_Dest : 2; + u32 CAO_Dest : 2; + u32 MEDIA_Dest : 2; + u32 net_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 cao_ovflow_error : 1; + u32 ctrl_usb_wan : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_maximumfill : 1; + u32 reserved :17; + } sram_dest_reg_714; + + struct { + u32 net_cnt :12; + u32 reserved1 : 4; + u32 net_addr_read : 1; + u32 reserved2 : 3; + u32 net_addr_write : 1; + u32 reserved3 :11; + } net_buf_reg_718; + + struct { + u32 wan_speed_sig : 2; + u32 reserved1 : 6; + u32 wan_wait_state : 8; + u32 sram_chip : 2; + u32 sram_memmap : 2; + u32 reserved2 : 4; + u32 wan_pkt_frame : 4; + u32 reserved3 : 4; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif -- cgit v1.2.2 From 64221be7b9006338e4a45228f013e467ee4bf045 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:57:49 -0700 Subject: [PATCH] dvb: flexcop: woraround irq stop problem The flexcop chip often stops generating interrupts after some hours of operation. Apparently this can be fixed by resetting register block 0x300 at each channel change (this is not detailed in the flexcop data books). This patch also restructures DMA handling and adds a bit of debug code for the irq problem in case it still happens for someone. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-common.h | 6 +- drivers/media/dvb/b2c2/flexcop-dma.c | 165 +++++++++++++++++--------- drivers/media/dvb/b2c2/flexcop-hw-filter.c | 12 +- drivers/media/dvb/b2c2/flexcop-misc.c | 12 ++ drivers/media/dvb/b2c2/flexcop-pci.c | 122 +++++++++++++------ drivers/media/dvb/b2c2/flexcop.c | 34 +++++- drivers/media/dvb/b2c2/flexcop.h | 1 + drivers/media/dvb/b2c2/flexcop_ibi_value_be.h | 9 +- drivers/media/dvb/b2c2/flexcop_ibi_value_le.h | 9 +- 9 files changed, 274 insertions(+), 96 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 773d158032df..a94912ac1872 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -108,6 +108,8 @@ void flexcop_device_kfree(struct flexcop_device*); int flexcop_device_initialize(struct flexcop_device*); void flexcop_device_exit(struct flexcop_device *fc); +void flexcop_reset_block_300(struct flexcop_device *fc); + /* from flexcop-dma.c */ int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size); void flexcop_dma_free(struct flexcop_dma *dma); @@ -115,7 +117,8 @@ void flexcop_dma_free(struct flexcop_dma *dma); int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); -int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index); +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx); +int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff); int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles); int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets); @@ -151,6 +154,7 @@ int flexcop_sram_init(struct flexcop_device *fc); /* from flexcop-misc.c */ void flexcop_determine_revision(struct flexcop_device *fc); void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix); +void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num); /* from flexcop-hw-filter.c */ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff); diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c index 8d2706075360..cf4ed1df6086 100644 --- a/drivers/media/dvb/b2c2/flexcop-dma.c +++ b/drivers/media/dvb/b2c2/flexcop-dma.c @@ -37,22 +37,90 @@ void flexcop_dma_free(struct flexcop_dma *dma) } EXPORT_SYMBOL(flexcop_dma_free); -int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +int flexcop_dma_config(struct flexcop_device *fc, + struct flexcop_dma *dma, + flexcop_dma_index_t dma_idx) { - flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + flexcop_ibi_value v0x0,v0x4,v0xc; + v0x0.raw = v0x4.raw = v0xc.raw = 0; - if (no & FC_DMA_1) - v.ctrl_208.DMA1_Timer_Enable_sig = onoff; + v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; + v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; + v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; - if (no & FC_DMA_2) - v.ctrl_208.DMA2_Timer_Enable_sig = onoff; + if ((dma_idx & FC_DMA_1) == dma_idx) { + fc->write_ibi_reg(fc,dma1_000,v0x0); + fc->write_ibi_reg(fc,dma1_004,v0x4); + fc->write_ibi_reg(fc,dma1_00c,v0xc); + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + fc->write_ibi_reg(fc,dma2_010,v0x0); + fc->write_ibi_reg(fc,dma2_014,v0x4); + fc->write_ibi_reg(fc,dma2_01c,v0xc); + } else { + err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call."); + return -EINVAL; + } - fc->write_ibi_reg(fc,ctrl_208,v); return 0; } -EXPORT_SYMBOL(flexcop_dma_control_timer_irq); +EXPORT_SYMBOL(flexcop_dma_config); + +/* start the DMA transfers, but not the DMA IRQs */ +int flexcop_dma_xfer_control(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + flexcop_dma_addr_index_t index, + int onoff) +{ + flexcop_ibi_value v0x0,v0xc; + flexcop_ibi_register r0x0,r0xc; + + if ((dma_idx & FC_DMA_1) == dma_idx) { + r0x0 = dma1_000; + r0xc = dma1_00c; + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + r0x0 = dma2_010; + r0xc = dma2_01c; + } else { + err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call."); + return -EINVAL; + } + + v0x0 = fc->read_ibi_reg(fc,r0x0); + v0xc = fc->read_ibi_reg(fc,r0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + + if (index & FC_DMA_SUBADDR_0) + v0x0.dma_0x0.dma_0start = onoff; + + if (index & FC_DMA_SUBADDR_1) + v0xc.dma_0xc.dma_1start = onoff; + + fc->write_ibi_reg(fc,r0x0,v0x0); + fc->write_ibi_reg(fc,r0xc,v0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_xfer_control); + +static int flexcop_dma_remap(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + int onoff) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + deb_info("%s\n",__FUNCTION__); + v.dma_0xc.remap_enable = onoff; + fc->write_ibi_reg(fc,r,v); + return 0; +} -int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +int flexcop_dma_control_size_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) { flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); @@ -67,75 +135,64 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t } EXPORT_SYMBOL(flexcop_dma_control_size_irq); -int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) { flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); if (no & FC_DMA_1) - v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; + v.ctrl_208.DMA1_Timer_Enable_sig = onoff; if (no & FC_DMA_2) - v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; + v.ctrl_208.DMA2_Timer_Enable_sig = onoff; fc->write_ibi_reg(fc,ctrl_208,v); return 0; } -EXPORT_SYMBOL(flexcop_dma_control_packet_irq); +EXPORT_SYMBOL(flexcop_dma_control_timer_irq); -int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index) +/* 1 cycles = 1.97 msec */ +int flexcop_dma_config_timer(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + u8 cycles) { + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - flexcop_ibi_value v0x0,v0x4,v0xc; - v0x0.raw = v0x4.raw = v0xc.raw = 0; - - v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; - v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; - v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; - - if (index & FC_DMA_SUBADDR_0) - v0x0.dma_0x0.dma_0start = 1; - - if (index & FC_DMA_SUBADDR_1) - v0xc.dma_0xc.dma_1start = 1; - - if (dma_idx & FC_DMA_1) { - fc->write_ibi_reg(fc,dma1_000,v0x0); - fc->write_ibi_reg(fc,dma1_004,v0x4); - fc->write_ibi_reg(fc,dma1_00c,v0xc); - } else { /* (dma_idx & FC_DMA_2) */ - fc->write_ibi_reg(fc,dma2_010,v0x0); - fc->write_ibi_reg(fc,dma2_014,v0x4); - fc->write_ibi_reg(fc,dma2_01c,v0xc); - } - - return 0; -} -EXPORT_SYMBOL(flexcop_dma_config); + flexcop_dma_remap(fc,dma_idx,0); -static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff) -{ - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - v.dma_0xc.remap_enable = onoff; + deb_info("%s\n",__FUNCTION__); + v.dma_0x4_write.dmatimer = cycles; fc->write_ibi_reg(fc,r,v); return 0; } +EXPORT_SYMBOL(flexcop_dma_config_timer); -/* 1 cycles = 1.97 msec */ -int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles) +/* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */ +int flexcop_dma_control_packet_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) { - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); - flexcop_dma_remap(fc,dma_idx,0); + deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw); + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw); - v.dma_0x4_write.dmatimer = cycles >> 1; - fc->write_ibi_reg(fc,r,v); return 0; } -EXPORT_SYMBOL(flexcop_dma_config_timer); +EXPORT_SYMBOL(flexcop_dma_control_packet_irq); -int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets) +int flexcop_dma_config_packet_count(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + u8 packets) { flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; flexcop_ibi_value v = fc->read_ibi_reg(fc,r); diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index 2baf43d3ce8f..75cf237196eb 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -10,6 +10,8 @@ static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) { flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff); + + deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off"); } void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) @@ -151,7 +153,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d { int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; - fc->feedcount += onoff ? 1 : -1; + fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ if (dvbdmxfeed->index >= max_pid_filter) fc->extra_feedcount += onoff ? 1 : -1; @@ -178,8 +180,14 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d /* if it was the first or last feed request change the stream-status */ if (fc->feedcount == onoff) { flexcop_rcv_data_ctrl(fc,onoff); - if (fc->stream_control) + if (fc->stream_control) /* device specific stream control */ fc->stream_control(fc,onoff); + + /* feeding stopped -> reset the flexcop filter*/ + if (onoff == 0) { + flexcop_reset_block_300(fc); + flexcop_hw_filter_init(fc); + } } return 0; diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c index 23082545651f..3a08d38b318a 100644 --- a/drivers/media/dvb/b2c2/flexcop-misc.c +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -65,3 +65,15 @@ void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type], flexcop_revision_names[fc->rev],suffix); } + +void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num) +{ + flexcop_ibi_value v; + int i; + for (i = 0; i < num; i++) { + v = fc->read_ibi_reg(fc,reg+4*i); + deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw); + } + deb_rdump("\n"); +} +EXPORT_SYMBOL(flexcop_dump_reg); diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index ed717c0073d5..a436d5584ea6 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -13,6 +13,10 @@ static int enable_pid_filtering = 1; module_param(enable_pid_filtering, int, 0444); MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); +static int irq_chk_intv; +module_param(irq_chk_intv, int, 0644); +MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging)."); + #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG #define dprintk(level,args...) \ do { if ((debug & level)) printk(args); } while (0) @@ -26,6 +30,7 @@ MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported #define deb_reg(args...) dprintk(0x02,args) #define deb_ts(args...) dprintk(0x04,args) #define deb_irq(args...) dprintk(0x08,args) +#define deb_chk(args...) dprintk(0x10,args) static int debug = 0; module_param(debug, int, 0644); @@ -56,6 +61,10 @@ struct flexcop_pci { spinlock_t irq_lock; + unsigned long last_irq; + + struct work_struct irq_check_work; + struct flexcop_device *fc_dev; }; @@ -88,18 +97,55 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi return 0; } +static void flexcop_pci_irq_check_work(void *data) +{ + struct flexcop_pci *fc_pci = data; + struct flexcop_device *fc = fc_pci->fc_dev; + + flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); + + flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4); + + if (v.sram_dest_reg_714.net_ovflow_error) + deb_chk("sram net_ovflow_error\n"); + if (v.sram_dest_reg_714.media_ovflow_error) + deb_chk("sram media_ovflow_error\n"); + if (v.sram_dest_reg_714.cai_ovflow_error) + deb_chk("sram cai_ovflow_error\n"); + if (v.sram_dest_reg_714.cai_ovflow_error) + deb_chk("sram cai_ovflow_error\n"); + + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); +} + /* When PID filtering is turned on, we use the timer IRQ, because small amounts * of data need to be passed to the user space instantly as well. When PID * filtering is turned off, we use the page-change-IRQ */ -static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs) { struct flexcop_pci *fc_pci = dev_id; struct flexcop_device *fc = fc_pci->fc_dev; - flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c); + flexcop_ibi_value v; irqreturn_t ret = IRQ_HANDLED; spin_lock_irq(&fc_pci->irq_lock); + v = fc->read_ibi_reg(fc,irq_20c); + + /* errors */ + if (v.irq_20c.Data_receiver_error) + deb_chk("data receiver error\n"); + if (v.irq_20c.Continuity_error_flag) + deb_chk("Contunuity error flag is set\n"); + if (v.irq_20c.LLC_SNAP_FLAG_set) + deb_chk("LLC_SNAP_FLAG_set is set\n"); + if (v.irq_20c.Transport_Error) + deb_chk("Transport error\n"); + + if ((fc_pci->count % 1000) == 0) + deb_chk("%d valid irq took place so far\n",fc_pci->count); + if (v.irq_20c.DMA1_IRQ_Status == 1) { if (fc_pci->active_dma1_addr == 0) flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); @@ -115,8 +161,9 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; - deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ", - v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos); + deb_irq("%u irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ", + jiffies_to_usecs(jiffies - fc_pci->last_irq),v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos); + fc_pci->last_irq = jiffies; /* buffer end was reached, restarted from the beginning * pass the data from last_cur_pos to the buffer end to the demux @@ -127,7 +174,6 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos); fc_pci->last_dma1_cur_pos = 0; - fc_pci->count = 0; } if (cur_pos > fc_pci->last_dma1_cur_pos) { @@ -139,16 +185,14 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) deb_irq("\n"); fc_pci->last_dma1_cur_pos = cur_pos; - } else + fc_pci->count++; + } else { + deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw); ret = IRQ_NONE; + } spin_unlock_irq(&fc_pci->irq_lock); -/* packet count would be ideal for hw filtering, but it isn't working. Either - * the data book is wrong, or I'm unable to read it correctly */ - -/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */ - return ret; } @@ -156,30 +200,35 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) { struct flexcop_pci *fc_pci = fc->bus_specific; if (onoff) { - flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); - flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); - flexcop_dma_config_timer(fc,FC_DMA_1,1); + flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1); + flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2); - if (fc_pci->fc_dev->pid_filtering) { - fc_pci->last_dma1_cur_pos = 0; - flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); - } else { - fc_pci->active_dma1_addr = 0; - flexcop_dma_control_size_irq(fc,FC_DMA_1,1); - } + flexcop_dma_config_timer(fc,FC_DMA_1,0); -/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0); - flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */ + flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1); + deb_irq("DMA xfer enabled\n"); - deb_irq("irqs enabled\n"); + fc_pci->last_dma1_cur_pos = 0; + flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); + deb_irq("IRQ enabled\n"); + +// fc_pci->active_dma1_addr = 0; +// flexcop_dma_control_size_irq(fc,FC_DMA_1,1); + + if (irq_chk_intv > 0) + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); } else { - if (fc_pci->fc_dev->pid_filtering) - flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); - else - flexcop_dma_control_size_irq(fc,FC_DMA_1,0); + if (irq_chk_intv > 0) + cancel_delayed_work(&fc_pci->irq_check_work); + + flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); + deb_irq("IRQ disabled\n"); -// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0); - deb_irq("irqs disabled\n"); +// flexcop_dma_control_size_irq(fc,FC_DMA_1,0); + + flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0); + deb_irq("DMA xfer disabled\n"); } return 0; @@ -198,6 +247,7 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); fc_pci->init_state |= FC_PCI_DMA_INIT; + goto success; dma1_free: flexcop_dma_free(&fc_pci->dma[0]); @@ -244,7 +294,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) pci_set_drvdata(fc_pci->pdev, fc_pci); - if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq, + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0) goto err_pci_iounmap; @@ -324,6 +374,8 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) goto err_fc_exit; + INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci); + goto success; err_fc_exit: flexcop_device_exit(fc); @@ -350,17 +402,17 @@ static void flexcop_pci_remove(struct pci_dev *pdev) static struct pci_device_id flexcop_pci_tbl[] = { { PCI_DEVICE(0x13d0, 0x2103) }, -/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */ +/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */ { }, }; MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); static struct pci_driver flexcop_pci_driver = { - .name = "Technisat/B2C2 FlexCop II/IIb/III PCI", + .name = "Technisat/B2C2 FlexCop II/IIb PCI", .id_table = flexcop_pci_tbl, - .probe = flexcop_pci_probe, - .remove = flexcop_pci_remove, + .probe = flexcop_pci_probe, + .remove = flexcop_pci_remove, }; static int __init flexcop_pci_module_init(void) diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 8b5d14dd36e3..12873d435406 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -46,7 +46,7 @@ int b2c2_flexcop_debug; module_param_named(debug, b2c2_flexcop_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS); +MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS); #undef DEBSTATUS /* global zero for ibi values */ @@ -173,9 +173,20 @@ static void flexcop_reset(struct flexcop_device *fc) fc->write_ibi_reg(fc,ctrl_208,ibi_zero); v210.raw = 0; - v210.sw_reset_210.reset_blocks = 0xff; + v210.sw_reset_210.reset_block_000 = 1; + v210.sw_reset_210.reset_block_100 = 1; + v210.sw_reset_210.reset_block_200 = 1; + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.reset_block_400 = 1; + v210.sw_reset_210.reset_block_500 = 1; + v210.sw_reset_210.reset_block_600 = 1; + v210.sw_reset_210.reset_block_700 = 1; v210.sw_reset_210.Block_reset_enable = 0xb2; + + v210.sw_reset_210.Special_controls = 0xc259; + fc->write_ibi_reg(fc,sw_reset_210,v210); + msleep(1); /* reset the periphical devices */ @@ -186,6 +197,25 @@ static void flexcop_reset(struct flexcop_device *fc) fc->write_ibi_reg(fc,misc_204,v204); } +void flexcop_reset_block_300(struct flexcop_device *fc) +{ + flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208), + v210 = fc->read_ibi_reg(fc,sw_reset_210); + + deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw); + + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.Block_reset_enable = 0xb2; + + fc->write_ibi_reg(fc,sw_reset_210,v210); + msleep(1); + + fc->write_ibi_reg(fc,ctrl_208,v208_save); +} +EXPORT_SYMBOL(flexcop_reset_block_300); + struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { void *bus; diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h index caa343a97bdc..0cebe1d92e0b 100644 --- a/drivers/media/dvb/b2c2/flexcop.h +++ b/drivers/media/dvb/b2c2/flexcop.h @@ -26,5 +26,6 @@ extern int b2c2_flexcop_debug; #define deb_i2c(args...) dprintk(0x04,args) #define deb_ts(args...) dprintk(0x08,args) #define deb_sram(args...) dprintk(0x10,args) +#define deb_rdump(args...) dprintk(0x20,args) #endif diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h index bf3cb5a71fb4..ed9a6756b194 100644 --- a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h @@ -152,7 +152,14 @@ typedef union { struct { u32 Special_controls :16; u32 Block_reset_enable : 8; - u32 reset_blocks : 8; + u32 reset_block_700 : 1; + u32 reset_block_600 : 1; + u32 reset_block_500 : 1; + u32 reset_block_400 : 1; + u32 reset_block_300 : 1; + u32 reset_block_200 : 1; + u32 reset_block_100 : 1; + u32 reset_block_000 : 1; } sw_reset_210; struct { diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h index bd4528d747d7..49f2315b6e58 100644 --- a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h @@ -150,7 +150,14 @@ typedef union { } irq_20c; struct { - u32 reset_blocks : 8; + u32 reset_block_000 : 1; + u32 reset_block_100 : 1; + u32 reset_block_200 : 1; + u32 reset_block_300 : 1; + u32 reset_block_400 : 1; + u32 reset_block_500 : 1; + u32 reset_block_600 : 1; + u32 reset_block_700 : 1; u32 Block_reset_enable : 8; u32 Special_controls :16; } sw_reset_210; -- cgit v1.2.2 From 7d53421c6adce47d067b834c605daeafe1ff9356 Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Thu, 7 Jul 2005 17:57:50 -0700 Subject: [PATCH] dvb: Twinhan DST: frontend fixes o Make the inversion setting specific, ie, only for the 200103A DVB-S This should not be flagged on other cards. o Make the frequency setting card specific o Make the bandwidth setting generic such that it supports more DVB-T cards o Set QAM size for DVB-C cards that do not autodetect QAM size o Fix a bug that caused the polarization not to be set. Set polarization for cards that do not autodetect polarization o Fix a bogus frontend signal lock, that caused a tuning delay as well. o Make the Symbolrate setting card specific Signed-off-by: Manu Abraham Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 227 ++++++++++++++--------- drivers/media/dvb/bt8xx/dst_ca.c | 349 +++++++++++++---------------------- drivers/media/dvb/bt8xx/dst_common.h | 3 + 3 files changed, 272 insertions(+), 307 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 1339912c308b..1f97c37fe9a6 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -258,10 +258,10 @@ int write_dst(struct dst_state *state, u8 *data, u8 len) if (debug && (verbose > 4)) { u8 i; if (verbose > 4) { - dprintk("%s writing", __FUNCTION__); + dprintk("%s writing [ ", __FUNCTION__); for (i = 0; i < len; i++) - dprintk(" %02x", data[i]); - dprintk("\n"); + dprintk("%02x ", data[i]); + dprintk("]\n"); } } for (cnt = 0; cnt < 2; cnt++) { @@ -320,10 +320,29 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len) } EXPORT_SYMBOL(read_dst); -static int dst_set_freq(struct dst_state *state, u32 freq) +static int dst_set_polarization(struct dst_state *state) { - u8 *val; + switch (state->voltage) { + case SEC_VOLTAGE_13: // vertical + printk("%s: Polarization=[Vertical]\n", __FUNCTION__); + state->tx_tuna[8] |= 0x40; //1 + break; + + case SEC_VOLTAGE_18: // horizontal + printk("%s: Polarization=[Horizontal]\n", __FUNCTION__); + state->tx_tuna[8] =~ 0x40; // 0 + break; + case SEC_VOLTAGE_OFF: + + break; + } + + return 0; +} + +static int dst_set_freq(struct dst_state *state, u32 freq) +{ state->frequency = freq; if (debug > 4) dprintk("%s: set Frequency %u\n", __FUNCTION__, freq); @@ -332,46 +351,30 @@ static int dst_set_freq(struct dst_state *state, u32 freq) freq = freq / 1000; if (freq < 950 || freq > 2150) return -EINVAL; - val = &state->tx_tuna[0]; - val[2] = (freq >> 8) & 0x7f; - val[3] = (u8) freq; - val[4] = 1; - val[8] &= ~4; - if (freq < 1531) - val[8] |= 4; + + state->tx_tuna[2] = (freq >> 8); + state->tx_tuna[3] = (u8) freq; + state->tx_tuna[4] = 0x01; + state->tx_tuna[8] &= ~0x04; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (freq < 1531) + state->tx_tuna[8] |= 0x04; + } + } else if (state->dst_type == DST_TYPE_IS_TERR) { freq = freq / 1000; if (freq < 137000 || freq > 858000) return -EINVAL; - val = &state->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; - val[5] = 0; - switch (state->bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; - - case BANDWIDTH_7_MHZ: - case BANDWIDTH_AUTO: - val[6] = 7; - break; - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; - } + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; - val[7] = 0; - val[8] = 0; } else if (state->dst_type == DST_TYPE_IS_CABLE) { - /* guess till will get one */ - freq = freq / 1000; - val = &state->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + } else return -EINVAL; return 0; @@ -379,51 +382,58 @@ static int dst_set_freq(struct dst_state *state, u32 freq) static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) { - u8 *val; - state->bandwidth = bandwidth; if (state->dst_type != DST_TYPE_IS_TERR) return 0; - val = &state->tx_tuna[0]; switch (bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; + case BANDWIDTH_6_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x06; + else { + state->tx_tuna[6] = 0x06; + state->tx_tuna[7] = 0x00; + } + break; - case BANDWIDTH_7_MHZ: - val[6] = 7; - break; + case BANDWIDTH_7_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x07; + else { + state->tx_tuna[6] = 0x07; + state->tx_tuna[7] = 0x00; + } + break; - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; + case BANDWIDTH_8_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x08; + else { + state->tx_tuna[6] = 0x08; + state->tx_tuna[7] = 0x00; + } + break; - default: - return -EINVAL; + default: + return -EINVAL; } return 0; } static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion) { - u8 *val; - state->inversion = inversion; - - val = &state->tx_tuna[0]; - - val[8] &= ~0x80; - switch (inversion) { - case INVERSION_OFF: - break; - case INVERSION_ON: - val[8] |= 0x80; - break; - default: - return -EINVAL; + case INVERSION_OFF: // Inversion = Normal + state->tx_tuna[8] &= ~0x80; + break; + + case INVERSION_ON: + state->tx_tuna[8] |= 0x80; + break; + default: + return -EINVAL; } return 0; } @@ -478,6 +488,52 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) return 0; } + +static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) +{ + if (state->dst_type != DST_TYPE_IS_CABLE) + return 0; + + state->modulation = modulation; + switch (modulation) { + case QAM_16: + state->tx_tuna[8] = 0x10; + break; + + case QAM_32: + state->tx_tuna[8] = 0x20; + break; + + case QAM_64: + state->tx_tuna[8] = 0x40; + break; + + case QAM_128: + state->tx_tuna[8] = 0x80; + break; + + case QAM_256: + state->tx_tuna[8] = 0x00; + break; + + case QPSK: + case QAM_AUTO: + case VSB_8: + case VSB_16: + default: + return -EINVAL; + + } + + return 0; +} + +static fe_modulation_t dst_get_modulation(struct dst_state *state) +{ + return state->modulation; +} + + u8 dst_check_sum(u8 * buf, u32 len) { u32 i; @@ -577,7 +633,7 @@ struct dst_types dst_tlist[] = { .device_id = "200103A", .offset = 0, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, .dst_feature = 0 }, /* obsolete */ @@ -626,7 +682,7 @@ struct dst_types dst_tlist[] = { .device_id = "DSTMCI", .offset = 1, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT, .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC }, @@ -872,7 +928,7 @@ static int dst_get_signal(struct dst_state* state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - + printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; @@ -954,15 +1010,8 @@ static int dst_get_tuna(struct dst_state* state) state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; state->decode_lock = 1; - /* - dst->decode_n1 = (dst->rx_tuna[4] << 8) + - (dst->rx_tuna[5]); - - dst->decode_n2 = (dst->rx_tuna[8] << 8) + - (dst->rx_tuna[7]); - */ state->diseq_flags |= HAS_LOCK; - /* dst->cur_jiff = jiffies; */ + return 1; } @@ -1145,7 +1194,8 @@ static int dst_init(struct dvb_frontend* fe) static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - state->inversion = INVERSION_ON; +// state->inversion = INVERSION_ON; + state->inversion = INVERSION_OFF; state->voltage = SEC_VOLTAGE_13; state->tone = SEC_TONE_OFF; state->symbol_rate = 29473000; @@ -1174,7 +1224,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) *status = 0; if (state->diseq_flags & HAS_LOCK) { - dst_get_signal(state); +// dst_get_signal(state); // don't require(?) to ask MCU if (state->decode_lock) *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; } @@ -1208,20 +1258,25 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet dst_set_freq(state, p->frequency); if (verbose > 4) - dprintk("Set Frequency = [%d]\n", p->frequency); + dprintk("Set Frequency=[%d]\n", p->frequency); - dst_set_inversion(state, p->inversion); +// dst_set_inversion(state, p->inversion); if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->u.qpsk.fec_inner); dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_polarization(state); if (verbose > 4) - dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate); + dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) { dst_set_bandwidth(state, p->u.ofdm.bandwidth); } else if (state->dst_type == DST_TYPE_IS_CABLE) { dst_set_fec(state, p->u.qam.fec_inner); dst_set_symbolrate(state, p->u.qam.symbol_rate); + dst_set_modulation(state, p->u.qam.modulation); } dst_write_tuna(fe); @@ -1233,8 +1288,11 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet struct dst_state* state = fe->demodulator_priv; p->frequency = state->decode_freq; - p->inversion = state->inversion; +// p->inversion = state->inversion; if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + p->inversion = state->inversion; + p->u.qpsk.symbol_rate = state->symbol_rate; p->u.qpsk.fec_inner = dst_get_fec(state); } else if (state->dst_type == DST_TYPE_IS_TERR) { @@ -1242,7 +1300,8 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet } else if (state->dst_type == DST_TYPE_IS_CABLE) { p->u.qam.symbol_rate = state->symbol_rate; p->u.qam.fec_inner = dst_get_fec(state); - p->u.qam.modulation = QAM_AUTO; +// p->u.qam.modulation = QAM_AUTO; + p->u.qam.modulation = dst_get_modulation(state); } return 0; diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index d781504cc2fa..bfaacd5fc20f 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -32,7 +32,7 @@ #include "dst_ca.h" #include "dst_common.h" -static unsigned int verbose = 1; +static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); @@ -295,34 +295,28 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, return 0; } -static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) { if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ } else { + hw_buffer->msg[0] = (length & 0xff) + 7; + hw_buffer->msg[1] = 0x40; hw_buffer->msg[2] = 0x03; hw_buffer->msg[3] = 0x00; + hw_buffer->msg[4] = 0x03; + hw_buffer->msg[5] = length & 0xff; + hw_buffer->msg[6] = 0x00; } return 0; } -static int debug_8820_buffer(struct ca_msg *hw_buffer) -{ - unsigned int i; - - dprintk("%s:Debug=[", __FUNCTION__); - for (i = 0; i < (hw_buffer->msg[0] + 1); i++) - dprintk(" %02x", hw_buffer->msg[i]); - dprintk("]\n"); - - return 0; -} -static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply) +static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) { - if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) { + if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { dprintk("%s: DST-CI Command failed.\n", __FUNCTION__); dprintk("%s: Resetting DST.\n", __FUNCTION__); rdc_reset_state(state); @@ -334,234 +328,141 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 r return 0; } - -static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +u32 asn_1_decode(u8 *asn_1_array) { - u32 hw_offset, buf_offset, i, k; - u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0; - u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0; - - if (verbose > 3) - dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length ); - - handle_en50221_tag(state, p_ca_message, hw_buffer); /* EN50221 tag */ - - /* Handle the length field (variable) */ - if (!(p_ca_message->msg[3] & 0x80)) { /* Length = 1 */ - length = p_ca_message->msg[3] & 0x7f; - words = 0; /* domi's suggestion */ - } - else { /* Length = words */ - words = p_ca_message->msg[3] & 0x7f; - for (i = 0; i < words; i++) { - length = length << 8; - length = length | p_ca_message->msg[4 + i]; + u8 length_field = 0, word_count = 0, count = 0; + u32 length = 0; + + length_field = asn_1_array[0]; + dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field); + if (length_field < 0x80) { + length = length_field & 0x7f; + dprintk("%s: Length=[%02x]\n", __FUNCTION__, length); + } else { + word_count = length_field & 0x7f; + for (count = 0; count < word_count; count++) { + length = (length | asn_1_array[count + 1]) << 8; + dprintk("%s: Length=[%04x]\n", __FUNCTION__, length); } } - if (verbose > 4) { - dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words); - - /* Debug Input string */ - for (i = 0; i < length; i++) - dprintk(" %02x", p_ca_message->msg[i]); - dprintk("]\n"); - } - - hw_offset = 7; - buf_offset = words + 4; - - /* Program Header */ - if (verbose > 4) - dprintk("\n%s:Program Header=[", __FUNCTION__); - for (i = 0; i < 6; i++) { - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; - if (verbose > 4) - dprintk(" %02x", p_ca_message->msg[buf_offset]); - hw_offset++, buf_offset++, hw_buffer_length++; - } - if (verbose > 4) - dprintk("]\n"); + return length; +} - program_info_length = 0; - program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9]; - if (verbose > 4) - dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n", - __FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset); +static int init_buffer(u8 *buffer, u32 length) +{ + u32 i; + for (i = 0; i < length; i++) + buffer[i] = 0; - if (program_info_length && (program_info_length < 256)) { /* If program_info_length */ - hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f; /* req only 4 bits */ - hw_buffer->msg[12] = hw_buffer->msg[12] + 1; /* increment! ASIC bug! */ + return 0; +} - if (p_ca_message->msg[buf_offset + 1] == 0x09) { /* Check CA descriptor */ - found_prog_ca_desc = 1; - if (verbose > 4) - dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__); - } +static int debug_string(u8 *msg, u32 length, u32 offset) +{ + u32 i; - if (found_prog_ca_desc) { /* Command only if CA descriptor */ - hw_buffer->msg[13] = p_ca_message->msg[buf_offset]; /* CA PMT command ID */ - hw_offset++, buf_offset++, hw_buffer_length++; - } + dprintk(" String=[ "); + for (i = offset; i < length; i++) + dprintk("%02x ", msg[i]); + dprintk("]\n"); - /* Program descriptors */ - if (verbose > 4) { - dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset); - dprintk("%s:Program descriptors=[", __FUNCTION__); - } - while (program_info_length && !error_condition) { /* Copy prog descriptors */ - if (program_info_length > p_ca_message->length) { /* Error situation */ - dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n", - __FUNCTION__, __LINE__, program_info_length); - dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); - error_condition = 1; - break; - } + return 0; +} - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; - dprintk(" %02x", p_ca_message->msg[buf_offset]); - hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--; - } - if (verbose > 4) { - dprintk("]\n"); - dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset); - } - if (found_prog_ca_desc) { - if (!reply) { - hw_buffer->msg[13] = 0x01; /* OK descrambling */ - if (verbose > 1) - dprintk("CA PMT Command = OK Descrambling\n"); - } - else { - hw_buffer->msg[13] = 0x02; /* Ok MMI */ - if (verbose > 1) - dprintk("CA PMT Command = Ok MMI\n"); - } - if (query) { - hw_buffer->msg[13] = 0x03; /* Query */ - if (verbose > 1) - dprintk("CA PMT Command = CA PMT query\n"); - } - } - } - else { - hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0; /* Don't write to ASIC */ - hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00; +static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length) +{ + u32 i; + dprintk("%s: Copying [", __FUNCTION__); + for (i = 0; i < length; i++) { + destination[i + dest_offset] = source[i + source_offset]; + dprintk(" %02x", source[i + source_offset]); } - if (verbose > 4) - dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n", - __FUNCTION__, p_ca_message->length, buf_offset, hw_offset); - - while ((buf_offset < p_ca_message->length) && !error_condition) { - /* Bail out in case of an indefinite loop */ - if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) { - dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n", - __FUNCTION__, __LINE__, program_info_length, buf_offset); - - dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); - error_condition = 1; - break; - } - - /* Stream Header */ - - for (k = 0; k < 5; k++) { - hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k]; - } + dprintk("]\n"); - es_info_length = 0; - es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4]; + return i; +} - if (verbose > 4) { - dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__, - p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1], - p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3], - p_ca_message->msg[buf_offset + 4]); +static int modify_4_bits(u8 *message, u32 pos) +{ + message[pos] &= 0x0f; - dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__, - p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length, - p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset); - } + return 0; +} - hw_buffer->msg[hw_offset + 3] &= 0x0f; /* req only 4 bits */ - if (found_prog_ca_desc) { - hw_buffer->msg[hw_offset + 3] = 0x00; - hw_buffer->msg[hw_offset + 4] = 0x00; - } - hw_offset += 5, buf_offset += 5, hw_buffer_length += 5; +static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +{ + u32 length = 0, count = 0; + u8 asn_1_words, program_header_length; + u16 program_info_length = 0, es_info_length = 0; + u32 hw_offset = 0, buf_offset = 0, i; + u8 dst_tag_length; - /* Check for CA descriptor */ - if (p_ca_message->msg[buf_offset + 1] == 0x09) { - if (verbose > 4) - dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__); - found_stream_ca_desc = 1; - } + length = asn_1_decode(&p_ca_message->msg[3]); + dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length); + dprintk("%s: ASN.1 ", __FUNCTION__); + debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length - /* ES descriptors */ - - if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) { -// if (!ca_pmt_done) { - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; /* CA PMT cmd(es) */ - if (verbose > 4) - printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]); -// hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1; - hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--; -// } - if (verbose > 4) - dprintk("%s:----->ES descriptors=[", __FUNCTION__); - - while (es_info_length && !error_condition) { /* ES descriptors */ - if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) { - if (verbose > 4) { - dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n", - __FUNCTION__, __LINE__, es_info_length, buf_offset); - - dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); - } - error_condition = 1; - break; - } + init_buffer(hw_buffer->msg, length); + handle_dst_tag(state, p_ca_message, hw_buffer, length); - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; - if (verbose > 3) - dprintk("%02x ", hw_buffer->msg[hw_offset]); - hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--; - } - found_stream_ca_desc = 0; /* unset for new streams */ - dprintk("]\n"); + hw_offset = 7; + asn_1_words = 1; // just a hack to test, should compute this one + buf_offset = 3; + program_header_length = 6; + dst_tag_length = 7; + +// debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset); +// dprintk("%s: Program Header(BUF)", __FUNCTION__); +// debug_string(&p_ca_message->msg[4], program_header_length, 0); +// dprintk("%s: Copying Program header\n", __FUNCTION__); + copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length); + buf_offset += program_header_length, hw_offset += program_header_length; + modify_4_bits(hw_buffer->msg, (hw_offset - 2)); + if (state->type_flags & DST_TYPE_HAS_INC_COUNT) { // workaround + dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__); + debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0); + hw_buffer->msg[hw_offset - 1] += 1; + } + +// dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count); +// debug_string(hw_buffer->msg, hw_offset, 0); + + program_info_length = ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; + dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length); + if (program_info_length) { + count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current + buf_offset += count, hw_offset += count; +// dprintk("%s: Program level ", __FUNCTION__); +// debug_string(hw_buffer->msg, hw_offset, 0); + } + + buf_offset += 1;// hw_offset += 1; + for (i = buf_offset; i < length; i++) { +// dprintk("%s: Stream Header ", __FUNCTION__); + count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5); + modify_4_bits(hw_buffer->msg, (hw_offset + 3)); + + hw_offset += 5, buf_offset += 5, i += 4; +// debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5)); + es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; + dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length); + if (es_info_length) { + // copy descriptors @ STREAM level + dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__); } - } - - /* MCU Magic words */ - - hw_buffer_length += 7; - hw_buffer->msg[0] = hw_buffer_length; - hw_buffer->msg[1] = 64; - hw_buffer->msg[4] = 3; - hw_buffer->msg[5] = hw_buffer->msg[0] - 7; - hw_buffer->msg[6] = 0; - - /* Fix length */ - hw_buffer->length = hw_buffer->msg[0]; - - put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]); - /* Do the actual write */ - if (verbose > 4) { - dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__); - dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length); } - /* Only for debugging! */ - if (verbose > 2) - debug_8820_buffer(hw_buffer); - if (verbose > 3) - dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply); - write_to_8820(state, hw_buffer, reply); + hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length)); +// dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]); + debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0); // dst tags also + write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply); // checksum return 0; } + /* Board supports CA PMT reply ? */ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) { @@ -605,7 +506,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer; if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } if (verbose > 3) @@ -630,8 +531,10 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, switch (command) { case CA_PMT: if (verbose > 3) +// dprintk("Command = SEND_CA_PMT\n"); dprintk("Command = SEND_CA_PMT\n"); - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { +// if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__); return -1; } @@ -664,7 +567,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, return -1; } if (verbose > 3) - printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); + dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); break; } @@ -681,17 +584,17 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct ca_msg *p_ca_message; if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 0b3da29245fb..ef532a6aceaa 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -47,6 +47,8 @@ #define DST_TYPE_HAS_FW_2 16 #define DST_TYPE_HAS_FW_3 32 #define DST_TYPE_HAS_FW_BUILD 64 +#define DST_TYPE_HAS_OBS_REGS 128 +#define DST_TYPE_HAS_INC_COUNT 256 /* Card capability list */ @@ -110,6 +112,7 @@ struct dst_state { u32 dst_hw_cap; u8 dst_fw_version; fe_sec_mini_cmd_t minicmd; + fe_modulation_t modulation; u8 messages[256]; }; -- cgit v1.2.2 From 3dff919425dd79954447e6ab39807b4c27ba3089 Mon Sep 17 00:00:00 2001 From: Allan Stirling Date: Thu, 7 Jul 2005 17:57:51 -0700 Subject: [PATCH] dvb: Twinhan DST: frontend polarization fix Fix a bug that caused the polarization (V/H) to be interchanged. Signed-off-by: Allan Stirling Signed-off-by: Manu Abraham Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 1f97c37fe9a6..d8f4200065ee 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -325,12 +325,12 @@ static int dst_set_polarization(struct dst_state *state) switch (state->voltage) { case SEC_VOLTAGE_13: // vertical printk("%s: Polarization=[Vertical]\n", __FUNCTION__); - state->tx_tuna[8] |= 0x40; //1 + state->tx_tuna[8] &= ~0x40; //1 break; case SEC_VOLTAGE_18: // horizontal printk("%s: Polarization=[Horizontal]\n", __FUNCTION__); - state->tx_tuna[8] =~ 0x40; // 0 + state->tx_tuna[8] |= 0x40; // 0 break; case SEC_VOLTAGE_OFF: -- cgit v1.2.2 From 771e71570ce4da549fe89978de0a29e3299d7fb7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 7 Jul 2005 17:57:52 -0700 Subject: [PATCH] dvb: ttusb-dec: kfree cleanup The Coverity checker discovered that these two kfree's can never be executed. Signed-off-by: Adrian Bunk Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 1699cc9f6bb0..725af3af5b27 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -157,7 +157,8 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf /* allocate memory for the internal state */ state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (state == NULL) + return NULL; /* setup the state */ state->config = config; @@ -167,10 +168,6 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; @@ -181,7 +178,8 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf /* allocate memory for the internal state */ state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (state == NULL) + return NULL; /* setup the state */ state->config = config; @@ -193,10 +191,6 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { -- cgit v1.2.2 From 96bf2f2b549aab918f4225841df54c3d58896822 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:53 -0700 Subject: [PATCH] dvb: ttpci: add support for Technotrend/Hauppauge DVB-S SE Add support for s5h1420 frontend (new Technotrend/Hauppauge DVB-S SE). Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 6 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/s5h1420.c | 800 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/s5h1420.h | 41 ++ drivers/media/dvb/ttpci/Kconfig | 9 +- drivers/media/dvb/ttpci/budget.c | 99 +++++ 6 files changed, 952 insertions(+), 4 deletions(-) create mode 100644 drivers/media/dvb/frontends/s5h1420.c create mode 100644 drivers/media/dvb/frontends/s5h1420.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index b4fddf513ebe..5c695937e2ad 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -40,6 +40,12 @@ config DVB_VES1X93 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_S5H1420 + tristate "Samsung S5H1420 based" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + comment "DVB-T (terrestrial) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 91d6d3576d3d..8d46dd721f45 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_DVB_NXT2002) += nxt2002.o obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o +obj-$(CONFIG_DVB_S5H1420) += s5h1420.o diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c new file mode 100644 index 000000000000..4f396ac8de77 --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -0,0 +1,800 @@ +/* +Driver for Samsung S5H1420 QPSK Demodulator + +Copyright (C) 2005 Andrew de Quincey + +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; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "s5h1420.h" + + + +#define TONE_FREQ 22000 + +struct s5h1420_state { + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct s5h1420_config* config; + struct dvb_frontend frontend; + + u8 postlocked:1; + u32 fclk; + u32 tunedfreq; + fe_code_rate_t fec_inner; + u32 symbol_rate; +}; + +static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings); + + +static int debug = 0; +#define dprintk if (debug) printk + +static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) +{ + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }; + struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }; + + if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1) + return ret; + + if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1) + return ret; + + return b1[0]; +} + +static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + switch(voltage) { + case SEC_VOLTAGE_13: + s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); + break; + + case SEC_VOLTAGE_18: + s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03); + break; + + case SEC_VOLTAGE_OFF: + s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd); + break; + } + + return 0; +} + +static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + switch(tone) { + case SEC_TONE_ON: + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); + break; + + case SEC_TONE_OFF: + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); + break; + } + + return 0; +} + +static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int i; + unsigned long timeout; + int result = 0; + + /* setup for DISEQC */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, 0x02); + msleep(15); + + /* write the DISEQC command bytes */ + for(i=0; i< cmd->msg_len; i++) { + s5h1420_writereg(state, 0x3c + i, cmd->msg[i]); + } + + /* kick off transmission */ + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08); + + /* wait for transmission to complete */ + timeout = jiffies + ((100*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (s5h1420_readreg(state, 0x3b) & 0x08) + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) + result = -ETIMEDOUT; + + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int i; + int length; + unsigned long timeout; + int result = 0; + + /* setup for DISEQC recieve */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */ + msleep(15); + + /* wait for reception to complete */ + timeout = jiffies + ((reply->timeout*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */ + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) { + result = -ETIMEDOUT; + goto exit; + } + + /* check error flag - FIXME: not sure what this does - docs do not describe + * beyond "error flag for diseqc receive data :( */ + if (s5h1420_readreg(state, 0x49)) { + result = -EIO; + goto exit; + } + + /* check length */ + length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4; + if (length > sizeof(reply->msg)) { + result = -EOVERFLOW; + goto exit; + } + reply->msg_len = length; + + /* extract data */ + for(i=0; i< length; i++) { + reply->msg[i] = s5h1420_readreg(state, 0x3c + i); + } + +exit: + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int result = 0; + unsigned long timeout; + + /* setup for tone burst */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01); + + /* set value for B position if requested */ + if (minicmd == SEC_MINI_B) { + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04); + } + msleep(15); + + /* start transmission */ + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); + + /* wait for transmission to complete */ + timeout = jiffies + ((20*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x08)) + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) + result = -ETIMEDOUT; + + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) +{ + u8 val; + fe_status_t status = 0; + + val = s5h1420_readreg(state, 0x14); + if (val & 0x02) + status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right + if (val & 0x01) + status |= FE_HAS_CARRIER; // FIXME: not sure if this is right + val = s5h1420_readreg(state, 0x36); + if (val & 0x01) + status |= FE_HAS_VITERBI; + if (val & 0x20) + status |= FE_HAS_SYNC; + if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC)) + status |= FE_HAS_LOCK; + + return status; +} + +static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + + if (status == NULL) + return -EINVAL; + + /* determine lock state */ + *status = s5h1420_get_status_bits(state); + + /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion, + wait a bit and check again */ + if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) { + val = s5h1420_readreg(state, 0x32); + if ((val & 0x07) == 0x03) { + if (val & 0x08) + s5h1420_writereg(state, 0x31, 0x13); + else + s5h1420_writereg(state, 0x31, 0x1b); + + /* wait a bit then update lock status */ + mdelay(200); + *status = s5h1420_get_status_bits(state); + } + } + + /* perform post lock setup */ + if ((*status & FE_HAS_LOCK) && (!state->postlocked)) { + + /* calculate the data rate */ + u32 tmp = s5h1420_getsymbolrate(state); + switch(s5h1420_readreg(state, 0x32) & 0x07) { + case 0: + tmp = (tmp * 2 * 1) / 2; + break; + + case 1: + tmp = (tmp * 2 * 2) / 3; + break; + + case 2: + tmp = (tmp * 2 * 3) / 4; + break; + + case 3: + tmp = (tmp * 2 * 5) / 6; + break; + + case 4: + tmp = (tmp * 2 * 6) / 7; + break; + + case 5: + tmp = (tmp * 2 * 7) / 8; + break; + } + tmp = state->fclk / tmp; + + /* set the MPEG_CLK_INTL for the calculated data rate */ + if (tmp < 4) + val = 0x00; + else if (tmp < 8) + val = 0x01; + else if (tmp < 12) + val = 0x02; + else if (tmp < 16) + val = 0x03; + else if (tmp < 24) + val = 0x04; + else if (tmp < 32) + val = 0x05; + else + val = 0x06; + s5h1420_writereg(state, 0x22, val); + + /* DC freeze */ + s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01); + + /* kicker disable + remove DC offset */ + s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f); + + /* post-lock processing has been done! */ + state->postlocked = 1; + } + + return 0; +} + +static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + s5h1420_writereg(state, 0x46, 0x1d); + mdelay(25); + return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); +} + +static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + u8 val = 0xff - s5h1420_readreg(state, 0x15); + + return (int) ((val << 8) | val); +} + +static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + s5h1420_writereg(state, 0x46, 0x1f); + mdelay(25); + return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); +} + +static void s5h1420_reset(struct s5h1420_state* state) +{ + s5h1420_writereg (state, 0x01, 0x08); + s5h1420_writereg (state, 0x01, 0x00); + udelay(10); +} + +static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +{ + u64 val; + + val = (p->u.qpsk.symbol_rate / 1000) * (1<<24); + if (p->u.qpsk.symbol_rate <= 21000000) { + val *= 2; + } + do_div(val, (state->fclk / 1000)); + + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f); + s5h1420_writereg(state, 0x11, val >> 16); + s5h1420_writereg(state, 0x12, val >> 8); + s5h1420_writereg(state, 0x13, val & 0xff); + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80); +} + +static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) +{ + u64 val; + int sampling = 2; + + if (s5h1420_readreg(state, 0x05) & 0x2) + sampling = 1; + + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); + val = s5h1420_readreg(state, 0x11) << 16; + val |= s5h1420_readreg(state, 0x12) << 8; + val |= s5h1420_readreg(state, 0x13); + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); + + val *= (state->fclk / 1000); + do_div(val, ((1<<24) * sampling)); + + return (u32) (val * 1000); +} + +static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) +{ + int val; + + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); + + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf); + s5h1420_writereg(state, 0x0e, val >> 16); + s5h1420_writereg(state, 0x0f, val >> 8); + s5h1420_writereg(state, 0x10, val & 0xff); + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40); +} + +static int s5h1420_getfreqoffset(struct s5h1420_state* state) +{ + int val; + + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); + val = s5h1420_readreg(state, 0x0e) << 16; + val |= s5h1420_readreg(state, 0x0f) << 8; + val |= s5h1420_readreg(state, 0x10); + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); + + if (val & 0x800000) + val |= 0xff000000; + + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = - ((val * (state->fclk/1000000)) / (1<<24)); + + return val; +} + +static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +{ + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + s5h1420_writereg(state, 0x31, 0x00); + s5h1420_writereg(state, 0x30, 0x3f); + } else { + switch(p->u.qpsk.fec_inner) { + case FEC_1_2: + s5h1420_writereg(state, 0x31, 0x10); + s5h1420_writereg(state, 0x30, 0x01); + break; + + case FEC_2_3: + s5h1420_writereg(state, 0x31, 0x11); + s5h1420_writereg(state, 0x30, 0x02); + break; + + case FEC_3_4: + s5h1420_writereg(state, 0x31, 0x12); + s5h1420_writereg(state, 0x30, 0x04); + break; + + case FEC_5_6: + s5h1420_writereg(state, 0x31, 0x13); + s5h1420_writereg(state, 0x30, 0x08); + break; + + case FEC_6_7: + s5h1420_writereg(state, 0x31, 0x14); + s5h1420_writereg(state, 0x30, 0x10); + break; + + case FEC_7_8: + s5h1420_writereg(state, 0x31, 0x15); + s5h1420_writereg(state, 0x30, 0x20); + break; + + default: + return; + } + } +} + +static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) +{ + switch(s5h1420_readreg(state, 0x32) & 0x07) { + case 0: + return FEC_1_2; + + case 1: + return FEC_2_3; + + case 2: + return FEC_3_4; + + case 3: + return FEC_5_6; + + case 4: + return FEC_6_7; + + case 5: + return FEC_7_8; + } + + return FEC_NONE; +} + +static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +{ + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + s5h1420_writereg(state, 0x31, 0x00); + s5h1420_writereg(state, 0x30, 0x3f); + } else { + u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7; + tmp |= 0x10; + + if (p->inversion == INVERSION_ON) + tmp |= 0x80; + + s5h1420_writereg(state, 0x31, tmp); + } +} + +static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) +{ + if (s5h1420_readreg(state, 0x32) & 0x08) + return INVERSION_ON; + + return INVERSION_OFF; +} + +static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u32 frequency_delta; + struct dvb_frontend_tune_settings fesettings; + + /* check if we should do a fast-tune */ + memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); + s5h1420_get_tune_settings(fe, &fesettings); + frequency_delta = p->frequency - state->tunedfreq; + if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && + (frequency_delta != 0) && + (state->fec_inner == p->u.qpsk.fec_inner) && + (state->symbol_rate == p->u.qpsk.symbol_rate)) { + + s5h1420_setfreqoffset(state, frequency_delta); + return 0; + } + + /* first of all, software reset */ + s5h1420_reset(state); + + /* set tuner PLL */ + if (state->config->pll_set) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_set(fe, p, &state->tunedfreq); + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); + } + + /* set s5h1420 fclk PLL according to desired symbol rate */ + if (p->u.qpsk.symbol_rate > 28000000) { + state->fclk = 88000000; + s5h1420_writereg(state, 0x03, 0x50); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xae); + } else if (p->u.qpsk.symbol_rate > 21000000) { + state->fclk = 59000000; + s5h1420_writereg(state, 0x03, 0x33); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xae); + } else { + state->fclk = 88000000; + s5h1420_writereg(state, 0x03, 0x50); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xac); + } + + /* set misc registers */ + s5h1420_writereg(state, 0x02, 0x00); + s5h1420_writereg(state, 0x07, 0xb0); + s5h1420_writereg(state, 0x0a, 0x67); + s5h1420_writereg(state, 0x0b, 0x78); + s5h1420_writereg(state, 0x0c, 0x48); + s5h1420_writereg(state, 0x0d, 0x6b); + s5h1420_writereg(state, 0x2e, 0x8e); + s5h1420_writereg(state, 0x35, 0x33); + s5h1420_writereg(state, 0x38, 0x01); + s5h1420_writereg(state, 0x39, 0x7d); + s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); + s5h1420_writereg(state, 0x3c, 0x00); + s5h1420_writereg(state, 0x45, 0x61); + s5h1420_writereg(state, 0x46, 0x1d); + + /* start QPSK */ + s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); + + /* set the frequency offset to adjust for PLL inaccuracy */ + s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq); + + /* set the reset of the parameters */ + s5h1420_setsymbolrate(state, p); + s5h1420_setinversion(state, p); + s5h1420_setfec(state, p); + + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; + state->postlocked = 0; + return 0; +} + +static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); + p->inversion = s5h1420_getinversion(state); + p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); + p->u.qpsk.fec_inner = s5h1420_getfec(state); + + return 0; +} + +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + fesettings->min_delay_ms = 50; + fesettings->step_size = 2000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1500; + fesettings->max_drift = 9000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 500; + fesettings->max_drift = 7000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 14 * fesettings->step_size; + } else { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 18 * fesettings->step_size; + } + + return 0; +} + +static int s5h1420_init (struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + /* disable power down and do reset */ + s5h1420_writereg(state, 0x02, 0x10); + msleep(10); + s5h1420_reset(state); + + /* init PLL */ + if (state->config->pll_init) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_init(fe); + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); + } + + return 0; +} + +static int s5h1420_sleep(struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + return s5h1420_writereg(state, 0x02, 0x12); +} + +static void s5h1420_release(struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1420_ops; + +struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c) +{ + struct s5h1420_state* state = NULL; + u8 identity; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); + state->postlocked = 0; + state->fclk = 88000000; + state->tunedfreq = 0; + state->fec_inner = FEC_NONE; + state->symbol_rate = 0; + + /* check if the demod is there + identify it */ + identity = s5h1420_readreg(state, 0x00); + if (identity != 0x03) + goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops s5h1420_ops = { + + .info = { + .name = "Samsung S5H1420 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* .symbol_rate_tolerance = ???,*/ + .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_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = s5h1420_release, + + .init = s5h1420_init, + .sleep = s5h1420_sleep, + + .set_frontend = s5h1420_set_frontend, + .get_frontend = s5h1420_get_frontend, + .get_tune_settings = s5h1420_get_tune_settings, + + .read_status = s5h1420_read_status, + .read_ber = s5h1420_read_ber, + .read_signal_strength = s5h1420_read_signal_strength, + .read_ucblocks = s5h1420_read_ucblocks, + + .diseqc_send_master_cmd = s5h1420_send_master_cmd, + .diseqc_recv_slave_reply = s5h1420_recv_slave_reply, + .diseqc_send_burst = s5h1420_send_burst, + .set_tone = s5h1420_set_tone, + .set_voltage = s5h1420_set_voltage, +}; + +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver"); +MODULE_AUTHOR("Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(s5h1420_attach); diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h new file mode 100644 index 000000000000..b687fc77ceb3 --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -0,0 +1,41 @@ +/* + Driver for S5H1420 QPSK Demodulators + + Copyright (C) 2005 Andrew de Quincey + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef S5H1420_H +#define S5H1420_H + +#include + +struct s5h1420_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout); +}; + +extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, + struct i2c_adapter* i2c); + +#endif // S5H1420_H diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 7ffa2c7315b3..bf3c011d2cfb 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -12,7 +12,7 @@ config DVB_AV7110 select DVB_STV0297 select DVB_L64781 help - Support for SAA7146 and AV7110 based DVB cards as produced + Support for SAA7146 and AV7110 based DVB cards as produced by Fujitsu-Siemens, Technotrend, Hauppauge and others. This driver only supports the fullfeatured cards with @@ -33,7 +33,7 @@ config DVB_AV7110_FIRMWARE If you want to compile the firmware into the driver you need to say Y here and provide the correct path of the firmware. You need this option if you want to compile the whole driver statically into the - kernel. + kernel. All other people say N. @@ -66,6 +66,7 @@ config DVB_BUDGET select DVB_L64781 select DVB_TDA8083 select DVB_TDA10021 + select DVB_S5H1420 help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -119,9 +120,9 @@ config DVB_BUDGET_PATCH select DVB_VES1X93 select DVB_TDA8083 help - Support for Budget Patch (full TS) modification on + Support for Budget Patch (full TS) modification on SAA7146+AV7110 based cards (DVB-S cards). This - driver doesn't use onboard MPEG2 decoder. The + driver doesn't use onboard MPEG2 decoder. The card is driven in Budget-only mode. Card is required to have loaded firmware to tune properly. Firmware can be loaded by insertion and removal of diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 083fd44e5f90..9961917e8a7f 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -40,6 +40,7 @@ #include "ves1820.h" #include "l64781.h" #include "tda8083.h" +#include "s5h1420.h" static void Set22K (struct budget *budget, int state) { @@ -177,6 +178,62 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m return 0; } +static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 buf; + struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) }; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + switch(voltage) { + case SEC_VOLTAGE_13: + buf = (buf & 0xf7) | 0x04; + break; + + case SEC_VOLTAGE_18: + buf = (buf & 0xf7) | 0x0c; + break; + + case SEC_VOLTAGE_OFF: + buf = buf & 0xf0; + break; + } + + msg.flags = 0; + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + return 0; +} + +static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 buf; + struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) }; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + if (arg) { + buf = buf | 0x10; + } else { + buf = buf & 0xef; + } + + msg.flags = 0; + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + return 0; +} + +static void lnbp21_init(struct budget* budget) +{ + u8 buf = 0x00; + struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) }; + + i2c_transfer (&budget->i2c_adap, &msg, 1); +} + static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -395,6 +452,38 @@ static struct tda8083_config grundig_29504_451_config = { .pll_set = grundig_29504_451_pll_set, }; +static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 1000; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xc2; + + if (div < 1450) + data[3] = 0x00; + else if (div < 1850) + data[3] = 0x40; + else if (div < 2000) + data[3] = 0x80; + else + data[3] = 0xc0; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + *freqout = div * 1000; + return 0; +} + +static struct s5h1420_config s5h1420_config = { + .demod_address = 0x53, + .pll_set = s5h1420_pll_set, +}; + static u8 read_pwm(struct budget* budget) { u8 b = 0xff; @@ -459,6 +548,15 @@ static void frontend_init(struct budget *budget) break; } break; + + case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) + budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; + budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + lnbp21_init(budget); + break; + } } if (budget->dvb_frontend == NULL) { @@ -532,6 +630,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), { -- cgit v1.2.2 From dd2bbb179326d23577ff8201c4f20e0db3e87f7b Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:54 -0700 Subject: [PATCH] dvb: ttpci: support for new TT DVB-T-CI Support for new TT DVB-T-CI, thanks to Andre Weidemann Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-ci.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 075eb40f5c16..a1267054bc01 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -69,6 +69,7 @@ struct budget_ci { int slot_status; struct dvb_ca_en50221 ca; char ir_dev_name[50]; + u8 tuner_pll_address; /* used for philips_tdm1316l configs */ }; /* from reading the following remotes: @@ -723,7 +724,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe) struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len = + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = sizeof(td1316_init) }; // setup PLL configuration @@ -746,7 +747,7 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend { struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; int tuner_frequency = 0; u8 band, cp, filter; @@ -869,12 +870,22 @@ static void frontend_init(struct budget_ci *budget_ci) break; case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->tuner_pll_address = 0x63; budget_ci->budget.dvb_frontend = tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { break; } break; + + case 0x1012: // Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->tuner_pll_address = 0x60; + budget_ci->budget.dvb_frontend = + tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; } if (budget_ci->budget.dvb_frontend == NULL) { @@ -954,11 +965,13 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), + MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), { .vendor = 0, } -- cgit v1.2.2 From c9090ebb247999354f80d45d45b3d5a804a94f7f Mon Sep 17 00:00:00 2001 From: Wolfgang Rohdewald Date: Thu, 7 Jul 2005 17:57:55 -0700 Subject: [PATCH] dvb: ttpci: fix error handling for firmware communication o make sure ERESTARTSYS will be propagated o ReleaseBitmap: starting with Firmware 261e, also release when BMP_LOADING o removes unused #define BMP_LOADINGS o in many cases changed the return value from -1 to something more meaningful like ETIMEDOUT, EINVAL o changed syslog message timeout waiting for COMMAND such that it indicates what command did not complete o reduce # of arguments for LoadBitmap and BlitBitmap o av7110_osd_cmd: remove the out: label Signed-off-by: Wolfgang Rohdewald Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.h | 3 +- drivers/media/dvb/ttpci/av7110_hw.c | 309 +++++++++++++++++++----------------- 2 files changed, 163 insertions(+), 149 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 4f69b4d01479..e54222d9b3f9 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -119,8 +119,7 @@ struct av7110 { volatile int bmp_state; #define BMP_NONE 0 #define BMP_LOADING 1 -#define BMP_LOADINGS 2 -#define BMP_LOADED 3 +#define BMP_LOADED 2 wait_queue_head_t bmpq; diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 7fa4a0ebe133..7d2bdd791c9e 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -137,7 +137,7 @@ static int waitdebi(struct av7110 *av7110, int adr, int state) return 0; udelay(5); } - return -1; + return -ETIMEDOUT; } static int load_dram(struct av7110 *av7110, u32 *data, int len) @@ -155,7 +155,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) for (i = 0; i < blocks; i++) { if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); - return -1; + return -ETIMEDOUT; } dprintk(4, "writing DRAM block %d\n", i); mwdebi(av7110, DEBISWAB, bootblock, @@ -170,7 +170,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) if (rest > 0) { if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); - return -1; + return -ETIMEDOUT; } if (rest > 4) mwdebi(av7110, DEBISWAB, bootblock, @@ -185,13 +185,13 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) } if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); - return -1; + return -ETIMEDOUT; } iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2); iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); - return -1; + return -ETIMEDOUT; } return 0; } @@ -263,7 +263,7 @@ int av7110_bootarm(struct av7110 *av7110) if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " "saa7146_wait_for_debi_done() timed out\n"); - return -1; + return -ETIMEDOUT; } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); mdelay(1); @@ -284,7 +284,7 @@ int av7110_bootarm(struct av7110 *av7110) if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); - return -1; + return -ETIMEDOUT; } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); msleep(30); /* the firmware needs some time to initialize */ @@ -328,7 +328,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", __FUNCTION__, stat & flags); - return -1; + return -ETIMEDOUT; } msleep(1); } @@ -412,7 +412,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", __FUNCTION__, type); - return -1; + return -ETIMEDOUT; } msleep(1); } @@ -435,8 +435,10 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n", - __FUNCTION__); + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", + __FUNCTION__, + (buf[0] >> 8) & 0xff + ); return -ETIMEDOUT; } } @@ -470,7 +472,7 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) ret = __av7110_send_fw_cmd(av7110, buf, length); up(&av7110->dcomlock); - if (ret) + if (ret && ret!=-ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", __FUNCTION__, ret); return ret; @@ -495,7 +497,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) } ret = av7110_send_fw_cmd(av7110, buf, num + 2); - if (ret) + if (ret && ret != -ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); return ret; } @@ -518,7 +520,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) } ret = av7110_send_fw_cmd(av7110, cmd, 18); - if (ret) + if (ret && ret != -ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); return ret; } @@ -558,7 +560,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } @@ -569,7 +571,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } #endif @@ -667,10 +669,10 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu for (i = 0; i < len; i++) buf[i + 4] = msg[i]; - if ((ret = av7110_send_fw_cmd(av7110, buf, 18))) + ret = av7110_send_fw_cmd(av7110, buf, 18); + if (ret && ret!=-ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); - - return 0; + return ret; } @@ -715,7 +717,7 @@ static int FlushText(struct av7110 *av7110) printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } up(&av7110->dcomlock); @@ -739,7 +741,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } #ifndef _NOHANDSHAKE @@ -750,7 +752,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } #endif @@ -761,7 +763,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); ret = __av7110_send_fw_cmd(av7110, cbuf, 5); up(&av7110->dcomlock); - if (ret) + if (ret && ret!=-ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); return ret; } @@ -816,9 +818,25 @@ static osd_raw_window_t bpp2bit[8] = { OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 }; -static inline int LoadBitmap(struct av7110 *av7110, u16 format, +static inline int WaitUntilBmpLoaded(struct av7110 *av7110) +{ + int ret = wait_event_interruptible_timeout(av7110->bmpq, + av7110->bmp_state != BMP_LOADING, 10*HZ); + if (ret == -ERESTARTSYS) + return ret; + if (ret == 0) { + printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", + ret, av7110->bmp_state); + av7110->bmp_state = BMP_NONE; + return -ETIMEDOUT; + } + return 0; +} + +static inline int LoadBitmap(struct av7110 *av7110, u16 dx, u16 dy, int inc, u8 __user * data) { + u16 format; int bpp; int i; int d, delta; @@ -827,14 +845,7 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format, dprintk(4, "%p\n", av7110); - ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ); - if (ret == -ERESTARTSYS || ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", - ret, av7110->bmp_state); - av7110->bmp_state = BMP_NONE; - return -1; - } - BUG_ON (av7110->bmp_state == BMP_LOADING); + format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; av7110->bmp_state = BMP_LOADING; if (format == OSD_BITMAP8) { @@ -847,18 +858,18 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format, bpp=1; delta = 8; } else { av7110->bmp_state = BMP_NONE; - return -1; + return -EINVAL; } av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; av7110->bmpp = 0; if (av7110->bmplen > 32768) { av7110->bmp_state = BMP_NONE; - return -1; + return -EINVAL; } for (i = 0; i < dy; i++) { if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { av7110->bmp_state = BMP_NONE; - return -1; + return -EINVAL; } } if (format != OSD_BITMAP8) { @@ -873,37 +884,27 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format, } av7110->bmplen += 1024; dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); - return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + if (!ret) + ret = WaitUntilBmpLoaded(av7110); + return ret; } -static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans) +static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) { - int ret; - dprintk(4, "%p\n", av7110); - BUG_ON (av7110->bmp_state == BMP_NONE); - - ret = wait_event_interruptible_timeout(av7110->bmpq, - av7110->bmp_state != BMP_LOADING, 10*HZ); - if (ret == -ERESTARTSYS || ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n", - ret, av7110->bmp_state); - av7110->bmp_state = BMP_NONE; - return (ret == 0) ? -ETIMEDOUT : ret; - } - - BUG_ON (av7110->bmp_state != BMP_LOADED); - - return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans); + return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); } static inline int ReleaseBitmap(struct av7110 *av7110) { dprintk(4, "%p\n", av7110); - if (av7110->bmp_state != BMP_LOADED) + if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) return -1; + if (av7110->bmp_state == BMP_LOADING) + dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); av7110->bmp_state = BMP_NONE; return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); } @@ -924,18 +925,22 @@ static u32 RGB2YUV(u16 R, u16 G, u16 B) return Cr | (Cb << 16) | (Y << 8); } -static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) +static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) { + int ret; + u16 ch, cl; u32 yuv; yuv = blend ? RGB2YUV(r,g,b) : 0; cl = (yuv & 0xffff); ch = ((yuv >> 16) & 0xffff); - SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ch, cl); - SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ((blend >> 4) & 0x0f)); + ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ch, cl); + if (!ret) + ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ((blend >> 4) & 0x0f)); + return ret; } static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) @@ -968,14 +973,14 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, { uint w, h, bpp, bpl, size, lpb, bnum, brest; int i; - int rc; + int rc,release_rc; w = x1 - x0 + 1; h = y1 - y0 + 1; if (inc <= 0) inc = w; if (w <= 0 || w > 720 || h <= 0 || h > 576) - return -1; + return -EINVAL; bpp = av7110->osdbpp[av7110->osdwin] + 1; bpl = ((w * bpp + 7) & ~7) / 8; size = h * bpl; @@ -983,176 +988,186 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, bnum = size / (lpb * bpl); brest = size - bnum * lpb * bpl; - for (i = 0; i < bnum; i++) { - rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], - w, lpb, inc, data); - if (rc) - return rc; - rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0); + if (av7110->bmp_state == BMP_LOADING) { + /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ + BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); + rc = WaitUntilBmpLoaded(av7110); if (rc) return rc; - data += lpb * inc; + /* just continue. This should work for all fw versions + * if bnum==1 && !brest && LoadBitmap was successful + */ } - if (brest) { - rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], - w, brest / bpl, inc, data); + + rc = 0; + for (i = 0; i < bnum; i++) { + rc = LoadBitmap(av7110, w, lpb, inc, data); if (rc) - return rc; - rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0); + break; + rc = BlitBitmap(av7110, x0, y0 + i * lpb); if (rc) - return rc; + break; + data += lpb * inc; } - ReleaseBitmap(av7110); - return 0; + if (!rc && brest) { + rc = LoadBitmap(av7110, w, brest / bpl, inc, data); + if (!rc) + rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); + } + release_rc = ReleaseBitmap(av7110); + if (!rc) + rc = release_rc; + if (rc) + dprintk(1,"returns %d\n",rc); + return rc; } int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) { int ret; - ret = down_interruptible(&av7110->osd_sema); - if (ret) + if (down_interruptible(&av7110->osd_sema)) return -ERESTARTSYS; - /* stupid, but OSD functions don't provide a return code anyway */ - ret = 0; - switch (dc->cmd) { case OSD_Close: - DestroyOSDWindow(av7110, av7110->osdwin); - goto out; + ret = DestroyOSDWindow(av7110, av7110->osdwin); + break; case OSD_Open: av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; - CreateOSDWindow(av7110, av7110->osdwin, + ret = CreateOSDWindow(av7110, av7110->osdwin, bpp2bit[av7110->osdbpp[av7110->osdwin]], dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; if (!dc->data) { - MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - SetColorBlend(av7110, av7110->osdwin); + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (ret) + break; + ret = SetColorBlend(av7110, av7110->osdwin); } - goto out; + break; case OSD_Show: - MoveWindowRel(av7110, av7110->osdwin, 0, 0); - goto out; + ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); + break; case OSD_Hide: - HideWindow(av7110, av7110->osdwin); - goto out; + ret = HideWindow(av7110, av7110->osdwin); + break; case OSD_Clear: - DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); - goto out; + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); + break; case OSD_Fill: - DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); - goto out; + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); + break; case OSD_SetColor: - OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); - goto out; + ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); + break; case OSD_SetPalette: - { - if (FW_VERSION(av7110->arm_app) >= 0x2618) { + if (FW_VERSION(av7110->arm_app) >= 0x2618) ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); - goto out; - } else { + else { int i, len = dc->x0-dc->color+1; u8 __user *colors = (u8 __user *)dc->data; u8 r, g, b, blend; - + ret = 0; for (i = 0; icolor + i, r, g, b, blend); + ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend); + if (ret) + break; } } - ret = 0; - goto out; - } - case OSD_SetTrans: - goto out; + break; case OSD_SetPixel: - DrawLine(av7110, av7110->osdwin, + ret = DrawLine(av7110, av7110->osdwin, dc->x0, dc->y0, 0, 0, dc->color); - goto out; - case OSD_GetPixel: - goto out; + break; case OSD_SetRow: dc->y1 = dc->y0; /* fall through */ case OSD_SetBlock: ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); - goto out; + break; case OSD_FillRow: - DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, dc->x1-dc->x0+1, dc->y1, dc->color); - goto out; + break; case OSD_FillBlock: - DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); - goto out; + break; case OSD_Line: - DrawLine(av7110, av7110->osdwin, + ret = DrawLine(av7110, av7110->osdwin, dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); - goto out; - case OSD_Query: - goto out; - case OSD_Test: - goto out; + break; case OSD_Text: { char textbuf[240]; if (strncpy_from_user(textbuf, dc->data, 240) < 0) { ret = -EFAULT; - goto out; + break; } textbuf[239] = 0; if (dc->x1 > 3) dc->x1 = 3; - SetFont(av7110, av7110->osdwin, dc->x1, + ret = SetFont(av7110, av7110->osdwin, dc->x1, (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); - FlushText(av7110); - WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); - goto out; + if (!ret) + ret = FlushText(av7110); + if (!ret) + ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); + break; } case OSD_SetWindow: - if (dc->x0 < 1 || dc->x0 > 7) { + if (dc->x0 < 1 || dc->x0 > 7) ret = -EINVAL; - goto out; + else { + av7110->osdwin = dc->x0; + ret = 0; } - av7110->osdwin = dc->x0; - goto out; + break; case OSD_MoveWindow: - MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - SetColorBlend(av7110, av7110->osdwin); - goto out; + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + break; case OSD_OpenRaw: if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { ret = -EINVAL; - goto out; + break; } - if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) { + if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; - } - else { + else av7110->osdbpp[av7110->osdwin] = 0; - } - CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, + ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; if (!dc->data) { - MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - SetColorBlend(av7110, av7110->osdwin); + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); } - goto out; + break; default: ret = -EINVAL; - goto out; + break; } -out: up(&av7110->osd_sema); + if (ret==-ERESTARTSYS) + dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); + else if (ret) + dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); + return ret; } -- cgit v1.2.2 From 7d87bc39b98e0bf927acd14611976f710bd9a783 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:56 -0700 Subject: [PATCH] dvb: ttpci: fix bug in timeout handling Fix bug in timeout handling. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_hw.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 7d2bdd791c9e..aa1efce6cb31 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -352,11 +352,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) start = jiffies; while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); return -ETIMEDOUT; } + msleep(1); } wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); @@ -364,11 +364,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); return -ETIMEDOUT; } + msleep(1); } #endif @@ -433,7 +433,6 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifdef COM_DEBUG start = jiffies; while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", __FUNCTION__, @@ -441,6 +440,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) ); return -ETIMEDOUT; } + msleep(1); } stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); @@ -554,25 +554,25 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, start = jiffies; while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) { -#ifdef _NOHANDSHAKE - msleep(1); -#endif if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } +#ifdef _NOHANDSHAKE + msleep(1); +#endif } #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } #endif @@ -712,13 +712,13 @@ static int FlushText(struct av7110 *av7110) return -ERESTARTSYS; start = jiffies; while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_OSD)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } up(&av7110->dcomlock); return 0; @@ -736,24 +736,24 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) start = jiffies; while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_OSD)) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } #endif for (i = 0; i < length / 2; i++) -- cgit v1.2.2 From c3d7b5aeb32668732ffc1968d12b804a98ef4fdd Mon Sep 17 00:00:00 2001 From: "Dr. Werner Fink" Date: Thu, 7 Jul 2005 17:57:57 -0700 Subject: [PATCH] dvb: ttpci: fix AUDUIO_CONTINUE ioctl Fixed typo in AUDUIO_CONTINUE ioctl: AUDIO_CMD_MUTE -> AUDIO_CMD_UNMUTE Signed-off-by: "Dr. Werner Fink" Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_av.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index ccf946125d02..13c506ea0bbd 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1200,7 +1200,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, case AUDIO_CONTINUE: if (av7110->audiostate.play_state == AUDIO_PAUSED) { av7110->audiostate.play_state = AUDIO_PLAYING; - audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16); + audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); } break; -- cgit v1.2.2 From eef5764d6806e29a768a632abce113c15264c5d6 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:58 -0700 Subject: [PATCH] dvb: ttpci: budget-av / tu1216 fix for QAM128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix for QAM128 in VHF band suggested by Timo Helkiö. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9e65bfd59c42..b65f4b0a481f 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -570,9 +570,9 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; - buf[2] = 0x8e; - buf[3] = (params->frequency < 174500000 ? 0xa1 : - params->frequency < 454000000 ? 0x92 : 0x34); + buf[2] = 0x86; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; -- cgit v1.2.2 From ce18a223607b0e8cc9a8375abc64281a13ac423c Mon Sep 17 00:00:00 2001 From: Wolfgang Rohdewald Date: Thu, 7 Jul 2005 17:57:59 -0700 Subject: [PATCH] dvb: ttpci: more error handling for firmware communication o propagate more errors back to caller or log them, mainly in av7110.c and av7110_av.c o fix error message in StartHWFilter o do not StopHWFilter for handle 0xffff Signed-off-by: Wolfgang Rohdewald Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 237 ++++++++++++++++++++++-------------- drivers/media/dvb/ttpci/av7110.h | 4 +- drivers/media/dvb/ttpci/av7110_av.c | 210 +++++++++++++++++++------------- drivers/media/dvb/ttpci/av7110_av.h | 4 +- drivers/media/dvb/ttpci/av7110_hw.h | 12 +- 5 files changed, 280 insertions(+), 187 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8e33a850e13e..e21deee9a985 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -116,13 +116,18 @@ static int av7110_num = 0; static void init_av7110_av(struct av7110 *av7110) { + int ret; struct saa7146_dev *dev = av7110->dev; /* set internal volume control to maximum */ av7110->adac_type = DVB_ADAC_TI; - av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret<0) + printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); - av7710_set_video_mode(av7110, vidmode); + ret = av7710_set_video_mode(av7110, vidmode); + if (ret<0) + printk("dvb-ttpci:cannot set video mode:%d\n",ret); /* handle different card types */ /* remaining inits according to card and frontend type */ @@ -156,8 +161,12 @@ static void init_av7110_av(struct av7110 *av7110) if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { // switch DVB SCART on - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); + if (ret<0) + printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + if (ret<0) + printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); if (rgb_on && (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 @@ -165,8 +174,12 @@ static void init_av7110_av(struct av7110 *av7110) } } - av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - av7110_setup_irc_config(av7110, 0); + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret<0) + printk("dvb-ttpci:cannot set volume :%d\n",ret); + ret = av7110_setup_irc_config(av7110, 0); + if (ret<0) + printk("dvb-ttpci:cannot setup irc config :%d\n",ret); } static void recover_arm(struct av7110 *av7110) @@ -258,8 +271,9 @@ static int arm_thread(void *data) * * If we want to support multiple controls we would have to do much more... */ -void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) +int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) { + int ret = 0; static struct av7110 *last; dprintk(4, "%p\n", av7110); @@ -270,9 +284,10 @@ void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) last = av7110; if (av7110) { - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); av7110->ir_config = ir_config; } + return ret; } static void (*irc_handler)(u32); @@ -765,13 +780,14 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, pcrpid, vpid, apid, ttpid, subpid); } -void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, +int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid) { + int ret = 0; dprintk(4, "%p\n", av7110); if (down_interruptible(&av7110->pid_mutex)) - return; + return -ERESTARTSYS; if (!(vpid & 0x8000)) av7110->pids[DMX_PES_VIDEO] = vpid; @@ -786,10 +802,11 @@ void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, if (av7110->fe_synced) { pcrpid = av7110->pids[DMX_PES_PCR]; - SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); + ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); } up(&av7110->pid_mutex); + return ret; } @@ -832,11 +849,13 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) ret = av7110_fw_request(av7110, buf, 20, &handle, 1); if (ret != 0 || handle >= 32) { printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " - "ret %x handle %04x\n", + "ret %d handle %04x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3], ret, handle); dvbdmxfilter->hw_handle = 0xffff; - return -1; + if (!ret) + ret = -1; + return ret; } av7110->handle2filter[handle] = dvbdmxfilter; @@ -859,7 +878,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) if (handle >= 32) { printk("%s tried to stop invalid filter %04x, filter type = %x\n", __FUNCTION__, handle, dvbdmxfilter->type); - return 0; + return -EINVAL; } av7110->handle2filter[handle] = NULL; @@ -873,18 +892,20 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) "resp %04x %04x pid %d\n", __FUNCTION__, buf[0], buf[1], buf[2], ret, answ[0], answ[1], dvbdmxfilter->feed->pid); - ret = -1; + if (!ret) + ret = -1; } return ret; } -static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) +static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv; u16 *pid = dvbdmx->pids, npids[5]; int i; + int ret = 0; dprintk(4, "%p\n", av7110); @@ -893,36 +914,49 @@ static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { npids[i] = 0; - ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - StartHWFilter(dvbdmxfeed->filter); - return; + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = StartHWFilter(dvbdmxfeed->filter); + return ret; + } + if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (ret) + return ret; } - if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) - ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); if (dvbdmxfeed->pes_type < 2 && npids[0]) if (av7110->fe_synced) - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (ret) + return ret; + } if ((dvbdmxfeed->ts_type & TS_PACKET)) { if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) - av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); + ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) - av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); + ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); } + return ret; } -static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) +static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv; u16 *pid = dvbdmx->pids, npids[5]; int i; + int ret = 0; + dprintk(4, "%p\n", av7110); if (dvbdmxfeed->pes_type <= 1) { - av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + if (ret) + return ret; if (!av7110->rec_mode) dvbdmx->recording = 0; if (!av7110->playing) @@ -933,24 +967,27 @@ static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) switch (i) { case 2: //teletext if (dvbdmxfeed->ts_type & TS_PACKET) - StopHWFilter(dvbdmxfeed->filter); + ret = StopHWFilter(dvbdmxfeed->filter); npids[2] = 0; break; case 0: case 1: case 4: if (!pids_off) - return; + return 0; npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; break; } - ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + return ret; } static int av7110_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = demux->priv; + int ret = 0; dprintk(4, "%p\n", av7110); @@ -971,21 +1008,22 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) !(demux->pids[1] & 0x8000)) { dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - av7110_av_start_play(av7110,RP_AV); - demux->playing = 1; + ret = av7110_av_start_play(av7110,RP_AV); + if (!ret) + demux->playing = 1; } break; default: - dvb_feed_start_pid(feed); + ret = dvb_feed_start_pid(feed); break; } } else if ((feed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE)) { - StartHWFilter(feed->filter); + ret = StartHWFilter(feed->filter); } } - if (feed->type == DMX_TYPE_SEC) { + else if (feed->type == DMX_TYPE_SEC) { int i; for (i = 0; i < demux->filternum; i++) { @@ -996,12 +1034,15 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (demux->filter[i].filter.parent != &feed->feed.sec) continue; demux->filter[i].state = DMX_STATE_GO; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) - StartHWFilter(&demux->filter[i]); + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StartHWFilter(&demux->filter[i]); + if (ret) + break; + } } } - return 0; + return ret; } @@ -1010,6 +1051,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = demux->priv; + int ret = 0; dprintk(4, "%p\n", av7110); if (feed->type == DMX_TYPE_TS) { @@ -1022,26 +1064,29 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) } if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) { - dvb_feed_stop_pid(feed); + ret = dvb_feed_stop_pid(feed); } else if ((feed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE)) - StopHWFilter(feed->filter); + ret = StopHWFilter(feed->filter); } - if (feed->type == DMX_TYPE_SEC) { + if (!ret && feed->type == DMX_TYPE_SEC) { int i; for (i = 0; ifilternum; i++) if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { demux->filter[i].state = DMX_STATE_READY; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) - StopHWFilter(&demux->filter[i]); + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StopHWFilter(&demux->filter[i]); + if (ret) + break; + } } } - return 0; + return ret; } @@ -1093,7 +1138,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); if (ret) { printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__); - return -EIO; + return ret; } dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", fwstc[0], fwstc[1], fwstc[2], fwstc[3]); @@ -1119,18 +1164,14 @@ static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_ON: - Set22K(av7110, 1); - break; + return Set22K(av7110, 1); case SEC_TONE_OFF: - Set22K(av7110, 0); - break; + return Set22K(av7110, 0); default: return -EINVAL; } - - return 0; } static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, @@ -1138,9 +1179,7 @@ static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, { struct av7110* av7110 = fe->dvb->priv; - av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); - - return 0; + return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); } static int av7110_diseqc_send_burst(struct dvb_frontend* fe, @@ -1148,9 +1187,7 @@ static int av7110_diseqc_send_burst(struct dvb_frontend* fe, { struct av7110* av7110 = fe->dvb->priv; - av7110_diseqc_send(av7110, 0, NULL, minicmd); - - return 0; + return av7110_diseqc_send(av7110, 0, NULL, minicmd); } /* simplified code from budget-core.c */ @@ -1992,76 +2029,84 @@ static struct l64781_config grundig_29504_401_config = { -static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) { + int ret = 0; int synced = (status & FE_HAS_LOCK) ? 1 : 0; av7110->fe_status = status; if (av7110->fe_synced == synced) - return; + return 0; av7110->fe_synced = synced; if (av7110->playing) - return; + return 0; if (down_interruptible(&av7110->pid_mutex)) - return; + return -ERESTARTSYS; if (av7110->fe_synced) { - SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], + ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); } else { - SetPIDs(av7110, 0, 0, 0, 0, 0); - av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); - av7110_wait_msgstate(av7110, GPMQBusy); + ret = SetPIDs(av7110, 0, 0, 0, 0, 0); + if (!ret) { + ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); + if (!ret) + ret = av7110_wait_msgstate(av7110, GPMQBusy); + } } up(&av7110->pid_mutex); + return ret; } static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_set_frontend(fe, params); + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_frontend(fe, params); + return ret; } static int av7110_fe_init(struct dvb_frontend* fe) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_init(fe); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_init(fe); + return ret; } static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct av7110* av7110 = fe->dvb->priv; - int ret; /* call the real implementation */ - ret = av7110->fe_read_status(fe, status); - if (ret) - return ret; - - if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) { - av7110_fe_lock_fix(av7110, *status); - } - - return 0; + int ret = av7110->fe_read_status(fe, status); + if (!ret) + if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) + ret = av7110_fe_lock_fix(av7110, *status); + return ret; } static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_diseqc_reset_overload(fe); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_reset_overload(fe); + return ret; } static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, @@ -2069,40 +2114,50 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_diseqc_send_master_cmd(fe, cmd); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + return ret; } static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_diseqc_send_burst(fe, minicmd); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_send_burst(fe, minicmd); + return ret; } static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_set_tone(fe, tone); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_tone(fe, tone); + return ret; } static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_set_voltage(fe, voltage); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_voltage(fe, voltage); + return ret; } static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + return ret; } static u8 read_pwm(struct av7110* av7110) diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index e54222d9b3f9..508b7739c609 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -254,12 +254,12 @@ struct av7110 { }; -extern void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, +extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); extern void av7110_register_irc_handler(void (*func)(u32)); extern void av7110_unregister_irc_handler(void (*func)(u32)); -extern void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config); +extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config); extern int av7110_ir_init (void); extern void av7110_ir_exit (void); diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 13c506ea0bbd..bbfad6def474 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -121,6 +121,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) int av7110_av_start_record(struct av7110 *av7110, int av, struct dvb_demux_feed *dvbdmxfeed) { + int ret = 0; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); @@ -137,7 +138,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av, dvbdmx->pesfilter[0]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[0]); - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; case RP_VIDEO: @@ -145,7 +146,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av, dvbdmx->pesfilter[1]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[1]); - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; case RP_AV: @@ -157,14 +158,15 @@ int av7110_av_start_record(struct av7110 *av7110, int av, dvbdmx->pesfilter[1]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[1]); - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); break; } - return 0; + return ret; } int av7110_av_start_play(struct av7110 *av7110, int av) { + int ret = 0; dprintk(2, "av7110:%p, \n", av7110); if (av7110->rec_mode) @@ -182,54 +184,57 @@ int av7110_av_start_play(struct av7110 *av7110, int av) av7110->playing |= av; switch (av7110->playing) { case RP_AUDIO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); break; case RP_VIDEO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); av7110->sinfo = 0; break; case RP_AV: av7110->sinfo = 0; - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; } - return av7110->playing; + if (!ret) + ret = av7110->playing; + return ret; } -void av7110_av_stop(struct av7110 *av7110, int av) +int av7110_av_stop(struct av7110 *av7110, int av) { + int ret = 0; dprintk(2, "av7110:%p, \n", av7110); if (!(av7110->playing & av) && !(av7110->rec_mode & av)) - return; - + return 0; av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); if (av7110->playing) { av7110->playing &= ~av; switch (av7110->playing) { case RP_AUDIO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); break; case RP_VIDEO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); break; case RP_NONE: - av7110_set_vidmode(av7110, av7110->vidmode); + ret = av7110_set_vidmode(av7110, av7110->vidmode); break; } } else { av7110->rec_mode &= ~av; switch (av7110->rec_mode) { case RP_AUDIO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; case RP_VIDEO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; case RP_NONE: break; } } + return ret; } @@ -317,19 +322,22 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) return 0; } -void av7110_set_vidmode(struct av7110 *av7110, int mode) +int av7110_set_vidmode(struct av7110 *av7110, int mode) { + int ret; dprintk(2, "av7110:%p, \n", av7110); - av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); - if (!av7110->playing) { - ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], + if (!ret && !av7110->playing) { + ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); } + return ret; } @@ -340,17 +348,18 @@ static int sw2mode[16] = { VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, }; -static void get_video_format(struct av7110 *av7110, u8 *buf, int count) +static int get_video_format(struct av7110 *av7110, u8 *buf, int count) { int i; int hsize, vsize; int sw; u8 *p; + int ret = 0; dprintk(2, "av7110:%p, \n", av7110); if (av7110->sinfo) - return; + return 0; for (i = 7; i < count - 10; i++) { p = buf + i; if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) @@ -359,11 +368,14 @@ static void get_video_format(struct av7110 *av7110, u8 *buf, int count) hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); vsize = ((p[1] &0x0F) << 8) | (p[2]); sw = (p[3] & 0x0F); - av7110_set_vidmode(av7110, sw2mode[sw]); - dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); - av7110->sinfo = 1; + ret = av7110_set_vidmode(av7110, sw2mode[sw]); + if (!ret) { + dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); + av7110->sinfo = 1; + } break; } + return ret; } @@ -974,7 +986,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, unsigned long arg = (unsigned long) parg; int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && @@ -987,49 +999,57 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_STOP: av7110->videostate.play_state = VIDEO_STOPPED; if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) - av7110_av_stop(av7110, RP_VIDEO); + ret = av7110_av_stop(av7110, RP_VIDEO); else - vidcom(av7110, VIDEO_CMD_STOP, + ret = vidcom(av7110, VIDEO_CMD_STOP, av7110->videostate.video_blank ? 0 : 1); - av7110->trickmode = TRICK_NONE; + if (!ret) + av7110->trickmode = TRICK_NONE; break; case VIDEO_PLAY: av7110->trickmode = TRICK_NONE; if (av7110->videostate.play_state == VIDEO_FREEZED) { av7110->videostate.play_state = VIDEO_PLAYING; - vidcom(av7110, VIDEO_CMD_PLAY, 0); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (ret) + break; } if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { if (av7110->playing == RP_AV) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (ret) + break; av7110->playing &= ~RP_VIDEO; } - av7110_av_start_play(av7110, RP_VIDEO); - vidcom(av7110, VIDEO_CMD_PLAY, 0); - } else { - //av7110_av_stop(av7110, RP_VIDEO); - vidcom(av7110, VIDEO_CMD_PLAY, 0); + ret = av7110_av_start_play(av7110, RP_VIDEO); } - av7110->videostate.play_state = VIDEO_PLAYING; + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (!ret) + av7110->videostate.play_state = VIDEO_PLAYING; break; case VIDEO_FREEZE: av7110->videostate.play_state = VIDEO_FREEZED; if (av7110->playing & RP_VIDEO) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); else - vidcom(av7110, VIDEO_CMD_FREEZE, 1); - av7110->trickmode = TRICK_FREEZE; + ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1); + if (!ret) + av7110->trickmode = TRICK_FREEZE; break; case VIDEO_CONTINUE: if (av7110->playing & RP_VIDEO) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); - vidcom(av7110, VIDEO_CMD_PLAY, 0); - av7110->videostate.play_state = VIDEO_PLAYING; - av7110->trickmode = TRICK_NONE; + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (!ret) { + av7110->videostate.play_state = VIDEO_PLAYING; + av7110->trickmode = TRICK_NONE; + } break; case VIDEO_SELECT_SOURCE: @@ -1045,7 +1065,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, break; case VIDEO_GET_EVENT: - ret=dvb_video_get_event(av7110, parg, file->f_flags); + ret = dvb_video_get_event(av7110, parg, file->f_flags); break; case VIDEO_GET_SIZE: @@ -1105,25 +1125,32 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_FAST_FORWARD: //note: arg is ignored by firmware if (av7110->playing & RP_VIDEO) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Scan_I, 2, AV_PES, 0); else - vidcom(av7110, VIDEO_CMD_FFWD, arg); - av7110->trickmode = TRICK_FAST; - av7110->videostate.play_state = VIDEO_PLAYING; + ret = vidcom(av7110, VIDEO_CMD_FFWD, arg); + if (!ret) { + av7110->trickmode = TRICK_FAST; + av7110->videostate.play_state = VIDEO_PLAYING; + } break; case VIDEO_SLOWMOTION: if (av7110->playing&RP_VIDEO) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); - vidcom(av7110, VIDEO_CMD_SLOW, arg); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } else { - vidcom(av7110, VIDEO_CMD_PLAY, 0); - vidcom(av7110, VIDEO_CMD_STOP, 0); - vidcom(av7110, VIDEO_CMD_SLOW, arg); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_STOP, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); + } + if (!ret) { + av7110->trickmode = TRICK_SLOW; + av7110->videostate.play_state = VIDEO_PLAYING; } - av7110->trickmode = TRICK_SLOW; - av7110->videostate.play_state = VIDEO_PLAYING; break; case VIDEO_GET_CAPABILITIES: @@ -1136,18 +1163,21 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, av7110_ipack_reset(&av7110->ipack[1]); if (av7110->playing == RP_AV) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + if (ret) + break; if (av7110->trickmode == TRICK_FAST) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Scan_I, 2, AV_PES, 0); if (av7110->trickmode == TRICK_SLOW) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); - vidcom(av7110, VIDEO_CMD_SLOW, arg); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } if (av7110->trickmode == TRICK_FREEZE) - vidcom(av7110, VIDEO_CMD_STOP, 1); + ret = vidcom(av7110, VIDEO_CMD_STOP, 1); } break; @@ -1170,7 +1200,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, unsigned long arg = (unsigned long) parg; int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); if (((file->f_flags & O_ACCMODE) == O_RDONLY) && (cmd != AUDIO_GET_STATUS)) @@ -1179,28 +1209,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, switch (cmd) { case AUDIO_STOP: if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - av7110_av_stop(av7110, RP_AUDIO); + ret = av7110_av_stop(av7110, RP_AUDIO); else - audcom(av7110, AUDIO_CMD_MUTE); - av7110->audiostate.play_state = AUDIO_STOPPED; + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_STOPPED; break; case AUDIO_PLAY: if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - av7110_av_start_play(av7110, RP_AUDIO); - audcom(av7110, AUDIO_CMD_UNMUTE); - av7110->audiostate.play_state = AUDIO_PLAYING; + ret = av7110_av_start_play(av7110, RP_AUDIO); + if (!ret) + ret = audcom(av7110, AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PLAYING; break; case AUDIO_PAUSE: - audcom(av7110, AUDIO_CMD_MUTE); - av7110->audiostate.play_state = AUDIO_PAUSED; + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PAUSED; break; case AUDIO_CONTINUE: if (av7110->audiostate.play_state == AUDIO_PAUSED) { av7110->audiostate.play_state = AUDIO_PLAYING; - audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); + ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); } break; @@ -1210,14 +1244,15 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, case AUDIO_SET_MUTE: { - audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); - av7110->audiostate.mute_state = (int) arg; + ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.mute_state = (int) arg; break; } case AUDIO_SET_AV_SYNC: av7110->audiostate.AV_sync_state = (int) arg; - audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); + ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); break; case AUDIO_SET_BYPASS_MODE: @@ -1229,21 +1264,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, switch(av7110->audiostate.channel_select) { case AUDIO_STEREO: - audcom(av7110, AUDIO_CMD_STEREO); - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x49); + ret = audcom(av7110, AUDIO_CMD_STEREO); + if (!ret) + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x49); break; case AUDIO_MONO_LEFT: - audcom(av7110, AUDIO_CMD_MONO_L); - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x4a); + ret = audcom(av7110, AUDIO_CMD_MONO_L); + if (!ret) + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x4a); break; case AUDIO_MONO_RIGHT: - audcom(av7110, AUDIO_CMD_MONO_R); - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x45); + ret = audcom(av7110, AUDIO_CMD_MONO_R); + if (!ret) + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x45); break; default: @@ -1264,7 +1302,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); av7110_ipack_reset(&av7110->ipack[0]); if (av7110->playing == RP_AV) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; case AUDIO_SET_ID: @@ -1274,7 +1312,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, { struct audio_mixer *amix = (struct audio_mixer *)parg; - av7110_set_volume(av7110, amix->volume_left, amix->volume_right); + ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); break; } case AUDIO_SET_STREAMTYPE: diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h index cc5e7a7e87c3..45dc144b8b43 100644 --- a/drivers/media/dvb/ttpci/av7110_av.h +++ b/drivers/media/dvb/ttpci/av7110_av.h @@ -3,14 +3,14 @@ struct av7110; -extern void av7110_set_vidmode(struct av7110 *av7110, int mode); +extern int av7110_set_vidmode(struct av7110 *av7110, int mode); extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); -extern void av7110_av_stop(struct av7110 *av7110, int av); +extern int av7110_av_stop(struct av7110 *av7110, int av); extern int av7110_av_start_record(struct av7110 *av7110, int av, struct dvb_demux_feed *dvbdmxfeed); extern int av7110_av_start_play(struct av7110 *av7110, int av); diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 52061e17c6dd..fedd20f9815d 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -458,27 +458,27 @@ static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); } -static inline void av7710_set_video_mode(struct av7110 *av7110, int mode) +static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) { - av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); } -static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg) +static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) { return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, (com>>16), (com&0xffff), (arg>>16), (arg&0xffff)); } -static int inline audcom(struct av7110 *av7110, u32 com) +static inline int audcom(struct av7110 *av7110, u32 com) { return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, (com>>16), (com&0xffff)); } -static inline void Set22K(struct av7110 *av7110, int state) +static inline int Set22K(struct av7110 *av7110, int state) { - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); } -- cgit v1.2.2 From 12ba05049f9060e21ed1f95e876d8d063d2575b2 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:58:00 -0700 Subject: [PATCH] dvb: ttpci: error handling fix Change error handling in av7110_stop_feed() to stop as many filters as possible in case of errors. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index e21deee9a985..87767af7207c 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1050,8 +1050,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = demux->priv; - - int ret = 0; + int i, rc, ret = 0; dprintk(4, "%p\n", av7110); if (feed->type == DMX_TYPE_TS) { @@ -1072,17 +1071,17 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) } if (!ret && feed->type == DMX_TYPE_SEC) { - int i; - - for (i = 0; ifilternum; i++) + for (i = 0; ifilternum; i++) { if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { demux->filter[i].state = DMX_STATE_READY; if (demux->dmx.frontend->source != DMX_MEMORY_FE) { - ret = StopHWFilter(&demux->filter[i]); - if (ret) - break; + rc = StopHWFilter(&demux->filter[i]); + if (!ret) + ret = rc; + /* keep going, stop as many filters as possible */ } + } } } -- cgit v1.2.2 From 7a2fa90fa8084846937aa194f8a40abfa99c692f Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:58:01 -0700 Subject: [PATCH] dvb: ttpci: cleanup indentation + whitespace Fix indentation and add some whitepsace between operators. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 12 ++++++------ drivers/media/dvb/ttpci/av7110_av.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 87767af7207c..ab4f77d73edc 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -122,11 +122,11 @@ static void init_av7110_av(struct av7110 *av7110) /* set internal volume control to maximum */ av7110->adac_type = DVB_ADAC_TI; ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); ret = av7710_set_video_mode(av7110, vidmode); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot set video mode:%d\n",ret); /* handle different card types */ @@ -162,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110) if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { // switch DVB SCART on ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); if (rgb_on && (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { @@ -175,10 +175,10 @@ static void init_av7110_av(struct av7110 *av7110) } ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot set volume :%d\n",ret); ret = av7110_setup_irc_config(av7110, 0); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot setup irc config :%d\n",ret); } diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index bbfad6def474..0696a5a4f855 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1126,7 +1126,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, //note: arg is ignored by firmware if (av7110->playing & RP_VIDEO) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); + __Scan_I, 2, AV_PES, 0); else ret = vidcom(av7110, VIDEO_CMD_FFWD, arg); if (!ret) { @@ -1164,15 +1164,15 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (av7110->playing == RP_AV) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); + __Play, 2, AV_PES, 0); if (ret) break; if (av7110->trickmode == TRICK_FAST) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); + __Scan_I, 2, AV_PES, 0); if (av7110->trickmode == TRICK_SLOW) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Slow, 2, 0, 0); + __Slow, 2, 0, 0); if (!ret) ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } @@ -1303,7 +1303,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, av7110_ipack_reset(&av7110->ipack[0]); if (av7110->playing == RP_AV) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); + __Play, 2, AV_PES, 0); break; case AUDIO_SET_ID: -- cgit v1.2.2 From 34612157b48d38e85ff72d65291b9eecb44dd0a6 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 7 Jul 2005 17:58:02 -0700 Subject: [PATCH] dvb: ttpci: make av7110_fe_lock_fix() retryable av7110_fe_lock_fix() modified in a way that it can be retried after -ERESTARTSYS Signed-off-by: Oliver Endriss Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index ab4f77d73edc..e4c6e87f6c5d 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2038,15 +2038,13 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) if (av7110->fe_synced == synced) return 0; - av7110->fe_synced = synced; - if (av7110->playing) return 0; if (down_interruptible(&av7110->pid_mutex)) return -ERESTARTSYS; - if (av7110->fe_synced) { + if (synced) { ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, @@ -2062,6 +2060,9 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) } } + if (!ret) + av7110->fe_synced = synced; + up(&av7110->pid_mutex); return ret; } -- cgit v1.2.2 From 80887a59c255f4a6c348dfc679501b3679d1070f Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Thu, 7 Jul 2005 17:58:03 -0700 Subject: [PATCH] dvb: ttpci: kj printk fix printk() calls should include appropriate KERN_* constant. Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_ipack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c index 246640741888..699ef8b5b99a 100644 --- a/drivers/media/dvb/ttpci/av7110_ipack.c +++ b/drivers/media/dvb/ttpci/av7110_ipack.c @@ -24,7 +24,7 @@ int av7110_ipack_init(struct ipack *p, int size, void (*func)(u8 *buf, int size, void *priv)) { if (!(p->buf = vmalloc(size*sizeof(u8)))) { - printk ("Couldn't allocate memory for ipack\n"); + printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); return -ENOMEM; } p->size = size; -- cgit v1.2.2 From 53936391741dee735304e997e2289500adf970c7 Mon Sep 17 00:00:00 2001 From: Gavin Hamill Date: Thu, 7 Jul 2005 17:58:04 -0700 Subject: [PATCH] dvb: ttpci: add support for Hauppauge/TT DVB-C budget Add support for Hauppauge/TT DVB-C budget. Signed-off-by: Gavin Hamill Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttusb-budget/Kconfig | 1 + drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 50 ++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig index 4aa714ab4c28..c6c1d41a2efb 100644 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ b/drivers/media/dvb/ttusb-budget/Kconfig @@ -3,6 +3,7 @@ config DVB_TTUSB_BUDGET depends on DVB_CORE && USB select DVB_CX22700 select DVB_TDA1004X + select DVB_VES1820 select DVB_TDA8083 select DVB_STV0299 help diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index afa0e7a0e506..2c17a5f58340 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -24,6 +24,7 @@ #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_net.h" +#include "ves1820.h" #include "cx22700.h" #include "tda1004x.h" #include "stv0299.h" @@ -1367,6 +1368,47 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = { .pll_set = ttusb_novas_grundig_29504_491_pll_set, }; +static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + + if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, + .pll_set = alps_tdbe2_pll_set, +}; + +static u8 read_pwm(struct ttusb* ttusb) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} static void frontend_init(struct ttusb* ttusb) @@ -1394,6 +1436,12 @@ static void frontend_init(struct ttusb* ttusb) break; + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); + if (ttusb->fe != NULL) + break; + break; + case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) // try the ALPS TDMB7 first ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap); @@ -1570,7 +1618,7 @@ static void ttusb_disconnect(struct usb_interface *intf) static struct usb_device_id ttusb_table[] = { {USB_DEVICE(0xb48, 0x1003)}, -/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */ + {USB_DEVICE(0xb48, 0x1004)}, {USB_DEVICE(0xb48, 0x1005)}, {} }; -- cgit v1.2.2 From 68293ddbabb26a58ddb0a84aa5058a7acd7127e7 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:58:06 -0700 Subject: [PATCH] dvb: dvb-usb: support Artect T1 with broken USB ids Add #define for device with broken USB ids. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index a0ffbb59fa14..494e1227cb7e 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -115,6 +115,12 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 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) }, + +// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs + +#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs +/* 25 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +#endif { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); @@ -228,12 +234,22 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { } }, +#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs + .num_device_descs = 2, +#else .num_device_descs = 1, +#endif .devices = { { "Artec T1 USB1.1 TVBOX with AN2235", { &dibusb_dib3000mb_table[20], NULL }, { &dibusb_dib3000mb_table[21], NULL }, }, +#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs + { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", + { &dibusb_dib3000mb_table[25], NULL }, + { NULL }, + }, +#endif } }; -- cgit v1.2.2 From 8945c8c3d207c7a69024c02d164f5ae790c5b7ba Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:07 -0700 Subject: [PATCH] dvb: usb: fix ADSTech Instant TV DVB-T USB2.0 support Fixed support for the ADSTech Instant TV DVB-T USB (2.0 version). Thanks to Gerolf Wendland for his support. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 494e1227cb7e..aee6263f07cc 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -31,10 +31,17 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d) return 0; } -/* some of the dibusb 1.1 device aren't equipped with the default tuner +static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x61; + d->pll_desc = &dvb_pll_tua6010xs; + return 0; +} + +/* Some of the Artec 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) +static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d) { u8 b[2] = { 0,0 }, b2[1]; int ret = 0; @@ -59,8 +66,7 @@ static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d) 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; + dibusb_thomson_tuner_attach(d); } else { u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab }; info("this device has the Panasonic ENV77H11D5 onboard."); @@ -114,6 +120,8 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 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) }, + +/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ /* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs @@ -140,7 +148,7 @@ static struct dvb_usb_properties dibusb1_1_properties = { .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb_power_ctrl, .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_dib3000mb_tuner_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, @@ -212,7 +220,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb_power_ctrl, .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_dib3000mb_tuner_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, @@ -257,7 +265,7 @@ 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", + .firmware = "dvb-usb-adstech-usb2-02.fw", .size_of_priv = sizeof(struct dibusb_state), @@ -266,7 +274,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = { .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, + .tuner_attach = dibusb_thomson_tuner_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, @@ -288,11 +296,11 @@ static struct dvb_usb_properties dibusb2_0b_properties = { } }, - .num_device_descs = 2, + .num_device_descs = 1, .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 */ + { &dibusb_dib3000mb_table[24], NULL }, }, } }; -- cgit v1.2.2 From 7f5fee57812c99c95edf6794a50413c75e99fd4d Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:08 -0700 Subject: [PATCH] dvb: usb: add isochronous streaming method Added isochronous-streaming method. Changed memory (de)allocation behaviour accordingly. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-common.h | 3 +- drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 178 +++++++++++++++++++++++------ drivers/media/dvb/dvb-usb/dvb-usb.h | 24 +++- 3 files changed, 167 insertions(+), 38 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index 67e0d73fbceb..abf7d2f562b8 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -15,11 +15,12 @@ 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_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) +#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args) /* commonly used methods */ extern int usb_cypress_load_firmware(struct usb_device *, const char *, int); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 83d476fb410a..dcd8c2f915f8 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -24,6 +24,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if ((ret = down_interruptible(&d->usb_sem))) return ret; + deb_xfer(">>> "); debug_dump(wbuf,wlen,deb_xfer); ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, @@ -46,8 +47,10 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (ret) err("recv bulk message failed: %d",ret); - else + else { + deb_xfer("<<< "); debug_dump(rbuf,actlen,deb_xfer); + } } up(&d->usb_sem); @@ -61,12 +64,19 @@ int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) } EXPORT_SYMBOL(dvb_usb_generic_write); -static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs) + +/* URB stuff for streaming */ +static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) { struct dvb_usb_device *d = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; - deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status, - urb->actual_length); + deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount, + urb->status,urb->actual_length,urb->transfer_buffer_length, + urb->number_of_packets,urb->error_count); switch (urb->status) { case 0: /* success */ @@ -81,11 +91,33 @@ static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs) 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"); + if (d->feedcount > 0) { + if (d->state & DVB_USB_STATE_DVB) { + switch (ptype) { + case PIPE_ISOCHRONOUS: + b = (u8 *) urb->transfer_buffer; + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status != 0) + deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) { + dvb_dmx_swfilter(&d->demux,b + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + debug_dump(b,20,deb_ts); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length); + break; + default: + err("unkown endpoint type in completition handler."); + return; + } + } + } usb_submit_urb(urb,GFP_ATOMIC); } @@ -94,7 +126,7 @@ 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); + deb_ts("killing URB no. %d.\n",i); /* stop the URB */ usb_kill_urb(d->urb_list[i]); @@ -107,9 +139,9 @@ 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); + deb_ts("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); + err("could not submit URB no. %d - get them all back",i); dvb_usb_urb_kill(d); return ret; } @@ -118,32 +150,78 @@ int dvb_usb_urb_submit(struct dvb_usb_device *d) return 0; } -static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) +static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d) { - int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize; + if (d->state & DVB_USB_STATE_URB_BUF) { + while (d->buf_num) { + d->buf_num--; + deb_mem("freeing buffer %d\n",d->buf_num); + usb_buffer_free(d->udev, d->buf_size, + d->buf_list[d->buf_num], d->dma_addr[d->buf_num]); + } + kfree(d->buf_list); + kfree(d->dma_addr); + } + + d->state &= ~DVB_USB_STATE_URB_BUF; - 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 0; +} + +static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size) +{ + d->buf_num = 0; + d->buf_size = size; + + deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + + if ((d->buf_list = kmalloc(num*sizeof(u8 *), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + if ((d->dma_addr = kmalloc(num*sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) { + kfree(d->buf_list); return -ENOMEM; } - deb_info("allocation successful\n"); - memset(d->buffer,0,bufsize); + memset(d->buf_list,0,num*sizeof(u8 *)); + memset(d->dma_addr,0,num*sizeof(dma_addr_t)); d->state |= DVB_USB_STATE_URB_BUF; + for (d->buf_num = 0; d->buf_num < num; d->buf_num++) { + deb_mem("allocating buffer %d\n",d->buf_num); + if (( d->buf_list[d->buf_num] = + usb_buffer_alloc(d->udev, size, SLAB_ATOMIC, + &d->dma_addr[d->buf_num]) ) == NULL) { + deb_mem("not enough memory for urb-buffer allocation.\n"); + dvb_usb_free_stream_buffers(d); + return -ENOMEM; + } + deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]); + memset(d->buf_list[d->buf_num],0,size); + } + deb_mem("allocation successful\n"); + + return 0; +} + +static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) +{ + int i; + + if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count, + d->props.urb.u.bulk.buffersize)) < 0) + return i; + /* allocate the URBs */ for (i = 0; i < d->props.urb.count; i++) { - if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) { + if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) 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->buf_list[i], d->props.urb.u.bulk.buffersize, - dvb_usb_bulk_urb_complete, d); + dvb_usb_urb_complete, d); d->urb_list[i]->transfer_flags = 0; d->urbs_initialized++; @@ -151,6 +229,47 @@ static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) return 0; } +static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d) +{ + int i,j; + + if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count, + d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < d->props.urb.count; i++) { + struct urb *urb; + int frame_offset = 0; + if ((d->urb_list[i] = + usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) + return -ENOMEM; + + urb = d->urb_list[i]; + + urb->dev = d->udev; + urb->context = d; + urb->complete = dvb_usb_urb_complete; + urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = d->props.urb.u.isoc.interval; + urb->number_of_packets = d->props.urb.u.isoc.framesperurb; + urb->transfer_buffer_length = d->buf_size; + urb->transfer_buffer = d->buf_list[i]; + urb->transfer_dma = d->dma_addr[i]; + + for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize; + frame_offset += d->props.urb.u.isoc.framesize; + } + + d->urbs_initialized++; + } + return 0; + +} + int dvb_usb_urb_init(struct dvb_usb_device *d) { /* @@ -174,8 +293,7 @@ int dvb_usb_urb_init(struct dvb_usb_device *d) 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; + return dvb_usb_isoc_urb_init(d); default: err("unkown URB-type for data transfer."); return -EINVAL; @@ -191,7 +309,7 @@ int dvb_usb_urb_exit(struct dvb_usb_device *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); + deb_mem("freeing URB no. %d.\n",i); /* free the URBs */ usb_free_urb(d->urb_list[i]); } @@ -202,10 +320,6 @@ int dvb_usb_urb_exit(struct dvb_usb_device *d) 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; + dvb_usb_free_stream_buffers(d); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index abcee1943f64..6c627e9ea648 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -189,6 +189,7 @@ struct dvb_usb_properties { struct { int framesperurb; int framesize; + int interval; } isoc; } u; } urb; @@ -207,19 +208,28 @@ struct dvb_usb_properties { * @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. + * + * @buf_num: number of buffer allocated. + * @buf_size: size of each buffer in buf_list. + * @buf_list: array containing all allocate buffers for streaming. + * @dma_addr: list of dma_addr_t for each buffer in buf_list. + * * @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 + * + * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board + * * @dvb_adap: device's dvb_adapter. * @dmxdev: device's dmxdev. * @demux: device's software demuxer. @@ -253,8 +263,12 @@ struct dvb_usb_device { /* usb */ struct usb_device *udev; struct urb **urb_list; - u8 *buffer; - dma_addr_t dma_handle; + + int buf_num; + unsigned long buf_size; + u8 **buf_list; + dma_addr_t *dma_addr; + int urbs_initialized; int urbs_submitted; -- cgit v1.2.2 From 49dc82fdac3866e6ce9c978df80cedfb735d740c Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:09 -0700 Subject: [PATCH] dvb: frontend: add FMD1216ME PLL o change dvb-pll desc to take the frequency as parameter for setbw-callback into consideration o added dvb-pll desc for Philips FMD1216ME (needed for cxusb) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 35 +++++++++++++++++++++++++++++++---- drivers/media/dvb/frontends/dvb-pll.h | 3 ++- 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index f73b5f48e235..818526869804 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -55,7 +55,7 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { }; EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); -static void thomson_dtt759x_bw(u8 *buf, int bandwidth) +static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth) { if (BANDWIDTH_7_MHZ == bandwidth) buf[3] |= 0x10; @@ -146,7 +146,7 @@ EXPORT_SYMBOL(dvb_pll_env57h1xd5); /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, int bandwidth) +static void tda665x_bw(u8 *buf, u32 freq, int bandwidth) { if (bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; @@ -178,7 +178,7 @@ EXPORT_SYMBOL(dvb_pll_tda665x); /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, int bandwidth) +static void tua6034_bw(u8 *buf, u32 freq, int bandwidth) { if (BANDWIDTH_7_MHZ != bandwidth) buf[3] |= 0x08; @@ -198,6 +198,33 @@ struct dvb_pll_desc dvb_pll_tua6034 = { }; EXPORT_SYMBOL(dvb_pll_tua6034); +/* Philips FMD1216ME + * used in Medion Hybrid PCMCIA card and USB Box + */ +static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth) +{ + if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000) + buf[3] |= 0x08; +} + +struct dvb_pll_desc dvb_pll_fmd1216me = { + .name = "placeholder", + .min = 50870000, + .max = 858000000, + .setbw = fmd1216me_bw, + .count = 7, + .entries = { + { 143870000, 36213333, 166667, 0xbc, 0x41 }, + { 158870000, 36213333, 166667, 0xf4, 0x41 }, + { 329870000, 36213333, 166667, 0xbc, 0x42 }, + { 441870000, 36213333, 166667, 0xf4, 0x42 }, + { 625870000, 36213333, 166667, 0xbc, 0x44 }, + { 803870000, 36213333, 166667, 0xf4, 0x44 }, + { 999999999, 36213333, 166667, 0xfc, 0x44 }, + } +}; +EXPORT_SYMBOL(dvb_pll_fmd1216me); + /* ----------------------------------------------------------- */ /* code */ @@ -231,7 +258,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, buf[3] = desc->entries[i].cb2; if (desc->setbw) - desc->setbw(buf, bandwidth); + desc->setbw(buf, freq, bandwidth); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index b796778624b6..dc4e1d49ef83 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -9,7 +9,7 @@ struct dvb_pll_desc { char *name; u32 min; u32 max; - void (*setbw)(u8 *buf, int bandwidth); + void (*setbw)(u8 *buf, u32 freq, int bandwidth); int count; struct { u32 limit; @@ -30,6 +30,7 @@ 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; +extern struct dvb_pll_desc dvb_pll_fmd1216me; int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); -- cgit v1.2.2 From 22c6d93a73105fddd58796d7cb10f5f90ee2a338 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:10 -0700 Subject: [PATCH] dvb: usb: support Medion hybrid USB2.0 DVB-T/analogue box Add preliminary support for the Medion Hybrid USB2.0 DVB-T/Analogue box. Analogue part is not working yet (cx25842 --> ivtv?). Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 16 ++ drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/cxusb.c | 287 ++++++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/cxusb.h | 30 ++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + 5 files changed, 338 insertions(+) create mode 100644 drivers/media/dvb/dvb-usb/cxusb.c create mode 100644 drivers/media/dvb/dvb-usb/cxusb.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 8aa32f6e447b..1a69130a8462 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -21,12 +21,14 @@ config DVB_USB_DEBUG config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB + select DVB_DIB3000MC 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 + select DVB_DIB3000MB help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-B demodulator. @@ -52,6 +54,7 @@ config DVB_USB_DIBUSB_MB 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 + select DVB_DIB3000MC help Support for 2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-C/P demodulator. @@ -66,12 +69,24 @@ config DVB_USB_DIBUSB_MC config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB + select DVB_DIB3000MC help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. +config DVB_USB_CXUSB + tristate "Medion MD95700 hybrid USB2.0 (Conexant) support" + depends on DVB_USB + select DVB_CX22702 + help + Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently + only the DVB-T part is supported and MPEG2 data transfer are not working + :(. + config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB + select DVB_NXT6000 + select DVB_MT352 help Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. @@ -87,6 +102,7 @@ config DVB_USB_VP7045 config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB + select DVB_DIB3000MC help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index d65b50f9abb0..746d87ed6f32 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -27,4 +27,7 @@ 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 +dvb-usb-cxusb-objs = cxusb.o +obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o + EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c new file mode 100644 index 000000000000..0324807376cf --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -0,0 +1,287 @@ +/* DVB USB compliant linux driver for Conexant USB reference design. + * + * The Conexant reference design I saw on their website was only for analogue + * capturing (using the cx25842). The box I took to write this driver (reverse + * engineered) is the one labeled Medion MD95700. In addition to the cx25842 + * for analogue capturing it also has a cx22702 DVB-T demodulator on the main + * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard. + * + * Maybe it is a little bit premature to call this driver cxusb, but I assume + * the USB protocol is identical or at least inherited from the reference + * design, so it can be reused for the "analogue-only" device (if it will + * appear at all). + * + * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue + * part + * + * FIXME: We're getting a lock and signal, but the isochronous transfer is empty + * for DVB-T. + * + * 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 "cxusb.h" + +#include "cx22702.h" + +/* debug */ +int dvb_usb_cxusb_debug; +module_param_named(debug,dvb_usb_cxusb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +static int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 sndbuf[1+wlen]; + memset(sndbuf,0,1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1],wbuf,wlen); + if (wo) + dvb_usb_generic_write(d,sndbuf,1+wlen); + else + dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0); + + return 0; +} + +/* I2C */ +static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path) +{ + struct cxusb_state *st = d->priv; + u8 o[2],i; + + if (path == st->cur_i2c_path) + return; + + o[0] = IOCTL_SET_I2C_PATH; + switch (path) { + case PATH_CX22702: + o[1] = 0; + break; + case PATH_TUNER_OTHER: + o[1] = 1; + break; + default: + err("unkown i2c path"); + return; + } + cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1); + + if (i != 0x01) + deb_info("i2c_path setting failed.\n"); + + st->cur_i2c_path = path; +} + +static int cxusb_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++) { + + switch (msg[i].addr) { + case 0x63: + cxusb_set_i2c_path(d,PATH_CX22702); + break; + default: + cxusb_set_i2c_path(d,PATH_TUNER_OTHER); + break; + } + + /* read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; + obuf[0] = msg[i].len; + obuf[1] = msg[i+1].len; + obuf[2] = msg[i].addr; + memcpy(&obuf[3],msg[i].buf,msg[i].len); + + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3+msg[i].len, + ibuf, 1+msg[i+1].len) < 0) + break; + + if (ibuf[0] != 0x08) + deb_info("i2c read could have been failed\n"); + + memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len); + + i++; + } else { /* write */ + u8 obuf[2+msg[i].len], ibuf; + obuf[0] = msg[i].addr; + obuf[1] = msg[i].len; + memcpy(&obuf[2],msg[i].buf,msg[i].len); + + if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0) + break; + if (ibuf != 0x08) + deb_info("i2c write could have been failed\n"); + } + } + + up(&d->i2c_sem); + return i; +} + +static u32 cxusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm cxusb_i2c_algo = { + .name = "Conexant USB I2C algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = cxusb_i2c_xfer, + .functionality = cxusb_i2c_func, +}; + +static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + return 0; +} + +static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) +{ + return 0; +} + +struct cx22702_config cxusb_cx22702_config = { + .demod_address = 0x63, + + .pll_init = dvb_usb_pll_init_i2c, + .pll_set = dvb_usb_pll_set_i2c, +}; + +/* Callbacks for DVB USB */ +static int cxusb_tuner_attach(struct dvb_usb_device *d) +{ + u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; + d->pll_addr = 0x61; + memcpy(d->pll_init,bpll,4); + d->pll_desc = &dvb_pll_fmd1216me; + return 0; +} + +static int cxusb_frontend_attach(struct dvb_usb_device *d) +{ + u8 buf[2] = { 0x03, 0x00 }; + u8 b = 0; + + cxusb_ctrl_msg(d,0xde,&b,0,NULL,0); + cxusb_set_i2c_path(d,PATH_TUNER_OTHER); + cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1); + + if (usb_set_interface(d->udev,0,6) < 0) + err("set interface failed\n"); + + cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); + cxusb_set_i2c_path(d,PATH_CX22702); + cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1); + + if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_properties cxusb_properties; + +static int cxusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE); +} + +static struct usb_device_id cxusb_table [] = { + { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, cxusb_table); + +static struct dvb_usb_properties cxusb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_frontend_attach, + .tuner_attach = cxusb_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 64, + .framesize = 940*3, + .interval = 1, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "Medion MD95700 (MDUSBTV-HYBRID)", + { NULL }, + { &cxusb_table[0], NULL }, + }, + } +}; + +static struct usb_driver cxusb_driver = { + .owner = THIS_MODULE, + .name = "cxusb", + .probe = cxusb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cxusb_table, +}; + +/* module stuff */ +static int __init cxusb_module_init(void) +{ + int result; + if ((result = usb_register(&cxusb_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit cxusb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&cxusb_driver); +} + +module_init (cxusb_module_init); +module_exit (cxusb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h new file mode 100644 index 000000000000..1d79016e3195 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -0,0 +1,30 @@ +#ifndef _DVB_USB_CXUSB_H_ +#define _DVB_USB_CXUSB_H_ + +#define DVB_USB_LOG_PREFIX "digitv" +#include "dvb-usb.h" + +extern int dvb_usb_cxusb_debug; +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) + +/* usb commands - some of it are guesses, don't have a reference yet */ +#define CMD_I2C_WRITE 0x08 +#define CMD_I2C_READ 0x09 + +#define CMD_IOCTL 0x0e +#define IOCTL_SET_I2C_PATH 0x02 + +#define CMD_POWER_OFF 0x50 +#define CMD_POWER_ON 0x51 + +enum cxusb_i2c_pathes { + PATH_UNDEF = 0x00, + PATH_CX22702 = 0x01, + PATH_TUNER_OTHER = 0x02, +}; + +struct cxusb_state { + enum cxusb_i2c_pathes cur_i2c_path; +}; + +#endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index bcb34191868b..de2463bae225 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -24,6 +24,7 @@ #define USB_VID_HANFTEK 0x15f4 #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_MEDION 0x1660 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 @@ -78,6 +79,7 @@ #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 #define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 +#define USB_PID_MEDION_MD95700 0x0932 #endif -- cgit v1.2.2 From c9b06fa47e1c1ff8704461c7fd6a99e3621ba0e6 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:11 -0700 Subject: [PATCH] dvb: usb: add module parm to disable remote control polling Add module parameter to deactive remote control polling. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-common.h | 1 + drivers/media/dvb/dvb-usb/dvb-usb-init.c | 4 ++++ drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 8 +++++++- 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index abf7d2f562b8..7300489d3e24 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -12,6 +12,7 @@ #include "dvb-usb.h" extern int dvb_usb_debug; +extern int dvb_usb_disable_rc_polling; #define deb_info(args...) dprintk(dvb_usb_debug,0x01,args) #define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 3aadec974cf1..c3b3ae4f3ec7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -18,6 +18,10 @@ 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); +int dvb_usb_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); + /* general initialization functions */ int dvb_usb_exit(struct dvb_usb_device *d) { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 9f1e23f82bae..f4038bf21c91 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -21,6 +21,10 @@ static void dvb_usb_read_remote_control(void *data) /* TODO: need a lock here. We can simply skip checking for the remote control if we're busy. */ + /* when the parameter has been set to 1 via sysfs while the driver was running */ + if (dvb_usb_disable_rc_polling) + return; + if (d->props.rc_query(d,&event,&state)) { err("error while querying for an remote control event."); goto schedule; @@ -85,7 +89,9 @@ schedule: int dvb_usb_remote_init(struct dvb_usb_device *d) { int i; - if (d->props.rc_key_map == NULL) + if (d->props.rc_key_map == NULL || + d->props.rc_query == NULL || + dvb_usb_disable_rc_polling) return 0; /* Initialise the remote-control structures.*/ -- cgit v1.2.2 From 0589b8e4fd24885a00d8954aef57c3319d161fee Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:12 -0700 Subject: [PATCH] dvb: frontend: add ALPS TDED4 PLL Add dvb_pll_desc for ALPS TDED4 used in Nebula USB boxes. Changed the name-field of the FMD1216. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 26 +++++++++++++++++++++++++- drivers/media/dvb/frontends/dvb-pll.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 818526869804..8be143b7ce4c 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -208,7 +208,7 @@ static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth) } struct dvb_pll_desc dvb_pll_fmd1216me = { - .name = "placeholder", + .name = "Philips FMD1216ME", .min = 50870000, .max = 858000000, .setbw = fmd1216me_bw, @@ -225,6 +225,30 @@ struct dvb_pll_desc dvb_pll_fmd1216me = { }; EXPORT_SYMBOL(dvb_pll_fmd1216me); +/* ALPS TDED4 + * used in Nebula-Cards and USB boxes + */ +static void tded4_bw(u8 *buf, u32 freq, int bandwidth) +{ + if (bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x04; +} + +struct dvb_pll_desc dvb_pll_tded4 = { + .name = "ALPS TDED4", + .min = 47000000, + .max = 863000000, + .setbw = tded4_bw, + .count = 4, + .entries = { + { 153000000, 36166667, 166667, 0x85, 0x01 }, + { 470000000, 36166667, 166667, 0x85, 0x02 }, + { 823000000, 36166667, 166667, 0x85, 0x08 }, + { 999999999, 36166667, 166667, 0x85, 0x88 }, + } +}; +EXPORT_SYMBOL(dvb_pll_tded4); + /* ----------------------------------------------------------- */ /* code */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index dc4e1d49ef83..57b64ffee402 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -31,6 +31,7 @@ extern struct dvb_pll_desc dvb_pll_env57h1xd5; extern struct dvb_pll_desc dvb_pll_tua6034; extern struct dvb_pll_desc dvb_pll_tda665x; extern struct dvb_pll_desc dvb_pll_fmd1216me; +extern struct dvb_pll_desc dvb_pll_tded4; int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); -- cgit v1.2.2 From 78c6e73f5a27f01e45e86a4e3d13863c9cce6374 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:13 -0700 Subject: [PATCH] dvb: usb: digitv-usb fixes Some more work on the digitv-usb driver: o MT352 initialization and PLL-programming o I2c-transfer fixed. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/digitv.c | 69 +++++++++++++------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 5acf3fde9522..f272d34f7725 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -1,10 +1,9 @@ /* 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) + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * - * partly based on the SDK published by Nebula Electronics (TODO do we want this line ?) + * partly based on the SDK published by Nebula Electronics * * 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 @@ -95,41 +94,20 @@ static int digitv_identify_state (struct usb_device *udev, struct 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 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; + static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, + 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, + 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, + 0x75, 0x32 }; + int i; - static u8 mt352_scan_ctl[] = { 0x88, 0x0f }; - static u8 mt352_capt_range[] = { 0x75, 0x32 }; + for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) + mt352_write(fe, &reset_buf[i], 2); - 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)); + for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) + mt352_write(fe, &init_buf[i], 2); return 0; } @@ -137,7 +115,7 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe) 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 */ + .pll_set = dvb_usb_pll_set, }; static struct nxt6000_config digitv_nxt6000_config = { @@ -150,9 +128,9 @@ static struct nxt6000_config digitv_nxt6000_config = { static int digitv_frontend_attach(struct dvb_usb_device *d) { - if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) == NULL) + 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) { + 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 " @@ -163,6 +141,13 @@ static int digitv_frontend_attach(struct dvb_usb_device *d) return -EIO; } +static int digitv_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x60; + d->pll_desc = &dvb_pll_tded4; + return 0; +} + static struct dvb_usb_rc_key digitv_rc_keys[] = { { 0x00, 0x16, KEY_POWER }, /* dummy key */ }; @@ -184,7 +169,6 @@ int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } - /* DVB USB Driver stuff */ static struct dvb_usb_properties digitv_properties; @@ -208,13 +192,8 @@ static struct dvb_usb_properties digitv_properties = { .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, + .tuner_attach = digitv_tuner_attach, .rc_interval = 1000, .rc_key_map = digitv_rc_keys, @@ -238,7 +217,7 @@ static struct dvb_usb_properties digitv_properties = { } }, - .num_device_descs = 2, + .num_device_descs = 1, .devices = { { "Nebula Electronics uDigiTV DVB-T USB2.0)", { &digitv_table[0], NULL }, -- cgit v1.2.2 From c251ef6167c46152e247fc41628a4ac2d0aca33e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:14 -0700 Subject: [PATCH] dvb: usb: dvb_usb_properties init fix There was no pid-filter-count set for some devices - led to an error. Thanks to Gerolf Wendland. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index aee6263f07cc..691900578ee3 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -209,6 +209,8 @@ static struct dvb_usb_properties dibusb1_1_properties = { 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, + .pid_filter_count = 16, + .usb_ctrl = CYPRESS_AN2235, .firmware = "dvb-usb-dibusb-an2235-01.fw", @@ -263,6 +265,8 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { 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, + .pid_filter_count = 32, + .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-adstech-usb2-02.fw", -- cgit v1.2.2 From 8257e8a444a2b81952de9f8bfeb3a4726c0f7d5b Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:15 -0700 Subject: [PATCH] dvb: usb: cxusb DVB-T fixes cxusb DVB-T fixes. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/cxusb.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 0324807376cf..b4bb206a510f 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -14,9 +14,6 @@ * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue * part * - * FIXME: We're getting a lock and signal, but the isochronous transfer is empty - * for DVB-T. - * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * * This program is free software; you can redistribute it and/or modify it @@ -157,12 +154,20 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { + u8 buf[2] = { 0x03, 0x00 }; + if (onoff) + cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); + else + cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0); + return 0; } struct cx22702_config cxusb_cx22702_config = { .demod_address = 0x63, + .output_mode = CX22702_PARALLEL_OUTPUT, + .pll_init = dvb_usb_pll_init_i2c, .pll_set = dvb_usb_pll_set_i2c, }; @@ -182,12 +187,15 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d) u8 buf[2] = { 0x03, 0x00 }; u8 b = 0; + if (usb_set_interface(d->udev,0,0) < 0) + err("set interface to alts=0 failed"); + cxusb_ctrl_msg(d,0xde,&b,0,NULL,0); cxusb_set_i2c_path(d,PATH_TUNER_OTHER); cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1); if (usb_set_interface(d->udev,0,6) < 0) - err("set interface failed\n"); + err("set interface failed"); cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); cxusb_set_i2c_path(d,PATH_CX22702); @@ -236,9 +244,9 @@ static struct dvb_usb_properties cxusb_properties = { .endpoint = 0x02, .u = { .isoc = { - .framesperurb = 64, - .framesize = 940*3, - .interval = 1, + .framesperurb = 32, + .framesize = 940, + .interval = 5, } } }, -- cgit v1.2.2 From 2f7f96b95991bcbe52dee5aa50a19130873738bf Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:16 -0700 Subject: [PATCH] dvb: usb: add VideoWalker DVB-T USB ids Add another USB ID pair for the VideoWalker USB DVB-T. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 12 +++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 3 +++ drivers/media/dvb/dvb-usb/dvb-usb.h | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 691900578ee3..1cd490252890 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -123,11 +123,13 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ /* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, +/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, +/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs -/* 25 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +/* 27 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, #endif { } /* Terminating entry */ }; @@ -170,7 +172,7 @@ static struct dvb_usb_properties dibusb1_1_properties = { } }, - .num_device_descs = 8, + .num_device_descs = 9, .devices = { { "AVerMedia AverTV DVBT USB1.1", { &dibusb_dib3000mb_table[0], NULL }, @@ -204,6 +206,10 @@ static struct dvb_usb_properties dibusb1_1_properties = { { &dibusb_dib3000mb_table[19], NULL }, { &dibusb_dib3000mb_table[20], NULL }, }, + { "VideoWalker DVB-T USB", + { &dibusb_dib3000mb_table[25], NULL }, + { &dibusb_dib3000mb_table[26], NULL }, + }, } }; @@ -256,7 +262,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { }, #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[25], NULL }, + { &dibusb_dib3000mb_table[27], NULL }, { NULL }, }, #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index de2463bae225..9fea93df6ab4 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -24,6 +24,7 @@ #define USB_VID_HANFTEK 0x15f4 #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_KYE 0x0458 #define USB_VID_MEDION 0x1660 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 @@ -80,6 +81,8 @@ #define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 #define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 #define USB_PID_MEDION_MD95700 0x0932 +#define USB_PID_KYE_DVB_T_COLD 0x701e +#define USB_PID_KYE_DVB_T_WARM 0x701f #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 6c627e9ea648..a80567caf508 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -195,7 +195,7 @@ struct dvb_usb_properties { } urb; int num_device_descs; - struct dvb_usb_device_description devices[8]; + struct dvb_usb_device_description devices[9]; }; -- cgit v1.2.2 From 97432808ee367e15485e55c734ba04ca290a306d Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:17 -0700 Subject: [PATCH] dvb: usb: digitv memcpy fix Fix memcpy copying into the wrong destination. Thanks to Allan Third for reporting. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/digitv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f272d34f7725..8155a26f0ddf 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -37,7 +37,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d, dvb_usb_generic_write(d,sndbuf,7); } else { dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); - memcpy(&rbuf,&rcvbuf[3],rlen); + memcpy(rbuf,&rcvbuf[3],rlen); } return 0; } -- cgit v1.2.2 From d72fa1c91d721bf4c68a18f2d8fed820a8f1611e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:20 -0700 Subject: [PATCH] dvb: usb Kconfig help text update o corrected some typos o added the Wikilink pointing to the USB device list Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 1a69130a8462..d4deb75352c9 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -3,19 +3,22 @@ config DVB_USB 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. + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. Almost every USB device needs a firmware, please look into - + . - Say Y if you own an USB DVB device. + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a 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 + Say Y if you want to enable debugging. See modinfo dvb-usb (and the appropriate drivers) for debug levels. config DVB_USB_A800 @@ -79,8 +82,7 @@ config DVB_USB_CXUSB select DVB_CX22702 help Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently - only the DVB-T part is supported and MPEG2 data transfer are not working - :(. + only the DVB-T part is supported. config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" -- cgit v1.2.2 From 2d188c68a04d89d9351c3130226d0e8af9439dda Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:21 -0700 Subject: [PATCH] dvb: usb: add vp7045 IR keymap Add keymap for Twinhan vp7045 remote control. Signed-off-by: Michael Paxton Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/vp7045.c | 39 +++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 02ecc9a8e3b6..bb99cbc098fc 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -94,13 +94,38 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) /* 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 }, + { 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. */ + { 0x00, 0xa1, KEY_CANCEL }, /* Cancel */ + { 0x00, 0x1c, KEY_EPG }, /* EPG */ + { 0x00, 0x40, KEY_TAB }, /* Tab */ + { 0x00, 0x48, KEY_INFO }, /* Preview */ + { 0x00, 0x04, KEY_LIST }, /* RecordList */ + { 0x00, 0x0f, KEY_TEXT } /* Teletext */ }; static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) -- cgit v1.2.2 From fb41f5a725d052d7542e0e966e5799b95c2648c8 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:23 -0700 Subject: [PATCH] dvb: usb: fix WideView USB ids o Steve Chang reported the real name behind 0x14aa: WideView, changed USB IDs accordingly. o fixed an assignment Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 4 ++-- drivers/media/dvb/dvb-usb/dibusb-mb.c | 4 ++-- drivers/media/dvb/dvb-usb/dtt200u-fe.c | 4 ++-- drivers/media/dvb/dvb-usb/dtt200u.c | 16 ++++++++-------- drivers/media/dvb/dvb-usb/dtt200u.h | 4 ++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index d4deb75352c9..91e88b2ed5d0 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -109,9 +109,9 @@ config DVB_USB_NOVA_T_USB2 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" + tristate "WideView/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. + Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 1cd490252890..cda2179d61aa 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -96,8 +96,8 @@ static int dibusb_probe(struct usb_interface *intf, /* 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)}, +/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD)}, +/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, 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) }, diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index d17d768038c6..7807f33573b8 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -1,5 +1,5 @@ -/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T - * USB2.0 receiver. +/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. * * Copyright (C) 2005 Patrick Boettcher * diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index fb2b5a2da137..1ebd3eff96d1 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -1,5 +1,5 @@ -/* DVB USB library compliant Linux driver for the Yakumo/Hama/Typhoon DVB-T - * USB2.0 receiver. +/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * @@ -89,8 +89,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf, } 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) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -127,8 +127,8 @@ static struct dvb_usb_properties dtt200u_properties = { .num_device_descs = 1, .devices = { - { .name = "Yakumo/Hama/Typhoon DVB-T USB2.0)", - .cold_ids = { &dtt200u_usb_table[0], &dtt200u_usb_table[2] }, + { .name = "WideView/Yakumo/Hama/Typhoon DVB-T USB2.0)", + .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, { 0 }, @@ -138,7 +138,7 @@ static struct dvb_usb_properties dtt200u_properties = { /* 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", + .name = "dtt200u", .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = dtt200u_usb_table, @@ -166,6 +166,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 device"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h index ed4142071518..9ab081a55b84 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.h +++ b/drivers/media/dvb/dvb-usb/dtt200u.h @@ -1,5 +1,5 @@ -/* Common header file of Linux driver for the Yakumo/Hama/Typhoon DVB-T - * USB2.0 receiver. +/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 9fea93df6ab4..75f4cb18a635 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -12,7 +12,7 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_ANCHOR 0x0547 -#define USB_VID_AVERMEDIA_UNK 0x14aa +#define USB_VID_WIDEVIEW 0x14aa #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f -- cgit v1.2.2 From 04f3e5ea51248ff974a13ef2dd0145125c76204c Mon Sep 17 00:00:00 2001 From: Michael Paxton Date: Thu, 7 Jul 2005 17:58:24 -0700 Subject: [PATCH] dvb: usb: vp7045 IR map fix Correct two keys of the vp7045 remote control key mapping. Signed-off-by: Michael Paxton Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/vp7045.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index bb99cbc098fc..72d5d3f74463 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -120,9 +120,9 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = { { 0x00, 0x4c, KEY_PAUSE }, { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */ { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - { 0x00, 0xa1, KEY_CANCEL }, /* Cancel */ + { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */ { 0x00, 0x1c, KEY_EPG }, /* EPG */ - { 0x00, 0x40, KEY_TAB }, /* Tab */ + { 0x00, 0x00, KEY_TAB }, /* Tab */ { 0x00, 0x48, KEY_INFO }, /* Preview */ { 0x00, 0x04, KEY_LIST }, /* RecordList */ { 0x00, 0x0f, KEY_TEXT } /* Teletext */ -- cgit v1.2.2 From 1df896aa239caf72483655290c40b21da536d85e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:24 -0700 Subject: [PATCH] dvb: usb: IR input fixes o fixed usage of the correct number of events in keymapping-array o better place for return Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index f4038bf21c91..fc7800f1743e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -39,7 +39,7 @@ static void dvb_usb_read_remote_control(void *data) 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, 1); input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); input_sync(&d->rc_input_dev); break; @@ -160,12 +160,12 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, break; } /* See if we can match the raw key code. */ - for (i = 0; i < sizeof(keymap)/sizeof(struct dvb_usb_rc_key); i++) + for (i = 0; i < d->props.rc_key_map_size; i++) if (keymap[i].custom == keybuf[1] && keymap[i].data == keybuf[3]) { *event = keymap[i].event; *state = REMOTE_KEY_PRESSED; - break; + return 0; } deb_err("key mapping failed - no appropriate key found in keymapping\n"); break; -- cgit v1.2.2 From 58769a5486bec8ed44b3b51029f8df8f13cddd5a Mon Sep 17 00:00:00 2001 From: Andrew Hodgson Date: Thu, 7 Jul 2005 17:58:26 -0700 Subject: [PATCH] dvb: usb: A800 rc and timeout fixes o add some remote control codes o not using HZ for control_msg-timeout Signed-off-by: Andrew Hodgson Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/a800.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index a3542935604f..672037c22819 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -61,6 +61,12 @@ static struct dvb_usb_rc_key a800_rc_keys[] = { { 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */ { 0x02, 0x04, KEY_EPG }, /* EPG */ { 0x02, 0x15, KEY_MENU }, /* MENU */ + + { 0x03, 0x03, KEY_CHANNELUP }, /* CH UP */ + { 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */ + { 0x03, 0x01, KEY_FIRST }, /* |<< / GREEN */ + { 0x03, 0x00, KEY_LAST }, /* >>| / BLUE */ + }; int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) @@ -68,7 +74,7 @@ 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) + 2000) != 5) return -ENODEV; /* call the universal NEC remote processor, to find out the key's state and event */ -- cgit v1.2.2 From e161f817bebecc1c1cc461dc83cce2eafbed9ee9 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:27 -0700 Subject: [PATCH] dvb: usb: dont use HZ for timeouts Don't use HZ for usb-transfer-timeouts. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index dcd8c2f915f8..f5799a4c228e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -29,7 +29,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, - 2*HZ); + 2000); if (ret) err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); @@ -43,7 +43,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, - 2*HZ); + 2000); if (ret) err("recv bulk message failed: %d",ret); -- cgit v1.2.2 From 25de192660627e1e8dc8ee6a120ff8b54d108593 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 7 Jul 2005 17:58:28 -0700 Subject: [PATCH] dvb: ttpci: fix timeout handling to be save with PREEMPT Timeout handling fixed, especially for preemtible kernels and/or high system load. Signed-off-by: Oliver Endriss Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_hw.c | 72 +++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 23 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index aa1efce6cb31..1220826696c5 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -308,6 +308,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) { unsigned long start; u32 stat; + int err; if (FW_VERSION(av7110->arm_app) <= 0x261c) { /* not supported by old firmware */ @@ -318,14 +319,14 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) /* new firmware */ start = jiffies; for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); if (down_interruptible(&av7110->dcomlock)) return -ERESTARTSYS; stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); up(&av7110->dcomlock); - if ((stat & flags) == 0) { + if ((stat & flags) == 0) break; - } - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + if (err) { printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", __FUNCTION__, stat & flags); return -ETIMEDOUT; @@ -342,6 +343,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) char *type = NULL; u16 flags[2] = {0, 0}; u32 stat; + int err; // dprintk(4, "%p\n", av7110); @@ -351,8 +353,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) } start = jiffies; - while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); return -ETIMEDOUT; } @@ -363,8 +368,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifndef _NOHANDSHAKE start = jiffies; - while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); return -ETIMEDOUT; } @@ -401,6 +409,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) /* non-immediate COMMAND type */ start = jiffies; for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); if (stat & flags[0]) { printk(KERN_ERR "%s: %s QUEUE overflow\n", @@ -409,7 +418,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) } if ((stat & flags[1]) == 0) break; - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + if (err) { printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", __FUNCTION__, type); return -ETIMEDOUT; @@ -432,12 +441,13 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifdef COM_DEBUG start = jiffies; - while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", - __FUNCTION__, - (buf[0] >> 8) & 0xff - ); + __FUNCTION__, (buf[0] >> 8) & 0xff); return -ETIMEDOUT; } msleep(1); @@ -553,8 +563,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, } start = jiffies; - while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; @@ -566,8 +579,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, #ifndef _NOHANDSHAKE start = jiffies; - while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; @@ -707,12 +723,16 @@ static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, static int FlushText(struct av7110 *av7110) { unsigned long start; + int err; if (down_interruptible(&av7110->dcomlock)) return -ERESTARTSYS; start = jiffies; - while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_OSD)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); @@ -735,8 +755,11 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) return -ERESTARTSYS; start = jiffies; - while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_OSD)) { + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (ret) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); @@ -746,8 +769,11 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) } #ifndef _NOHANDSHAKE start = jiffies; - while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (ret) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); -- cgit v1.2.2 From d8667cbbe440aacb246832afc217a6a44664115c Mon Sep 17 00:00:00 2001 From: Mac Michaels Date: Thu, 7 Jul 2005 17:58:29 -0700 Subject: [PATCH] dvb: frontend: add driver for LGDT3302 Add support for LGDT3302 (ATSC VSB/QAM) used in DViCO FusionHDTV3 Gold. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dvb-pll.c | 13 + drivers/media/dvb/frontends/dvb-pll.h | 1 + drivers/media/dvb/frontends/lgdt3302.c | 618 ++++++++++++++++++++++++++++ drivers/media/dvb/frontends/lgdt3302.h | 49 +++ drivers/media/dvb/frontends/lgdt3302_priv.h | 72 ++++ 7 files changed, 761 insertions(+) create mode 100644 drivers/media/dvb/frontends/lgdt3302.c create mode 100644 drivers/media/dvb/frontends/lgdt3302.h create mode 100644 drivers/media/dvb/frontends/lgdt3302_priv.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 5c695937e2ad..d847c62bd837 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -187,4 +187,11 @@ config DVB_BCM3510 An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LGDT3302 + tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)" + depends on DVB_CORE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 8d46dd721f45..de5e240cba7f 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o +obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 8be143b7ce4c..71e06ec7925a 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -93,6 +93,19 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { }; EXPORT_SYMBOL(dvb_pll_lg_z201); +struct dvb_pll_desc dvb_pll_microtune_4042 = { + .name = "Microtune 4042 FI5", + .min = 57000000, + .max = 858000000, + .count = 3, + .entries = { + { 162000000, 44000000, 62500, 0x8e, 0xa1 }, + { 457000000, 44000000, 62500, 0x8e, 0x91 }, + { 999999999, 44000000, 62500, 0x8e, 0x31 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_microtune_4042); + struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 57b64ffee402..98312bfe59d0 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -24,6 +24,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; 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_microtune_4042; extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c new file mode 100644 index 000000000000..d0b91219cf6e --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -0,0 +1,618 @@ +/* + * $Id: lgdt3302.c,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * + * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * Based on code from Kirk Lapray + * Copyright (C) 2005 + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * NOTES ABOUT THIS DRIVER + * + * This driver supports DViCO FusionHDTV 3 Gold under Linux. + * + * TODO: + * BER and signal strength always return 0. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "lgdt3302_priv.h" +#include "lgdt3302.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off)."); +#define dprintk(args...) \ +do { \ +if (debug) printk(KERN_DEBUG "lgdt3302: " args); \ +} while (0) + +struct lgdt3302_state +{ + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + + /* Configuration settings */ + const struct lgdt3302_config* config; + + struct dvb_frontend frontend; + + /* Demodulator private data */ + fe_modulation_t current_modulation; + + /* Tuner private data */ + u32 current_frequency; +}; + +static int i2c_writebytes (struct lgdt3302_state* state, + u8 addr, /* demod_address or pll_address */ + u8 *buf, /* data bytes to send */ + int len /* number of bytes to send */ ) +{ + if (addr == state->config->pll_address) { + struct i2c_msg msg = + { .addr = addr, .flags = 0, .buf = buf, .len = len }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); + return -EREMOTEIO; + } + } else { + u8 tmp[] = { buf[0], buf[1] }; + struct i2c_msg msg = + { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; + int err; + int i; + + for (i=1; ii2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); + return -EREMOTEIO; + } + tmp[0]++; + } + } + return 0; +} +static int i2c_readbytes (struct lgdt3302_state* state, + u8 addr, /* demod_address or pll_address */ + u8 *buf, /* holds data bytes read */ + int len /* number of bytes to read */ ) +{ + struct i2c_msg msg = + { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); + return -EREMOTEIO; + } + return 0; +} + +/* + * This routine writes the register (reg) to the demod bus + * then reads the data returned for (len) bytes. + */ + +static u8 i2c_selectreadbytes (struct lgdt3302_state* state, + enum I2C_REG reg, u8* buf, int len) +{ + u8 wr [] = { reg }; + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, + .flags = 0, .buf = wr, .len = 1 }, + { .addr = state->config->demod_address, + .flags = I2C_M_RD, .buf = buf, .len = len }, + }; + int ret; + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret); + } else { + ret = 0; + } + return ret; +} + +/* Software reset */ +int lgdt3302_SwReset(struct lgdt3302_state* state) +{ + u8 ret; + u8 reset[] = { + IRQ_MASK, + 0x00 /* bit 6 is active low software reset + * bits 5-0 are 1 to mask interrupts */ + }; + + ret = i2c_writebytes(state, + state->config->demod_address, + reset, sizeof(reset)); + if (ret == 0) { + /* spec says reset takes 100 ns why wait */ + /* mdelay(100); */ /* keep low for 100mS */ + reset[1] = 0x7f; /* force reset high (inactive) + * and unmask interrupts */ + ret = i2c_writebytes(state, + state->config->demod_address, + reset, sizeof(reset)); + } + /* Spec does not indicate a need for this either */ + /*mdelay(5); */ /* wait 5 msec before doing more */ + return ret; +} + +static int lgdt3302_init(struct dvb_frontend* fe) +{ + /* Hardware reset is done using gpio[0] of cx23880x chip. + * I'd like to do it here, but don't know how to find chip address. + * cx88-cards.c arranges for the reset bit to be inactive (high). + * Maybe there needs to be a callable function in cx88-core or + * the caller of this function needs to do it. */ + + dprintk("%s entered\n", __FUNCTION__); + return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv); +} + +static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; /* Dummy out for now */ + return 0; +} + +static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + u8 buf[2]; + + i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf)); + + *ucblocks = (buf[0] << 8) | buf[1]; + return 0; +} + +static int lgdt3302_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + u8 buf[4]; + struct lgdt3302_state* state = + (struct lgdt3302_state*) fe->demodulator_priv; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ + static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; + static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; + static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb }; + static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 }; + static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 }; + static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x00, 0x00, 0x00 }; + static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; + + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + dprintk("%s: VSB_8 MODE\n", __FUNCTION__); + + /* Select VSB mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x07; + break; + + case QAM_64: + dprintk("%s: QAM_64 MODE\n", __FUNCTION__); + + /* Select QAM_64 mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x04; + break; + + case QAM_256: + dprintk("%s: QAM_256 MODE\n", __FUNCTION__); + + /* Select QAM_256 mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x05; + break; + default: + printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); + return -1; + } + /* Initializations common to all modes */ + + /* Select the requested mode */ + i2c_writebytes(state, state->config->demod_address, + top_ctrl_cfg, sizeof(top_ctrl_cfg)); + + /* Change the value of IFBW[11:0] + of AGC IF/RF loop filter bandwidth register */ + i2c_writebytes(state, state->config->demod_address, + agc_rf_cfg, sizeof(agc_rf_cfg)); + + /* Change the value of bit 6, 'nINAGCBY' and + 'NSSEL[1:0] of ACG function control register 2 */ + /* Change the value of bit 6 'RFFIX' + of AGC function control register 3 */ + i2c_writebytes(state, state->config->demod_address, + agc_ctrl_cfg, sizeof(agc_ctrl_cfg)); + + /* Change the TPCLK pin polarity + data is valid on falling clock */ + i2c_writebytes(state, state->config->demod_address, + demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); + + if (param->u.vsb.modulation == VSB_8) { + /* Initialization for VSB modes only */ + /* Change the value of NCOCTFV[25:0]of carrier + recovery center frequency register for VSB */ + i2c_writebytes(state, state->config->demod_address, + vsb_freq_cfg, sizeof(vsb_freq_cfg)); + } else { + /* Initialization for QAM modes only */ + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to value from 'IFACC' register 0x39/0x3b -1 */ + int value; + i2c_selectreadbytes(state, AGC_RFIF_ACC0, + &agc_delay_cfg[1], 3); + value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; + value = value -1; + dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); + agc_delay_cfg[1] = (value >> 8) & 0x0f; + agc_delay_cfg[2] = 0x00; + agc_delay_cfg[3] = value & 0xff; + i2c_writebytes(state, state->config->demod_address, + agc_delay_cfg, sizeof(agc_delay_cfg)); + + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + i2c_writebytes(state, state->config->demod_address, + agc_loop_cfg, sizeof(agc_loop_cfg)); + } + + state->config->set_ts_params(fe, 0); + lgdt3302_SwReset(state); + state->current_modulation = param->u.vsb.modulation; + } +#else + printk("lgdt3302: %s: you need a newer kernel for this, sorry\n",__FUNCTION__); +#endif + + /* Change only if we are actually changing the channel */ + if (state->current_frequency != param->frequency) { + dvb_pll_configure(state->config->pll_desc, buf, + param->frequency, 0); + dprintk("%s: tuner bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]); + i2c_writebytes(state, state->config->pll_address ,buf, 4); + + /* Check the status of the tuner pll */ + i2c_readbytes(state, state->config->pll_address, buf, 1); + dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); + + lgdt3302_SwReset(state); + + /* Update current frequency */ + state->current_frequency = param->frequency; + } + return 0; +} + +static int lgdt3302_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* param) +{ + struct lgdt3302_state *state = fe->demodulator_priv; + param->frequency = state->current_frequency; + return 0; +} + +static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + u8 buf[3]; + + *status = 0; /* Reset status result */ + + /* Check the status of the tuner pll */ + i2c_readbytes(state, state->config->pll_address, buf, 1); + dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0xc0) != 0x40) + return 0; /* Tuner PLL not locked or not powered on */ + + /* + * You must set the Mask bits to 1 in the IRQ_MASK in order + * to see that status bit in the IRQ_STATUS register. + * This is done in SwReset(); + */ + + /* signal status */ + i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); + dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); + if ((buf[2] & 0x30) == 0x10) + *status |= FE_HAS_SIGNAL; + + /* sync status */ + if ((buf[2] & 0x03) == 0x01) { + *status |= FE_HAS_SYNC; + } + + /* FEC error status */ + if ((buf[2] & 0x0c) == 0x08) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + } + +#if 0 + /* Alternative method to check for a signal */ + /* AGC status register */ + i2c_selectreadbytes(state, AGC_STATUS, buf, 1); + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0x0c) == 0x80) /* Test signal does not exist flag */ + /* Test AGC lock flag */ + *status |= FE_HAS_SIGNAL; + else + return 0; + + /* Carrier Recovery Lock Status Register */ + i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* Need to undestand why there are 3 lock levels here */ + if ((buf[0] & 0x07) == 0x07) + *status |= FE_HAS_CARRIER; + else + return 0; + break; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + case VSB_8: + if ((buf[0] & 0x80) == 0x80) + *status |= FE_HAS_CARRIER; + else + return 0; + break; +#endif + default: + printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__); + } +#endif + + return 0; +} + +static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + /* not directly available. */ + return 0; +} + +static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) +{ +#ifdef SNR_IN_DB + /* + * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise) + * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker + * respectively. The following tables are built on these formulas. + * The usual definition is SNR = 20 log10(signal/noise) + * If the specification is wrong the value retuned is 1/2 the actual SNR in db. + * + * This table is a an ordered list of noise values computed by the + * formula from the spec sheet such that the index into the table + * starting at 43 or 45 is the SNR value in db. There are duplicate noise + * value entries at the beginning because the SNR varies more than + * 1 db for a change of 1 digit in noise at very small values of noise. + * + * Examples from SNR_EQ table: + * noise SNR + * 0 43 + * 1 42 + * 2 39 + * 3 37 + * 4 36 + * 5 35 + * 6 34 + * 7 33 + * 8 33 + * 9 32 + * 10 32 + * 11 31 + * 12 31 + * 13 30 + */ + + static const u32 SNR_EQ[] = + { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, + 9, 11, 13, 17, 21, 26, 33, 41, 52, 65, + 81, 102, 129, 162, 204, 257, 323, 406, 511, 644, + 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433, + 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323, + 80978, 101945, 128341, 161571, 203406, 256073, 0x40000 + }; + + static const u32 SNR_PH[] = + { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8, + 10, 12, 15, 19, 23, 29, 37, 46, 58, 73, + 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, + 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, + 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, + 90833, 114351, 143960, 181235, 228161, 0x040000 + }; + + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + static u32 snr_db; /* index into SNR_EQ[] */ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + + /* read both equalizer and pase tracker noise data */ + i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + + if (state->current_modulation == VSB_8) { + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + + /* + * Look up noise value in table. + * A better search algorithm could be used... + * watch out there are duplicate entries. + */ + for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) { + if (noise < SNR_EQ[snr_db]) { + *snr = 43 - snr_db; + break; + } + } + } else { + /* Phase Tracker Mean-Square Error Register for QAM */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + + /* Look up noise value in table. */ + for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) { + if (noise < SNR_PH[snr_db]) { + *snr = 45 - snr_db; + break; + } + } + } +#else + /* Return the raw noise value */ + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + + /* read both equalizer and pase tracker noise data */ + i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + + if (state->current_modulation == VSB_8) { + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + } else { + /* Phase Tracker Mean-Square Error Register for QAM */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + } + + /* Small values for noise mean signal is better so invert noise */ + /* Noise is 19 bit value so discard 3 LSB*/ + *snr = ~noise>>3; +#endif + + dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); + + return 0; +} + +static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + /* I have no idea about this - it may not be needed */ + fe_tune_settings->min_delay_ms = 500; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + return 0; +} + +static void lgdt3302_release(struct dvb_frontend* fe) +{ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops lgdt3302_ops; + +struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config, + struct i2c_adapter* i2c) +{ + struct lgdt3302_state* state = NULL; + u8 buf[1]; + + /* Allocate memory for the internal state */ + state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL); + if (state == NULL) + goto error; + memset(state,0,sizeof(*state)); + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); + /* Verify communication with demod chip */ + if (i2c_selectreadbytes(state, 2, buf, 1)) + goto error; + + state->current_frequency = -1; + state->current_modulation = -1; + + /* Create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) + kfree(state); + dprintk("%s: ERROR\n",__FUNCTION__); + return NULL; +} + +static struct dvb_frontend_ops lgdt3302_ops = { + .info = { + .name= "LG Electronics LGDT3302 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + /* Symbol rate is for all VSB modes need to check QAM */ + .symbol_rate_min = 10762000, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt3302_init, + .set_frontend = lgdt3302_set_parameters, + .get_frontend = lgdt3302_get_frontend, + .get_tune_settings = lgdt3302_get_tune_settings, + .read_status = lgdt3302_read_status, + .read_ber = lgdt3302_read_ber, + .read_signal_strength = lgdt3302_read_signal_strength, + .read_snr = lgdt3302_read_snr, + .read_ucblocks = lgdt3302_read_ucblocks, + .release = lgdt3302_release, +}; + +MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_AUTHOR("Wilson Michaels"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(lgdt3302_attach); + +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h new file mode 100644 index 000000000000..81587a40032b --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3302.h @@ -0,0 +1,49 @@ +/* + * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * + * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LGDT3302_H +#define LGDT3302_H + +#include + +struct lgdt3302_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + u8 pll_address; + struct dvb_pll_desc *pll_desc; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config, + struct i2c_adapter* i2c); + +#endif /* LGDT3302_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h new file mode 100644 index 000000000000..6193fa7a569d --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3302_priv.h @@ -0,0 +1,72 @@ +/* + * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * + * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LGDT3302_PRIV_ +#define _LGDT3302_PRIV_ + +/* i2c control register addresses */ +enum I2C_REG { + TOP_CONTROL= 0x00, + IRQ_MASK= 0x01, + IRQ_STATUS= 0x02, + VSB_CARRIER_FREQ0= 0x16, + VSB_CARRIER_FREQ1= 0x17, + VSB_CARRIER_FREQ2= 0x18, + VSB_CARRIER_FREQ3= 0x19, + CARRIER_MSEQAM1= 0x1a, + CARRIER_MSEQAM2= 0x1b, + CARRIER_LOCK= 0x1c, + TIMING_RECOVERY= 0x1d, + AGC_DELAY0= 0x2a, + AGC_DELAY1= 0x2b, + AGC_DELAY2= 0x2c, + AGC_RF_BANDWIDTH0= 0x2d, + AGC_RF_BANDWIDTH1= 0x2e, + AGC_RF_BANDWIDTH2= 0x2f, + AGC_LOOP_BANDWIDTH0= 0x30, + AGC_LOOP_BANDWIDTH1= 0x31, + AGC_FUNC_CTRL1= 0x32, + AGC_FUNC_CTRL2= 0x33, + AGC_FUNC_CTRL3= 0x34, + AGC_RFIF_ACC0= 0x39, + AGC_RFIF_ACC1= 0x3a, + AGC_RFIF_ACC2= 0x3b, + AGC_STATUS= 0x3f, + SYNC_STATUS_VSB= 0x43, + EQPH_ERR0= 0x47, + EQ_ERR1= 0x48, + EQ_ERR2= 0x49, + PH_ERR1= 0x4a, + PH_ERR2= 0x4b, + DEMUX_CONTROL= 0x66, + PACKET_ERR_COUNTER1= 0x6a, + PACKET_ERR_COUNTER2= 0x6b, +}; + +#endif /* _LGDT3302_PRIV_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v1.2.2 From 63b5c1c47fd6c5ae26d279756e8a050c721ea379 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:30 -0700 Subject: [PATCH] dvb: usb/pci: correct syntax of driver name fields Change the name-field of the pci_driver and usb_driver structs to the name of the module after compilation. It seems that this field is used in some places where special characters are not allowed. Thanks to Alan Halverson for finding this problem. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-pci.c | 2 +- drivers/media/dvb/b2c2/flexcop-usb.c | 2 +- drivers/media/dvb/dvb-usb/a800.c | 2 +- drivers/media/dvb/dvb-usb/cxusb.c | 2 +- drivers/media/dvb/dvb-usb/dibusb-mb.c | 2 +- drivers/media/dvb/dvb-usb/dibusb-mc.c | 2 +- drivers/media/dvb/dvb-usb/digitv.c | 2 +- drivers/media/dvb/dvb-usb/nova-t-usb2.c | 2 +- drivers/media/dvb/dvb-usb/umt-010.c | 2 +- drivers/media/dvb/dvb-usb/vp7045.c | 6 +++--- 10 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index a436d5584ea6..2f76eb3fea40 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -409,7 +409,7 @@ static struct pci_device_id flexcop_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); static struct pci_driver flexcop_pci_driver = { - .name = "Technisat/B2C2 FlexCop II/IIb PCI", + .name = "b2c2_flexcop_pci", .id_table = flexcop_pci_tbl, .probe = flexcop_pci_probe, .remove = flexcop_pci_remove, diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 0113449abd15..0a78ba3737a5 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -545,7 +545,7 @@ static struct usb_device_id flexcop_usb_table [] = { /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver flexcop_usb_driver = { .owner = THIS_MODULE, - .name = "Technisat/B2C2 FlexCop II/IIb/III USB", + .name = "b2c2_flexcop_usb", .probe = flexcop_usb_probe, .disconnect = flexcop_usb_disconnect, .id_table = flexcop_usb_table, diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index 672037c22819..f2fcc2f1f846 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -149,7 +149,7 @@ static struct dvb_usb_properties a800_properties = { static struct usb_driver a800_driver = { .owner = THIS_MODULE, - .name = "AVerMedia AverTV DVB-T USB 2.0 (A800)", + .name = "dvb_usb_a800", .probe = a800_probe, .disconnect = dvb_usb_device_exit, .id_table = a800_table, diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index b4bb206a510f..c3e1b661aae6 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -262,7 +262,7 @@ static struct dvb_usb_properties cxusb_properties = { static struct usb_driver cxusb_driver = { .owner = THIS_MODULE, - .name = "cxusb", + .name = "dvb_usb_cxusb", .probe = cxusb_probe, .disconnect = dvb_usb_device_exit, .id_table = cxusb_table, diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index cda2179d61aa..828b5182e16c 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -317,7 +317,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = { static struct usb_driver dibusb_driver = { .owner = THIS_MODULE, - .name = "DiBcom based USB DVB-T devices (DiB3000M-B based)", + .name = "dvb_usb_dibusb_mb", .probe = dibusb_probe, .disconnect = dvb_usb_device_exit, .id_table = dibusb_dib3000mb_table, diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index aad8ed3fe005..e9dac430f37d 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -83,7 +83,7 @@ static struct dvb_usb_properties dibusb_mc_properties = { static struct usb_driver dibusb_mc_driver = { .owner = THIS_MODULE, - .name = "DiBcom based USB2.0 DVB-T (DiB3000M-C/P based) devices", + .name = "dvb_usb_dibusb_mc", .probe = dibusb_mc_probe, .disconnect = dvb_usb_device_exit, .id_table = dibusb_dib3000mc_table, diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 8155a26f0ddf..9a676afc1d6e 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -228,7 +228,7 @@ static struct dvb_usb_properties digitv_properties = { static struct usb_driver digitv_driver = { .owner = THIS_MODULE, - .name = "Nebula Electronics uDigiTV DVB-T USB2.0 device", + .name = "dvb_usb_digitv", .probe = digitv_probe, .disconnect = dvb_usb_device_exit, .id_table = digitv_table, diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index 9d83781aef95..258a92bfbcc7 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -203,7 +203,7 @@ static struct dvb_usb_properties nova_t_properties = { static struct usb_driver nova_t_driver = { .owner = THIS_MODULE, - .name = "Hauppauge WinTV-NOVA-T usb2", + .name = "dvb_usb_nova_t_usb2", .probe = nova_t_probe, .disconnect = dvb_usb_device_exit, .id_table = nova_t_table, diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index aa560422ce7c..2112ac3cf5e2 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -129,7 +129,7 @@ static struct dvb_usb_properties umt_properties = { static struct usb_driver umt_driver = { .owner = THIS_MODULE, - .name = "HanfTek UMT-010 USB2.0 DVB-T devices", + .name = "dvb_usb_umt_010", .probe = umt_probe, .disconnect = dvb_usb_device_exit, .id_table = umt_table, diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 72d5d3f74463..5adc5d69ec84 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -44,7 +44,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, 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) { + outbuf, 20, 2000) != 20) { err("USB control message 'out' went wrong."); ret = -EIO; goto unlock; @@ -55,7 +55,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, 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) { + inbuf, 12, 2000) != 12) { err("USB control message 'in' went wrong."); ret = -EIO; goto unlock; @@ -255,7 +255,7 @@ static struct dvb_usb_properties vp7045_properties = { /* 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", + .name = "dvb_usb_vp7045", .probe = vp7045_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = vp7045_usb_table, -- cgit v1.2.2 From 4b2bd30eb79c292a83b1dfd3cca6d435c02fd5c0 Mon Sep 17 00:00:00 2001 From: Steffen Motzer Date: Thu, 7 Jul 2005 17:58:31 -0700 Subject: [PATCH] dvb: dst: fix tuning problem Fix tuning failure for 200103A, 200103A failed to tune to low band due to wrong tone setting on the 200103A. Signed-off-by: Steffen Motzer Signed-off-by: Manu Abraham Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index d8f4200065ee..9bd12832e3d9 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1147,7 +1147,11 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_OFF: - state->tx_tuna[2] = 0xff; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + state->tx_tuna[2] = 0x00; + else + state->tx_tuna[2] = 0xff; + break; case SEC_TONE_ON: -- cgit v1.2.2 From d590f9c20e15620ba708e5bd71d345bf1b7b0d73 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:33 -0700 Subject: [PATCH] dvb: usb: add supprt for WideView WT-220U Add support and rewrote some parts with the help of vendor information (Thanks to Steve Chang from WideView, Inc.): o added support for the WT-220U (Pensize DVB-T receiver) o corrected byte order for unc,ber and the pid filter o corrected number of pids that can be fetched at the same time. o added some comments in Kconfig-file o added USB IDs for the WT-220U Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 4 +- drivers/media/dvb/dvb-usb/dtt200u-fe.c | 72 +++++++++++++-------------- drivers/media/dvb/dvb-usb/dtt200u.c | 86 ++++++++++++++++++++++++++++----- drivers/media/dvb/dvb-usb/dtt200u.h | 38 ++++++--------- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 3 +- 5 files changed, 130 insertions(+), 73 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 91e88b2ed5d0..612e5b087b1c 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -109,9 +109,11 @@ config DVB_USB_NOVA_T_USB2 Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. config DVB_USB_DTT200U - tristate "WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support" + tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" depends on DVB_USB help Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). + + The WT-220U and its clones are pen-sized. diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index 7807f33573b8..b032523b07bc 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -14,61 +14,58 @@ struct dtt200u_fe_state { struct dvb_usb_device *d; + fe_status_t stat; + 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 }; + u8 st = GET_TUNE_STATUS, b[3]; + + dvb_usb_generic_rw(state->d,&st,1,b,3,0); - dvb_usb_generic_rw(state->d,&bw,1,br,3,0); - switch (br[0]) { + switch (b[0]) { case 0x01: - *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; break; - case 0x00: - *stat = 0; + case 0x00: /* pending */ + *stat = FE_TIMEDOUT; /* during set_frontend */ break; default: - moan("br[0]",GET_TUNE_STAT); + case 0x02: /* failed */ + *stat = 0; 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); + u8 bw = GET_VIT_ERR_CNT,b[3]; + dvb_usb_generic_rw(state->d,&bw,1,b,3,0); + *ber = (b[0] << 16) | (b[1] << 8) | b[2]; 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); + u8 bw = GET_RS_UNCOR_BLK_CNT,b[2]; + + dvb_usb_generic_rw(state->d,&bw,1,b,2,0); + *unc = (b[0] << 8) | b[1]; 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; + u8 bw = GET_AGC, b; dvb_usb_generic_rw(state->d,&bw,1,&b,1,0); *strength = (b << 8) | b; return 0; @@ -86,7 +83,7 @@ static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr) static int dtt200u_fe_init(struct dvb_frontend* fe) { struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 b = RESET_DEMOD; + u8 b = SET_INIT; return dvb_usb_generic_write(state->d,&b,1); } @@ -98,8 +95,8 @@ static int dtt200u_fe_sleep(struct dvb_frontend* 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; + tune->step_size = 0; + tune->max_drift = 0; return 0; } @@ -107,27 +104,32 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dtt200u_fe_state *state = fe->demodulator_priv; + int i; + fe_status_t st; u16 freq = fep->frequency / 250000; - u8 bw,bwbuf[2] = { SET_BANDWIDTH, 0 }, freqbuf[3] = { SET_FREQUENCY, 0, 0 }; + u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 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_8_MHZ: bwbuf[1] = 8; break; + case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break; + case BANDWIDTH_6_MHZ: bwbuf[1] = 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)); + for (i = 0; i < 30; i++) { + msleep(20); + dtt200u_fe_read_status(fe, &st); + if (st & FE_TIMEDOUT) + continue; + } return 0; } @@ -174,7 +176,7 @@ success: static struct dvb_frontend_ops dtt200u_fe_ops = { .info = { - .name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T", + .name = "WideView USB DVB-T", .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 1ebd3eff96d1..47dba6e45968 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -3,6 +3,8 @@ * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * + * Thanks to Steve Chang from WideView for providing support for the WT-220U. + * * 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. @@ -16,14 +18,24 @@ 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_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = SET_INIT; + + if (onoff) + dvb_usb_generic_write(d,&b,2); + + return 0; +} + static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff) { - u8 b_streaming[2] = { SET_TS_CTRL, onoff }; + u8 b_streaming[2] = { SET_STREAMING, onoff }; u8 b_rst_pid = RESET_PID_FILTER; dvb_usb_generic_write(d,b_streaming,2); - if (!onoff) + if (onoff == 0) dvb_usb_generic_write(d,&b_rst_pid,1); return 0; } @@ -36,7 +48,7 @@ static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int b_pid[0] = SET_PID_FILTER; b_pid[1] = index; b_pid[2] = pid & 0xff; - b_pid[3] = (pid >> 8) & 0xff; + b_pid[3] = (pid >> 8) & 0x1f; return dvb_usb_generic_write(d,b_pid,4); } @@ -54,9 +66,9 @@ static struct dvb_usb_rc_key dtt200u_rc_keys[] = { { 0x80, 0x08, KEY_5 }, { 0x80, 0x09, KEY_6 }, { 0x80, 0x0a, KEY_7 }, - { 0x00, 0x0c, KEY_ZOOM }, + { 0x80, 0x0c, KEY_ZOOM }, { 0x80, 0x0d, KEY_0 }, - { 0x00, 0x0e, KEY_SELECT }, + { 0x80, 0x0e, KEY_SELECT }, { 0x80, 0x12, KEY_POWER }, { 0x80, 0x1a, KEY_CHANNELUP }, { 0x80, 0x1b, KEY_8 }, @@ -66,7 +78,7 @@ static struct dvb_usb_rc_key dtt200u_rc_keys[] = { static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - u8 key[5],cmd = GET_RC_KEY; + u8 key[5],cmd = GET_RC_CODE; 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) @@ -81,32 +93,41 @@ static int dtt200u_frontend_attach(struct dvb_usb_device *d) } static struct dvb_usb_properties dtt200u_properties; +static struct dvb_usb_properties wt220u_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); + if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 || + dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0) + return 0; + + return -ENODEV; } static struct usb_device_id dtt200u_usb_table [] = { +// { USB_DEVICE(0x04b4,0x8613) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_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 */ + .pid_filter_count = 15, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-dtt200u-01.fw", + .power_ctrl = dtt200u_power_ctrl, .streaming_ctrl = dtt200u_streaming_ctrl, .pid_filter = dtt200u_pid_filter, .frontend_attach = dtt200u_frontend_attach, - .rc_interval = 200, + .rc_interval = 300, .rc_key_map = dtt200u_rc_keys, .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), .rc_query = dtt200u_rc_query, @@ -127,7 +148,7 @@ static struct dvb_usb_properties dtt200u_properties = { .num_device_descs = 1, .devices = { - { .name = "WideView/Yakumo/Hama/Typhoon DVB-T USB2.0)", + { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, @@ -135,10 +156,51 @@ static struct dvb_usb_properties dtt200u_properties = { } }; +static struct dvb_usb_properties wt220u_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-01.fw", + + .power_ctrl = dtt200u_power_ctrl, + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + + .rc_interval = 300, + .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 = "WideView WT-220U PenType Receiver (and clones)", + .cold_ids = { &dtt200u_usb_table[2], NULL }, + .warm_ids = { &dtt200u_usb_table[3], 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 = "dtt200u", + .name = "dvb_usb_dtt200u", .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = dtt200u_usb_table, @@ -166,6 +228,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 device"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h index 9ab081a55b84..6f1f3042e21a 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.h +++ b/drivers/media/dvb/dvb-usb/dtt200u.h @@ -22,44 +22,34 @@ extern int dvb_usb_dtt200u_debug; /* guessed protocol description (reverse engineered): * read * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 - * 81 - - * 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 +#define GET_SPEED 0x00 +#define GET_TUNE_STATUS 0x81 +#define GET_RC_CODE 0x84 +#define GET_CONFIGURATION 0x88 +#define GET_AGC 0x89 +#define GET_SNR 0x8a +#define GET_VIT_ERR_CNT 0x8c +#define GET_RS_ERR_CNT 0x8d +#define GET_RS_UNCOR_BLK_CNT 0x8e /* write - * 01 - reset the demod + * 01 - init * 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) + * 08 - transfer switch */ -#define RESET_DEMOD 0x01 -#define SET_FREQUENCY 0x02 +#define SET_INIT 0x01 +#define SET_RF_FREQ 0x02 #define SET_BANDWIDTH 0x03 #define SET_PID_FILTER 0x04 #define RESET_PID_FILTER 0x05 -#define SET_TS_CTRL 0x08 +#define SET_STREAMING 0x08 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 75f4cb18a635..794d513a8480 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -72,6 +72,8 @@ #define USB_PID_HANFTEK_UMT_010_WARM 0x0015 #define USB_PID_DTT200U_COLD 0x0201 #define USB_PID_DTT200U_WARM 0x0301 +#define USB_PID_WT220U_COLD 0x0222 +#define USB_PID_WT220U_WARM 0x0221 #define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_NEBULA_DIGITV 0x0201 @@ -84,5 +86,4 @@ #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f - #endif -- cgit v1.2.2 From 0d723c09f03e0b2cb4405c361c927efac373fe0c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:42 -0700 Subject: [PATCH] v4l: add DVB support for DViCO FusionHDTV3 Gold-T - Correct sync byte for MPEG-2 transport stream packets. - Add lgdt3302 as dependency of cx88-dvb in Kconfig. - Add dvb support in v4l for DViCO FusionHDTV3 Gold-T using lgdt3302 frontend. This adds support for a different board from the previous (Gold-Q) patch. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 13 +++++++++++++ drivers/media/dvb/frontends/dvb-pll.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 71e06ec7925a..5afeaa9b43b4 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -106,6 +106,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { }; EXPORT_SYMBOL(dvb_pll_microtune_4042); +struct dvb_pll_desc dvb_pll_thomson_dtt7611 = { + .name = "Thomson dtt7611", + .min = 44000000, + .max = 958000000, + .count = 3, + .entries = { + { 157250000, 44000000, 62500, 0x8e, 0x39 }, + { 454000000, 44000000, 62500, 0x8e, 0x3a }, + { 999999999, 44000000, 62500, 0x8e, 0x3c }, + }, +}; +EXPORT_SYMBOL(dvb_pll_thomson_dtt7611); + struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 98312bfe59d0..cb794759d89e 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -25,6 +25,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; 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_microtune_4042; +extern struct dvb_pll_desc dvb_pll_thomson_dtt7611; extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; -- cgit v1.2.2 From 08d805258f69bff5ba8268a969f140ef1f105c71 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:43 -0700 Subject: [PATCH] v4l: LGDT3302 read status fix - Fix bug in lgdt3302_read_status to return correct FE_HAS_SIGNAL and FS_HAS_CARRIER status. - Removed #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10). Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 43 ++++++++++++++-------------------- 1 file changed, 18 insertions(+), 25 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index d0b91219cf6e..09c914256e49 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -1,5 +1,5 @@ /* - * $Id: lgdt3302.c,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $ * * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM * @@ -34,7 +34,6 @@ * */ -#include #include #include #include @@ -208,8 +207,6 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; @@ -301,9 +298,6 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, lgdt3302_SwReset(state); state->current_modulation = param->u.vsb.modulation; } -#else - printk("lgdt3302: %s: you need a newer kernel for this, sorry\n",__FUNCTION__); -#endif /* Change only if we are actually changing the channel */ if (state->current_frequency != param->frequency) { @@ -352,11 +346,28 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) * This is done in SwReset(); */ + /* AGC status register */ + i2c_selectreadbytes(state, AGC_STATUS, buf, 1); + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0x0c) == 0x8){ + /* Test signal does not exist flag */ + /* as well as the AGC lock flag. */ + *status |= FE_HAS_SIGNAL; + } else { + /* Without a signal all other status bits are meaningless */ + return 0; + } + /* signal status */ i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); + +#if 0 + /* Alternative method to check for a signal */ + /* using the SNR good/bad interrupts. */ if ((buf[2] & 0x30) == 0x10) *status |= FE_HAS_SIGNAL; +#endif /* sync status */ if ((buf[2] & 0x03) == 0x01) { @@ -369,17 +380,6 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) *status |= FE_HAS_VITERBI; } -#if 0 - /* Alternative method to check for a signal */ - /* AGC status register */ - i2c_selectreadbytes(state, AGC_STATUS, buf, 1); - dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); - if ((buf[0] & 0x0c) == 0x80) /* Test signal does not exist flag */ - /* Test AGC lock flag */ - *status |= FE_HAS_SIGNAL; - else - return 0; - /* Carrier Recovery Lock Status Register */ i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); @@ -389,21 +389,14 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) /* Need to undestand why there are 3 lock levels here */ if ((buf[0] & 0x07) == 0x07) *status |= FE_HAS_CARRIER; - else - return 0; break; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) case VSB_8: if ((buf[0] & 0x80) == 0x80) *status |= FE_HAS_CARRIER; - else - return 0; break; -#endif default: printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__); } -#endif return 0; } -- cgit v1.2.2 From 58ba006be9b5a8f14f32c530d19fcd4e633aadf8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 12 Jul 2005 13:58:37 -0700 Subject: [PATCH] dvb: LGDT3302 QAM256 initialization fix - Initialize all non mutually exclusive variables without regard to the mode selected. - Do a software reset each time the parameters are set, regardless of whether anything changes. This may allow an application to recover from a hung condition. - Improved error reporting. - Removed $Id:$ Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 64 ++++++++++++++++------------------ 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index 09c914256e49..2eea03d218cd 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -1,6 +1,4 @@ /* - * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $ - * * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM * * Copyright (C) 2005 Wilson Michaels @@ -83,7 +81,10 @@ static int i2c_writebytes (struct lgdt3302_state* state, if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - return -EREMOTEIO; + if (err < 0) + return err; + else + return -EREMOTEIO; } } else { u8 tmp[] = { buf[0], buf[1] }; @@ -96,7 +97,10 @@ static int i2c_writebytes (struct lgdt3302_state* state, tmp[1] = buf[i]; if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - return -EREMOTEIO; + if (err < 0) + return err; + else + return -EREMOTEIO; } tmp[0]++; } @@ -218,6 +222,8 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Change only if we are actually changing the modulation */ if (state->current_modulation != param->u.vsb.modulation) { + int value; + switch(param->u.vsb.modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __FUNCTION__); @@ -266,36 +272,29 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, i2c_writebytes(state, state->config->demod_address, demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); - if (param->u.vsb.modulation == VSB_8) { - /* Initialization for VSB modes only */ - /* Change the value of NCOCTFV[25:0]of carrier - recovery center frequency register for VSB */ - i2c_writebytes(state, state->config->demod_address, + /* Change the value of NCOCTFV[25:0] of carrier + recovery center frequency register */ + i2c_writebytes(state, state->config->demod_address, vsb_freq_cfg, sizeof(vsb_freq_cfg)); - } else { - /* Initialization for QAM modes only */ - /* Set the value of 'INLVTHD' register 0x2a/0x2c - to value from 'IFACC' register 0x39/0x3b -1 */ - int value; - i2c_selectreadbytes(state, AGC_RFIF_ACC0, - &agc_delay_cfg[1], 3); - value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; - value = value -1; - dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); - agc_delay_cfg[1] = (value >> 8) & 0x0f; - agc_delay_cfg[2] = 0x00; - agc_delay_cfg[3] = value & 0xff; - i2c_writebytes(state, state->config->demod_address, - agc_delay_cfg, sizeof(agc_delay_cfg)); - - /* Change the value of IAGCBW[15:8] - of inner AGC loop filter bandwith */ - i2c_writebytes(state, state->config->demod_address, - agc_loop_cfg, sizeof(agc_loop_cfg)); - } + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to value from 'IFACC' register 0x39/0x3b -1 */ + i2c_selectreadbytes(state, AGC_RFIF_ACC0, + &agc_delay_cfg[1], 3); + value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; + value = value -1; + dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); + agc_delay_cfg[1] = (value >> 8) & 0x0f; + agc_delay_cfg[2] = 0x00; + agc_delay_cfg[3] = value & 0xff; + i2c_writebytes(state, state->config->demod_address, + agc_delay_cfg, sizeof(agc_delay_cfg)); + + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + i2c_writebytes(state, state->config->demod_address, + agc_loop_cfg, sizeof(agc_loop_cfg)); state->config->set_ts_params(fe, 0); - lgdt3302_SwReset(state); state->current_modulation = param->u.vsb.modulation; } @@ -311,11 +310,10 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, i2c_readbytes(state, state->config->pll_address, buf, 1); dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); - lgdt3302_SwReset(state); - /* Update current frequency */ state->current_frequency = param->frequency; } + lgdt3302_SwReset(state); return 0; } -- cgit v1.2.2 From 8df3d46077e63ab87f954eb6e827689cdfe97155 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 12 Jul 2005 13:58:38 -0700 Subject: [PATCH] dvb: usb: fix some typos corrected some typos. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 2 +- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 6 +++--- drivers/media/dvb/dvb-usb/vp7045.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index bdd72f779707..3491ff40885c 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -175,7 +175,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) 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); + err("strange '%s' doesn't want to attach a frontend.",d->desc->name); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index c3b3ae4f3ec7..65f0c095abc9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -51,17 +51,17 @@ static int dvb_usb_init(struct dvb_usb_device *d) /* 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)"); + err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware 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."); + info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count); 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."); + info("will pass the complete MPEG2 transport stream to the software demuxer."); d->pid_filtering = 0; d->max_feed_count = 255; } diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 5adc5d69ec84..9ac95f54f9fc 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -128,7 +128,7 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = { { 0x00, 0x0f, KEY_TEXT } /* Teletext */ }; -static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) +static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key; int i; @@ -144,7 +144,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) 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; + *event = vp7045_rc_keys[i].event; break; } return 0; -- cgit v1.2.2 From 27b05fd22f8a1f9afd0377817b1811cfc95f8b7b Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Tue, 12 Jul 2005 13:58:39 -0700 Subject: [PATCH] dvb: fix kobject names (no slashes) The / in the driver name (budget dvb /w video in) is not a valid character for device names - removed it, now it works! Same for ttusb-budget. Signed-off-by: Patrick Boettcher Signed-off-by: Julian Scheel Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index b65f4b0a481f..9746d2bb916f 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1022,7 +1022,7 @@ static struct pci_device_id pci_tbl[] = { MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { - .name = "budget dvb /w video in\0", + .name = "budget_av", .pci_tbl = pci_tbl, .module = THIS_MODULE, diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 2c17a5f58340..aa43b5fcb8e7 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1626,7 +1626,7 @@ static struct usb_device_id ttusb_table[] = { MODULE_DEVICE_TABLE(usb, ttusb_table); static struct usb_driver ttusb_driver = { - .name = "Technotrend/Hauppauge USB-Nova", + .name = "ttusb", .probe = ttusb_probe, .disconnect = ttusb_disconnect, .id_table = ttusb_table, -- cgit v1.2.2 From a6dfa37888298e8369f197883ae5f058fbd98a70 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Tue, 12 Jul 2005 13:58:40 -0700 Subject: [PATCH] dvb: dst: printk -> dprintk - stop log spamming when running femon (printk -> dprintk) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 9bd12832e3d9..07a0b0a968a6 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -928,7 +928,7 @@ static int dst_get_signal(struct dst_state* state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__); + dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; -- cgit v1.2.2 From 3952db66efee4f22f3c6a0fd02a1e7071556a8d6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 14 Jul 2005 00:33:33 -0700 Subject: [PATCH] dvb: LGDT3302 QAM lock bug fix Fix QAM lock bug. Previously, it was necessary to first scan in VSB before attempting to get a QAM lock. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index 2eea03d218cd..c85a2a99df42 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -217,13 +217,11 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb }; static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 }; static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 }; - static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x00, 0x00, 0x00 }; + static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x07, 0x00, 0xfe }; static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; /* Change only if we are actually changing the modulation */ if (state->current_modulation != param->u.vsb.modulation) { - int value; - switch(param->u.vsb.modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __FUNCTION__); @@ -276,16 +274,8 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, recovery center frequency register */ i2c_writebytes(state, state->config->demod_address, vsb_freq_cfg, sizeof(vsb_freq_cfg)); - /* Set the value of 'INLVTHD' register 0x2a/0x2c - to value from 'IFACC' register 0x39/0x3b -1 */ - i2c_selectreadbytes(state, AGC_RFIF_ACC0, - &agc_delay_cfg[1], 3); - value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; - value = value -1; - dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); - agc_delay_cfg[1] = (value >> 8) & 0x0f; - agc_delay_cfg[2] = 0x00; - agc_delay_cfg[3] = value & 0xff; + + /* Set the value of 'INLVTHD' register 0x2a/0x2c to 0x7fe */ i2c_writebytes(state, state->config->demod_address, agc_delay_cfg, sizeof(agc_delay_cfg)); -- cgit v1.2.2 From 9e00e48626474854bf712372fe6656ef4621af0f Mon Sep 17 00:00:00 2001 From: Gregory B Frost Date: Wed, 27 Jul 2005 11:45:48 -0700 Subject: [PATCH] DVICO Fusion DVB-T1 Tuner (LG-Z201) fix It is a small modification to the table that defines the way that the LG-Z201 tuner is controlled for the DVICO Fusion DVB-T1 tuner card. I believe that a mistake was made when the dvb tuner code was reorganised (to use a generic table for the tuner information instead of inline code) and as a result, the DVICO card doesn't tune properly. The modification I have made to the table makes it behave like it did with the old inline tuner code that worked. The patch is on top of the 2.6.12 kernel. Signed-off-by: Gregory B Frost Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 5afeaa9b43b4..5264310c070e 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -82,13 +82,14 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { .name = "LG z201", .min = 174000000, .max = 862000000, - .count = 5, + .count = 6, .entries = { { 0, 36166667, 166666, 0xbc, 0x03 }, - { 443250000, 36166667, 166666, 0xbc, 0x01 }, - { 542000000, 36166667, 166666, 0xbc, 0x02 }, - { 830000000, 36166667, 166666, 0xf4, 0x02 }, - { 999999999, 36166667, 166666, 0xfc, 0x02 }, + { 157500000, 36166667, 166666, 0xbc, 0x01 }, + { 443250000, 36166667, 166666, 0xbc, 0x02 }, + { 542000000, 36166667, 166666, 0xbc, 0x04 }, + { 830000000, 36166667, 166666, 0xf4, 0x04 }, + { 999999999, 36166667, 166666, 0xfc, 0x04 }, }, }; EXPORT_SYMBOL(dvb_pll_lg_z201); -- cgit v1.2.2 From b6aef071bdef0cd9f69113bb3575aa45fafdbbbf Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 27 Jul 2005 11:45:54 -0700 Subject: [PATCH] dvb/v4l: lgdt3302: isolate tuner Remove the dvb_pll_desc from the frontend and replace with a pll_set-callback to isolate the tuner programming from the frontend. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 68 ++++++++++++++++------------------ drivers/media/dvb/frontends/lgdt3302.h | 7 ++-- 2 files changed, 34 insertions(+), 41 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index c85a2a99df42..136563606fb1 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -74,11 +74,14 @@ static int i2c_writebytes (struct lgdt3302_state* state, u8 *buf, /* data bytes to send */ int len /* number of bytes to send */ ) { - if (addr == state->config->pll_address) { - struct i2c_msg msg = - { .addr = addr, .flags = 0, .buf = buf, .len = len }; - int err; + u8 tmp[] = { buf[0], buf[1] }; + struct i2c_msg msg = + { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; + int err; + int i; + for (i=1; ii2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); if (err < 0) @@ -86,27 +89,11 @@ static int i2c_writebytes (struct lgdt3302_state* state, else return -EREMOTEIO; } - } else { - u8 tmp[] = { buf[0], buf[1] }; - struct i2c_msg msg = - { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; - int err; - int i; - - for (i=1; ii2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - tmp[0]++; - } + tmp[0]++; } return 0; } + static int i2c_readbytes (struct lgdt3302_state* state, u8 addr, /* demod_address or pll_address */ u8 *buf, /* holds data bytes read */ @@ -207,7 +194,6 @@ static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int lgdt3302_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { - u8 buf[4]; struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; @@ -290,16 +276,30 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Change only if we are actually changing the channel */ if (state->current_frequency != param->frequency) { - dvb_pll_configure(state->config->pll_desc, buf, - param->frequency, 0); - dprintk("%s: tuner bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]); - i2c_writebytes(state, state->config->pll_address ,buf, 4); + u8 buf[5]; - /* Check the status of the tuner pll */ - i2c_readbytes(state, state->config->pll_address, buf, 1); - dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); + /* This must be done before the initialized msg is declared */ + state->config->pll_set(fe, param, buf); + + struct i2c_msg msg = + { .addr = buf[0], .flags = 0, .buf = &buf[1], .len = 4 }; + int err; + dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n", __FUNCTION__, + buf[0],buf[1],buf[2],buf[3],buf[4]); + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } +#if 0 + /* Check the status of the tuner pll */ + i2c_readbytes(state, buf[0], &buf[1], 1); + dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[1]); +#endif /* Update current frequency */ state->current_frequency = param->frequency; } @@ -322,12 +322,6 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) *status = 0; /* Reset status result */ - /* Check the status of the tuner pll */ - i2c_readbytes(state, state->config->pll_address, buf, 1); - dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); - if ((buf[0] & 0xc0) != 0x40) - return 0; /* Tuner PLL not locked or not powered on */ - /* * You must set the Mask bits to 1 in the IRQ_MASK in order * to see that status bit in the IRQ_STATUS register. diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h index 81587a40032b..327c47e598a2 100644 --- a/drivers/media/dvb/frontends/lgdt3302.h +++ b/drivers/media/dvb/frontends/lgdt3302.h @@ -1,6 +1,4 @@ /* - * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ - * * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM * * Copyright (C) 2005 Wilson Michaels @@ -30,8 +28,9 @@ struct lgdt3302_config { /* The demodulator's i2c address */ u8 demod_address; - u8 pll_address; - struct dvb_pll_desc *pll_desc; + + /* PLL interface */ + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pll_address); /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); -- cgit v1.2.2 From 0ccef6dbb08770bf21ffc82094c2117bd7977ff8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 27 Jul 2005 11:45:55 -0700 Subject: [PATCH] dvb/4vl: RF input selection fir Select the RF input connector based upon the type of demodulation selected. ANT RF connector is selected for 8-VSB and CABLE RF connector is selected for QAM64/QAM256. This only affects the cards that use the Microtune 4042 tuner. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 12 ++++++++++++ drivers/media/dvb/frontends/lgdt3302.h | 1 + 2 files changed, 13 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index 136563606fb1..c803c05002ad 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -214,6 +214,10 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Select VSB mode and serial MPEG interface */ top_ctrl_cfg[1] = 0x07; + + /* Select ANT connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 1); break; case QAM_64: @@ -221,6 +225,10 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Select QAM_64 mode and serial MPEG interface */ top_ctrl_cfg[1] = 0x04; + + /* Select CABLE connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 0); break; case QAM_256: @@ -228,6 +236,10 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Select QAM_256 mode and serial MPEG interface */ top_ctrl_cfg[1] = 0x05; + + /* Select CABLE connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 0); break; default: printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h index 327c47e598a2..6bf6f985e080 100644 --- a/drivers/media/dvb/frontends/lgdt3302.h +++ b/drivers/media/dvb/frontends/lgdt3302.h @@ -30,6 +30,7 @@ struct lgdt3302_config u8 demod_address; /* PLL interface */ + int (*pll_rf_set) (struct dvb_frontend* fe, int index); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pll_address); /* Need to set device param for start_dma */ -- cgit v1.2.2 From 723d52e6a6391e8c4954dca0a7efd3645181981f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 27 Jul 2005 11:45:56 -0700 Subject: [PATCH] lgdt3302: warning fix warning: `i2c_readbytes' defined but not used This code will either be re-enabled or deleted in a future patch. Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index c803c05002ad..c3b8d4e080bb 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -94,6 +94,7 @@ static int i2c_writebytes (struct lgdt3302_state* state, return 0; } +#if 0 static int i2c_readbytes (struct lgdt3302_state* state, u8 addr, /* demod_address or pll_address */ u8 *buf, /* holds data bytes read */ @@ -109,6 +110,7 @@ static int i2c_readbytes (struct lgdt3302_state* state, } return 0; } +#endif /* * This routine writes the register (reg) to the demod bus -- cgit v1.2.2 From 6ddcc9197beef7cba993c38cdcad45aefb557d33 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 27 Jul 2005 11:46:00 -0700 Subject: [PATCH] dvb: rename lgdt3302 frontend module to lgdt330x Rename lgdt3302 to lgdt330x, to make way for the addition of lgdt3303 support in future revisions. I am changing the name of this module now so that hopefully the name will be changed before the release of 2.6.13 ... It wouldn't make sense to release 2.6.13 with the name lgdt3302 in it, which will only be renamed to lgdt330x in later versions. Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 4 +- drivers/media/dvb/frontends/Makefile | 2 +- drivers/media/dvb/frontends/lgdt3302.c | 607 ---------------------------- drivers/media/dvb/frontends/lgdt3302.h | 49 --- drivers/media/dvb/frontends/lgdt3302_priv.h | 72 ---- drivers/media/dvb/frontends/lgdt330x.c | 606 +++++++++++++++++++++++++++ drivers/media/dvb/frontends/lgdt330x.h | 49 +++ drivers/media/dvb/frontends/lgdt330x_priv.h | 70 ++++ 8 files changed, 728 insertions(+), 731 deletions(-) delete mode 100644 drivers/media/dvb/frontends/lgdt3302.c delete mode 100644 drivers/media/dvb/frontends/lgdt3302.h delete mode 100644 drivers/media/dvb/frontends/lgdt3302_priv.h create mode 100644 drivers/media/dvb/frontends/lgdt330x.c create mode 100644 drivers/media/dvb/frontends/lgdt330x.h create mode 100644 drivers/media/dvb/frontends/lgdt330x_priv.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index d847c62bd837..e83256d0fd14 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -187,8 +187,8 @@ config DVB_BCM3510 An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. -config DVB_LGDT3302 - tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)" +config DVB_LGDT330X + tristate "LGDT3302 or LGDT3303 based (DViCO FusionHDTV Gold)" depends on DVB_CORE help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index de5e240cba7f..ad8658ffd60a 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -30,4 +30,4 @@ obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o -obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o +obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c deleted file mode 100644 index c3b8d4e080bb..000000000000 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM - * - * Copyright (C) 2005 Wilson Michaels - * - * Based on code from Kirk Lapray - * Copyright (C) 2005 - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* - * NOTES ABOUT THIS DRIVER - * - * This driver supports DViCO FusionHDTV 3 Gold under Linux. - * - * TODO: - * BER and signal strength always return 0. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvb-pll.h" -#include "lgdt3302_priv.h" -#include "lgdt3302.h" - -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off)."); -#define dprintk(args...) \ -do { \ -if (debug) printk(KERN_DEBUG "lgdt3302: " args); \ -} while (0) - -struct lgdt3302_state -{ - struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - - /* Configuration settings */ - const struct lgdt3302_config* config; - - struct dvb_frontend frontend; - - /* Demodulator private data */ - fe_modulation_t current_modulation; - - /* Tuner private data */ - u32 current_frequency; -}; - -static int i2c_writebytes (struct lgdt3302_state* state, - u8 addr, /* demod_address or pll_address */ - u8 *buf, /* data bytes to send */ - int len /* number of bytes to send */ ) -{ - u8 tmp[] = { buf[0], buf[1] }; - struct i2c_msg msg = - { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; - int err; - int i; - - for (i=1; ii2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - tmp[0]++; - } - return 0; -} - -#if 0 -static int i2c_readbytes (struct lgdt3302_state* state, - u8 addr, /* demod_address or pll_address */ - u8 *buf, /* holds data bytes read */ - int len /* number of bytes to read */ ) -{ - struct i2c_msg msg = - { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; - int err; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); - return -EREMOTEIO; - } - return 0; -} -#endif - -/* - * This routine writes the register (reg) to the demod bus - * then reads the data returned for (len) bytes. - */ - -static u8 i2c_selectreadbytes (struct lgdt3302_state* state, - enum I2C_REG reg, u8* buf, int len) -{ - u8 wr [] = { reg }; - struct i2c_msg msg [] = { - { .addr = state->config->demod_address, - .flags = 0, .buf = wr, .len = 1 }, - { .addr = state->config->demod_address, - .flags = I2C_M_RD, .buf = buf, .len = len }, - }; - int ret; - ret = i2c_transfer(state->i2c, msg, 2); - if (ret != 2) { - printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret); - } else { - ret = 0; - } - return ret; -} - -/* Software reset */ -int lgdt3302_SwReset(struct lgdt3302_state* state) -{ - u8 ret; - u8 reset[] = { - IRQ_MASK, - 0x00 /* bit 6 is active low software reset - * bits 5-0 are 1 to mask interrupts */ - }; - - ret = i2c_writebytes(state, - state->config->demod_address, - reset, sizeof(reset)); - if (ret == 0) { - /* spec says reset takes 100 ns why wait */ - /* mdelay(100); */ /* keep low for 100mS */ - reset[1] = 0x7f; /* force reset high (inactive) - * and unmask interrupts */ - ret = i2c_writebytes(state, - state->config->demod_address, - reset, sizeof(reset)); - } - /* Spec does not indicate a need for this either */ - /*mdelay(5); */ /* wait 5 msec before doing more */ - return ret; -} - -static int lgdt3302_init(struct dvb_frontend* fe) -{ - /* Hardware reset is done using gpio[0] of cx23880x chip. - * I'd like to do it here, but don't know how to find chip address. - * cx88-cards.c arranges for the reset bit to be inactive (high). - * Maybe there needs to be a callable function in cx88-core or - * the caller of this function needs to do it. */ - - dprintk("%s entered\n", __FUNCTION__); - return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv); -} - -static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber) -{ - *ber = 0; /* Dummy out for now */ - return 0; -} - -static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; - u8 buf[2]; - - i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf)); - - *ucblocks = (buf[0] << 8) | buf[1]; - return 0; -} - -static int lgdt3302_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) -{ - struct lgdt3302_state* state = - (struct lgdt3302_state*) fe->demodulator_priv; - - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ - static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; - static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; - static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb }; - static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 }; - static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 }; - static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x07, 0x00, 0xfe }; - static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; - - /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - switch(param->u.vsb.modulation) { - case VSB_8: - dprintk("%s: VSB_8 MODE\n", __FUNCTION__); - - /* Select VSB mode and serial MPEG interface */ - top_ctrl_cfg[1] = 0x07; - - /* Select ANT connector if supported by card */ - if (state->config->pll_rf_set) - state->config->pll_rf_set(fe, 1); - break; - - case QAM_64: - dprintk("%s: QAM_64 MODE\n", __FUNCTION__); - - /* Select QAM_64 mode and serial MPEG interface */ - top_ctrl_cfg[1] = 0x04; - - /* Select CABLE connector if supported by card */ - if (state->config->pll_rf_set) - state->config->pll_rf_set(fe, 0); - break; - - case QAM_256: - dprintk("%s: QAM_256 MODE\n", __FUNCTION__); - - /* Select QAM_256 mode and serial MPEG interface */ - top_ctrl_cfg[1] = 0x05; - - /* Select CABLE connector if supported by card */ - if (state->config->pll_rf_set) - state->config->pll_rf_set(fe, 0); - break; - default: - printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); - return -1; - } - /* Initializations common to all modes */ - - /* Select the requested mode */ - i2c_writebytes(state, state->config->demod_address, - top_ctrl_cfg, sizeof(top_ctrl_cfg)); - - /* Change the value of IFBW[11:0] - of AGC IF/RF loop filter bandwidth register */ - i2c_writebytes(state, state->config->demod_address, - agc_rf_cfg, sizeof(agc_rf_cfg)); - - /* Change the value of bit 6, 'nINAGCBY' and - 'NSSEL[1:0] of ACG function control register 2 */ - /* Change the value of bit 6 'RFFIX' - of AGC function control register 3 */ - i2c_writebytes(state, state->config->demod_address, - agc_ctrl_cfg, sizeof(agc_ctrl_cfg)); - - /* Change the TPCLK pin polarity - data is valid on falling clock */ - i2c_writebytes(state, state->config->demod_address, - demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); - - /* Change the value of NCOCTFV[25:0] of carrier - recovery center frequency register */ - i2c_writebytes(state, state->config->demod_address, - vsb_freq_cfg, sizeof(vsb_freq_cfg)); - - /* Set the value of 'INLVTHD' register 0x2a/0x2c to 0x7fe */ - i2c_writebytes(state, state->config->demod_address, - agc_delay_cfg, sizeof(agc_delay_cfg)); - - /* Change the value of IAGCBW[15:8] - of inner AGC loop filter bandwith */ - i2c_writebytes(state, state->config->demod_address, - agc_loop_cfg, sizeof(agc_loop_cfg)); - - state->config->set_ts_params(fe, 0); - state->current_modulation = param->u.vsb.modulation; - } - - /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { - u8 buf[5]; - - /* This must be done before the initialized msg is declared */ - state->config->pll_set(fe, param, buf); - - struct i2c_msg msg = - { .addr = buf[0], .flags = 0, .buf = &buf[1], .len = 4 }; - int err; - - dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n", __FUNCTION__, - buf[0],buf[1],buf[2],buf[3],buf[4]); - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } -#if 0 - /* Check the status of the tuner pll */ - i2c_readbytes(state, buf[0], &buf[1], 1); - dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[1]); -#endif - /* Update current frequency */ - state->current_frequency = param->frequency; - } - lgdt3302_SwReset(state); - return 0; -} - -static int lgdt3302_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* param) -{ - struct lgdt3302_state *state = fe->demodulator_priv; - param->frequency = state->current_frequency; - return 0; -} - -static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; - u8 buf[3]; - - *status = 0; /* Reset status result */ - - /* - * You must set the Mask bits to 1 in the IRQ_MASK in order - * to see that status bit in the IRQ_STATUS register. - * This is done in SwReset(); - */ - - /* AGC status register */ - i2c_selectreadbytes(state, AGC_STATUS, buf, 1); - dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); - if ((buf[0] & 0x0c) == 0x8){ - /* Test signal does not exist flag */ - /* as well as the AGC lock flag. */ - *status |= FE_HAS_SIGNAL; - } else { - /* Without a signal all other status bits are meaningless */ - return 0; - } - - /* signal status */ - i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); - dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); - -#if 0 - /* Alternative method to check for a signal */ - /* using the SNR good/bad interrupts. */ - if ((buf[2] & 0x30) == 0x10) - *status |= FE_HAS_SIGNAL; -#endif - - /* sync status */ - if ((buf[2] & 0x03) == 0x01) { - *status |= FE_HAS_SYNC; - } - - /* FEC error status */ - if ((buf[2] & 0x0c) == 0x08) { - *status |= FE_HAS_LOCK; - *status |= FE_HAS_VITERBI; - } - - /* Carrier Recovery Lock Status Register */ - i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); - dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); - switch (state->current_modulation) { - case QAM_256: - case QAM_64: - /* Need to undestand why there are 3 lock levels here */ - if ((buf[0] & 0x07) == 0x07) - *status |= FE_HAS_CARRIER; - break; - case VSB_8: - if ((buf[0] & 0x80) == 0x80) - *status |= FE_HAS_CARRIER; - break; - default: - printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__); - } - - return 0; -} - -static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - /* not directly available. */ - return 0; -} - -static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) -{ -#ifdef SNR_IN_DB - /* - * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise) - * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker - * respectively. The following tables are built on these formulas. - * The usual definition is SNR = 20 log10(signal/noise) - * If the specification is wrong the value retuned is 1/2 the actual SNR in db. - * - * This table is a an ordered list of noise values computed by the - * formula from the spec sheet such that the index into the table - * starting at 43 or 45 is the SNR value in db. There are duplicate noise - * value entries at the beginning because the SNR varies more than - * 1 db for a change of 1 digit in noise at very small values of noise. - * - * Examples from SNR_EQ table: - * noise SNR - * 0 43 - * 1 42 - * 2 39 - * 3 37 - * 4 36 - * 5 35 - * 6 34 - * 7 33 - * 8 33 - * 9 32 - * 10 32 - * 11 31 - * 12 31 - * 13 30 - */ - - static const u32 SNR_EQ[] = - { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, - 9, 11, 13, 17, 21, 26, 33, 41, 52, 65, - 81, 102, 129, 162, 204, 257, 323, 406, 511, 644, - 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433, - 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323, - 80978, 101945, 128341, 161571, 203406, 256073, 0x40000 - }; - - static const u32 SNR_PH[] = - { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8, - 10, 12, 15, 19, 23, 29, 37, 46, 58, 73, - 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, - 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, - 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, - 90833, 114351, 143960, 181235, 228161, 0x040000 - }; - - static u8 buf[5];/* read data buffer */ - static u32 noise; /* noise value */ - static u32 snr_db; /* index into SNR_EQ[] */ - struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; - - /* read both equalizer and pase tracker noise data */ - i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); - - if (state->current_modulation == VSB_8) { - /* Equalizer Mean-Square Error Register for VSB */ - noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; - - /* - * Look up noise value in table. - * A better search algorithm could be used... - * watch out there are duplicate entries. - */ - for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) { - if (noise < SNR_EQ[snr_db]) { - *snr = 43 - snr_db; - break; - } - } - } else { - /* Phase Tracker Mean-Square Error Register for QAM */ - noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; - - /* Look up noise value in table. */ - for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) { - if (noise < SNR_PH[snr_db]) { - *snr = 45 - snr_db; - break; - } - } - } -#else - /* Return the raw noise value */ - static u8 buf[5];/* read data buffer */ - static u32 noise; /* noise value */ - struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; - - /* read both equalizer and pase tracker noise data */ - i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); - - if (state->current_modulation == VSB_8) { - /* Equalizer Mean-Square Error Register for VSB */ - noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; - } else { - /* Phase Tracker Mean-Square Error Register for QAM */ - noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; - } - - /* Small values for noise mean signal is better so invert noise */ - /* Noise is 19 bit value so discard 3 LSB*/ - *snr = ~noise>>3; -#endif - - dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); - - return 0; -} - -static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) -{ - /* I have no idea about this - it may not be needed */ - fe_tune_settings->min_delay_ms = 500; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - return 0; -} - -static void lgdt3302_release(struct dvb_frontend* fe) -{ - struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops lgdt3302_ops; - -struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config, - struct i2c_adapter* i2c) -{ - struct lgdt3302_state* state = NULL; - u8 buf[1]; - - /* Allocate memory for the internal state */ - state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL); - if (state == NULL) - goto error; - memset(state,0,sizeof(*state)); - - /* Setup the state */ - state->config = config; - state->i2c = i2c; - memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); - /* Verify communication with demod chip */ - if (i2c_selectreadbytes(state, 2, buf, 1)) - goto error; - - state->current_frequency = -1; - state->current_modulation = -1; - - /* Create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - if (state) - kfree(state); - dprintk("%s: ERROR\n",__FUNCTION__); - return NULL; -} - -static struct dvb_frontend_ops lgdt3302_ops = { - .info = { - .name= "LG Electronics LGDT3302 VSB/QAM Frontend", - .type = FE_ATSC, - .frequency_min= 54000000, - .frequency_max= 858000000, - .frequency_stepsize= 62500, - /* Symbol rate is for all VSB modes need to check QAM */ - .symbol_rate_min = 10762000, - .symbol_rate_max = 10762000, - .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB - }, - .init = lgdt3302_init, - .set_frontend = lgdt3302_set_parameters, - .get_frontend = lgdt3302_get_frontend, - .get_tune_settings = lgdt3302_get_tune_settings, - .read_status = lgdt3302_read_status, - .read_ber = lgdt3302_read_ber, - .read_signal_strength = lgdt3302_read_signal_strength, - .read_snr = lgdt3302_read_snr, - .read_ucblocks = lgdt3302_read_ucblocks, - .release = lgdt3302_release, -}; - -MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); -MODULE_AUTHOR("Wilson Michaels"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(lgdt3302_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * compile-command: "make DVB=1" - * End: - */ diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h deleted file mode 100644 index 6bf6f985e080..000000000000 --- a/drivers/media/dvb/frontends/lgdt3302.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM - * - * Copyright (C) 2005 Wilson Michaels - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef LGDT3302_H -#define LGDT3302_H - -#include - -struct lgdt3302_config -{ - /* The demodulator's i2c address */ - u8 demod_address; - - /* PLL interface */ - int (*pll_rf_set) (struct dvb_frontend* fe, int index); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pll_address); - - /* Need to set device param for start_dma */ - int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); -}; - -extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config, - struct i2c_adapter* i2c); - -#endif /* LGDT3302_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h deleted file mode 100644 index 6193fa7a569d..000000000000 --- a/drivers/media/dvb/frontends/lgdt3302_priv.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ - * - * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM - * - * Copyright (C) 2005 Wilson Michaels - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _LGDT3302_PRIV_ -#define _LGDT3302_PRIV_ - -/* i2c control register addresses */ -enum I2C_REG { - TOP_CONTROL= 0x00, - IRQ_MASK= 0x01, - IRQ_STATUS= 0x02, - VSB_CARRIER_FREQ0= 0x16, - VSB_CARRIER_FREQ1= 0x17, - VSB_CARRIER_FREQ2= 0x18, - VSB_CARRIER_FREQ3= 0x19, - CARRIER_MSEQAM1= 0x1a, - CARRIER_MSEQAM2= 0x1b, - CARRIER_LOCK= 0x1c, - TIMING_RECOVERY= 0x1d, - AGC_DELAY0= 0x2a, - AGC_DELAY1= 0x2b, - AGC_DELAY2= 0x2c, - AGC_RF_BANDWIDTH0= 0x2d, - AGC_RF_BANDWIDTH1= 0x2e, - AGC_RF_BANDWIDTH2= 0x2f, - AGC_LOOP_BANDWIDTH0= 0x30, - AGC_LOOP_BANDWIDTH1= 0x31, - AGC_FUNC_CTRL1= 0x32, - AGC_FUNC_CTRL2= 0x33, - AGC_FUNC_CTRL3= 0x34, - AGC_RFIF_ACC0= 0x39, - AGC_RFIF_ACC1= 0x3a, - AGC_RFIF_ACC2= 0x3b, - AGC_STATUS= 0x3f, - SYNC_STATUS_VSB= 0x43, - EQPH_ERR0= 0x47, - EQ_ERR1= 0x48, - EQ_ERR2= 0x49, - PH_ERR1= 0x4a, - PH_ERR2= 0x4b, - DEMUX_CONTROL= 0x66, - PACKET_ERR_COUNTER1= 0x6a, - PACKET_ERR_COUNTER2= 0x6b, -}; - -#endif /* _LGDT3302_PRIV_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c new file mode 100644 index 000000000000..e94dee50eecd --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -0,0 +1,606 @@ +/* + * Support for LGDT3302 & LGDT3303 (DViCO FusionHDTV Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * Based on code from Kirk Lapray + * Copyright (C) 2005 + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * NOTES ABOUT THIS DRIVER + * + * This driver supports DViCO FusionHDTV Gold under Linux. + * + * TODO: + * BER and signal strength always return 0. + * Include support for LGDT3303 + * + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "lgdt330x_priv.h" +#include "lgdt330x.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off)."); +#define dprintk(args...) \ +do { \ +if (debug) printk(KERN_DEBUG "lgdt330x: " args); \ +} while (0) + +struct lgdt330x_state +{ + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + + /* Configuration settings */ + const struct lgdt330x_config* config; + + struct dvb_frontend frontend; + + /* Demodulator private data */ + fe_modulation_t current_modulation; + + /* Tuner private data */ + u32 current_frequency; +}; + +static int i2c_writebytes (struct lgdt330x_state* state, + u8 addr, /* demod_address or pll_address */ + u8 *buf, /* data bytes to send */ + int len /* number of bytes to send */ ) +{ + u8 tmp[] = { buf[0], buf[1] }; + struct i2c_msg msg = + { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; + int err; + int i; + + for (i=1; ii2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + tmp[0]++; + } + return 0; +} + +#if 0 +static int i2c_readbytes (struct lgdt330x_state* state, + u8 addr, /* demod_address or pll_address */ + u8 *buf, /* holds data bytes read */ + int len /* number of bytes to read */ ) +{ + struct i2c_msg msg = + { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt330x: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); + return -EREMOTEIO; + } + return 0; +} +#endif + +/* + * This routine writes the register (reg) to the demod bus + * then reads the data returned for (len) bytes. + */ + +static u8 i2c_selectreadbytes (struct lgdt330x_state* state, + enum I2C_REG reg, u8* buf, int len) +{ + u8 wr [] = { reg }; + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, + .flags = 0, .buf = wr, .len = 1 }, + { .addr = state->config->demod_address, + .flags = I2C_M_RD, .buf = buf, .len = len }, + }; + int ret; + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret); + } else { + ret = 0; + } + return ret; +} + +/* Software reset */ +int lgdt330x_SwReset(struct lgdt330x_state* state) +{ + u8 ret; + u8 reset[] = { + IRQ_MASK, + 0x00 /* bit 6 is active low software reset + * bits 5-0 are 1 to mask interrupts */ + }; + + ret = i2c_writebytes(state, + state->config->demod_address, + reset, sizeof(reset)); + if (ret == 0) { + /* spec says reset takes 100 ns why wait */ + /* mdelay(100); */ /* keep low for 100mS */ + reset[1] = 0x7f; /* force reset high (inactive) + * and unmask interrupts */ + ret = i2c_writebytes(state, + state->config->demod_address, + reset, sizeof(reset)); + } + /* Spec does not indicate a need for this either */ + /*mdelay(5); */ /* wait 5 msec before doing more */ + return ret; +} + +static int lgdt330x_init(struct dvb_frontend* fe) +{ + /* Hardware reset is done using gpio[0] of cx23880x chip. + * I'd like to do it here, but don't know how to find chip address. + * cx88-cards.c arranges for the reset bit to be inactive (high). + * Maybe there needs to be a callable function in cx88-core or + * the caller of this function needs to do it. */ + + dprintk("%s entered\n", __FUNCTION__); + return lgdt330x_SwReset((struct lgdt330x_state*) fe->demodulator_priv); +} + +static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; /* Dummy out for now */ + return 0; +} + +static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + u8 buf[2]; + + i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf)); + + *ucblocks = (buf[0] << 8) | buf[1]; + return 0; +} + +static int lgdt330x_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + struct lgdt330x_state* state = + (struct lgdt330x_state*) fe->demodulator_priv; + + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ + static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; + static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; + static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb }; + static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 }; + static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 }; + static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x07, 0x00, 0xfe }; + static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; + + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + dprintk("%s: VSB_8 MODE\n", __FUNCTION__); + + /* Select VSB mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x07; + + /* Select ANT connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 1); + break; + + case QAM_64: + dprintk("%s: QAM_64 MODE\n", __FUNCTION__); + + /* Select QAM_64 mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x04; + + /* Select CABLE connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 0); + break; + + case QAM_256: + dprintk("%s: QAM_256 MODE\n", __FUNCTION__); + + /* Select QAM_256 mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x05; + + /* Select CABLE connector if supported by card */ + if (state->config->pll_rf_set) + state->config->pll_rf_set(fe, 0); + break; + default: + printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); + return -1; + } + /* Initializations common to all modes */ + + /* Select the requested mode */ + i2c_writebytes(state, state->config->demod_address, + top_ctrl_cfg, sizeof(top_ctrl_cfg)); + + /* Change the value of IFBW[11:0] + of AGC IF/RF loop filter bandwidth register */ + i2c_writebytes(state, state->config->demod_address, + agc_rf_cfg, sizeof(agc_rf_cfg)); + + /* Change the value of bit 6, 'nINAGCBY' and + 'NSSEL[1:0] of ACG function control register 2 */ + /* Change the value of bit 6 'RFFIX' + of AGC function control register 3 */ + i2c_writebytes(state, state->config->demod_address, + agc_ctrl_cfg, sizeof(agc_ctrl_cfg)); + + /* Change the TPCLK pin polarity + data is valid on falling clock */ + i2c_writebytes(state, state->config->demod_address, + demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); + + /* Change the value of NCOCTFV[25:0] of carrier + recovery center frequency register */ + i2c_writebytes(state, state->config->demod_address, + vsb_freq_cfg, sizeof(vsb_freq_cfg)); + + /* Set the value of 'INLVTHD' register 0x2a/0x2c to 0x7fe */ + i2c_writebytes(state, state->config->demod_address, + agc_delay_cfg, sizeof(agc_delay_cfg)); + + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + i2c_writebytes(state, state->config->demod_address, + agc_loop_cfg, sizeof(agc_loop_cfg)); + + state->config->set_ts_params(fe, 0); + state->current_modulation = param->u.vsb.modulation; + } + + /* Change only if we are actually changing the channel */ + if (state->current_frequency != param->frequency) { + u8 buf[5]; + struct i2c_msg msg = { .flags = 0, .buf = &buf[1], .len = 4 }; + int err; + + state->config->pll_set(fe, param, buf); + msg.addr = buf[0]; + + dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n", __FUNCTION__, + buf[0],buf[1],buf[2],buf[3],buf[4]); + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } +#if 0 + /* Check the status of the tuner pll */ + i2c_readbytes(state, buf[0], &buf[1], 1); + dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[1]); +#endif + /* Update current frequency */ + state->current_frequency = param->frequency; + } + lgdt330x_SwReset(state); + return 0; +} + +static int lgdt330x_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* param) +{ + struct lgdt330x_state *state = fe->demodulator_priv; + param->frequency = state->current_frequency; + return 0; +} + +static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + u8 buf[3]; + + *status = 0; /* Reset status result */ + + /* + * You must set the Mask bits to 1 in the IRQ_MASK in order + * to see that status bit in the IRQ_STATUS register. + * This is done in SwReset(); + */ + + /* AGC status register */ + i2c_selectreadbytes(state, AGC_STATUS, buf, 1); + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0x0c) == 0x8){ + /* Test signal does not exist flag */ + /* as well as the AGC lock flag. */ + *status |= FE_HAS_SIGNAL; + } else { + /* Without a signal all other status bits are meaningless */ + return 0; + } + + /* signal status */ + i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); + dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); + +#if 0 + /* Alternative method to check for a signal */ + /* using the SNR good/bad interrupts. */ + if ((buf[2] & 0x30) == 0x10) + *status |= FE_HAS_SIGNAL; +#endif + + /* sync status */ + if ((buf[2] & 0x03) == 0x01) { + *status |= FE_HAS_SYNC; + } + + /* FEC error status */ + if ((buf[2] & 0x0c) == 0x08) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + } + + /* Carrier Recovery Lock Status Register */ + i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* Need to undestand why there are 3 lock levels here */ + if ((buf[0] & 0x07) == 0x07) + *status |= FE_HAS_CARRIER; + break; + case VSB_8: + if ((buf[0] & 0x80) == 0x80) + *status |= FE_HAS_CARRIER; + break; + default: + printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); + } + + return 0; +} + +static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + /* not directly available. */ + return 0; +} + +static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) +{ +#ifdef SNR_IN_DB + /* + * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise) + * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker + * respectively. The following tables are built on these formulas. + * The usual definition is SNR = 20 log10(signal/noise) + * If the specification is wrong the value retuned is 1/2 the actual SNR in db. + * + * This table is a an ordered list of noise values computed by the + * formula from the spec sheet such that the index into the table + * starting at 43 or 45 is the SNR value in db. There are duplicate noise + * value entries at the beginning because the SNR varies more than + * 1 db for a change of 1 digit in noise at very small values of noise. + * + * Examples from SNR_EQ table: + * noise SNR + * 0 43 + * 1 42 + * 2 39 + * 3 37 + * 4 36 + * 5 35 + * 6 34 + * 7 33 + * 8 33 + * 9 32 + * 10 32 + * 11 31 + * 12 31 + * 13 30 + */ + + static const u32 SNR_EQ[] = + { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, + 9, 11, 13, 17, 21, 26, 33, 41, 52, 65, + 81, 102, 129, 162, 204, 257, 323, 406, 511, 644, + 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433, + 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323, + 80978, 101945, 128341, 161571, 203406, 256073, 0x40000 + }; + + static const u32 SNR_PH[] = + { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8, + 10, 12, 15, 19, 23, 29, 37, 46, 58, 73, + 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, + 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, + 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, + 90833, 114351, 143960, 181235, 228161, 0x040000 + }; + + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + static u32 snr_db; /* index into SNR_EQ[] */ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + + /* read both equalizer and pase tracker noise data */ + i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + + if (state->current_modulation == VSB_8) { + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + + /* + * Look up noise value in table. + * A better search algorithm could be used... + * watch out there are duplicate entries. + */ + for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) { + if (noise < SNR_EQ[snr_db]) { + *snr = 43 - snr_db; + break; + } + } + } else { + /* Phase Tracker Mean-Square Error Register for QAM */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + + /* Look up noise value in table. */ + for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) { + if (noise < SNR_PH[snr_db]) { + *snr = 45 - snr_db; + break; + } + } + } +#else + /* Return the raw noise value */ + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + + /* read both equalizer and pase tracker noise data */ + i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + + if (state->current_modulation == VSB_8) { + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + } else { + /* Phase Tracker Mean-Square Error Register for QAM */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + } + + /* Small values for noise mean signal is better so invert noise */ + /* Noise is 19 bit value so discard 3 LSB*/ + *snr = ~noise>>3; +#endif + + dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); + + return 0; +} + +static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + /* I have no idea about this - it may not be needed */ + fe_tune_settings->min_delay_ms = 500; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + return 0; +} + +static void lgdt330x_release(struct dvb_frontend* fe) +{ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops lgdt330x_ops; + +struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, + struct i2c_adapter* i2c) +{ + struct lgdt330x_state* state = NULL; + u8 buf[1]; + + /* Allocate memory for the internal state */ + state = (struct lgdt330x_state*) kmalloc(sizeof(struct lgdt330x_state), GFP_KERNEL); + if (state == NULL) + goto error; + memset(state,0,sizeof(*state)); + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &lgdt330x_ops, sizeof(struct dvb_frontend_ops)); + /* Verify communication with demod chip */ + if (i2c_selectreadbytes(state, 2, buf, 1)) + goto error; + + state->current_frequency = -1; + state->current_modulation = -1; + + /* Create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) + kfree(state); + dprintk("%s: ERROR\n",__FUNCTION__); + return NULL; +} + +static struct dvb_frontend_ops lgdt330x_ops = { + .info = { + .name= "LG Electronics lgdt330x VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + /* Symbol rate is for all VSB modes need to check QAM */ + .symbol_rate_min = 10762000, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt330x_init, + .set_frontend = lgdt330x_set_parameters, + .get_frontend = lgdt330x_get_frontend, + .get_tune_settings = lgdt330x_get_tune_settings, + .read_status = lgdt330x_read_status, + .read_ber = lgdt330x_read_ber, + .read_signal_strength = lgdt330x_read_signal_strength, + .read_snr = lgdt330x_read_snr, + .read_ucblocks = lgdt330x_read_ucblocks, + .release = lgdt330x_release, +}; + +MODULE_DESCRIPTION("lgdt330x [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_AUTHOR("Wilson Michaels"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(lgdt330x_attach); + +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h new file mode 100644 index 000000000000..04986f8e7565 --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt330x.h @@ -0,0 +1,49 @@ +/* + * Support for LGDT3302 & LGDT3303 (DViCO FustionHDTV Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LGDT330X_H +#define LGDT330X_H + +#include + +struct lgdt330x_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + + /* PLL interface */ + int (*pll_rf_set) (struct dvb_frontend* fe, int index); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pll_address); + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, + struct i2c_adapter* i2c); + +#endif /* LGDT330X_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/lgdt330x_priv.h b/drivers/media/dvb/frontends/lgdt330x_priv.h new file mode 100644 index 000000000000..4143ce8f1a95 --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt330x_priv.h @@ -0,0 +1,70 @@ +/* + * Support for LGDT3302 & LGDT3303 (DViCO FustionHDTV Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LGDT330X_PRIV_ +#define _LGDT330X_PRIV_ + +/* i2c control register addresses */ +enum I2C_REG { + TOP_CONTROL= 0x00, + IRQ_MASK= 0x01, + IRQ_STATUS= 0x02, + VSB_CARRIER_FREQ0= 0x16, + VSB_CARRIER_FREQ1= 0x17, + VSB_CARRIER_FREQ2= 0x18, + VSB_CARRIER_FREQ3= 0x19, + CARRIER_MSEQAM1= 0x1a, + CARRIER_MSEQAM2= 0x1b, + CARRIER_LOCK= 0x1c, + TIMING_RECOVERY= 0x1d, + AGC_DELAY0= 0x2a, + AGC_DELAY1= 0x2b, + AGC_DELAY2= 0x2c, + AGC_RF_BANDWIDTH0= 0x2d, + AGC_RF_BANDWIDTH1= 0x2e, + AGC_RF_BANDWIDTH2= 0x2f, + AGC_LOOP_BANDWIDTH0= 0x30, + AGC_LOOP_BANDWIDTH1= 0x31, + AGC_FUNC_CTRL1= 0x32, + AGC_FUNC_CTRL2= 0x33, + AGC_FUNC_CTRL3= 0x34, + AGC_RFIF_ACC0= 0x39, + AGC_RFIF_ACC1= 0x3a, + AGC_RFIF_ACC2= 0x3b, + AGC_STATUS= 0x3f, + SYNC_STATUS_VSB= 0x43, + EQPH_ERR0= 0x47, + EQ_ERR1= 0x48, + EQ_ERR2= 0x49, + PH_ERR1= 0x4a, + PH_ERR2= 0x4b, + DEMUX_CONTROL= 0x66, + PACKET_ERR_COUNTER1= 0x6a, + PACKET_ERR_COUNTER2= 0x6b, +}; + +#endif /* _LGDT330X_PRIV_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v1.2.2 From 1963c907b21e140082d081b1c8f8c2154593c7d7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 8 Aug 2005 09:22:43 -0700 Subject: [PATCH] dvb: lgdt330x frontend: some bug fixes & add lgdt3303 support - Structural changes within lgdt330x driver, framework now supports both chips... tested OK on lgdt3302 and lgdt3303. - Add LG/TUA6034 dvb_pll_desc for ATSC with LG TDVS-H062F & DViCO FusionHDTV5. - Fixed LGDT330X signal strength: For now, always set it to 0. - Corrected LGDT330X boundary condition error in read_snr: dB calculation. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 16 + drivers/media/dvb/frontends/dvb-pll.h | 1 + drivers/media/dvb/frontends/lgdt330x.c | 549 ++++++++++++++++++++-------- drivers/media/dvb/frontends/lgdt330x.h | 16 +- drivers/media/dvb/frontends/lgdt330x_priv.h | 8 +- 5 files changed, 423 insertions(+), 167 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 5264310c070e..536c35d969b7 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -225,6 +225,22 @@ struct dvb_pll_desc dvb_pll_tua6034 = { }; EXPORT_SYMBOL(dvb_pll_tua6034); +/* Infineon TUA6034 + * used in LG Innotek TDVS-H062F + */ +struct dvb_pll_desc dvb_pll_tdvs_tua6034 = { + .name = "LG/Infineon TUA6034", + .min = 54000000, + .max = 863000000, + .count = 3, + .entries = { + { 160000000, 44000000, 62500, 0xce, 0x01 }, + { 455000000, 44000000, 62500, 0xce, 0x02 }, + { 999999999, 44000000, 62500, 0xce, 0x04 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_tdvs_tua6034); + /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index cb794759d89e..205b2d1a8852 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -31,6 +31,7 @@ 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_tdvs_tua6034; extern struct dvb_pll_desc dvb_pll_tda665x; extern struct dvb_pll_desc dvb_pll_fmd1216me; extern struct dvb_pll_desc dvb_pll_tded4; diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index e94dee50eecd..c48e7c11d708 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -1,11 +1,8 @@ /* - * Support for LGDT3302 & LGDT3303 (DViCO FusionHDTV Gold) - VSB/QAM + * Support for LGDT3302 and LGDT3303 - VSB/QAM * * Copyright (C) 2005 Wilson Michaels * - * Based on code from Kirk Lapray - * Copyright (C) 2005 - * * 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; either version 2 of the License, or @@ -25,11 +22,13 @@ /* * NOTES ABOUT THIS DRIVER * - * This driver supports DViCO FusionHDTV Gold under Linux. + * This Linux driver supports: + * DViCO FusionHDTV 3 Gold-Q + * DViCO FusionHDTV 3 Gold-T + * DViCO FusionHDTV 5 Gold * * TODO: - * BER and signal strength always return 0. - * Include support for LGDT3303 + * signal strength always returns 0. * */ @@ -41,7 +40,6 @@ #include #include "dvb_frontend.h" -#include "dvb-pll.h" #include "lgdt330x_priv.h" #include "lgdt330x.h" @@ -70,55 +68,37 @@ struct lgdt330x_state u32 current_frequency; }; -static int i2c_writebytes (struct lgdt330x_state* state, - u8 addr, /* demod_address or pll_address */ +static int i2c_write_demod_bytes (struct lgdt330x_state* state, u8 *buf, /* data bytes to send */ int len /* number of bytes to send */ ) { - u8 tmp[] = { buf[0], buf[1] }; struct i2c_msg msg = - { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; - int err; + { .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 }; int i; + int err; - for (i=1; ii2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err); if (err < 0) return err; else return -EREMOTEIO; } - tmp[0]++; - } - return 0; -} - -#if 0 -static int i2c_readbytes (struct lgdt330x_state* state, - u8 addr, /* demod_address or pll_address */ - u8 *buf, /* holds data bytes read */ - int len /* number of bytes to read */ ) -{ - struct i2c_msg msg = - { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; - int err; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt330x: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); - return -EREMOTEIO; + msg.buf += 2; } return 0; } -#endif /* * This routine writes the register (reg) to the demod bus * then reads the data returned for (len) bytes. */ -static u8 i2c_selectreadbytes (struct lgdt330x_state* state, +static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, enum I2C_REG reg, u8* buf, int len) { u8 wr [] = { reg }; @@ -139,7 +119,7 @@ static u8 i2c_selectreadbytes (struct lgdt330x_state* state, } /* Software reset */ -int lgdt330x_SwReset(struct lgdt330x_state* state) +static int lgdt3302_SwReset(struct lgdt330x_state* state) { u8 ret; u8 reset[] = { @@ -148,23 +128,83 @@ int lgdt330x_SwReset(struct lgdt330x_state* state) * bits 5-0 are 1 to mask interrupts */ }; - ret = i2c_writebytes(state, - state->config->demod_address, + ret = i2c_write_demod_bytes(state, reset, sizeof(reset)); if (ret == 0) { - /* spec says reset takes 100 ns why wait */ - /* mdelay(100); */ /* keep low for 100mS */ - reset[1] = 0x7f; /* force reset high (inactive) - * and unmask interrupts */ - ret = i2c_writebytes(state, - state->config->demod_address, + + /* force reset high (inactive) and unmask interrupts */ + reset[1] = 0x7f; + ret = i2c_write_demod_bytes(state, reset, sizeof(reset)); } - /* Spec does not indicate a need for this either */ - /*mdelay(5); */ /* wait 5 msec before doing more */ return ret; } +static int lgdt3303_SwReset(struct lgdt330x_state* state) +{ + u8 ret; + u8 reset[] = { + 0x02, + 0x00 /* bit 0 is active low software reset */ + }; + + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + if (ret == 0) { + + /* force reset high (inactive) */ + reset[1] = 0x01; + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + } + return ret; +} + +static int lgdt330x_SwReset(struct lgdt330x_state* state) +{ + switch (state->config->demod_chip) { + case LGDT3302: + return lgdt3302_SwReset(state); + case LGDT3303: + return lgdt3303_SwReset(state); + default: + return -ENODEV; + } +} + +#ifdef MUTE_TDA9887 +static int i2c_write_ntsc_demod (struct lgdt330x_state* state, u8 buf[2]) +{ + struct i2c_msg msg = + { .addr = 0x43, + .flags = 0, + .buf = buf, + .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + return 0; +} + +static void fiddle_with_ntsc_if_demod(struct lgdt330x_state* state) +{ + // Experimental code + u8 buf0[] = {0x00, 0x20}; + u8 buf1[] = {0x01, 0x00}; + u8 buf2[] = {0x02, 0x00}; + + i2c_write_ntsc_demod(state, buf0); + i2c_write_ntsc_demod(state, buf1); + i2c_write_ntsc_demod(state, buf2); +} +#endif + static int lgdt330x_init(struct dvb_frontend* fe) { /* Hardware reset is done using gpio[0] of cx23880x chip. @@ -173,22 +213,101 @@ static int lgdt330x_init(struct dvb_frontend* fe) * Maybe there needs to be a callable function in cx88-core or * the caller of this function needs to do it. */ - dprintk("%s entered\n", __FUNCTION__); - return lgdt330x_SwReset((struct lgdt330x_state*) fe->demodulator_priv); + /* + * Array of byte pairs + * to initialize each different chip + */ + static u8 lgdt3302_init_data[] = { + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ + /* Change the value of NCOCTFV[25:0] of carrier + recovery center frequency register */ + VSB_CARRIER_FREQ0, 0x00, + VSB_CARRIER_FREQ1, 0x87, + VSB_CARRIER_FREQ2, 0x8e, + VSB_CARRIER_FREQ3, 0x01, + /* Change the TPCLK pin polarity + data is valid on falling clock */ + DEMUX_CONTROL, 0xfb, + /* Change the value of IFBW[11:0] of + AGC IF/RF loop filter bandwidth register */ + AGC_RF_BANDWIDTH0, 0x40, + AGC_RF_BANDWIDTH1, 0x93, + AGC_RF_BANDWIDTH2, 0x00, + /* Change the value of bit 6, 'nINAGCBY' and + 'NSSEL[1:0] of ACG function control register 2 */ + AGC_FUNC_CTRL2, 0xc6, + /* Change the value of bit 6 'RFFIX' + of AGC function control register 3 */ + AGC_FUNC_CTRL3, 0x40, + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to 0x7fe */ + AGC_DELAY0, 0x07, + AGC_DELAY2, 0xfe, + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + AGC_LOOP_BANDWIDTH0, 0x08, + AGC_LOOP_BANDWIDTH1, 0x9a + }; + + static u8 lgdt3303_init_data[] = { + 0x4c, 0x14 + }; + + struct lgdt330x_state* state = fe->demodulator_priv; + char *chip_name; + int err; + + switch (state->config->demod_chip) { + case LGDT3302: + chip_name = "LGDT3302"; + err = i2c_write_demod_bytes(state, lgdt3302_init_data, + sizeof(lgdt3302_init_data)); + break; + case LGDT3303: + chip_name = "LGDT3303"; + err = i2c_write_demod_bytes(state, lgdt3303_init_data, + sizeof(lgdt3303_init_data)); +#ifdef MUTE_TDA9887 + fiddle_with_ntsc_if_demod(state); +#endif + break; + default: + chip_name = "undefined"; + printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n"); + err = -ENODEV; + } + dprintk("%s entered as %s\n", __FUNCTION__, chip_name); + if (err < 0) + return err; + return lgdt330x_SwReset(state); } static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber) { - *ber = 0; /* Dummy out for now */ + *ber = 0; /* Not supplied by the demod chips */ return 0; } static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + struct lgdt330x_state* state = fe->demodulator_priv; + int err; u8 buf[2]; - i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf)); + switch (state->config->demod_chip) { + case LGDT3302: + err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, + buf, sizeof(buf)); + break; + case LGDT3303: + err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, + buf, sizeof(buf)); + break; + default: + printk(KERN_WARNING + "Only LGDT3302 and LGDT3303 are supported chips.\n"); + err = -ENODEV; + } *ucblocks = (buf[0] << 8) | buf[1]; return 0; @@ -197,123 +316,113 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) static int lgdt330x_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { - struct lgdt330x_state* state = - (struct lgdt330x_state*) fe->demodulator_priv; + /* + * Array of byte pairs + * to initialize 8VSB for lgdt3303 chip 50 MHz IF + */ + static u8 lgdt3303_8vsb_44_data[] = { + 0x04, 0x00, + 0x0d, 0x40, + 0x0e, 0x87, + 0x0f, 0x8e, + 0x10, 0x01, + 0x47, 0x8b }; + + /* + * Array of byte pairs + * to initialize QAM for lgdt3303 chip + */ + static u8 lgdt3303_qam_data[] = { + 0x04, 0x00, + 0x0d, 0x00, + 0x0e, 0x00, + 0x0f, 0x00, + 0x10, 0x00, + 0x51, 0x63, + 0x47, 0x66, + 0x48, 0x66, + 0x4d, 0x1a, + 0x49, 0x08, + 0x4a, 0x9b }; + + struct lgdt330x_state* state = fe->demodulator_priv; - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; - static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; - static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb }; - static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 }; - static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 }; - static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x07, 0x00, 0xfe }; - static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; + int err; /* Change only if we are actually changing the modulation */ if (state->current_modulation != param->u.vsb.modulation) { switch(param->u.vsb.modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __FUNCTION__); - /* Select VSB mode and serial MPEG interface */ - top_ctrl_cfg[1] = 0x07; + /* Select VSB mode */ + top_ctrl_cfg[1] = 0x03; /* Select ANT connector if supported by card */ if (state->config->pll_rf_set) state->config->pll_rf_set(fe, 1); + + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, + sizeof(lgdt3303_8vsb_44_data)); + } break; case QAM_64: dprintk("%s: QAM_64 MODE\n", __FUNCTION__); - /* Select QAM_64 mode and serial MPEG interface */ - top_ctrl_cfg[1] = 0x04; + /* Select QAM_64 mode */ + top_ctrl_cfg[1] = 0x00; /* Select CABLE connector if supported by card */ if (state->config->pll_rf_set) state->config->pll_rf_set(fe, 0); + + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_qam_data, + sizeof(lgdt3303_qam_data)); + } break; case QAM_256: dprintk("%s: QAM_256 MODE\n", __FUNCTION__); - /* Select QAM_256 mode and serial MPEG interface */ - top_ctrl_cfg[1] = 0x05; + /* Select QAM_256 mode */ + top_ctrl_cfg[1] = 0x01; /* Select CABLE connector if supported by card */ if (state->config->pll_rf_set) state->config->pll_rf_set(fe, 0); + + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_qam_data, + sizeof(lgdt3303_qam_data)); + } break; default: printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); return -1; } - /* Initializations common to all modes */ + /* + * select serial or parallel MPEG harware interface + * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 + * Parallel: 0x00 + */ + top_ctrl_cfg[1] |= state->config->serial_mpeg; /* Select the requested mode */ - i2c_writebytes(state, state->config->demod_address, - top_ctrl_cfg, sizeof(top_ctrl_cfg)); - - /* Change the value of IFBW[11:0] - of AGC IF/RF loop filter bandwidth register */ - i2c_writebytes(state, state->config->demod_address, - agc_rf_cfg, sizeof(agc_rf_cfg)); - - /* Change the value of bit 6, 'nINAGCBY' and - 'NSSEL[1:0] of ACG function control register 2 */ - /* Change the value of bit 6 'RFFIX' - of AGC function control register 3 */ - i2c_writebytes(state, state->config->demod_address, - agc_ctrl_cfg, sizeof(agc_ctrl_cfg)); - - /* Change the TPCLK pin polarity - data is valid on falling clock */ - i2c_writebytes(state, state->config->demod_address, - demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); - - /* Change the value of NCOCTFV[25:0] of carrier - recovery center frequency register */ - i2c_writebytes(state, state->config->demod_address, - vsb_freq_cfg, sizeof(vsb_freq_cfg)); - - /* Set the value of 'INLVTHD' register 0x2a/0x2c to 0x7fe */ - i2c_writebytes(state, state->config->demod_address, - agc_delay_cfg, sizeof(agc_delay_cfg)); - - /* Change the value of IAGCBW[15:8] - of inner AGC loop filter bandwith */ - i2c_writebytes(state, state->config->demod_address, - agc_loop_cfg, sizeof(agc_loop_cfg)); - + i2c_write_demod_bytes(state, top_ctrl_cfg, + sizeof(top_ctrl_cfg)); state->config->set_ts_params(fe, 0); state->current_modulation = param->u.vsb.modulation; } /* Change only if we are actually changing the channel */ if (state->current_frequency != param->frequency) { - u8 buf[5]; - struct i2c_msg msg = { .flags = 0, .buf = &buf[1], .len = 4 }; - int err; - - state->config->pll_set(fe, param, buf); - msg.addr = buf[0]; - - dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n", __FUNCTION__, - buf[0],buf[1],buf[2],buf[3],buf[4]); - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } -#if 0 - /* Check the status of the tuner pll */ - i2c_readbytes(state, buf[0], &buf[1], 1); - dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[1]); -#endif - /* Update current frequency */ + /* Tune to the new frequency */ + state->config->pll_set(fe, param); + /* Keep track of the new frequency */ state->current_frequency = param->frequency; } lgdt330x_SwReset(state); @@ -328,21 +437,15 @@ static int lgdt330x_get_frontend(struct dvb_frontend* fe, return 0; } -static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + struct lgdt330x_state* state = fe->demodulator_priv; u8 buf[3]; *status = 0; /* Reset status result */ - /* - * You must set the Mask bits to 1 in the IRQ_MASK in order - * to see that status bit in the IRQ_STATUS register. - * This is done in SwReset(); - */ - /* AGC status register */ - i2c_selectreadbytes(state, AGC_STATUS, buf, 1); + i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); if ((buf[0] & 0x0c) == 0x8){ /* Test signal does not exist flag */ @@ -353,16 +456,15 @@ static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } + /* + * You must set the Mask bits to 1 in the IRQ_MASK in order + * to see that status bit in the IRQ_STATUS register. + * This is done in SwReset(); + */ /* signal status */ - i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); + i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf)); dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); -#if 0 - /* Alternative method to check for a signal */ - /* using the SNR good/bad interrupts. */ - if ((buf[2] & 0x30) == 0x10) - *status |= FE_HAS_SIGNAL; -#endif /* sync status */ if ((buf[2] & 0x03) == 0x01) { @@ -376,7 +478,7 @@ static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) } /* Carrier Recovery Lock Status Register */ - i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); + i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); switch (state->current_modulation) { case QAM_256: @@ -396,13 +498,75 @@ static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } +static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct lgdt330x_state* state = fe->demodulator_priv; + int err; + u8 buf[3]; + + *status = 0; /* Reset status result */ + + /* lgdt3303 AGC status register */ + err = i2c_read_demod_bytes(state, 0x58, buf, 1); + if (err < 0) + return err; + + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0x21) == 0x01){ + /* Test input signal does not exist flag */ + /* as well as the AGC lock flag. */ + *status |= FE_HAS_SIGNAL; + } else { + /* Without a signal all other status bits are meaningless */ + return 0; + } + + /* Carrier Recovery Lock Status Register */ + i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* Need to undestand why there are 3 lock levels here */ + if ((buf[0] & 0x07) == 0x07) + *status |= FE_HAS_CARRIER; + else + break; + i2c_read_demod_bytes(state, 0x8a, buf, 1); + if ((buf[0] & 0x04) == 0x04) + *status |= FE_HAS_SYNC; + if ((buf[0] & 0x01) == 0x01) + *status |= FE_HAS_LOCK; + if ((buf[0] & 0x08) == 0x08) + *status |= FE_HAS_VITERBI; + break; + case VSB_8: + if ((buf[0] & 0x80) == 0x80) + *status |= FE_HAS_CARRIER; + else + break; + i2c_read_demod_bytes(state, 0x38, buf, 1); + if ((buf[0] & 0x02) == 0x00) + *status |= FE_HAS_SYNC; + if ((buf[0] & 0x01) == 0x01) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + } + break; + default: + printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); + } + return 0; +} + static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) { /* not directly available. */ + *strength = 0; return 0; } -static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) +static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) { #ifdef SNR_IN_DB /* @@ -451,7 +615,7 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, - 90833, 114351, 143960, 181235, 228161, 0x040000 + 90833, 114351, 143960, 181235, 228161, 0x080000 }; static u8 buf[5];/* read data buffer */ @@ -459,8 +623,8 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) static u32 snr_db; /* index into SNR_EQ[] */ struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; - /* read both equalizer and pase tracker noise data */ - i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + /* read both equalizer and phase tracker noise data */ + i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); if (state->current_modulation == VSB_8) { /* Equalizer Mean-Square Error Register for VSB */ @@ -496,19 +660,20 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; /* read both equalizer and pase tracker noise data */ - i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); if (state->current_modulation == VSB_8) { - /* Equalizer Mean-Square Error Register for VSB */ - noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; - } else { - /* Phase Tracker Mean-Square Error Register for QAM */ + /* Phase Tracker Mean-Square Error Register for VSB */ noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + } else { + + /* Carrier Recovery Mean-Square Error for QAM */ + i2c_read_demod_bytes(state, 0x1a, buf, 2); + noise = ((buf[0] & 3) << 8) | buf[1]; } /* Small values for noise mean signal is better so invert noise */ - /* Noise is 19 bit value so discard 3 LSB*/ - *snr = ~noise>>3; + *snr = ~noise; #endif dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); @@ -516,6 +681,32 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) return 0; } +static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) +{ + /* Return the raw noise value */ + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + + if (state->current_modulation == VSB_8) { + + /* Phase Tracker Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; + } else { + + /* Carrier Recovery Mean-Square Error for QAM */ + i2c_read_demod_bytes(state, 0x1a, buf, 2); + noise = (buf[0] << 8) | buf[1]; + } + + /* Small values for noise mean signal is better so invert noise */ + *snr = ~noise; + + dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); + + return 0; +} + static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) { /* I have no idea about this - it may not be needed */ @@ -531,7 +722,8 @@ static void lgdt330x_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops lgdt330x_ops; +static struct dvb_frontend_ops lgdt3302_ops; +static struct dvb_frontend_ops lgdt3303_ops; struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, struct i2c_adapter* i2c) @@ -548,9 +740,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, /* Setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &lgdt330x_ops, sizeof(struct dvb_frontend_ops)); + switch (config->demod_chip) { + case LGDT3302: + memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); + break; + case LGDT3303: + memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + goto error; + } + /* Verify communication with demod chip */ - if (i2c_selectreadbytes(state, 2, buf, 1)) + if (i2c_read_demod_bytes(state, 2, buf, 1)) goto error; state->current_frequency = -1; @@ -568,9 +770,33 @@ error: return NULL; } -static struct dvb_frontend_ops lgdt330x_ops = { +static struct dvb_frontend_ops lgdt3302_ops = { + .info = { + .name= "LG Electronics LGDT3302/LGDT3303 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + /* Symbol rate is for all VSB modes need to check QAM */ + .symbol_rate_min = 10762000, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt330x_init, + .set_frontend = lgdt330x_set_parameters, + .get_frontend = lgdt330x_get_frontend, + .get_tune_settings = lgdt330x_get_tune_settings, + .read_status = lgdt3302_read_status, + .read_ber = lgdt330x_read_ber, + .read_signal_strength = lgdt330x_read_signal_strength, + .read_snr = lgdt3302_read_snr, + .read_ucblocks = lgdt330x_read_ucblocks, + .release = lgdt330x_release, +}; + +static struct dvb_frontend_ops lgdt3303_ops = { .info = { - .name= "LG Electronics lgdt330x VSB/QAM Frontend", + .name= "LG Electronics LGDT3303 VSB/QAM Frontend", .type = FE_ATSC, .frequency_min= 54000000, .frequency_max= 858000000, @@ -584,15 +810,15 @@ static struct dvb_frontend_ops lgdt330x_ops = { .set_frontend = lgdt330x_set_parameters, .get_frontend = lgdt330x_get_frontend, .get_tune_settings = lgdt330x_get_tune_settings, - .read_status = lgdt330x_read_status, + .read_status = lgdt3303_read_status, .read_ber = lgdt330x_read_ber, .read_signal_strength = lgdt330x_read_signal_strength, - .read_snr = lgdt330x_read_snr, + .read_snr = lgdt3303_read_snr, .read_ucblocks = lgdt330x_read_ucblocks, .release = lgdt330x_release, }; -MODULE_DESCRIPTION("lgdt330x [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); MODULE_AUTHOR("Wilson Michaels"); MODULE_LICENSE("GPL"); @@ -601,6 +827,5 @@ EXPORT_SYMBOL(lgdt330x_attach); /* * Local variables: * c-basic-offset: 8 - * compile-command: "make DVB=1" * End: */ diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h index 04986f8e7565..e209ba1e47c5 100644 --- a/drivers/media/dvb/frontends/lgdt330x.h +++ b/drivers/media/dvb/frontends/lgdt330x.h @@ -1,5 +1,5 @@ /* - * Support for LGDT3302 & LGDT3303 (DViCO FustionHDTV Gold) - VSB/QAM + * Support for LGDT3302 and LGDT3303 - VSB/QAM * * Copyright (C) 2005 Wilson Michaels * @@ -24,14 +24,26 @@ #include +typedef enum lg_chip_t { + UNDEFINED, + LGDT3302, + LGDT3303 +}lg_chip_type; + struct lgdt330x_config { /* The demodulator's i2c address */ u8 demod_address; + /* LG demodulator chip LGDT3302 or LGDT3303 */ + lg_chip_type demod_chip; + + /* MPEG hardware interface - 0:parallel 1:serial */ + int serial_mpeg; + /* PLL interface */ int (*pll_rf_set) (struct dvb_frontend* fe, int index); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pll_address); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); diff --git a/drivers/media/dvb/frontends/lgdt330x_priv.h b/drivers/media/dvb/frontends/lgdt330x_priv.h index 4143ce8f1a95..59b7c5b9012d 100644 --- a/drivers/media/dvb/frontends/lgdt330x_priv.h +++ b/drivers/media/dvb/frontends/lgdt330x_priv.h @@ -1,5 +1,5 @@ /* - * Support for LGDT3302 & LGDT3303 (DViCO FustionHDTV Gold) - VSB/QAM + * Support for LGDT3302 and LGDT3303 - VSB/QAM * * Copyright (C) 2005 Wilson Michaels * @@ -57,8 +57,10 @@ enum I2C_REG { PH_ERR1= 0x4a, PH_ERR2= 0x4b, DEMUX_CONTROL= 0x66, - PACKET_ERR_COUNTER1= 0x6a, - PACKET_ERR_COUNTER2= 0x6b, + LGDT3302_PACKET_ERR_COUNTER1= 0x6a, + LGDT3302_PACKET_ERR_COUNTER2= 0x6b, + LGDT3303_PACKET_ERR_COUNTER1= 0x8b, + LGDT3303_PACKET_ERR_COUNTER2= 0x8c, }; #endif /* _LGDT330X_PRIV_ */ -- cgit v1.2.2 From e179d8b0552e2fdb45c6022c589af945f8cbecbe Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 9 Aug 2005 17:48:54 -0700 Subject: [PATCH] dvb: lgdt330x frontend: trivial text cleanups Two trivial text changes in Kconfig and lgdt330x.c Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 2 +- drivers/media/dvb/frontends/lgdt330x.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index e83256d0fd14..a50a41f6f79d 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -188,7 +188,7 @@ config DVB_BCM3510 support this frontend. config DVB_LGDT330X - tristate "LGDT3302 or LGDT3303 based (DViCO FusionHDTV Gold)" + tristate "LG Electronics LGDT3302/LGDT3303 based" depends on DVB_CORE help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index c48e7c11d708..e1c71afad214 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -772,7 +772,7 @@ error: static struct dvb_frontend_ops lgdt3302_ops = { .info = { - .name= "LG Electronics LGDT3302/LGDT3303 VSB/QAM Frontend", + .name= "LG Electronics LGDT3302 VSB/QAM Frontend", .type = FE_ATSC, .frequency_min= 54000000, .frequency_max= 858000000, -- cgit v1.2.2 From aeb3f76350e78aba90653b563de6677b442d21d6 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 9 Aug 2005 17:48:54 -0700 Subject: [PATCH] DVB: lgdt330x frontend: some bug fixes & add lgdt3303 support This patch removes the tda9887 stuff from lgdt330x.c. It's experimental code which wasn't supposed to leak out and we don't want it in 2.6.13. Signed-off-by: Michael Krufky Acked-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt330x.c | 35 ---------------------------------- 1 file changed, 35 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index e1c71afad214..1f1cd7a8d500 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -172,38 +172,6 @@ static int lgdt330x_SwReset(struct lgdt330x_state* state) } } -#ifdef MUTE_TDA9887 -static int i2c_write_ntsc_demod (struct lgdt330x_state* state, u8 buf[2]) -{ - struct i2c_msg msg = - { .addr = 0x43, - .flags = 0, - .buf = buf, - .len = 2 }; - int err; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - return 0; -} - -static void fiddle_with_ntsc_if_demod(struct lgdt330x_state* state) -{ - // Experimental code - u8 buf0[] = {0x00, 0x20}; - u8 buf1[] = {0x01, 0x00}; - u8 buf2[] = {0x02, 0x00}; - - i2c_write_ntsc_demod(state, buf0); - i2c_write_ntsc_demod(state, buf1); - i2c_write_ntsc_demod(state, buf2); -} -#endif static int lgdt330x_init(struct dvb_frontend* fe) { @@ -267,9 +235,6 @@ static int lgdt330x_init(struct dvb_frontend* fe) chip_name = "LGDT3303"; err = i2c_write_demod_bytes(state, lgdt3303_init_data, sizeof(lgdt3303_init_data)); -#ifdef MUTE_TDA9887 - fiddle_with_ntsc_if_demod(state); -#endif break; default: chip_name = "undefined"; -- cgit v1.2.2