mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 15:28:50 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
322
drivers/media/usb/dvb-usb/Kconfig
Normal file
322
drivers/media/usb/dvb-usb/Kconfig
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
config DVB_USB
|
||||
tristate "Support for various USB DVB devices"
|
||||
depends on DVB_CORE && USB && I2C && RC_CORE
|
||||
help
|
||||
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
|
||||
<file:Documentation/dvb/README.dvb-usb>.
|
||||
|
||||
For a complete list of supported USB devices see the LinuxTV DVB Wiki:
|
||||
<http://www.linuxtv.org/wiki/index.php/DVB_USB>
|
||||
|
||||
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 debugging. 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
|
||||
select DVB_DIB3000MC
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
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_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DIB3000MB
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
|
||||
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the Linux-DVB Wiki at www.linuxtv.org.
|
||||
|
||||
Say Y if you own such a device and want to use it. You should build it as
|
||||
a module.
|
||||
|
||||
config DVB_USB_DIBUSB_MB_FAULTY
|
||||
bool "Support faulty USB IDs"
|
||||
depends on DVB_USB_DIBUSB_MB
|
||||
help
|
||||
Support for faulty USB IDs due to an invalid EEPROM on some Artec devices.
|
||||
|
||||
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
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for USB2.0 DVB-T receivers based on reference designs made by
|
||||
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the Linux-DVB Wiki at www.linuxtv.org.
|
||||
|
||||
Say Y if you own such a device and want to use it. You should build it as
|
||||
a module.
|
||||
|
||||
config DVB_USB_DIB0700
|
||||
tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DIB7000M if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DIB8000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2266 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
|
||||
USB bridge is also present in devices having the DiB7700 DVB-T-USB
|
||||
silicon. This chip can be found in devices offered by Hauppauge,
|
||||
Avermedia and other big and small companies.
|
||||
|
||||
For an up-to-date list of devices supported by this driver, have a look
|
||||
on the LinuxTV Wiki at www.linuxtv.org.
|
||||
|
||||
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
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DIB3000MC
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
|
||||
|
||||
config DVB_USB_CXUSB
|
||||
tristate "Conexant USB2.0 hybrid reference design support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ATBM8830 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGS8GXX if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MAX2165 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Conexant USB2.0 hybrid reference design.
|
||||
Currently, only DVB and ATSC modes are supported, analog mode
|
||||
shall be added in the future. Devices that require this module:
|
||||
|
||||
Medion MD95700 hybrid USB2.0 device.
|
||||
DViCO FusionHDTV (Bluebird) USB2.0 devices
|
||||
TechnoTrend TVStick CT2-4400 and CT2-4650 CI devices
|
||||
|
||||
config DVB_USB_M920X
|
||||
tristate "Uli m920x DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
|
||||
Currently, only devices with a product id of
|
||||
"DTV USB MINI" (in cold state) are supported.
|
||||
Firmware required.
|
||||
|
||||
config DVB_USB_DIGITV
|
||||
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
|
||||
|
||||
config DVB_USB_VP7045
|
||||
tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the
|
||||
|
||||
TwinhanDTV Alpha (stick) (VP-7045),
|
||||
TwinhanDTV MagicBox II (VP-7046),
|
||||
DigitalNow TinyUSB 2 DVB-t,
|
||||
DigitalRise USB 2.0 Ter (Beetle) and
|
||||
TYPHOON DVB-T USB DRIVE
|
||||
|
||||
DVB-T USB2.0 receivers.
|
||||
|
||||
config DVB_USB_VP702X
|
||||
tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the
|
||||
|
||||
TwinhanDTV StarBox,
|
||||
DigitalRise USB Starbox and
|
||||
TYPHOON DVB-S USB 2.0 BOX
|
||||
|
||||
DVB-S USB2.0 receivers.
|
||||
|
||||
config DVB_USB_GP8PSK
|
||||
tristate "GENPIX 8PSK->USB module support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the
|
||||
GENPIX 8psk module
|
||||
|
||||
DVB-S USB2.0 receivers.
|
||||
|
||||
config DVB_USB_NOVA_T_USB2
|
||||
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_DIB3000MC
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_TTUSB2
|
||||
tristate "Pinnacle 400e DVB-S USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver and
|
||||
the TechnoTrend CT-3650 CI DVB-C/T USB2.0 receiver. The
|
||||
firmware protocol used by this module is similar to the one used by the
|
||||
old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
|
||||
|
||||
config DVB_USB_DTT200U
|
||||
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.
|
||||
|
||||
config DVB_USB_OPERA1
|
||||
tristate "Opera1 DVB-S USB2.0 receiver"
|
||||
depends on DVB_USB
|
||||
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Opera DVB-S USB2.0 receiver.
|
||||
|
||||
config DVB_USB_AF9005
|
||||
tristate "Afatech AF9005 DVB-T USB1.1 support"
|
||||
depends on DVB_USB
|
||||
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
|
||||
and the TerraTec Cinergy T USB XE (Rev.1)
|
||||
|
||||
config DVB_USB_AF9005_REMOTE
|
||||
tristate "Afatech AF9005 default remote control support"
|
||||
depends on DVB_USB_AF9005
|
||||
help
|
||||
Say Y here to support the default remote control decoding for the
|
||||
Afatech AF9005 based receiver.
|
||||
|
||||
config DVB_USB_PCTV452E
|
||||
tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
|
||||
depends on DVB_USB
|
||||
select TTPCI_EEPROM
|
||||
select DVB_LNBP22 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for external USB adapter designed by Pinnacle,
|
||||
shipped under the brand name 'PCTV HDTV Pro USB'.
|
||||
Also supports TT Connect S2-3600/3650 cards.
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
config DVB_USB_DW2102
|
||||
tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
|
||||
receivers.
|
||||
|
||||
config DVB_USB_CINERGY_T2
|
||||
tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
|
||||
config DVB_USB_DTV5100
|
||||
tristate "AME DTV-5100 USB2.0 DVB-T support"
|
||||
depends on DVB_USB
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
|
||||
|
||||
config DVB_USB_FRIIO
|
||||
tristate "Friio ISDB-T USB2.0 Receiver support"
|
||||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the Japanese DTV receiver Friio.
|
||||
|
||||
config DVB_USB_AZ6027
|
||||
tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
|
||||
depends on DVB_USB
|
||||
select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the AZ6027 device
|
||||
|
||||
config DVB_USB_TECHNISAT_USB2
|
||||
tristate "Technisat DVB-S/S2 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y here to support the Technisat USB2 DVB-S/S2 device
|
||||
83
drivers/media/usb/dvb-usb/Makefile
Normal file
83
drivers/media/usb/dvb-usb/Makefile
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
dvb-usb-objs += dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o
|
||||
dvb-usb-objs += dvb-usb-dvb.o dvb-usb-remote.o usb-urb.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-vp702x-objs := vp702x.o vp702x-fe.o
|
||||
obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
|
||||
|
||||
dvb-usb-gp8psk-objs := gp8psk.o gp8psk-fe.o
|
||||
obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.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-m920x-objs := m920x.o
|
||||
obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.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
|
||||
|
||||
dvb-usb-ttusb2-objs := ttusb2.o
|
||||
obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o
|
||||
|
||||
dvb-usb-dib0700-objs := dib0700_core.o dib0700_devices.o
|
||||
obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
|
||||
|
||||
dvb-usb-opera-objs := opera1.o
|
||||
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
|
||||
|
||||
dvb-usb-af9005-objs := af9005.o af9005-fe.o
|
||||
obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
|
||||
|
||||
dvb-usb-af9005-remote-objs := af9005-remote.o
|
||||
obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
|
||||
|
||||
dvb-usb-pctv452e-objs := pctv452e.o
|
||||
obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
|
||||
|
||||
dvb-usb-dw2102-objs := dw2102.o
|
||||
obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
|
||||
|
||||
dvb-usb-dtv5100-objs := dtv5100.o
|
||||
obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
|
||||
|
||||
dvb-usb-cinergyT2-objs := cinergyT2-core.o cinergyT2-fe.o
|
||||
obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
|
||||
|
||||
dvb-usb-friio-objs := friio.o friio-fe.o
|
||||
obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
|
||||
|
||||
dvb-usb-az6027-objs := az6027.o
|
||||
obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
|
||||
|
||||
dvb-usb-technisat-usb2-objs := technisat-usb2.o
|
||||
obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
|
||||
|
||||
ccflags-y += -I$(srctree)/drivers/media/dvb-core
|
||||
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/
|
||||
# due to tuner-xc3028
|
||||
ccflags-y += -I$(srctree)/drivers/media/tuners
|
||||
ccflags-y += -I$(srctree)/drivers/media/pci/ttpci
|
||||
191
drivers/media/usb/dvb-usb/a800.c
Normal file
191
drivers/media/usb/dvb-usb/a800.c
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/* 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);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/* assure to put cold to 0 for iManufacturer == 1 */
|
||||
static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold)
|
||||
{
|
||||
*cold = udev->descriptor.iManufacturer != 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rc_map_table rc_map_a800_table[] = {
|
||||
{ 0x0201, KEY_MODE }, /* SOURCE */
|
||||
{ 0x0200, KEY_POWER2 }, /* POWER */
|
||||
{ 0x0205, KEY_1 }, /* 1 */
|
||||
{ 0x0206, KEY_2 }, /* 2 */
|
||||
{ 0x0207, KEY_3 }, /* 3 */
|
||||
{ 0x0209, KEY_4 }, /* 4 */
|
||||
{ 0x020a, KEY_5 }, /* 5 */
|
||||
{ 0x020b, KEY_6 }, /* 6 */
|
||||
{ 0x020d, KEY_7 }, /* 7 */
|
||||
{ 0x020e, KEY_8 }, /* 8 */
|
||||
{ 0x020f, KEY_9 }, /* 9 */
|
||||
{ 0x0212, KEY_LEFT }, /* L / DISPLAY */
|
||||
{ 0x0211, KEY_0 }, /* 0 */
|
||||
{ 0x0213, KEY_RIGHT }, /* R / CH RTN */
|
||||
{ 0x0217, KEY_CAMERA }, /* SNAP SHOT */
|
||||
{ 0x0210, KEY_LAST }, /* 16-CH PREV */
|
||||
{ 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */
|
||||
{ 0x020c, KEY_ZOOM }, /* FULL SCREEN */
|
||||
{ 0x021f, KEY_VOLUMEUP }, /* VOL UP */
|
||||
{ 0x0214, KEY_MUTE }, /* MUTE */
|
||||
{ 0x0208, KEY_AUDIO }, /* AUDIO */
|
||||
{ 0x0219, KEY_RECORD }, /* RECORD */
|
||||
{ 0x0218, KEY_PLAY }, /* PLAY */
|
||||
{ 0x021b, KEY_STOP }, /* STOP */
|
||||
{ 0x021a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
|
||||
{ 0x021d, KEY_BACK }, /* << / RED */
|
||||
{ 0x021c, KEY_FORWARD }, /* >> / YELLOW */
|
||||
{ 0x0203, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x0204, KEY_EPG }, /* EPG */
|
||||
{ 0x0215, KEY_MENU }, /* MENU */
|
||||
|
||||
{ 0x0303, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x0301, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x0300, KEY_LAST }, /* >>| / BLUE */
|
||||
|
||||
};
|
||||
|
||||
static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
int ret;
|
||||
u8 *key = kmalloc(5, GFP_KERNEL);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
|
||||
0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
|
||||
2000) != 5) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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: %*ph\n", 5, key);
|
||||
ret = 0;
|
||||
out:
|
||||
kfree(key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_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, NULL, adapter_nr);
|
||||
}
|
||||
|
||||
/* 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_device_properties a800_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-avertv-a800-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
|
||||
.frontend_attach = dibusb_dib3000mc_frontend_attach,
|
||||
.tuner_attach = dibusb_dib3000mc_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = a800_power_ctrl,
|
||||
.identify_state = a800_identify_state,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_map_table = rc_map_a800_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_a800_table),
|
||||
.rc_query = a800_rc_query,
|
||||
},
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
.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 = {
|
||||
.name = "dvb_usb_a800",
|
||||
.probe = a800_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = a800_table,
|
||||
};
|
||||
|
||||
module_usb_driver(a800_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
1487
drivers/media/usb/dvb-usb/af9005-fe.c
Normal file
1487
drivers/media/usb/dvb-usb/af9005-fe.c
Normal file
File diff suppressed because it is too large
Load diff
157
drivers/media/usb/dvb-usb/af9005-remote.c
Normal file
157
drivers/media/usb/dvb-usb/af9005-remote.c
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/* DVB USB compliant Linux driver for the Afatech 9005
|
||||
* USB1.1 DVB-T receiver.
|
||||
*
|
||||
* Standard remote decode function
|
||||
*
|
||||
* Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
|
||||
*
|
||||
* Thanks to Afatech who kindly provided 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; 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.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "af9005.h"
|
||||
/* debug */
|
||||
static int dvb_usb_af9005_remote_debug;
|
||||
module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,
|
||||
"enable (1) or disable (0) debug messages."
|
||||
DVB_USB_DEBUG_STATUS);
|
||||
|
||||
#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
|
||||
|
||||
struct rc_map_table rc_map_af9005_table[] = {
|
||||
|
||||
{0x01b7, KEY_POWER},
|
||||
{0x01a7, KEY_VOLUMEUP},
|
||||
{0x0187, KEY_CHANNELUP},
|
||||
{0x017f, KEY_MUTE},
|
||||
{0x01bf, KEY_VOLUMEDOWN},
|
||||
{0x013f, KEY_CHANNELDOWN},
|
||||
{0x01df, KEY_1},
|
||||
{0x015f, KEY_2},
|
||||
{0x019f, KEY_3},
|
||||
{0x011f, KEY_4},
|
||||
{0x01ef, KEY_5},
|
||||
{0x016f, KEY_6},
|
||||
{0x01af, KEY_7},
|
||||
{0x0127, KEY_8},
|
||||
{0x0107, KEY_9},
|
||||
{0x01cf, KEY_ZOOM},
|
||||
{0x014f, KEY_0},
|
||||
{0x018f, KEY_GOTO}, /* marked jump on the remote */
|
||||
|
||||
{0x00bd, KEY_POWER},
|
||||
{0x007d, KEY_VOLUMEUP},
|
||||
{0x00fd, KEY_CHANNELUP},
|
||||
{0x009d, KEY_MUTE},
|
||||
{0x005d, KEY_VOLUMEDOWN},
|
||||
{0x00dd, KEY_CHANNELDOWN},
|
||||
{0x00ad, KEY_1},
|
||||
{0x006d, KEY_2},
|
||||
{0x00ed, KEY_3},
|
||||
{0x008d, KEY_4},
|
||||
{0x004d, KEY_5},
|
||||
{0x00cd, KEY_6},
|
||||
{0x00b5, KEY_7},
|
||||
{0x0075, KEY_8},
|
||||
{0x00f5, KEY_9},
|
||||
{0x0095, KEY_ZOOM},
|
||||
{0x0055, KEY_0},
|
||||
{0x00d5, KEY_GOTO}, /* marked jump on the remote */
|
||||
};
|
||||
|
||||
int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
|
||||
|
||||
static int repeatable_keys[] = {
|
||||
KEY_VOLUMEUP,
|
||||
KEY_VOLUMEDOWN,
|
||||
KEY_CHANNELUP,
|
||||
KEY_CHANNELDOWN
|
||||
};
|
||||
|
||||
int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
|
||||
int *state)
|
||||
{
|
||||
u16 mark, space;
|
||||
u32 result;
|
||||
u8 cust, dat, invdat;
|
||||
int i;
|
||||
|
||||
if (len >= 6) {
|
||||
mark = (u16) (data[0] << 8) + data[1];
|
||||
space = (u16) (data[2] << 8) + data[3];
|
||||
if (space * 3 < mark) {
|
||||
for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
|
||||
if (d->last_event == repeatable_keys[i]) {
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
*event = d->last_event;
|
||||
deb_decode("repeat key, event %x\n",
|
||||
*event);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
deb_decode("repeated key ignored (non repeatable)\n");
|
||||
return 0;
|
||||
} else if (len >= 33 * 4) { /*32 bits + start code */
|
||||
result = 0;
|
||||
for (i = 4; i < 4 + 32 * 4; i += 4) {
|
||||
result <<= 1;
|
||||
mark = (u16) (data[i] << 8) + data[i + 1];
|
||||
mark >>= 1;
|
||||
space = (u16) (data[i + 2] << 8) + data[i + 3];
|
||||
space >>= 1;
|
||||
if (mark * 2 > space)
|
||||
result += 1;
|
||||
}
|
||||
deb_decode("key pressed, raw value %x\n", result);
|
||||
if ((result & 0xff000000) != 0xfe000000) {
|
||||
deb_decode
|
||||
("doesn't start with 0xfe, ignored\n");
|
||||
return 0;
|
||||
}
|
||||
cust = (result >> 16) & 0xff;
|
||||
dat = (result >> 8) & 0xff;
|
||||
invdat = (~result) & 0xff;
|
||||
if (dat != invdat) {
|
||||
deb_decode("code != inverted code\n");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < rc_map_af9005_table_size; i++) {
|
||||
if (rc5_custom(&rc_map_af9005_table[i]) == cust
|
||||
&& rc5_data(&rc_map_af9005_table[i]) == dat) {
|
||||
*event = rc_map_af9005_table[i].keycode;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
deb_decode
|
||||
("key pressed, event %x\n", *event);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
deb_decode("not found in table\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(rc_map_af9005_table);
|
||||
EXPORT_SYMBOL(rc_map_af9005_table_size);
|
||||
EXPORT_SYMBOL(af9005_rc_decode);
|
||||
|
||||
MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
|
||||
MODULE_DESCRIPTION
|
||||
("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
203
drivers/media/usb/dvb-usb/af9005-script.h
Normal file
203
drivers/media/usb/dvb-usb/af9005-script.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
File automatically generated by createinit.py using data
|
||||
extracted from AF05BDA.sys (windows driver):
|
||||
|
||||
dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
|
||||
python createinit.py > af9005-script.h
|
||||
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u16 reg;
|
||||
u8 pos;
|
||||
u8 len;
|
||||
u8 val;
|
||||
} RegDesc;
|
||||
|
||||
static RegDesc script[] = {
|
||||
{0xa180, 0x0, 0x8, 0xa},
|
||||
{0xa181, 0x0, 0x8, 0xd7},
|
||||
{0xa182, 0x0, 0x8, 0xa3},
|
||||
{0xa0a0, 0x0, 0x8, 0x0},
|
||||
{0xa0a1, 0x0, 0x5, 0x0},
|
||||
{0xa0a1, 0x5, 0x1, 0x1},
|
||||
{0xa0c0, 0x0, 0x4, 0x1},
|
||||
{0xa20e, 0x4, 0x4, 0xa},
|
||||
{0xa20f, 0x0, 0x8, 0x40},
|
||||
{0xa210, 0x0, 0x8, 0x8},
|
||||
{0xa32a, 0x0, 0x4, 0xa},
|
||||
{0xa32c, 0x0, 0x8, 0x20},
|
||||
{0xa32b, 0x0, 0x8, 0x15},
|
||||
{0xa1a0, 0x1, 0x1, 0x1},
|
||||
{0xa000, 0x0, 0x1, 0x1},
|
||||
{0xa000, 0x1, 0x1, 0x0},
|
||||
{0xa001, 0x1, 0x1, 0x1},
|
||||
{0xa001, 0x0, 0x1, 0x0},
|
||||
{0xa001, 0x5, 0x1, 0x0},
|
||||
{0xa00e, 0x0, 0x5, 0x10},
|
||||
{0xa00f, 0x0, 0x3, 0x4},
|
||||
{0xa00f, 0x3, 0x3, 0x5},
|
||||
{0xa010, 0x0, 0x3, 0x4},
|
||||
{0xa010, 0x3, 0x3, 0x5},
|
||||
{0xa016, 0x4, 0x4, 0x3},
|
||||
{0xa01f, 0x0, 0x6, 0xa},
|
||||
{0xa020, 0x0, 0x6, 0xa},
|
||||
{0xa2bc, 0x0, 0x1, 0x1},
|
||||
{0xa2bc, 0x5, 0x1, 0x1},
|
||||
{0xa015, 0x0, 0x8, 0x50},
|
||||
{0xa016, 0x0, 0x1, 0x0},
|
||||
{0xa02a, 0x0, 0x8, 0x50},
|
||||
{0xa029, 0x0, 0x8, 0x4b},
|
||||
{0xa614, 0x0, 0x8, 0x46},
|
||||
{0xa002, 0x0, 0x5, 0x19},
|
||||
{0xa003, 0x0, 0x5, 0x1a},
|
||||
{0xa004, 0x0, 0x5, 0x19},
|
||||
{0xa005, 0x0, 0x5, 0x1a},
|
||||
{0xa008, 0x0, 0x8, 0x69},
|
||||
{0xa009, 0x0, 0x2, 0x2},
|
||||
{0xae1b, 0x0, 0x8, 0x69},
|
||||
{0xae1c, 0x0, 0x8, 0x2},
|
||||
{0xae1d, 0x0, 0x8, 0x2a},
|
||||
{0xa022, 0x0, 0x8, 0xaa},
|
||||
{0xa006, 0x0, 0x8, 0xc8},
|
||||
{0xa007, 0x0, 0x2, 0x0},
|
||||
{0xa00c, 0x0, 0x8, 0xba},
|
||||
{0xa00d, 0x0, 0x2, 0x2},
|
||||
{0xa608, 0x0, 0x8, 0xba},
|
||||
{0xa60e, 0x0, 0x2, 0x2},
|
||||
{0xa609, 0x0, 0x8, 0x80},
|
||||
{0xa60e, 0x2, 0x2, 0x3},
|
||||
{0xa00a, 0x0, 0x8, 0xb6},
|
||||
{0xa00b, 0x0, 0x2, 0x0},
|
||||
{0xa011, 0x0, 0x8, 0xb9},
|
||||
{0xa012, 0x0, 0x2, 0x0},
|
||||
{0xa013, 0x0, 0x8, 0xbd},
|
||||
{0xa014, 0x0, 0x2, 0x2},
|
||||
{0xa366, 0x0, 0x1, 0x1},
|
||||
{0xa2bc, 0x3, 0x1, 0x0},
|
||||
{0xa2bd, 0x0, 0x8, 0xa},
|
||||
{0xa2be, 0x0, 0x8, 0x14},
|
||||
{0xa2bf, 0x0, 0x8, 0x8},
|
||||
{0xa60a, 0x0, 0x8, 0xbd},
|
||||
{0xa60e, 0x4, 0x2, 0x2},
|
||||
{0xa60b, 0x0, 0x8, 0x86},
|
||||
{0xa60e, 0x6, 0x2, 0x3},
|
||||
{0xa001, 0x2, 0x2, 0x1},
|
||||
{0xa1c7, 0x0, 0x8, 0xf5},
|
||||
{0xa03d, 0x0, 0x8, 0xb1},
|
||||
{0xa616, 0x0, 0x8, 0xff},
|
||||
{0xa617, 0x0, 0x8, 0xad},
|
||||
{0xa618, 0x0, 0x8, 0xad},
|
||||
{0xa61e, 0x3, 0x1, 0x1},
|
||||
{0xae1a, 0x0, 0x8, 0x0},
|
||||
{0xae19, 0x0, 0x8, 0xc8},
|
||||
{0xae18, 0x0, 0x8, 0x61},
|
||||
{0xa140, 0x0, 0x8, 0x0},
|
||||
{0xa141, 0x0, 0x8, 0xc8},
|
||||
{0xa142, 0x0, 0x7, 0x61},
|
||||
{0xa023, 0x0, 0x8, 0xff},
|
||||
{0xa021, 0x0, 0x8, 0xad},
|
||||
{0xa026, 0x0, 0x1, 0x0},
|
||||
{0xa024, 0x0, 0x8, 0xff},
|
||||
{0xa025, 0x0, 0x8, 0xff},
|
||||
{0xa1c8, 0x0, 0x8, 0xf},
|
||||
{0xa2bc, 0x1, 0x1, 0x0},
|
||||
{0xa60c, 0x0, 0x4, 0x5},
|
||||
{0xa60c, 0x4, 0x4, 0x6},
|
||||
{0xa60d, 0x0, 0x8, 0xa},
|
||||
{0xa371, 0x0, 0x1, 0x1},
|
||||
{0xa366, 0x1, 0x3, 0x7},
|
||||
{0xa338, 0x0, 0x8, 0x10},
|
||||
{0xa339, 0x0, 0x6, 0x7},
|
||||
{0xa33a, 0x0, 0x6, 0x1f},
|
||||
{0xa33b, 0x0, 0x8, 0xf6},
|
||||
{0xa33c, 0x3, 0x5, 0x4},
|
||||
{0xa33d, 0x4, 0x4, 0x0},
|
||||
{0xa33d, 0x1, 0x1, 0x1},
|
||||
{0xa33d, 0x2, 0x1, 0x1},
|
||||
{0xa33d, 0x3, 0x1, 0x1},
|
||||
{0xa16d, 0x0, 0x4, 0xf},
|
||||
{0xa161, 0x0, 0x5, 0x5},
|
||||
{0xa162, 0x0, 0x4, 0x5},
|
||||
{0xa165, 0x0, 0x8, 0xff},
|
||||
{0xa166, 0x0, 0x8, 0x9c},
|
||||
{0xa2c3, 0x0, 0x4, 0x5},
|
||||
{0xa61a, 0x0, 0x6, 0xf},
|
||||
{0xb200, 0x0, 0x8, 0xa1},
|
||||
{0xb201, 0x0, 0x8, 0x7},
|
||||
{0xa093, 0x0, 0x1, 0x0},
|
||||
{0xa093, 0x1, 0x5, 0xf},
|
||||
{0xa094, 0x0, 0x8, 0xff},
|
||||
{0xa095, 0x0, 0x8, 0xf},
|
||||
{0xa080, 0x2, 0x5, 0x3},
|
||||
{0xa081, 0x0, 0x4, 0x0},
|
||||
{0xa081, 0x4, 0x4, 0x9},
|
||||
{0xa082, 0x0, 0x5, 0x1f},
|
||||
{0xa08d, 0x0, 0x8, 0x1},
|
||||
{0xa083, 0x0, 0x8, 0x32},
|
||||
{0xa084, 0x0, 0x1, 0x0},
|
||||
{0xa08e, 0x0, 0x8, 0x3},
|
||||
{0xa085, 0x0, 0x8, 0x32},
|
||||
{0xa086, 0x0, 0x3, 0x0},
|
||||
{0xa087, 0x0, 0x8, 0x6e},
|
||||
{0xa088, 0x0, 0x5, 0x15},
|
||||
{0xa089, 0x0, 0x8, 0x0},
|
||||
{0xa08a, 0x0, 0x5, 0x19},
|
||||
{0xa08b, 0x0, 0x8, 0x92},
|
||||
{0xa08c, 0x0, 0x5, 0x1c},
|
||||
{0xa120, 0x0, 0x8, 0x0},
|
||||
{0xa121, 0x0, 0x5, 0x10},
|
||||
{0xa122, 0x0, 0x8, 0x0},
|
||||
{0xa123, 0x0, 0x7, 0x40},
|
||||
{0xa123, 0x7, 0x1, 0x0},
|
||||
{0xa124, 0x0, 0x8, 0x13},
|
||||
{0xa125, 0x0, 0x7, 0x10},
|
||||
{0xa1c0, 0x0, 0x8, 0x0},
|
||||
{0xa1c1, 0x0, 0x5, 0x4},
|
||||
{0xa1c2, 0x0, 0x8, 0x0},
|
||||
{0xa1c3, 0x0, 0x5, 0x10},
|
||||
{0xa1c3, 0x5, 0x3, 0x0},
|
||||
{0xa1c4, 0x0, 0x6, 0x0},
|
||||
{0xa1c5, 0x0, 0x7, 0x10},
|
||||
{0xa100, 0x0, 0x8, 0x0},
|
||||
{0xa101, 0x0, 0x5, 0x10},
|
||||
{0xa102, 0x0, 0x8, 0x0},
|
||||
{0xa103, 0x0, 0x7, 0x40},
|
||||
{0xa103, 0x7, 0x1, 0x0},
|
||||
{0xa104, 0x0, 0x8, 0x18},
|
||||
{0xa105, 0x0, 0x7, 0xa},
|
||||
{0xa106, 0x0, 0x8, 0x20},
|
||||
{0xa107, 0x0, 0x8, 0x40},
|
||||
{0xa108, 0x0, 0x4, 0x0},
|
||||
{0xa38c, 0x0, 0x8, 0xfc},
|
||||
{0xa38d, 0x0, 0x8, 0x0},
|
||||
{0xa38e, 0x0, 0x8, 0x7e},
|
||||
{0xa38f, 0x0, 0x8, 0x0},
|
||||
{0xa390, 0x0, 0x8, 0x2f},
|
||||
{0xa60f, 0x5, 0x1, 0x1},
|
||||
{0xa170, 0x0, 0x8, 0xdc},
|
||||
{0xa171, 0x0, 0x2, 0x0},
|
||||
{0xa2ae, 0x0, 0x1, 0x1},
|
||||
{0xa2ae, 0x1, 0x1, 0x1},
|
||||
{0xa392, 0x0, 0x1, 0x1},
|
||||
{0xa391, 0x2, 0x1, 0x0},
|
||||
{0xabc1, 0x0, 0x8, 0xff},
|
||||
{0xabc2, 0x0, 0x8, 0x0},
|
||||
{0xabc8, 0x0, 0x8, 0x8},
|
||||
{0xabca, 0x0, 0x8, 0x10},
|
||||
{0xabcb, 0x0, 0x1, 0x0},
|
||||
{0xabc3, 0x5, 0x3, 0x7},
|
||||
{0xabc0, 0x6, 0x1, 0x0},
|
||||
{0xabc0, 0x4, 0x2, 0x0},
|
||||
{0xa344, 0x4, 0x4, 0x1},
|
||||
{0xabc0, 0x7, 0x1, 0x1},
|
||||
{0xabc0, 0x2, 0x1, 0x1},
|
||||
{0xa345, 0x0, 0x8, 0x66},
|
||||
{0xa346, 0x0, 0x8, 0x66},
|
||||
{0xa347, 0x0, 0x4, 0x0},
|
||||
{0xa343, 0x0, 0x4, 0xa},
|
||||
{0xa347, 0x4, 0x4, 0x2},
|
||||
{0xa348, 0x0, 0x4, 0xc},
|
||||
{0xa348, 0x4, 0x4, 0x7},
|
||||
{0xa349, 0x0, 0x6, 0x2},
|
||||
};
|
||||
1120
drivers/media/usb/dvb-usb/af9005.c
Normal file
1120
drivers/media/usb/dvb-usb/af9005.c
Normal file
File diff suppressed because it is too large
Load diff
3496
drivers/media/usb/dvb-usb/af9005.h
Normal file
3496
drivers/media/usb/dvb-usb/af9005.h
Normal file
File diff suppressed because it is too large
Load diff
1188
drivers/media/usb/dvb-usb/az6027.c
Normal file
1188
drivers/media/usb/dvb-usb/az6027.c
Normal file
File diff suppressed because it is too large
Load diff
14
drivers/media/usb/dvb-usb/az6027.h
Normal file
14
drivers/media/usb/dvb-usb/az6027.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _DVB_USB_VP6027_H_
|
||||
#define _DVB_USB_VP6027_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "az6027"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
|
||||
extern int dvb_usb_az6027_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_az6027_debug, 0x04, args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_az6027_debug, 0x08, args)
|
||||
|
||||
#endif
|
||||
253
drivers/media/usb/dvb-usb/cinergyT2-core.c
Normal file
253
drivers/media/usb/dvb-usb/cinergyT2-core.c
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
|
||||
*
|
||||
* Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
|
||||
*
|
||||
* Based on the dvb-usb-framework code and the
|
||||
* original Terratec Cinergy T2 driver by:
|
||||
*
|
||||
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
|
||||
* Holger Waechtler <holger@qanu.de>
|
||||
*
|
||||
* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
|
||||
*
|
||||
* 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 "cinergyT2.h"
|
||||
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_cinergyt2_debug;
|
||||
|
||||
module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
|
||||
"(or-able)).");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct cinergyt2_state {
|
||||
u8 rc_counter;
|
||||
};
|
||||
|
||||
/* We are missing a release hook with usb_device data */
|
||||
static struct dvb_usb_device *cinergyt2_usb_device;
|
||||
|
||||
static struct dvb_usb_device_properties cinergyt2_properties;
|
||||
|
||||
static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
|
||||
{
|
||||
char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
|
||||
char result[64];
|
||||
return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result,
|
||||
sizeof(result), 0);
|
||||
}
|
||||
|
||||
static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable)
|
||||
{
|
||||
char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 };
|
||||
char state[3];
|
||||
return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0);
|
||||
}
|
||||
|
||||
static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION };
|
||||
char state[3];
|
||||
int ret;
|
||||
|
||||
adap->fe_adap[0].fe = cinergyt2_fe_attach(adap->dev);
|
||||
|
||||
ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state,
|
||||
sizeof(state), 0);
|
||||
if (ret < 0) {
|
||||
deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep "
|
||||
"state info\n");
|
||||
}
|
||||
|
||||
/* Copy this pointer as we are gonna need it in the release phase */
|
||||
cinergyt2_usb_device = adap->dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rc_map_table rc_map_cinergyt2_table[] = {
|
||||
{ 0x0401, KEY_POWER },
|
||||
{ 0x0402, KEY_1 },
|
||||
{ 0x0403, KEY_2 },
|
||||
{ 0x0404, KEY_3 },
|
||||
{ 0x0405, KEY_4 },
|
||||
{ 0x0406, KEY_5 },
|
||||
{ 0x0407, KEY_6 },
|
||||
{ 0x0408, KEY_7 },
|
||||
{ 0x0409, KEY_8 },
|
||||
{ 0x040a, KEY_9 },
|
||||
{ 0x040c, KEY_0 },
|
||||
{ 0x040b, KEY_VIDEO },
|
||||
{ 0x040d, KEY_REFRESH },
|
||||
{ 0x040e, KEY_SELECT },
|
||||
{ 0x040f, KEY_EPG },
|
||||
{ 0x0410, KEY_UP },
|
||||
{ 0x0414, KEY_DOWN },
|
||||
{ 0x0411, KEY_LEFT },
|
||||
{ 0x0413, KEY_RIGHT },
|
||||
{ 0x0412, KEY_OK },
|
||||
{ 0x0415, KEY_TEXT },
|
||||
{ 0x0416, KEY_INFO },
|
||||
{ 0x0417, KEY_RED },
|
||||
{ 0x0418, KEY_GREEN },
|
||||
{ 0x0419, KEY_YELLOW },
|
||||
{ 0x041a, KEY_BLUE },
|
||||
{ 0x041c, KEY_VOLUMEUP },
|
||||
{ 0x041e, KEY_VOLUMEDOWN },
|
||||
{ 0x041d, KEY_MUTE },
|
||||
{ 0x041b, KEY_CHANNELUP },
|
||||
{ 0x041f, KEY_CHANNELDOWN },
|
||||
{ 0x0440, KEY_PAUSE },
|
||||
{ 0x044c, KEY_PLAY },
|
||||
{ 0x0458, KEY_RECORD },
|
||||
{ 0x0454, KEY_PREVIOUS },
|
||||
{ 0x0448, KEY_STOP },
|
||||
{ 0x045c, KEY_NEXT }
|
||||
};
|
||||
|
||||
/* Number of keypresses to ignore before detect repeating */
|
||||
#define RC_REPEAT_DELAY 3
|
||||
|
||||
static int repeatable_keys[] = {
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_VOLUMEUP,
|
||||
KEY_VOLUMEDOWN,
|
||||
KEY_CHANNELUP,
|
||||
KEY_CHANNELDOWN
|
||||
};
|
||||
|
||||
static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct cinergyt2_state *st = d->priv;
|
||||
u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS;
|
||||
int i;
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0);
|
||||
if (key[4] == 0xff) {
|
||||
/* key repeat */
|
||||
st->rc_counter++;
|
||||
if (st->rc_counter > RC_REPEAT_DELAY) {
|
||||
for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
|
||||
if (d->last_event == repeatable_keys[i]) {
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
*event = d->last_event;
|
||||
deb_rc("repeat key, event %x\n",
|
||||
*event);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
deb_rc("repeated key (non repeatable)\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hack to pass checksum on the custom field */
|
||||
key[2] = ~key[1];
|
||||
dvb_usb_nec_rc_key_to_event(d, key, event, state);
|
||||
if (key[0] != 0) {
|
||||
if (*event != d->last_event)
|
||||
st->rc_counter = 0;
|
||||
|
||||
deb_rc("key: %*ph\n", 5, key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
return dvb_usb_device_init(intf, &cinergyt2_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
}
|
||||
|
||||
|
||||
static struct usb_device_id cinergyt2_usb_table[] = {
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties cinergyt2_properties = {
|
||||
.size_of_priv = sizeof(struct cinergyt2_state),
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.streaming_ctrl = cinergyt2_streaming_ctrl,
|
||||
.frontend_attach = cinergyt2_frontend_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = cinergyt2_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 50,
|
||||
.rc_map_table = rc_map_cinergyt2_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table),
|
||||
.rc_query = cinergyt2_rc_query,
|
||||
},
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 1,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver",
|
||||
.cold_ids = {NULL},
|
||||
.warm_ids = { &cinergyt2_usb_table[0], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static struct usb_driver cinergyt2_driver = {
|
||||
.name = "cinergyT2",
|
||||
.probe = cinergyt2_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = cinergyt2_usb_table
|
||||
};
|
||||
|
||||
module_usb_driver(cinergyt2_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Tomi Orava");
|
||||
355
drivers/media/usb/dvb-usb/cinergyT2-fe.c
Normal file
355
drivers/media/usb/dvb-usb/cinergyT2-fe.c
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
|
||||
*
|
||||
* Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
|
||||
*
|
||||
* Based on the dvb-usb-framework code and the
|
||||
* original Terratec Cinergy T2 driver by:
|
||||
*
|
||||
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
|
||||
* Holger Waechtler <holger@qanu.de>
|
||||
*
|
||||
* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
|
||||
*
|
||||
* 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 "cinergyT2.h"
|
||||
|
||||
|
||||
/**
|
||||
* convert linux-dvb frontend parameter set into TPS.
|
||||
* See ETSI ETS-300744, section 4.6.2, table 9 for details.
|
||||
*
|
||||
* This function is probably reusable and may better get placed in a support
|
||||
* library.
|
||||
*
|
||||
* We replace errornous fields by default TPS fields (the ones with value 0).
|
||||
*/
|
||||
|
||||
static uint16_t compute_tps(struct dtv_frontend_properties *op)
|
||||
{
|
||||
uint16_t tps = 0;
|
||||
|
||||
switch (op->code_rate_HP) {
|
||||
case FEC_2_3:
|
||||
tps |= (1 << 7);
|
||||
break;
|
||||
case FEC_3_4:
|
||||
tps |= (2 << 7);
|
||||
break;
|
||||
case FEC_5_6:
|
||||
tps |= (3 << 7);
|
||||
break;
|
||||
case FEC_7_8:
|
||||
tps |= (4 << 7);
|
||||
break;
|
||||
case FEC_1_2:
|
||||
case FEC_AUTO:
|
||||
default:
|
||||
/* tps |= (0 << 7) */;
|
||||
}
|
||||
|
||||
switch (op->code_rate_LP) {
|
||||
case FEC_2_3:
|
||||
tps |= (1 << 4);
|
||||
break;
|
||||
case FEC_3_4:
|
||||
tps |= (2 << 4);
|
||||
break;
|
||||
case FEC_5_6:
|
||||
tps |= (3 << 4);
|
||||
break;
|
||||
case FEC_7_8:
|
||||
tps |= (4 << 4);
|
||||
break;
|
||||
case FEC_1_2:
|
||||
case FEC_AUTO:
|
||||
default:
|
||||
/* tps |= (0 << 4) */;
|
||||
}
|
||||
|
||||
switch (op->modulation) {
|
||||
case QAM_16:
|
||||
tps |= (1 << 13);
|
||||
break;
|
||||
case QAM_64:
|
||||
tps |= (2 << 13);
|
||||
break;
|
||||
case QPSK:
|
||||
default:
|
||||
/* tps |= (0 << 13) */;
|
||||
}
|
||||
|
||||
switch (op->transmission_mode) {
|
||||
case TRANSMISSION_MODE_8K:
|
||||
tps |= (1 << 0);
|
||||
break;
|
||||
case TRANSMISSION_MODE_2K:
|
||||
default:
|
||||
/* tps |= (0 << 0) */;
|
||||
}
|
||||
|
||||
switch (op->guard_interval) {
|
||||
case GUARD_INTERVAL_1_16:
|
||||
tps |= (1 << 2);
|
||||
break;
|
||||
case GUARD_INTERVAL_1_8:
|
||||
tps |= (2 << 2);
|
||||
break;
|
||||
case GUARD_INTERVAL_1_4:
|
||||
tps |= (3 << 2);
|
||||
break;
|
||||
case GUARD_INTERVAL_1_32:
|
||||
default:
|
||||
/* tps |= (0 << 2) */;
|
||||
}
|
||||
|
||||
switch (op->hierarchy) {
|
||||
case HIERARCHY_1:
|
||||
tps |= (1 << 10);
|
||||
break;
|
||||
case HIERARCHY_2:
|
||||
tps |= (2 << 10);
|
||||
break;
|
||||
case HIERARCHY_4:
|
||||
tps |= (3 << 10);
|
||||
break;
|
||||
case HIERARCHY_NONE:
|
||||
default:
|
||||
/* tps |= (0 << 10) */;
|
||||
}
|
||||
|
||||
return tps;
|
||||
}
|
||||
|
||||
struct cinergyt2_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
struct dvb_usb_device *d;
|
||||
};
|
||||
|
||||
static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
|
||||
fe_status_t *status)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg result;
|
||||
u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
|
||||
sizeof(result), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (0xffff - le16_to_cpu(result.gain) > 30)
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
if (result.lock_bits & (1 << 6))
|
||||
*status |= FE_HAS_LOCK;
|
||||
if (result.lock_bits & (1 << 5))
|
||||
*status |= FE_HAS_SYNC;
|
||||
if (result.lock_bits & (1 << 4))
|
||||
*status |= FE_HAS_CARRIER;
|
||||
if (result.lock_bits & (1 << 1))
|
||||
*status |= FE_HAS_VITERBI;
|
||||
|
||||
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 cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*ber = le32_to_cpu(status.viterbi_error_rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0) {
|
||||
err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
*unc = le32_to_cpu(status.uncorrected_block_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *strength)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0) {
|
||||
err("cinergyt2_fe_read_signal_strength() Failed!"
|
||||
" (Error=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*strength = (0xffff - le16_to_cpu(status.gain));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_get_status_msg status;
|
||||
char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
|
||||
sizeof(status), 0);
|
||||
if (ret < 0) {
|
||||
err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*snr = (status.snr << 8) | status.snr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_init(struct dvb_frontend *fe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
deb_info("cinergyt2_fe_sleep() Called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 800;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
struct dvbt_set_parameters_msg param;
|
||||
char result[2];
|
||||
int err;
|
||||
|
||||
param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
|
||||
param.tps = cpu_to_le16(compute_tps(fep));
|
||||
param.freq = cpu_to_le32(fep->frequency / 1000);
|
||||
param.flags = 0;
|
||||
|
||||
switch (fep->bandwidth_hz) {
|
||||
default:
|
||||
case 8000000:
|
||||
param.bandwidth = 8;
|
||||
break;
|
||||
case 7000000:
|
||||
param.bandwidth = 7;
|
||||
break;
|
||||
case 6000000:
|
||||
param.bandwidth = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
err = dvb_usb_generic_rw(state->d,
|
||||
(char *)¶m, sizeof(param),
|
||||
result, sizeof(result), 0);
|
||||
if (err < 0)
|
||||
err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
static void cinergyt2_fe_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct cinergyt2_fe_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops cinergyt2_fe_ops;
|
||||
|
||||
struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct cinergyt2_fe_state *s = kzalloc(sizeof(
|
||||
struct cinergyt2_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->d = d;
|
||||
memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
return &s->fe;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops cinergyt2_fe_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = DRIVER_NAME,
|
||||
.frequency_min = 174000000,
|
||||
.frequency_max = 862000000,
|
||||
.frequency_stepsize = 166667,
|
||||
.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_HIERARCHY_AUTO
|
||||
| FE_CAN_RECOVER
|
||||
| FE_CAN_MUTE_TS
|
||||
},
|
||||
|
||||
.release = cinergyt2_fe_release,
|
||||
|
||||
.init = cinergyt2_fe_init,
|
||||
.sleep = cinergyt2_fe_sleep,
|
||||
|
||||
.set_frontend = cinergyt2_fe_set_frontend,
|
||||
.get_tune_settings = cinergyt2_fe_get_tune_settings,
|
||||
|
||||
.read_status = cinergyt2_fe_read_status,
|
||||
.read_ber = cinergyt2_fe_read_ber,
|
||||
.read_signal_strength = cinergyt2_fe_read_signal_strength,
|
||||
.read_snr = cinergyt2_fe_read_snr,
|
||||
.read_ucblocks = cinergyt2_fe_read_unc_blocks,
|
||||
};
|
||||
95
drivers/media/usb/dvb-usb/cinergyT2.h
Normal file
95
drivers/media/usb/dvb-usb/cinergyT2.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
|
||||
*
|
||||
* Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
|
||||
*
|
||||
* Based on the dvb-usb-framework code and the
|
||||
* original Terratec Cinergy T2 driver by:
|
||||
*
|
||||
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
|
||||
* Holger Waechtler <holger@qanu.de>
|
||||
*
|
||||
* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
|
||||
*
|
||||
* 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 _DVB_USB_CINERGYT2_H_
|
||||
#define _DVB_USB_CINERGYT2_H_
|
||||
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "cinergyT2"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
|
||||
|
||||
extern int dvb_usb_cinergyt2_debug;
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args)
|
||||
#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args)
|
||||
#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args)
|
||||
#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args)
|
||||
#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args)
|
||||
#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args)
|
||||
|
||||
|
||||
|
||||
enum cinergyt2_ep1_cmd {
|
||||
CINERGYT2_EP1_PID_TABLE_RESET = 0x01,
|
||||
CINERGYT2_EP1_PID_SETUP = 0x02,
|
||||
CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03,
|
||||
CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04,
|
||||
CINERGYT2_EP1_GET_TUNER_STATUS = 0x05,
|
||||
CINERGYT2_EP1_START_SCAN = 0x06,
|
||||
CINERGYT2_EP1_CONTINUE_SCAN = 0x07,
|
||||
CINERGYT2_EP1_GET_RC_EVENTS = 0x08,
|
||||
CINERGYT2_EP1_SLEEP_MODE = 0x09,
|
||||
CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A
|
||||
};
|
||||
|
||||
|
||||
struct dvbt_get_status_msg {
|
||||
uint32_t freq;
|
||||
uint8_t bandwidth;
|
||||
uint16_t tps;
|
||||
uint8_t flags;
|
||||
__le16 gain;
|
||||
uint8_t snr;
|
||||
__le32 viterbi_error_rate;
|
||||
uint32_t rs_error_rate;
|
||||
__le32 uncorrected_block_count;
|
||||
uint8_t lock_bits;
|
||||
uint8_t prev_lock_bits;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
struct dvbt_set_parameters_msg {
|
||||
uint8_t cmd;
|
||||
__le32 freq;
|
||||
uint8_t bandwidth;
|
||||
__le16 tps;
|
||||
uint8_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d);
|
||||
|
||||
#endif /* _DVB_USB_CINERGYT2_H_ */
|
||||
|
||||
2418
drivers/media/usb/dvb-usb/cxusb.c
Normal file
2418
drivers/media/usb/dvb-usb/cxusb.c
Normal file
File diff suppressed because it is too large
Load diff
41
drivers/media/usb/dvb-usb/cxusb.h
Normal file
41
drivers/media/usb/dvb-usb/cxusb.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef _DVB_USB_CXUSB_H_
|
||||
#define _DVB_USB_CXUSB_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "cxusb"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
/* usb commands - some of it are guesses, don't have a reference yet */
|
||||
#define CMD_BLUEBIRD_GPIO_RW 0x05
|
||||
|
||||
#define CMD_I2C_WRITE 0x08
|
||||
#define CMD_I2C_READ 0x09
|
||||
|
||||
#define CMD_GPIO_READ 0x0d
|
||||
#define CMD_GPIO_WRITE 0x0e
|
||||
#define GPIO_TUNER 0x02
|
||||
|
||||
#define CMD_POWER_OFF 0xdc
|
||||
#define CMD_POWER_ON 0xde
|
||||
|
||||
#define CMD_STREAMING_ON 0x36
|
||||
#define CMD_STREAMING_OFF 0x37
|
||||
|
||||
#define CMD_AVER_STREAM_ON 0x18
|
||||
#define CMD_AVER_STREAM_OFF 0x19
|
||||
|
||||
#define CMD_GET_IR_CODE 0x47
|
||||
|
||||
#define CMD_ANALOG 0x50
|
||||
#define CMD_DIGITAL 0x51
|
||||
|
||||
#define CMD_SP2_CI_WRITE 0x70
|
||||
#define CMD_SP2_CI_READ 0x71
|
||||
|
||||
struct cxusb_state {
|
||||
u8 gpio_write_state[3];
|
||||
struct i2c_client *i2c_client_demod;
|
||||
struct i2c_client *i2c_client_tuner;
|
||||
struct i2c_client *i2c_client_ci;
|
||||
};
|
||||
|
||||
#endif
|
||||
75
drivers/media/usb/dvb-usb/dib0700.h
Normal file
75
drivers/media/usb/dvb-usb/dib0700.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2005-6 DiBcom, SA
|
||||
*/
|
||||
#ifndef _DIB0700_H_
|
||||
#define _DIB0700_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dib0700"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "dib07x0.h"
|
||||
|
||||
extern int dvb_usb_dib0700_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args)
|
||||
#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
|
||||
#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args)
|
||||
|
||||
#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */
|
||||
/* higher than 1.21 */
|
||||
#define REQUEST_I2C_READ 0x2
|
||||
#define REQUEST_I2C_WRITE 0x3
|
||||
#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */
|
||||
#define REQUEST_JUMPRAM 0x8
|
||||
#define REQUEST_SET_CLOCK 0xB
|
||||
#define REQUEST_SET_GPIO 0xC
|
||||
#define REQUEST_ENABLE_VIDEO 0xF
|
||||
// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
|
||||
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
|
||||
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
|
||||
#define REQUEST_SET_I2C_PARAM 0x10
|
||||
#define REQUEST_SET_RC 0x11
|
||||
#define REQUEST_NEW_I2C_READ 0x12
|
||||
#define REQUEST_NEW_I2C_WRITE 0x13
|
||||
#define REQUEST_GET_VERSION 0x15
|
||||
|
||||
struct dib0700_state {
|
||||
u8 channel_state;
|
||||
u16 mt2060_if1[2];
|
||||
u8 rc_toggle;
|
||||
u8 rc_counter;
|
||||
u8 is_dib7000pc;
|
||||
u8 fw_use_new_i2c_api;
|
||||
u8 disable_streaming_master_mode;
|
||||
u32 fw_version;
|
||||
u32 nb_packet_buffer_size;
|
||||
int (*read_status)(struct dvb_frontend *, fe_status_t *);
|
||||
int (*sleep)(struct dvb_frontend* fe);
|
||||
u8 buf[255];
|
||||
};
|
||||
|
||||
extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
|
||||
u32 *romversion, u32 *ramversion, u32 *fwtype);
|
||||
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
|
||||
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
|
||||
extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
|
||||
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
|
||||
extern int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf);
|
||||
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
|
||||
extern struct i2c_algorithm dib0700_i2c_algo;
|
||||
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold);
|
||||
extern int dib0700_change_protocol(struct rc_dev *dev, u64 *rc_type);
|
||||
extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz);
|
||||
|
||||
extern int dib0700_device_count;
|
||||
extern int dvb_usb_dib0700_ir_proto;
|
||||
extern struct dvb_usb_device_properties dib0700_devices[];
|
||||
extern struct usb_device_id dib0700_usb_id_table[];
|
||||
|
||||
#endif
|
||||
880
drivers/media/usb/dvb-usb/dib0700_core.c
Normal file
880
drivers/media/usb/dvb-usb/dib0700_core.c
Normal file
|
|
@ -0,0 +1,880 @@
|
|||
/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2005-6 DiBcom, SA
|
||||
*/
|
||||
#include "dib0700.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_dib0700_debug;
|
||||
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int nb_packet_buffer_size = 21;
|
||||
module_param(nb_packet_buffer_size, int, 0644);
|
||||
MODULE_PARM_DESC(nb_packet_buffer_size,
|
||||
"Set the dib0700 driver data buffer size. This parameter "
|
||||
"corresponds to the number of TS packets. The actual size of "
|
||||
"the data buffer corresponds to this parameter "
|
||||
"multiplied by 188 (default: 21)");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
|
||||
int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
|
||||
u32 *romversion, u32 *ramversion, u32 *fwtype)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
|
||||
REQUEST_GET_VERSION,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
|
||||
st->buf, 16, USB_CTRL_GET_TIMEOUT);
|
||||
if (hwversion != NULL)
|
||||
*hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) |
|
||||
(st->buf[2] << 8) | st->buf[3];
|
||||
if (romversion != NULL)
|
||||
*romversion = (st->buf[4] << 24) | (st->buf[5] << 16) |
|
||||
(st->buf[6] << 8) | st->buf[7];
|
||||
if (ramversion != NULL)
|
||||
*ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) |
|
||||
(st->buf[10] << 8) | st->buf[11];
|
||||
if (fwtype != NULL)
|
||||
*fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
|
||||
(st->buf[14] << 8) | st->buf[15];
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* expecting rx buffer: request data[0] data[1] ... data[2] */
|
||||
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
|
||||
{
|
||||
int status;
|
||||
|
||||
deb_data(">>> ");
|
||||
debug_dump(tx, txlen, deb_data);
|
||||
|
||||
status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
|
||||
tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
|
||||
if (status != txlen)
|
||||
deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
|
||||
|
||||
return status < 0 ? status : 0;
|
||||
}
|
||||
|
||||
/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
|
||||
int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
|
||||
{
|
||||
u16 index, value;
|
||||
int status;
|
||||
|
||||
if (txlen < 2) {
|
||||
err("tx buffer length is smaller than 2. Makes no sense.");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (txlen > 4) {
|
||||
err("tx buffer length is larger than 4. Not supported.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
deb_data(">>> ");
|
||||
debug_dump(tx,txlen,deb_data);
|
||||
|
||||
value = ((txlen - 2) << 8) | tx[1];
|
||||
index = 0;
|
||||
if (txlen > 2)
|
||||
index |= (tx[2] << 8);
|
||||
if (txlen > 3)
|
||||
index |= tx[3];
|
||||
|
||||
status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
|
||||
USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
|
||||
if (status < 0)
|
||||
deb_info("ep 0 read error (status = %d)\n",status);
|
||||
|
||||
deb_data("<<< ");
|
||||
debug_dump(rx, rxlen, deb_data);
|
||||
|
||||
return status; /* length in case of success */
|
||||
}
|
||||
|
||||
int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
st->buf[0] = REQUEST_SET_GPIO;
|
||||
st->buf[1] = gpio;
|
||||
st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
|
||||
|
||||
ret = dib0700_ctrl_wr(d, st->buf, 3);
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
int ret;
|
||||
|
||||
if (st->fw_version >= 0x10201) {
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
st->buf[0] = REQUEST_SET_USB_XFER_LEN;
|
||||
st->buf[1] = (nb_ts_packets >> 8) & 0xff;
|
||||
st->buf[2] = nb_ts_packets & 0xff;
|
||||
|
||||
deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
|
||||
|
||||
ret = dib0700_ctrl_wr(d, st->buf, 3);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
} else {
|
||||
deb_info("this firmware does not allow to change the USB xfer len\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C master xfer function (supported in 1.20 firmware)
|
||||
*/
|
||||
static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
/* The new i2c firmware messages are more reliable and in particular
|
||||
properly support i2c read calls not preceded by a write */
|
||||
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct dib0700_state *st = d->priv;
|
||||
uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */
|
||||
uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
|
||||
uint8_t en_start = 0;
|
||||
uint8_t en_stop = 0;
|
||||
int result, i;
|
||||
|
||||
/* Ensure nobody else hits the i2c bus while we're sending our
|
||||
sequence of messages, (such as the remote control thread) */
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EINTR;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (i == 0) {
|
||||
/* First message in the transaction */
|
||||
en_start = 1;
|
||||
} else if (!(msg[i].flags & I2C_M_NOSTART)) {
|
||||
/* Device supports repeated-start */
|
||||
en_start = 1;
|
||||
} else {
|
||||
/* Not the first packet and device doesn't support
|
||||
repeated start */
|
||||
en_start = 0;
|
||||
}
|
||||
if (i == (num - 1)) {
|
||||
/* Last message in the transaction */
|
||||
en_stop = 1;
|
||||
}
|
||||
|
||||
if (msg[i].flags & I2C_M_RD) {
|
||||
/* Read request */
|
||||
u16 index, value;
|
||||
uint8_t i2c_dest;
|
||||
|
||||
i2c_dest = (msg[i].addr << 1);
|
||||
value = ((en_start << 7) | (en_stop << 6) |
|
||||
(msg[i].len & 0x3F)) << 8 | i2c_dest;
|
||||
/* I2C ctrl + FE bus; */
|
||||
index = ((gen_mode << 6) & 0xC0) |
|
||||
((bus_mode << 4) & 0x30);
|
||||
|
||||
result = usb_control_msg(d->udev,
|
||||
usb_rcvctrlpipe(d->udev, 0),
|
||||
REQUEST_NEW_I2C_READ,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, msg[i].buf,
|
||||
msg[i].len,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (result < 0) {
|
||||
deb_info("i2c read error (status = %d)\n", result);
|
||||
break;
|
||||
}
|
||||
|
||||
deb_data("<<< ");
|
||||
debug_dump(msg[i].buf, msg[i].len, deb_data);
|
||||
|
||||
} else {
|
||||
/* Write request */
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return -EINTR;
|
||||
}
|
||||
st->buf[0] = REQUEST_NEW_I2C_WRITE;
|
||||
st->buf[1] = msg[i].addr << 1;
|
||||
st->buf[2] = (en_start << 7) | (en_stop << 6) |
|
||||
(msg[i].len & 0x3F);
|
||||
/* I2C ctrl + FE bus; */
|
||||
st->buf[3] = ((gen_mode << 6) & 0xC0) |
|
||||
((bus_mode << 4) & 0x30);
|
||||
/* The Actual i2c payload */
|
||||
memcpy(&st->buf[4], msg[i].buf, msg[i].len);
|
||||
|
||||
deb_data(">>> ");
|
||||
debug_dump(st->buf, msg[i].len + 4, deb_data);
|
||||
|
||||
result = usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev, 0),
|
||||
REQUEST_NEW_I2C_WRITE,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
0, 0, st->buf, msg[i].len + 4,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
if (result < 0) {
|
||||
deb_info("i2c write error (status = %d)\n", result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C master xfer function (pre-1.20 firmware)
|
||||
*/
|
||||
static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct dib0700_state *st = d->priv;
|
||||
int i,len;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EINTR;
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* fill in the address */
|
||||
st->buf[1] = msg[i].addr << 1;
|
||||
/* fill the buffer */
|
||||
memcpy(&st->buf[2], msg[i].buf, msg[i].len);
|
||||
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
st->buf[0] = REQUEST_I2C_READ;
|
||||
st->buf[1] |= 1;
|
||||
|
||||
/* special thing in the current firmware: when length is zero the read-failed */
|
||||
len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
|
||||
msg[i+1].buf, msg[i+1].len);
|
||||
if (len <= 0) {
|
||||
deb_info("I2C read failed on address 0x%02x\n",
|
||||
msg[i].addr);
|
||||
break;
|
||||
}
|
||||
|
||||
msg[i+1].len = len;
|
||||
|
||||
i++;
|
||||
} else {
|
||||
st->buf[0] = REQUEST_I2C_WRITE;
|
||||
if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct dib0700_state *st = d->priv;
|
||||
|
||||
if (st->fw_use_new_i2c_api == 1) {
|
||||
/* User running at least fw 1.20 */
|
||||
return dib0700_i2c_xfer_new(adap, msg, num);
|
||||
} else {
|
||||
/* Use legacy calls */
|
||||
return dib0700_i2c_xfer_legacy(adap, msg, num);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
struct i2c_algorithm dib0700_i2c_algo = {
|
||||
.master_xfer = dib0700_i2c_xfer,
|
||||
.functionality = dib0700_i2c_func,
|
||||
};
|
||||
|
||||
int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold)
|
||||
{
|
||||
s16 ret;
|
||||
u8 *b;
|
||||
|
||||
b = kmalloc(16, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
|
||||
|
||||
deb_info("FW GET_VERSION length: %d\n",ret);
|
||||
|
||||
*cold = ret <= 0;
|
||||
deb_info("cold: %d\n", *cold);
|
||||
|
||||
kfree(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
|
||||
u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
|
||||
u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
st->buf[0] = REQUEST_SET_CLOCK;
|
||||
st->buf[1] = (en_pll << 7) | (pll_src << 6) |
|
||||
(pll_range << 5) | (clock_gpio3 << 4);
|
||||
st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */
|
||||
st->buf[3] = pll_prediv & 0xff; /* LSB */
|
||||
st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
|
||||
st->buf[5] = pll_loopdiv & 0xff; /* LSB */
|
||||
st->buf[6] = (free_div >> 8) & 0xff; /* MSB */
|
||||
st->buf[7] = free_div & 0xff; /* LSB */
|
||||
st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */
|
||||
st->buf[9] = dsuScaler & 0xff; /* LSB */
|
||||
|
||||
ret = dib0700_ctrl_wr(d, st->buf, 10);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
u16 divider;
|
||||
int ret;
|
||||
|
||||
if (scl_kHz == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
st->buf[0] = REQUEST_SET_I2C_PARAM;
|
||||
divider = (u16) (30000 / scl_kHz);
|
||||
st->buf[1] = 0;
|
||||
st->buf[2] = (u8) (divider >> 8);
|
||||
st->buf[3] = (u8) (divider & 0xff);
|
||||
divider = (u16) (72000 / scl_kHz);
|
||||
st->buf[4] = (u8) (divider >> 8);
|
||||
st->buf[5] = (u8) (divider & 0xff);
|
||||
divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
|
||||
st->buf[6] = (u8) (divider >> 8);
|
||||
st->buf[7] = (u8) (divider & 0xff);
|
||||
|
||||
deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
|
||||
(st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
|
||||
st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
|
||||
|
||||
ret = dib0700_ctrl_wr(d, st->buf, 8);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
|
||||
{
|
||||
switch (clk_MHz) {
|
||||
case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dib0700_jumpram(struct usb_device *udev, u32 address)
|
||||
{
|
||||
int ret = 0, actlen;
|
||||
u8 *buf;
|
||||
|
||||
buf = kmalloc(8, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
buf[0] = REQUEST_JUMPRAM;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
buf[3] = 0;
|
||||
buf[4] = (address >> 24) & 0xff;
|
||||
buf[5] = (address >> 16) & 0xff;
|
||||
buf[6] = (address >> 8) & 0xff;
|
||||
buf[7] = address & 0xff;
|
||||
|
||||
if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
|
||||
deb_fw("jumpram to 0x%x failed\n",address);
|
||||
goto out;
|
||||
}
|
||||
if (actlen != 8) {
|
||||
deb_fw("jumpram to 0x%x failed\n",address);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
|
||||
{
|
||||
struct hexline hx;
|
||||
int pos = 0, ret, act_len, i, adap_num;
|
||||
u8 *buf;
|
||||
u32 fw_version;
|
||||
|
||||
buf = kmalloc(260, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
|
||||
deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
|
||||
hx.addr, hx.len, hx.chk);
|
||||
|
||||
buf[0] = hx.len;
|
||||
buf[1] = (hx.addr >> 8) & 0xff;
|
||||
buf[2] = hx.addr & 0xff;
|
||||
buf[3] = hx.type;
|
||||
memcpy(&buf[4],hx.data,hx.len);
|
||||
buf[4+hx.len] = hx.chk;
|
||||
|
||||
ret = usb_bulk_msg(udev,
|
||||
usb_sndbulkpipe(udev, 0x01),
|
||||
buf,
|
||||
hx.len + 5,
|
||||
&act_len,
|
||||
1000);
|
||||
|
||||
if (ret < 0) {
|
||||
err("firmware download failed at %d with %d",pos,ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* start the firmware */
|
||||
if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
|
||||
info("firmware started successfully.");
|
||||
msleep(500);
|
||||
}
|
||||
} else
|
||||
ret = -EIO;
|
||||
|
||||
/* the number of ts packet has to be at least 1 */
|
||||
if (nb_packet_buffer_size < 1)
|
||||
nb_packet_buffer_size = 1;
|
||||
|
||||
/* get the fimware version */
|
||||
usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
REQUEST_GET_VERSION,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
|
||||
buf, 16, USB_CTRL_GET_TIMEOUT);
|
||||
fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
|
||||
|
||||
/* set the buffer size - DVB-USB is allocating URB buffers
|
||||
* only after the firwmare download was successful */
|
||||
for (i = 0; i < dib0700_device_count; i++) {
|
||||
for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
|
||||
adap_num++) {
|
||||
if (fw_version >= 0x10201) {
|
||||
dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
|
||||
} else {
|
||||
/* for fw version older than 1.20.1,
|
||||
* the buffersize has to be n times 512 */
|
||||
dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
|
||||
if (dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize < 512)
|
||||
dib0700_devices[i].adapter[adap_num].fe[0].stream.u.bulk.buffersize = 512;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
struct dib0700_state *st = adap->dev->priv;
|
||||
int ret;
|
||||
|
||||
if ((onoff != 0) && (st->fw_version >= 0x10201)) {
|
||||
/* for firmware later than 1.20.1,
|
||||
* the USB xfer length can be set */
|
||||
ret = dib0700_set_usb_xfer_len(adap->dev,
|
||||
st->nb_packet_buffer_size);
|
||||
if (ret < 0) {
|
||||
deb_info("can not set the USB xfer len\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&adap->dev->usb_mutex);
|
||||
|
||||
st->buf[0] = REQUEST_ENABLE_VIDEO;
|
||||
/* this bit gives a kind of command,
|
||||
* rather than enabling something or not */
|
||||
st->buf[1] = (onoff << 4) | 0x00;
|
||||
|
||||
if (st->disable_streaming_master_mode == 1)
|
||||
st->buf[2] = 0x00;
|
||||
else
|
||||
st->buf[2] = 0x01 << 4; /* Master mode */
|
||||
|
||||
st->buf[3] = 0x00;
|
||||
|
||||
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
|
||||
|
||||
st->channel_state &= ~0x3;
|
||||
if ((adap->fe_adap[0].stream.props.endpoint != 2)
|
||||
&& (adap->fe_adap[0].stream.props.endpoint != 3)) {
|
||||
deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint);
|
||||
if (onoff)
|
||||
st->channel_state |= 1 << (adap->id);
|
||||
else
|
||||
st->channel_state |= 1 << ~(adap->id);
|
||||
} else {
|
||||
if (onoff)
|
||||
st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2);
|
||||
else
|
||||
st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint);
|
||||
}
|
||||
|
||||
st->buf[2] |= st->channel_state;
|
||||
|
||||
deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
|
||||
|
||||
ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
|
||||
mutex_unlock(&adap->dev->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dib0700_change_protocol(struct rc_dev *rc, u64 *rc_type)
|
||||
{
|
||||
struct dvb_usb_device *d = rc->priv;
|
||||
struct dib0700_state *st = d->priv;
|
||||
int new_proto, ret;
|
||||
|
||||
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
|
||||
err("could not acquire lock");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
st->buf[0] = REQUEST_SET_RC;
|
||||
st->buf[1] = 0;
|
||||
st->buf[2] = 0;
|
||||
|
||||
/* Set the IR mode */
|
||||
if (*rc_type & RC_BIT_RC5) {
|
||||
new_proto = 1;
|
||||
*rc_type = RC_BIT_RC5;
|
||||
} else if (*rc_type & RC_BIT_NEC) {
|
||||
new_proto = 0;
|
||||
*rc_type = RC_BIT_NEC;
|
||||
} else if (*rc_type & RC_BIT_RC6_MCE) {
|
||||
if (st->fw_version < 0x10200) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
new_proto = 2;
|
||||
*rc_type = RC_BIT_RC6_MCE;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
st->buf[1] = new_proto;
|
||||
|
||||
ret = dib0700_ctrl_wr(d, st->buf, 3);
|
||||
if (ret < 0) {
|
||||
err("ir protocol setup failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
d->props.rc.core.protocol = *rc_type;
|
||||
|
||||
out:
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Number of keypresses to ignore before start repeating */
|
||||
#define RC_REPEAT_DELAY_V1_20 10
|
||||
|
||||
/* This is the structure of the RC response packet starting in firmware 1.20 */
|
||||
struct dib0700_rc_response {
|
||||
u8 report_id;
|
||||
u8 data_state;
|
||||
u8 system;
|
||||
u8 not_system;
|
||||
u8 data;
|
||||
u8 not_data;
|
||||
};
|
||||
#define RC_MSG_SIZE_V1_20 6
|
||||
|
||||
static void dib0700_rc_urb_completion(struct urb *purb)
|
||||
{
|
||||
struct dvb_usb_device *d = purb->context;
|
||||
struct dib0700_rc_response *poll_reply;
|
||||
enum rc_type protocol;
|
||||
u32 uninitialized_var(keycode);
|
||||
u8 toggle;
|
||||
|
||||
deb_info("%s()\n", __func__);
|
||||
if (d->rc_dev == NULL) {
|
||||
/* This will occur if disable_rc_polling=1 */
|
||||
kfree(purb->transfer_buffer);
|
||||
usb_free_urb(purb);
|
||||
return;
|
||||
}
|
||||
|
||||
poll_reply = purb->transfer_buffer;
|
||||
|
||||
if (purb->status < 0) {
|
||||
deb_info("discontinuing polling\n");
|
||||
kfree(purb->transfer_buffer);
|
||||
usb_free_urb(purb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (purb->actual_length != RC_MSG_SIZE_V1_20) {
|
||||
deb_info("malformed rc msg size=%d\n", purb->actual_length);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
|
||||
poll_reply->report_id, poll_reply->data_state,
|
||||
poll_reply->system, poll_reply->not_system,
|
||||
poll_reply->data, poll_reply->not_data,
|
||||
purb->actual_length);
|
||||
|
||||
switch (d->props.rc.core.protocol) {
|
||||
case RC_BIT_NEC:
|
||||
protocol = RC_TYPE_NEC;
|
||||
toggle = 0;
|
||||
|
||||
/* NEC protocol sends repeat code as 0 0 0 FF */
|
||||
if (poll_reply->system == 0x00 &&
|
||||
poll_reply->not_system == 0x00 &&
|
||||
poll_reply->data == 0x00 &&
|
||||
poll_reply->not_data == 0xff) {
|
||||
poll_reply->data_state = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((poll_reply->data ^ poll_reply->not_data) != 0xff) {
|
||||
deb_data("NEC32 protocol\n");
|
||||
keycode = RC_SCANCODE_NEC32(poll_reply->system << 24 |
|
||||
poll_reply->not_system << 16 |
|
||||
poll_reply->data << 8 |
|
||||
poll_reply->not_data);
|
||||
} else if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
|
||||
deb_data("NEC extended protocol\n");
|
||||
keycode = RC_SCANCODE_NECX(poll_reply->system << 8 |
|
||||
poll_reply->not_system,
|
||||
poll_reply->data);
|
||||
|
||||
} else {
|
||||
deb_data("NEC normal protocol\n");
|
||||
keycode = RC_SCANCODE_NEC(poll_reply->system,
|
||||
poll_reply->data);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
deb_data("RC5 protocol\n");
|
||||
protocol = RC_TYPE_RC5;
|
||||
toggle = poll_reply->report_id;
|
||||
keycode = RC_SCANCODE_RC5(poll_reply->system, poll_reply->data);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((poll_reply->data + poll_reply->not_data) != 0xff) {
|
||||
/* Key failed integrity check */
|
||||
err("key failed integrity check: %02x %02x %02x %02x",
|
||||
poll_reply->system, poll_reply->not_system,
|
||||
poll_reply->data, poll_reply->not_data);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
rc_keydown(d->rc_dev, protocol, keycode, toggle);
|
||||
|
||||
resubmit:
|
||||
/* Clean the buffer before we requeue */
|
||||
memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
|
||||
|
||||
/* Requeue URB */
|
||||
usb_submit_urb(purb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf)
|
||||
{
|
||||
struct dib0700_state *st = d->priv;
|
||||
struct urb *purb;
|
||||
const struct usb_endpoint_descriptor *e;
|
||||
int ret, rc_ep = 1;
|
||||
unsigned int pipe = 0;
|
||||
|
||||
/* Poll-based. Don't initialize bulk mode */
|
||||
if (st->fw_version < 0x10200 || !intf)
|
||||
return 0;
|
||||
|
||||
/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
|
||||
|
||||
purb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (purb == NULL) {
|
||||
err("rc usb alloc urb failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
|
||||
if (purb->transfer_buffer == NULL) {
|
||||
err("rc kzalloc failed");
|
||||
usb_free_urb(purb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
purb->status = -EINPROGRESS;
|
||||
|
||||
/*
|
||||
* Some devices like the Hauppauge NovaTD model 52009 use an interrupt
|
||||
* endpoint, while others use a bulk one.
|
||||
*/
|
||||
e = &intf->altsetting[0].endpoint[rc_ep].desc;
|
||||
if (usb_endpoint_dir_in(e)) {
|
||||
if (usb_endpoint_xfer_bulk(e)) {
|
||||
pipe = usb_rcvbulkpipe(d->udev, rc_ep);
|
||||
usb_fill_bulk_urb(purb, d->udev, pipe,
|
||||
purb->transfer_buffer,
|
||||
RC_MSG_SIZE_V1_20,
|
||||
dib0700_rc_urb_completion, d);
|
||||
|
||||
} else if (usb_endpoint_xfer_int(e)) {
|
||||
pipe = usb_rcvintpipe(d->udev, rc_ep);
|
||||
usb_fill_int_urb(purb, d->udev, pipe,
|
||||
purb->transfer_buffer,
|
||||
RC_MSG_SIZE_V1_20,
|
||||
dib0700_rc_urb_completion, d, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pipe) {
|
||||
err("There's no endpoint for remote controller");
|
||||
kfree(purb->transfer_buffer);
|
||||
usb_free_urb(purb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = usb_submit_urb(purb, GFP_ATOMIC);
|
||||
if (ret) {
|
||||
err("rc submit urb failed");
|
||||
kfree(purb->transfer_buffer);
|
||||
usb_free_urb(purb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dib0700_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct dvb_usb_device *dev;
|
||||
|
||||
for (i = 0; i < dib0700_device_count; i++)
|
||||
if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
|
||||
&dev, adapter_nr) == 0) {
|
||||
struct dib0700_state *st = dev->priv;
|
||||
u32 hwversion, romversion, fw_version, fwtype;
|
||||
|
||||
dib0700_get_version(dev, &hwversion, &romversion,
|
||||
&fw_version, &fwtype);
|
||||
|
||||
deb_info("Firmware version: %x, %d, 0x%x, %d\n",
|
||||
hwversion, romversion, fw_version, fwtype);
|
||||
|
||||
st->fw_version = fw_version;
|
||||
st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
|
||||
|
||||
/* Disable polling mode on newer firmwares */
|
||||
if (st->fw_version >= 0x10200)
|
||||
dev->props.rc.core.bulk_mode = true;
|
||||
else
|
||||
dev->props.rc.core.bulk_mode = false;
|
||||
|
||||
dib0700_rc_setup(dev, intf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_driver dib0700_driver = {
|
||||
.name = "dvb_usb_dib0700",
|
||||
.probe = dib0700_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dib0700_usb_id_table,
|
||||
};
|
||||
|
||||
module_usb_driver(dib0700_driver);
|
||||
|
||||
MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw");
|
||||
MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
|
||||
MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
5009
drivers/media/usb/dvb-usb/dib0700_devices.c
Normal file
5009
drivers/media/usb/dvb-usb/dib0700_devices.c
Normal file
File diff suppressed because it is too large
Load diff
21
drivers/media/usb/dvb-usb/dib07x0.h
Normal file
21
drivers/media/usb/dvb-usb/dib07x0.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef _DIB07X0_H_
|
||||
#define _DIB07X0_H_
|
||||
|
||||
enum dib07x0_gpios {
|
||||
GPIO0 = 0,
|
||||
GPIO1 = 2,
|
||||
GPIO2 = 3,
|
||||
GPIO3 = 4,
|
||||
GPIO4 = 5,
|
||||
GPIO5 = 6,
|
||||
GPIO6 = 8,
|
||||
GPIO7 = 10,
|
||||
GPIO8 = 11,
|
||||
GPIO9 = 14,
|
||||
GPIO10 = 15,
|
||||
};
|
||||
|
||||
#define GPIO_IN 0
|
||||
#define GPIO_OUT 1
|
||||
|
||||
#endif
|
||||
488
drivers/media/usb/dvb-usb/dibusb-common.c
Normal file
488
drivers/media/usb/dvb-usb/dibusb-common.c
Normal file
|
|
@ -0,0 +1,488 @@
|
|||
/* 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 <linux/kconfig.h>
|
||||
#include "dibusb.h"
|
||||
|
||||
/* Max transfer size done by I2C transfer functions */
|
||||
#define MAX_XFER_SIZE 64
|
||||
|
||||
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_adapter *adap, int onoff)
|
||||
{
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
if (st->ops.fifo_ctrl != NULL)
|
||||
if (st->ops.fifo_ctrl(adap->fe_adap[0].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_adapter *adap, int index, u16 pid, int onoff)
|
||||
{
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
if (st->ops.pid_ctrl != NULL)
|
||||
st->ops.pid_ctrl(adap->fe_adap[0].fe,
|
||||
index, pid, onoff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_pid_filter);
|
||||
|
||||
int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
if (st->ops.pid_parse != NULL)
|
||||
if (st->ops.pid_parse(adap->fe_adap[0].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_adapter *adap, int onoff)
|
||||
{
|
||||
u8 b[3] = { 0 };
|
||||
int ret;
|
||||
|
||||
if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
|
||||
return ret;
|
||||
|
||||
if (onoff) {
|
||||
b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
|
||||
b[1] = 0x00;
|
||||
if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
b[0] = DIBUSB_REQ_SET_IOCTL;
|
||||
b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
|
||||
return dvb_usb_generic_write(adap->dev,b,3);
|
||||
}
|
||||
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[MAX_XFER_SIZE]; /* 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);
|
||||
|
||||
if (4 + wlen > sizeof(sndbuf)) {
|
||||
warn("i2c wr: len=%d is too big!\n", wlen);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
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 (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
|
||||
&& (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 ((msg[i].flags & I2C_M_RD) == 0) {
|
||||
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
|
||||
break;
|
||||
} else if (msg[i].addr != 0x50) {
|
||||
/* 0x50 is the address of the eeprom - we need to protect it
|
||||
* from dibusb's bad i2c implementation: reads without
|
||||
* writing the offset before are forbidden */
|
||||
if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
struct i2c_algorithm dibusb_i2c_algo = {
|
||||
.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);
|
||||
|
||||
/* 3000MC/P stuff */
|
||||
// Config Adjacent channels Perf -cal22
|
||||
static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
|
||||
.band_caps = BAND_VHF | BAND_UHF,
|
||||
.setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
|
||||
|
||||
.agc1_max = 48497,
|
||||
.agc1_min = 23593,
|
||||
.agc2_max = 46531,
|
||||
.agc2_min = 24904,
|
||||
|
||||
.agc1_pt1 = 0x65,
|
||||
.agc1_pt2 = 0x69,
|
||||
|
||||
.agc1_slope1 = 0x51,
|
||||
.agc1_slope2 = 0x27,
|
||||
|
||||
.agc2_pt1 = 0,
|
||||
.agc2_pt2 = 0x33,
|
||||
|
||||
.agc2_slope1 = 0x35,
|
||||
.agc2_slope2 = 0x37,
|
||||
};
|
||||
|
||||
static struct dib3000mc_config stk3000p_dib3000p_config = {
|
||||
&dib3000p_mt2060_agc_config,
|
||||
|
||||
.max_time = 0x196,
|
||||
.ln_adc_level = 0x1cc7,
|
||||
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_command1 = 1,
|
||||
.agc_command2 = 1,
|
||||
};
|
||||
|
||||
static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
|
||||
.band_caps = BAND_VHF | BAND_UHF,
|
||||
.setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
|
||||
|
||||
.agc1_max = 56361,
|
||||
.agc1_min = 22282,
|
||||
.agc2_max = 47841,
|
||||
.agc2_min = 36045,
|
||||
|
||||
.agc1_pt1 = 0x3b,
|
||||
.agc1_pt2 = 0x6b,
|
||||
|
||||
.agc1_slope1 = 0x55,
|
||||
.agc1_slope2 = 0x1d,
|
||||
|
||||
.agc2_pt1 = 0,
|
||||
.agc2_pt2 = 0x0a,
|
||||
|
||||
.agc2_slope1 = 0x95,
|
||||
.agc2_slope2 = 0x1e,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
|
||||
|
||||
static struct dib3000mc_config mod3000p_dib3000p_config = {
|
||||
&dib3000p_panasonic_agc_config,
|
||||
|
||||
.max_time = 0x51,
|
||||
.ln_adc_level = 0x1cc7,
|
||||
|
||||
.output_mpeg2_in_188_bytes = 1,
|
||||
|
||||
.agc_command1 = 1,
|
||||
.agc_command2 = 1,
|
||||
};
|
||||
|
||||
int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
|
||||
le16_to_cpu(adap->dev->udev->descriptor.idProduct) ==
|
||||
USB_PID_LITEON_DVB_T_WARM) {
|
||||
msleep(1000);
|
||||
}
|
||||
|
||||
adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
|
||||
&adap->dev->i2c_adap,
|
||||
DEFAULT_DIB3000P_I2C_ADDRESS,
|
||||
&mod3000p_dib3000p_config);
|
||||
if ((adap->fe_adap[0].fe) == NULL)
|
||||
adap->fe_adap[0].fe = dvb_attach(dib3000mc_attach,
|
||||
&adap->dev->i2c_adap,
|
||||
DEFAULT_DIB3000MC_I2C_ADDRESS,
|
||||
&mod3000p_dib3000p_config);
|
||||
if ((adap->fe_adap[0].fe) != NULL) {
|
||||
if (adap->priv != NULL) {
|
||||
struct dibusb_state *st = adap->priv;
|
||||
st->ops.pid_parse = dib3000mc_pid_parse;
|
||||
st->ops.pid_ctrl = dib3000mc_pid_control;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
|
||||
|
||||
static struct mt2060_config stk3000p_mt2060_config = {
|
||||
0x60
|
||||
};
|
||||
|
||||
int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dibusb_state *st = adap->priv;
|
||||
u8 a,b;
|
||||
u16 if1 = 1220;
|
||||
struct i2c_adapter *tun_i2c;
|
||||
|
||||
// First IF calibration for Liteon Sticks
|
||||
if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
|
||||
le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) {
|
||||
|
||||
dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
|
||||
dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
|
||||
|
||||
if (a == 0x00)
|
||||
if1 += b;
|
||||
else if (a == 0x80)
|
||||
if1 -= b;
|
||||
else
|
||||
warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
|
||||
|
||||
} else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM &&
|
||||
le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) {
|
||||
u8 desc;
|
||||
dibusb_read_eeprom_byte(adap->dev, 7, &desc);
|
||||
if (desc == 2) {
|
||||
a = 127;
|
||||
do {
|
||||
dibusb_read_eeprom_byte(adap->dev, a, &desc);
|
||||
a--;
|
||||
} while (a > 7 && (desc == 0xff || desc == 0x00));
|
||||
if (desc & 0x80)
|
||||
if1 -= (0xff - desc);
|
||||
else
|
||||
if1 += desc;
|
||||
}
|
||||
}
|
||||
|
||||
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe_adap[0].fe, 1);
|
||||
if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
|
||||
/* not found - use panasonic pll parameters */
|
||||
if (dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
st->mt2060_present = 1;
|
||||
/* set the correct parameters for the dib3000p */
|
||||
dib3000mc_set_config(adap->fe_adap[0].fe, &stk3000p_dib3000p_config);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* common remote control stuff
|
||||
*/
|
||||
struct rc_map_table rc_map_dibusb_table[] = {
|
||||
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
|
||||
{ 0x0016, KEY_POWER },
|
||||
{ 0x0010, KEY_MUTE },
|
||||
{ 0x0003, KEY_1 },
|
||||
{ 0x0001, KEY_2 },
|
||||
{ 0x0006, KEY_3 },
|
||||
{ 0x0009, KEY_4 },
|
||||
{ 0x001d, KEY_5 },
|
||||
{ 0x001f, KEY_6 },
|
||||
{ 0x000d, KEY_7 },
|
||||
{ 0x0019, KEY_8 },
|
||||
{ 0x001b, KEY_9 },
|
||||
{ 0x0015, KEY_0 },
|
||||
{ 0x0005, KEY_CHANNELUP },
|
||||
{ 0x0002, KEY_CHANNELDOWN },
|
||||
{ 0x001e, KEY_VOLUMEUP },
|
||||
{ 0x000a, KEY_VOLUMEDOWN },
|
||||
{ 0x0011, KEY_RECORD },
|
||||
{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
|
||||
{ 0x0014, KEY_PLAY },
|
||||
{ 0x001a, KEY_STOP },
|
||||
{ 0x0040, KEY_REWIND },
|
||||
{ 0x0012, KEY_FASTFORWARD },
|
||||
{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
|
||||
{ 0x004c, KEY_PAUSE },
|
||||
{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
|
||||
{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
|
||||
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
|
||||
{ 0x000c, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x001c, KEY_EPG }, /* EPG */
|
||||
{ 0x0000, KEY_TAB }, /* Tab */
|
||||
{ 0x0048, KEY_INFO }, /* Preview */
|
||||
{ 0x0004, KEY_LIST }, /* RecordList */
|
||||
{ 0x000f, KEY_TEXT }, /* Teletext */
|
||||
/* Key codes for the KWorld/ADSTech/JetWay remote. */
|
||||
{ 0x8612, KEY_POWER },
|
||||
{ 0x860f, KEY_SELECT }, /* source */
|
||||
{ 0x860c, KEY_UNKNOWN }, /* scan */
|
||||
{ 0x860b, KEY_EPG },
|
||||
{ 0x8610, KEY_MUTE },
|
||||
{ 0x8601, KEY_1 },
|
||||
{ 0x8602, KEY_2 },
|
||||
{ 0x8603, KEY_3 },
|
||||
{ 0x8604, KEY_4 },
|
||||
{ 0x8605, KEY_5 },
|
||||
{ 0x8606, KEY_6 },
|
||||
{ 0x8607, KEY_7 },
|
||||
{ 0x8608, KEY_8 },
|
||||
{ 0x8609, KEY_9 },
|
||||
{ 0x860a, KEY_0 },
|
||||
{ 0x8618, KEY_ZOOM },
|
||||
{ 0x861c, KEY_UNKNOWN }, /* preview */
|
||||
{ 0x8613, KEY_UNKNOWN }, /* snap */
|
||||
{ 0x8600, KEY_UNDO },
|
||||
{ 0x861d, KEY_RECORD },
|
||||
{ 0x860d, KEY_STOP },
|
||||
{ 0x860e, KEY_PAUSE },
|
||||
{ 0x8616, KEY_PLAY },
|
||||
{ 0x8611, KEY_BACK },
|
||||
{ 0x8619, KEY_FORWARD },
|
||||
{ 0x8614, KEY_UNKNOWN }, /* pip */
|
||||
{ 0x8615, KEY_ESC },
|
||||
{ 0x861a, KEY_UP },
|
||||
{ 0x861e, KEY_DOWN },
|
||||
{ 0x861f, KEY_LEFT },
|
||||
{ 0x861b, KEY_RIGHT },
|
||||
|
||||
/* Key codes for the DiBcom MOD3000 remote. */
|
||||
{ 0x8000, KEY_MUTE },
|
||||
{ 0x8001, KEY_TEXT },
|
||||
{ 0x8002, KEY_HOME },
|
||||
{ 0x8003, KEY_POWER },
|
||||
|
||||
{ 0x8004, KEY_RED },
|
||||
{ 0x8005, KEY_GREEN },
|
||||
{ 0x8006, KEY_YELLOW },
|
||||
{ 0x8007, KEY_BLUE },
|
||||
|
||||
{ 0x8008, KEY_DVD },
|
||||
{ 0x8009, KEY_AUDIO },
|
||||
{ 0x800a, KEY_IMAGES }, /* Pictures */
|
||||
{ 0x800b, KEY_VIDEO },
|
||||
|
||||
{ 0x800c, KEY_BACK },
|
||||
{ 0x800d, KEY_UP },
|
||||
{ 0x800e, KEY_RADIO },
|
||||
{ 0x800f, KEY_EPG },
|
||||
|
||||
{ 0x8010, KEY_LEFT },
|
||||
{ 0x8011, KEY_OK },
|
||||
{ 0x8012, KEY_RIGHT },
|
||||
{ 0x8013, KEY_UNKNOWN }, /* SAP */
|
||||
|
||||
{ 0x8014, KEY_TV },
|
||||
{ 0x8015, KEY_DOWN },
|
||||
{ 0x8016, KEY_MENU }, /* DVD Menu */
|
||||
{ 0x8017, KEY_LAST },
|
||||
|
||||
{ 0x8018, KEY_RECORD },
|
||||
{ 0x8019, KEY_STOP },
|
||||
{ 0x801a, KEY_PAUSE },
|
||||
{ 0x801b, KEY_PLAY },
|
||||
|
||||
{ 0x801c, KEY_PREVIOUS },
|
||||
{ 0x801d, KEY_REWIND },
|
||||
{ 0x801e, KEY_FASTFORWARD },
|
||||
{ 0x801f, KEY_NEXT},
|
||||
|
||||
{ 0x8040, KEY_1 },
|
||||
{ 0x8041, KEY_2 },
|
||||
{ 0x8042, KEY_3 },
|
||||
{ 0x8043, KEY_CHANNELUP },
|
||||
|
||||
{ 0x8044, KEY_4 },
|
||||
{ 0x8045, KEY_5 },
|
||||
{ 0x8046, KEY_6 },
|
||||
{ 0x8047, KEY_CHANNELDOWN },
|
||||
|
||||
{ 0x8048, KEY_7 },
|
||||
{ 0x8049, KEY_8 },
|
||||
{ 0x804a, KEY_9 },
|
||||
{ 0x804b, KEY_VOLUMEUP },
|
||||
|
||||
{ 0x804c, KEY_CLEAR },
|
||||
{ 0x804d, KEY_0 },
|
||||
{ 0x804e, KEY_ENTER },
|
||||
{ 0x804f, KEY_VOLUMEDOWN },
|
||||
};
|
||||
EXPORT_SYMBOL(rc_map_dibusb_table);
|
||||
|
||||
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: %*ph\n", 5, key);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dibusb_rc_query);
|
||||
471
drivers/media/usb/dvb-usb/dibusb-mb.c
Normal file
471
drivers/media/usb/dvb-usb/dibusb-mb.c
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
/* 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"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
struct dibusb_state *st = adap->priv;
|
||||
|
||||
return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
|
||||
}
|
||||
|
||||
static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dib3000_config demod_cfg;
|
||||
struct dibusb_state *st = adap->priv;
|
||||
|
||||
demod_cfg.demod_address = 0x8;
|
||||
|
||||
adap->fe_adap[0].fe = dvb_attach(dib3000mb_attach, &demod_cfg,
|
||||
&adap->dev->i2c_adap, &st->ops);
|
||||
if ((adap->fe_adap[0].fe) == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
adap->fe_adap[0].fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dibusb_state *st = adap->priv;
|
||||
|
||||
st->tuner_addr = 0x61;
|
||||
|
||||
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, &adap->dev->i2c_adap,
|
||||
DVB_PLL_TUA6010XS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dibusb_state *st = adap->priv;
|
||||
|
||||
st->tuner_addr = 0x60;
|
||||
|
||||
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap,
|
||||
DVB_PLL_TDA665X);
|
||||
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_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
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 },
|
||||
};
|
||||
struct dibusb_state *st = adap->priv;
|
||||
|
||||
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
|
||||
msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
|
||||
|
||||
if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
|
||||
adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
|
||||
|
||||
if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
|
||||
err("tuner i2c write failed.");
|
||||
ret = -EREMOTEIO;
|
||||
}
|
||||
|
||||
if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
|
||||
adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
|
||||
|
||||
if (b2[0] == 0xfe) {
|
||||
info("This device has the Thomson Cable onboard. Which is default.");
|
||||
ret = dibusb_thomson_tuner_attach(adap);
|
||||
} else {
|
||||
info("This device has the Panasonic ENV77H11D5 onboard.");
|
||||
ret = dibusb_panasonic_tuner_attach(adap);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties dibusb1_1_properties;
|
||||
static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
|
||||
static struct dvb_usb_device_properties dibusb2_0b_properties;
|
||||
static struct dvb_usb_device_properties artec_t1_usb2_properties;
|
||||
|
||||
static int dibusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &dibusb2_0b_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
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_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) },
|
||||
/* 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) },
|
||||
|
||||
/* 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) },
|
||||
|
||||
/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) },
|
||||
|
||||
/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
|
||||
/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
|
||||
|
||||
/*
|
||||
* XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices
|
||||
* we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that
|
||||
* have been left on the device. If you don't have such a device but an Artec
|
||||
* device that's supposed to work with this driver but is not detected by it,
|
||||
* free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
|
||||
/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
|
||||
#endif
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
|
||||
|
||||
static struct dvb_usb_device_properties dibusb1_1_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_AN2135,
|
||||
|
||||
.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_tuner_probe_and_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = dibusb_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_map_table = rc_map_dibusb_table,
|
||||
.rc_map_size = 111, /* 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,
|
||||
|
||||
.num_device_descs = 9,
|
||||
.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 },
|
||||
},
|
||||
{ "Unknown 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 },
|
||||
},
|
||||
{ "VideoWalker DVB-T USB",
|
||||
{ &dibusb_dib3000mb_table[25], NULL },
|
||||
{ &dibusb_dib3000mb_table[26], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = CYPRESS_AN2235,
|
||||
|
||||
.firmware = "dvb-usb-dibusb-an2235-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_tuner_probe_and_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
},
|
||||
},
|
||||
.power_ctrl = dibusb_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_map_table = rc_map_dibusb_table,
|
||||
.rc_map_size = 111, /* 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,
|
||||
|
||||
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
|
||||
.num_device_descs = 2,
|
||||
#else
|
||||
.num_device_descs = 1,
|
||||
#endif
|
||||
.devices = {
|
||||
{ "Artec T1 USB1.1 TVBOX with AN2235",
|
||||
{ &dibusb_dib3000mb_table[21], NULL },
|
||||
{ &dibusb_dib3000mb_table[22], NULL },
|
||||
},
|
||||
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
|
||||
{ "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
|
||||
{ &dibusb_dib3000mb_table[30], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ NULL },
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties dibusb2_0b_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.firmware = "dvb-usb-adstech-usb2-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_thomson_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_map_table = rc_map_dibusb_table,
|
||||
.rc_map_size = 111, /* 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,
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "KWorld/ADSTech Instant DVB-T USB2.0",
|
||||
{ &dibusb_dib3000mb_table[23], NULL },
|
||||
{ &dibusb_dib3000mb_table[24], NULL },
|
||||
},
|
||||
{ "KWorld Xpert DVB-T USB2.0",
|
||||
{ &dibusb_dib3000mb_table[27], NULL },
|
||||
{ NULL }
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties artec_t1_usb2_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 16,
|
||||
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mb_frontend_attach,
|
||||
.tuner_attach = dibusb_tuner_probe_and_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_map_table = rc_map_dibusb_table,
|
||||
.rc_map_size = 111, /* 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,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Artec T1 USB2.0",
|
||||
{ &dibusb_dib3000mb_table[28], NULL },
|
||||
{ &dibusb_dib3000mb_table[29], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver dibusb_driver = {
|
||||
.name = "dvb_usb_dibusb_mb",
|
||||
.probe = dibusb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dibusb_dib3000mb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(dibusb_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
149
drivers/media/usb/dvb-usb/dibusb-mc.c
Normal file
149
drivers/media/usb/dvb-usb/dibusb-mc.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* 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"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_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,
|
||||
NULL, adapter_nr);
|
||||
}
|
||||
|
||||
/* 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) },
|
||||
/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
|
||||
/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) },
|
||||
/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) },
|
||||
/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) },
|
||||
/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) },
|
||||
/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) },
|
||||
/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) },
|
||||
/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) },
|
||||
/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) },
|
||||
/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) },
|
||||
/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) },
|
||||
/* 14 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) },
|
||||
/* 15 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
|
||||
|
||||
static struct dvb_usb_device_properties dibusb_mc_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mc_frontend_attach,
|
||||
.tuner_attach = dibusb_dib3000mc_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_map_table = rc_map_dibusb_table,
|
||||
.rc_map_size = 111, /* FIXME */
|
||||
.rc_query = dibusb_rc_query,
|
||||
},
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 8,
|
||||
.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 check the warm ID)",
|
||||
{ &dibusb_dib3000mc_table[2], NULL },
|
||||
{ &dibusb_dib3000mc_table[3], NULL },
|
||||
},
|
||||
{ "LITE-ON USB2.0 DVB-T Tuner",
|
||||
/* Also rebranded as Intuix S800, Toshiba */
|
||||
{ &dibusb_dib3000mc_table[4], NULL },
|
||||
{ &dibusb_dib3000mc_table[5], NULL },
|
||||
},
|
||||
{ "MSI Digivox Mini SL",
|
||||
{ &dibusb_dib3000mc_table[6], NULL },
|
||||
{ &dibusb_dib3000mc_table[7], NULL },
|
||||
},
|
||||
{ "GRAND - USB2.0 DVB-T adapter",
|
||||
{ &dibusb_dib3000mc_table[8], NULL },
|
||||
{ &dibusb_dib3000mc_table[9], NULL },
|
||||
},
|
||||
{ "Artec T14 - USB2.0 DVB-T",
|
||||
{ &dibusb_dib3000mc_table[10], NULL },
|
||||
{ &dibusb_dib3000mc_table[11], NULL },
|
||||
},
|
||||
{ "Leadtek - USB2.0 Winfast DTV dongle",
|
||||
{ &dibusb_dib3000mc_table[12], NULL },
|
||||
{ &dibusb_dib3000mc_table[13], NULL },
|
||||
},
|
||||
{ "Humax/Coex DVB-T USB Stick 2.0 High Speed",
|
||||
{ &dibusb_dib3000mc_table[14], NULL },
|
||||
{ &dibusb_dib3000mc_table[15], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver dibusb_mc_driver = {
|
||||
.name = "dvb_usb_dibusb_mc",
|
||||
.probe = dibusb_mc_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dibusb_dib3000mc_table,
|
||||
};
|
||||
|
||||
module_usb_driver(dibusb_mc_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
131
drivers/media/usb/dvb-usb/dibusb.h
Normal file
131
drivers/media/usb/dvb-usb/dibusb.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* 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_
|
||||
|
||||
#ifndef DVB_USB_LOG_PREFIX
|
||||
#define DVB_USB_LOG_PREFIX "dibusb"
|
||||
#endif
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "dib3000.h"
|
||||
#include "dib3000mc.h"
|
||||
#include "mt2060.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;
|
||||
int mt2060_present;
|
||||
u8 tuner_addr;
|
||||
};
|
||||
|
||||
struct dibusb_device_state {
|
||||
/* 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_adapter *);
|
||||
extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *);
|
||||
|
||||
extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int);
|
||||
extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int);
|
||||
extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int);
|
||||
extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int);
|
||||
|
||||
extern int dibusb_power_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 rc_map_table rc_map_dibusb_table[];
|
||||
extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
|
||||
extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
|
||||
|
||||
#endif
|
||||
354
drivers/media/usb/dvb-usb/digitv.c
Normal file
354
drivers/media/usb/dvb-usb/digitv.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
|
||||
* receiver
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
*
|
||||
* 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
|
||||
* Software Foundation, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "digitv.h"
|
||||
|
||||
#include "mt352.h"
|
||||
#include "nxt6000.h"
|
||||
|
||||
/* debug */
|
||||
static 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);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
|
||||
|
||||
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 (mutex_lock_interruptible(&d->i2c_mutex) < 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;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 digitv_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm digitv_i2c_algo = {
|
||||
.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_device_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 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;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
|
||||
mt352_write(fe, &reset_buf[i], 2);
|
||||
|
||||
msleep(1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
|
||||
mt352_write(fe, &init_buf[i], 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt352_config digitv_mt352_config = {
|
||||
.demod_init = digitv_mt352_demod_init,
|
||||
};
|
||||
|
||||
static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
u8 b[5];
|
||||
|
||||
fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b));
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
|
||||
}
|
||||
|
||||
static struct nxt6000_config digitv_nxt6000_config = {
|
||||
.clock_inversion = 1,
|
||||
};
|
||||
|
||||
static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct digitv_state *st = adap->dev->priv;
|
||||
|
||||
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if ((adap->fe_adap[0].fe) != NULL) {
|
||||
st->is_nxt6000 = 0;
|
||||
return 0;
|
||||
}
|
||||
adap->fe_adap[0].fe = dvb_attach(nxt6000_attach,
|
||||
&digitv_nxt6000_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if ((adap->fe_adap[0].fe) != NULL) {
|
||||
st->is_nxt6000 = 1;
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct digitv_state *st = adap->dev->priv;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4))
|
||||
return -ENODEV;
|
||||
|
||||
if (st->is_nxt6000)
|
||||
adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rc_map_table rc_map_digitv_table[] = {
|
||||
{ 0x5f55, KEY_0 },
|
||||
{ 0x6f55, KEY_1 },
|
||||
{ 0x9f55, KEY_2 },
|
||||
{ 0xaf55, KEY_3 },
|
||||
{ 0x5f56, KEY_4 },
|
||||
{ 0x6f56, KEY_5 },
|
||||
{ 0x9f56, KEY_6 },
|
||||
{ 0xaf56, KEY_7 },
|
||||
{ 0x5f59, KEY_8 },
|
||||
{ 0x6f59, KEY_9 },
|
||||
{ 0x9f59, KEY_TV },
|
||||
{ 0xaf59, KEY_AUX },
|
||||
{ 0x5f5a, KEY_DVD },
|
||||
{ 0x6f5a, KEY_POWER },
|
||||
{ 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */
|
||||
{ 0xaf5a, KEY_AUDIO },
|
||||
{ 0x5f65, KEY_INFO },
|
||||
{ 0x6f65, KEY_F13 }, /* 16:9 */
|
||||
{ 0x9f65, KEY_F14 }, /* 14:9 */
|
||||
{ 0xaf65, KEY_EPG },
|
||||
{ 0x5f66, KEY_EXIT },
|
||||
{ 0x6f66, KEY_MENU },
|
||||
{ 0x9f66, KEY_UP },
|
||||
{ 0xaf66, KEY_DOWN },
|
||||
{ 0x5f69, KEY_LEFT },
|
||||
{ 0x6f69, KEY_RIGHT },
|
||||
{ 0x9f69, KEY_ENTER },
|
||||
{ 0xaf69, KEY_CHANNELUP },
|
||||
{ 0x5f6a, KEY_CHANNELDOWN },
|
||||
{ 0x6f6a, KEY_VOLUMEUP },
|
||||
{ 0x9f6a, KEY_VOLUMEDOWN },
|
||||
{ 0xaf6a, KEY_RED },
|
||||
{ 0x5f95, KEY_GREEN },
|
||||
{ 0x6f95, KEY_YELLOW },
|
||||
{ 0x9f95, KEY_BLUE },
|
||||
{ 0xaf95, KEY_SUBTITLE },
|
||||
{ 0x5f96, KEY_F15 }, /* AD */
|
||||
{ 0x6f96, KEY_TEXT },
|
||||
{ 0x9f96, KEY_MUTE },
|
||||
{ 0xaf96, KEY_REWIND },
|
||||
{ 0x5f99, KEY_STOP },
|
||||
{ 0x6f99, KEY_PLAY },
|
||||
{ 0x9f99, KEY_FASTFORWARD },
|
||||
{ 0xaf99, KEY_F16 }, /* chapter */
|
||||
{ 0x5f9a, KEY_PAUSE },
|
||||
{ 0x6f9a, KEY_PLAY },
|
||||
{ 0x9f9a, KEY_RECORD },
|
||||
{ 0xaf9a, KEY_F17 }, /* picture in picture */
|
||||
{ 0x5fa5, KEY_KPPLUS }, /* zoom in */
|
||||
{ 0x6fa5, KEY_KPMINUS }, /* zoom out */
|
||||
{ 0x9fa5, KEY_F18 }, /* capture */
|
||||
{ 0xafa5, KEY_F19 }, /* web */
|
||||
{ 0x5fa6, KEY_EMAIL },
|
||||
{ 0x6fa6, KEY_PHONE },
|
||||
{ 0x9fa6, KEY_PC },
|
||||
};
|
||||
|
||||
static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
int i;
|
||||
u8 key[5];
|
||||
u8 b[4] = { 0 };
|
||||
|
||||
*event = 0;
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
|
||||
|
||||
/* Tell the device we've read the remote. Not sure how necessary
|
||||
this is, but the Nebula SDK does it. */
|
||||
digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
|
||||
|
||||
/* if something is inside the buffer, simulate key press */
|
||||
if (key[1] != 0)
|
||||
{
|
||||
for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
|
||||
if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] &&
|
||||
rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) {
|
||||
*event = d->props.rc.legacy.rc_map_table[i].keycode;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key[0] != 0)
|
||||
deb_rc("key: %*ph\n", 5, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties digitv_properties;
|
||||
|
||||
static int digitv_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d,
|
||||
adapter_nr);
|
||||
if (ret == 0) {
|
||||
u8 b[4] = { 0 };
|
||||
|
||||
if (d != NULL) { /* do that only when the firmware is loaded */
|
||||
b[0] = 1;
|
||||
digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0);
|
||||
|
||||
b[0] = 0;
|
||||
digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_device_properties digitv_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-digitv-02.fw",
|
||||
|
||||
.size_of_priv = sizeof(struct digitv_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.frontend_attach = digitv_frontend_attach,
|
||||
.tuner_attach = digitv_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.identify_state = digitv_identify_state,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 1000,
|
||||
.rc_map_table = rc_map_digitv_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_digitv_table),
|
||||
.rc_query = digitv_rc_query,
|
||||
},
|
||||
|
||||
.i2c_algo = &digitv_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Nebula Electronics uDigiTV DVB-T USB2.0)",
|
||||
{ &digitv_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver digitv_driver = {
|
||||
.name = "dvb_usb_digitv",
|
||||
.probe = digitv_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = digitv_table,
|
||||
};
|
||||
|
||||
module_usb_driver(digitv_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
|
||||
MODULE_VERSION("1.0-alpha");
|
||||
MODULE_LICENSE("GPL");
|
||||
66
drivers/media/usb/dvb-usb/digitv.h
Normal file
66
drivers/media/usb/dvb-usb/digitv.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef _DVB_USB_DIGITV_H_
|
||||
#define _DVB_USB_DIGITV_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "digitv"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
struct digitv_state {
|
||||
int is_nxt6000;
|
||||
};
|
||||
|
||||
/* protocol (from usblogging and the SDK:
|
||||
*
|
||||
* Always 7 bytes bulk message(s) for controlling
|
||||
*
|
||||
* First byte describes the command. Reads are 2 consecutive transfer (as always).
|
||||
*
|
||||
* General structure:
|
||||
*
|
||||
* write or first message of a read:
|
||||
* <cmdbyte> VV <len> B0 B1 B2 B3
|
||||
*
|
||||
* second message of a read
|
||||
* <cmdbyte> VV <len> R0 R1 R2 R3
|
||||
*
|
||||
* whereas 0 < len <= 4
|
||||
*
|
||||
* I2C address is stored somewhere inside the device.
|
||||
*
|
||||
* 0x01 read from EEPROM
|
||||
* VV = offset; B* = 0; R* = value(s)
|
||||
*
|
||||
* 0x02 read register of the COFDM
|
||||
* VV = register; B* = 0; R* = value(s)
|
||||
*
|
||||
* 0x05 write register of the COFDM
|
||||
* VV = register; B* = value(s);
|
||||
*
|
||||
* 0x06 write to the tuner (only for NXT6000)
|
||||
* VV = 0; B* = PLL data; len = 4;
|
||||
*
|
||||
* 0x03 read remote control
|
||||
* VV = 0; B* = 0; len = 4; R* = key
|
||||
*
|
||||
* 0x07 write to the remote (don't know why one should this, resetting ?)
|
||||
* VV = 0; B* = key; len = 4;
|
||||
*
|
||||
* 0x08 write remote type
|
||||
* VV = 0; B[0] = 0x01, len = 4
|
||||
*
|
||||
* 0x09 write device init
|
||||
* TODO
|
||||
*/
|
||||
#define USB_READ_EEPROM 1
|
||||
|
||||
#define USB_READ_COFDM 2
|
||||
#define USB_WRITE_COFDM 5
|
||||
|
||||
#define USB_WRITE_TUNER 6
|
||||
|
||||
#define USB_READ_REMOTE 3
|
||||
#define USB_WRITE_REMOTE 7
|
||||
#define USB_WRITE_REMOTE_TYPE 8
|
||||
|
||||
#define USB_DEV_INIT 9
|
||||
|
||||
#endif
|
||||
210
drivers/media/usb/dvb-usb/dtt200u-fe.c
Normal file
210
drivers/media/usb/dvb-usb/dtt200u-fe.c
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
|
||||
* Typhoon/ Yuan DVB-T USB2.0 receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
#include "dtt200u.h"
|
||||
|
||||
struct dtt200u_fe_state {
|
||||
struct dvb_usb_device *d;
|
||||
|
||||
fe_status_t stat;
|
||||
|
||||
struct dtv_frontend_properties fep;
|
||||
struct dvb_frontend frontend;
|
||||
};
|
||||
|
||||
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
|
||||
{
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
u8 st = GET_TUNE_STATUS, b[3];
|
||||
|
||||
dvb_usb_generic_rw(state->d,&st,1,b,3,0);
|
||||
|
||||
switch (b[0]) {
|
||||
case 0x01:
|
||||
*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
break;
|
||||
case 0x00: /* pending */
|
||||
*stat = FE_TIMEDOUT; /* during set_frontend */
|
||||
break;
|
||||
default:
|
||||
case 0x02: /* failed */
|
||||
*stat = 0;
|
||||
break;
|
||||
}
|
||||
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_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_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_AGC, 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 = SET_INIT;
|
||||
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 = 0;
|
||||
tune->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
int i;
|
||||
fe_status_t st;
|
||||
u16 freq = fep->frequency / 250000;
|
||||
u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
|
||||
|
||||
switch (fep->bandwidth_hz) {
|
||||
case 8000000:
|
||||
bwbuf[1] = 8;
|
||||
break;
|
||||
case 7000000:
|
||||
bwbuf[1] = 7;
|
||||
break;
|
||||
case 6000000:
|
||||
bwbuf[1] = 6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < 30; i++) {
|
||||
msleep(20);
|
||||
dtt200u_fe_read_status(fe, &st);
|
||||
if (st & FE_TIMEDOUT)
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_fe_get_frontend(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
|
||||
struct dtt200u_fe_state *state = fe->demodulator_priv;
|
||||
memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
|
||||
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 = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
deb_info("attaching frontend dtt200u\n");
|
||||
|
||||
state->d = d;
|
||||
|
||||
memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
return &state->frontend;
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops dtt200u_fe_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "WideView USB DVB-T",
|
||||
.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,
|
||||
};
|
||||
368
drivers/media/usb/dvb-usb/dtt200u.c
Normal file
368
drivers/media/usb/dvb-usb/dtt200u.c
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
|
||||
* Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
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_adapter *adap, int onoff)
|
||||
{
|
||||
u8 b_streaming[2] = { SET_STREAMING, onoff };
|
||||
u8 b_rst_pid = RESET_PID_FILTER;
|
||||
|
||||
dvb_usb_generic_write(adap->dev, b_streaming, 2);
|
||||
|
||||
if (onoff == 0)
|
||||
dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, 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) & 0x1f;
|
||||
|
||||
return dvb_usb_generic_write(adap->dev, b_pid, 4);
|
||||
}
|
||||
|
||||
/* remote control */
|
||||
/* key list for the tiny remote control (Yakumo, don't know about the others) */
|
||||
static struct rc_map_table rc_map_dtt200u_table[] = {
|
||||
{ 0x8001, KEY_MUTE },
|
||||
{ 0x8002, KEY_CHANNELDOWN },
|
||||
{ 0x8003, KEY_VOLUMEDOWN },
|
||||
{ 0x8004, KEY_1 },
|
||||
{ 0x8005, KEY_2 },
|
||||
{ 0x8006, KEY_3 },
|
||||
{ 0x8007, KEY_4 },
|
||||
{ 0x8008, KEY_5 },
|
||||
{ 0x8009, KEY_6 },
|
||||
{ 0x800a, KEY_7 },
|
||||
{ 0x800c, KEY_ZOOM },
|
||||
{ 0x800d, KEY_0 },
|
||||
{ 0x800e, KEY_SELECT },
|
||||
{ 0x8012, KEY_POWER },
|
||||
{ 0x801a, KEY_CHANNELUP },
|
||||
{ 0x801b, KEY_8 },
|
||||
{ 0x801e, KEY_VOLUMEUP },
|
||||
{ 0x801f, KEY_9 },
|
||||
};
|
||||
|
||||
static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
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)
|
||||
deb_info("key: %*ph\n", 5, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties dtt200u_properties;
|
||||
static struct dvb_usb_device_properties wt220u_fc_properties;
|
||||
static struct dvb_usb_device_properties wt220u_properties;
|
||||
static struct dvb_usb_device_properties wt220u_zl0353_properties;
|
||||
static struct dvb_usb_device_properties wt220u_miglia_properties;
|
||||
|
||||
static int dtt200u_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &wt220u_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_device_id dtt200u_usb_table [] = {
|
||||
{ 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) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) },
|
||||
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) },
|
||||
{ USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties dtt200u_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-dtt200u-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 300,
|
||||
.rc_map_table = rc_map_dtt200u_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
},
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .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 },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 300,
|
||||
.rc_map_table = rc_map_dtt200u_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
},
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
|
||||
.cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[3], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_fc_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-fc03.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 300,
|
||||
.rc_map_table = rc_map_dtt200u_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
},
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
|
||||
.cold_ids = { &dtt200u_usb_table[6], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[7], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_zl0353_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-zl0353-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
|
||||
.pid_filter_count = 15,
|
||||
|
||||
.streaming_ctrl = dtt200u_streaming_ctrl,
|
||||
.pid_filter = dtt200u_pid_filter,
|
||||
.frontend_attach = dtt200u_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.power_ctrl = dtt200u_power_ctrl,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 300,
|
||||
.rc_map_table = rc_map_dtt200u_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
|
||||
.rc_query = dtt200u_rc_query,
|
||||
},
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (based on ZL353)",
|
||||
.cold_ids = { &dtt200u_usb_table[4], NULL },
|
||||
.warm_ids = { &dtt200u_usb_table[5], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties wt220u_miglia_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-wt220u-miglia-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "WideView WT-220U PenType Receiver (Miglia)",
|
||||
.cold_ids = { &dtt200u_usb_table[9], NULL },
|
||||
/* This device turns into WT220U_ZL0353_WARM when fw
|
||||
has been uploaded */
|
||||
.warm_ids = { NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver dtt200u_usb_driver = {
|
||||
.name = "dvb_usb_dtt200u",
|
||||
.probe = dtt200u_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dtt200u_usb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(dtt200u_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
57
drivers/media/usb/dvb-usb/dtt200u.h
Normal file
57
drivers/media/usb/dvb-usb/dtt200u.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* 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)
|
||||
*
|
||||
* 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
|
||||
* 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
|
||||
*/
|
||||
|
||||
#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 - init
|
||||
* 02 - frequency (divided by 250000)
|
||||
* 03 - bandwidth
|
||||
* 04 - pid table (index pid(7:0) pid(12:8))
|
||||
* 05 - reset the pid table
|
||||
* 08 - transfer switch
|
||||
*/
|
||||
|
||||
#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_STREAMING 0x08
|
||||
|
||||
extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
|
||||
|
||||
#endif
|
||||
224
drivers/media/usb/dvb-usb/dtv5100.c
Normal file
224
drivers/media/usb/dvb-usb/dtv5100.c
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
|
||||
*
|
||||
* Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com>
|
||||
* http://royale.zerezo.com/dtv5100/
|
||||
*
|
||||
* Inspired by gl861.c and au6610.c drivers
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dtv5100.h"
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_dtv5100_debug;
|
||||
module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u8 request;
|
||||
u8 type;
|
||||
u16 value;
|
||||
u16 index;
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
/* write { reg }, read { value } */
|
||||
request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
|
||||
DTV5100_TUNER_READ);
|
||||
type = USB_TYPE_VENDOR | USB_DIR_IN;
|
||||
value = 0;
|
||||
break;
|
||||
case 2:
|
||||
/* write { reg, value } */
|
||||
request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
|
||||
DTV5100_TUNER_WRITE);
|
||||
type = USB_TYPE_VENDOR | USB_DIR_OUT;
|
||||
value = wbuf[1];
|
||||
break;
|
||||
default:
|
||||
warn("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
index = (addr << 8) + wbuf[0];
|
||||
|
||||
msleep(1); /* avoid I2C errors */
|
||||
return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
|
||||
type, value, index, rbuf, rlen,
|
||||
DTV5100_USB_TIMEOUT);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (dtv5100_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 (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 dtv5100_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm dtv5100_i2c_algo = {
|
||||
.master_xfer = dtv5100_i2c_xfer,
|
||||
.functionality = dtv5100_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct zl10353_config dtv5100_zl10353_config = {
|
||||
.demod_address = DTV5100_DEMOD_ADDR,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe_adap[0].fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
/* disable i2c gate, or it won't work... is this safe? */
|
||||
adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config dtv5100_qt1010_config = {
|
||||
.i2c_address = DTV5100_TUNER_ADDR
|
||||
};
|
||||
|
||||
static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe_adap[0].fe, &adap->dev->i2c_adap,
|
||||
&dtv5100_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties dtv5100_properties;
|
||||
|
||||
static int dtv5100_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int i, ret;
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
/* initialize non qt1010/zl10353 part? */
|
||||
for (i = 0; dtv5100_init[i].request; i++) {
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
dtv5100_init[i].request,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
dtv5100_init[i].value,
|
||||
dtv5100_init[i].index, NULL, 0,
|
||||
DTV5100_USB_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dvb_usb_device_init(intf, &dtv5100_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_device_id dtv5100_table[] = {
|
||||
{ USB_DEVICE(0x06be, 0xa232) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dtv5100_table);
|
||||
|
||||
static struct dvb_usb_device_properties dtv5100_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.frontend_attach = dtv5100_frontend_attach,
|
||||
.tuner_attach = dtv5100_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
} },
|
||||
|
||||
.i2c_algo = &dtv5100_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
.name = "AME DTV-5100 USB2.0 DVB-T",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &dtv5100_table[0], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver dtv5100_driver = {
|
||||
.name = "dvb_usb_dtv5100",
|
||||
.probe = dtv5100_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = dtv5100_table,
|
||||
};
|
||||
|
||||
module_usb_driver(dtv5100_driver);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
51
drivers/media/usb/dvb-usb/dtv5100.h
Normal file
51
drivers/media/usb/dvb-usb/dtv5100.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
|
||||
*
|
||||
* Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com>
|
||||
* http://royale.zerezo.com/dtv5100/
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _DVB_USB_DTV5100_H_
|
||||
#define _DVB_USB_DTV5100_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dtv5100"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define DTV5100_USB_TIMEOUT 500
|
||||
|
||||
#define DTV5100_DEMOD_ADDR 0x00
|
||||
#define DTV5100_DEMOD_WRITE 0xc0
|
||||
#define DTV5100_DEMOD_READ 0xc1
|
||||
|
||||
#define DTV5100_TUNER_ADDR 0xc4
|
||||
#define DTV5100_TUNER_WRITE 0xc7
|
||||
#define DTV5100_TUNER_READ 0xc8
|
||||
|
||||
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
|
||||
#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T"
|
||||
|
||||
static struct {
|
||||
u8 request;
|
||||
u8 value;
|
||||
u16 index;
|
||||
} dtv5100_init[] = {
|
||||
{ 0x000000c5, 0x00000000, 0x00000001 },
|
||||
{ 0x000000c5, 0x00000001, 0x00000001 },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
#endif
|
||||
52
drivers/media/usb/dvb-usb/dvb-usb-common.h
Normal file
52
drivers/media/usb/dvb-usb/dvb-usb-common.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* 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;
|
||||
extern int dvb_usb_disable_rc_polling;
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args)
|
||||
#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args)
|
||||
#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args)
|
||||
#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args)
|
||||
#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args)
|
||||
#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
|
||||
|
||||
/* commonly used methods */
|
||||
extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
|
||||
|
||||
extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff);
|
||||
|
||||
extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
|
||||
extern int usb_urb_exit(struct usb_data_stream *stream);
|
||||
extern int usb_urb_submit(struct usb_data_stream *stream);
|
||||
extern int usb_urb_kill(struct usb_data_stream *stream);
|
||||
|
||||
extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
|
||||
|
||||
extern int dvb_usb_i2c_init(struct dvb_usb_device *);
|
||||
extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
|
||||
|
||||
extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap,
|
||||
short *adapter_nums);
|
||||
extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
|
||||
extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
|
||||
|
||||
extern int dvb_usb_remote_init(struct dvb_usb_device *);
|
||||
extern int dvb_usb_remote_exit(struct dvb_usb_device *);
|
||||
|
||||
#endif
|
||||
288
drivers/media/usb/dvb-usb/dvb-usb-dvb.c
Normal file
288
drivers/media/usb/dvb-usb/dvb-usb-dvb.c
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/* dvb-usb-dvb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 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"
|
||||
|
||||
/* does the complete input transfer handling */
|
||||
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
|
||||
int newfeedcount, ret;
|
||||
|
||||
if (adap == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if ((adap->active_fe < 0) ||
|
||||
(adap->active_fe >= adap->num_frontends_initialized)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
newfeedcount = adap->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");
|
||||
usb_urb_kill(&adap->fe_adap[adap->active_fe].stream);
|
||||
|
||||
if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
|
||||
ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0);
|
||||
if (ret < 0) {
|
||||
err("error while stopping stream.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adap->feedcount = newfeedcount;
|
||||
|
||||
/* activate the pid on the device specific pid_filter */
|
||||
deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",
|
||||
adap->fe_adap[adap->active_fe].pid_filtering ?
|
||||
"yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid,
|
||||
dvbdmxfeed->index, onoff ? "on" : "off");
|
||||
if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
|
||||
adap->fe_adap[adap->active_fe].pid_filtering &&
|
||||
adap->props.fe[adap->active_fe].pid_filter != NULL)
|
||||
adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
|
||||
|
||||
/* start the feed if this was the first feed and there is still a feed
|
||||
* for reception.
|
||||
*/
|
||||
if (adap->feedcount == onoff && adap->feedcount > 0) {
|
||||
deb_ts("submitting all URBs\n");
|
||||
usb_urb_submit(&adap->fe_adap[adap->active_fe].stream);
|
||||
|
||||
deb_ts("controlling pid parser\n");
|
||||
if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER &&
|
||||
adap->props.fe[adap->active_fe].caps &
|
||||
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
|
||||
adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) {
|
||||
ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap,
|
||||
adap->fe_adap[adap->active_fe].pid_filtering);
|
||||
if (ret < 0) {
|
||||
err("could not handle pid_parser");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
deb_ts("start feeding\n");
|
||||
if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) {
|
||||
ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1);
|
||||
if (ret < 0) {
|
||||
err("error while enabling fifo.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
|
||||
{
|
||||
int i;
|
||||
int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
|
||||
adap->dev->owner, &adap->dev->udev->dev,
|
||||
adapter_nums);
|
||||
|
||||
if (ret < 0) {
|
||||
deb_info("dvb_register_adapter failed: error %d", ret);
|
||||
goto err;
|
||||
}
|
||||
adap->dvb_adap.priv = adap;
|
||||
|
||||
if (adap->dev->props.read_mac_address) {
|
||||
if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
|
||||
info("MAC address: %pM",adap->dvb_adap.proposed_mac);
|
||||
else
|
||||
err("MAC address reading failed.");
|
||||
}
|
||||
|
||||
|
||||
adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
|
||||
adap->demux.priv = adap;
|
||||
|
||||
adap->demux.filternum = 0;
|
||||
for (i = 0; i < adap->props.num_frontends; i++) {
|
||||
if (adap->demux.filternum < adap->fe_adap[i].max_feed_count)
|
||||
adap->demux.filternum = adap->fe_adap[i].max_feed_count;
|
||||
}
|
||||
adap->demux.feednum = adap->demux.filternum;
|
||||
adap->demux.start_feed = dvb_usb_start_feed;
|
||||
adap->demux.stop_feed = dvb_usb_stop_feed;
|
||||
adap->demux.write_to_decoder = NULL;
|
||||
if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
|
||||
err("dvb_dmx_init failed: error %d",ret);
|
||||
goto err_dmx;
|
||||
}
|
||||
|
||||
adap->dmxdev.filternum = adap->demux.filternum;
|
||||
adap->dmxdev.demux = &adap->demux.dmx;
|
||||
adap->dmxdev.capabilities = 0;
|
||||
if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
|
||||
err("dvb_dmxdev_init failed: error %d",ret);
|
||||
goto err_dmx_dev;
|
||||
}
|
||||
|
||||
if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
|
||||
&adap->demux.dmx)) < 0) {
|
||||
err("dvb_net_init failed: error %d",ret);
|
||||
goto err_net_init;
|
||||
}
|
||||
|
||||
adap->state |= DVB_USB_ADAP_STATE_DVB;
|
||||
return 0;
|
||||
|
||||
err_net_init:
|
||||
dvb_dmxdev_release(&adap->dmxdev);
|
||||
err_dmx_dev:
|
||||
dvb_dmx_release(&adap->demux);
|
||||
err_dmx:
|
||||
dvb_unregister_adapter(&adap->dvb_adap);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (adap->state & DVB_USB_ADAP_STATE_DVB) {
|
||||
deb_info("unregistering DVB part\n");
|
||||
dvb_net_release(&adap->dvb_net);
|
||||
adap->demux.dmx.close(&adap->demux.dmx);
|
||||
dvb_dmxdev_release(&adap->dmxdev);
|
||||
dvb_dmx_release(&adap->demux);
|
||||
dvb_unregister_adapter(&adap->dvb_adap);
|
||||
adap->state &= ~DVB_USB_ADAP_STATE_DVB;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
int ret = (adap->props.frontend_ctrl) ?
|
||||
adap->props.frontend_ctrl(fe, onoff) : 0;
|
||||
|
||||
if (ret < 0) {
|
||||
err("frontend_ctrl request failed");
|
||||
return ret;
|
||||
}
|
||||
if (onoff)
|
||||
adap->active_fe = fe->id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
dvb_usb_device_power_ctrl(adap->dev, 1);
|
||||
|
||||
dvb_usb_set_active_fe(fe, 1);
|
||||
|
||||
if (adap->fe_adap[fe->id].fe_init)
|
||||
adap->fe_adap[fe->id].fe_init(fe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
if (adap->fe_adap[fe->id].fe_sleep)
|
||||
adap->fe_adap[fe->id].fe_sleep(fe);
|
||||
|
||||
dvb_usb_set_active_fe(fe, 0);
|
||||
|
||||
return dvb_usb_device_power_ctrl(adap->dev, 0);
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
/* register all given adapter frontends */
|
||||
for (i = 0; i < adap->props.num_frontends; i++) {
|
||||
|
||||
if (adap->props.fe[i].frontend_attach == NULL) {
|
||||
err("strange: '%s' #%d,%d "
|
||||
"doesn't want to attach a frontend.",
|
||||
adap->dev->desc->name, adap->id, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = adap->props.fe[i].frontend_attach(adap);
|
||||
if (ret || adap->fe_adap[i].fe == NULL) {
|
||||
/* only print error when there is no FE at all */
|
||||
if (i == 0)
|
||||
err("no frontend was attached by '%s'",
|
||||
adap->dev->desc->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
adap->fe_adap[i].fe->id = i;
|
||||
|
||||
/* re-assign sleep and wakeup functions */
|
||||
adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init;
|
||||
adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup;
|
||||
adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep;
|
||||
adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep;
|
||||
|
||||
if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) {
|
||||
err("Frontend %d registration failed.", i);
|
||||
dvb_frontend_detach(adap->fe_adap[i].fe);
|
||||
adap->fe_adap[i].fe = NULL;
|
||||
/* In error case, do not try register more FEs,
|
||||
* still leaving already registered FEs alive. */
|
||||
if (i == 0)
|
||||
return -ENODEV;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only attach the tuner if the demod is there */
|
||||
if (adap->props.fe[i].tuner_attach != NULL)
|
||||
adap->props.fe[i].tuner_attach(adap);
|
||||
|
||||
adap->num_frontends_initialized++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
int i = adap->num_frontends_initialized - 1;
|
||||
|
||||
/* unregister all given adapter frontends */
|
||||
for (; i >= 0; i--) {
|
||||
if (adap->fe_adap[i].fe != NULL) {
|
||||
dvb_unregister_frontend(adap->fe_adap[i].fe);
|
||||
dvb_frontend_detach(adap->fe_adap[i].fe);
|
||||
}
|
||||
}
|
||||
adap->num_frontends_initialized = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
146
drivers/media/usb/dvb-usb/dvb-usb-firmware.c
Normal file
146
drivers/media/usb/dvb-usb/dvb-usb-firmware.c
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* dvb-usb-firmware.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
|
||||
*
|
||||
* FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
struct usb_cypress_controller {
|
||||
int id;
|
||||
const char *name; /* name of the usb controller */
|
||||
u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */
|
||||
};
|
||||
|
||||
static struct usb_cypress_controller cypress[] = {
|
||||
{ .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 },
|
||||
{ .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, 5000);
|
||||
}
|
||||
|
||||
int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
|
||||
{
|
||||
struct hexline hx;
|
||||
u8 reset;
|
||||
int ret,pos=0;
|
||||
|
||||
/* 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.");
|
||||
|
||||
while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
|
||||
deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
|
||||
ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
|
||||
|
||||
if (ret != hx.len) {
|
||||
err("error while transferring firmware "
|
||||
"(transferred size: %d, block size: %d)",
|
||||
ret,hx.len);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
err("firmware download failed at %d with %d",pos,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (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;
|
||||
}
|
||||
} else
|
||||
ret = -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_cypress_load_firmware);
|
||||
|
||||
int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
|
||||
{
|
||||
int ret;
|
||||
const struct firmware *fw = NULL;
|
||||
|
||||
if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
|
||||
err("did not find the firmware file. (%s) "
|
||||
"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
|
||||
props->firmware,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
info("downloading firmware from file '%s'",props->firmware);
|
||||
|
||||
switch (props->usb_ctrl) {
|
||||
case CYPRESS_AN2135:
|
||||
case CYPRESS_AN2235:
|
||||
case CYPRESS_FX2:
|
||||
ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl);
|
||||
break;
|
||||
case DEVICE_SPECIFIC:
|
||||
if (props->download_firmware)
|
||||
ret = props->download_firmware(udev,fw);
|
||||
else {
|
||||
err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
|
||||
int *pos)
|
||||
{
|
||||
u8 *b = (u8 *) &fw->data[*pos];
|
||||
int data_offs = 4;
|
||||
if (*pos >= fw->size)
|
||||
return 0;
|
||||
|
||||
memset(hx,0,sizeof(struct hexline));
|
||||
|
||||
hx->len = b[0];
|
||||
|
||||
if ((*pos + hx->len + 4) >= fw->size)
|
||||
return -EINVAL;
|
||||
|
||||
hx->addr = b[1] | (b[2] << 8);
|
||||
hx->type = b[3];
|
||||
|
||||
if (hx->type == 0x04) {
|
||||
/* b[4] and b[5] are the Extended linear address record data field */
|
||||
hx->addr |= (b[4] << 24) | (b[5] << 16);
|
||||
/* hx->len -= 2;
|
||||
data_offs += 2; */
|
||||
}
|
||||
memcpy(hx->data,&b[data_offs],hx->len);
|
||||
hx->chk = b[hx->len + data_offs];
|
||||
|
||||
*pos += hx->len + 5;
|
||||
|
||||
return *pos;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_get_hexline);
|
||||
43
drivers/media/usb/dvb-usb/dvb-usb-i2c.c
Normal file
43
drivers/media/usb/dvb-usb/dvb-usb-i2c.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* dvb-usb-i2c.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 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;
|
||||
}
|
||||
|
||||
strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
|
||||
d->i2c_adap.algo = d->props.i2c_algo;
|
||||
d->i2c_adap.algo_data = NULL;
|
||||
d->i2c_adap.dev.parent = &d->udev->dev;
|
||||
|
||||
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;
|
||||
}
|
||||
304
drivers/media/usb/dvb-usb/dvb-usb-init.c
Normal file
304
drivers/media/usb/dvb-usb/dvb-usb-init.c
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* DVB USB library - provides a generic interface for a DVB USB device driver.
|
||||
*
|
||||
* dvb-usb-init.c
|
||||
*
|
||||
* Copyright (C) 2004-6 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,mem=128,uxfer=256 (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).");
|
||||
|
||||
static int dvb_usb_force_pid_filter_usage;
|
||||
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
|
||||
MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
|
||||
|
||||
static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
|
||||
{
|
||||
struct dvb_usb_adapter *adap;
|
||||
int ret, n, o;
|
||||
|
||||
for (n = 0; n < d->props.num_adapters; n++) {
|
||||
adap = &d->adapter[n];
|
||||
adap->dev = d;
|
||||
adap->id = n;
|
||||
|
||||
memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
|
||||
|
||||
for (o = 0; o < adap->props.num_frontends; o++) {
|
||||
struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
|
||||
/* speed - when running at FULL speed we need a HW PID filter */
|
||||
if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_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 && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
|
||||
(props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
|
||||
info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
|
||||
adap->fe_adap[o].pid_filtering = 1;
|
||||
adap->fe_adap[o].max_feed_count = props->pid_filter_count;
|
||||
} else {
|
||||
info("will pass the complete MPEG2 transport stream to the software demuxer.");
|
||||
adap->fe_adap[o].pid_filtering = 0;
|
||||
adap->fe_adap[o].max_feed_count = 255;
|
||||
}
|
||||
|
||||
if (!adap->fe_adap[o].pid_filtering &&
|
||||
dvb_usb_force_pid_filter_usage &&
|
||||
props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
|
||||
info("pid filter enabled by module option.");
|
||||
adap->fe_adap[o].pid_filtering = 1;
|
||||
adap->fe_adap[o].max_feed_count = props->pid_filter_count;
|
||||
}
|
||||
|
||||
if (props->size_of_priv > 0) {
|
||||
adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
|
||||
if (adap->fe_adap[o].priv == NULL) {
|
||||
err("no memory for priv for adapter %d fe %d.", n, o);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adap->props.size_of_priv > 0) {
|
||||
adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
|
||||
if (adap->priv == NULL) {
|
||||
err("no memory for priv for adapter %d.", n);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = dvb_usb_adapter_stream_init(adap)) ||
|
||||
(ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) ||
|
||||
(ret = dvb_usb_adapter_frontend_init(adap))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* use exclusive FE lock if there is multiple shared FEs */
|
||||
if (adap->fe_adap[1].fe)
|
||||
adap->dvb_adap.mfe_shared = 1;
|
||||
|
||||
d->num_adapters_initialized++;
|
||||
d->state |= DVB_USB_STATE_DVB;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < d->num_adapters_initialized; n++) {
|
||||
dvb_usb_adapter_frontend_exit(&d->adapter[n]);
|
||||
dvb_usb_adapter_dvb_exit(&d->adapter[n]);
|
||||
dvb_usb_adapter_stream_exit(&d->adapter[n]);
|
||||
kfree(d->adapter[n].priv);
|
||||
}
|
||||
d->num_adapters_initialized = 0;
|
||||
d->state &= ~DVB_USB_STATE_DVB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* general initialization functions */
|
||||
static 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_adapter_exit(d);
|
||||
dvb_usb_i2c_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, short *adapter_nums)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_init(&d->usb_mutex);
|
||||
mutex_init(&d->i2c_mutex);
|
||||
|
||||
d->state = DVB_USB_STATE_INIT;
|
||||
|
||||
if (d->props.size_of_priv > 0) {
|
||||
d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
|
||||
if (d->priv == NULL) {
|
||||
err("no memory for priv in 'struct dvb_usb_device'");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* check the capabilities and set appropriate variables */
|
||||
dvb_usb_device_power_ctrl(d, 1);
|
||||
|
||||
if ((ret = dvb_usb_i2c_init(d)) ||
|
||||
(ret = dvb_usb_adapter_init(d, adapter_nums))) {
|
||||
dvb_usb_exit(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dvb_usb_remote_init(d)))
|
||||
err("could not initialize remote control.");
|
||||
|
||||
dvb_usb_device_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_device_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;
|
||||
}
|
||||
|
||||
int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
if (onoff)
|
||||
d->powered++;
|
||||
else
|
||||
d->powered--;
|
||||
|
||||
if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
|
||||
deb_info("power control: %d\n", onoff);
|
||||
if (d->props.power_ctrl)
|
||||
return d->props.power_ctrl(d, onoff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* USB
|
||||
*/
|
||||
int dvb_usb_device_init(struct usb_interface *intf,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct module *owner, struct dvb_usb_device **du,
|
||||
short *adapter_nums)
|
||||
{
|
||||
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 (du != NULL)
|
||||
*du = NULL;
|
||||
|
||||
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 = dvb_usb_download_firmware(udev, props);
|
||||
if (!props->no_reconnect || ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
info("found a '%s' in warm state.", desc->name);
|
||||
d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
|
||||
if (d == NULL) {
|
||||
err("no memory for 'struct dvb_usb_device'");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
d->udev = udev;
|
||||
memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
|
||||
d->desc = desc;
|
||||
d->owner = owner;
|
||||
|
||||
usb_set_intfdata(intf, d);
|
||||
|
||||
if (du != NULL)
|
||||
*du = d;
|
||||
|
||||
ret = dvb_usb_init(d, adapter_nums);
|
||||
|
||||
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_VERSION("1.0");
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
|
||||
MODULE_LICENSE("GPL");
|
||||
391
drivers/media/usb/dvb-usb/dvb-usb-remote.c
Normal file
391
drivers/media/usb/dvb-usb/dvb-usb-remote.c
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
/* dvb-usb-remote.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file contains functions for initializing the input-device and for handling remote-control-queries.
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
static unsigned int
|
||||
legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
|
||||
struct rc_map_table *keymap,
|
||||
unsigned int keymap_size)
|
||||
{
|
||||
unsigned int index;
|
||||
unsigned int scancode;
|
||||
|
||||
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
|
||||
index = ke->index;
|
||||
} else {
|
||||
if (input_scancode_to_scalar(ke, &scancode))
|
||||
return keymap_size;
|
||||
|
||||
/* See if we can match the raw key code. */
|
||||
for (index = 0; index < keymap_size; index++)
|
||||
if (keymap[index].scancode == scancode)
|
||||
break;
|
||||
|
||||
/* See if there is an unused hole in the map */
|
||||
if (index >= keymap_size) {
|
||||
for (index = 0; index < keymap_size; index++) {
|
||||
if (keymap[index].keycode == KEY_RESERVED ||
|
||||
keymap[index].keycode == KEY_UNKNOWN) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
|
||||
struct input_keymap_entry *ke)
|
||||
{
|
||||
struct dvb_usb_device *d = input_get_drvdata(dev);
|
||||
struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
|
||||
unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
|
||||
unsigned int index;
|
||||
|
||||
index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
|
||||
if (index >= keymap_size)
|
||||
return -EINVAL;
|
||||
|
||||
ke->keycode = keymap[index].keycode;
|
||||
if (ke->keycode == KEY_UNKNOWN)
|
||||
ke->keycode = KEY_RESERVED;
|
||||
ke->len = sizeof(keymap[index].scancode);
|
||||
memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
|
||||
ke->index = index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
|
||||
const struct input_keymap_entry *ke,
|
||||
unsigned int *old_keycode)
|
||||
{
|
||||
struct dvb_usb_device *d = input_get_drvdata(dev);
|
||||
struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
|
||||
unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
|
||||
unsigned int index;
|
||||
|
||||
index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
|
||||
/*
|
||||
* FIXME: Currently, it is not possible to increase the size of
|
||||
* scancode table. For it to happen, one possibility
|
||||
* would be to allocate a table with key_map_size + 1,
|
||||
* copying data, appending the new key on it, and freeing
|
||||
* the old one - or maybe just allocating some spare space
|
||||
*/
|
||||
if (index >= keymap_size)
|
||||
return -EINVAL;
|
||||
|
||||
*old_keycode = keymap[index].keycode;
|
||||
keymap->keycode = ke->keycode;
|
||||
__set_bit(ke->keycode, dev->keybit);
|
||||
|
||||
if (*old_keycode != KEY_RESERVED) {
|
||||
__clear_bit(*old_keycode, dev->keybit);
|
||||
for (index = 0; index < keymap_size; index++) {
|
||||
if (keymap[index].keycode == *old_keycode) {
|
||||
__set_bit(*old_keycode, dev->keybit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 legacy_dvb_usb_read_remote_control(struct work_struct *work)
|
||||
{
|
||||
struct dvb_usb_device *d =
|
||||
container_of(work, struct dvb_usb_device, rc_query_work.work);
|
||||
u32 event;
|
||||
int state;
|
||||
|
||||
/* 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.legacy.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->input_dev, EV_KEY, event, 1);
|
||||
input_sync(d->input_dev);
|
||||
input_event(d->input_dev, EV_KEY, d->last_event, 0);
|
||||
input_sync(d->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.legacy.rc_interval));
|
||||
}
|
||||
|
||||
static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int i, err, rc_interval;
|
||||
struct input_dev *input_dev;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
input_dev->name = "IR-receiver inside an USB DVB receiver";
|
||||
input_dev->phys = d->rc_phys;
|
||||
usb_to_input_id(d->udev, &input_dev->id);
|
||||
input_dev->dev.parent = &d->udev->dev;
|
||||
d->input_dev = input_dev;
|
||||
d->rc_dev = NULL;
|
||||
|
||||
input_dev->getkeycode = legacy_dvb_usb_getkeycode;
|
||||
input_dev->setkeycode = legacy_dvb_usb_setkeycode;
|
||||
|
||||
/* set the bits for the keys */
|
||||
deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
|
||||
for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
|
||||
deb_rc("setting bit for event %d item %d\n",
|
||||
d->props.rc.legacy.rc_map_table[i].keycode, i);
|
||||
set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
|
||||
}
|
||||
|
||||
/* setting these two values to non-zero, we have to manage key repeats */
|
||||
input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
|
||||
input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150;
|
||||
|
||||
input_set_drvdata(input_dev, d);
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
input_free_device(input_dev);
|
||||
|
||||
rc_interval = d->props.rc.legacy.rc_interval;
|
||||
|
||||
INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
|
||||
|
||||
info("schedule remote query interval to %d msecs.", rc_interval);
|
||||
schedule_delayed_work(&d->rc_query_work,
|
||||
msecs_to_jiffies(rc_interval));
|
||||
|
||||
d->state |= DVB_USB_STATE_REMOTE;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 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(struct work_struct *work)
|
||||
{
|
||||
struct dvb_usb_device *d =
|
||||
container_of(work, struct dvb_usb_device, rc_query_work.work);
|
||||
int err;
|
||||
|
||||
/* 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, or when bulk mode is enabled after IR init
|
||||
*/
|
||||
if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
|
||||
return;
|
||||
|
||||
err = d->props.rc.core.rc_query(d);
|
||||
if (err)
|
||||
err("error %d while querying for an remote control event.", err);
|
||||
|
||||
schedule_delayed_work(&d->rc_query_work,
|
||||
msecs_to_jiffies(d->props.rc.core.rc_interval));
|
||||
}
|
||||
|
||||
static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int err, rc_interval;
|
||||
struct rc_dev *dev;
|
||||
|
||||
dev = rc_allocate_device();
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->driver_name = d->props.rc.core.module_name;
|
||||
dev->map_name = d->props.rc.core.rc_codes;
|
||||
dev->change_protocol = d->props.rc.core.change_protocol;
|
||||
dev->allowed_protocols = d->props.rc.core.allowed_protos;
|
||||
dev->driver_type = d->props.rc.core.driver_type;
|
||||
usb_to_input_id(d->udev, &dev->input_id);
|
||||
dev->input_name = "IR-receiver inside an USB DVB receiver";
|
||||
dev->input_phys = d->rc_phys;
|
||||
dev->dev.parent = &d->udev->dev;
|
||||
dev->priv = d;
|
||||
|
||||
err = rc_register_device(dev);
|
||||
if (err < 0) {
|
||||
rc_free_device(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
d->input_dev = NULL;
|
||||
d->rc_dev = dev;
|
||||
|
||||
if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
|
||||
return 0;
|
||||
|
||||
/* Polling mode - initialize a work queue for handling it */
|
||||
INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
|
||||
|
||||
rc_interval = d->props.rc.core.rc_interval;
|
||||
|
||||
info("schedule remote query interval to %d msecs.", rc_interval);
|
||||
schedule_delayed_work(&d->rc_query_work,
|
||||
msecs_to_jiffies(rc_interval));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvb_usb_remote_init(struct dvb_usb_device *d)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (dvb_usb_disable_rc_polling)
|
||||
return 0;
|
||||
|
||||
if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
|
||||
d->props.rc.mode = DVB_RC_LEGACY;
|
||||
else if (d->props.rc.core.rc_codes)
|
||||
d->props.rc.mode = DVB_RC_CORE;
|
||||
else
|
||||
return 0;
|
||||
|
||||
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
|
||||
strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
|
||||
|
||||
/* Start the remote-control polling. */
|
||||
if (d->props.rc.legacy.rc_interval < 40)
|
||||
d->props.rc.legacy.rc_interval = 100; /* default */
|
||||
|
||||
if (d->props.rc.mode == DVB_RC_LEGACY)
|
||||
err = legacy_dvb_usb_remote_init(d);
|
||||
else
|
||||
err = rc_core_dvb_usb_remote_init(d);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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_sync(&d->rc_query_work);
|
||||
if (d->props.rc.mode == DVB_RC_LEGACY)
|
||||
input_unregister_device(d->input_dev);
|
||||
else
|
||||
rc_unregister_device(d->rc_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 rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
|
||||
*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 < d->props.rc.legacy.rc_map_size; i++)
|
||||
if (rc5_custom(&keymap[i]) == keybuf[1] &&
|
||||
rc5_data(&keymap[i]) == keybuf[3]) {
|
||||
*event = keymap[i].keycode;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
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("unknown type of remote status: %d\n",keybuf[0]);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
|
||||
121
drivers/media/usb/dvb-usb/dvb-usb-urb.c
Normal file
121
drivers/media/usb/dvb-usb/dvb-usb-urb.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/* dvb-usb-urb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file keeps 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 || wbuf == NULL || wlen == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (d->props.generic_bulk_ctrl_endpoint == 0) {
|
||||
err("endpoint for generic control not specified.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
deb_xfer(">>> ");
|
||||
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,
|
||||
2000);
|
||||
|
||||
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_response ?
|
||||
d->props.generic_bulk_ctrl_endpoint_response :
|
||||
d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
|
||||
2000);
|
||||
|
||||
if (ret)
|
||||
err("recv bulk message failed: %d",ret);
|
||||
else {
|
||||
deb_xfer("<<< ");
|
||||
debug_dump(rbuf,actlen,deb_xfer);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
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_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = stream->user_priv;
|
||||
if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
|
||||
dvb_dmx_swfilter(&adap->demux, buffer, length);
|
||||
}
|
||||
|
||||
static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = stream->user_priv;
|
||||
if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
|
||||
dvb_dmx_swfilter_204(&adap->demux, buffer, length);
|
||||
}
|
||||
|
||||
static void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
|
||||
u8 *buffer, size_t length)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = stream->user_priv;
|
||||
if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
|
||||
dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
int i, ret = 0;
|
||||
for (i = 0; i < adap->props.num_frontends; i++) {
|
||||
|
||||
adap->fe_adap[i].stream.udev = adap->dev->udev;
|
||||
if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
|
||||
adap->fe_adap[i].stream.complete =
|
||||
dvb_usb_data_complete_204;
|
||||
else
|
||||
if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
|
||||
adap->fe_adap[i].stream.complete =
|
||||
dvb_usb_data_complete_raw;
|
||||
else
|
||||
adap->fe_adap[i].stream.complete = dvb_usb_data_complete;
|
||||
adap->fe_adap[i].stream.user_priv = adap;
|
||||
ret = usb_urb_init(&adap->fe_adap[i].stream,
|
||||
&adap->props.fe[i].stream);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < adap->props.num_frontends; i++)
|
||||
usb_urb_exit(&adap->fe_adap[i].stream);
|
||||
return 0;
|
||||
}
|
||||
483
drivers/media/usb/dvb-usb/dvb-usb.h
Normal file
483
drivers/media/usb/dvb-usb/dvb-usb.h
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
/* dvb-usb.h is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* the headerfile, all dvb-usb-drivers have to include.
|
||||
*
|
||||
* TODO: clean-up the structures for unused fields and update the comments
|
||||
*/
|
||||
#ifndef __DVB_USB_H__
|
||||
#define __DVB_USB_H__
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_net.h"
|
||||
#include "dmxdev.h"
|
||||
|
||||
#include "dvb-pll.h"
|
||||
|
||||
#include "dvb-usb-ids.h"
|
||||
|
||||
/* debug */
|
||||
#ifdef CONFIG_DVB_USB_DEBUG
|
||||
#define dprintk(var,level,args...) \
|
||||
do { if ((var & level)) { printk(args); } } while (0)
|
||||
|
||||
#define debug_dump(b,l,func) {\
|
||||
int loop_; \
|
||||
for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
|
||||
func("\n");\
|
||||
}
|
||||
#define DVB_USB_DEBUG_STATUS
|
||||
#else
|
||||
#define dprintk(args...)
|
||||
#define debug_dump(b,l,func)
|
||||
|
||||
#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
|
||||
|
||||
#endif
|
||||
|
||||
/* generic log methods - taken from usb.h */
|
||||
#ifndef DVB_USB_LOG_PREFIX
|
||||
#define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
|
||||
#endif
|
||||
|
||||
#undef err
|
||||
#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
#undef info
|
||||
#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
#undef warn
|
||||
#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
|
||||
|
||||
/**
|
||||
* struct dvb_usb_device_description - name and its according USB IDs
|
||||
* @name: real name of the box, regardless which DVB USB device class is in use
|
||||
* @cold_ids: array of struct usb_device_id which describe the device in
|
||||
* pre-firmware state
|
||||
* @warm_ids: array of struct usb_device_id which describe the device in
|
||||
* post-firmware state
|
||||
*
|
||||
* Each DVB USB device class can have one or more actual devices, this struct
|
||||
* assigns a name to it.
|
||||
*/
|
||||
struct dvb_usb_device_description {
|
||||
const char *name;
|
||||
|
||||
#define DVB_USB_ID_MAX_NUM 15
|
||||
struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
|
||||
struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
|
||||
};
|
||||
|
||||
static inline u8 rc5_custom(struct rc_map_table *key)
|
||||
{
|
||||
return (key->scancode >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static inline u8 rc5_data(struct rc_map_table *key)
|
||||
{
|
||||
return key->scancode & 0xff;
|
||||
}
|
||||
|
||||
static inline u16 rc5_scan(struct rc_map_table *key)
|
||||
{
|
||||
return key->scancode & 0xffff;
|
||||
}
|
||||
|
||||
struct dvb_usb_device;
|
||||
struct dvb_usb_adapter;
|
||||
struct usb_data_stream;
|
||||
|
||||
/**
|
||||
* Properties of USB streaming - TODO this structure should be somewhere else
|
||||
* describes the kind of USB transfer used for data-streaming.
|
||||
* (BULK or ISOC)
|
||||
*/
|
||||
struct usb_data_stream_properties {
|
||||
#define USB_BULK 1
|
||||
#define USB_ISOC 2
|
||||
int type;
|
||||
int count;
|
||||
int endpoint;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int buffersize; /* per URB */
|
||||
} bulk;
|
||||
struct {
|
||||
int framesperurb;
|
||||
int framesize;
|
||||
int interval;
|
||||
} isoc;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
|
||||
* A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
|
||||
* @caps: capabilities of the DVB USB device.
|
||||
* @pid_filter_count: number of PID filter position in the optional hardware
|
||||
* PID-filter.
|
||||
* @num_frontends: number of frontends of the DVB USB adapter.
|
||||
* @frontend_ctrl: called to power on/off active frontend.
|
||||
* @streaming_ctrl: 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.
|
||||
* @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).
|
||||
* @stream: configuration of the USB streaming
|
||||
*/
|
||||
struct dvb_usb_adapter_fe_properties {
|
||||
#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
|
||||
#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
|
||||
#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
|
||||
#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
|
||||
#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10
|
||||
int caps;
|
||||
int pid_filter_count;
|
||||
|
||||
int (*streaming_ctrl) (struct dvb_usb_adapter *, int);
|
||||
int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
|
||||
int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
|
||||
|
||||
int (*frontend_attach) (struct dvb_usb_adapter *);
|
||||
int (*tuner_attach) (struct dvb_usb_adapter *);
|
||||
|
||||
struct usb_data_stream_properties stream;
|
||||
|
||||
int size_of_priv;
|
||||
};
|
||||
|
||||
#define MAX_NO_OF_FE_PER_ADAP 3
|
||||
struct dvb_usb_adapter_properties {
|
||||
int size_of_priv;
|
||||
|
||||
int (*frontend_ctrl) (struct dvb_frontend *, int);
|
||||
|
||||
int num_frontends;
|
||||
struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_rc_legacy - old properties of remote controller
|
||||
* @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
|
||||
* remote control handling).
|
||||
* @rc_map_size: number of items in @rc_map_table.
|
||||
* @rc_query: called to query an event event.
|
||||
* @rc_interval: time in ms between two queries.
|
||||
*/
|
||||
struct dvb_rc_legacy {
|
||||
/* remote control properties */
|
||||
#define REMOTE_NO_KEY_PRESSED 0x00
|
||||
#define REMOTE_KEY_PRESSED 0x01
|
||||
#define REMOTE_KEY_REPEAT 0x02
|
||||
struct rc_map_table *rc_map_table;
|
||||
int rc_map_size;
|
||||
int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
|
||||
int rc_interval;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_rc properties of remote controller, using rc-core
|
||||
* @rc_codes: name of rc codes table
|
||||
* @protocol: type of protocol(s) currently used by the driver
|
||||
* @allowed_protos: protocol(s) supported by the driver
|
||||
* @driver_type: Used to point if a device supports raw mode
|
||||
* @change_protocol: callback to change protocol
|
||||
* @rc_query: called to query an event event.
|
||||
* @rc_interval: time in ms between two queries.
|
||||
* @bulk_mode: device supports bulk mode for RC (disable polling mode)
|
||||
*/
|
||||
struct dvb_rc {
|
||||
char *rc_codes;
|
||||
u64 protocol;
|
||||
u64 allowed_protos;
|
||||
enum rc_driver_type driver_type;
|
||||
int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
|
||||
char *module_name;
|
||||
int (*rc_query) (struct dvb_usb_device *d);
|
||||
int rc_interval;
|
||||
bool bulk_mode; /* uses bulk mode */
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
|
||||
* based on rc-core
|
||||
* This is initialized/used only inside dvb-usb-remote.c.
|
||||
* It shouldn't be set by the drivers.
|
||||
*/
|
||||
enum dvb_usb_mode {
|
||||
DVB_RC_LEGACY,
|
||||
DVB_RC_CORE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_device_properties - properties of a dvb-usb-device
|
||||
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
|
||||
* download.
|
||||
* @firmware: name of the firmware file.
|
||||
* @download_firmware: called to download the firmware when the usb_ctrl is
|
||||
* DEVICE_SPECIFIC.
|
||||
* @no_reconnect: device doesn't do a reconnect after downloading the firmware,
|
||||
* so do the warm initialization right after it
|
||||
*
|
||||
* @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.
|
||||
* @read_mac_address: called to read the MAC address of the device.
|
||||
* @identify_state: called to determine the state (cold or warm), when it
|
||||
* is not distinguishable by the USB IDs.
|
||||
*
|
||||
* @rc: remote controller properties
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate
|
||||
* endpoint for responses to control messages sent with bulk transfers via
|
||||
* the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used
|
||||
* instead of the generic_bulk_ctrl_endpoint when reading usb responses in
|
||||
* the dvb_usb_generic_rw helper function.
|
||||
*
|
||||
* @num_device_descs: number of struct dvb_usb_device_description in @devices
|
||||
* @devices: array of struct dvb_usb_device_description compatibles with these
|
||||
* properties.
|
||||
*/
|
||||
#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
|
||||
struct dvb_usb_device_properties {
|
||||
|
||||
#define DVB_USB_IS_AN_I2C_ADAPTER 0x01
|
||||
int caps;
|
||||
|
||||
#define DEVICE_SPECIFIC 0
|
||||
#define CYPRESS_AN2135 1
|
||||
#define CYPRESS_AN2235 2
|
||||
#define CYPRESS_FX2 3
|
||||
int usb_ctrl;
|
||||
int (*download_firmware) (struct usb_device *, const struct firmware *);
|
||||
const char *firmware;
|
||||
int no_reconnect;
|
||||
|
||||
int size_of_priv;
|
||||
|
||||
int num_adapters;
|
||||
struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
|
||||
|
||||
int (*power_ctrl) (struct dvb_usb_device *, int);
|
||||
int (*read_mac_address) (struct dvb_usb_device *, u8 []);
|
||||
int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
|
||||
struct dvb_usb_device_description **, int *);
|
||||
|
||||
struct {
|
||||
enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */
|
||||
struct dvb_rc_legacy legacy;
|
||||
struct dvb_rc core;
|
||||
} rc;
|
||||
|
||||
struct i2c_algorithm *i2c_algo;
|
||||
|
||||
int generic_bulk_ctrl_endpoint;
|
||||
int generic_bulk_ctrl_endpoint_response;
|
||||
|
||||
int num_device_descs;
|
||||
struct dvb_usb_device_description devices[12];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct usb_data_stream - generic object of an USB stream
|
||||
* @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.
|
||||
*/
|
||||
#define MAX_NO_URBS_FOR_DATA_STREAM 10
|
||||
struct usb_data_stream {
|
||||
struct usb_device *udev;
|
||||
struct usb_data_stream_properties props;
|
||||
|
||||
#define USB_STATE_INIT 0x00
|
||||
#define USB_STATE_URB_BUF 0x01
|
||||
int state;
|
||||
|
||||
void (*complete) (struct usb_data_stream *, u8 *, size_t);
|
||||
|
||||
struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
int buf_num;
|
||||
unsigned long buf_size;
|
||||
u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
|
||||
|
||||
int urbs_initialized;
|
||||
int urbs_submitted;
|
||||
|
||||
void *user_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_usb_adapter - a DVB adapter on a USB device
|
||||
* @id: index of this adapter (starting with 0).
|
||||
*
|
||||
* @feedcount: number of reqested feeds (used for streaming-activation)
|
||||
* @pid_filtering: is hardware pid_filtering used or not.
|
||||
*
|
||||
* @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 or the board
|
||||
*
|
||||
* @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_init: rerouted frontend-init (wakeup) function.
|
||||
* @fe_sleep: rerouted frontend-sleep function.
|
||||
*
|
||||
* @stream: the usb data stream.
|
||||
*/
|
||||
struct dvb_usb_fe_adapter {
|
||||
struct dvb_frontend *fe;
|
||||
|
||||
int (*fe_init) (struct dvb_frontend *);
|
||||
int (*fe_sleep) (struct dvb_frontend *);
|
||||
|
||||
struct usb_data_stream stream;
|
||||
|
||||
int pid_filtering;
|
||||
int max_feed_count;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct dvb_usb_adapter {
|
||||
struct dvb_usb_device *dev;
|
||||
struct dvb_usb_adapter_properties props;
|
||||
|
||||
#define DVB_USB_ADAP_STATE_INIT 0x000
|
||||
#define DVB_USB_ADAP_STATE_DVB 0x001
|
||||
int state;
|
||||
|
||||
u8 id;
|
||||
|
||||
int feedcount;
|
||||
|
||||
/* dvb */
|
||||
struct dvb_adapter dvb_adap;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_demux demux;
|
||||
struct dvb_net dvb_net;
|
||||
|
||||
struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP];
|
||||
int active_fe;
|
||||
int num_frontends_initialized;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @powered: indicated whether the device is power or not.
|
||||
* Powered is in/decremented for each call to modify the state.
|
||||
* @udev: pointer to the device's struct usb_device.
|
||||
*
|
||||
* @usb_mutex: semaphore of USB control messages (reading needs two messages)
|
||||
* @i2c_mutex: semaphore for i2c-transfers
|
||||
*
|
||||
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
|
||||
*
|
||||
* @rc_dev: rc device for the remote control (rc-core mode)
|
||||
* @input_dev: input device for the remote control (legacy mode)
|
||||
* @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_device_properties props;
|
||||
struct dvb_usb_device_description *desc;
|
||||
|
||||
struct usb_device *udev;
|
||||
|
||||
#define DVB_USB_STATE_INIT 0x000
|
||||
#define DVB_USB_STATE_I2C 0x001
|
||||
#define DVB_USB_STATE_DVB 0x002
|
||||
#define DVB_USB_STATE_REMOTE 0x004
|
||||
int state;
|
||||
|
||||
int powered;
|
||||
|
||||
/* locking */
|
||||
struct mutex usb_mutex;
|
||||
|
||||
/* i2c */
|
||||
struct mutex i2c_mutex;
|
||||
struct i2c_adapter i2c_adap;
|
||||
|
||||
int num_adapters_initialized;
|
||||
struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
|
||||
|
||||
/* remote control */
|
||||
struct rc_dev *rc_dev;
|
||||
struct input_dev *input_dev;
|
||||
char rc_phys[64];
|
||||
struct delayed_work 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_device_properties *,
|
||||
struct module *, struct dvb_usb_device **,
|
||||
short *adapter_nums);
|
||||
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 firmware download types and function */
|
||||
struct hexline {
|
||||
u8 len;
|
||||
u32 addr;
|
||||
u8 type;
|
||||
u8 data[255];
|
||||
u8 chk;
|
||||
};
|
||||
extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
|
||||
extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
|
||||
|
||||
|
||||
#endif
|
||||
2168
drivers/media/usb/dvb-usb/dw2102.c
Normal file
2168
drivers/media/usb/dvb-usb/dw2102.c
Normal file
File diff suppressed because it is too large
Load diff
9
drivers/media/usb/dvb-usb/dw2102.h
Normal file
9
drivers/media/usb/dvb-usb/dw2102.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _DW2102_H_
|
||||
#define _DW2102_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "dw2102"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args)
|
||||
#endif
|
||||
472
drivers/media/usb/dvb-usb/friio-fe.c
Normal file
472
drivers/media/usb/dvb-usb/friio-fe.c
Normal file
|
|
@ -0,0 +1,472 @@
|
|||
/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
|
||||
*
|
||||
* This module is based off the the gl861 and vp702x modules.
|
||||
*
|
||||
* 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 <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "friio.h"
|
||||
|
||||
struct jdvbt90502_state {
|
||||
struct i2c_adapter *i2c;
|
||||
struct dvb_frontend frontend;
|
||||
struct jdvbt90502_config config;
|
||||
};
|
||||
|
||||
/* NOTE: TC90502 has 16bit register-address? */
|
||||
/* register 0x0100 is used for reading PLL status, so reg is u16 here */
|
||||
static int jdvbt90502_reg_read(struct jdvbt90502_state *state,
|
||||
const u16 reg, u8 *buf, const size_t count)
|
||||
{
|
||||
int ret;
|
||||
u8 wbuf[3];
|
||||
struct i2c_msg msg[2];
|
||||
|
||||
wbuf[0] = reg & 0xFF;
|
||||
wbuf[1] = 0;
|
||||
wbuf[2] = reg >> 8;
|
||||
|
||||
msg[0].addr = state->config.demod_address;
|
||||
msg[0].flags = 0;
|
||||
msg[0].buf = wbuf;
|
||||
msg[0].len = sizeof(wbuf);
|
||||
|
||||
msg[1].addr = msg[0].addr;
|
||||
msg[1].flags = I2C_M_RD;
|
||||
msg[1].buf = buf;
|
||||
msg[1].len = count;
|
||||
|
||||
ret = i2c_transfer(state->i2c, msg, 2);
|
||||
if (ret != 2) {
|
||||
deb_fe(" reg read failed.\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* currently 16bit register-address is not used, so reg is u8 here */
|
||||
static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
|
||||
const u8 reg, const u8 val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
u8 wbuf[2];
|
||||
|
||||
wbuf[0] = reg;
|
||||
wbuf[1] = val;
|
||||
|
||||
msg.addr = state->config.demod_address;
|
||||
msg.flags = 0;
|
||||
msg.buf = wbuf;
|
||||
msg.len = sizeof(wbuf);
|
||||
|
||||
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
|
||||
deb_fe(" reg write failed.");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
|
||||
{
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
int err, i;
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
err = jdvbt90502_single_reg_write(state,
|
||||
buf[0] + i, buf[i + 1]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read pll status byte via the demodulator's I2C register */
|
||||
/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */
|
||||
static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* +1 for reading */
|
||||
u8 pll_addr_byte = (state->config.pll_address << 1) + 1;
|
||||
|
||||
*result = 0;
|
||||
|
||||
ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG,
|
||||
pll_addr_byte);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = jdvbt90502_reg_read(state, 0x0100, result, 1);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
deb_fe("PLL read val:%02x\n", *result);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
||||
/* set pll frequency via the demodulator's I2C register */
|
||||
static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
|
||||
{
|
||||
int ret;
|
||||
int retry;
|
||||
u8 res1;
|
||||
u8 res2[9];
|
||||
|
||||
u8 pll_freq_cmd[PLL_CMD_LEN];
|
||||
u8 pll_agc_cmd[PLL_CMD_LEN];
|
||||
struct i2c_msg msg[2];
|
||||
u32 f;
|
||||
|
||||
deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
|
||||
state->frontend.ops.info.frequency_stepsize);
|
||||
/* freq -> oscilator frequency conversion. */
|
||||
/* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */
|
||||
f = freq / state->frontend.ops.info.frequency_stepsize;
|
||||
/* add 399[1/7 MHZ] = 57MHz for the IF */
|
||||
f += 399;
|
||||
/* add center frequency shift if necessary */
|
||||
if (f % 7 == 0)
|
||||
f++;
|
||||
pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
|
||||
pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
|
||||
pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;
|
||||
pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF;
|
||||
pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */
|
||||
pll_freq_cmd[BANDSWITCH_BYTE] = 0x08; /* UHF band */
|
||||
|
||||
msg[0].addr = state->config.demod_address;
|
||||
msg[0].flags = 0;
|
||||
msg[0].buf = pll_freq_cmd;
|
||||
msg[0].len = sizeof(pll_freq_cmd);
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg[0], 1);
|
||||
if (ret != 1)
|
||||
goto error;
|
||||
|
||||
udelay(50);
|
||||
|
||||
pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG];
|
||||
pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE];
|
||||
pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1];
|
||||
pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2];
|
||||
pll_agc_cmd[CONTROL_BYTE] = 0x9A; /* AGC_CTRL instead of BANDSWITCH */
|
||||
pll_agc_cmd[AGC_CTRL_BYTE] = 0x50;
|
||||
/* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */
|
||||
|
||||
msg[1].addr = msg[0].addr;
|
||||
msg[1].flags = 0;
|
||||
msg[1].buf = pll_agc_cmd;
|
||||
msg[1].len = sizeof(pll_agc_cmd);
|
||||
|
||||
ret = i2c_transfer(state->i2c, &msg[1], 1);
|
||||
if (ret != 1)
|
||||
goto error;
|
||||
|
||||
/* I don't know what these cmds are for, */
|
||||
/* but the USB log on a windows box contains them */
|
||||
ret = jdvbt90502_single_reg_write(state, 0x01, 0x40);
|
||||
ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00);
|
||||
if (ret)
|
||||
goto error;
|
||||
udelay(100);
|
||||
|
||||
/* wait for the demod to be ready? */
|
||||
#define RETRY_COUNT 5
|
||||
for (retry = 0; retry < RETRY_COUNT; retry++) {
|
||||
ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1);
|
||||
if (ret)
|
||||
goto error;
|
||||
/* if (res1 != 0x00) goto error; */
|
||||
ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2));
|
||||
if (ret)
|
||||
goto error;
|
||||
if (res2[0] >= 0xA7)
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
if (retry >= RETRY_COUNT) {
|
||||
deb_fe("%s: FE does not get ready after freq setting.\n",
|
||||
__func__);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
|
||||
{
|
||||
u8 result;
|
||||
int ret;
|
||||
|
||||
*state = FE_HAS_SIGNAL;
|
||||
|
||||
ret = jdvbt90502_pll_read(fe->demodulator_priv, &result);
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
*state = FE_HAS_SIGNAL
|
||||
| FE_HAS_CARRIER
|
||||
| FE_HAS_VITERBI
|
||||
| FE_HAS_SYNC;
|
||||
|
||||
if (result & PLL_STATUS_LOCKED)
|
||||
*state |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *strength)
|
||||
{
|
||||
int ret;
|
||||
u8 rbuf[37];
|
||||
|
||||
*strength = 0;
|
||||
|
||||
/* status register (incl. signal strength) : 0x89 */
|
||||
/* TODO: read just the necessary registers [0x8B..0x8D]? */
|
||||
ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089,
|
||||
rbuf, sizeof(rbuf));
|
||||
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */
|
||||
*strength = (rbuf[3] << 8) + rbuf[4];
|
||||
if (rbuf[2])
|
||||
*strength = 0xffff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* filter out un-supported properties to notify users */
|
||||
static int jdvbt90502_set_property(struct dvb_frontend *fe,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
switch (tvp->cmd) {
|
||||
case DTV_DELIVERY_SYSTEM:
|
||||
if (tvp->u.data != SYS_ISDBT)
|
||||
r = -EINVAL;
|
||||
break;
|
||||
case DTV_CLEAR:
|
||||
case DTV_TUNE:
|
||||
case DTV_FREQUENCY:
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int jdvbt90502_get_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
p->inversion = INVERSION_AUTO;
|
||||
p->bandwidth_hz = 6000000;
|
||||
p->code_rate_HP = FEC_AUTO;
|
||||
p->code_rate_LP = FEC_AUTO;
|
||||
p->modulation = QAM_64;
|
||||
p->transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
p->guard_interval = GUARD_INTERVAL_AUTO;
|
||||
p->hierarchy = HIERARCHY_AUTO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
|
||||
/**
|
||||
* NOTE: ignore all the parameters except frequency.
|
||||
* others should be fixed to the proper value for ISDB-T,
|
||||
* but don't check here.
|
||||
*/
|
||||
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
int ret;
|
||||
|
||||
deb_fe("%s: Freq:%d\n", __func__, p->frequency);
|
||||
|
||||
/* for recovery from DTV_CLEAN */
|
||||
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
|
||||
|
||||
ret = jdvbt90502_pll_set_freq(state, p->frequency);
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (reg, val) commad list to initialize this module.
|
||||
* captured on a Windows box.
|
||||
*/
|
||||
static u8 init_code[][2] = {
|
||||
{0x01, 0x40},
|
||||
{0x04, 0x38},
|
||||
{0x05, 0x40},
|
||||
{0x07, 0x40},
|
||||
{0x0F, 0x4F},
|
||||
{0x11, 0x21},
|
||||
{0x12, 0x0B},
|
||||
{0x13, 0x2F},
|
||||
{0x14, 0x31},
|
||||
{0x16, 0x02},
|
||||
{0x21, 0xC4},
|
||||
{0x22, 0x20},
|
||||
{0x2C, 0x79},
|
||||
{0x2D, 0x34},
|
||||
{0x2F, 0x00},
|
||||
{0x30, 0x28},
|
||||
{0x31, 0x31},
|
||||
{0x32, 0xDF},
|
||||
{0x38, 0x01},
|
||||
{0x39, 0x78},
|
||||
{0x3B, 0x33},
|
||||
{0x3C, 0x33},
|
||||
{0x48, 0x90},
|
||||
{0x51, 0x68},
|
||||
{0x5E, 0x38},
|
||||
{0x71, 0x00},
|
||||
{0x72, 0x08},
|
||||
{0x77, 0x00},
|
||||
{0xC0, 0x21},
|
||||
{0xC1, 0x10},
|
||||
{0xE4, 0x1A},
|
||||
{0xEA, 0x1F},
|
||||
{0x77, 0x00},
|
||||
{0x71, 0x00},
|
||||
{0x71, 0x00},
|
||||
{0x76, 0x0C},
|
||||
};
|
||||
|
||||
static const int init_code_len = sizeof(init_code) / sizeof(u8[2]);
|
||||
|
||||
static int jdvbt90502_init(struct dvb_frontend *fe)
|
||||
{
|
||||
int i = -1;
|
||||
int ret;
|
||||
struct i2c_msg msg;
|
||||
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
|
||||
deb_fe("%s called.\n", __func__);
|
||||
|
||||
msg.addr = state->config.demod_address;
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
for (i = 0; i < init_code_len; i++) {
|
||||
msg.buf = init_code[i];
|
||||
ret = i2c_transfer(state->i2c, &msg, 1);
|
||||
if (ret != 1)
|
||||
goto error;
|
||||
}
|
||||
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
||||
static void jdvbt90502_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct jdvbt90502_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops jdvbt90502_ops;
|
||||
|
||||
struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct jdvbt90502_state *state = NULL;
|
||||
|
||||
deb_info("%s called.\n", __func__);
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->i2c = &d->i2c_adap;
|
||||
state->config = friio_fe_config;
|
||||
|
||||
/* create dvb_frontend */
|
||||
state->frontend.ops = jdvbt90502_ops;
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
if (jdvbt90502_init(&state->frontend) < 0)
|
||||
goto error;
|
||||
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops jdvbt90502_ops = {
|
||||
.delsys = { SYS_ISDBT },
|
||||
.info = {
|
||||
.name = "Comtech JDVBT90502 ISDB-T",
|
||||
.frequency_min = 473000000, /* UHF 13ch, center */
|
||||
.frequency_max = 767142857, /* UHF 62ch, center */
|
||||
.frequency_stepsize = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER,
|
||||
.frequency_tolerance = 0,
|
||||
|
||||
/* NOTE: this driver ignores all parameters but frequency. */
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
|
||||
FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.release = jdvbt90502_release,
|
||||
|
||||
.init = jdvbt90502_init,
|
||||
.write = _jdvbt90502_write,
|
||||
|
||||
.set_property = jdvbt90502_set_property,
|
||||
|
||||
.set_frontend = jdvbt90502_set_frontend,
|
||||
.get_frontend = jdvbt90502_get_frontend,
|
||||
|
||||
.read_status = jdvbt90502_read_status,
|
||||
.read_signal_strength = jdvbt90502_read_signal_strength,
|
||||
};
|
||||
522
drivers/media/usb/dvb-usb/friio.c
Normal file
522
drivers/media/usb/dvb-usb/friio.c
Normal file
|
|
@ -0,0 +1,522 @@
|
|||
/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
|
||||
*
|
||||
* This module is based off the the gl861 and vp702x modules.
|
||||
*
|
||||
* 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 "friio.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_friio_debug;
|
||||
module_param_named(debug, dvb_usb_friio_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,
|
||||
"set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
|
||||
DVB_USB_DEBUG_STATUS);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
/**
|
||||
* Indirect I2C access to the PLL via FE.
|
||||
* whole I2C protocol data to the PLL is sent via the FE's I2C register.
|
||||
* This is done by a control msg to the FE with the I2C data accompanied, and
|
||||
* a specific USB request number is assigned for that purpose.
|
||||
*
|
||||
* this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
|
||||
* TODO: refoctored, smarter i2c functions.
|
||||
*/
|
||||
static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index = wbuf[0]; /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
|
||||
u16 value = addr << (8 + 1);
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write only */
|
||||
u8 req, type;
|
||||
|
||||
deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
|
||||
wbuf[1], wbuf[0], wlen - 1);
|
||||
|
||||
if (wo && wlen >= 2) {
|
||||
req = GL861_REQ_I2C_DATA_CTRL_WRITE;
|
||||
type = GL861_WRITE;
|
||||
udelay(20);
|
||||
return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
req, type, value, index,
|
||||
&wbuf[1], wlen - 1, 2000);
|
||||
}
|
||||
|
||||
deb_xfer("not supported ctrl-msg, aborting.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* normal I2C access (without extra data arguments).
|
||||
* write to the register wbuf[0] at I2C address addr with the value wbuf[1],
|
||||
* or read from the register wbuf[0].
|
||||
* register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
|
||||
*/
|
||||
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index;
|
||||
u16 value = addr << (8 + 1);
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 req, type;
|
||||
unsigned int pipe;
|
||||
|
||||
/* special case for the indirect I2C access to the PLL via FE, */
|
||||
if (addr == friio_fe_config.demod_address &&
|
||||
wbuf[0] == JDVBT90502_2ND_I2C_REG)
|
||||
return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
|
||||
|
||||
if (wo) {
|
||||
req = GL861_REQ_I2C_WRITE;
|
||||
type = GL861_WRITE;
|
||||
pipe = usb_sndctrlpipe(d->udev, 0);
|
||||
} else { /* rw */
|
||||
req = GL861_REQ_I2C_READ;
|
||||
type = GL861_READ;
|
||||
pipe = usb_rcvctrlpipe(d->udev, 0);
|
||||
}
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0];
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
case 3:
|
||||
/* special case for 16bit register-address */
|
||||
index = (wbuf[2] << 8) | wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
default:
|
||||
deb_xfer("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
msleep(1);
|
||||
return usb_control_msg(d->udev, pipe, req, type,
|
||||
value, index, rbuf, rlen, 2000);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
|
||||
if (gl861_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 (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 gl861_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static int friio_ext_ctl(struct dvb_usb_adapter *adap,
|
||||
u32 sat_color, int lnb_on)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct i2c_msg msg;
|
||||
u8 *buf;
|
||||
u32 mask;
|
||||
u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
|
||||
|
||||
buf = kmalloc(2, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
msg.addr = 0x00;
|
||||
msg.flags = 0;
|
||||
msg.len = 2;
|
||||
msg.buf = buf;
|
||||
|
||||
buf[0] = 0x00;
|
||||
|
||||
/* send 2bit header (&B10) */
|
||||
buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
|
||||
ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
buf[1] = lnb | FRIIO_CTL_STROBE;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
/* send 32bit(satur, R, G, B) data in serial */
|
||||
mask = 1 << 31;
|
||||
for (i = 0; i < 32; i++) {
|
||||
buf[1] = lnb | FRIIO_CTL_STROBE;
|
||||
if (sat_color & mask)
|
||||
buf[1] |= FRIIO_CTL_LED;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
/* set the strobe off */
|
||||
buf[1] = lnb;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
buf[1] |= FRIIO_CTL_CLK;
|
||||
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
|
||||
|
||||
kfree(buf);
|
||||
return (ret == 70);
|
||||
}
|
||||
|
||||
|
||||
static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
|
||||
|
||||
/* TODO: move these init cmds to the FE's init routine? */
|
||||
static u8 streaming_init_cmds[][2] = {
|
||||
{0x33, 0x08},
|
||||
{0x37, 0x40},
|
||||
{0x3A, 0x1F},
|
||||
{0x3B, 0xFF},
|
||||
{0x3C, 0x1F},
|
||||
{0x3D, 0xFF},
|
||||
{0x38, 0x00},
|
||||
{0x35, 0x00},
|
||||
{0x39, 0x00},
|
||||
{0x36, 0x00},
|
||||
};
|
||||
static int cmdlen = sizeof(streaming_init_cmds) / 2;
|
||||
|
||||
/*
|
||||
* Command sequence in this init function is a replay
|
||||
* of the captured USB commands from the Windows proprietary driver.
|
||||
*/
|
||||
static int friio_initialize(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int retry = 0;
|
||||
u8 *rbuf, *wbuf;
|
||||
|
||||
deb_info("%s called.\n", __func__);
|
||||
|
||||
wbuf = kmalloc(3, GFP_KERNEL);
|
||||
if (!wbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
rbuf = kmalloc(2, GFP_KERNEL);
|
||||
if (!rbuf) {
|
||||
kfree(wbuf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
|
||||
/* because the i2c device is not set up yet. */
|
||||
wbuf[0] = 0x11;
|
||||
wbuf[1] = 0x02;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
msleep(2);
|
||||
|
||||
wbuf[0] = 0x11;
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
msleep(1);
|
||||
|
||||
/* following msgs should be in the FE's init code? */
|
||||
/* cmd sequence to identify the device type? (friio black/white) */
|
||||
wbuf[0] = 0x03;
|
||||
wbuf[1] = 0x80;
|
||||
/* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
|
||||
0x1200, 0x0100, wbuf, 2, 2000);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[2] = 0x01; /* reg.0x0100 */
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
|
||||
/* my Friio White returns 0xffff. */
|
||||
if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
wbuf[0] = 0x03;
|
||||
wbuf[1] = 0x80;
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
|
||||
0x9000, 0x0100, wbuf, 2, 2000);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[2] = 0x01; /* reg.0x0100 */
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
|
||||
/* my Friio White returns 0xffff again. */
|
||||
if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
|
||||
goto error;
|
||||
|
||||
msleep(1);
|
||||
|
||||
restart:
|
||||
/* ============ start DEMOD init cmds ================== */
|
||||
/* read PLL status to clear the POR bit */
|
||||
wbuf[0] = JDVBT90502_2ND_I2C_REG;
|
||||
wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1; /* +1 for reading */
|
||||
ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(5);
|
||||
/* note: DEMODULATOR has 16bit register-address. */
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[2] = 0x01; /* reg addr: 0x0100 */
|
||||
wbuf[1] = 0x00; /* val: not used */
|
||||
ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
/*
|
||||
msleep(1);
|
||||
wbuf[0] = 0x80;
|
||||
wbuf[1] = 0x00;
|
||||
ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
*/
|
||||
if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */
|
||||
if (++retry > 3) {
|
||||
deb_info("failed to get the correct"
|
||||
" FE demod status:0x%02x\n", rbuf[0]);
|
||||
goto error;
|
||||
}
|
||||
msleep(100);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/* TODO: check return value in rbuf */
|
||||
/* =========== end DEMOD init cmds ===================== */
|
||||
msleep(1);
|
||||
|
||||
wbuf[0] = 0x30;
|
||||
wbuf[1] = 0x04;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
msleep(2);
|
||||
/* following 2 cmds unnecessary? */
|
||||
wbuf[0] = 0x00;
|
||||
wbuf[1] = 0x01;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
wbuf[0] = 0x06;
|
||||
wbuf[1] = 0x0F;
|
||||
ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
/* some streaming ctl cmds (maybe) */
|
||||
msleep(10);
|
||||
for (i = 0; i < cmdlen; i++) {
|
||||
ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
|
||||
NULL, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
msleep(1);
|
||||
}
|
||||
msleep(20);
|
||||
|
||||
/* change the LED color etc. */
|
||||
ret = friio_streaming_ctrl(&d->adapter[0], 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(wbuf);
|
||||
kfree(rbuf);
|
||||
deb_info("%s:ret == %d\n", __func__, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
|
||||
static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
int ret;
|
||||
|
||||
deb_info("%s called.(%d)\n", __func__, onoff);
|
||||
|
||||
/* set the LED color and saturation (and LNB on) */
|
||||
if (onoff)
|
||||
ret = friio_ext_ctl(adap, 0x6400ff64, 1);
|
||||
else
|
||||
ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
|
||||
|
||||
if (ret != 1) {
|
||||
deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int friio_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (friio_initialize(adap->dev) < 0)
|
||||
return -EIO;
|
||||
|
||||
adap->fe_adap[0].fe = jdvbt90502_attach(adap->dev);
|
||||
if (adap->fe_adap[0].fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties friio_properties;
|
||||
|
||||
static int friio_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
|
||||
return -ENODEV;
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = usb_set_interface(interface_to_usbdev(intf),
|
||||
alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret != 0) {
|
||||
deb_rc("failed to set alt-setting!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dvb_usb_device_init(intf, &friio_properties,
|
||||
THIS_MODULE, &d, adapter_nr);
|
||||
if (ret == 0)
|
||||
friio_streaming_ctrl(&d->adapter[0], 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct jdvbt90502_config friio_fe_config = {
|
||||
.demod_address = FRIIO_DEMOD_ADDR,
|
||||
.pll_address = FRIIO_PLL_ADDR,
|
||||
};
|
||||
|
||||
static struct i2c_algorithm gl861_i2c_algo = {
|
||||
.master_xfer = gl861_i2c_xfer,
|
||||
.functionality = gl861_i2c_func,
|
||||
};
|
||||
|
||||
static struct usb_device_id friio_table[] = {
|
||||
{ USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, friio_table);
|
||||
|
||||
|
||||
static struct dvb_usb_device_properties friio_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
/* caps:0 => no pid filter, 188B TS packet */
|
||||
/* GL861 has a HW pid filter, but no info available. */
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = 0,
|
||||
|
||||
.frontend_attach = friio_frontend_attach,
|
||||
.streaming_ctrl = friio_streaming_ctrl,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
/* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
|
||||
.count = 8,
|
||||
.endpoint = 0x01,
|
||||
.u = {
|
||||
/* GL861 has 6KB buf inside */
|
||||
.bulk = {
|
||||
.buffersize = 16384,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.i2c_algo = &gl861_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
.name = "774 Friio ISDB-T USB2.0",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &friio_table[0], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver friio_driver = {
|
||||
.name = "dvb_usb_friio",
|
||||
.probe = friio_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = friio_table,
|
||||
};
|
||||
|
||||
module_usb_driver(friio_driver);
|
||||
|
||||
MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
|
||||
MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
|
||||
MODULE_VERSION("0.2");
|
||||
MODULE_LICENSE("GPL");
|
||||
99
drivers/media/usb/dvb-usb/friio.h
Normal file
99
drivers/media/usb/dvb-usb/friio.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
|
||||
*
|
||||
* Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
|
||||
*
|
||||
* This module is based off the the gl861 and vp702x modules.
|
||||
*
|
||||
* 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_FRIIO_H_
|
||||
#define _DVB_USB_FRIIO_H_
|
||||
|
||||
/**
|
||||
* Friio Components
|
||||
* USB hub: AU4254
|
||||
* USB controller(+ TS dmx & streaming): GL861
|
||||
* Frontend: comtech JDVBT-90502
|
||||
* (tuner PLL: tua6034, I2C addr:(0xC0 >> 1))
|
||||
* (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1))
|
||||
* LED x3 (+LNB) control: PIC 16F676
|
||||
* EEPROM: 24C08
|
||||
*
|
||||
* (USB smart card reader: AU9522)
|
||||
*
|
||||
*/
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "friio"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_friio_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_friio_debug, 0x04, args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_friio_debug, 0x08, args)
|
||||
|
||||
/* Vendor requests */
|
||||
#define GL861_WRITE 0x40
|
||||
#define GL861_READ 0xc0
|
||||
|
||||
/* command bytes */
|
||||
#define GL861_REQ_I2C_WRITE 0x01
|
||||
#define GL861_REQ_I2C_READ 0x02
|
||||
/* For control msg with data argument */
|
||||
/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */
|
||||
#define GL861_REQ_I2C_DATA_CTRL_WRITE 0x03
|
||||
|
||||
#define GL861_ALTSETTING_COUNT 2
|
||||
#define FRIIO_BULK_ALTSETTING 0
|
||||
#define FRIIO_ISOC_ALTSETTING 1
|
||||
|
||||
/* LED & LNB control via PIC. */
|
||||
/* basically, it's serial control with clock and strobe. */
|
||||
/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */
|
||||
/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/
|
||||
#define FRIIO_CTL_LNB (1 << 0)
|
||||
#define FRIIO_CTL_STROBE (1 << 1)
|
||||
#define FRIIO_CTL_CLK (1 << 2)
|
||||
#define FRIIO_CTL_LED (1 << 3)
|
||||
|
||||
/* Front End related */
|
||||
|
||||
#define FRIIO_DEMOD_ADDR (0x30 >> 1)
|
||||
#define FRIIO_PLL_ADDR (0xC0 >> 1)
|
||||
|
||||
#define JDVBT90502_PLL_CLK 4000000
|
||||
#define JDVBT90502_PLL_DIVIDER 28
|
||||
|
||||
#define JDVBT90502_2ND_I2C_REG 0xFE
|
||||
|
||||
/* byte index for pll i2c command data structure*/
|
||||
/* see datasheet for tua6034 */
|
||||
#define DEMOD_REDIRECT_REG 0
|
||||
#define ADDRESS_BYTE 1
|
||||
#define DIVIDER_BYTE1 2
|
||||
#define DIVIDER_BYTE2 3
|
||||
#define CONTROL_BYTE 4
|
||||
#define BANDSWITCH_BYTE 5
|
||||
#define AGC_CTRL_BYTE 5
|
||||
#define PLL_CMD_LEN 6
|
||||
|
||||
/* bit masks for PLL STATUS response */
|
||||
#define PLL_STATUS_POR_MODE 0x80 /* 1: Power on Reset (test) Mode */
|
||||
#define PLL_STATUS_LOCKED 0x40 /* 1: locked */
|
||||
#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */
|
||||
#define PLL_STATUS_TESTMODE 0x07 /* digital output level (5 level) */
|
||||
/* 0.15Vcc step 0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */
|
||||
|
||||
|
||||
struct jdvbt90502_config {
|
||||
u8 demod_address; /* i2c addr for demodulator IC */
|
||||
u8 pll_address; /* PLL addr on the secondary i2c*/
|
||||
};
|
||||
extern struct jdvbt90502_config friio_fe_config;
|
||||
|
||||
extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d);
|
||||
#endif
|
||||
369
drivers/media/usb/dvb-usb/gp8psk-fe.c
Normal file
369
drivers/media/usb/dvb-usb/gp8psk-fe.c
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/* DVB USB compliant Linux driver for the
|
||||
* - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
|
||||
*
|
||||
* Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
|
||||
* Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
|
||||
*
|
||||
* Thanks to GENPIX for the sample code used to implement this module.
|
||||
*
|
||||
* This module is based off the vp7045 and vp702x modules
|
||||
*
|
||||
* 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 "gp8psk.h"
|
||||
|
||||
struct gp8psk_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
struct dvb_usb_device *d;
|
||||
u8 lock;
|
||||
u16 snr;
|
||||
unsigned long next_status_check;
|
||||
unsigned long status_check_interval;
|
||||
};
|
||||
|
||||
static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
u8 status;
|
||||
gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
|
||||
return status & bmDCtuned;
|
||||
}
|
||||
|
||||
static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
|
||||
}
|
||||
|
||||
static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
|
||||
{
|
||||
u8 buf[6];
|
||||
if (time_after(jiffies,st->next_status_check)) {
|
||||
gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
|
||||
gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
|
||||
st->snr = (buf[1]) << 8 | buf[0];
|
||||
st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
gp8psk_fe_update_status(st);
|
||||
|
||||
if (st->lock)
|
||||
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
else
|
||||
*status = 0;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
st->status_check_interval = 1000;
|
||||
else
|
||||
st->status_check_interval = 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
|
||||
{
|
||||
(void) fe;
|
||||
*ber = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
|
||||
{
|
||||
(void) fe;
|
||||
*unc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
gp8psk_fe_update_status(st);
|
||||
/* snr is reported in dBu*256 */
|
||||
*snr = st->snr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
gp8psk_fe_update_status(st);
|
||||
/* snr is reported in dBu*256 */
|
||||
/* snr / 38.4 ~= 100% strength */
|
||||
/* snr * 17 returns 100% strength as 65535 */
|
||||
if (st->snr > 0xf00)
|
||||
*strength = 0xffff;
|
||||
else
|
||||
*strength = (st->snr << 4) + st->snr; /* snr*17 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
tune->min_delay_ms = 800;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u8 cmd[10];
|
||||
u32 freq = c->frequency * 1000;
|
||||
int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
|
||||
|
||||
deb_fe("%s()\n", __func__);
|
||||
|
||||
cmd[4] = freq & 0xff;
|
||||
cmd[5] = (freq >> 8) & 0xff;
|
||||
cmd[6] = (freq >> 16) & 0xff;
|
||||
cmd[7] = (freq >> 24) & 0xff;
|
||||
|
||||
/* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */
|
||||
if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8)
|
||||
c->delivery_system = SYS_TURBO;
|
||||
|
||||
switch (c->delivery_system) {
|
||||
case SYS_DVBS:
|
||||
if (c->modulation != QPSK) {
|
||||
deb_fe("%s: unsupported modulation selected (%d)\n",
|
||||
__func__, c->modulation);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
c->fec_inner = FEC_AUTO;
|
||||
break;
|
||||
case SYS_DVBS2: /* kept for backwards compatibility */
|
||||
deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
|
||||
break;
|
||||
case SYS_TURBO:
|
||||
deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
|
||||
break;
|
||||
|
||||
default:
|
||||
deb_fe("%s: unsupported delivery system selected (%d)\n",
|
||||
__func__, c->delivery_system);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
cmd[0] = c->symbol_rate & 0xff;
|
||||
cmd[1] = (c->symbol_rate >> 8) & 0xff;
|
||||
cmd[2] = (c->symbol_rate >> 16) & 0xff;
|
||||
cmd[3] = (c->symbol_rate >> 24) & 0xff;
|
||||
switch (c->modulation) {
|
||||
case QPSK:
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
if (gp8psk_tuned_to_DCII(fe))
|
||||
gp8psk_bcm4500_reload(state->d);
|
||||
switch (c->fec_inner) {
|
||||
case FEC_1_2:
|
||||
cmd[9] = 0; break;
|
||||
case FEC_2_3:
|
||||
cmd[9] = 1; break;
|
||||
case FEC_3_4:
|
||||
cmd[9] = 2; break;
|
||||
case FEC_5_6:
|
||||
cmd[9] = 3; break;
|
||||
case FEC_7_8:
|
||||
cmd[9] = 4; break;
|
||||
case FEC_AUTO:
|
||||
cmd[9] = 5; break;
|
||||
default:
|
||||
cmd[9] = 5; break;
|
||||
}
|
||||
if (c->delivery_system == SYS_TURBO)
|
||||
cmd[8] = ADV_MOD_TURBO_QPSK;
|
||||
else
|
||||
cmd[8] = ADV_MOD_DVB_QPSK;
|
||||
break;
|
||||
case PSK_8: /* PSK_8 is for compatibility with DN */
|
||||
cmd[8] = ADV_MOD_TURBO_8PSK;
|
||||
switch (c->fec_inner) {
|
||||
case FEC_2_3:
|
||||
cmd[9] = 0; break;
|
||||
case FEC_3_4:
|
||||
cmd[9] = 1; break;
|
||||
case FEC_3_5:
|
||||
cmd[9] = 2; break;
|
||||
case FEC_5_6:
|
||||
cmd[9] = 3; break;
|
||||
case FEC_8_9:
|
||||
cmd[9] = 4; break;
|
||||
default:
|
||||
cmd[9] = 0; break;
|
||||
}
|
||||
break;
|
||||
case QAM_16: /* QAM_16 is for compatibility with DN */
|
||||
cmd[8] = ADV_MOD_TURBO_16QAM;
|
||||
cmd[9] = 0;
|
||||
break;
|
||||
default: /* Unknown modulation */
|
||||
deb_fe("%s: unsupported modulation selected (%d)\n",
|
||||
__func__, c->modulation);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
gp8psk_set_tuner_mode(fe, 0);
|
||||
gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
|
||||
|
||||
state->lock = 0;
|
||||
state->next_status_check = jiffies;
|
||||
state->status_check_interval = 200;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
|
||||
deb_fe("%s\n",__func__);
|
||||
|
||||
if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
|
||||
m->msg, m->msg_len)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
|
||||
fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
struct gp8psk_fe_state *st = fe->demodulator_priv;
|
||||
u8 cmd;
|
||||
|
||||
deb_fe("%s\n",__func__);
|
||||
|
||||
/* These commands are certainly wrong */
|
||||
cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
|
||||
|
||||
if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
|
||||
&cmd, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
|
||||
if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
|
||||
(tone == SEC_TONE_ON), 0, NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
|
||||
if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
|
||||
voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
|
||||
}
|
||||
|
||||
static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
|
||||
{
|
||||
struct gp8psk_fe_state* state = fe->demodulator_priv;
|
||||
u8 cmd = sw_cmd & 0x7f;
|
||||
|
||||
if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
|
||||
NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
|
||||
0, NULL, 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gp8psk_fe_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct gp8psk_fe_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops gp8psk_fe_ops;
|
||||
|
||||
struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
s->d = d;
|
||||
memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
|
||||
goto success;
|
||||
error:
|
||||
return NULL;
|
||||
success:
|
||||
return &s->fe;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops gp8psk_fe_ops = {
|
||||
.delsys = { SYS_DVBS },
|
||||
.info = {
|
||||
.name = "Genpix DVB-S",
|
||||
.frequency_min = 800000,
|
||||
.frequency_max = 2250000,
|
||||
.frequency_stepsize = 100,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.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_QAM_16 is for compatibility
|
||||
* (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
|
||||
*/
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
|
||||
},
|
||||
|
||||
.release = gp8psk_fe_release,
|
||||
|
||||
.init = NULL,
|
||||
.sleep = NULL,
|
||||
|
||||
.set_frontend = gp8psk_fe_set_frontend,
|
||||
|
||||
.get_tune_settings = gp8psk_fe_get_tune_settings,
|
||||
|
||||
.read_status = gp8psk_fe_read_status,
|
||||
.read_ber = gp8psk_fe_read_ber,
|
||||
.read_signal_strength = gp8psk_fe_read_signal_strength,
|
||||
.read_snr = gp8psk_fe_read_snr,
|
||||
.read_ucblocks = gp8psk_fe_read_unc_blocks,
|
||||
|
||||
.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
|
||||
.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
|
||||
.set_tone = gp8psk_fe_set_tone,
|
||||
.set_voltage = gp8psk_fe_set_voltage,
|
||||
.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
|
||||
.enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
|
||||
};
|
||||
328
drivers/media/usb/dvb-usb/gp8psk.c
Normal file
328
drivers/media/usb/dvb-usb/gp8psk.c
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/* DVB USB compliant Linux driver for the
|
||||
* - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
|
||||
*
|
||||
* Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
|
||||
* Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
|
||||
*
|
||||
* Thanks to GENPIX for the sample code used to implement this module.
|
||||
*
|
||||
* This module is based off the vp7045 and vp702x modules
|
||||
*
|
||||
* 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 "gp8psk.h"
|
||||
|
||||
/* debug */
|
||||
static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
|
||||
int dvb_usb_gp8psk_debug;
|
||||
module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
|
||||
{
|
||||
return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6));
|
||||
}
|
||||
|
||||
static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
|
||||
{
|
||||
return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1));
|
||||
}
|
||||
|
||||
static void gp8psk_info(struct dvb_usb_device *d)
|
||||
{
|
||||
u8 fpga_vers, fw_vers[6];
|
||||
|
||||
if (!gp8psk_get_fw_version(d, fw_vers))
|
||||
info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i",
|
||||
fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
|
||||
2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
|
||||
else
|
||||
info("failed to get FW version");
|
||||
|
||||
if (!gp8psk_get_fpga_version(d, &fpga_vers))
|
||||
info("FPGA Version = %i", fpga_vers);
|
||||
else
|
||||
info("failed to get FPGA version");
|
||||
}
|
||||
|
||||
int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret = 0,try = 0;
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
while (ret >= 0 && ret != blen && try < 3) {
|
||||
ret = usb_control_msg(d->udev,
|
||||
usb_rcvctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value,index,b,blen,
|
||||
2000);
|
||||
deb_info("reading number %d (ret: %d)\n",try,ret);
|
||||
try++;
|
||||
}
|
||||
|
||||
if (ret < 0 || ret != blen) {
|
||||
warn("usb in %d operation failed.", req);
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
if (usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value,index,b,blen,
|
||||
2000) != blen) {
|
||||
warn("usb out operation failed.");
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret;
|
||||
const struct firmware *fw = NULL;
|
||||
const u8 *ptr;
|
||||
u8 *buf;
|
||||
if ((ret = request_firmware(&fw, bcm4500_firmware,
|
||||
&d->udev->dev)) != 0) {
|
||||
err("did not find the bcm4500 firmware file. (%s) "
|
||||
"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
|
||||
bcm4500_firmware,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
|
||||
goto out_rel_fw;
|
||||
|
||||
info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
|
||||
|
||||
ptr = fw->data;
|
||||
buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_rel_fw;
|
||||
}
|
||||
|
||||
while (ptr[0] != 0xff) {
|
||||
u16 buflen = ptr[0] + 4;
|
||||
if (ptr + buflen >= fw->data + fw->size) {
|
||||
err("failed to load bcm4500 firmware.");
|
||||
goto out_free;
|
||||
}
|
||||
memcpy(buf, ptr, buflen);
|
||||
if (dvb_usb_generic_write(d, buf, buflen)) {
|
||||
err("failed to load bcm4500 firmware.");
|
||||
goto out_free;
|
||||
}
|
||||
ptr += buflen;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out_free:
|
||||
kfree(buf);
|
||||
out_rel_fw:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 status, buf;
|
||||
int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
|
||||
|
||||
if (onoff) {
|
||||
gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
|
||||
if (! (status & bm8pskStarted)) { /* started */
|
||||
if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
|
||||
gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
gp8psk_info(d);
|
||||
}
|
||||
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
|
||||
if(gp8psk_load_bcm4500fw(d))
|
||||
return -EINVAL;
|
||||
|
||||
if (! (status & bmIntersilOn)) /* LNB Power */
|
||||
if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
|
||||
&buf, 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* Set DVB mode to 1 */
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
|
||||
return -EINVAL;
|
||||
/* Abort possible TS (if previous tune crashed) */
|
||||
if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
/* Turn off LNB power */
|
||||
if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
/* Turn off 8psk power */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
|
||||
gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
|
||||
{
|
||||
u8 buf;
|
||||
int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
|
||||
/* Turn off 8psk power */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
/* Turn On 8psk power */
|
||||
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
|
||||
return -EINVAL;
|
||||
/* load BCM4500 firmware */
|
||||
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
|
||||
if (gp8psk_load_bcm4500fw(d))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
|
||||
}
|
||||
|
||||
static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties gp8psk_properties;
|
||||
|
||||
static int gp8psk_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
ret = dvb_usb_device_init(intf, &gp8psk_properties,
|
||||
THIS_MODULE, NULL, adapter_nr);
|
||||
if (ret == 0) {
|
||||
info("found Genpix USB device pID = %x (hex)",
|
||||
le16_to_cpu(udev->descriptor.idProduct));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id gp8psk_usb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
|
||||
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
|
||||
/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties gp8psk_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-gp8psk-01.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.streaming_ctrl = gp8psk_streaming_ctrl,
|
||||
.frontend_attach = gp8psk_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.power_ctrl = gp8psk_power_ctrl,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 4,
|
||||
.devices = {
|
||||
{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
|
||||
.cold_ids = { &gp8psk_usb_table[0], NULL },
|
||||
.warm_ids = { &gp8psk_usb_table[1], NULL },
|
||||
},
|
||||
{ .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &gp8psk_usb_table[2], NULL },
|
||||
},
|
||||
{ .name = "Genpix SkyWalker-1 DVB-S receiver",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &gp8psk_usb_table[3], NULL },
|
||||
},
|
||||
{ .name = "Genpix SkyWalker-2 DVB-S receiver",
|
||||
.cold_ids = { NULL },
|
||||
.warm_ids = { &gp8psk_usb_table[4], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver gp8psk_usb_driver = {
|
||||
.name = "dvb_usb_gp8psk",
|
||||
.probe = gp8psk_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = gp8psk_usb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(gp8psk_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
|
||||
MODULE_DESCRIPTION("Driver for Genpix DVB-S");
|
||||
MODULE_VERSION("1.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
100
drivers/media/usb/dvb-usb/gp8psk.h
Normal file
100
drivers/media/usb/dvb-usb/gp8psk.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* DVB USB compliant Linux driver for the
|
||||
* - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
|
||||
*
|
||||
* Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
|
||||
* Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
|
||||
*
|
||||
* Thanks to GENPIX for the sample code used to implement this module.
|
||||
*
|
||||
* This module is based off the vp7045 and vp702x modules
|
||||
*
|
||||
* 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_GP8PSK_H_
|
||||
#define _DVB_USB_GP8PSK_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "gp8psk"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_gp8psk_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
|
||||
|
||||
/* Twinhan Vendor requests */
|
||||
#define TH_COMMAND_IN 0xC0
|
||||
#define TH_COMMAND_OUT 0xC1
|
||||
|
||||
/* gp8psk commands */
|
||||
|
||||
#define GET_8PSK_CONFIG 0x80 /* in */
|
||||
#define SET_8PSK_CONFIG 0x81
|
||||
#define I2C_WRITE 0x83
|
||||
#define I2C_READ 0x84
|
||||
#define ARM_TRANSFER 0x85
|
||||
#define TUNE_8PSK 0x86
|
||||
#define GET_SIGNAL_STRENGTH 0x87 /* in */
|
||||
#define LOAD_BCM4500 0x88
|
||||
#define BOOT_8PSK 0x89 /* in */
|
||||
#define START_INTERSIL 0x8A /* in */
|
||||
#define SET_LNB_VOLTAGE 0x8B
|
||||
#define SET_22KHZ_TONE 0x8C
|
||||
#define SEND_DISEQC_COMMAND 0x8D
|
||||
#define SET_DVB_MODE 0x8E
|
||||
#define SET_DN_SWITCH 0x8F
|
||||
#define GET_SIGNAL_LOCK 0x90 /* in */
|
||||
#define GET_FW_VERS 0x92
|
||||
#define GET_SERIAL_NUMBER 0x93 /* in */
|
||||
#define USE_EXTRA_VOLT 0x94
|
||||
#define GET_FPGA_VERS 0x95
|
||||
#define CW3K_INIT 0x9d
|
||||
|
||||
/* PSK_configuration bits */
|
||||
#define bm8pskStarted 0x01
|
||||
#define bm8pskFW_Loaded 0x02
|
||||
#define bmIntersilOn 0x04
|
||||
#define bmDVBmode 0x08
|
||||
#define bm22kHz 0x10
|
||||
#define bmSEL18V 0x20
|
||||
#define bmDCtuned 0x40
|
||||
#define bmArmed 0x80
|
||||
|
||||
/* Satellite modulation modes */
|
||||
#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
|
||||
#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */
|
||||
#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */
|
||||
#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */
|
||||
|
||||
#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */
|
||||
#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */
|
||||
#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */
|
||||
#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
|
||||
#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */
|
||||
#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */
|
||||
|
||||
#define GET_USB_SPEED 0x07
|
||||
|
||||
#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
|
||||
|
||||
/* firmware revision id's */
|
||||
#define GP8PSK_FW_REV1 0x020604
|
||||
#define GP8PSK_FW_REV2 0x020704
|
||||
#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
|
||||
|
||||
extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
|
||||
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
|
||||
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen);
|
||||
extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
|
||||
|
||||
#endif
|
||||
1276
drivers/media/usb/dvb-usb/m920x.c
Normal file
1276
drivers/media/usb/dvb-usb/m920x.c
Normal file
File diff suppressed because it is too large
Load diff
77
drivers/media/usb/dvb-usb/m920x.h
Normal file
77
drivers/media/usb/dvb-usb/m920x.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef _DVB_USB_M920X_H_
|
||||
#define _DVB_USB_M920X_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "m920x"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb(args...) dprintk(dvb_usb_m920x_debug,0x01,args)
|
||||
|
||||
#define M9206_CORE 0x22
|
||||
#define M9206_RC_STATE 0xff51
|
||||
#define M9206_RC_KEY 0xff52
|
||||
#define M9206_RC_INIT1 0xff54
|
||||
#define M9206_RC_INIT2 0xff55
|
||||
#define M9206_FW_GO 0xff69
|
||||
|
||||
#define M9206_I2C 0x23
|
||||
#define M9206_FILTER 0x25
|
||||
#define M9206_FW 0x30
|
||||
|
||||
#define M9206_MAX_FILTERS 8
|
||||
#define M9206_MAX_ADAPTERS 4
|
||||
|
||||
/*
|
||||
sequences found in logs:
|
||||
[index value]
|
||||
0x80 write addr
|
||||
(0x00 out byte)*
|
||||
0x40 out byte
|
||||
|
||||
0x80 write addr
|
||||
(0x00 out byte)*
|
||||
0x80 read addr
|
||||
(0x21 in byte)*
|
||||
0x60 in byte
|
||||
|
||||
this sequence works:
|
||||
0x80 read addr
|
||||
(0x21 in byte)*
|
||||
0x60 in byte
|
||||
|
||||
Guess at API of the I2C function:
|
||||
I2C operation is done one byte at a time with USB control messages. The
|
||||
index the messages is sent to is made up of a set of flags that control
|
||||
the I2C bus state:
|
||||
0x80: Send START condition. After a START condition, one would normally
|
||||
always send the 7-bit slave I2C address as the 7 MSB, followed by
|
||||
the read/write bit as the LSB.
|
||||
0x40: Send STOP condition. This should be set on the last byte of an
|
||||
I2C transaction.
|
||||
0x20: Read a byte from the slave. As opposed to writing a byte to the
|
||||
slave. The slave will normally not produce any data unless you
|
||||
set the R/W bit to 1 when sending the slave's address after the
|
||||
START condition.
|
||||
0x01: Respond with ACK, as opposed to a NACK. For a multi-byte read,
|
||||
the master should send an ACK, that is pull SDA low during the 9th
|
||||
clock cycle, after every byte but the last. This flags only makes
|
||||
sense when bit 0x20 is set, indicating a read.
|
||||
|
||||
What any other bits might mean, or how to get the slave's ACK/NACK
|
||||
response to a write, is unknown.
|
||||
*/
|
||||
|
||||
struct m920x_state {
|
||||
u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
|
||||
int filtering_enabled[M9206_MAX_ADAPTERS];
|
||||
int rep_count;
|
||||
};
|
||||
|
||||
/* Initialisation data for the m920x
|
||||
*/
|
||||
|
||||
struct m920x_inits {
|
||||
u16 address;
|
||||
u8 data;
|
||||
};
|
||||
|
||||
#endif
|
||||
233
drivers/media/usb/dvb-usb/nova-t-usb2.c
Normal file
233
drivers/media/usb/dvb-usb/nova-t-usb2.c
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/* 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);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define deb_rc(args...) dprintk(debug,0x01,args)
|
||||
#define deb_ee(args...) dprintk(debug,0x02,args)
|
||||
|
||||
/* Hauppauge NOVA-T USB2 keys */
|
||||
static struct rc_map_table rc_map_haupp_table[] = {
|
||||
{ 0x1e00, KEY_0 },
|
||||
{ 0x1e01, KEY_1 },
|
||||
{ 0x1e02, KEY_2 },
|
||||
{ 0x1e03, KEY_3 },
|
||||
{ 0x1e04, KEY_4 },
|
||||
{ 0x1e05, KEY_5 },
|
||||
{ 0x1e06, KEY_6 },
|
||||
{ 0x1e07, KEY_7 },
|
||||
{ 0x1e08, KEY_8 },
|
||||
{ 0x1e09, KEY_9 },
|
||||
{ 0x1e0a, KEY_KPASTERISK },
|
||||
{ 0x1e0b, KEY_RED },
|
||||
{ 0x1e0c, KEY_RADIO },
|
||||
{ 0x1e0d, KEY_MENU },
|
||||
{ 0x1e0e, KEY_GRAVE }, /* # */
|
||||
{ 0x1e0f, KEY_MUTE },
|
||||
{ 0x1e10, KEY_VOLUMEUP },
|
||||
{ 0x1e11, KEY_VOLUMEDOWN },
|
||||
{ 0x1e12, KEY_CHANNEL },
|
||||
{ 0x1e14, KEY_UP },
|
||||
{ 0x1e15, KEY_DOWN },
|
||||
{ 0x1e16, KEY_LEFT },
|
||||
{ 0x1e17, KEY_RIGHT },
|
||||
{ 0x1e18, KEY_VIDEO },
|
||||
{ 0x1e19, KEY_AUDIO },
|
||||
{ 0x1e1a, KEY_IMAGES },
|
||||
{ 0x1e1b, KEY_EPG },
|
||||
{ 0x1e1c, KEY_TV },
|
||||
{ 0x1e1e, KEY_NEXT },
|
||||
{ 0x1e1f, KEY_BACK },
|
||||
{ 0x1e20, KEY_CHANNELUP },
|
||||
{ 0x1e21, KEY_CHANNELDOWN },
|
||||
{ 0x1e24, KEY_LAST }, /* Skip backwards */
|
||||
{ 0x1e25, KEY_OK },
|
||||
{ 0x1e29, KEY_BLUE},
|
||||
{ 0x1e2e, KEY_GREEN },
|
||||
{ 0x1e30, KEY_PAUSE },
|
||||
{ 0x1e32, KEY_REWIND },
|
||||
{ 0x1e34, KEY_FASTFORWARD },
|
||||
{ 0x1e35, KEY_PLAY },
|
||||
{ 0x1e36, KEY_STOP },
|
||||
{ 0x1e37, KEY_RECORD },
|
||||
{ 0x1e38, KEY_YELLOW },
|
||||
{ 0x1e3b, KEY_GOTO },
|
||||
{ 0x1e3d, 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_device_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(rc_map_haupp_table); i++) {
|
||||
if (rc5_data(&rc_map_haupp_table[i]) == data &&
|
||||
rc5_custom(&rc_map_haupp_table[i]) == custom) {
|
||||
|
||||
deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]),
|
||||
rc5_custom(&rc_map_haupp_table[i]));
|
||||
|
||||
*event = rc_map_haupp_table[i].keycode;
|
||||
*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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_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, NULL, adapter_nr);
|
||||
}
|
||||
|
||||
/* 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_device_properties nova_t_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-nova-t-usb2-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.pid_filter = dibusb_pid_filter,
|
||||
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
|
||||
.frontend_attach = dibusb_dib3000mc_frontend_attach,
|
||||
.tuner_attach = dibusb_dib3000mc_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.size_of_priv = sizeof(struct dibusb_device_state),
|
||||
|
||||
.power_ctrl = dibusb2_0_power_ctrl,
|
||||
.read_mac_address = nova_t_read_mac_address,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 100,
|
||||
.rc_map_table = rc_map_haupp_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_haupp_table),
|
||||
.rc_query = nova_t_rc_query,
|
||||
},
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Hauppauge WinTV-NOVA-T usb2",
|
||||
{ &nova_t_table[0], NULL },
|
||||
{ &nova_t_table[1], NULL },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver nova_t_driver = {
|
||||
.name = "dvb_usb_nova_t_usb2",
|
||||
.probe = nova_t_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = nova_t_table,
|
||||
};
|
||||
|
||||
module_usb_driver(nova_t_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
583
drivers/media/usb/dvb-usb/opera1.c
Normal file
583
drivers/media/usb/dvb-usb/opera1.c
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
|
||||
*
|
||||
* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
|
||||
* Copyright (C) 2006 Marco Gittler (g.marco@freenet.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
|
||||
*/
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "opera"
|
||||
|
||||
#include "dvb-usb.h"
|
||||
#include "stv0299.h"
|
||||
|
||||
#define OPERA_READ_MSG 0
|
||||
#define OPERA_WRITE_MSG 1
|
||||
#define OPERA_I2C_TUNER 0xd1
|
||||
|
||||
#define READ_FX2_REG_REQ 0xba
|
||||
#define READ_MAC_ADDR 0x08
|
||||
#define OPERA_WRITE_FX2 0xbb
|
||||
#define OPERA_TUNER_REQ 0xb1
|
||||
#define REG_1F_SYMBOLRATE_BYTE0 0x1f
|
||||
#define REG_20_SYMBOLRATE_BYTE1 0x20
|
||||
#define REG_21_SYMBOLRATE_BYTE2 0x21
|
||||
|
||||
#define ADDR_B600_VOLTAGE_13V (0x02)
|
||||
#define ADDR_B601_VOLTAGE_18V (0x03)
|
||||
#define ADDR_B1A6_STREAM_CTRL (0x04)
|
||||
#define ADDR_B880_READ_REMOTE (0x05)
|
||||
|
||||
struct opera1_state {
|
||||
u32 last_key_pressed;
|
||||
};
|
||||
struct rc_map_opera_table {
|
||||
u32 keycode;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
static int dvb_usb_opera1_debug;
|
||||
module_param_named(debug, dvb_usb_opera1_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);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
|
||||
static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
|
||||
u8 * data, u16 len, int flags)
|
||||
{
|
||||
int ret;
|
||||
u8 tmp;
|
||||
u8 *buf;
|
||||
unsigned int pipe = (flags == OPERA_READ_MSG) ?
|
||||
usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
|
||||
u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
|
||||
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags == OPERA_WRITE_MSG)
|
||||
memcpy(buf, data, len);
|
||||
ret = usb_control_msg(dev, pipe, request,
|
||||
request_type | USB_TYPE_VENDOR, value, 0x0,
|
||||
buf, len, 2000);
|
||||
|
||||
if (request == OPERA_TUNER_REQ) {
|
||||
tmp = buf[0];
|
||||
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
|
||||
0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
buf[0] = tmp;
|
||||
}
|
||||
if (flags == OPERA_READ_MSG)
|
||||
memcpy(data, buf, len);
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
|
||||
static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
|
||||
u8 * buf, u16 len)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 request;
|
||||
u16 value;
|
||||
|
||||
if (!dev) {
|
||||
info("no usb_device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
switch (addr>>1){
|
||||
case ADDR_B600_VOLTAGE_13V:
|
||||
request=0xb6;
|
||||
value=0x00;
|
||||
break;
|
||||
case ADDR_B601_VOLTAGE_18V:
|
||||
request=0xb6;
|
||||
value=0x01;
|
||||
break;
|
||||
case ADDR_B1A6_STREAM_CTRL:
|
||||
request=0xb1;
|
||||
value=0xa6;
|
||||
break;
|
||||
case ADDR_B880_READ_REMOTE:
|
||||
request=0xb8;
|
||||
value=0x80;
|
||||
break;
|
||||
default:
|
||||
request=0xb1;
|
||||
value=addr;
|
||||
}
|
||||
ret = opera1_xilinx_rw(dev->udev, request,
|
||||
value, buf, len,
|
||||
addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
|
||||
|
||||
mutex_unlock(&dev->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i = 0, tmp = 0;
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((tmp = opera1_usb_i2c_msgxfer(d,
|
||||
(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
|
||||
msg[i].buf,
|
||||
msg[i].len
|
||||
)) != msg[i].len) {
|
||||
break;
|
||||
}
|
||||
if (dvb_usb_opera1_debug & 0x10)
|
||||
info("sending i2c message %d %d", tmp, msg[i].len);
|
||||
}
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 opera1_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm opera1_i2c_algo = {
|
||||
.master_xfer = opera1_i2c_xfer,
|
||||
.functionality = opera1_i2c_func,
|
||||
};
|
||||
|
||||
static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
static u8 command_13v[1]={0x00};
|
||||
static u8 command_18v[1]={0x01};
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
|
||||
};
|
||||
struct dvb_usb_adapter *udev_adap =
|
||||
(struct dvb_usb_adapter *)(fe->dvb->priv);
|
||||
if (voltage == SEC_VOLTAGE_18) {
|
||||
msg[0].addr = ADDR_B601_VOLTAGE_18V;
|
||||
msg[0].buf = command_18v;
|
||||
}
|
||||
i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
|
||||
u32 ratio)
|
||||
{
|
||||
stv0299_writereg(fe, 0x13, 0x98);
|
||||
stv0299_writereg(fe, 0x14, 0x95);
|
||||
stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
|
||||
stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
|
||||
stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
|
||||
return 0;
|
||||
|
||||
}
|
||||
static u8 opera1_inittab[] = {
|
||||
0x00, 0xa1,
|
||||
0x01, 0x15,
|
||||
0x02, 0x30,
|
||||
0x03, 0x00,
|
||||
0x04, 0x7d,
|
||||
0x05, 0x05,
|
||||
0x06, 0x02,
|
||||
0x07, 0x00,
|
||||
0x0b, 0x00,
|
||||
0x0c, 0x01,
|
||||
0x0d, 0x81,
|
||||
0x0e, 0x44,
|
||||
0x0f, 0x19,
|
||||
0x10, 0x3f,
|
||||
0x11, 0x84,
|
||||
0x12, 0xda,
|
||||
0x13, 0x98,
|
||||
0x14, 0x95,
|
||||
0x15, 0xc9,
|
||||
0x16, 0xeb,
|
||||
0x17, 0x00,
|
||||
0x18, 0x19,
|
||||
0x19, 0x8b,
|
||||
0x1a, 0x00,
|
||||
0x1b, 0x82,
|
||||
0x1c, 0x7f,
|
||||
0x1d, 0x00,
|
||||
0x1e, 0x00,
|
||||
REG_1F_SYMBOLRATE_BYTE0, 0x06,
|
||||
REG_20_SYMBOLRATE_BYTE1, 0x50,
|
||||
REG_21_SYMBOLRATE_BYTE2, 0x10,
|
||||
0x22, 0x00,
|
||||
0x23, 0x00,
|
||||
0x24, 0x37,
|
||||
0x25, 0xbc,
|
||||
0x26, 0x00,
|
||||
0x27, 0x00,
|
||||
0x28, 0x00,
|
||||
0x29, 0x1e,
|
||||
0x2a, 0x14,
|
||||
0x2b, 0x1f,
|
||||
0x2c, 0x09,
|
||||
0x2d, 0x0a,
|
||||
0x2e, 0x00,
|
||||
0x2f, 0x00,
|
||||
0x30, 0x00,
|
||||
0x31, 0x1f,
|
||||
0x32, 0x19,
|
||||
0x33, 0xfc,
|
||||
0x34, 0x13,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
static struct stv0299_config opera1_stv0299_config = {
|
||||
.demod_address = 0xd0>>1,
|
||||
.min_delay_ms = 100,
|
||||
.mclk = 88000000UL,
|
||||
.invert = 1,
|
||||
.skip_reinit = 0,
|
||||
.lock_output = STV0299_LOCKOUTPUT_0,
|
||||
.volt13_op0_op1 = STV0299_VOLT13_OP0,
|
||||
.inittab = opera1_inittab,
|
||||
.set_symbol_rate = opera1_stv0299_set_symbol_rate,
|
||||
};
|
||||
|
||||
static int opera1_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
|
||||
&d->dev->i2c_adap);
|
||||
if ((d->fe_adap[0].fe) != NULL) {
|
||||
d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
|
||||
return 0;
|
||||
}
|
||||
info("not attached stv0299");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(
|
||||
dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
|
||||
&adap->dev->i2c_adap, DVB_PLL_OPERA1
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 val = onoff ? 0x01 : 0x00;
|
||||
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("power %s", onoff ? "on" : "off");
|
||||
return opera1_xilinx_rw(d->udev, 0xb7, val,
|
||||
&val, 1, OPERA_WRITE_MSG);
|
||||
}
|
||||
|
||||
static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
static u8 buf_start[2] = { 0xff, 0x03 };
|
||||
static u8 buf_stop[2] = { 0xff, 0x00 };
|
||||
struct i2c_msg start_tuner[] = {
|
||||
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
|
||||
};
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("streaming %s", onoff ? "on" : "off");
|
||||
i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
||||
int onoff)
|
||||
{
|
||||
u8 b_pid[3];
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
|
||||
};
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("pidfilter index: %d pid: %d %s", index, pid,
|
||||
onoff ? "on" : "off");
|
||||
b_pid[0] = (2 * index) + 4;
|
||||
b_pid[1] = onoff ? (pid & 0xff) : (0x00);
|
||||
b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
|
||||
i2c_transfer(&adap->dev->i2c_adap, msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
int u = 0x04;
|
||||
u8 b_pid[3];
|
||||
struct i2c_msg msg[] = {
|
||||
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
|
||||
};
|
||||
if (dvb_usb_opera1_debug)
|
||||
info("%s hw-pidfilter", onoff ? "enable" : "disable");
|
||||
for (; u < 0x7e; u += 2) {
|
||||
b_pid[0] = u;
|
||||
b_pid[1] = 0;
|
||||
b_pid[2] = 0x80;
|
||||
i2c_transfer(&adap->dev->i2c_adap, msg, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rc_map_table rc_map_opera1_table[] = {
|
||||
{0x5fa0, KEY_1},
|
||||
{0x51af, KEY_2},
|
||||
{0x5da2, KEY_3},
|
||||
{0x41be, KEY_4},
|
||||
{0x0bf5, KEY_5},
|
||||
{0x43bd, KEY_6},
|
||||
{0x47b8, KEY_7},
|
||||
{0x49b6, KEY_8},
|
||||
{0x05fa, KEY_9},
|
||||
{0x45ba, KEY_0},
|
||||
{0x09f6, KEY_CHANNELUP}, /*chanup */
|
||||
{0x1be5, KEY_CHANNELDOWN}, /*chandown */
|
||||
{0x5da3, KEY_VOLUMEDOWN}, /*voldown */
|
||||
{0x5fa1, KEY_VOLUMEUP}, /*volup */
|
||||
{0x07f8, KEY_SPACE}, /*tab */
|
||||
{0x1fe1, KEY_OK}, /*play ok */
|
||||
{0x1be4, KEY_ZOOM}, /*zoom */
|
||||
{0x59a6, KEY_MUTE}, /*mute */
|
||||
{0x5ba5, KEY_RADIO}, /*tv/f */
|
||||
{0x19e7, KEY_RECORD}, /*rec */
|
||||
{0x01fe, KEY_STOP}, /*Stop */
|
||||
{0x03fd, KEY_PAUSE}, /*pause */
|
||||
{0x03fc, KEY_SCREEN}, /*<- -> */
|
||||
{0x07f9, KEY_CAMERA}, /*capture */
|
||||
{0x47b9, KEY_ESC}, /*exit */
|
||||
{0x43bc, KEY_POWER2}, /*power */
|
||||
};
|
||||
|
||||
static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
|
||||
{
|
||||
struct opera1_state *opst = dev->priv;
|
||||
u8 rcbuffer[32];
|
||||
const u16 startmarker1 = 0x10ed;
|
||||
const u16 startmarker2 = 0x11ec;
|
||||
struct i2c_msg read_remote[] = {
|
||||
{.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
|
||||
};
|
||||
int i = 0;
|
||||
u32 send_key = 0;
|
||||
|
||||
if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (rcbuffer[i])
|
||||
send_key |= 1;
|
||||
if (i < 31)
|
||||
send_key = send_key << 1;
|
||||
}
|
||||
if (send_key & 0x8000)
|
||||
send_key = (send_key << 1) | (send_key >> 15 & 0x01);
|
||||
|
||||
if (send_key == 0xffff && opst->last_key_pressed != 0) {
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
*event = opst->last_key_pressed;
|
||||
return 0;
|
||||
}
|
||||
for (; send_key != 0;) {
|
||||
if (send_key >> 16 == startmarker2) {
|
||||
break;
|
||||
} else if (send_key >> 16 == startmarker1) {
|
||||
send_key =
|
||||
(send_key & 0xfffeffff) | (startmarker1 << 16);
|
||||
break;
|
||||
} else
|
||||
send_key >>= 1;
|
||||
}
|
||||
|
||||
if (send_key == 0)
|
||||
return 0;
|
||||
|
||||
send_key = (send_key & 0xffff) | 0x0100;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
|
||||
if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = rc_map_opera1_table[i].keycode;
|
||||
opst->last_key_pressed =
|
||||
rc_map_opera1_table[i].keycode;
|
||||
break;
|
||||
}
|
||||
opst->last_key_pressed = 0;
|
||||
}
|
||||
} else
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_device_id opera1_table[] = {
|
||||
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)},
|
||||
{USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, opera1_table);
|
||||
|
||||
static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
u8 command[] = { READ_MAC_ADDR };
|
||||
opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
|
||||
opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
|
||||
return 0;
|
||||
}
|
||||
static int opera1_xilinx_load_firmware(struct usb_device *dev,
|
||||
const char *filename)
|
||||
{
|
||||
const struct firmware *fw = NULL;
|
||||
u8 *b, *p;
|
||||
int ret = 0, i,fpgasize=40;
|
||||
u8 testval;
|
||||
info("start downloading fpga firmware %s",filename);
|
||||
|
||||
if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
|
||||
err("did not find the firmware file. (%s) "
|
||||
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
|
||||
filename);
|
||||
return ret;
|
||||
} else {
|
||||
p = kmalloc(fw->size, GFP_KERNEL);
|
||||
opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
|
||||
if (p != NULL && testval != 0x67) {
|
||||
|
||||
u8 reset = 0, fpga_command = 0;
|
||||
memcpy(p, fw->data, fw->size);
|
||||
/* clear fpga ? */
|
||||
opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
|
||||
OPERA_WRITE_MSG);
|
||||
for (i = 0; i < fw->size;) {
|
||||
if ( (fw->size - i) <fpgasize){
|
||||
fpgasize=fw->size-i;
|
||||
}
|
||||
b = (u8 *) p + i;
|
||||
if (opera1_xilinx_rw
|
||||
(dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
|
||||
OPERA_WRITE_MSG) != fpgasize
|
||||
) {
|
||||
err("error while transferring firmware");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
i = i + fpgasize;
|
||||
}
|
||||
/* restart the CPU */
|
||||
if (ret || opera1_xilinx_rw
|
||||
(dev, 0xa0, 0xe600, &reset, 1,
|
||||
OPERA_WRITE_MSG) != 1) {
|
||||
err("could not restart the USB controller CPU.");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
kfree(p);
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties opera1_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-opera-01.fw",
|
||||
.size_of_priv = sizeof(struct opera1_state),
|
||||
|
||||
.power_ctrl = opera1_power_ctrl,
|
||||
.i2c_algo = &opera1_i2c_algo,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_map_table = rc_map_opera1_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
|
||||
.rc_interval = 200,
|
||||
.rc_query = opera1_rc_query,
|
||||
},
|
||||
.read_mac_address = opera1_read_mac_address,
|
||||
.generic_bulk_ctrl_endpoint = 0x00,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.frontend_attach = opera1_frontend_attach,
|
||||
.streaming_ctrl = opera1_streaming_ctrl,
|
||||
.tuner_attach = opera1_tuner_attach,
|
||||
.caps =
|
||||
DVB_USB_ADAP_HAS_PID_FILTER |
|
||||
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter = opera1_pid_filter,
|
||||
.pid_filter_ctrl = opera1_pid_filter_control,
|
||||
.pid_filter_count = 252,
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 10,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{"Opera1 DVB-S USB2.0",
|
||||
{&opera1_table[0], NULL},
|
||||
{&opera1_table[1], NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static int opera1_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM &&
|
||||
le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 &&
|
||||
opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (0 != dvb_usb_device_init(intf, &opera1_properties,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_driver opera1_driver = {
|
||||
.name = "opera1",
|
||||
.probe = opera1_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = opera1_table,
|
||||
};
|
||||
|
||||
module_usb_driver(opera1_driver);
|
||||
|
||||
MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
|
||||
MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
|
||||
MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
1063
drivers/media/usb/dvb-usb/pctv452e.c
Normal file
1063
drivers/media/usb/dvb-usb/pctv452e.c
Normal file
File diff suppressed because it is too large
Load diff
790
drivers/media/usb/dvb-usb/technisat-usb2.c
Normal file
790
drivers/media/usb/dvb-usb/technisat-usb2.c
Normal file
|
|
@ -0,0 +1,790 @@
|
|||
/*
|
||||
* Linux driver for Technisat DVB-S/S2 USB 2.0 device
|
||||
*
|
||||
* Copyright (C) 2010 Patrick Boettcher,
|
||||
* Kernel Labs Inc. PO Box 745, St James, NY 11780
|
||||
*
|
||||
* Development was sponsored by Technisat Digital UK Limited, whose
|
||||
* registered office is Witan Gate House 500 - 600 Witan Gate West,
|
||||
* Milton Keynes, MK9 1SH
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
|
||||
* TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
|
||||
* THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER
|
||||
* NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "technisat-usb2"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "stv6110x.h"
|
||||
#include "stv090x.h"
|
||||
|
||||
/* module parameters */
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,
|
||||
"set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
|
||||
DVB_USB_DEBUG_STATUS);
|
||||
|
||||
/* disables all LED control command and
|
||||
* also does not start the signal polling thread */
|
||||
static int disable_led_control;
|
||||
module_param(disable_led_control, int, 0444);
|
||||
MODULE_PARM_DESC(disable_led_control,
|
||||
"disable LED control of the device "
|
||||
"(default: 0 - LED control is active).");
|
||||
|
||||
/* device private data */
|
||||
struct technisat_usb2_state {
|
||||
struct dvb_usb_device *dev;
|
||||
struct delayed_work green_led_work;
|
||||
u8 power_state;
|
||||
|
||||
u16 last_scan_code;
|
||||
};
|
||||
|
||||
/* debug print helpers */
|
||||
#define deb_info(args...) dprintk(debug, 0x01, args)
|
||||
#define deb_eeprom(args...) dprintk(debug, 0x02, args)
|
||||
#define deb_i2c(args...) dprintk(debug, 0x04, args)
|
||||
#define deb_rc(args...) dprintk(debug, 0x08, args)
|
||||
|
||||
/* vendor requests */
|
||||
#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
|
||||
#define SET_FRONT_END_RESET_VENDOR_REQUEST 0xB4
|
||||
#define GET_VERSION_INFO_VENDOR_REQUEST 0xB5
|
||||
#define SET_GREEN_LED_VENDOR_REQUEST 0xB6
|
||||
#define SET_RED_LED_VENDOR_REQUEST 0xB7
|
||||
#define GET_IR_DATA_VENDOR_REQUEST 0xB8
|
||||
#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST 0xB9
|
||||
#define SET_USB_REENUMERATION 0xBA
|
||||
|
||||
/* i2c-access methods */
|
||||
#define I2C_SPEED_100KHZ_BIT 0x40
|
||||
|
||||
#define I2C_STATUS_NAK 7
|
||||
#define I2C_STATUS_OK 8
|
||||
|
||||
static int technisat_usb2_i2c_access(struct usb_device *udev,
|
||||
u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
|
||||
{
|
||||
u8 b[64];
|
||||
int ret, actual_length;
|
||||
|
||||
deb_i2c("i2c-access: %02x, tx: ", device_addr);
|
||||
debug_dump(tx, txlen, deb_i2c);
|
||||
deb_i2c(" ");
|
||||
|
||||
if (txlen > 62) {
|
||||
err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
|
||||
device_addr);
|
||||
txlen = 62;
|
||||
}
|
||||
if (rxlen > 62) {
|
||||
err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
|
||||
device_addr);
|
||||
rxlen = 62;
|
||||
}
|
||||
|
||||
b[0] = I2C_SPEED_100KHZ_BIT;
|
||||
b[1] = device_addr << 1;
|
||||
|
||||
if (rx != NULL) {
|
||||
b[0] |= rxlen;
|
||||
b[1] |= 1;
|
||||
}
|
||||
|
||||
memcpy(&b[2], tx, txlen);
|
||||
ret = usb_bulk_msg(udev,
|
||||
usb_sndbulkpipe(udev, 0x01),
|
||||
b, 2 + txlen,
|
||||
NULL, 1000);
|
||||
|
||||
if (ret < 0) {
|
||||
err("i2c-error: out failed %02x = %d", device_addr, ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_bulk_msg(udev,
|
||||
usb_rcvbulkpipe(udev, 0x01),
|
||||
b, 64, &actual_length, 1000);
|
||||
if (ret < 0) {
|
||||
err("i2c-error: in failed %02x = %d", device_addr, ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (b[0] != I2C_STATUS_OK) {
|
||||
err("i2c-error: %02x = %d", device_addr, b[0]);
|
||||
/* handle tuner-i2c-nak */
|
||||
if (!(b[0] == I2C_STATUS_NAK &&
|
||||
device_addr == 0x60
|
||||
/* && device_is_technisat_usb2 */))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
deb_i2c("status: %d, ", b[0]);
|
||||
|
||||
if (rx != NULL) {
|
||||
memcpy(rx, &b[2], rxlen);
|
||||
|
||||
deb_i2c("rx (%d): ", rxlen);
|
||||
debug_dump(rx, rxlen, deb_i2c);
|
||||
}
|
||||
|
||||
deb_i2c("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int num)
|
||||
{
|
||||
int ret = 0, i;
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
|
||||
/* Ensure nobody else hits the i2c bus while we're sending our
|
||||
sequence of messages, (such as the remote control thread) */
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
|
||||
ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
|
||||
msg[i].buf, msg[i].len,
|
||||
msg[i+1].buf, msg[i+1].len);
|
||||
if (ret != 0)
|
||||
break;
|
||||
i++;
|
||||
} else {
|
||||
ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
|
||||
msg[i].buf, msg[i].len,
|
||||
NULL, 0);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = i;
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm technisat_usb2_i2c_algo = {
|
||||
.master_xfer = technisat_usb2_i2c_xfer,
|
||||
.functionality = technisat_usb2_i2c_func,
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void technisat_usb2_frontend_reset(struct usb_device *udev)
|
||||
{
|
||||
usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
SET_FRONT_END_RESET_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
10, 0,
|
||||
NULL, 0, 500);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* LED control */
|
||||
enum technisat_usb2_led_state {
|
||||
TECH_LED_OFF,
|
||||
TECH_LED_BLINK,
|
||||
TECH_LED_ON,
|
||||
TECH_LED_UNDEFINED
|
||||
};
|
||||
|
||||
static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
u8 led[8] = {
|
||||
red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
|
||||
0
|
||||
};
|
||||
|
||||
if (disable_led_control && state != TECH_LED_OFF)
|
||||
return 0;
|
||||
|
||||
switch (state) {
|
||||
case TECH_LED_ON:
|
||||
led[1] = 0x82;
|
||||
break;
|
||||
case TECH_LED_BLINK:
|
||||
led[1] = 0x82;
|
||||
if (red) {
|
||||
led[2] = 0x02;
|
||||
led[3] = 10;
|
||||
led[4] = 10;
|
||||
} else {
|
||||
led[2] = 0xff;
|
||||
led[3] = 50;
|
||||
led[4] = 50;
|
||||
}
|
||||
led[5] = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
case TECH_LED_OFF:
|
||||
led[1] = 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
0, 0,
|
||||
led, sizeof(led), 500);
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
|
||||
{
|
||||
int ret;
|
||||
u8 b = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
(red << 8) | green, 0,
|
||||
&b, 1, 500);
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void technisat_usb2_green_led_control(struct work_struct *work)
|
||||
{
|
||||
struct technisat_usb2_state *state =
|
||||
container_of(work, struct technisat_usb2_state, green_led_work.work);
|
||||
struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
|
||||
|
||||
if (state->power_state == 0)
|
||||
goto schedule;
|
||||
|
||||
if (fe != NULL) {
|
||||
enum fe_status status;
|
||||
|
||||
if (fe->ops.read_status(fe, &status) != 0)
|
||||
goto schedule;
|
||||
|
||||
if (status & FE_HAS_LOCK) {
|
||||
u32 ber;
|
||||
|
||||
if (fe->ops.read_ber(fe, &ber) != 0)
|
||||
goto schedule;
|
||||
|
||||
if (ber > 1000)
|
||||
technisat_usb2_set_led(state->dev, 0, TECH_LED_BLINK);
|
||||
else
|
||||
technisat_usb2_set_led(state->dev, 0, TECH_LED_ON);
|
||||
} else
|
||||
technisat_usb2_set_led(state->dev, 0, TECH_LED_OFF);
|
||||
}
|
||||
|
||||
schedule:
|
||||
schedule_delayed_work(&state->green_led_work,
|
||||
msecs_to_jiffies(500));
|
||||
}
|
||||
|
||||
/* method to find out whether the firmware has to be downloaded or not */
|
||||
static int technisat_usb2_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold)
|
||||
{
|
||||
int ret;
|
||||
u8 version[3];
|
||||
|
||||
/* first select the interface */
|
||||
if (usb_set_interface(udev, 0, 1) != 0)
|
||||
err("could not set alternate setting to 0");
|
||||
else
|
||||
info("set alternate setting");
|
||||
|
||||
*cold = 0; /* by default do not download a firmware - just in case something is wrong */
|
||||
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
GET_VERSION_INFO_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
0, 0,
|
||||
version, sizeof(version), 500);
|
||||
|
||||
if (ret < 0)
|
||||
*cold = 1;
|
||||
else {
|
||||
info("firmware version: %d.%d", version[1], version[2]);
|
||||
*cold = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* power control */
|
||||
static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
|
||||
{
|
||||
struct technisat_usb2_state *state = d->priv;
|
||||
|
||||
state->power_state = level;
|
||||
|
||||
if (disable_led_control)
|
||||
return 0;
|
||||
|
||||
/* green led is turned off in any case - will be turned on when tuning */
|
||||
technisat_usb2_set_led(d, 0, TECH_LED_OFF);
|
||||
/* red led is turned on all the time */
|
||||
technisat_usb2_set_led(d, 1, TECH_LED_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mac address reading - from the eeprom */
|
||||
#if 0
|
||||
static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
|
||||
{
|
||||
u8 reg;
|
||||
u8 b[16];
|
||||
int i, j;
|
||||
|
||||
/* full EEPROM dump */
|
||||
for (j = 0; j < 256 * 4; j += 16) {
|
||||
reg = j;
|
||||
if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, ®, 1, b, 16) != 0)
|
||||
break;
|
||||
|
||||
deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
|
||||
for (i = 0; i < 16; i++)
|
||||
deb_eeprom("%02x ", b[i]);
|
||||
deb_eeprom("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
|
||||
{
|
||||
u8 lrc = 0;
|
||||
while (--length)
|
||||
lrc ^= *b++;
|
||||
return lrc;
|
||||
}
|
||||
|
||||
static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
|
||||
u16 offset, u8 *b, u16 length, u8 tries)
|
||||
{
|
||||
u8 bo = offset & 0xff;
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = 0x50 | ((offset >> 8) & 0x3),
|
||||
.buf = &bo,
|
||||
.len = 1
|
||||
}, {
|
||||
.addr = 0x50 | ((offset >> 8) & 0x3),
|
||||
.flags = I2C_M_RD,
|
||||
.buf = b,
|
||||
.len = length
|
||||
}
|
||||
};
|
||||
|
||||
while (tries--) {
|
||||
int status;
|
||||
|
||||
if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
|
||||
break;
|
||||
|
||||
status =
|
||||
technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
|
||||
|
||||
if (status)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
#define EEPROM_MAC_START 0x3f8
|
||||
#define EEPROM_MAC_TOTAL 8
|
||||
static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
|
||||
u8 mac[])
|
||||
{
|
||||
u8 buf[EEPROM_MAC_TOTAL];
|
||||
|
||||
if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
|
||||
buf, EEPROM_MAC_TOTAL, 4) != 0)
|
||||
return -ENODEV;
|
||||
|
||||
memcpy(mac, buf, 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* frontend attach */
|
||||
static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
|
||||
fe_sec_voltage_t voltage)
|
||||
{
|
||||
int i;
|
||||
u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
|
||||
|
||||
gpio[2] = 1; /* high - voltage ? */
|
||||
|
||||
switch (voltage) {
|
||||
case SEC_VOLTAGE_13:
|
||||
gpio[0] = 1;
|
||||
break;
|
||||
case SEC_VOLTAGE_18:
|
||||
gpio[0] = 1;
|
||||
gpio[1] = 1;
|
||||
break;
|
||||
default:
|
||||
case SEC_VOLTAGE_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0)
|
||||
return -EREMOTEIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct stv090x_config technisat_usb2_stv090x_config = {
|
||||
.device = STV0903,
|
||||
.demod_mode = STV090x_SINGLE,
|
||||
.clk_mode = STV090x_CLK_EXT,
|
||||
|
||||
.xtal = 8000000,
|
||||
.address = 0x68,
|
||||
|
||||
.ts1_mode = STV090x_TSMODE_DVBCI,
|
||||
.ts1_clk = 13400000,
|
||||
.ts1_tei = 1,
|
||||
|
||||
.repeater_level = STV090x_RPTLEVEL_64,
|
||||
|
||||
.tuner_bbgain = 6,
|
||||
};
|
||||
|
||||
static struct stv6110x_config technisat_usb2_stv6110x_config = {
|
||||
.addr = 0x60,
|
||||
.refclk = 16000000,
|
||||
.clk_div = 2,
|
||||
};
|
||||
|
||||
static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
|
||||
{
|
||||
struct usb_device *udev = a->dev->udev;
|
||||
int ret;
|
||||
|
||||
a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
|
||||
&a->dev->i2c_adap, STV090x_DEMODULATOR_0);
|
||||
|
||||
if (a->fe_adap[0].fe) {
|
||||
struct stv6110x_devctl *ctl;
|
||||
|
||||
ctl = dvb_attach(stv6110x_attach,
|
||||
a->fe_adap[0].fe,
|
||||
&technisat_usb2_stv6110x_config,
|
||||
&a->dev->i2c_adap);
|
||||
|
||||
if (ctl) {
|
||||
technisat_usb2_stv090x_config.tuner_init = ctl->tuner_init;
|
||||
technisat_usb2_stv090x_config.tuner_sleep = ctl->tuner_sleep;
|
||||
technisat_usb2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
|
||||
technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
|
||||
technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
|
||||
technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
|
||||
technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
|
||||
technisat_usb2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
|
||||
technisat_usb2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
|
||||
technisat_usb2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
|
||||
technisat_usb2_stv090x_config.tuner_get_status = ctl->tuner_get_status;
|
||||
|
||||
/* call the init function once to initialize
|
||||
tuner's clock output divider and demod's
|
||||
master clock */
|
||||
if (a->fe_adap[0].fe->ops.init)
|
||||
a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
|
||||
|
||||
if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
0, 0,
|
||||
NULL, 0, 500);
|
||||
mutex_unlock(&a->dev->i2c_mutex);
|
||||
|
||||
if (ret != 0)
|
||||
err("could not set IF_CLK to external");
|
||||
|
||||
a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
|
||||
|
||||
/* if everything was successful assign a nice name to the frontend */
|
||||
strlcpy(a->fe_adap[0].fe->ops.info.name, a->dev->desc->name,
|
||||
sizeof(a->fe_adap[0].fe->ops.info.name));
|
||||
} else {
|
||||
dvb_frontend_detach(a->fe_adap[0].fe);
|
||||
a->fe_adap[0].fe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
technisat_usb2_set_led_timer(a->dev, 1, 1);
|
||||
|
||||
return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* Remote control */
|
||||
|
||||
/* the device is giving providing raw IR-signals to the host mapping
|
||||
* it only to one remote control is just the default implementation
|
||||
*/
|
||||
#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
|
||||
#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
|
||||
|
||||
#define FIRMWARE_CLOCK_TICK 83333
|
||||
#define FIRMWARE_CLOCK_DIVISOR 256
|
||||
|
||||
#define IR_PERCENT_TOLERANCE 15
|
||||
|
||||
#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
|
||||
#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
|
||||
|
||||
#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
|
||||
#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
|
||||
|
||||
#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
|
||||
#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
|
||||
|
||||
#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
|
||||
#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
|
||||
|
||||
static int technisat_usb2_get_ir(struct dvb_usb_device *d)
|
||||
{
|
||||
u8 buf[62], *b;
|
||||
int ret;
|
||||
struct ir_raw_event ev;
|
||||
|
||||
buf[0] = GET_IR_DATA_VENDOR_REQUEST;
|
||||
buf[1] = 0x08;
|
||||
buf[2] = 0x8f;
|
||||
buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
|
||||
buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
|
||||
GET_IR_DATA_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
0, 0,
|
||||
buf, 5, 500);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
|
||||
GET_IR_DATA_VENDOR_REQUEST,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
0x8080, 0,
|
||||
buf, sizeof(buf), 500);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret == 1)
|
||||
return 0; /* no key pressed */
|
||||
|
||||
/* decoding */
|
||||
b = buf+1;
|
||||
|
||||
#if 0
|
||||
deb_rc("RC: %d ", ret);
|
||||
debug_dump(b, ret, deb_rc);
|
||||
#endif
|
||||
|
||||
ev.pulse = 0;
|
||||
while (1) {
|
||||
ev.pulse = !ev.pulse;
|
||||
ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
|
||||
ir_raw_event_store(d->rc_dev, &ev);
|
||||
|
||||
b++;
|
||||
if (*b == 0xff) {
|
||||
ev.pulse = 0;
|
||||
ev.duration = 888888*2;
|
||||
ir_raw_event_store(d->rc_dev, &ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ir_raw_event_handle(d->rc_dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int technisat_usb2_rc_query(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret = technisat_usb2_get_ir(d);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
if (!disable_led_control)
|
||||
technisat_usb2_set_led(d, 1, TECH_LED_BLINK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB-USB and USB stuff follows */
|
||||
static struct usb_device_id technisat_usb2_id_table[] = {
|
||||
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) },
|
||||
{ 0 } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table);
|
||||
|
||||
/* device description */
|
||||
static struct dvb_usb_device_properties technisat_usb2_devices = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.identify_state = technisat_usb2_identify_state,
|
||||
.firmware = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
|
||||
|
||||
.size_of_priv = sizeof(struct technisat_usb2_state),
|
||||
|
||||
.i2c_algo = &technisat_usb2_i2c_algo,
|
||||
|
||||
.power_ctrl = technisat_usb2_power_ctrl,
|
||||
.read_mac_address = technisat_usb2_read_mac_address,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.frontend_attach = technisat_usb2_frontend_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 8,
|
||||
.endpoint = 0x2,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 32,
|
||||
.framesize = 2048,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = 0,
|
||||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Technisat SkyStar USB HD (DVB-S/S2)",
|
||||
{ &technisat_usb2_id_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
|
||||
.rc.core = {
|
||||
.rc_interval = 100,
|
||||
.rc_codes = RC_MAP_TECHNISAT_USB2,
|
||||
.module_name = "technisat-usb2",
|
||||
.rc_query = technisat_usb2_rc_query,
|
||||
.allowed_protos = RC_BIT_ALL,
|
||||
.driver_type = RC_DRIVER_IR_RAW,
|
||||
}
|
||||
};
|
||||
|
||||
static int technisat_usb2_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *dev;
|
||||
|
||||
if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
|
||||
&dev, adapter_nr) != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (dev) {
|
||||
struct technisat_usb2_state *state = dev->priv;
|
||||
state->dev = dev;
|
||||
|
||||
if (!disable_led_control) {
|
||||
INIT_DELAYED_WORK(&state->green_led_work,
|
||||
technisat_usb2_green_led_control);
|
||||
schedule_delayed_work(&state->green_led_work,
|
||||
msecs_to_jiffies(500));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void technisat_usb2_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *dev = usb_get_intfdata(intf);
|
||||
|
||||
/* work and stuff was only created when the device is is hot-state */
|
||||
if (dev != NULL) {
|
||||
struct technisat_usb2_state *state = dev->priv;
|
||||
if (state != NULL)
|
||||
cancel_delayed_work_sync(&state->green_led_work);
|
||||
}
|
||||
|
||||
dvb_usb_device_exit(intf);
|
||||
}
|
||||
|
||||
static struct usb_driver technisat_usb2_driver = {
|
||||
.name = "dvb_usb_technisat_usb2",
|
||||
.probe = technisat_usb2_probe,
|
||||
.disconnect = technisat_usb2_disconnect,
|
||||
.id_table = technisat_usb2_id_table,
|
||||
};
|
||||
|
||||
module_usb_driver(technisat_usb2_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
|
||||
MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
826
drivers/media/usb/dvb-usb/ttusb2.c
Normal file
826
drivers/media/usb/dvb-usb/ttusb2.c
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
|
||||
* (e.g. Pinnacle 400e DVB-S USB2.0).
|
||||
*
|
||||
* The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
|
||||
*
|
||||
* TDA8263 + TDA10086
|
||||
*
|
||||
* I2C addresses:
|
||||
* 0x08 - LNBP21PD - LNB power supply
|
||||
* 0x0e - TDA10086 - Demodulator
|
||||
* 0x50 - FX2 eeprom
|
||||
* 0x60 - TDA8263 - Tuner
|
||||
* 0x78 ???
|
||||
*
|
||||
* Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
|
||||
* Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
|
||||
* Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#define DVB_USB_LOG_PREFIX "ttusb2"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#include "ttusb2.h"
|
||||
|
||||
#include "tda826x.h"
|
||||
#include "tda10086.h"
|
||||
#include "tda1002x.h"
|
||||
#include "tda10048.h"
|
||||
#include "tda827x.h"
|
||||
#include "lnbp21.h"
|
||||
/* CA */
|
||||
#include "dvb_ca_en50221.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_ttusb2_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args)
|
||||
module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
static int dvb_usb_ttusb2_debug_ci;
|
||||
module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
|
||||
MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define ci_dbg(format, arg...) \
|
||||
do { \
|
||||
if (dvb_usb_ttusb2_debug_ci) \
|
||||
printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
|
||||
": %s " format "\n" , __func__, ## arg); \
|
||||
} while (0)
|
||||
|
||||
enum {
|
||||
TT3650_CMD_CI_TEST = 0x40,
|
||||
TT3650_CMD_CI_RD_CTRL,
|
||||
TT3650_CMD_CI_WR_CTRL,
|
||||
TT3650_CMD_CI_RD_ATTR,
|
||||
TT3650_CMD_CI_WR_ATTR,
|
||||
TT3650_CMD_CI_RESET,
|
||||
TT3650_CMD_CI_SET_VIDEO_PORT
|
||||
};
|
||||
|
||||
struct ttusb2_state {
|
||||
struct dvb_ca_en50221 ca;
|
||||
struct mutex ca_mutex;
|
||||
u8 id;
|
||||
u16 last_rc_key;
|
||||
};
|
||||
|
||||
static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
|
||||
u8 *wbuf, int wlen, u8 *rbuf, int rlen)
|
||||
{
|
||||
struct ttusb2_state *st = d->priv;
|
||||
u8 *s, *r = NULL;
|
||||
int ret = 0;
|
||||
|
||||
s = kzalloc(wlen+4, GFP_KERNEL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
r = kzalloc(64, GFP_KERNEL);
|
||||
if (!r) {
|
||||
kfree(s);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s[0] = 0xaa;
|
||||
s[1] = ++st->id;
|
||||
s[2] = cmd;
|
||||
s[3] = wlen;
|
||||
memcpy(&s[4],wbuf,wlen);
|
||||
|
||||
ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
|
||||
|
||||
if (ret != 0 ||
|
||||
r[0] != 0x55 ||
|
||||
r[1] != s[1] ||
|
||||
r[2] != cmd ||
|
||||
(rlen > 0 && r[3] != rlen)) {
|
||||
warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
|
||||
kfree(s);
|
||||
kfree(r);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rlen > 0)
|
||||
memcpy(rbuf, &r[4], rlen);
|
||||
|
||||
kfree(s);
|
||||
kfree(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ci */
|
||||
static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
|
||||
{
|
||||
int ret;
|
||||
u8 rx[60];/* (64 -4) */
|
||||
ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
|
||||
if (!ret)
|
||||
memcpy(data, rx, read_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
|
||||
{
|
||||
struct dvb_usb_device *d = ca->data;
|
||||
struct ttusb2_state *state = d->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
|
||||
{
|
||||
u8 buf[3];
|
||||
int ret = 0;
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = (address >> 8) & 0x0F;
|
||||
buf[1] = address;
|
||||
|
||||
|
||||
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
|
||||
|
||||
ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return buf[2];
|
||||
}
|
||||
|
||||
static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
|
||||
{
|
||||
u8 buf[3];
|
||||
|
||||
ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = (address >> 8) & 0x0F;
|
||||
buf[1] = address;
|
||||
buf[2] = value;
|
||||
|
||||
return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
|
||||
}
|
||||
|
||||
static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
|
||||
{
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = address & 3;
|
||||
|
||||
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
|
||||
|
||||
ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = address;
|
||||
buf[1] = value;
|
||||
|
||||
return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
|
||||
}
|
||||
|
||||
static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
|
||||
{
|
||||
u8 buf[1];
|
||||
int ret;
|
||||
|
||||
ci_dbg("%d %d", slot, enable);
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = enable;
|
||||
|
||||
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (enable != buf[0]) {
|
||||
err("CI not %sabled.", enable ? "en" : "dis");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
return tt3650_ci_set_video_port(ca, slot, 0);
|
||||
}
|
||||
|
||||
static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
return tt3650_ci_set_video_port(ca, slot, 1);
|
||||
}
|
||||
|
||||
static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = ca->data;
|
||||
struct ttusb2_state *state = d->priv;
|
||||
u8 buf[1];
|
||||
int ret;
|
||||
|
||||
ci_dbg("%d", slot);
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = 0;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
msleep(500);
|
||||
|
||||
buf[0] = 1;
|
||||
|
||||
ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
msleep(500);
|
||||
|
||||
buf[0] = 0; /* FTA */
|
||||
|
||||
ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
|
||||
|
||||
msleep(1100);
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
u8 buf[1];
|
||||
int ret;
|
||||
|
||||
if (slot)
|
||||
return -EINVAL;
|
||||
|
||||
ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (1 == buf[0]) {
|
||||
return DVB_CA_EN50221_POLL_CAM_PRESENT |
|
||||
DVB_CA_EN50221_POLL_CAM_READY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tt3650_ci_uninit(struct dvb_usb_device *d)
|
||||
{
|
||||
struct ttusb2_state *state;
|
||||
|
||||
ci_dbg("");
|
||||
|
||||
if (NULL == d)
|
||||
return;
|
||||
|
||||
state = d->priv;
|
||||
if (NULL == state)
|
||||
return;
|
||||
|
||||
if (NULL == state->ca.data)
|
||||
return;
|
||||
|
||||
dvb_ca_en50221_release(&state->ca);
|
||||
|
||||
memset(&state->ca, 0, sizeof(state->ca));
|
||||
}
|
||||
|
||||
static int tt3650_ci_init(struct dvb_usb_adapter *a)
|
||||
{
|
||||
struct dvb_usb_device *d = a->dev;
|
||||
struct ttusb2_state *state = d->priv;
|
||||
int ret;
|
||||
|
||||
ci_dbg("");
|
||||
|
||||
mutex_init(&state->ca_mutex);
|
||||
|
||||
state->ca.owner = THIS_MODULE;
|
||||
state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
|
||||
state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
|
||||
state->ca.read_cam_control = tt3650_ci_read_cam_control;
|
||||
state->ca.write_cam_control = tt3650_ci_write_cam_control;
|
||||
state->ca.slot_reset = tt3650_ci_slot_reset;
|
||||
state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
|
||||
state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
|
||||
state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
|
||||
state->ca.data = d;
|
||||
|
||||
ret = dvb_ca_en50221_init(&a->dvb_adap,
|
||||
&state->ca,
|
||||
/* flags */ 0,
|
||||
/* n_slots */ 1);
|
||||
if (ret) {
|
||||
err("Cannot initialize CI: Error %d.", ret);
|
||||
memset(&state->ca, 0, sizeof(state->ca));
|
||||
return ret;
|
||||
}
|
||||
|
||||
info("CI initialized.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
static u8 obuf[60], ibuf[60];
|
||||
int i, write_read, read;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 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 = i+1 < num && (msg[i+1].flags & I2C_M_RD);
|
||||
read = msg[i].flags & I2C_M_RD;
|
||||
|
||||
obuf[0] = (msg[i].addr << 1) | (write_read | read);
|
||||
if (read)
|
||||
obuf[1] = 0;
|
||||
else
|
||||
obuf[1] = msg[i].len;
|
||||
|
||||
/* read request */
|
||||
if (write_read)
|
||||
obuf[2] = msg[i+1].len;
|
||||
else if (read)
|
||||
obuf[2] = msg[i].len;
|
||||
else
|
||||
obuf[2] = 0;
|
||||
|
||||
memcpy(&obuf[3], msg[i].buf, msg[i].len);
|
||||
|
||||
if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
|
||||
err("i2c transfer failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (write_read) {
|
||||
memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
|
||||
i++;
|
||||
} else if (read)
|
||||
memcpy(msg[i].buf, &ibuf[3], msg[i].len);
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ttusb2_i2c_algo = {
|
||||
.master_xfer = ttusb2_i2c_xfer,
|
||||
.functionality = ttusb2_i2c_func,
|
||||
};
|
||||
|
||||
/* command to poll IR receiver (copied from pctv452e.c) */
|
||||
#define CMD_GET_IR_CODE 0x1b
|
||||
|
||||
/* IR */
|
||||
static int tt3650_rc_query(struct dvb_usb_device *d)
|
||||
{
|
||||
int ret;
|
||||
u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
|
||||
struct ttusb2_state *st = d->priv;
|
||||
ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (rx[8] & 0x01) {
|
||||
/* got a "press" event */
|
||||
st->last_rc_key = RC_SCANCODE_RC5(rx[3], rx[2]);
|
||||
deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
|
||||
rc_keydown(d->rc_dev, RC_TYPE_RC5, st->last_rc_key, rx[1]);
|
||||
} else if (st->last_rc_key) {
|
||||
rc_keyup(d->rc_dev);
|
||||
st->last_rc_key = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int ttusb2_identify_state (struct usb_device *udev, struct
|
||||
dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
|
||||
{
|
||||
u8 b = onoff;
|
||||
ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
|
||||
return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static struct tda10086_config tda10086_config = {
|
||||
.demod_address = 0x0e,
|
||||
.invert = 0,
|
||||
.diseqc_tone = 1,
|
||||
.xtal_freq = TDA10086_XTAL_16M,
|
||||
};
|
||||
|
||||
static struct tda10023_config tda10023_config = {
|
||||
.demod_address = 0x0c,
|
||||
.invert = 0,
|
||||
.xtal = 16000000,
|
||||
.pll_m = 11,
|
||||
.pll_p = 3,
|
||||
.pll_n = 1,
|
||||
.deltaf = 0xa511,
|
||||
};
|
||||
|
||||
static struct tda10048_config tda10048_config = {
|
||||
.demod_address = 0x10 >> 1,
|
||||
.output_mode = TDA10048_PARALLEL_OUTPUT,
|
||||
.inversion = TDA10048_INVERSION_ON,
|
||||
.dtv6_if_freq_khz = TDA10048_IF_4000,
|
||||
.dtv7_if_freq_khz = TDA10048_IF_4500,
|
||||
.dtv8_if_freq_khz = TDA10048_IF_5000,
|
||||
.clk_freq_khz = TDA10048_CLK_16000,
|
||||
.no_firmware = 1,
|
||||
.set_pll = true ,
|
||||
.pll_m = 5,
|
||||
.pll_n = 3,
|
||||
.pll_p = 0,
|
||||
};
|
||||
|
||||
static struct tda827x_config tda827x_config = {
|
||||
.config = 0,
|
||||
};
|
||||
|
||||
static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev,0,3) < 0)
|
||||
err("set interface to alts=3 failed");
|
||||
|
||||
if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
|
||||
deb_info("TDA10086 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||
|
||||
return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
|
||||
}
|
||||
|
||||
static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
|
||||
err("set interface to alts=3 failed");
|
||||
|
||||
if (adap->fe_adap[0].fe == NULL) {
|
||||
/* FE 0 DVB-C */
|
||||
adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
|
||||
&tda10023_config, &adap->dev->i2c_adap, 0x48);
|
||||
|
||||
if (adap->fe_adap[0].fe == NULL) {
|
||||
deb_info("TDA10023 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
tt3650_ci_init(adap);
|
||||
} else {
|
||||
adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
|
||||
&tda10048_config, &adap->dev->i2c_adap);
|
||||
|
||||
if (adap->fe_adap[1].fe == NULL) {
|
||||
deb_info("TDA10048 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* tuner is behind TDA10023 I2C-gate */
|
||||
adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_frontend *fe;
|
||||
|
||||
/* MFE: select correct FE to attach tuner since that's called twice */
|
||||
if (adap->fe_adap[1].fe == NULL)
|
||||
fe = adap->fe_adap[0].fe;
|
||||
else
|
||||
fe = adap->fe_adap[1].fe;
|
||||
|
||||
/* attach tuner */
|
||||
if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
|
||||
printk(KERN_ERR "%s: No tda827x found!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
|
||||
deb_info("TDA8263 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
|
||||
deb_info("LNBP21 attach failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties ttusb2_properties;
|
||||
static struct dvb_usb_device_properties ttusb2_properties_s2400;
|
||||
static struct dvb_usb_device_properties ttusb2_properties_ct3650;
|
||||
|
||||
static void ttusb2_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
|
||||
tt3650_ci_uninit(d);
|
||||
dvb_usb_device_exit(intf);
|
||||
}
|
||||
|
||||
static int ttusb2_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_device_id ttusb2_table [] = {
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
|
||||
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
|
||||
{ USB_DEVICE(USB_VID_TECHNOTREND,
|
||||
USB_PID_TECHNOTREND_CONNECT_S2400) },
|
||||
{ USB_DEVICE(USB_VID_TECHNOTREND,
|
||||
USB_PID_TECHNOTREND_CONNECT_CT3650) },
|
||||
{ USB_DEVICE(USB_VID_TECHNOTREND,
|
||||
USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, ttusb2_table);
|
||||
|
||||
static struct dvb_usb_device_properties ttusb2_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-pctv-400e-01.fw",
|
||||
|
||||
.size_of_priv = sizeof(struct ttusb2_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.streaming_ctrl = NULL, // ttusb2_streaming_ctrl,
|
||||
|
||||
.frontend_attach = ttusb2_frontend_tda10086_attach,
|
||||
.tuner_attach = ttusb2_tuner_tda826x_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 4,
|
||||
.framesize = 940,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = ttusb2_power_ctrl,
|
||||
.identify_state = ttusb2_identify_state,
|
||||
|
||||
.i2c_algo = &ttusb2_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "Pinnacle 400e DVB-S USB2.0",
|
||||
{ &ttusb2_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Pinnacle 450e DVB-S USB2.0",
|
||||
{ &ttusb2_table[1], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-tt-s2400-01.fw",
|
||||
|
||||
.size_of_priv = sizeof(struct ttusb2_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.streaming_ctrl = NULL,
|
||||
|
||||
.frontend_attach = ttusb2_frontend_tda10086_attach,
|
||||
.tuner_attach = ttusb2_tuner_tda826x_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 4,
|
||||
.framesize = 940,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
}
|
||||
},
|
||||
|
||||
.power_ctrl = ttusb2_power_ctrl,
|
||||
.identify_state = ttusb2_identify_state,
|
||||
|
||||
.i2c_algo = &ttusb2_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 2,
|
||||
.devices = {
|
||||
{ "Technotrend TT-connect S-2400",
|
||||
{ &ttusb2_table[2], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "Technotrend TT-connect S-2400 (8kB EEPROM)",
|
||||
{ &ttusb2_table[4], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.size_of_priv = sizeof(struct ttusb2_state),
|
||||
|
||||
.rc.core = {
|
||||
.rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */
|
||||
.rc_codes = RC_MAP_TT_1500,
|
||||
.rc_query = tt3650_rc_query,
|
||||
.allowed_protos = RC_BIT_RC5,
|
||||
},
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 2,
|
||||
.fe = {{
|
||||
.streaming_ctrl = NULL,
|
||||
|
||||
.frontend_attach = ttusb2_frontend_tda10023_attach,
|
||||
.tuner_attach = ttusb2_tuner_tda827x_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 4,
|
||||
.framesize = 940,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.streaming_ctrl = NULL,
|
||||
|
||||
.frontend_attach = ttusb2_frontend_tda10023_attach,
|
||||
.tuner_attach = ttusb2_tuner_tda827x_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 4,
|
||||
.framesize = 940,
|
||||
.interval = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = ttusb2_power_ctrl,
|
||||
.identify_state = ttusb2_identify_state,
|
||||
|
||||
.i2c_algo = &ttusb2_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "Technotrend TT-connect CT-3650",
|
||||
.warm_ids = { &ttusb2_table[3], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver ttusb2_driver = {
|
||||
.name = "dvb_usb_ttusb2",
|
||||
.probe = ttusb2_probe,
|
||||
.disconnect = ttusb2_usb_disconnect,
|
||||
.id_table = ttusb2_table,
|
||||
};
|
||||
|
||||
module_usb_driver(ttusb2_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
70
drivers/media/usb/dvb-usb/ttusb2.h
Normal file
70
drivers/media/usb/dvb-usb/ttusb2.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
|
||||
* (e.g. Pinnacle 400e DVB-S USB2.0).
|
||||
*
|
||||
* Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
|
||||
* Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
|
||||
* Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.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_TTUSB2_H_
|
||||
#define _DVB_USB_TTUSB2_H_
|
||||
|
||||
/* TTUSB protocol
|
||||
*
|
||||
* always to messages (out/in)
|
||||
* out message:
|
||||
* 0xaa <id> <cmdbyte> <datalen> <data...>
|
||||
*
|
||||
* in message (complete block is always 0x40 bytes long)
|
||||
* 0x55 <id> <cmdbyte> <datalen> <data...>
|
||||
*
|
||||
* id is incremented for each transaction
|
||||
*/
|
||||
|
||||
#define CMD_DSP_DOWNLOAD 0x13
|
||||
/* out data: <byte>[28]
|
||||
* last block must be empty */
|
||||
|
||||
#define CMD_DSP_BOOT 0x14
|
||||
/* out data: nothing */
|
||||
|
||||
#define CMD_POWER 0x15
|
||||
/* out data: <on=1/off=0> */
|
||||
|
||||
#define CMD_LNB 0x16
|
||||
/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */
|
||||
|
||||
#define CMD_GET_VERSION 0x17
|
||||
/* in data: <version_byte>[5] */
|
||||
|
||||
#define CMD_DISEQC 0x18
|
||||
/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
|
||||
|
||||
#define CMD_PID_ENABLE 0x22
|
||||
/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
|
||||
|
||||
#define CMD_PID_DISABLE 0x23
|
||||
/* out data: <index> */
|
||||
|
||||
#define CMD_FILTER_ENABLE 0x24
|
||||
/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */
|
||||
|
||||
#define CMD_FILTER_DISABLE 0x25
|
||||
/* out data: <index> */
|
||||
|
||||
#define CMD_GET_DSP_VERSION 0x26
|
||||
/* in data: <version_byte>[28] */
|
||||
|
||||
#define CMD_I2C_XFER 0x31
|
||||
/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen]
|
||||
* in data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */
|
||||
|
||||
#define CMD_I2C_BITRATE 0x32
|
||||
/* out data: <default=0> */
|
||||
|
||||
#endif
|
||||
151
drivers/media/usb/dvb-usb/umt-010.c
Normal file
151
drivers/media/usb/dvb-usb/umt-010.c
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/* 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"
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
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_adapter *adap)
|
||||
{
|
||||
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;
|
||||
|
||||
adap->fe_adap[0].fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int umt_tuner_attach (struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_TUA6034);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* USB Driver stuff */
|
||||
static struct dvb_usb_device_properties umt_properties;
|
||||
|
||||
static int umt_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
if (0 == dvb_usb_device_init(intf, &umt_properties,
|
||||
THIS_MODULE, NULL, adapter_nr))
|
||||
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_device_properties umt_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-umt-010-02.fw",
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.streaming_ctrl = dibusb2_0_streaming_ctrl,
|
||||
.frontend_attach = umt_mt352_frontend_attach,
|
||||
.tuner_attach = umt_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = MAX_NO_URBS_FOR_DATA_STREAM,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct dibusb_state),
|
||||
}
|
||||
},
|
||||
.power_ctrl = dibusb_power_ctrl,
|
||||
|
||||
.i2c_algo = &dibusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.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 = {
|
||||
.name = "dvb_usb_umt_010",
|
||||
.probe = umt_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = umt_table,
|
||||
};
|
||||
|
||||
module_usb_driver(umt_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
254
drivers/media/usb/dvb-usb/usb-urb.c
Normal file
254
drivers/media/usb/dvb-usb/usb-urb.c
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/* usb-urb.c is part of the DVB USB library.
|
||||
*
|
||||
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
|
||||
* see dvb-usb-init.c for copyright information.
|
||||
*
|
||||
* This file keeps functions for initializing and handling the
|
||||
* BULK and ISOC USB data transfers in a generic way.
|
||||
* Can be used for DVB-only and also, that's the plan, for
|
||||
* Hybrid USB devices (analog and DVB).
|
||||
*/
|
||||
#include "dvb-usb-common.h"
|
||||
|
||||
/* URB stuff for streaming */
|
||||
static void usb_urb_complete(struct urb *urb)
|
||||
{
|
||||
struct usb_data_stream *stream = urb->context;
|
||||
int ptype = usb_pipetype(urb->pipe);
|
||||
int i;
|
||||
u8 *b;
|
||||
|
||||
deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
|
||||
ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
|
||||
urb->status,urb->actual_length,urb->transfer_buffer_length,
|
||||
urb->number_of_packets,urb->error_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.\n", urb->status);
|
||||
break;
|
||||
}
|
||||
|
||||
b = (u8 *) urb->transfer_buffer;
|
||||
switch (ptype) {
|
||||
case PIPE_ISOCHRONOUS:
|
||||
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)
|
||||
stream->complete(stream, 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_uxfer);
|
||||
break;
|
||||
case PIPE_BULK:
|
||||
if (urb->actual_length > 0)
|
||||
stream->complete(stream, b, urb->actual_length);
|
||||
break;
|
||||
default:
|
||||
err("unknown endpoint type in completition handler.");
|
||||
return;
|
||||
}
|
||||
usb_submit_urb(urb,GFP_ATOMIC);
|
||||
}
|
||||
|
||||
int usb_urb_kill(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < stream->urbs_submitted; i++) {
|
||||
deb_ts("killing URB no. %d.\n",i);
|
||||
|
||||
/* stop the URB */
|
||||
usb_kill_urb(stream->urb_list[i]);
|
||||
}
|
||||
stream->urbs_submitted = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_submit(struct usb_data_stream *stream)
|
||||
{
|
||||
int i,ret;
|
||||
for (i = 0; i < stream->urbs_initialized; i++) {
|
||||
deb_ts("submitting URB no. %d\n",i);
|
||||
if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
|
||||
err("could not submit URB no. %d - get them all back",i);
|
||||
usb_urb_kill(stream);
|
||||
return ret;
|
||||
}
|
||||
stream->urbs_submitted++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_free_stream_buffers(struct usb_data_stream *stream)
|
||||
{
|
||||
if (stream->state & USB_STATE_URB_BUF) {
|
||||
while (stream->buf_num) {
|
||||
stream->buf_num--;
|
||||
deb_mem("freeing buffer %d\n",stream->buf_num);
|
||||
usb_free_coherent(stream->udev, stream->buf_size,
|
||||
stream->buf_list[stream->buf_num],
|
||||
stream->dma_addr[stream->buf_num]);
|
||||
}
|
||||
}
|
||||
|
||||
stream->state &= ~USB_STATE_URB_BUF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
|
||||
{
|
||||
stream->buf_num = 0;
|
||||
stream->buf_size = size;
|
||||
|
||||
deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
|
||||
|
||||
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
|
||||
deb_mem("allocating buffer %d\n",stream->buf_num);
|
||||
if (( stream->buf_list[stream->buf_num] =
|
||||
usb_alloc_coherent(stream->udev, size, GFP_ATOMIC,
|
||||
&stream->dma_addr[stream->buf_num]) ) == NULL) {
|
||||
deb_mem("not enough memory for urb-buffer allocation.\n");
|
||||
usb_free_stream_buffers(stream);
|
||||
return -ENOMEM;
|
||||
}
|
||||
deb_mem("buffer %d: %p (dma: %Lu)\n",
|
||||
stream->buf_num,
|
||||
stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
|
||||
memset(stream->buf_list[stream->buf_num],0,size);
|
||||
stream->state |= USB_STATE_URB_BUF;
|
||||
}
|
||||
deb_mem("allocation successful\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_bulk_urb_init(struct usb_data_stream *stream)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
|
||||
stream->props.u.bulk.buffersize)) < 0)
|
||||
return i;
|
||||
|
||||
/* allocate the URBs */
|
||||
for (i = 0; i < stream->props.count; i++) {
|
||||
stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!stream->urb_list[i]) {
|
||||
deb_mem("not enough memory for urb_alloc_urb!.\n");
|
||||
for (j = 0; j < i; j++)
|
||||
usb_free_urb(stream->urb_list[j]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
|
||||
usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
|
||||
stream->buf_list[i],
|
||||
stream->props.u.bulk.buffersize,
|
||||
usb_urb_complete, stream);
|
||||
|
||||
stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
|
||||
stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_isoc_urb_init(struct usb_data_stream *stream)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
|
||||
stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
|
||||
return i;
|
||||
|
||||
/* allocate the URBs */
|
||||
for (i = 0; i < stream->props.count; i++) {
|
||||
struct urb *urb;
|
||||
int frame_offset = 0;
|
||||
|
||||
stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC);
|
||||
if (!stream->urb_list[i]) {
|
||||
deb_mem("not enough memory for urb_alloc_urb!\n");
|
||||
for (j = 0; j < i; j++)
|
||||
usb_free_urb(stream->urb_list[j]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
urb = stream->urb_list[i];
|
||||
|
||||
urb->dev = stream->udev;
|
||||
urb->context = stream;
|
||||
urb->complete = usb_urb_complete;
|
||||
urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
|
||||
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
||||
urb->interval = stream->props.u.isoc.interval;
|
||||
urb->number_of_packets = stream->props.u.isoc.framesperurb;
|
||||
urb->transfer_buffer_length = stream->buf_size;
|
||||
urb->transfer_buffer = stream->buf_list[i];
|
||||
urb->transfer_dma = stream->dma_addr[i];
|
||||
|
||||
for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
|
||||
urb->iso_frame_desc[j].offset = frame_offset;
|
||||
urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
|
||||
frame_offset += stream->props.u.isoc.framesize;
|
||||
}
|
||||
|
||||
stream->urbs_initialized++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
|
||||
{
|
||||
if (stream == NULL || props == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&stream->props, props, sizeof(*props));
|
||||
|
||||
usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
|
||||
|
||||
if (stream->complete == NULL) {
|
||||
err("there is no data callback - this doesn't make sense.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (stream->props.type) {
|
||||
case USB_BULK:
|
||||
return usb_bulk_urb_init(stream);
|
||||
case USB_ISOC:
|
||||
return usb_isoc_urb_init(stream);
|
||||
default:
|
||||
err("unknown URB-type for data transfer.");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_urb_exit(struct usb_data_stream *stream)
|
||||
{
|
||||
int i;
|
||||
|
||||
usb_urb_kill(stream);
|
||||
|
||||
for (i = 0; i < stream->urbs_initialized; i++) {
|
||||
if (stream->urb_list[i] != NULL) {
|
||||
deb_mem("freeing URB no. %d.\n",i);
|
||||
/* free the URBs */
|
||||
usb_free_urb(stream->urb_list[i]);
|
||||
}
|
||||
}
|
||||
stream->urbs_initialized = 0;
|
||||
|
||||
usb_free_stream_buffers(stream);
|
||||
return 0;
|
||||
}
|
||||
379
drivers/media/usb/dvb-usb/vp702x-fe.c
Normal file
379
drivers/media/usb/dvb-usb/vp702x-fe.c
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
|
||||
* DVB-S receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Metzler Brothers Systementwicklung GbR
|
||||
*
|
||||
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
|
||||
*
|
||||
* Thanks to Twinhan who kindly provided hardware and information.
|
||||
*
|
||||
* This file can be removed soon, after the DST-driver is rewritten to provice
|
||||
* the frontend-controlling separately.
|
||||
*
|
||||
* 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 "vp702x.h"
|
||||
|
||||
struct vp702x_fe_state {
|
||||
struct dvb_frontend fe;
|
||||
struct dvb_usb_device *d;
|
||||
|
||||
struct dvb_frontend_ops ops;
|
||||
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t tone_mode;
|
||||
|
||||
u8 lnb_buf[8];
|
||||
|
||||
u8 lock;
|
||||
u8 sig;
|
||||
u8 snr;
|
||||
|
||||
unsigned long next_status_check;
|
||||
unsigned long status_check_interval;
|
||||
};
|
||||
|
||||
static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
|
||||
{
|
||||
struct vp702x_device_state *dst = st->d->priv;
|
||||
u8 *buf;
|
||||
|
||||
if (time_after(jiffies, st->next_status_check)) {
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
buf = dst->buf;
|
||||
|
||||
vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
|
||||
st->lock = buf[4];
|
||||
|
||||
vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
|
||||
st->snr = buf[0];
|
||||
|
||||
vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
|
||||
st->sig = buf[0];
|
||||
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 vp702x_chksum(u8 *buf,int f, int count)
|
||||
{
|
||||
u8 s = 0;
|
||||
int i;
|
||||
for (i = f; i < f+count; i++)
|
||||
s += buf[i];
|
||||
return ~s+1;
|
||||
}
|
||||
|
||||
static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
deb_fe("%s\n",__func__);
|
||||
|
||||
if (st->lock == 0)
|
||||
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
|
||||
else
|
||||
*status = 0;
|
||||
|
||||
if (*status & FE_HAS_LOCK)
|
||||
st->status_check_interval = 1000;
|
||||
else
|
||||
st->status_check_interval = 250;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
*ber = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not supported by this Frontend */
|
||||
static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
*unc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
|
||||
*strength = (st->sig << 8) | st->sig;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
|
||||
{
|
||||
u8 _snr;
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
vp702x_fe_refresh_state(st);
|
||||
|
||||
_snr = (st->snr & 0x1f) * 0xff / 0x1f;
|
||||
*snr = (_snr << 8) | _snr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
|
||||
{
|
||||
deb_fe("%s\n",__func__);
|
||||
tune->min_delay_ms = 2000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
struct vp702x_device_state *dst = st->d->priv;
|
||||
u32 freq = fep->frequency/1000;
|
||||
/*CalFrequency*/
|
||||
/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
|
||||
u64 sr;
|
||||
u8 *cmd;
|
||||
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
|
||||
cmd = dst->buf;
|
||||
memset(cmd, 0, 10);
|
||||
|
||||
cmd[0] = (freq >> 8) & 0x7f;
|
||||
cmd[1] = freq & 0xff;
|
||||
cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
|
||||
|
||||
sr = (u64) (fep->symbol_rate/1000) << 20;
|
||||
do_div(sr,88000);
|
||||
cmd[3] = (sr >> 12) & 0xff;
|
||||
cmd[4] = (sr >> 4) & 0xff;
|
||||
cmd[5] = (sr << 4) & 0xf0;
|
||||
|
||||
deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
|
||||
fep->frequency, freq, freq, fep->symbol_rate,
|
||||
(unsigned long) sr, (unsigned long) sr);
|
||||
|
||||
/* if (fep->inversion == INVERSION_ON)
|
||||
cmd[6] |= 0x80; */
|
||||
|
||||
if (st->voltage == SEC_VOLTAGE_18)
|
||||
cmd[6] |= 0x40;
|
||||
|
||||
/* if (fep->symbol_rate > 8000000)
|
||||
cmd[6] |= 0x20;
|
||||
|
||||
if (fep->frequency < 1531000)
|
||||
cmd[6] |= 0x04;
|
||||
|
||||
if (st->tone_mode == SEC_TONE_ON)
|
||||
cmd[6] |= 0x01;*/
|
||||
|
||||
cmd[7] = vp702x_chksum(cmd,0,7);
|
||||
|
||||
st->status_check_interval = 250;
|
||||
st->next_status_check = jiffies;
|
||||
|
||||
vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
|
||||
|
||||
if (cmd[2] == 0 && cmd[3] == 0)
|
||||
deb_fe("tuning failed.\n");
|
||||
else
|
||||
deb_fe("tuning succeeded.\n");
|
||||
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
deb_fe("%s\n",__func__);
|
||||
vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
deb_fe("%s\n",__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
|
||||
struct dvb_diseqc_master_cmd *m)
|
||||
{
|
||||
u8 *cmd;
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
struct vp702x_device_state *dst = st->d->priv;
|
||||
|
||||
deb_fe("%s\n",__func__);
|
||||
|
||||
if (m->msg_len > 4)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
|
||||
cmd = dst->buf;
|
||||
cmd[1] = SET_DISEQC_CMD;
|
||||
cmd[2] = m->msg_len;
|
||||
memcpy(&cmd[3], m->msg, m->msg_len);
|
||||
cmd[7] = vp702x_chksum(cmd, 0, 7);
|
||||
|
||||
vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
|
||||
|
||||
if (cmd[2] == 0 && cmd[3] == 0)
|
||||
deb_fe("diseqc cmd failed.\n");
|
||||
else
|
||||
deb_fe("diseqc cmd succeeded.\n");
|
||||
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
|
||||
{
|
||||
deb_fe("%s\n",__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
struct vp702x_device_state *dst = st->d->priv;
|
||||
u8 *buf;
|
||||
|
||||
deb_fe("%s\n",__func__);
|
||||
|
||||
st->tone_mode = tone;
|
||||
|
||||
if (tone == SEC_TONE_ON)
|
||||
st->lnb_buf[2] = 0x02;
|
||||
else
|
||||
st->lnb_buf[2] = 0x00;
|
||||
|
||||
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
|
||||
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
|
||||
buf = dst->buf;
|
||||
memcpy(buf, st->lnb_buf, 8);
|
||||
|
||||
vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
|
||||
if (buf[2] == 0 && buf[3] == 0)
|
||||
deb_fe("set_tone cmd failed.\n");
|
||||
else
|
||||
deb_fe("set_tone cmd succeeded.\n");
|
||||
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
|
||||
voltage)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
struct vp702x_device_state *dst = st->d->priv;
|
||||
u8 *buf;
|
||||
deb_fe("%s\n",__func__);
|
||||
|
||||
st->voltage = voltage;
|
||||
|
||||
if (voltage != SEC_VOLTAGE_OFF)
|
||||
st->lnb_buf[4] = 0x01;
|
||||
else
|
||||
st->lnb_buf[4] = 0x00;
|
||||
|
||||
st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
|
||||
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
|
||||
buf = dst->buf;
|
||||
memcpy(buf, st->lnb_buf, 8);
|
||||
|
||||
vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
|
||||
if (buf[2] == 0 && buf[3] == 0)
|
||||
deb_fe("set_voltage cmd failed.\n");
|
||||
else
|
||||
deb_fe("set_voltage cmd succeeded.\n");
|
||||
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vp702x_fe_release(struct dvb_frontend* fe)
|
||||
{
|
||||
struct vp702x_fe_state *st = fe->demodulator_priv;
|
||||
kfree(st);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops vp702x_fe_ops;
|
||||
|
||||
struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
|
||||
{
|
||||
struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
s->d = d;
|
||||
|
||||
memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
|
||||
s->lnb_buf[1] = SET_LNB_POWER;
|
||||
s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
|
||||
|
||||
return &s->fe;
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops vp702x_fe_ops = {
|
||||
.delsys = { SYS_DVBS },
|
||||
.info = {
|
||||
.name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
|
||||
.frequency_tolerance = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500, /* ppm */
|
||||
.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_QPSK |
|
||||
FE_CAN_FEC_AUTO
|
||||
},
|
||||
.release = vp702x_fe_release,
|
||||
|
||||
.init = vp702x_fe_init,
|
||||
.sleep = vp702x_fe_sleep,
|
||||
|
||||
.set_frontend = vp702x_fe_set_frontend,
|
||||
.get_tune_settings = vp702x_fe_get_tune_settings,
|
||||
|
||||
.read_status = vp702x_fe_read_status,
|
||||
.read_ber = vp702x_fe_read_ber,
|
||||
.read_signal_strength = vp702x_fe_read_signal_strength,
|
||||
.read_snr = vp702x_fe_read_snr,
|
||||
.read_ucblocks = vp702x_fe_read_unc_blocks,
|
||||
|
||||
.diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg,
|
||||
.diseqc_send_burst = vp702x_fe_send_diseqc_burst,
|
||||
.set_tone = vp702x_fe_set_tone,
|
||||
.set_voltage = vp702x_fe_set_voltage,
|
||||
};
|
||||
444
drivers/media/usb/dvb-usb/vp702x.c
Normal file
444
drivers/media/usb/dvb-usb/vp702x.c
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
|
||||
* receiver.
|
||||
*
|
||||
* Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Metzler Brothers Systementwicklung GbR
|
||||
*
|
||||
* Copyright (C) 2005 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 "vp702x.h"
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_vp702x_debug;
|
||||
module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct vp702x_adapter_state {
|
||||
int pid_filter_count;
|
||||
int pid_filter_can_bypass;
|
||||
u8 pid_filter_state;
|
||||
};
|
||||
|
||||
static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
|
||||
u16 value, u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(d->udev,
|
||||
usb_rcvctrlpipe(d->udev, 0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, b, blen,
|
||||
2000);
|
||||
|
||||
if (ret < 0) {
|
||||
warn("usb in operation failed. (%d)", ret);
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
|
||||
deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&d->usb_mutex);
|
||||
ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req,
|
||||
u16 value, u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
|
||||
debug_dump(b,blen,deb_xfer);
|
||||
|
||||
if ((ret = usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev,0),
|
||||
req,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value,index,b,blen,
|
||||
2000)) != blen) {
|
||||
warn("usb out operation failed. (%d)",ret);
|
||||
return -EIO;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
|
||||
u16 index, u8 *b, int blen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&d->usb_mutex);
|
||||
ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
|
||||
return ret;
|
||||
|
||||
ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
|
||||
msleep(msec);
|
||||
ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
|
||||
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
|
||||
int olen, u8 *i, int ilen, int msec)
|
||||
{
|
||||
struct vp702x_device_state *st = d->priv;
|
||||
int ret = 0;
|
||||
u8 *buf;
|
||||
int buflen = max(olen + 2, ilen + 1);
|
||||
|
||||
ret = mutex_lock_interruptible(&st->buf_mutex);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (buflen > st->buf_len) {
|
||||
buf = kmalloc(buflen, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
mutex_unlock(&st->buf_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
info("successfully reallocated a bigger buffer");
|
||||
kfree(st->buf);
|
||||
st->buf = buf;
|
||||
st->buf_len = buflen;
|
||||
} else {
|
||||
buf = st->buf;
|
||||
}
|
||||
|
||||
buf[0] = 0x00;
|
||||
buf[1] = cmd;
|
||||
memcpy(&buf[2], o, olen);
|
||||
|
||||
ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
|
||||
|
||||
if (ret == 0)
|
||||
memcpy(i, &buf[1], ilen);
|
||||
mutex_unlock(&st->buf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
|
||||
{
|
||||
int ret;
|
||||
struct vp702x_device_state *st = adap->dev->priv;
|
||||
u8 *buf;
|
||||
|
||||
mutex_lock(&st->buf_mutex);
|
||||
|
||||
buf = st->buf;
|
||||
memset(buf, 0, 16);
|
||||
|
||||
ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
|
||||
0, buf, 16);
|
||||
mutex_unlock(&st->buf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
|
||||
{
|
||||
int ret;
|
||||
struct vp702x_device_state *st = adap->dev->priv;
|
||||
u8 *buf;
|
||||
|
||||
mutex_lock(&st->buf_mutex);
|
||||
|
||||
buf = st->buf;
|
||||
memset(buf, 0, 16);
|
||||
ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
|
||||
0, buf, 16);
|
||||
|
||||
mutex_unlock(&st->buf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
|
||||
{
|
||||
struct vp702x_adapter_state *st = adap->priv;
|
||||
struct vp702x_device_state *dst = adap->dev->priv;
|
||||
u8 *buf;
|
||||
|
||||
if (onoff)
|
||||
st->pid_filter_state |= (1 << id);
|
||||
else {
|
||||
st->pid_filter_state &= ~(1 << id);
|
||||
pid = 0xffff;
|
||||
}
|
||||
|
||||
id = 0x10 + id*2;
|
||||
|
||||
vp702x_set_pld_state(adap, st->pid_filter_state);
|
||||
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
|
||||
buf = dst->buf;
|
||||
memset(buf, 0, 16);
|
||||
vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
|
||||
vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
|
||||
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct vp702x_adapter_state *st = adap->priv;
|
||||
struct vp702x_device_state *dst = adap->dev->priv;
|
||||
int i;
|
||||
u8 *b;
|
||||
|
||||
st->pid_filter_count = 8;
|
||||
st->pid_filter_can_bypass = 1;
|
||||
st->pid_filter_state = 0x00;
|
||||
|
||||
vp702x_set_pld_mode(adap, 1); /* bypass */
|
||||
|
||||
for (i = 0; i < st->pid_filter_count; i++)
|
||||
vp702x_set_pid(adap, 0xffff, i, 1);
|
||||
|
||||
mutex_lock(&dst->buf_mutex);
|
||||
b = dst->buf;
|
||||
memset(b, 0, 10);
|
||||
vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
|
||||
vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
|
||||
vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
|
||||
mutex_unlock(&dst->buf_mutex);
|
||||
/*vp702x_set_pld_mode(d, 0); // filter */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keys for the enclosed remote control */
|
||||
static struct rc_map_table rc_map_vp702x_table[] = {
|
||||
{ 0x0001, KEY_1 },
|
||||
{ 0x0002, KEY_2 },
|
||||
};
|
||||
|
||||
/* remote control stuff (does not work with my box) */
|
||||
static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
u8 *key;
|
||||
int i;
|
||||
|
||||
/* remove the following return to enabled remote querying */
|
||||
return 0;
|
||||
|
||||
key = kmalloc(10, GFP_KERNEL);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
|
||||
|
||||
deb_rc("remote query key: %x %d\n",key[1],key[1]);
|
||||
|
||||
if (key[1] == 0x44) {
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
kfree(key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
|
||||
if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = rc_map_vp702x_table[i].keycode;
|
||||
break;
|
||||
}
|
||||
kfree(key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
|
||||
{
|
||||
u8 i, *buf;
|
||||
struct vp702x_device_state *st = d->priv;
|
||||
|
||||
mutex_lock(&st->buf_mutex);
|
||||
buf = st->buf;
|
||||
for (i = 6; i < 12; i++)
|
||||
vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
|
||||
|
||||
memcpy(mac, buf, 6);
|
||||
mutex_unlock(&st->buf_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 buf[10] = { 0 };
|
||||
|
||||
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
|
||||
|
||||
if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
|
||||
buf, 10, 10))
|
||||
return -EIO;
|
||||
|
||||
buf[9] = '\0';
|
||||
info("system string: %s",&buf[1]);
|
||||
|
||||
vp702x_init_pid_filter(adap);
|
||||
|
||||
adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
|
||||
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_properties vp702x_properties;
|
||||
|
||||
static int vp702x_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct vp702x_device_state *st;
|
||||
int ret;
|
||||
|
||||
ret = dvb_usb_device_init(intf, &vp702x_properties,
|
||||
THIS_MODULE, &d, adapter_nr);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
st = d->priv;
|
||||
st->buf_len = 16;
|
||||
st->buf = kmalloc(st->buf_len, GFP_KERNEL);
|
||||
if (!st->buf) {
|
||||
ret = -ENOMEM;
|
||||
dvb_usb_device_exit(intf);
|
||||
goto out;
|
||||
}
|
||||
mutex_init(&st->buf_mutex);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void vp702x_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
struct vp702x_device_state *st = d->priv;
|
||||
mutex_lock(&st->buf_mutex);
|
||||
kfree(st->buf);
|
||||
mutex_unlock(&st->buf_mutex);
|
||||
dvb_usb_device_exit(intf);
|
||||
}
|
||||
|
||||
static struct usb_device_id vp702x_usb_table [] = {
|
||||
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
|
||||
// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
|
||||
// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
|
||||
|
||||
static struct dvb_usb_device_properties vp702x_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-vp702x-02.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.size_of_priv = sizeof(struct vp702x_device_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
|
||||
|
||||
.streaming_ctrl = vp702x_streaming_ctrl,
|
||||
.frontend_attach = vp702x_frontend_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 10,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.size_of_priv = sizeof(struct vp702x_adapter_state),
|
||||
}
|
||||
},
|
||||
.read_mac_address = vp702x_read_mac_addr,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_map_table = rc_map_vp702x_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_vp702x_table),
|
||||
.rc_interval = 400,
|
||||
.rc_query = vp702x_rc_query,
|
||||
},
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
|
||||
.cold_ids = { &vp702x_usb_table[0], NULL },
|
||||
.warm_ids = { NULL },
|
||||
},
|
||||
/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
|
||||
.cold_ids = { &vp702x_usb_table[2], NULL },
|
||||
.warm_ids = { &vp702x_usb_table[3], NULL },
|
||||
},
|
||||
*/ { NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver vp702x_usb_driver = {
|
||||
.name = "dvb_usb_vp702x",
|
||||
.probe = vp702x_usb_probe,
|
||||
.disconnect = vp702x_usb_disconnect,
|
||||
.id_table = vp702x_usb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(vp702x_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
113
drivers/media/usb/dvb-usb/vp702x.h
Normal file
113
drivers/media/usb/dvb-usb/vp702x.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#ifndef _DVB_USB_VP7021_H_
|
||||
#define _DVB_USB_VP7021_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "vp702x"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
extern int dvb_usb_vp702x_debug;
|
||||
#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args)
|
||||
#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args)
|
||||
|
||||
/* commands are read and written with USB control messages */
|
||||
|
||||
/* consecutive read/write operation */
|
||||
#define REQUEST_OUT 0xB2
|
||||
#define REQUEST_IN 0xB3
|
||||
|
||||
/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0
|
||||
* request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer
|
||||
* the returning buffer looks as follows
|
||||
* request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */
|
||||
|
||||
#define GET_TUNER_STATUS 0x05
|
||||
/* additional in buffer:
|
||||
* 0 1 2 3 4 5 6 7 8
|
||||
* N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */
|
||||
|
||||
#define GET_SYSTEM_STRING 0x06
|
||||
/* additional in buffer:
|
||||
* 0 1 2 3 4 5 6 7 8
|
||||
* N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */
|
||||
|
||||
#define SET_DISEQC_CMD 0x08
|
||||
/* additional out buffer:
|
||||
* 0 1 2 3 4
|
||||
* len X1 X2 X3 X4
|
||||
* additional in buffer:
|
||||
* 0 1 2
|
||||
* N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */
|
||||
|
||||
#define SET_LNB_POWER 0x09
|
||||
/* additional out buffer:
|
||||
* 0 1 2
|
||||
* 0x00 0xff 1 = on, 0 = off
|
||||
* additional in buffer:
|
||||
* 0 1 2
|
||||
* N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */
|
||||
|
||||
#define GET_MAC_ADDRESS 0x0A
|
||||
/* #define GET_MAC_ADDRESS 0x0B */
|
||||
/* additional in buffer:
|
||||
* 0 1 2 3 4 5 6 7 8
|
||||
* N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */
|
||||
|
||||
#define SET_PID_FILTER 0x11
|
||||
/* additional in buffer:
|
||||
* 0 1 ... 14 15 16
|
||||
* PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */
|
||||
|
||||
/* request: 0xB2; i: 0; v: 0;
|
||||
* b[0] != 0 -> tune and lock a channel
|
||||
* 0 1 2 3 4 5 6 7
|
||||
* freq0 freq1 divstep srate0 srate1 srate2 flag chksum
|
||||
*/
|
||||
|
||||
/* one direction requests */
|
||||
#define READ_REMOTE_REQ 0xB4
|
||||
/* IN i: 0; v: 0; b[0] == request, b[1] == key */
|
||||
|
||||
#define READ_PID_NUMBER_REQ 0xB5
|
||||
/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */
|
||||
|
||||
#define WRITE_EEPROM_REQ 0xB6
|
||||
/* OUT i: offset; v: value to write; no extra buffer */
|
||||
|
||||
#define READ_EEPROM_REQ 0xB7
|
||||
/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */
|
||||
|
||||
#define READ_STATUS 0xB8
|
||||
/* IN i: 0; v: 0; bufferlen 10 */
|
||||
|
||||
#define READ_TUNER_REG_REQ 0xB9
|
||||
/* IN i: 0; v: register; b[0] = value */
|
||||
|
||||
#define READ_FX2_REG_REQ 0xBA
|
||||
/* IN i: offset; v: 0; b[0] = value */
|
||||
|
||||
#define WRITE_FX2_REG_REQ 0xBB
|
||||
/* OUT i: offset; v: value to write; 1 byte extra buffer */
|
||||
|
||||
#define SET_TUNER_POWER_REQ 0xBC
|
||||
/* IN i: 0 = power off, 1 = power on */
|
||||
|
||||
#define WRITE_TUNER_REG_REQ 0xBD
|
||||
/* IN i: register, v: value to write, no extra buffer */
|
||||
|
||||
#define RESET_TUNER 0xBE
|
||||
/* IN i: 0, v: 0, no extra buffer */
|
||||
|
||||
struct vp702x_device_state {
|
||||
struct mutex buf_mutex;
|
||||
int buf_len;
|
||||
u8 *buf;
|
||||
};
|
||||
|
||||
|
||||
extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
|
||||
|
||||
extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
|
||||
extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
|
||||
|
||||
#endif
|
||||
190
drivers/media/usb/dvb-usb/vp7045-fe.c
Normal file
190
drivers/media/usb/dvb-usb/vp7045-fe.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/* 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 dtv_frontend_properties *fep = &fe->dtv_property_cache;
|
||||
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->bandwidth_hz) {
|
||||
case 8000000:
|
||||
buf[4] = 8;
|
||||
break;
|
||||
case 7000000:
|
||||
buf[4] = 7;
|
||||
break;
|
||||
case 6000000:
|
||||
buf[4] = 6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
|
||||
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 = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
goto error;
|
||||
|
||||
s->d = d;
|
||||
memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
|
||||
s->fe.demodulator_priv = s;
|
||||
|
||||
return &s->fe;
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct dvb_frontend_ops vp7045_fe_ops = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "Twinhan VP7045/46 USB DVB-T",
|
||||
.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_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,
|
||||
};
|
||||
302
drivers/media/usb/dvb-usb/vp7045.c
Normal file
302
drivers/media/usb/dvb-usb/vp7045.c
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/* 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 */
|
||||
static 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);
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#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)
|
||||
|
||||
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 *buf = d->priv;
|
||||
|
||||
buf[0] = cmd;
|
||||
|
||||
if (outlen > 19)
|
||||
outlen = 19;
|
||||
|
||||
if (inlen > 11)
|
||||
inlen = 11;
|
||||
|
||||
ret = mutex_lock_interruptible(&d->usb_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (out != NULL && outlen > 0)
|
||||
memcpy(&buf[1], out, outlen);
|
||||
|
||||
deb_xfer("out buffer: ");
|
||||
debug_dump(buf, outlen+1, deb_xfer);
|
||||
|
||||
|
||||
if (usb_control_msg(d->udev,
|
||||
usb_sndctrlpipe(d->udev,0),
|
||||
TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
|
||||
buf, 20, 2000) != 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,
|
||||
buf, 12, 2000) != 12) {
|
||||
err("USB control message 'in' went wrong.");
|
||||
ret = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
deb_xfer("in buffer: ");
|
||||
debug_dump(buf, 12, deb_xfer);
|
||||
|
||||
if (in != NULL && inlen > 0)
|
||||
memcpy(in, &buf[1], inlen);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&d->usb_mutex);
|
||||
|
||||
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 rc_map_table rc_map_vp7045_table[] = {
|
||||
{ 0x0016, KEY_POWER },
|
||||
{ 0x0010, KEY_MUTE },
|
||||
{ 0x0003, KEY_1 },
|
||||
{ 0x0001, KEY_2 },
|
||||
{ 0x0006, KEY_3 },
|
||||
{ 0x0009, KEY_4 },
|
||||
{ 0x001d, KEY_5 },
|
||||
{ 0x001f, KEY_6 },
|
||||
{ 0x000d, KEY_7 },
|
||||
{ 0x0019, KEY_8 },
|
||||
{ 0x001b, KEY_9 },
|
||||
{ 0x0015, KEY_0 },
|
||||
{ 0x0005, KEY_CHANNELUP },
|
||||
{ 0x0002, KEY_CHANNELDOWN },
|
||||
{ 0x001e, KEY_VOLUMEUP },
|
||||
{ 0x000a, KEY_VOLUMEDOWN },
|
||||
{ 0x0011, KEY_RECORD },
|
||||
{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
|
||||
{ 0x0014, KEY_PLAY },
|
||||
{ 0x001a, KEY_STOP },
|
||||
{ 0x0040, KEY_REWIND },
|
||||
{ 0x0012, KEY_FASTFORWARD },
|
||||
{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
|
||||
{ 0x004c, KEY_PAUSE },
|
||||
{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
|
||||
{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
|
||||
{ 0x000c, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x001c, KEY_EPG }, /* EPG */
|
||||
{ 0x0000, KEY_TAB }, /* Tab */
|
||||
{ 0x0048, KEY_INFO }, /* Preview */
|
||||
{ 0x0004, KEY_LIST }, /* RecordList */
|
||||
{ 0x000f, KEY_TEXT }, /* Teletext */
|
||||
{ 0x0041, KEY_PREVIOUSSONG },
|
||||
{ 0x0042, KEY_NEXTSONG },
|
||||
{ 0x004b, KEY_UP },
|
||||
{ 0x0051, KEY_DOWN },
|
||||
{ 0x004e, KEY_LEFT },
|
||||
{ 0x0052, KEY_RIGHT },
|
||||
{ 0x004f, KEY_ENTER },
|
||||
{ 0x0013, KEY_CANCEL },
|
||||
{ 0x004a, KEY_CLEAR },
|
||||
{ 0x0054, KEY_PRINT }, /* Capture */
|
||||
{ 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */
|
||||
{ 0x0008, KEY_VIDEO }, /* A/V */
|
||||
{ 0x0007, KEY_SLEEP }, /* Hibernate */
|
||||
{ 0x0045, KEY_ZOOM }, /* Zoom+ */
|
||||
{ 0x0018, KEY_RED},
|
||||
{ 0x0053, KEY_GREEN},
|
||||
{ 0x005e, KEY_YELLOW},
|
||||
{ 0x005f, KEY_BLUE}
|
||||
};
|
||||
|
||||
static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, 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 < ARRAY_SIZE(rc_map_vp7045_table); i++)
|
||||
if (rc5_data(&rc_map_vp7045_table[i]) == key) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = rc_map_vp7045_table[i].keycode;
|
||||
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_adapter *adap)
|
||||
{
|
||||
u8 buf[255] = { 0 };
|
||||
|
||||
vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);
|
||||
buf[10] = '\0';
|
||||
deb_info("firmware says: %s ",buf);
|
||||
|
||||
vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);
|
||||
buf[10] = '\0';
|
||||
deb_info("%s ",buf);
|
||||
|
||||
vp7045_usb_op(adap->dev,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); */
|
||||
|
||||
adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_device_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, NULL, adapter_nr);
|
||||
}
|
||||
|
||||
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_device_properties vp7045_properties = {
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
.firmware = "dvb-usb-vp7045-01.fw",
|
||||
.size_of_priv = 20,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.num_frontends = 1,
|
||||
.fe = {{
|
||||
.frontend_attach = vp7045_frontend_attach,
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
}
|
||||
},
|
||||
.power_ctrl = vp7045_power_ctrl,
|
||||
.read_mac_address = vp7045_read_mac_addr,
|
||||
|
||||
.rc.legacy = {
|
||||
.rc_interval = 400,
|
||||
.rc_map_table = rc_map_vp7045_table,
|
||||
.rc_map_size = ARRAY_SIZE(rc_map_vp7045_table),
|
||||
.rc_query = vp7045_rc_query,
|
||||
},
|
||||
|
||||
.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 },
|
||||
},
|
||||
{ NULL },
|
||||
}
|
||||
};
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver vp7045_usb_driver = {
|
||||
.name = "dvb_usb_vp7045",
|
||||
.probe = vp7045_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = vp7045_usb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(vp7045_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
|
||||
MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_LICENSE("GPL");
|
||||
70
drivers/media/usb/dvb-usb/vp7045.h
Normal file
70
drivers/media/usb/dvb-usb/vp7045.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* 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"
|
||||
|
||||
/* 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 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue